From d81c794336dafbd233420202c62e7537bf7ce84f Mon Sep 17 00:00:00 2001 From: Clemens <68013019+ClFeSc@users.noreply.github.com> Date: Wed, 28 Dec 2022 00:57:43 +0100 Subject: [PATCH 01/58] Improve validation (#125) * Improve validation by introducing multiple new validation decorators * `IsIdMap` for types of the form `{ readonly [key: UUID]: T }`. This transforms the object, so using instance objects (instead of plain objects) will no longer be supported. * `IsLiteralUnion` for literal unions of types `number | string | symbol` (e.g. `participant | trainer`). Uses `isIn` internally. * `IsReachableTransferPoints` for `ReachableTransferPoints` used in `TransferPoint`. Very specific but necessary due to the unique structure of this type. * `IsUUIDSet` for `UUIDSet` * `IsValue` for *simple* values that are required for a property. For example, when a `type` property has to have the value `'partial'`, one can use `@IsValue('partial')` for this. Allowed are the types `bigint | boolean | number | string | symbol | null | undefined`. The reason is that this validator also uses `isIn` internally, which in turn uses `===` which might produce incorrect results for `object` values. * All validators are required to be applied to correctly types properties by the use of `GenericPropertyDecorator`. Using e.g. `@IsLiteralUnion({ partial: true, complete: true })` on a property typed `string` raises a TypeScript error. Co-authored-by: Julian Schmidt --- .../export-import/file-format/base-file.ts | 9 ++- .../file-format/partial-export.ts | 12 +--- .../export-import/file-format/state-export.ts | 22 ++----- shared/src/models/alarm-group.ts | 7 ++- shared/src/models/client.ts | 5 +- shared/src/models/hospital-patient.ts | 21 +++---- shared/src/models/hospital.ts | 6 +- shared/src/models/material-template.ts | 7 ++- shared/src/models/material.ts | 19 +++--- shared/src/models/patient-template.ts | 7 ++- shared/src/models/patient.ts | 49 ++++++++-------- shared/src/models/personnel-template.ts | 10 ++-- shared/src/models/personnel.ts | 27 +++++---- shared/src/models/transfer-point.ts | 12 ++-- .../src/models/utils/biometric-information.ts | 5 +- shared/src/models/utils/cater-for.ts | 17 ++++-- shared/src/models/utils/exercise-status.ts | 8 +++ shared/src/models/utils/material-type.ts | 7 +++ .../src/models/utils/patient-status-code.ts | 22 ++++++- shared/src/models/utils/patient-status.ts | 11 ++++ shared/src/models/utils/personnel-type.ts | 11 ++++ shared/src/models/utils/role.ts | 6 ++ shared/src/models/utils/sex.ts | 8 +++ shared/src/models/utils/start-points.ts | 25 +++++++- shared/src/models/utils/transfer.ts | 8 ++- shared/src/models/vehicle-template.ts | 16 ++++- shared/src/models/vehicle.ts | 11 ++-- shared/src/state.ts | 49 +++++++++------- .../src/store/action-reducers/alarm-group.ts | 13 +++-- shared/src/store/action-reducers/client.ts | 19 +++--- .../store/action-reducers/configuration.ts | 9 +-- .../emergency-operation-center.ts | 5 +- shared/src/store/action-reducers/exercise.ts | 8 +-- shared/src/store/action-reducers/hospital.ts | 11 ++-- .../action-reducers/map-image-templates.ts | 7 ++- .../src/store/action-reducers/map-images.ts | 36 +++++++----- shared/src/store/action-reducers/material.ts | 5 +- shared/src/store/action-reducers/patient.ts | 19 +++--- shared/src/store/action-reducers/personnel.ts | 5 +- .../store/action-reducers/transfer-point.ts | 19 +++--- shared/src/store/action-reducers/transfer.ts | 48 +++++++++------ shared/src/store/action-reducers/vehicle.ts | 19 +++--- shared/src/store/action-reducers/viewport.ts | 13 +++-- shared/src/store/validate-exercise-action.ts | 26 ++++++++- shared/src/store/validate-exercise-export.ts | 8 --- .../utils/validators/combine-decorators.ts | 37 ++++++++++++ .../utils/validators/create-map-validator.ts | 38 ++++++++++++ .../validators/generic-property-decorator.ts | 13 +++++ shared/src/utils/validators/index.ts | 7 +++ shared/src/utils/validators/is-id-map.ts | 48 +++++++++++++++ .../src/utils/validators/is-literal-union.ts | 58 +++++++++++++++++++ .../is-reachable-transfer-points-object.ts | 33 +++++++++++ shared/src/utils/validators/is-uuid-set.ts | 27 +++++++++ shared/src/utils/validators/is-value.ts | 45 ++++++++++++++ shared/src/utils/validators/make-validator.ts | 31 ++++++++++ 55 files changed, 751 insertions(+), 273 deletions(-) create mode 100644 shared/src/utils/validators/combine-decorators.ts create mode 100644 shared/src/utils/validators/create-map-validator.ts create mode 100644 shared/src/utils/validators/generic-property-decorator.ts create mode 100644 shared/src/utils/validators/index.ts create mode 100644 shared/src/utils/validators/is-id-map.ts create mode 100644 shared/src/utils/validators/is-literal-union.ts create mode 100644 shared/src/utils/validators/is-reachable-transfer-points-object.ts create mode 100644 shared/src/utils/validators/is-uuid-set.ts create mode 100644 shared/src/utils/validators/is-value.ts create mode 100644 shared/src/utils/validators/make-validator.ts diff --git a/shared/src/export-import/file-format/base-file.ts b/shared/src/export-import/file-format/base-file.ts index cde1aa076..34a78a0b2 100644 --- a/shared/src/export-import/file-format/base-file.ts +++ b/shared/src/export-import/file-format/base-file.ts @@ -1,5 +1,6 @@ -import { IsIn, IsInt, IsString, Min } from 'class-validator'; +import { IsInt, Min } from 'class-validator'; import { ExerciseState } from '../../state'; +import { IsLiteralUnion } from '../../utils/validators'; export abstract class BaseExportImportFile { public static readonly currentFileVersion = 1; @@ -13,7 +14,9 @@ export abstract class BaseExportImportFile { @Min(0) public readonly dataVersion: number = ExerciseState.currentStateVersion; - @IsIn(['complete', 'partial']) - @IsString() + @IsLiteralUnion({ + complete: true, + partial: true, + }) public abstract readonly type: 'complete' | 'partial'; } diff --git a/shared/src/export-import/file-format/partial-export.ts b/shared/src/export-import/file-format/partial-export.ts index a819a58ae..94a810171 100644 --- a/shared/src/export-import/file-format/partial-export.ts +++ b/shared/src/export-import/file-format/partial-export.ts @@ -1,21 +1,15 @@ import { Type } from 'class-transformer'; -import { - IsArray, - IsIn, - IsOptional, - IsString, - ValidateNested, -} from 'class-validator'; +import { IsArray, IsOptional, ValidateNested } from 'class-validator'; import { MapImageTemplate, PatientTemplate, VehicleTemplate, } from '../../models'; +import { IsValue } from '../../utils/validators'; import { BaseExportImportFile } from './base-file'; export class PartialExport extends BaseExportImportFile { - @IsIn(['partial']) - @IsString() + @IsValue('partial' as const) public readonly type: 'partial' = 'partial'; @IsOptional() diff --git a/shared/src/export-import/file-format/state-export.ts b/shared/src/export-import/file-format/state-export.ts index 8d39d6f91..eddc3f1a8 100644 --- a/shared/src/export-import/file-format/state-export.ts +++ b/shared/src/export-import/file-format/state-export.ts @@ -1,32 +1,21 @@ import { Type } from 'class-transformer'; -import type { ValidationError } from 'class-validator'; -import { - IsArray, - IsIn, - IsOptional, - IsString, - ValidateNested, -} from 'class-validator'; +import { IsArray, IsOptional, ValidateNested } from 'class-validator'; import { ExerciseState } from '../../state'; import type { ExerciseAction } from '../../store'; -import { validateExerciseAction } from '../../store'; +import { IsExerciseAction } from '../../store'; import { Mutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; import { BaseExportImportFile } from './base-file'; export class StateHistoryCompound { @IsArray() + @IsExerciseAction({ each: true }) public actionHistory: ExerciseAction[]; @ValidateNested() @Type(() => ExerciseState) public initialState: Mutable; - public validateActions(): (ValidationError | string)[][] { - return this.actionHistory.map((action) => - validateExerciseAction(action) - ); - } - public constructor( actionHistory: ExerciseAction[], initialState: Mutable @@ -37,8 +26,7 @@ export class StateHistoryCompound { } export class StateExport extends BaseExportImportFile { - @IsIn(['complete']) - @IsString() + @IsValue('complete' as const) public readonly type: 'complete' = 'complete'; @ValidateNested() diff --git a/shared/src/models/alarm-group.ts b/shared/src/models/alarm-group.ts index 91f2843e5..3d4d58d72 100644 --- a/shared/src/models/alarm-group.ts +++ b/shared/src/models/alarm-group.ts @@ -1,7 +1,8 @@ -import { IsObject, IsString, IsUUID } from 'class-validator'; +import { IsString, IsUUID } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsIdMap } from '../utils/validators/is-id-map'; import { getCreate } from './utils'; -import type { AlarmGroupVehicle } from './utils/alarm-group-vehicle'; +import { AlarmGroupVehicle } from './utils/alarm-group-vehicle'; export class AlarmGroup { @IsUUID(4, uuidValidationOptions) @@ -10,7 +11,7 @@ export class AlarmGroup { @IsString() public readonly name: string; - @IsObject() + @IsIdMap(AlarmGroupVehicle) public alarmGroupVehicles: { readonly [key: UUID]: AlarmGroupVehicle } = {}; /** diff --git a/shared/src/models/client.ts b/shared/src/models/client.ts index 18fa28792..aac8ec2eb 100644 --- a/shared/src/models/client.ts +++ b/shared/src/models/client.ts @@ -6,7 +6,9 @@ import { MaxLength, } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsLiteralUnion } from '../utils/validators'; import { getCreate, Role } from './utils'; +import { roleAllowedValues } from './utils/role'; export class Client { @IsUUID(4, uuidValidationOptions) @@ -17,8 +19,7 @@ export class Client { @MaxLength(255) public readonly name: string; - // TODO - @IsString() + @IsLiteralUnion(roleAllowedValues) public readonly role: Role; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/models/hospital-patient.ts b/shared/src/models/hospital-patient.ts index 643d2fa63..b9aa4655f 100644 --- a/shared/src/models/hospital-patient.ts +++ b/shared/src/models/hospital-patient.ts @@ -1,25 +1,26 @@ import { Type } from 'class-transformer'; import { - IsDefined, IsNumber, IsString, IsUUID, - Max, Min, ValidateNested, } from 'class-validator'; import type { Mutable } from '../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../utils'; +import { IsIdMap, IsLiteralUnion } from '../utils/validators'; import { getCreate, HealthPoints, - healthPointsDefaults, ImageProperties, + IsValidHealthPoint, PatientStatus, + patientStatusAllowedValues, } from './utils'; import { BiometricInformation } from './utils/biometric-information'; import { PersonalInformation } from './utils/personal-information'; -import type { Patient, PatientHealthState } from '.'; +import { PatientHealthState } from './patient-health-state'; +import type { Patient } from '.'; export class HospitalPatient { /** @@ -54,19 +55,17 @@ export class HospitalPatient { @Type(() => BiometricInformation) public readonly biometricInformation: BiometricInformation; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly pretriageStatus: PatientStatus; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly realStatus: PatientStatus; @ValidateNested() @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; } = {}; @@ -80,9 +79,7 @@ export class HospitalPatient { /** * See {@link HealthPoints} for context of this property. */ - @IsNumber() - @Max(healthPointsDefaults.max) - @Min(healthPointsDefaults.min) + @IsValidHealthPoint() public readonly health: HealthPoints; @IsNumber() diff --git a/shared/src/models/hospital.ts b/shared/src/models/hospital.ts index d1b07bcc9..80797693a 100644 --- a/shared/src/models/hospital.ts +++ b/shared/src/models/hospital.ts @@ -1,5 +1,6 @@ -import { IsDefined, IsNumber, IsString, IsUUID, Min } from 'class-validator'; +import { IsNumber, IsString, IsUUID, Min } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; +import { IsUUIDSet } from '../utils/validators'; import { getCreate } from './utils'; export class Hospital { @@ -19,8 +20,7 @@ export class Hospital { /** * These Ids reference a hospitalPatients patientId */ - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly patientIds: UUIDSet = {}; /** diff --git a/shared/src/models/material-template.ts b/shared/src/models/material-template.ts index 34b869b39..95f6ba6ec 100644 --- a/shared/src/models/material-template.ts +++ b/shared/src/models/material-template.ts @@ -1,11 +1,12 @@ import { Type } from 'class-transformer'; -import { IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator'; +import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; +import { IsLiteralUnion } from '../utils/validators'; import { CanCaterFor, getCreate, ImageProperties } from './utils'; -import { MaterialType } from './utils/material-type'; +import { MaterialType, materialTypeAllowedValues } from './utils/material-type'; export class MaterialTemplate { - @IsString() + @IsLiteralUnion(materialTypeAllowedValues) public readonly materialType: MaterialType; @ValidateNested() diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts index 49f3aef4d..e82ab1ed0 100644 --- a/shared/src/models/material.ts +++ b/shared/src/models/material.ts @@ -1,18 +1,18 @@ import { Type } from 'class-transformer'; import { - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, - Max, - Min, + IsString, ValidateNested, + IsNumber, + Min, + Max, + IsOptional, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { uuid, UUID, UUIDSet, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; +import { IsUUIDSet } from '../utils/validators'; import type { MaterialTemplate } from './material-template'; -import { CanCaterFor, getCreate, ImageProperties, Position } from './utils'; +import { CanCaterFor, Position, ImageProperties, getCreate } from './utils'; export class Material { @IsUUID(4, uuidValidationOptions) @@ -24,8 +24,7 @@ export class Material { @IsString() public readonly vehicleName: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPatientIds: UUIDSet; @ValidateNested() diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts index 753d09f83..65e319f09 100644 --- a/shared/src/models/patient-template.ts +++ b/shared/src/models/patient-template.ts @@ -1,6 +1,7 @@ import { Type } from 'class-transformer'; -import { IsDefined, IsUUID, ValidateNested } from 'class-validator'; +import { IsUUID, ValidateNested } from 'class-validator'; import { cloneDeepMutable, UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsIdMap } from '../utils/validators'; import type { PatientStatusCode } from './utils'; import { BiometricInformation, @@ -14,7 +15,7 @@ import { PersonalInformation } from './utils/personal-information'; import { Patient } from './patient'; import type { FunctionParameters } from './patient-health-state'; import { PretriageInformation } from './utils/pretriage-information'; -import type { PatientHealthState } from '.'; +import { PatientHealthState } from './patient-health-state'; export class PatientTemplate { @IsUUID(4, uuidValidationOptions) @@ -32,7 +33,7 @@ export class PatientTemplate { @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; }; diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index a249d7310..19423c02d 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -1,31 +1,32 @@ import { Type } from 'class-transformer'; import { - IsBoolean, - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, + ValidateNested, + IsOptional, + IsNumber, Max, - MaxLength, Min, - ValidateNested, + IsBoolean, + IsString, + MaxLength, + isEmpty, } from 'class-validator'; -import { isEmpty } from 'lodash-es'; -import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; +import { IsLiteralUnion, IsIdMap, IsUUIDSet } from '../utils/validators'; +import { PatientHealthState } from './patient-health-state'; import { - getCreate, - HealthPoints, - healthPointsDefaults, - ImageProperties, + BiometricInformation, + PatientStatusCode, PatientStatus, + patientStatusAllowedValues, + ImageProperties, Position, + healthPointsDefaults, + HealthPoints, + getCreate, } from './utils'; -import { BiometricInformation } from './utils/biometric-information'; -import { PatientStatusCode } from './utils/patient-status-code'; -import { PretriageInformation } from './utils/pretriage-information'; import { PersonalInformation } from './utils/personal-information'; -import type { PatientHealthState } from '.'; +import { PretriageInformation } from './utils/pretriage-information'; export class Patient { @IsUUID(4, uuidValidationOptions) @@ -51,12 +52,10 @@ export class Patient { @Type(() => PatientStatusCode) public readonly patientStatusCode: PatientStatusCode; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly pretriageStatus: PatientStatus; - // TODO - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly realStatus: PatientStatus; @ValidateNested() @@ -84,7 +83,7 @@ export class Patient { @IsNumber() public readonly stateTime: number = 0; - @IsDefined() + @IsIdMap(PatientHealthState) public readonly healthStates: { readonly [stateId: UUID]: PatientHealthState; } = {}; @@ -103,12 +102,10 @@ export class Patient { @Min(healthPointsDefaults.min) public readonly health: HealthPoints; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPersonnelIds: UUIDSet = {}; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedMaterialIds: UUIDSet = {}; /** * The speed with which the patients healthStatus changes diff --git a/shared/src/models/personnel-template.ts b/shared/src/models/personnel-template.ts index 505cf4903..ccc06782a 100644 --- a/shared/src/models/personnel-template.ts +++ b/shared/src/models/personnel-template.ts @@ -1,16 +1,18 @@ import { Type } from 'class-transformer'; -import { IsNumber, IsString, Max, Min, ValidateNested } from 'class-validator'; +import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; +import { IsLiteralUnion } from '../utils/validators'; import { + PersonnelType, CanCaterFor, - getCreate, ImageProperties, - PersonnelType, + getCreate, } from './utils'; +import { personnelTypeAllowedValues } from './utils/personnel-type'; // TODO: These are not (yet) saved in the state -> Decide whether they should and if not move this file from the models folder away export class PersonnelTemplate { - @IsString() + @IsLiteralUnion(personnelTypeAllowedValues) public readonly personnelType: PersonnelType; @ValidateNested() diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts index 20cd9aa8b..afe24d0e4 100644 --- a/shared/src/models/personnel.ts +++ b/shared/src/models/personnel.ts @@ -1,25 +1,26 @@ import { Type } from 'class-transformer'; import { - IsDefined, - IsNumber, - IsOptional, - IsString, IsUUID, - Max, - Min, + IsString, ValidateNested, + IsNumber, + Min, + Max, + IsOptional, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { UUID, UUIDSet, uuid, uuidValidationOptions } from '../utils'; +import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; +import { IsLiteralUnion, IsUUIDSet } from '../utils/validators'; import type { PersonnelTemplate } from './personnel-template'; import { + PersonnelType, CanCaterFor, - Position, ImageProperties, - PersonnelType, - getCreate, + Position, Transfer, + getCreate, } from './utils'; +import { personnelTypeAllowedValues } from './utils/personnel-type'; export class Personnel { @IsUUID(4, uuidValidationOptions) @@ -28,15 +29,13 @@ export class Personnel { @IsUUID(4, uuidValidationOptions) public readonly vehicleId: UUID; - // TODO - @IsString() + @IsLiteralUnion(personnelTypeAllowedValues) public readonly personnelType: PersonnelType; @IsString() public readonly vehicleName: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly assignedPatientIds: UUIDSet; @ValidateNested() diff --git a/shared/src/models/transfer-point.ts b/shared/src/models/transfer-point.ts index 46242c969..b825b36be 100644 --- a/shared/src/models/transfer-point.ts +++ b/shared/src/models/transfer-point.ts @@ -1,6 +1,7 @@ import { Type } from 'class-transformer'; -import { IsDefined, IsString, IsUUID, ValidateNested } from 'class-validator'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; +import { IsReachableTransferPoints, IsUUIDSet } from '../utils/validators'; import type { ImageProperties } from './utils'; import { getCreate, Position } from './utils'; @@ -12,12 +13,10 @@ export class TransferPoint { @Type(() => Position) public readonly position: Position; - // TODO - @IsDefined() + @IsReachableTransferPoints() public readonly reachableTransferPoints: ReachableTransferPoints; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly reachableHospitals: UUIDSet = {}; @IsString() @@ -56,8 +55,7 @@ export class TransferPoint { } } -// TODO: Add validation -interface ReachableTransferPoints { +export interface ReachableTransferPoints { readonly [connectTransferPointId: UUID]: { /** * The time in ms it takes to get from this transfer point to the other one. diff --git a/shared/src/models/utils/biometric-information.ts b/shared/src/models/utils/biometric-information.ts index 3ecef84c4..9e7734d8b 100644 --- a/shared/src/models/utils/biometric-information.ts +++ b/shared/src/models/utils/biometric-information.ts @@ -1,13 +1,14 @@ import { IsInt, IsString, Min } from 'class-validator'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; -import { Sex } from './sex'; +import { Sex, sexAllowedValues } from './sex'; export class BiometricInformation { @IsInt() @Min(0) public readonly age: number; - @IsString() + @IsLiteralUnion(sexAllowedValues) public readonly sex: Sex; /** diff --git a/shared/src/models/utils/cater-for.ts b/shared/src/models/utils/cater-for.ts index 1ec5b0892..42d26c639 100644 --- a/shared/src/models/utils/cater-for.ts +++ b/shared/src/models/utils/cater-for.ts @@ -1,6 +1,14 @@ -import { IsNumber, IsString, Min } from 'class-validator'; +import { IsNumber, Min } from 'class-validator'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; +type LogicalOperator = 'and' | 'or'; +const logicalOperatorAllowedValues: AllowedValues = { + and: true, + or: true, +}; + export class CanCaterFor { /** * if {@link logicalOperator} `=== 'and'` it is cumulative, @@ -30,9 +38,8 @@ export class CanCaterFor { @Min(0) public readonly green: number; - // TODO: Use a better validator - @IsString() - public readonly logicalOperator: 'and' | 'or'; + @IsLiteralUnion(logicalOperatorAllowedValues) + public readonly logicalOperator: LogicalOperator; /** * @deprecated Use {@link create} instead @@ -41,7 +48,7 @@ export class CanCaterFor { red: number, yellow: number, green: number, - logicalOperator: 'and' | 'or' + logicalOperator: LogicalOperator ) { this.red = red; this.yellow = yellow; diff --git a/shared/src/models/utils/exercise-status.ts b/shared/src/models/utils/exercise-status.ts index 8c00def2d..ce94ea98e 100644 --- a/shared/src/models/utils/exercise-status.ts +++ b/shared/src/models/utils/exercise-status.ts @@ -1 +1,9 @@ +import type { AllowedValues } from '../../utils/validators'; + export type ExerciseStatus = 'notStarted' | 'paused' | 'running'; + +export const exerciseStatusAllowedValues: AllowedValues = { + notStarted: true, + paused: true, + running: true, +}; diff --git a/shared/src/models/utils/material-type.ts b/shared/src/models/utils/material-type.ts index e88b92a4c..dbfbdacfe 100644 --- a/shared/src/models/utils/material-type.ts +++ b/shared/src/models/utils/material-type.ts @@ -1 +1,8 @@ +import type { AllowedValues } from '../../utils/validators'; + export type MaterialType = 'big' | 'standard'; + +export const materialTypeAllowedValues: AllowedValues = { + big: true, + standard: true, +}; diff --git a/shared/src/models/utils/patient-status-code.ts b/shared/src/models/utils/patient-status-code.ts index 5539f72a6..e18deed7c 100644 --- a/shared/src/models/utils/patient-status-code.ts +++ b/shared/src/models/utils/patient-status-code.ts @@ -1,9 +1,25 @@ import { Type } from 'class-transformer'; -import { IsString, ValidateNested } from 'class-validator'; +import { ValidateNested } from 'class-validator'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion } from '../../utils/validators'; import { getCreate } from './get-create'; type ColorCode = 'V' | 'W' | 'X' | 'Y' | 'Z'; +const colorCodeAllowedValues: AllowedValues = { + V: true, + W: true, + X: true, + Y: true, + Z: true, +}; type BehaviourCode = 'A' | 'B' | 'C' | 'D' | 'E'; +const behaviourCodeAllowedValues: AllowedValues = { + A: true, + B: true, + C: true, + D: true, + E: true, +}; export const colorCodeMap = { V: 'black', @@ -26,10 +42,10 @@ export const behaviourCodeMap: { [key in BehaviourCode]: string } = { }; export class PatientStatusDataField { - @IsString() + @IsLiteralUnion(colorCodeAllowedValues) public readonly colorCode: ColorCode; - @IsString() + @IsLiteralUnion(behaviourCodeAllowedValues) public readonly behaviourCode: BehaviourCode; /** diff --git a/shared/src/models/utils/patient-status.ts b/shared/src/models/utils/patient-status.ts index e4e2888eb..26524d0ac 100644 --- a/shared/src/models/utils/patient-status.ts +++ b/shared/src/models/utils/patient-status.ts @@ -1,3 +1,5 @@ +import type { AllowedValues } from '../../utils/validators'; + export type PatientStatus = | 'black' | 'blue' @@ -16,3 +18,12 @@ export const statusNames: { white: 'Ungesichtet', yellow: 'SK II', }; + +export const patientStatusAllowedValues: AllowedValues = { + black: true, + blue: true, + green: true, + red: true, + white: true, + yellow: true, +}; diff --git a/shared/src/models/utils/personnel-type.ts b/shared/src/models/utils/personnel-type.ts index 7f5c1628b..0ef52f35f 100644 --- a/shared/src/models/utils/personnel-type.ts +++ b/shared/src/models/utils/personnel-type.ts @@ -1,4 +1,15 @@ +import type { AllowedValues } from '../../utils/validators'; + export type PersonnelType = 'gf' | 'notarzt' | 'notSan' | 'rettSan' | 'san'; + +export const personnelTypeAllowedValues: AllowedValues = { + gf: true, + notarzt: true, + notSan: true, + rettSan: true, + san: true, +}; + export const personnelTypeNames: { [key in PersonnelType]: string; } = { diff --git a/shared/src/models/utils/role.ts b/shared/src/models/utils/role.ts index 88151fac8..7f184dd6b 100644 --- a/shared/src/models/utils/role.ts +++ b/shared/src/models/utils/role.ts @@ -1 +1,7 @@ +import type { AllowedValues } from '../../utils/validators'; + export type Role = 'participant' | 'trainer'; +export const roleAllowedValues: AllowedValues = { + participant: true, + trainer: true, +}; diff --git a/shared/src/models/utils/sex.ts b/shared/src/models/utils/sex.ts index e1c6ea13b..57f988dd0 100644 --- a/shared/src/models/utils/sex.ts +++ b/shared/src/models/utils/sex.ts @@ -1 +1,9 @@ +import type { AllowedValues } from '../../utils/validators'; + export type Sex = 'diverse' | 'female' | 'male'; + +export const sexAllowedValues: AllowedValues = { + diverse: true, + female: true, + male: true, +}; diff --git a/shared/src/models/utils/start-points.ts b/shared/src/models/utils/start-points.ts index 3b9ffaf93..604c54344 100644 --- a/shared/src/models/utils/start-points.ts +++ b/shared/src/models/utils/start-points.ts @@ -1,11 +1,13 @@ -import { IsIn, IsNumber, IsString, IsUUID, Min } from 'class-validator'; +import type { TypeOptions } from 'class-transformer'; +import { IsNumber, IsString, IsUUID, Min } from 'class-validator'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import { getCreate } from './get-create'; export type StartPoint = AlarmGroupStartPoint | TransferStartPoint; export class TransferStartPoint { - @IsIn(['transferPoint']) + @IsValue('transferPoint' as const) public readonly type = 'transferPoint'; @IsUUID(4, uuidValidationOptions) @@ -22,7 +24,7 @@ export class TransferStartPoint { } export class AlarmGroupStartPoint { - @IsIn(['alarmGroup']) + @IsValue('alarmGroup' as const) public readonly type = 'alarmGroup'; @IsString() @@ -42,3 +44,20 @@ export class AlarmGroupStartPoint { static readonly create = getCreate(this); } + +export const startPointTypeOptions: TypeOptions = { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: [ + { + name: 'alarmGroup', + value: AlarmGroupStartPoint, + }, + { + name: 'transferPoint', + value: TransferStartPoint, + }, + ], + }, +}; diff --git a/shared/src/models/utils/transfer.ts b/shared/src/models/utils/transfer.ts index 65ba7340b..a5a33d610 100644 --- a/shared/src/models/utils/transfer.ts +++ b/shared/src/models/utils/transfer.ts @@ -1,7 +1,8 @@ -import { IsBoolean, IsNumber, IsObject, IsUUID } from 'class-validator'; +import { Type } from 'class-transformer'; +import { IsBoolean, IsNumber, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuidValidationOptions } from '../../utils'; import { getCreate } from './get-create'; -import { StartPoint } from './start-points'; +import { StartPoint, startPointTypeOptions } from './start-points'; export class Transfer { /** @@ -10,7 +11,8 @@ export class Transfer { @IsNumber() public readonly endTimeStamp: number; - @IsObject() + @ValidateNested() + @Type(() => Object, startPointTypeOptions) public readonly startPoint: StartPoint; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/models/vehicle-template.ts b/shared/src/models/vehicle-template.ts index b4ceb0900..f0dd3157b 100644 --- a/shared/src/models/vehicle-template.ts +++ b/shared/src/models/vehicle-template.ts @@ -7,9 +7,15 @@ import { IsArray, } from 'class-validator'; import { uuidValidationOptions, UUID, uuid } from '../utils'; +import { IsLiteralUnion } from '../utils/validators'; import type { PersonnelType } from './utils'; -import { ImageProperties, getCreate } from './utils'; +import { + ImageProperties, + personnelTypeAllowedValues, + getCreate, +} from './utils'; import type { MaterialType } from './utils/material-type'; +import { materialTypeAllowedValues } from './utils/material-type'; export class VehicleTemplate { @IsUUID(4, uuidValidationOptions) @@ -29,11 +35,15 @@ export class VehicleTemplate { public readonly patientCapacity: number; @IsArray() - @IsString({ each: true }) + @IsLiteralUnion(personnelTypeAllowedValues, { + each: true, + }) public readonly personnel: readonly PersonnelType[]; @IsArray() - @IsString({ each: true }) + @IsLiteralUnion(materialTypeAllowedValues, { + each: true, + }) public readonly materials: readonly MaterialType[]; /** diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index 87073bf5c..95141b20b 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -1,6 +1,5 @@ import { Type } from 'class-transformer'; import { - IsDefined, IsNumber, IsOptional, IsString, @@ -8,6 +7,7 @@ import { ValidateNested, } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; +import { IsUUIDSet } from '../utils/validators'; import { getCreate, Position, Transfer } from './utils'; import { ImageProperties } from './utils/image-properties'; @@ -21,8 +21,7 @@ export class Vehicle { @IsString() public readonly name: string; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly materialIds: UUIDSet = {}; @IsNumber() @@ -48,12 +47,10 @@ export class Vehicle { @IsOptional() public readonly transfer?: Transfer; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly personnelIds: UUIDSet = {}; - // @IsUUID(4, uuidArrayValidationOptions) // TODO: this doesn't work on this kind of set - @IsDefined() + @IsUUIDSet() public readonly patientIds: UUIDSet = {}; /** diff --git a/shared/src/state.ts b/shared/src/state.ts index 866711741..9a03c7395 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -8,36 +8,45 @@ import { Min, ValidateNested, } from 'class-validator'; -import { defaultMapImagesTemplates } from './data/default-state/map-images-templates'; +import { + defaultMapImagesTemplates, + defaultPatientCategories, + defaultVehicleTemplates, +} from './data'; import { defaultMaterialTemplates } from './data/default-state/material-templates'; -import { defaultPatientCategories } from './data/default-state/patient-templates'; import { defaultPersonnelTemplates } from './data/default-state/personnel-templates'; -import { defaultVehicleTemplates } from './data/default-state/vehicle-templates'; -import type { +import { AlarmGroup, Client, + EocLogEntry, Hospital, HospitalPatient, MapImage, + MapImageTemplate, Material, Patient, Personnel, TransferPoint, Vehicle, + VehicleTemplate, Viewport, } from './models'; -import { EocLogEntry, MapImageTemplate, VehicleTemplate } from './models'; import { ExerciseConfiguration } from './models/exercise-configuration'; import type { MaterialTemplate } from './models/material-template'; import { PatientCategory } from './models/patient-category'; import type { PersonnelTemplate } from './models/personnel-template'; import type { PersonnelType } from './models/utils'; -import { getCreate, SpatialTree } from './models/utils'; -import { ExerciseStatus } from './models/utils/exercise-status'; +import { + ExerciseStatus, + exerciseStatusAllowedValues, + getCreate, + SpatialTree, +} from './models/utils'; import type { MaterialType } from './models/utils/material-type'; import type { SpatialElementType } from './store/action-reducers/utils/spatial-elements'; import type { UUID } from './utils'; import { uuid, uuidValidationOptions } from './utils'; +import { IsIdMap, IsLiteralUnion } from './utils/validators'; export class ExerciseState { @IsUUID(4, uuidValidationOptions) @@ -52,32 +61,32 @@ export class ExerciseState { @IsInt() @Min(0) public readonly currentTime = 0; - @IsString() + @IsLiteralUnion(exerciseStatusAllowedValues) public readonly currentStatus: ExerciseStatus = 'notStarted'; - @IsObject() + @IsIdMap(Viewport) public readonly viewports: { readonly [key: UUID]: Viewport } = {}; - @IsObject() + @IsIdMap(Vehicle) public readonly vehicles: { readonly [key: UUID]: Vehicle } = {}; - @IsObject() + @IsIdMap(Personnel) public readonly personnel: { readonly [key: UUID]: Personnel } = {}; - @IsObject() + @IsIdMap(Patient) public readonly patients: { readonly [key: UUID]: Patient } = {}; - @IsObject() + @IsIdMap(Material) public readonly materials: { readonly [key: UUID]: Material } = {}; - @IsObject() + @IsIdMap(MapImage) public readonly mapImages: { readonly [key: UUID]: MapImage } = {}; - @IsObject() + @IsIdMap(TransferPoint) public readonly transferPoints: { readonly [key: UUID]: TransferPoint } = {}; - @IsObject() + @IsIdMap(Hospital) public readonly hospitals: { readonly [key: UUID]: Hospital } = {}; - @IsObject() + @IsIdMap(HospitalPatient, (hospitalPatient) => hospitalPatient.patientId) public readonly hospitalPatients: { readonly [key: UUID]: HospitalPatient; } = {}; - @IsObject() + @IsIdMap(AlarmGroup) public readonly alarmGroups: { readonly [key: UUID]: AlarmGroup } = {}; - @IsObject() + @IsIdMap(Client) public readonly clients: { readonly [key: UUID]: Client } = {}; @IsArray() @ValidateNested() @@ -104,7 +113,7 @@ export class ExerciseState { @Type(() => EocLogEntry) public readonly eocLog: readonly EocLogEntry[] = []; @IsString() - public readonly participantId: string = ''; + public readonly participantId: string; // Mutable` could still have immutable objects in spatialTree @IsObject() diff --git a/shared/src/store/action-reducers/alarm-group.ts b/shared/src/store/action-reducers/alarm-group.ts index 909b3c49a..598c30c63 100644 --- a/shared/src/store/action-reducers/alarm-group.ts +++ b/shared/src/store/action-reducers/alarm-group.ts @@ -10,12 +10,13 @@ import { AlarmGroup } from '../../models/alarm-group'; import { AlarmGroupVehicle } from '../../models/utils/alarm-group-vehicle'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { getElement } from './utils/get-element'; export class AddAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Add AlarmGroup' as const) public readonly type = '[AlarmGroup] Add AlarmGroup'; @ValidateNested() @@ -24,7 +25,7 @@ export class AddAlarmGroupAction implements Action { } export class RenameAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Rename AlarmGroup' as const) public readonly type = '[AlarmGroup] Rename AlarmGroup'; @IsUUID(4, uuidValidationOptions) @@ -34,14 +35,14 @@ export class RenameAlarmGroupAction implements Action { public readonly name!: string; } export class RemoveAlarmGroupAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Remove AlarmGroup' as const) public readonly type = '[AlarmGroup] Remove AlarmGroup'; @IsUUID(4, uuidValidationOptions) public readonly alarmGroupId!: UUID; } export class AddAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Add AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Add AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) @@ -52,7 +53,7 @@ export class AddAlarmGroupVehicleAction implements Action { public readonly alarmGroupVehicle!: AlarmGroupVehicle; } export class EditAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Edit AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Edit AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) @@ -69,7 +70,7 @@ export class EditAlarmGroupVehicleAction implements Action { public readonly name!: string; } export class RemoveAlarmGroupVehicleAction implements Action { - @IsString() + @IsValue('[AlarmGroup] Remove AlarmGroupVehicle' as const) public readonly type = '[AlarmGroup] Remove AlarmGroupVehicle'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/client.ts b/shared/src/store/action-reducers/client.ts index 37ae01b13..5c1438f22 100644 --- a/shared/src/store/action-reducers/client.ts +++ b/shared/src/store/action-reducers/client.ts @@ -1,18 +1,13 @@ import { Type } from 'class-transformer'; -import { - IsString, - ValidateNested, - IsUUID, - IsOptional, - IsBoolean, -} from 'class-validator'; +import { IsBoolean, IsOptional, IsUUID, ValidateNested } from 'class-validator'; import { Client } from '../../models'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddClientAction implements Action { - @IsString() + @IsValue('[Client] Add client' as const) public readonly type = '[Client] Add client'; @ValidateNested() @Type(() => Client) @@ -20,14 +15,14 @@ export class AddClientAction implements Action { } export class RemoveClientAction implements Action { - @IsString() + @IsValue('[Client] Remove client' as const) public readonly type = '[Client] Remove client'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; } export class RestrictViewToViewportAction implements Action { - @IsString() + @IsValue('[Client] Restrict to viewport' as const) public readonly type = '[Client] Restrict to viewport'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; @@ -37,7 +32,7 @@ export class RestrictViewToViewportAction implements Action { } export class SetWaitingRoomAction implements Action { - @IsString() + @IsValue('[Client] Set waitingroom' as const) public readonly type = '[Client] Set waitingroom'; @IsUUID(4, uuidValidationOptions) public readonly clientId!: UUID; diff --git a/shared/src/store/action-reducers/configuration.ts b/shared/src/store/action-reducers/configuration.ts index 6d9f906ec..d850e5635 100644 --- a/shared/src/store/action-reducers/configuration.ts +++ b/shared/src/store/action-reducers/configuration.ts @@ -1,11 +1,12 @@ import { Type } from 'class-transformer'; -import { IsBoolean, IsString, ValidateNested } from 'class-validator'; +import { IsBoolean, ValidateNested } from 'class-validator'; import { TileMapProperties } from '../../models/utils'; import { cloneDeepMutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; export class SetTileMapPropertiesAction implements Action { - @IsString() + @IsValue('[Configuration] Set tileMapProperties' as const) public readonly type = '[Configuration] Set tileMapProperties'; @ValidateNested() @@ -14,7 +15,7 @@ export class SetTileMapPropertiesAction implements Action { } export class SetPretriageEnabledAction implements Action { - @IsString() + @IsValue('[Configuration] Set pretriageEnabled' as const) public readonly type = '[Configuration] Set pretriageEnabled'; @IsBoolean() @@ -22,7 +23,7 @@ export class SetPretriageEnabledAction implements Action { } export class SetBluePatientsEnabledFlagAction implements Action { - @IsString() + @IsValue('[Configuration] Set bluePatientsEnabled' as const) public readonly type = '[Configuration] Set bluePatientsEnabled'; @IsBoolean() diff --git a/shared/src/store/action-reducers/emergency-operation-center.ts b/shared/src/store/action-reducers/emergency-operation-center.ts index d2ddcc094..71a0a7531 100644 --- a/shared/src/store/action-reducers/emergency-operation-center.ts +++ b/shared/src/store/action-reducers/emergency-operation-center.ts @@ -1,10 +1,11 @@ import { IsString, MaxLength } from 'class-validator'; import { EocLogEntry } from '../../models'; -import type { Action, ActionReducer } from '../action-reducer'; import { cloneDeepMutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import type { Action, ActionReducer } from '../action-reducer'; export class AddLogEntryAction implements Action { - @IsString() + @IsValue('[Emergency Operation Center] Add Log Entry' as const) public readonly type = '[Emergency Operation Center] Add Log Entry'; @IsString() @MaxLength(255) diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts index 35535ee9e..55a1fbba3 100644 --- a/shared/src/store/action-reducers/exercise.ts +++ b/shared/src/store/action-reducers/exercise.ts @@ -4,7 +4,6 @@ import { IsBoolean, IsInt, IsPositive, - IsString, ValidateNested, } from 'class-validator'; import type { Personnel, Vehicle } from '../../models'; @@ -12,6 +11,7 @@ import { Patient } from '../../models'; import { getStatus } from '../../models/utils'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { letElementArrive } from './transfer'; @@ -19,17 +19,17 @@ import { updateTreatments } from './utils/calculate-treatments'; import { PatientUpdate } from './utils/patient-updates'; export class PauseExerciseAction implements Action { - @IsString() + @IsValue('[Exercise] Pause' as const) public readonly type = '[Exercise] Pause'; } export class StartExerciseAction implements Action { - @IsString() + @IsValue('[Exercise] Start' as const) public readonly type = '[Exercise] Start'; } export class ExerciseTickAction implements Action { - @IsString() + @IsValue('[Exercise] Tick' as const) public readonly type = '[Exercise] Tick'; @IsArray() diff --git a/shared/src/store/action-reducers/hospital.ts b/shared/src/store/action-reducers/hospital.ts index 6e98dc9ed..0f2214691 100644 --- a/shared/src/store/action-reducers/hospital.ts +++ b/shared/src/store/action-reducers/hospital.ts @@ -9,12 +9,13 @@ import { import { Hospital } from '../../models'; import { HospitalPatient } from '../../models/hospital-patient'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; import { deleteVehicle } from './vehicle'; export class AddHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Add hospital' as const) public readonly type = '[Hospital] Add hospital'; @ValidateNested() @Type(() => Hospital) @@ -22,7 +23,7 @@ export class AddHospitalAction implements Action { } export class EditTransportDurationToHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Edit transportDuration to hospital' as const) public readonly type = '[Hospital] Edit transportDuration to hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -33,7 +34,7 @@ export class EditTransportDurationToHospitalAction implements Action { } export class RenameHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Rename hospital' as const) public readonly type = '[Hospital] Rename hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -43,14 +44,14 @@ export class RenameHospitalAction implements Action { } export class RemoveHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Remove hospital' as const) public readonly type = '[Hospital] Remove hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; } export class TransportPatientToHospitalAction implements Action { - @IsString() + @IsValue('[Hospital] Transport patient to hospital' as const) public readonly type = '[Hospital] Transport patient to hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; diff --git a/shared/src/store/action-reducers/map-image-templates.ts b/shared/src/store/action-reducers/map-image-templates.ts index 537172d72..d771cac2e 100644 --- a/shared/src/store/action-reducers/map-image-templates.ts +++ b/shared/src/store/action-reducers/map-image-templates.ts @@ -5,11 +5,12 @@ import { ImageProperties } from '../../models/utils'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; export class AddMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Add mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Add mapImageTemplate'; @ValidateNested() @@ -18,7 +19,7 @@ export class AddMapImageTemplateAction implements Action { } export class EditMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Edit mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Edit mapImageTemplate'; @IsUUID(4, uuidValidationOptions) @@ -33,7 +34,7 @@ export class EditMapImageTemplateAction implements Action { } export class DeleteMapImageTemplateAction implements Action { - @IsString() + @IsValue('[MapImageTemplate] Delete mapImageTemplate' as const) public readonly type = '[MapImageTemplate] Delete mapImageTemplate'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/map-images.ts b/shared/src/store/action-reducers/map-images.ts index f18af2372..26bce6329 100644 --- a/shared/src/store/action-reducers/map-images.ts +++ b/shared/src/store/action-reducers/map-images.ts @@ -18,11 +18,12 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Add MapImage' as const) public readonly type = '[MapImage] Add MapImage'; @ValidateNested() @@ -31,7 +32,7 @@ export class AddMapImageAction implements Action { } export class MoveMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Move MapImage' as const) public readonly type = '[MapImage] Move MapImage'; @IsUUID(4, uuidValidationOptions) @@ -43,7 +44,7 @@ export class MoveMapImageAction implements Action { } export class ScaleMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Scale MapImage' as const) public readonly type = '[MapImage] Scale MapImage'; @IsUUID(4, uuidValidationOptions) @@ -61,7 +62,7 @@ export class ScaleMapImageAction implements Action { } export class RemoveMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Remove MapImage' as const) public readonly type = '[MapImage] Remove MapImage'; @IsUUID(4, uuidValidationOptions) @@ -69,7 +70,7 @@ export class RemoveMapImageAction implements Action { } export class SetIsLockedMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Set isLocked' as const) public readonly type = '[MapImage] Set isLocked'; @IsUUID(4, uuidValidationOptions) @@ -80,32 +81,39 @@ export class SetIsLockedMapImageAction implements Action { } export class ReconfigureMapImageUrlAction implements Action { - @IsString() + @IsValue('[MapImage] Reconfigure Url' as const) public readonly type = '[MapImage] Reconfigure Url'; @IsUUID(4, uuidValidationOptions) public readonly mapImageId!: UUID; /** - * data URI or URL of new image + * Data URI or URL of new image */ @IsString() public readonly newUrl!: string; } +type ChangeZIndexActionMode = + | 'bringToBack' + | 'bringToFront' + | 'oneLayerBack' + | 'oneLayerForward'; + export class ChangeZIndexMapImageAction implements Action { - @IsString() + @IsValue('[MapImage] Change zIndex' as const) public readonly type = '[MapImage] Change zIndex'; @IsUUID(4, uuidValidationOptions) public readonly mapImageId!: UUID; - @IsString() - public readonly mode!: - | 'bringToBack' - | 'bringToFront' - | 'oneLayerBack' - | 'oneLayerForward'; + @IsLiteralUnion({ + bringToBack: true, + bringToFront: true, + oneLayerBack: true, + oneLayerForward: true, + }) + public readonly mode!: ChangeZIndexActionMode; } export namespace MapImagesActionReducers { diff --git a/shared/src/store/action-reducers/material.ts b/shared/src/store/action-reducers/material.ts index de5192175..a38b201ab 100644 --- a/shared/src/store/action-reducers/material.ts +++ b/shared/src/store/action-reducers/material.ts @@ -1,12 +1,13 @@ import { Type } from 'class-transformer'; -import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { IsUUID, ValidateNested } from 'class-validator'; import { Position } from '../../models/utils'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { updateElementPosition } from './utils/spatial-elements'; export class MoveMaterialAction implements Action { - @IsString() + @IsValue('[Material] Move material' as const) public readonly type = '[Material] Move material'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts index f2e63736a..277ab6e50 100644 --- a/shared/src/store/action-reducers/patient.ts +++ b/shared/src/store/action-reducers/patient.ts @@ -1,7 +1,11 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, MaxLength, ValidateNested } from 'class-validator'; import { Patient } from '../../models'; -import { PatientStatus, Position } from '../../models/utils'; +import { + PatientStatus, + patientStatusAllowedValues, + Position, +} from '../../models/utils'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { @@ -10,6 +14,7 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { updateTreatments } from './utils/calculate-treatments'; @@ -29,7 +34,7 @@ export function deletePatient( } export class AddPatientAction implements Action { - @IsString() + @IsValue('[Patient] Add patient' as const) public readonly type = '[Patient] Add patient'; @ValidateNested() @Type(() => Patient) @@ -37,7 +42,7 @@ export class AddPatientAction implements Action { } export class MovePatientAction implements Action { - @IsString() + @IsValue('[Patient] Move patient' as const) public readonly type = '[Patient] Move patient'; @IsUUID(4, uuidValidationOptions) @@ -49,25 +54,25 @@ export class MovePatientAction implements Action { } export class RemovePatientAction implements Action { - @IsString() + @IsValue('[Patient] Remove patient' as const) public readonly type = '[Patient] Remove patient'; @IsUUID(4, uuidValidationOptions) public readonly patientId!: UUID; } export class SetVisibleStatusAction implements Action { - @IsString() + @IsValue('[Patient] Set Visible Status' as const) public readonly type = '[Patient] Set Visible Status'; @IsUUID(4, uuidValidationOptions) public readonly patientId!: UUID; - @IsString() + @IsLiteralUnion(patientStatusAllowedValues) public readonly patientStatus!: PatientStatus; } export class SetUserTextAction implements Action { - @IsString() + @IsValue('[Patient] Set Remarks' as const) public readonly type = '[Patient] Set Remarks'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/personnel.ts b/shared/src/store/action-reducers/personnel.ts index 89cdeaae9..843c122ed 100644 --- a/shared/src/store/action-reducers/personnel.ts +++ b/shared/src/store/action-reducers/personnel.ts @@ -1,12 +1,13 @@ import { Type } from 'class-transformer'; -import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { IsUUID, ValidateNested } from 'class-validator'; import { Position } from '../../models/utils'; import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { updateElementPosition } from './utils/spatial-elements'; export class MovePersonnelAction implements Action { - @IsString() + @IsValue('[Personnel] Move personnel' as const) public readonly type = '[Personnel] Move personnel'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts index 51fe81602..dd55cbae0 100644 --- a/shared/src/store/action-reducers/transfer-point.ts +++ b/shared/src/store/action-reducers/transfer-point.ts @@ -8,7 +8,8 @@ import { } from 'class-validator'; import { TransferPoint } from '../../models'; import { Position } from '../../models/utils'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { letElementArrive } from './transfer'; @@ -18,7 +19,7 @@ import { getElement } from './utils/get-element'; // TODO check: type "TransferPoint" the T is big, in other files, the second word starts with a small letter export class AddTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Add TransferPoint' as const) public readonly type = `[TransferPoint] Add TransferPoint`; @ValidateNested() @Type(() => TransferPoint) @@ -26,7 +27,7 @@ export class AddTransferPointAction implements Action { } export class MoveTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Move TransferPoint' as const) public readonly type = '[TransferPoint] Move TransferPoint'; @IsUUID(4, uuidValidationOptions) @@ -38,7 +39,7 @@ export class MoveTransferPointAction implements Action { } export class RenameTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Rename TransferPoint' as const) public readonly type = '[TransferPoint] Rename TransferPoint'; @IsUUID(4, uuidValidationOptions) @@ -54,7 +55,7 @@ export class RenameTransferPointAction implements Action { } export class RemoveTransferPointAction implements Action { - @IsString() + @IsValue('[TransferPoint] Remove TransferPoint' as const) public readonly type = '[TransferPoint] Remove TransferPoint'; @IsUUID(4, uuidValidationOptions) @@ -62,7 +63,7 @@ export class RemoveTransferPointAction implements Action { } export class ConnectTransferPointsAction implements Action { - @IsString() + @IsValue('[TransferPoint] Connect TransferPoints' as const) public readonly type = '[TransferPoint] Connect TransferPoints'; @IsUUID(4, uuidValidationOptions) @@ -77,7 +78,7 @@ export class ConnectTransferPointsAction implements Action { } export class DisconnectTransferPointsAction implements Action { - @IsString() + @IsValue('[TransferPoint] Disconnect TransferPoints' as const) public readonly type = '[TransferPoint] Disconnect TransferPoints'; @IsUUID(4, uuidValidationOptions) @@ -88,7 +89,7 @@ export class DisconnectTransferPointsAction implements Action { } export class ConnectHospitalAction implements Action { - @IsString() + @IsValue('[TransferPoint] Connect hospital' as const) public readonly type = '[TransferPoint] Connect hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; @@ -98,7 +99,7 @@ export class ConnectHospitalAction implements Action { } export class DisconnectHospitalAction implements Action { - @IsString() + @IsValue('[TransferPoint] Disconnect hospital' as const) public readonly type = '[TransferPoint] Disconnect hospital'; @IsUUID(4, uuidValidationOptions) public readonly hospitalId!: UUID; diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index ad5362962..cd9f88fa9 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -1,17 +1,26 @@ -import { IsInt, IsObject, IsOptional, IsString, IsUUID } from 'class-validator'; -import type { ExerciseState, Position } from '../..'; -import { imageSizeToPosition, TransferPoint } from '../..'; -import { StartPoint } from '../../models/utils/start-points'; +import { Type } from 'class-transformer'; +import { IsInt, IsOptional, IsUUID, ValidateNested } from 'class-validator'; +import { TransferPoint } from '../../models'; +import type { Position } from '../../models/utils'; +import { StartPoint, startPointTypeOptions } from '../../models/utils'; +import type { ExerciseState } from '../../state'; +import { imageSizeToPosition } from '../../state-helpers'; import type { Mutable } from '../../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import type { AllowedValues } from '../../utils/validators'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; -import { getElement } from './utils/get-element'; +import { getElement } from './utils'; import { removeElementPosition, updateElementPosition, } from './utils/spatial-elements'; +type TransferableElementType = 'personnel' | 'vehicles'; +const transferableElementTypeAllowedValues: AllowedValues = + { personnel: true, vehicles: true }; + /** * Personnel/Vehicle in transfer will arrive immediately at new targetTransferPoint * Transfer gets deleted afterwards @@ -19,7 +28,7 @@ import { */ export function letElementArrive( draftState: Mutable, - elementType: 'personnel' | 'vehicles', + elementType: TransferableElementType, elementId: UUID ) { const element = getElement(draftState, elementType, elementId); @@ -48,16 +57,17 @@ export function letElementArrive( } export class AddToTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Add to transfer' as const) public readonly type = '[Transfer] Add to transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; - @IsObject() + @ValidateNested() + @Type(() => Object, startPointTypeOptions) public readonly startPoint!: StartPoint; @IsUUID(4, uuidValidationOptions) @@ -65,11 +75,11 @@ export class AddToTransferAction implements Action { } export class EditTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Edit transfer' as const) public readonly type = '[Transfer] Edit transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; @@ -89,11 +99,11 @@ export class EditTransferAction implements Action { } export class FinishTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Finish transfer' as const) public readonly type = '[Transfer] Finish transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; @@ -103,11 +113,11 @@ export class FinishTransferAction implements Action { } export class TogglePauseTransferAction implements Action { - @IsString() + @IsValue('[Transfer] Toggle pause transfer' as const) public readonly type = '[Transfer] Toggle pause transfer'; - @IsString() - elementType!: 'personnel' | 'vehicles'; + @IsLiteralUnion(transferableElementTypeAllowedValues) + elementType!: TransferableElementType; @IsUUID(4, uuidValidationOptions) public readonly elementId!: UUID; diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts index 6f4d2a433..6db4d99bb 100644 --- a/shared/src/store/action-reducers/vehicle.ts +++ b/shared/src/store/action-reducers/vehicle.ts @@ -11,6 +11,7 @@ import { UUID, uuidValidationOptions, } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { deletePatient } from './patient'; @@ -43,7 +44,7 @@ export function deleteVehicle( } export class AddVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Add vehicle' as const) public readonly type = '[Vehicle] Add vehicle'; @ValidateNested() @Type(() => Vehicle) @@ -61,7 +62,7 @@ export class AddVehicleAction implements Action { } export class RenameVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Rename vehicle' as const) public readonly type = '[Vehicle] Rename vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; @@ -71,7 +72,7 @@ export class RenameVehicleAction implements Action { } export class MoveVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Move vehicle' as const) public readonly type = '[Vehicle] Move vehicle'; @IsUUID(4, uuidValidationOptions) @@ -83,27 +84,31 @@ export class MoveVehicleAction implements Action { } export class RemoveVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Remove vehicle' as const) public readonly type = '[Vehicle] Remove vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; } export class UnloadVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Unload vehicle' as const) public readonly type = '[Vehicle] Unload vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; } export class LoadVehicleAction implements Action { - @IsString() + @IsValue('[Vehicle] Load vehicle' as const) public readonly type = '[Vehicle] Load vehicle'; @IsUUID(4, uuidValidationOptions) public readonly vehicleId!: UUID; - @IsString() + @IsLiteralUnion({ + materials: true, + patients: true, + personnel: true, + }) public readonly elementToBeLoadedType!: | 'materials' | 'patients' diff --git a/shared/src/store/action-reducers/viewport.ts b/shared/src/store/action-reducers/viewport.ts index 98a5e07a2..13c3b1919 100644 --- a/shared/src/store/action-reducers/viewport.ts +++ b/shared/src/store/action-reducers/viewport.ts @@ -2,12 +2,13 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { Viewport } from '../../models'; import { Position, Size } from '../../models/utils'; -import { uuidValidationOptions, UUID, cloneDeepMutable } from '../../utils'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; export class AddViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Add viewport' as const) readonly type = '[Viewport] Add viewport'; @ValidateNested() @Type(() => Viewport) @@ -15,14 +16,14 @@ export class AddViewportAction implements Action { } export class RemoveViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Remove viewport' as const) public readonly type = '[Viewport] Remove viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; } export class MoveViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Move viewport' as const) public readonly type = '[Viewport] Move viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @@ -32,7 +33,7 @@ export class MoveViewportAction implements Action { } export class ResizeViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Resize viewport' as const) public readonly type = '[Viewport] Resize viewport'; @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @@ -45,7 +46,7 @@ export class ResizeViewportAction implements Action { } export class RenameViewportAction implements Action { - @IsString() + @IsValue('[Viewport] Rename viewport' as const) public readonly type = '[Viewport] Rename viewport'; @IsUUID(4, uuidValidationOptions) diff --git a/shared/src/store/validate-exercise-action.ts b/shared/src/store/validate-exercise-action.ts index 1c95dfba4..3c25697ea 100644 --- a/shared/src/store/validate-exercise-action.ts +++ b/shared/src/store/validate-exercise-action.ts @@ -1,7 +1,13 @@ import { plainToInstance } from 'class-transformer'; -import type { ValidationError } from 'class-validator'; +import type { + ValidationArguments, + ValidationError, + ValidationOptions, +} from 'class-validator'; import { validateSync } from 'class-validator'; import type { Constructor } from '../utils'; +import type { GenericPropertyDecorator } from '../utils/validators/generic-property-decorator'; +import { makeValidator } from '../utils/validators/make-validator'; import type { ExerciseAction } from './action-reducers'; import { getExerciseActionTypeDictionary } from './action-reducers'; import { defaultValidateOptions } from './validation-options'; @@ -30,3 +36,21 @@ export function validateExerciseAction( defaultValidateOptions ); } + +// Decorators for validation +// Placed here instead of in utils/validators to prevent circular imports + +export function isExerciseAction(value: unknown): value is ExerciseAction { + return validateExerciseAction(value as ExerciseAction).length === 0; +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsExerciseAction( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isExerciseAction', + (value: unknown, args?: ValidationArguments) => isExerciseAction(value), + validationOptions + ); +} diff --git a/shared/src/store/validate-exercise-export.ts b/shared/src/store/validate-exercise-export.ts index 276d3cc78..747047fa3 100644 --- a/shared/src/store/validate-exercise-export.ts +++ b/shared/src/store/validate-exercise-export.ts @@ -4,7 +4,6 @@ import { validateSync } from 'class-validator'; import type { ExportImportFile } from '../export-import/file-format'; import { PartialExport, StateExport } from '../export-import/file-format'; import type { Constructor } from '../utils'; -import { validateExerciseAction } from './validate-exercise-action'; import { defaultValidateOptions } from './validation-options'; /** @@ -35,12 +34,5 @@ export function validateExerciseExport( ), defaultValidateOptions ); - if (exportImportFile.type === 'complete' && exportImportFile.history) { - validationErrors.push( - ...exportImportFile.history.actionHistory.flatMap((action) => - validateExerciseAction(action) - ) - ); - } return validationErrors; } diff --git a/shared/src/utils/validators/combine-decorators.ts b/shared/src/utils/validators/combine-decorators.ts new file mode 100644 index 000000000..d48c1fef8 --- /dev/null +++ b/shared/src/utils/validators/combine-decorators.ts @@ -0,0 +1,37 @@ +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +// Source: https://github.com/nestjs/nest/blob/a448f53b7746d35bf25a18f1759c971e5b7fea1c/packages/common/decorators/core/apply-decorators.ts + +/** + * @param decorators one or more decorators (e.g., `IsString(...)`) + * @returns a new decorator that applies all the provided decorators + * + * Useful to build new decorators (or a decorator factory) encapsulating multiple decorators + */ +export function combineDecorators( + ...decorators: Array< + | ClassDecorator + | GenericPropertyDecorator + | MethodDecorator + | PropertyDecorator + > +) { + // eslint-disable-next-line @typescript-eslint/ban-types + return ( + target: TFunction | object, + propertyKey?: string | symbol, + descriptor?: TypedPropertyDescriptor + ) => { + for (const decorator of decorators) { + if (target instanceof Function && !descriptor) { + (decorator as ClassDecorator)(target); + continue; + } + (decorator as MethodDecorator | PropertyDecorator)( + target, + propertyKey!, + descriptor! + ); + } + }; +} diff --git a/shared/src/utils/validators/create-map-validator.ts b/shared/src/utils/validators/create-map-validator.ts new file mode 100644 index 000000000..7d8716bc6 --- /dev/null +++ b/shared/src/utils/validators/create-map-validator.ts @@ -0,0 +1,38 @@ +export interface MapValidationFunctions { + keyValidator: (key: number | string | symbol) => key is K; + valueValidator: (value: unknown) => value is V; + consistencyValidator?: (key: string, value: unknown) => boolean; +} + +/** + * The provided flow is as follows: + * + * 1. It's checked whether `valueToBeValidated` is of type `object` + * 2. It's checked whether `valueToBeValidated` is not `null` + * 3. For every key-value pair of the object, the following are verified: + * 1. It's checked whether the key fulfills {@link keyValidator} + * 2. It's checked whether the transformed value is valid using {@link valueValidator} + * 3. When {@link consistencyValidator} is provided, it's applied to the key and value + * + * This process is guaranteed to be short-circuiting, so later steps can rely on a successful earlier step. + */ +export function createMapValidator({ + keyValidator, + valueValidator, + consistencyValidator, +}: MapValidationFunctions): ( + valueToBeValidated: unknown +) => valueToBeValidated is { [key in K]: V } { + return ( + valueToBeValidated: unknown + ): valueToBeValidated is { [key in K]: V } => + typeof valueToBeValidated === 'object' && + valueToBeValidated !== null && + Object.entries(valueToBeValidated).every( + ([key, value]: [string, unknown]) => + keyValidator(key) && + valueValidator(value) && + (consistencyValidator === undefined || + consistencyValidator(key, value as V)) + ); +} diff --git a/shared/src/utils/validators/generic-property-decorator.ts b/shared/src/utils/validators/generic-property-decorator.ts new file mode 100644 index 000000000..8ea7ab03f --- /dev/null +++ b/shared/src/utils/validators/generic-property-decorator.ts @@ -0,0 +1,13 @@ +/** + * T The type the decorated property in the class must be. This only works for public properties. + * Each Whether the Decorator is used to validate an array (https://github.com/typestack/class-validator#validating-arrays) + */ +export type GenericPropertyDecorator = < + Target extends { + readonly [key in Key]: Each extends true ? readonly T[] : T; + }, + Key extends string +>( + target: Target, + propertyKey: Key +) => void; diff --git a/shared/src/utils/validators/index.ts b/shared/src/utils/validators/index.ts new file mode 100644 index 000000000..04aec4b96 --- /dev/null +++ b/shared/src/utils/validators/index.ts @@ -0,0 +1,7 @@ +// TODO: Propagate the errors from subobjects + +export * from './is-id-map'; +export * from './is-reachable-transfer-points-object'; +export * from './is-literal-union'; +export * from './is-uuid-set'; +export * from './is-value'; diff --git a/shared/src/utils/validators/is-id-map.ts b/shared/src/utils/validators/is-id-map.ts new file mode 100644 index 000000000..3b2e201e7 --- /dev/null +++ b/shared/src/utils/validators/is-id-map.ts @@ -0,0 +1,48 @@ +import { plainToInstance, Transform } from 'class-transformer'; +import type { ValidationOptions } from 'class-validator'; +import { isUUID, ValidateNested } from 'class-validator'; +import type { Constructor } from '../constructor'; +import type { UUID } from '../uuid'; +import { combineDecorators } from './combine-decorators'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +// An `isIdMap` function is omitted. +// It's currently not used and it's not trivial to migrate the decorator approach below +// to a standalone function. +// For reference, such an implementation once existed as part of https://github.com/hpi-sam/digital-fuesim-manv/pull/125. + +/** + * An `IdMap` is of type `{ readonly [key: UUID]: T }` + * + * @property getId A function to get the id that is used as the key in the object. Defaults to `.id`, this might be wrong for some types, though. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsIdMap( + type: Constructor, + getId: (value: T) => UUID = (value) => (value as { id: UUID }).id, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator<{ readonly [key: UUID]: T }, Each> { + const transform = Transform( + (params) => { + const plainChildren = params.value as { [key: UUID]: T }; + if (Object.keys(plainChildren).some((key) => !isUUID(key, 4))) { + return 'invalid'; + } + const instanceChildrenWithKey = Object.entries(plainChildren).map( + ([key, plainChild]) => + [key, plainToInstance(type, plainChild)] as const + ); + if ( + instanceChildrenWithKey.some( + ([key, child]) => getId(child) !== key + ) + ) { + return 'invalid'; + } + return instanceChildrenWithKey.map(([, child]) => child); + }, + { toClassOnly: true } + ); + const validateNested = ValidateNested({ ...validationOptions, each: true }); + return combineDecorators(transform, validateNested); +} diff --git a/shared/src/utils/validators/is-literal-union.ts b/shared/src/utils/validators/is-literal-union.ts new file mode 100644 index 000000000..5b4455f37 --- /dev/null +++ b/shared/src/utils/validators/is-literal-union.ts @@ -0,0 +1,58 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isIn } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +/** + * A type for validating unions of string literals. + * + * @example + * ````ts + * type StringLiteralUnion = 'a' | 'b'; + * + * const stringLiteralUnionAllowedValues: AllowedValues = { + * a: true, + * b: true, + * }; + * + * class MyClassToValidate { + * @IsLiteralUnion(stringLiteralUnionAllowedValues) + * public readonly myString: StringLiteralUnion; + * } + * + * ```` + */ +export type AllowedValues = { + [key in T]: true; +}; + +export function isLiteralUnion( + allowedValues: AllowedValues, + valueToBeValidated: unknown +): boolean { + return isIn(valueToBeValidated, Object.keys(allowedValues)); +} + +/** + * A validator to check whether a property is part of a literal union type. + * + * Only literal types that may be keys of objects, i.e. `number`, `string`, and `symbol`, are allowed. + * @param allowedValues {@link AllowedValues} that specify which values may be present. + * @param validationOptions {@link ValidationOptions} passed on to `class-validator`. + * @returns A `class-validator` validator that verifies that the value is in the keys of {@link allowedValues}. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsLiteralUnion< + T extends number | string | symbol, + Each extends boolean = false +>( + allowedValues: AllowedValues, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isLiteralUnion', + (value: unknown, args?: ValidationArguments) => + isLiteralUnion(allowedValues, value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-reachable-transfer-points-object.ts b/shared/src/utils/validators/is-reachable-transfer-points-object.ts new file mode 100644 index 000000000..362390edb --- /dev/null +++ b/shared/src/utils/validators/is-reachable-transfer-points-object.ts @@ -0,0 +1,33 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isUUID, isNumber, min } from 'class-validator'; +import type { ReachableTransferPoints } from '../../models/transfer-point'; +import type { UUID } from '../uuid'; +import { createMapValidator } from './create-map-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +export const isReachableTransferPoints = createMapValidator< + UUID, + ReachableTransferPoints +>({ + keyValidator: ((key) => isUUID(key, 4)) as (key: unknown) => key is UUID, + valueValidator: ((value) => + typeof value === 'object' && + value !== null && + isNumber((value as { duration: number }).duration) && + min((value as { duration: number }).duration, 0)) as ( + value: unknown + ) => value is ReachableTransferPoints, +}); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsReachableTransferPoints( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isReachableTransferPoints', + (value: unknown, args?: ValidationArguments) => + isReachableTransferPoints(value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-uuid-set.ts b/shared/src/utils/validators/is-uuid-set.ts new file mode 100644 index 000000000..8e586a497 --- /dev/null +++ b/shared/src/utils/validators/is-uuid-set.ts @@ -0,0 +1,27 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isUUID } from 'class-validator'; +import type { UUID } from '../uuid'; +import type { UUIDSet } from '../uuid-set'; +import { createMapValidator } from './create-map-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +export const isUUIDSet = createMapValidator({ + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + keyValidator: <(key: unknown) => key is UUID>((key) => isUUID(key, 4)), + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + valueValidator: <(value: unknown) => value is true>( + ((value) => value === true) + ), +}); + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsUUIDSet( + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isUUIDSet', + (value: unknown, args?: ValidationArguments) => isUUIDSet(value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/is-value.ts b/shared/src/utils/validators/is-value.ts new file mode 100644 index 000000000..0f6ee8e59 --- /dev/null +++ b/shared/src/utils/validators/is-value.ts @@ -0,0 +1,45 @@ +import type { ValidationOptions, ValidationArguments } from 'class-validator'; +import { isIn } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; +import { makeValidator } from './make-validator'; + +/** + * Check whether two values are identical, using {@link isIn} from `class-validator`. + * + * As of `class-validator` version `0.14.0`, this means that the equality check is doen with `===`. + * @param expectedValue The single value that is allowed. + * @param valueToBeValidated The actual value. + * @returns Whether the values are identical. + */ +export function isValue< + T extends bigint | boolean | number | string | symbol | null | undefined +>(expectedValue: T, valueToBeValidated: unknown): boolean { + return isIn(valueToBeValidated, [expectedValue]); +} + +/** + * A validator for a constant value. Uses {@link isIn} for validation, all limitations of this validator apply. + * + * This means that, as of `class-validator` version `0.14.0`, `===` is used for equality checks. + * + * It is highly recommended to use `as const` with this decorator to enable better type checking. + * @param expectedValue The single value that is allowed for this property. + * @param validationOptions {@link ValidationOptions} passed on to `class-validator`. + * @returns A `class-validator` validator that verifies that the value is exactly {@link expectedValue}. + */ +// TODO [typescript@>=5.0]: Use `const T` (https://github.com/microsoft/TypeScript/pull/51865) (and remove doc comment about `as const`) +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsValue< + T extends bigint | boolean | number | string | symbol | null | undefined, + Each extends boolean = false +>( + expectedValue: T, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + return makeValidator( + 'isValue', + (value: unknown, args?: ValidationArguments) => + isValue(expectedValue, value), + validationOptions + ); +} diff --git a/shared/src/utils/validators/make-validator.ts b/shared/src/utils/validators/make-validator.ts new file mode 100644 index 000000000..2a37f2920 --- /dev/null +++ b/shared/src/utils/validators/make-validator.ts @@ -0,0 +1,31 @@ +import type { ValidationArguments, ValidationOptions } from 'class-validator'; +import { registerDecorator } from 'class-validator'; +import type { GenericPropertyDecorator } from './generic-property-decorator'; + +export function makeValidator( + name: `is${string}`, + validationFunction: ( + value: unknown, + validationArguments?: ValidationArguments + ) => boolean, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator { + // Disabled as this is the suggested way for [class-validator](https://github.com/typestack/class-validator#custom-validation-decorators) + // eslint-disable-next-line @typescript-eslint/ban-types + return function (object: Object, propertyName: string) { + registerDecorator({ + name, + target: object.constructor, + propertyName, + options: { + message: + validationOptions?.message ?? + `Value must be a correct ${name.slice(2)}`, + ...validationOptions, + }, + validator: { + validate: validationFunction, + }, + }); + }; +} From e5f194f91091113fc0a608dc689457ba8ee47bc4 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Mon, 2 Jan 2023 18:14:14 +0100 Subject: [PATCH 02/58] Feature/state benchmark (#581) * Move state migrations to shared * Add benchmark package * Update readmes * Make problem with duplicated RestoreError more obvious --- .eslint/typescript.eslintrc.cjs | 2 +- .gitignore | 3 + .prettierignore | 3 + README.md | 8 +- backend/README.md | 5 - backend/src/database/migrate-in-database.ts | 94 + .../state-migrations/impossible-migration.ts | 18 - .../database/state-migrations/migrations.ts | 227 -- backend/src/exercise/exercise-wrapper.ts | 28 +- backend/src/utils/import-exercise.ts | 2 +- benchmark/.eslintrc.json | 21 + benchmark/.gitignore | 3 + benchmark/README.md | 21 + .../empty-state-version-14.permanent.json | 1 + benchmark/package-lock.json | 3224 +++++++++++++++++ benchmark/package.json | 35 + benchmark/src/app.ts | 99 + benchmark/src/benchmark-step.ts | 46 + benchmark/src/benchmark.ts | 81 + benchmark/src/calculation-step.ts | 29 + benchmark/src/print.ts | 32 + benchmark/src/step.ts | 43 + benchmark/src/steps.ts | 264 ++ benchmark/tsconfig.json | 22 + package.json | 5 +- shared/README.md | 6 +- shared/src/index.ts | 1 + .../10-rename-delete-transfer-action.ts | 5 +- .../11-add-map-image-is-locked.ts | 5 +- .../12-rename-incorrect-patient-images.ts | 4 +- .../13-add-map-image-zindex.ts | 5 +- ...rsonnel-and-material-templates-to-state.ts | 4 +- .../src}/state-migrations/3-update-eoc-log.ts | 5 +- .../4-remove-set-participant-id-action.ts | 4 +- .../state-migrations/5-remove-statistics.ts | 2 +- .../6-remove-state-history.ts | 4 +- .../state-migrations/7-add-patient-remarks.ts | 5 +- .../8-treatment-system-improvements.ts | 9 +- .../9-remove-is-being-treated.ts | 5 +- .../state-migrations/impossible-migration.ts | 29 + shared/src/state-migrations/index.ts | 1 + .../state-migrations/migration-functions.ts | 54 + .../src}/state-migrations/migrations.spec.ts | 4 +- shared/src/state-migrations/migrations.ts | 76 + shared/src/utils/index.ts | 1 + shared/src/utils/sort-object.spec.ts | 55 + shared/src/utils/sort-object.ts | 24 + 47 files changed, 4325 insertions(+), 299 deletions(-) create mode 100644 backend/src/database/migrate-in-database.ts delete mode 100644 backend/src/database/state-migrations/impossible-migration.ts delete mode 100644 backend/src/database/state-migrations/migrations.ts create mode 100644 benchmark/.eslintrc.json create mode 100644 benchmark/.gitignore create mode 100644 benchmark/README.md create mode 100644 benchmark/data/empty-state-version-14.permanent.json create mode 100644 benchmark/package-lock.json create mode 100644 benchmark/package.json create mode 100644 benchmark/src/app.ts create mode 100644 benchmark/src/benchmark-step.ts create mode 100644 benchmark/src/benchmark.ts create mode 100644 benchmark/src/calculation-step.ts create mode 100644 benchmark/src/print.ts create mode 100644 benchmark/src/step.ts create mode 100644 benchmark/src/steps.ts create mode 100644 benchmark/tsconfig.json rename {backend/src/database => shared/src}/state-migrations/10-rename-delete-transfer-action.ts (71%) rename {backend/src/database => shared/src}/state-migrations/11-add-map-image-is-locked.ts (82%) rename {backend/src/database => shared/src}/state-migrations/12-rename-incorrect-patient-images.ts (92%) rename {backend/src/database => shared/src}/state-migrations/13-add-map-image-zindex.ts (82%) rename {backend/src/database => shared/src}/state-migrations/14-add-personnel-and-material-templates-to-state.ts (96%) rename {backend/src/database => shared/src}/state-migrations/3-update-eoc-log.ts (90%) rename {backend/src/database => shared/src}/state-migrations/4-remove-set-participant-id-action.ts (78%) rename {backend/src/database => shared/src}/state-migrations/5-remove-statistics.ts (74%) rename {backend/src/database => shared/src}/state-migrations/6-remove-state-history.ts (89%) rename {backend/src/database => shared/src}/state-migrations/7-add-patient-remarks.ts (81%) rename {backend/src/database => shared/src}/state-migrations/8-treatment-system-improvements.ts (95%) rename {backend/src/database => shared/src}/state-migrations/9-remove-is-being-treated.ts (82%) create mode 100644 shared/src/state-migrations/impossible-migration.ts create mode 100644 shared/src/state-migrations/index.ts create mode 100644 shared/src/state-migrations/migration-functions.ts rename {backend/src/database => shared/src}/state-migrations/migrations.spec.ts (76%) create mode 100644 shared/src/state-migrations/migrations.ts create mode 100644 shared/src/utils/sort-object.spec.ts create mode 100644 shared/src/utils/sort-object.ts diff --git a/.eslint/typescript.eslintrc.cjs b/.eslint/typescript.eslintrc.cjs index 641970e2d..16c63261e 100644 --- a/.eslint/typescript.eslintrc.cjs +++ b/.eslint/typescript.eslintrc.cjs @@ -19,7 +19,7 @@ module.exports = { 'no-console': [ 'warn', { - allow: ['log', 'warn', 'error', 'assert'], + allow: ['log', 'warn', 'error', 'assert', 'table'], }, ], 'no-promise-executor-return': 'warn', diff --git a/.gitignore b/.gitignore index 657964f6a..930b28bed 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,6 @@ backend/coverage shared/coverage shared/tsconfig.build.tsbuildinfo + +benchmark/data/* +!benchmark/data/*.permanent.json diff --git a/.prettierignore b/.prettierignore index 2098131c8..20069305f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,6 @@ backend/src/database/migrations/ docker-compose.yml # same, but probably not needed .env.example + +# The states in here should not be touched by humans +benchmark/data diff --git a/README.md b/README.md index b430efbd7..f74d27424 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,11 @@ If a test fails a new screenshot is taken and put in the `comparison` folder. If the new screenshot is the new desired result, then you only have to move it in the `baseline` folder and replace the old reference screenshot with the same name. In the `diff` folder you can see the changes between the baseline and the comparison screenshot. +## Benchmarking + +You can run the benchmarks via `npm run benchmark` in the root folder. +Look at the [benchmark readme](./benchmark/README.md) for more information. + ## Styleguide - names are never unique, ids are @@ -172,7 +177,8 @@ This repository is a monorepo that consists of the following packages: - [frontend](./frontend) the browser-based client application ([Angular](https://angular.io/)) - [backend](./backend) the server-side application ([NodeJs](https://nodejs.org/)) -- [shared](./shared) the shared code that is used by both frontend and backend +- [benchmark](./benchmark/) benchmarks and tests some parts of the application +- [shared](./shared) the shared code that is used by the frontend, backend and the benchmark package Each package has its own `README.md` file with additional documentation. Please check them out before you start working on the project. diff --git a/backend/README.md b/backend/README.md index e9faca3af..41d55de4e 100644 --- a/backend/README.md +++ b/backend/README.md @@ -99,11 +99,6 @@ If you want to, you can also disable the database. Set the environment variable `DFM_USE_DB` (in [`../.env`](../.env)) to `false` to achieve this. Note however that this results in a) all history being saved in memory instead of on disk, and b) once the backend exits, for whatever reason, all data is gone forever. -### Migrations - -We use [state migrations](./src/database/state-migrations/) to convert outdated states to new versions. -Look at [`migrations.ts`](./src/database/state-migrations/migrations.ts) for more information. - ### Note on long term storage The current setup when using a database is that no exercises get deleted unless anyone deletes them from the UI (or, more precisely, using the HTTP request `DELETE /api/exercises/:exerciseId`). diff --git a/backend/src/database/migrate-in-database.ts b/backend/src/database/migrate-in-database.ts new file mode 100644 index 000000000..83501e4dc --- /dev/null +++ b/backend/src/database/migrate-in-database.ts @@ -0,0 +1,94 @@ +import type { UUID } from 'digital-fuesim-manv-shared'; +import { applyMigrations } from 'digital-fuesim-manv-shared'; +import type { EntityManager } from 'typeorm'; +import { RestoreError } from '../utils/restore-error'; +import { ActionWrapperEntity } from './entities/action-wrapper.entity'; +import { ExerciseWrapperEntity } from './entities/exercise-wrapper.entity'; + +export async function migrateInDatabase( + exerciseId: UUID, + entityManager: EntityManager +): Promise { + const exercise = await entityManager.findOne(ExerciseWrapperEntity, { + where: { id: exerciseId }, + }); + if (exercise === null) { + throw new RestoreError( + 'Cannot find exercise to convert in database', + exerciseId + ); + } + const initialState = JSON.parse(exercise.initialStateString); + const currentState = JSON.parse(exercise.currentStateString); + const actions = ( + await entityManager.find(ActionWrapperEntity, { + where: { exercise: { id: exerciseId } }, + select: { actionString: true }, + order: { index: 'ASC' }, + }) + ).map((action) => JSON.parse(action.actionString)); + const newVersion = applyMigrations(exercise.stateVersion, { + currentState, + history: { + initialState, + actions, + }, + }); + exercise.stateVersion = newVersion; + // Save exercise wrapper + const patch: Partial = { + stateVersion: exercise.stateVersion, + }; + patch.initialStateString = JSON.stringify(initialState); + patch.currentStateString = JSON.stringify(currentState); + await entityManager.update( + ExerciseWrapperEntity, + { id: exerciseId }, + patch + ); + // Save actions + if (actions !== undefined) { + let patchedActionsIndex = 0; + const indicesToRemove: number[] = []; + const actionsToUpdate: { + previousIndex: number; + newIndex: number; + actionString: string; + }[] = []; + actions.forEach((action, i) => { + if (action === null) { + indicesToRemove.push(i); + return; + } + actionsToUpdate.push({ + previousIndex: i, + newIndex: patchedActionsIndex++, + actionString: JSON.stringify(action), + }); + }); + if (indicesToRemove.length > 0) { + await entityManager + .createQueryBuilder() + .delete() + .from(ActionWrapperEntity) + // eslint-disable-next-line unicorn/string-content + .where('index IN (:...ids)', { ids: indicesToRemove }) + .execute(); + } + if (actionsToUpdate.length > 0) { + await Promise.all( + actionsToUpdate.map( + async ({ previousIndex, newIndex, actionString }) => + entityManager.update( + ActionWrapperEntity, + { + index: previousIndex, + exercise: { id: exerciseId }, + }, + { actionString, index: newIndex } + ) + ) + ); + } + } +} diff --git a/backend/src/database/state-migrations/impossible-migration.ts b/backend/src/database/state-migrations/impossible-migration.ts deleted file mode 100644 index 0de739d2d..000000000 --- a/backend/src/database/state-migrations/impossible-migration.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { UUID } from 'digital-fuesim-manv-shared'; -import { RestoreError } from '../../utils/restore-error'; -import type { Migration } from './migrations'; - -export const impossibleMigration: Migration = { - actions: (initialState, actions) => { - throw new RestoreError( - 'The migration is not possible', - (initialState as { id?: UUID }).id ?? 'unknown' - ); - }, - state: (state) => { - throw new RestoreError( - 'The migration is not possible', - (state as { id?: UUID }).id ?? 'unknown' - ); - }, -}; diff --git a/backend/src/database/state-migrations/migrations.ts b/backend/src/database/state-migrations/migrations.ts deleted file mode 100644 index 5cf3450e8..000000000 --- a/backend/src/database/state-migrations/migrations.ts +++ /dev/null @@ -1,227 +0,0 @@ -import type { - UUID, - StateExport, - Mutable, - ExerciseAction, -} from 'digital-fuesim-manv-shared'; -import { - cloneDeepMutable, - ExerciseState, - applyAllActions, -} from 'digital-fuesim-manv-shared'; -import type { EntityManager } from 'typeorm'; -import { RestoreError } from '../../utils/restore-error'; -import { ActionWrapperEntity } from '../entities/action-wrapper.entity'; -import { ExerciseWrapperEntity } from '../entities/exercise-wrapper.entity'; -import { addMapImageZIndex13 } from './13-add-map-image-zindex'; -import { updateEocLog3 } from './3-update-eoc-log'; -import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; -import { removeStatistics5 } from './5-remove-statistics'; -import { removeStateHistory6 } from './6-remove-state-history'; -import { addPatientRemarks7 } from './7-add-patient-remarks'; -import { treatmentSystemImprovements8 } from './8-treatment-system-improvements'; -import { removeIsBeingTreated9 } from './9-remove-is-being-treated'; -import { renameDeleteTransferAction10 } from './10-rename-delete-transfer-action'; -import { addMapImageIsLocked11 } from './11-add-map-image-is-locked'; -import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-images'; -import { impossibleMigration } from './impossible-migration'; -import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; - -/** - * Such a function gets the already migrated initial state of the exercise and an array of all actions (not yet migrated). - * It is expected that afterwards the actions in the provided array are migrated. - * It is not allowed to modify the order of the actions, to add an action or to remove an action. - * To indicate that an action should be removed it can be replaced by `null`. - * It may throw a {@link RestoreError} when a migration is not possible. - */ -type MigrateActionsFunction = ( - initialState: object, - actions: (object | null)[] -) => void; - -/** - * Such a function gets the not yet migrated state and is expected to mutate it to a migrated version. - * It may throw a {@link RestoreError} when a migration is not possible. - */ -type MigrateStateFunction = (state: object) => void; - -export interface Migration { - actions: MigrateActionsFunction | null; - state: MigrateStateFunction | null; -} - -// TODO: It'd probably be better not to export this -export const migrations: { - [key: number]: Migration; -} = { - 2: impossibleMigration, - 3: updateEocLog3, - 4: removeSetParticipantIdAction4, - 5: removeStatistics5, - 6: removeStateHistory6, - 7: addPatientRemarks7, - 8: treatmentSystemImprovements8, - 9: removeIsBeingTreated9, - 10: renameDeleteTransferAction10, - 11: addMapImageIsLocked11, - 12: renameIncorrectPatientImages12, - 13: addMapImageZIndex13, - 14: addPersonnelAndMaterialToState14, -}; - -export async function migrateInDatabase( - exerciseId: UUID, - entityManager: EntityManager -): Promise { - const exercise = await entityManager.findOne(ExerciseWrapperEntity, { - where: { id: exerciseId }, - }); - if (exercise === null) { - throw new RestoreError( - 'Cannot find exercise to convert in database', - exerciseId - ); - } - const initialState = JSON.parse(exercise.initialStateString); - const currentState = JSON.parse(exercise.currentStateString); - const actions = ( - await entityManager.find(ActionWrapperEntity, { - where: { exercise: { id: exerciseId } }, - select: { actionString: true }, - order: { index: 'ASC' }, - }) - ).map((action) => JSON.parse(action.actionString)); - const newVersion = applyMigrations(exercise.stateVersion, { - currentState, - history: { - initialState, - actions, - }, - }); - exercise.stateVersion = newVersion; - // Save exercise wrapper - const patch: Partial = { - stateVersion: exercise.stateVersion, - }; - patch.initialStateString = JSON.stringify(initialState); - patch.currentStateString = JSON.stringify(currentState); - await entityManager.update( - ExerciseWrapperEntity, - { id: exerciseId }, - patch - ); - // Save actions - if (actions !== undefined) { - let patchedActionsIndex = 0; - const indicesToRemove: number[] = []; - const actionsToUpdate: { - previousIndex: number; - newIndex: number; - actionString: string; - }[] = []; - actions.forEach((action, i) => { - if (action === null) { - indicesToRemove.push(i); - return; - } - actionsToUpdate.push({ - previousIndex: i, - newIndex: patchedActionsIndex++, - actionString: JSON.stringify(action), - }); - }); - if (indicesToRemove.length > 0) { - await entityManager - .createQueryBuilder() - .delete() - .from(ActionWrapperEntity) - // eslint-disable-next-line unicorn/string-content - .where('index IN (:...ids)', { ids: indicesToRemove }) - .execute(); - } - if (actionsToUpdate.length > 0) { - await Promise.all( - actionsToUpdate.map( - async ({ previousIndex, newIndex, actionString }) => - entityManager.update( - ActionWrapperEntity, - { - index: previousIndex, - exercise: { id: exerciseId }, - }, - { actionString, index: newIndex } - ) - ) - ); - } - } -} - -export function migrateStateExport( - stateExportToMigrate: StateExport -): Mutable { - const stateExport = cloneDeepMutable(stateExportToMigrate); - const propertiesToMigrate = { - currentState: stateExport.currentState, - history: stateExport.history - ? { - initialState: stateExport.history.initialState, - actions: stateExport.history.actionHistory, - } - : undefined, - }; - const newVersion = applyMigrations( - stateExport.dataVersion, - propertiesToMigrate - ); - stateExport.dataVersion = newVersion; - stateExport.currentState = propertiesToMigrate.currentState; - if (stateExport.history) { - stateExport.history.actionHistory = - // Remove actions that are marked to be removed by the migrations - propertiesToMigrate.history!.actions.filter( - (action) => action !== null - ); - } - return stateExport; -} - -/** - * Migrates {@link propertiesToMigrate} to the newest version ({@link ExerciseState.currentStateVersion}) - * by mutating them. - * - * @returns The new state version - */ -function applyMigrations( - currentStateVersion: number, - propertiesToMigrate: { - currentState: object; - history?: { initialState: object; actions: (object | null)[] }; - } -): number { - const targetVersion = ExerciseState.currentStateVersion; - for (let i = currentStateVersion + 1; i <= targetVersion; i++) { - const stateMigration = migrations[i]!.state; - if (stateMigration !== null) { - if (propertiesToMigrate.history) - stateMigration(propertiesToMigrate.history.initialState); - else stateMigration(propertiesToMigrate.currentState); - } - if (!propertiesToMigrate.history) continue; - const actionMigration = migrations[i]!.actions; - if (actionMigration !== null) { - actionMigration( - propertiesToMigrate.history.initialState, - propertiesToMigrate.history.actions - ); - } - } - if (propertiesToMigrate.history) - propertiesToMigrate.currentState = applyAllActions( - propertiesToMigrate.history.initialState as ExerciseState, - propertiesToMigrate.history.actions.filter( - (action) => action !== null - ) as ExerciseAction[] - ); - return targetVersion; -} diff --git a/backend/src/exercise/exercise-wrapper.ts b/backend/src/exercise/exercise-wrapper.ts index f0ff834cf..73a50ea2d 100644 --- a/backend/src/exercise/exercise-wrapper.ts +++ b/backend/src/exercise/exercise-wrapper.ts @@ -1,33 +1,33 @@ -import type { EntityManager } from 'typeorm'; -import { LessThan } from 'typeorm'; import type { ExerciseAction, - StateExport, ExerciseIds, + ExerciseTimeline, Role, + StateExport, UUID, - ExerciseTimeline, } from 'digital-fuesim-manv-shared'; import { - ExerciseState, - cloneDeepMutable, applyAction, - ReducerError, + cloneDeepMutable, + ExerciseState, reduceExerciseState, - validateExerciseState, + ReducerError, validateExerciseAction, + validateExerciseState, } from 'digital-fuesim-manv-shared'; -import { IncrementIdGenerator } from '../utils/increment-id-generator'; -import { ValidationErrorWrapper } from '../utils/validation-error-wrapper'; +import type { EntityManager } from 'typeorm'; +import { LessThan } from 'typeorm'; +import { Config } from '../config'; +import type { ActionWrapperEntity } from '../database/entities/action-wrapper.entity'; import { ExerciseWrapperEntity } from '../database/entities/exercise-wrapper.entity'; +import { migrateInDatabase } from '../database/migrate-in-database'; import { NormalType } from '../database/normal-type'; import type { DatabaseService } from '../database/services/database-service'; -import { Config } from '../config'; +import { pushAll, removeAll } from '../utils/array'; +import { IncrementIdGenerator } from '../utils/increment-id-generator'; import { RestoreError } from '../utils/restore-error'; import { UserReadableIdGenerator } from '../utils/user-readable-id-generator'; -import type { ActionWrapperEntity } from '../database/entities/action-wrapper.entity'; -import { migrateInDatabase } from '../database/state-migrations/migrations'; -import { pushAll, removeAll } from '../utils/array'; +import { ValidationErrorWrapper } from '../utils/validation-error-wrapper'; import { ActionWrapper } from './action-wrapper'; import type { ClientWrapper } from './client-wrapper'; import { exerciseMap } from './exercise-map'; diff --git a/backend/src/utils/import-exercise.ts b/backend/src/utils/import-exercise.ts index a1d34d1e8..54ca04939 100644 --- a/backend/src/utils/import-exercise.ts +++ b/backend/src/utils/import-exercise.ts @@ -1,12 +1,12 @@ import { plainToInstance } from 'class-transformer'; import type { ExerciseIds } from 'digital-fuesim-manv-shared'; import { + migrateStateExport, ReducerError, StateExport, validateExerciseExport, } from 'digital-fuesim-manv-shared'; import type { DatabaseService } from '../database/services/database-service'; -import { migrateStateExport } from '../database/state-migrations/migrations'; import { ExerciseWrapper } from '../exercise/exercise-wrapper'; import type { HttpResponse } from '../exercise/http-handler/utils'; diff --git a/benchmark/.eslintrc.json b/benchmark/.eslintrc.json new file mode 100644 index 000000000..4509eeec6 --- /dev/null +++ b/benchmark/.eslintrc.json @@ -0,0 +1,21 @@ +{ + "root": true, + "overrides": [ + { + "files": ["*.ts", "*.js"], + "parserOptions": { + "project": ["tsconfig.json"], + "createDefaultProgram": true, + // TODO: No idea why eslint seems to look for the tsconfig in the root directory instead of relative to this config + // It doesn't seem to do this in "shared" + "tsconfigRootDir": "./benchmark" + }, + "parser": "@typescript-eslint/parser", + "extends": [ + "../.eslint/typescript.eslintrc.cjs", + "../.eslint/total-functions.eslintrc.cjs", + "prettier" + ] + } + ] +} diff --git a/benchmark/.gitignore b/benchmark/.gitignore new file mode 100644 index 000000000..29637c64e --- /dev/null +++ b/benchmark/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +data/* +!data/*.permanent.json diff --git a/benchmark/README.md b/benchmark/README.md new file mode 100644 index 000000000..89655a918 --- /dev/null +++ b/benchmark/README.md @@ -0,0 +1,21 @@ +# Benchmarks + +This package contains benchmarks that can be used to + +- track and compare the performance of different exerciseExports +- check different exerciseExports and the current reducers for correctness +- test migrations on different exerciseExports +- run custom benchmarks and tests - good for fast prototyping + +## Running the benchmarks + +The benchmarks are run on all exerciseExports in [`data/`](data/). +To test custom or confidential exerciseExports, add them to the [`data/`](data/) folder. Only exerciseExports ending with `.permanent.json` are tracked by git. +The benchmarks can be run with `npm run benchmark`. + +## Architecture + +The entry point to the benchmarks is [`src/app.ts`](src/app.ts). + +If you want to check the implementation of a specific benchmark or want to add a new one look in [`src/steps.ts`](src/steps.ts). +To add a new benchmark, add a new step to the `steps` array in [`src/steps.ts`](src/steps.ts) and modify the stepState. diff --git a/benchmark/data/empty-state-version-14.permanent.json b/benchmark/data/empty-state-version-14.permanent.json new file mode 100644 index 000000000..97efd5bb5 --- /dev/null +++ b/benchmark/data/empty-state-version-14.permanent.json @@ -0,0 +1 @@ +{"fileVersion":1,"dataVersion":14,"type":"complete","currentState":{"id":"c1bffad0-e5d3-49ef-930e-21a9a2d1c5d0","currentTime":0,"currentStatus":"notStarted","viewports":{},"vehicles":{},"personnel":{},"patients":{},"materials":{},"mapImages":{},"transferPoints":{},"hospitals":{},"hospitalPatients":{},"alarmGroups":{},"clients":{"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559":{"id":"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559","name":"","role":"trainer","isInWaitingRoom":false}},"patientCategories":[{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"6868cf32-ae03-45c7-a9c7-0f0ade65b03b","biometricInformation":{"sex":"female","externalFeatures":"blaue Augen, rothaarig, 1,69 m","age":16},"pretriageInformation":{"injuries":"Prellmarke an der Stirn; blutende Wunde am linken Unterarm","bodyCheck":"leichte Schmerzen beim Auftreten im rechten Sprunggelenk; Schwanger; sonst o.B.","breathing":"unauffällig","awareness":"leicht verwirrt","pulse":"79; gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"D"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"ac7c0497-583c-4622-b064-842b117be2d2","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,72 m","age":35},"pretriageInformation":{"injuries":"keine äußeren Verletzungen sichtbar","bodyCheck":"Pat. ist teilnahmslos; keine Kooperation bei der Untersuchung","breathing":"unauffällig","awareness":"verwirrt","pulse":"82; Puls gut tastbar","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"535508d9-4a42-4981-87e0-b3609e953a1d":{"id":"535508d9-4a42-4981-87e0-b3609e953a1d","functionParameters":{"constantChange":-6.944444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"535508d9-4a42-4981-87e0-b3609e953a1d","health":100000},{"id":"1b3dbb5f-501f-4d64-9772-beb5077917bf","biometricInformation":{"sex":"male","externalFeatures":"1,89 m, Vollbart, blond, blauäugig","age":25},"pretriageInformation":{"injuries":"keine äußeren Verletzungen zu sehen","bodyCheck":"Pat. ist nahezu hysterisch; es besteht keine Kooperation bei Untersuchung","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"94","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7d9d3abc-fbf9-4838-9907-f97d952921b2":{"id":"7d9d3abc-fbf9-4838-9907-f97d952921b2","functionParameters":{"constantChange":-6.313131313131313,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"7d9d3abc-fbf9-4838-9907-f97d952921b2","health":100000},{"id":"719964b6-1be7-4489-84a0-0cc78f71ae78","biometricInformation":{"sex":"female","externalFeatures":"1,76m, hellblond, blaue Augen, Brille","age":35},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"keine Kooperation bei Untersuchung; Pat. hysterisch und verwirrt","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"95","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"a242b15a-1651-40f9-b91f-41256e64e278":{"id":"a242b15a-1651-40f9-b91f-41256e64e278","functionParameters":{"constantChange":-5.787037037037037,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"a242b15a-1651-40f9-b91f-41256e64e278","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"21a4b49c-9334-4f2e-8e44-728b89dfe002","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,79 m, adipös","age":50},"pretriageInformation":{"injuries":"leichte Augenverletzung rechts","bodyCheck":"Pat. wirkt apathisch; keine Kooperation bei Untersuchung; Prellung Unterschenkel rechts; starke Schmerzen nur beim Auftreten","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"83; Puls flach","skin":"unauffällig","pain":"stark, aber nur beim Auftreten","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9aaf7336-75ca-4850-82e5-a1607efd6a7f":{"id":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","functionParameters":{"constantChange":-9.920634920634921,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","health":100000},{"id":"b9dea356-e5e9-464d-a0cd-350d495c59c1","biometricInformation":{"sex":"female","externalFeatures":"1,59 m, blaue Augen, graue Haare","age":65},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"leichter Druckschmerzen im linkes Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"89","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"2a650e54-6c69-42cd-acfd-7b1da8ea767c":{"id":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","functionParameters":{"constantChange":-8.680555555555555,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"786a06fa-53a5-4bc9-a003-5bbda97fba68","biometricInformation":{"sex":"male","externalFeatures":"Spitzbart, blaue Augen, blonde Haare, 182 cm","age":52},"pretriageInformation":{"injuries":"leicht blutende Wunde an der linken Hand, evt. Glassplitter in der Tiefe sichtbar; Prellmarke rechte Schläfe","bodyCheck":"leichte Schmerzen beim Auftreten im linken Fuß","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"85; Puls gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9dea5618-e952-4ace-b209-0a9dfd25039d":{"id":"9dea5618-e952-4ace-b209-0a9dfd25039d","functionParameters":{"constantChange":-34.72222222222222,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"1bcda560-31ad-4b62-9204-92909a863a18","maximumHealth":50000}]},"1bcda560-31ad-4b62-9204-92909a863a18":{"id":"1bcda560-31ad-4b62-9204-92909a863a18","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"2affe314-2858-46b3-b058-aa5df912496e","earliestTime":1440000}]},"2affe314-2858-46b3-b058-aa5df912496e":{"id":"2affe314-2858-46b3-b058-aa5df912496e","functionParameters":{"constantChange":16.203703703703702,"notarztModifier":48.611111111111114,"notSanModifier":48.611111111111114,"rettSanModifier":48.611111111111114},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9dea5618-e952-4ace-b209-0a9dfd25039d","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8be494f4-2ed0-4f79-bcb2-f491499f604f","biometricInformation":{"sex":"female","externalFeatures":"1,66 m, blond, blaue Augen","age":30},"pretriageInformation":{"injuries":"Zeigefingeramputation rechts","bodyCheck":"dezenter Druckschmerzen im rechten Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"98; rhythmisch","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9f2c922b-6b2c-40e0-8a2d-699df90fd564":{"id":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","functionParameters":{"constantChange":-7.716049382716049,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","maximumHealth":50000}]},"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4":{"id":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":90.27777777777777,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"73e03d5d-ec75-434f-b975-d9369587dee4","earliestTime":720000}]},"73e03d5d-ec75-434f-b975-d9369587dee4":{"id":"73e03d5d-ec75-434f-b975-d9369587dee4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":100000},{"matchingHealthStateId":"590514f7-bad9-4762-b06d-dd54a67ad2ad","earliestTime":720000}]},"590514f7-bad9-4762-b06d-dd54a67ad2ad":{"id":"590514f7-bad9-4762-b06d-dd54a67ad2ad","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":93.05555555555556,"notSanModifier":93.05555555555556,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"Z","behaviourCode":"B"},"thirdField":{"colorCode":"Z","behaviourCode":"C"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"7d8db924-24b6-43a4-a1a9-b3acd7785329","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, blaue Augen, 1,69 m, Brille","age":76},"pretriageInformation":{"injuries":"keine äußeren Verletzungen","bodyCheck":"dezenter Druckschmerzen im linken Bein in Höhe der Patella","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"warm, rot","pain":"keine","pupils":"isocor","psyche":"sehr aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b3671073-e1b2-43fb-9d20-499ddf8f15d9":{"id":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","functionParameters":{"constantChange":-17.36111111111111,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"03e6df66-9069-4fe4-b887-6feeb251f4bd","maximumHealth":50000}]},"03e6df66-9069-4fe4-b887-6feeb251f4bd":{"id":"03e6df66-9069-4fe4-b887-6feeb251f4bd","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","maximumHealth":20000}]},"8300f7bf-05b9-4f46-9098-ecb7eda9775d":{"id":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","functionParameters":{"constantChange":-27.77777777777778,"notarztModifier":27.77777777777778,"notSanModifier":27.77777777777778,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","earliestTime":2880000}]},"3e8874cd-6f2a-452e-9259-c905ab7e6e57":{"id":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","health":100000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"db84352c-c0e2-4c72-b404-f8838c2f7e56","biometricInformation":{"sex":"male","externalFeatures":"dunkle Haare, braune Augen, Muttermal Stirn, 165 cm","age":14},"pretriageInformation":{"injuries":"Kunststofffremdkörper linker Oberarm; Schulterfraktur links; Luxationsfraktur rechtes Handgelenk","bodyCheck":"Risswunde am Hinterkopf; Hüftprellung rechts","breathing":"unauffällig","awareness":"wach, orientiert","pulse":"124; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"98e5d181-6472-489b-8ecf-24f195ccaa00":{"id":"98e5d181-6472-489b-8ecf-24f195ccaa00","functionParameters":{"constantChange":4.444444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"98e5d181-6472-489b-8ecf-24f195ccaa00","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9c72ee24-1dba-4ab9-a2b4-302d22659e21","biometricInformation":{"sex":"male","externalFeatures":"blaue Augen, weiße Haare, 174 cm","age":72},"pretriageInformation":{"injuries":"Fehlstellung linker Oberarm; offene Fraktur Unterarm links; große Platzwunde Kopf; Handquetschung links; Dialysepatient","bodyCheck":"Schlüsselbeinfraktur rechts; Thoraxprellung auf der gleichen Seite","breathing":"unauffällig","awareness":"wach und orientiert","pulse":"122; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5":{"id":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"676414f6-f8e2-40b6-9c81-b666a9156572","earliestTime":2880000}]},"676414f6-f8e2-40b6-9c81-b666a9156572":{"id":"676414f6-f8e2-40b6-9c81-b666a9156572","functionParameters":{"constantChange":0,"notarztModifier":22.22222222222222,"notSanModifier":22.22222222222222,"rettSanModifier":22.22222222222222},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"Y","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"63c7f1c7-2c5b-4e1a-8427-91c67216d0d1","biometricInformation":{"sex":"male","externalFeatures":"Vollbart, blond, blaue Augen, 1,87 m","age":55},"pretriageInformation":{"injuries":"Prellmarke Unterschenkel rechts; Fehlstellung rechtes Sprunggelenk; Wunde Unterarm rechts","bodyCheck":"Druckschmerz rechte Hüfte; Prellung Unterschenkel links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"123; Puls flach","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"54443596-73be-426d-9ef7-96fbc3bf4839":{"id":"54443596-73be-426d-9ef7-96fbc3bf4839","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","earliestTime":2880000}]},"ab5b1286-1904-42a0-a9e1-2ddea8579ce6":{"id":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":33000}]}},"startingHealthStateId":"54443596-73be-426d-9ef7-96fbc3bf4839","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"1713df33-edcb-45c0-9136-f03c563e312c","biometricInformation":{"sex":"male","externalFeatures":"Glatze, graublaue Augen, Brille, 174 cm","age":57},"pretriageInformation":{"injuries":"leicht blutende Wunde Unterarm links; grobe Fehlstellung rechtes Sprunggelenk; Prellmarke Unterschenkel rechts","bodyCheck":"Druckschmerz linke Hüfte; Prellung Unterschenkel links; Schmerzen im Genitalbereich","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"122; Puls kräftig","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"D"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"154647a0-aa9c-4887-a7b3-c1b03e018c3d","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, braune Augen, ca. 1,70 m","age":71},"pretriageInformation":{"injuries":"rechte Hand stark schmerzhaft; kleine blutende Platzwunde am Kopf; Glasfremdkörper am ganzen rechten Arm; unstillbares Nasenbluten","bodyCheck":"Thoraxprellung links; Schlüsselbeinfraktur links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"132; Puls kräftig","skin":"kühl, blass","pain":"starke","pupils":"isocor","psyche":"aggressiv","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"ec613c7e-b8f0-4f20-a25f-83858af6243d":{"id":"ec613c7e-b8f0-4f20-a25f-83858af6243d","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","maximumHealth":20000}]},"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2":{"id":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","functionParameters":{"constantChange":20.833333333333332,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6bfd72c1-059e-485d-a397-501ccf5e4531","minimumHealth":50000}]},"6bfd72c1-059e-485d-a397-501ccf5e4531":{"id":"6bfd72c1-059e-485d-a397-501ccf5e4531","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6fe239b8-b8a0-47f2-8608-59dc11401221","earliestTime":2160000}]},"6fe239b8-b8a0-47f2-8608-59dc11401221":{"id":"6fe239b8-b8a0-47f2-8608-59dc11401221","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"e5f07410-b137-4be2-8676-bf413bc559c5","earliestTime":720000}]},"e5f07410-b137-4be2-8676-bf413bc559c5":{"id":"e5f07410-b137-4be2-8676-bf413bc559c5","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6e24dba3-b987-4266-ba76-3d9d06501315","earliestTime":720000}]},"6e24dba3-b987-4266-ba76-3d9d06501315":{"id":"6e24dba3-b987-4266-ba76-3d9d06501315","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":50000},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"ec613c7e-b8f0-4f20-a25f-83858af6243d","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9abdfe8f-ac7c-4a42-9d0c-3a1ec5e09238","biometricInformation":{"sex":"female","externalFeatures":"grüne Augen, grauhaarig, 1,68 m, adipös, Brille","age":51},"pretriageInformation":{"injuries":"starke Schmerzen am linken Sprunggelenk; Prellmarke und Schürfwunde linker Unterschenkel","bodyCheck":"Beckenprellung, Fraktur nicht auszuschließen","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"kaltschweißig","pain":"stärkste","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"02156cc6-b3f0-4041-a079-ba95b387c1a0":{"id":"02156cc6-b3f0-4041-a079-ba95b387c1a0","functionParameters":{"constantChange":-10.416666666666666,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a31b9df5-7993-4a34-8851-b474ea23c094","maximumHealth":20000}]},"a31b9df5-7993-4a34-8851-b474ea23c094":{"id":"a31b9df5-7993-4a34-8851-b474ea23c094","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"02156cc6-b3f0-4041-a079-ba95b387c1a0","health":50000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"A"},"thirdField":{"colorCode":"Z","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"afdd27cc-2281-468f-a0d8-a8bc187b8e18","biometricInformation":{"sex":"male","externalFeatures":"1,86 m, Glatze, braune Augen, Brille","age":60},"pretriageInformation":{"injuries":"Prellmarken linker Thorax; offene Oberarmfraktur rechts","bodyCheck":"Rippenserienfraktur li.; Beckenprellung rechts; Hämatom hinter dem rechten Ohr; einseitig hebender Thorax rechts","breathing":"flache Schonatmung","awareness":"somnolent","pulse":"134; Puls fadenförmig","skin":"zyanotisch","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"11357873-6d12-41ce-a7dd-129fadd9fc20","biometricInformation":{"sex":"male","externalFeatures":"1,84 m, braune Augen, Brille, braune Haare","age":15},"pretriageInformation":{"injuries":"Weichteilquetschung rechter Unterschenkel, mäßig blutend, aber schon deutlicher Blutverlust","bodyCheck":"Oberschenkelfraktur rechts; kleiner Eisenfremdkörper in der linken Hand","breathing":"flache Atmung","awareness":"somnolent","pulse":"154; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"686cd1dd-d265-48f7-93d3-94928056a3e7","biometricInformation":{"sex":"female","externalFeatures":"1,75 m, blonde Haare, blaue Augen, Brille, extrem adipös","age":50},"pretriageInformation":{"injuries":"Kopfplatzwunde über dem Ohr; Prellmarke Stirn; Gesicht blutverschmiert","bodyCheck":"Unterarmfraktur rechts","breathing":"Atemwegsverlegung","awareness":"bewusstlos, Massenbewegungen auf Schmerz","pulse":"85; gut tastbar","skin":"tief zyanotisch","pain":"entfällt","pupils":"rechts weit","psyche":"entfällt","hearing":"entfällt","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"5d9ff1e5-10ae-4910-940f-3eb37f4bc5f7","biometricInformation":{"sex":"female","externalFeatures":"1,72 m, braune Augen, blonde Haare","age":25},"pretriageInformation":{"injuries":"offene Fraktur rechter Unterschenkel, nur noch mäßig blutend, aber schon großer Blutverlust; Wunde linke Schläfe; schwanger ca. 36 SSW","bodyCheck":"schulternahe Oberarmfraktur rechts; linke Hand mit Fehlstellung im Handgelenk","breathing":"flache Atmung","awareness":"somnolent","pulse":"150; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8f87e7fc-3226-466c-bee7-ba04a93d8637","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, grüne Augen, ca. 1,60 m","age":80},"pretriageInformation":{"injuries":"große Weichteilquetschung linker Unterschenkel, nur noch mäßig blutend; aber schon deutlicher Blutverlust","bodyCheck":"Oberarmfraktur rechts; fraglicher Fremdkörper rechte Hand in Wunde; blutende Prellmarke am Hinterkopf","breathing":"flache Atmung","awareness":"somnolent","pulse":"132; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b0c3cbcf-448a-4eb4-8c71-4a94d338a531":{"id":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"d51fc779-8d12-44cc-96cc-ec689c41ff02","earliestTime":2160000}]},"d51fc779-8d12-44cc-96cc-ec689c41ff02":{"id":"d51fc779-8d12-44cc-96cc-ec689c41ff02","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":1440000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"4382691d-53ea-4eeb-931e-146a5e35ea85","biometricInformation":{"sex":"male","externalFeatures":"1,78m, Bart, schwarzhaarig, braune Augen","age":50},"pretriageInformation":{"injuries":"Teil-Amputation rechter Unterarm, spritzend blutend; schon großer Blutverlust","bodyCheck":"geschlossene Oberschenkelfraktur links; Metallfremdkörper rechter Unterschenkel","breathing":"flache Atmung","awareness":"somnolent","pulse":"145; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b72fa6f0-eacc-43a9-a7a7-7764107d17b1":{"id":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":2160000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"V","behaviourCode":"E"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"3c407f4b-012a-4314-a50b-2e334110284e","biometricInformation":{"sex":"female","externalFeatures":"1,64 m, blaue Augen, blond","age":55},"pretriageInformation":{"injuries":"starke Schmerzen im gesamten Abdomen mit gespannter Bauchdecke","bodyCheck":"Prellmarken und Wunde linke Flanke; Rippenserienfraktur links","breathing":"schwere Atemnot 30/min.","awareness":"wach, verwirrt","pulse":"114; flach","skin":"kühl, blass","pain":"starke Bauchschmerzen","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","health":20000}]}],"vehicleTemplates":[{"id":"5ac07da0-c7dc-43ef-94ee-af023966eeeb","vehicleType":"RTW","name":"RTW ???","image":{"url":"/assets/rtw-vehicle.png","height":100,"aspectRatio":2.211377245508982},"patientCapacity":1,"personnel":["notSan","rettSan"],"materials":["standard"]},{"id":"a3d76307-35d8-47ee-8fda-7445c65bf909","vehicleType":"KTW","name":"KTW ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":1,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"a6e71070-6b57-45d3-8863-800428e006f4","vehicleType":"KTW (KatSchutz)","name":"KTW (KatSchutz) ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":2,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"3d7d1950-20a0-4625-a3c0-1dd9d5c7ccc0","vehicleType":"GW-San","name":"GW-San ???","image":{"url":"/assets/gwSan-vehicle.png","height":120,"aspectRatio":2.021018593371059},"patientCapacity":0,"personnel":["gf","rettSan","rettSan","san","san","notarzt"],"materials":["big","big","big","big"]},{"id":"fc8782ac-9567-4bcd-8a5a-8d31f608f03d","vehicleType":"NEF","name":"NEF ???","image":{"url":"/assets/nef-vehicle.png","height":70,"aspectRatio":2.4120194910665944},"patientCapacity":0,"personnel":["notarzt","notSan"],"materials":["standard"]},{"id":"c0690dad-e6be-452f-85e0-2dd942241315","vehicleType":"Tragetrupp","name":"Tragetrupp ???","image":{"url":"/assets/carrying-unit.svg","height":210,"aspectRatio":1},"patientCapacity":1,"personnel":[],"materials":[]},{"id":"cad2cc9b-a624-4020-aa5f-180ed0160f33","vehicleType":"RTH","name":"RTH ???","image":{"url":"/assets/rth-vehicle.svg","height":300,"aspectRatio":2.3846153846153846},"patientCapacity":1,"personnel":["notarzt","notSan"],"materials":["standard"]}],"materialTemplates":{"standard":{"materialType":"standard","canCaterFor":{"red":2,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/material.svg","height":40,"aspectRatio":1}},"big":{"materialType":"big","canCaterFor":{"red":2,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":10,"image":{"url":"/assets/material.svg","height":56,"aspectRatio":1}}},"personnelTemplates":{"san":{"personnelType":"san","canCaterFor":{"red":0,"yellow":0,"green":5,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/san-personnel.svg","height":80,"aspectRatio":1}},"rettSan":{"personnelType":"rettSan","canCaterFor":{"red":1,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/rettSan-personnel.svg","height":80,"aspectRatio":1}},"notSan":{"personnelType":"notSan","canCaterFor":{"red":2,"yellow":1,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/notSan-personnel.svg","height":80,"aspectRatio":1}},"notarzt":{"personnelType":"notarzt","canCaterFor":{"red":2,"yellow":2,"green":2,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":15,"image":{"url":"/assets/notarzt-personnel.svg","height":80,"aspectRatio":1}},"gf":{"personnelType":"gf","canCaterFor":{"red":0,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":0,"treatmentRange":0,"image":{"url":"/assets/gf-personnel.svg","height":80,"aspectRatio":1}}},"mapImageTemplates":[{"id":"90db6ee0-b8ba-4131-bc87-264fc218fa8f","name":"Feuer","image":{"url":"/assets/fire.svg","height":427,"aspectRatio":0.7330210772833724}},{"id":"9b27ad1c-d1d0-4bd1-9e93-e62d50969085","name":"Brennendes Haus","image":{"url":"/assets/house-fire.svg","height":623,"aspectRatio":0.6308186195826645}}],"eocLog":[],"participantId":"657034","spatialTrees":{"materials":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"patients":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"personnel":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}}},"configuration":{"pretriageEnabled":true,"bluePatientsEnabled":false,"tileMapProperties":{"tileUrl":"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}","maxZoom":20}}},"history":{"actionHistory":[{"type":"[Client] Add client","client":{"id":"1a4d8d3f-3a6d-47af-9a23-bfc814d1b559","name":"","role":"trainer","isInWaitingRoom":false}}],"initialState":{"id":"c1bffad0-e5d3-49ef-930e-21a9a2d1c5d0","currentTime":0,"currentStatus":"notStarted","viewports":{},"vehicles":{},"personnel":{},"patients":{},"materials":{},"mapImages":{},"transferPoints":{},"hospitals":{},"hospitalPatients":{},"alarmGroups":{},"clients":{},"patientCategories":[{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"6868cf32-ae03-45c7-a9c7-0f0ade65b03b","biometricInformation":{"sex":"female","externalFeatures":"blaue Augen, rothaarig, 1,69 m","age":16},"pretriageInformation":{"injuries":"Prellmarke an der Stirn; blutende Wunde am linken Unterarm","bodyCheck":"leichte Schmerzen beim Auftreten im rechten Sprunggelenk; Schwanger; sonst o.B.","breathing":"unauffällig","awareness":"leicht verwirrt","pulse":"79; gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"D"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"ac7c0497-583c-4622-b064-842b117be2d2","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,72 m","age":35},"pretriageInformation":{"injuries":"keine äußeren Verletzungen sichtbar","bodyCheck":"Pat. ist teilnahmslos; keine Kooperation bei der Untersuchung","breathing":"unauffällig","awareness":"verwirrt","pulse":"82; Puls gut tastbar","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"535508d9-4a42-4981-87e0-b3609e953a1d":{"id":"535508d9-4a42-4981-87e0-b3609e953a1d","functionParameters":{"constantChange":-6.944444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"535508d9-4a42-4981-87e0-b3609e953a1d","health":100000},{"id":"1b3dbb5f-501f-4d64-9772-beb5077917bf","biometricInformation":{"sex":"male","externalFeatures":"1,89 m, Vollbart, blond, blauäugig","age":25},"pretriageInformation":{"injuries":"keine äußeren Verletzungen zu sehen","bodyCheck":"Pat. ist nahezu hysterisch; es besteht keine Kooperation bei Untersuchung","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"94","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7d9d3abc-fbf9-4838-9907-f97d952921b2":{"id":"7d9d3abc-fbf9-4838-9907-f97d952921b2","functionParameters":{"constantChange":-6.313131313131313,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"7d9d3abc-fbf9-4838-9907-f97d952921b2","health":100000},{"id":"719964b6-1be7-4489-84a0-0cc78f71ae78","biometricInformation":{"sex":"female","externalFeatures":"1,76m, hellblond, blaue Augen, Brille","age":35},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"keine Kooperation bei Untersuchung; Pat. hysterisch und verwirrt","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"95","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"hysterisch","hearing":"schwerhörig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"a242b15a-1651-40f9-b91f-41256e64e278":{"id":"a242b15a-1651-40f9-b91f-41256e64e278","functionParameters":{"constantChange":-5.787037037037037,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":50000}]}},"startingHealthStateId":"a242b15a-1651-40f9-b91f-41256e64e278","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"21a4b49c-9334-4f2e-8e44-728b89dfe002","biometricInformation":{"sex":"female","externalFeatures":"braune Haare, braune Augen, 1,79 m, adipös","age":50},"pretriageInformation":{"injuries":"leichte Augenverletzung rechts","bodyCheck":"Pat. wirkt apathisch; keine Kooperation bei Untersuchung; Prellung Unterschenkel rechts; starke Schmerzen nur beim Auftreten","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"83; Puls flach","skin":"unauffällig","pain":"stark, aber nur beim Auftreten","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9aaf7336-75ca-4850-82e5-a1607efd6a7f":{"id":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","functionParameters":{"constantChange":-9.920634920634921,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9aaf7336-75ca-4850-82e5-a1607efd6a7f","health":100000},{"id":"b9dea356-e5e9-464d-a0cd-350d495c59c1","biometricInformation":{"sex":"female","externalFeatures":"1,59 m, blaue Augen, graue Haare","age":65},"pretriageInformation":{"injuries":"äußerlich keine Verletzungen","bodyCheck":"leichter Druckschmerzen im linkes Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"89","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"2a650e54-6c69-42cd-acfd-7b1da8ea767c":{"id":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","functionParameters":{"constantChange":-8.680555555555555,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","maximumHealth":50000}]},"a6905bd4-506a-4559-9b09-e68fbbb63c4e":{"id":"a6905bd4-506a-4559-9b09-e68fbbb63c4e","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","earliestTime":720000}]},"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34":{"id":"d9138d7e-50d5-42b1-b2ba-a99e56a6ad34","functionParameters":{"constantChange":48.611111111111114,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"2a650e54-6c69-42cd-acfd-7b1da8ea767c","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"X","behaviourCode":"D"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"786a06fa-53a5-4bc9-a003-5bbda97fba68","biometricInformation":{"sex":"male","externalFeatures":"Spitzbart, blaue Augen, blonde Haare, 182 cm","age":52},"pretriageInformation":{"injuries":"leicht blutende Wunde an der linken Hand, evt. Glassplitter in der Tiefe sichtbar; Prellmarke rechte Schläfe","bodyCheck":"leichte Schmerzen beim Auftreten im linken Fuß","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"85; Puls gut tastbar","skin":"unauffällig","pain":"leichte","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9dea5618-e952-4ace-b209-0a9dfd25039d":{"id":"9dea5618-e952-4ace-b209-0a9dfd25039d","functionParameters":{"constantChange":-34.72222222222222,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"1bcda560-31ad-4b62-9204-92909a863a18","maximumHealth":50000}]},"1bcda560-31ad-4b62-9204-92909a863a18":{"id":"1bcda560-31ad-4b62-9204-92909a863a18","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"2affe314-2858-46b3-b058-aa5df912496e","earliestTime":1440000}]},"2affe314-2858-46b3-b058-aa5df912496e":{"id":"2affe314-2858-46b3-b058-aa5df912496e","functionParameters":{"constantChange":16.203703703703702,"notarztModifier":48.611111111111114,"notSanModifier":48.611111111111114,"rettSanModifier":48.611111111111114},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9dea5618-e952-4ace-b209-0a9dfd25039d","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8be494f4-2ed0-4f79-bcb2-f491499f604f","biometricInformation":{"sex":"female","externalFeatures":"1,66 m, blond, blaue Augen","age":30},"pretriageInformation":{"injuries":"Zeigefingeramputation rechts","bodyCheck":"dezenter Druckschmerzen im rechten Bein","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"98; rhythmisch","skin":"unauffällig","pain":"keine","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"9f2c922b-6b2c-40e0-8a2d-699df90fd564":{"id":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","functionParameters":{"constantChange":-7.716049382716049,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","maximumHealth":50000}]},"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4":{"id":"91fb3035-8aa2-4a44-b5d1-447f32fc1ba4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":90.27777777777777,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"73e03d5d-ec75-434f-b975-d9369587dee4","earliestTime":720000}]},"73e03d5d-ec75-434f-b975-d9369587dee4":{"id":"73e03d5d-ec75-434f-b975-d9369587dee4","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":100000},{"matchingHealthStateId":"590514f7-bad9-4762-b06d-dd54a67ad2ad","earliestTime":720000}]},"590514f7-bad9-4762-b06d-dd54a67ad2ad":{"id":"590514f7-bad9-4762-b06d-dd54a67ad2ad","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":93.05555555555556,"notSanModifier":93.05555555555556,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"9f2c922b-6b2c-40e0-8a2d-699df90fd564","health":100000}]},{"name":{"firstField":{"colorCode":"X","behaviourCode":"D"},"secondField":{"colorCode":"Z","behaviourCode":"B"},"thirdField":{"colorCode":"Z","behaviourCode":"C"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"7d8db924-24b6-43a4-a1a9-b3acd7785329","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, blaue Augen, 1,69 m, Brille","age":76},"pretriageInformation":{"injuries":"keine äußeren Verletzungen","bodyCheck":"dezenter Druckschmerzen im linken Bein in Höhe der Patella","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"warm, rot","pain":"keine","pupils":"isocor","psyche":"sehr aufgeregt","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b3671073-e1b2-43fb-9d20-499ddf8f15d9":{"id":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","functionParameters":{"constantChange":-17.36111111111111,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"03e6df66-9069-4fe4-b887-6feeb251f4bd","maximumHealth":50000}]},"03e6df66-9069-4fe4-b887-6feeb251f4bd":{"id":"03e6df66-9069-4fe4-b887-6feeb251f4bd","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","maximumHealth":20000}]},"8300f7bf-05b9-4f46-9098-ecb7eda9775d":{"id":"8300f7bf-05b9-4f46-9098-ecb7eda9775d","functionParameters":{"constantChange":-27.77777777777778,"notarztModifier":27.77777777777778,"notSanModifier":27.77777777777778,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","earliestTime":2880000}]},"3e8874cd-6f2a-452e-9259-c905ab7e6e57":{"id":"3e8874cd-6f2a-452e-9259-c905ab7e6e57","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b3671073-e1b2-43fb-9d20-499ddf8f15d9","health":100000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"db84352c-c0e2-4c72-b404-f8838c2f7e56","biometricInformation":{"sex":"male","externalFeatures":"dunkle Haare, braune Augen, Muttermal Stirn, 165 cm","age":14},"pretriageInformation":{"injuries":"Kunststofffremdkörper linker Oberarm; Schulterfraktur links; Luxationsfraktur rechtes Handgelenk","bodyCheck":"Risswunde am Hinterkopf; Hüftprellung rechts","breathing":"unauffällig","awareness":"wach, orientiert","pulse":"124; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"98e5d181-6472-489b-8ecf-24f195ccaa00":{"id":"98e5d181-6472-489b-8ecf-24f195ccaa00","functionParameters":{"constantChange":4.444444444444445,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"98e5d181-6472-489b-8ecf-24f195ccaa00","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"X","behaviourCode":"A"},"thirdField":{"colorCode":"X","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9c72ee24-1dba-4ab9-a2b4-302d22659e21","biometricInformation":{"sex":"male","externalFeatures":"blaue Augen, weiße Haare, 174 cm","age":72},"pretriageInformation":{"injuries":"Fehlstellung linker Oberarm; offene Fraktur Unterarm links; große Platzwunde Kopf; Handquetschung links; Dialysepatient","bodyCheck":"Schlüsselbeinfraktur rechts; Thoraxprellung auf der gleichen Seite","breathing":"unauffällig","awareness":"wach und orientiert","pulse":"122; Puls kräftig","skin":"unauffällig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5":{"id":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"676414f6-f8e2-40b6-9c81-b666a9156572","earliestTime":2880000}]},"676414f6-f8e2-40b6-9c81-b666a9156572":{"id":"676414f6-f8e2-40b6-9c81-b666a9156572","functionParameters":{"constantChange":0,"notarztModifier":22.22222222222222,"notSanModifier":22.22222222222222,"rettSanModifier":22.22222222222222},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":85000}]}},"startingHealthStateId":"3ef8fb89-cf33-45c8-bbdc-86bccf7b20c5","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"B"},"secondField":{"colorCode":"Y","behaviourCode":"A"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"63c7f1c7-2c5b-4e1a-8427-91c67216d0d1","biometricInformation":{"sex":"male","externalFeatures":"Vollbart, blond, blaue Augen, 1,87 m","age":55},"pretriageInformation":{"injuries":"Prellmarke Unterschenkel rechts; Fehlstellung rechtes Sprunggelenk; Wunde Unterarm rechts","bodyCheck":"Druckschmerz rechte Hüfte; Prellung Unterschenkel links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"123; Puls flach","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"aufgeregt","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"54443596-73be-426d-9ef7-96fbc3bf4839":{"id":"54443596-73be-426d-9ef7-96fbc3bf4839","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","earliestTime":2880000}]},"ab5b1286-1904-42a0-a9e1-2ddea8579ce6":{"id":"ab5b1286-1904-42a0-a9e1-2ddea8579ce6","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":33000}]}},"startingHealthStateId":"54443596-73be-426d-9ef7-96fbc3bf4839","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"A"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"1713df33-edcb-45c0-9136-f03c563e312c","biometricInformation":{"sex":"male","externalFeatures":"Glatze, graublaue Augen, Brille, 174 cm","age":57},"pretriageInformation":{"injuries":"leicht blutende Wunde Unterarm links; grobe Fehlstellung rechtes Sprunggelenk; Prellmarke Unterschenkel rechts","bodyCheck":"Druckschmerz linke Hüfte; Prellung Unterschenkel links; Schmerzen im Genitalbereich","breathing":"unauffällig","awareness":"wach aber verwirrt","pulse":"122; Puls kräftig","skin":"kaltschweißig","pain":"starke","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]}},"startingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"D"},"secondField":{"colorCode":"Y","behaviourCode":"B"},"thirdField":{"colorCode":"Y","behaviourCode":"B"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"154647a0-aa9c-4887-a7b3-c1b03e018c3d","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, braune Augen, ca. 1,70 m","age":71},"pretriageInformation":{"injuries":"rechte Hand stark schmerzhaft; kleine blutende Platzwunde am Kopf; Glasfremdkörper am ganzen rechten Arm; unstillbares Nasenbluten","bodyCheck":"Thoraxprellung links; Schlüsselbeinfraktur links","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"132; Puls kräftig","skin":"kühl, blass","pain":"starke","pupils":"isocor","psyche":"aggressiv","hearing":"unauffällig","isWalkable":true},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"ec613c7e-b8f0-4f20-a25f-83858af6243d":{"id":"ec613c7e-b8f0-4f20-a25f-83858af6243d","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","maximumHealth":20000}]},"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2":{"id":"e485a8a1-d6e3-4283-9c33-7a79d0bf9fc2","functionParameters":{"constantChange":20.833333333333332,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6bfd72c1-059e-485d-a397-501ccf5e4531","minimumHealth":50000}]},"6bfd72c1-059e-485d-a397-501ccf5e4531":{"id":"6bfd72c1-059e-485d-a397-501ccf5e4531","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6fe239b8-b8a0-47f2-8608-59dc11401221","earliestTime":2160000}]},"6fe239b8-b8a0-47f2-8608-59dc11401221":{"id":"6fe239b8-b8a0-47f2-8608-59dc11401221","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":41.666666666666664},"nextStateConditions":[{"matchingHealthStateId":"e5f07410-b137-4be2-8676-bf413bc559c5","earliestTime":720000}]},"e5f07410-b137-4be2-8676-bf413bc559c5":{"id":"e5f07410-b137-4be2-8676-bf413bc559c5","functionParameters":{"constantChange":-41.666666666666664,"notarztModifier":41.666666666666664,"notSanModifier":41.666666666666664,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"6e24dba3-b987-4266-ba76-3d9d06501315","earliestTime":720000}]},"6e24dba3-b987-4266-ba76-3d9d06501315":{"id":"6e24dba3-b987-4266-ba76-3d9d06501315","functionParameters":{"constantChange":-69.44444444444444,"notarztModifier":69.44444444444444,"notSanModifier":69.44444444444444,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","minimumHealth":50000},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"ec613c7e-b8f0-4f20-a25f-83858af6243d","health":50000}]},{"name":{"firstField":{"colorCode":"Y","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"9abdfe8f-ac7c-4a42-9d0c-3a1ec5e09238","biometricInformation":{"sex":"female","externalFeatures":"grüne Augen, grauhaarig, 1,68 m, adipös, Brille","age":51},"pretriageInformation":{"injuries":"starke Schmerzen am linken Sprunggelenk; Prellmarke und Schürfwunde linker Unterschenkel","bodyCheck":"Beckenprellung, Fraktur nicht auszuschließen","breathing":"unauffällig","awareness":"wach, verwirrt","pulse":"97; Puls gut tastbar","skin":"kaltschweißig","pain":"stärkste","pupils":"isocor","psyche":"hysterisch","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"02156cc6-b3f0-4041-a079-ba95b387c1a0":{"id":"02156cc6-b3f0-4041-a079-ba95b387c1a0","functionParameters":{"constantChange":-10.416666666666666,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a31b9df5-7993-4a34-8851-b474ea23c094","maximumHealth":20000}]},"a31b9df5-7993-4a34-8851-b474ea23c094":{"id":"a31b9df5-7993-4a34-8851-b474ea23c094","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"02156cc6-b3f0-4041-a079-ba95b387c1a0","health":50000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"A"},"thirdField":{"colorCode":"Z","behaviourCode":"A"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"afdd27cc-2281-468f-a0d8-a8bc187b8e18","biometricInformation":{"sex":"male","externalFeatures":"1,86 m, Glatze, braune Augen, Brille","age":60},"pretriageInformation":{"injuries":"Prellmarken linker Thorax; offene Oberarmfraktur rechts","bodyCheck":"Rippenserienfraktur li.; Beckenprellung rechts; Hämatom hinter dem rechten Ohr; einseitig hebender Thorax rechts","breathing":"flache Schonatmung","awareness":"somnolent","pulse":"134; Puls fadenförmig","skin":"zyanotisch","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"11357873-6d12-41ce-a7dd-129fadd9fc20","biometricInformation":{"sex":"male","externalFeatures":"1,84 m, braune Augen, Brille, braune Haare","age":15},"pretriageInformation":{"injuries":"Weichteilquetschung rechter Unterschenkel, mäßig blutend, aber schon deutlicher Blutverlust","bodyCheck":"Oberschenkelfraktur rechts; kleiner Eisenfremdkörper in der linken Hand","breathing":"flache Atmung","awareness":"somnolent","pulse":"154; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"686cd1dd-d265-48f7-93d3-94928056a3e7","biometricInformation":{"sex":"female","externalFeatures":"1,75 m, blonde Haare, blaue Augen, Brille, extrem adipös","age":50},"pretriageInformation":{"injuries":"Kopfplatzwunde über dem Ohr; Prellmarke Stirn; Gesicht blutverschmiert","bodyCheck":"Unterarmfraktur rechts","breathing":"Atemwegsverlegung","awareness":"bewusstlos, Massenbewegungen auf Schmerz","pulse":"85; gut tastbar","skin":"tief zyanotisch","pain":"entfällt","pupils":"rechts weit","psyche":"entfällt","hearing":"entfällt","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000},{"id":"5d9ff1e5-10ae-4910-940f-3eb37f4bc5f7","biometricInformation":{"sex":"female","externalFeatures":"1,72 m, braune Augen, blonde Haare","age":25},"pretriageInformation":{"injuries":"offene Fraktur rechter Unterschenkel, nur noch mäßig blutend, aber schon großer Blutverlust; Wunde linke Schläfe; schwanger ca. 36 SSW","bodyCheck":"schulternahe Oberarmfraktur rechts; linke Hand mit Fehlstellung im Handgelenk","breathing":"flache Atmung","awareness":"somnolent","pulse":"150; Puls fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"c6a9af9e-a8b5-4eb4-940a-879cd4416538":{"id":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","earliestTime":2160000}]}},"startingHealthStateId":"c6a9af9e-a8b5-4eb4-940a-879cd4416538","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"B"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"8f87e7fc-3226-466c-bee7-ba04a93d8637","biometricInformation":{"sex":"female","externalFeatures":"graue Haare, Brille, grüne Augen, ca. 1,60 m","age":80},"pretriageInformation":{"injuries":"große Weichteilquetschung linker Unterschenkel, nur noch mäßig blutend; aber schon deutlicher Blutverlust","bodyCheck":"Oberarmfraktur rechts; fraglicher Fremdkörper rechte Hand in Wunde; blutende Prellmarke am Hinterkopf","breathing":"flache Atmung","awareness":"somnolent","pulse":"132; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b0c3cbcf-448a-4eb4-8c71-4a94d338a531":{"id":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"d51fc779-8d12-44cc-96cc-ec689c41ff02","earliestTime":2160000}]},"d51fc779-8d12-44cc-96cc-ec689c41ff02":{"id":"d51fc779-8d12-44cc-96cc-ec689c41ff02","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":1440000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b0c3cbcf-448a-4eb4-8c71-4a94d338a531","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"Z","behaviourCode":"C"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"4382691d-53ea-4eeb-931e-146a5e35ea85","biometricInformation":{"sex":"male","externalFeatures":"1,78m, Bart, schwarzhaarig, braune Augen","age":50},"pretriageInformation":{"injuries":"Teil-Amputation rechter Unterarm, spritzend blutend; schon großer Blutverlust","bodyCheck":"geschlossene Oberschenkelfraktur links; Metallfremdkörper rechter Unterschenkel","breathing":"flache Atmung","awareness":"somnolent","pulse":"145; fadenförmig","skin":"grau marmoriert","pain":"stärkste","pupils":"isocor","psyche":"teilnahmslos","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"b72fa6f0-eacc-43a9-a7a7-7764107d17b1":{"id":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","functionParameters":{"constantChange":-13.88888888888889,"notarztModifier":13.88888888888889,"notSanModifier":13.88888888888889,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0},{"matchingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","earliestTime":2160000}]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"b72fa6f0-eacc-43a9-a7a7-7764107d17b1","health":20000}]},{"name":{"firstField":{"colorCode":"Z","behaviourCode":"C"},"secondField":{"colorCode":"V","behaviourCode":"E"},"thirdField":{"colorCode":"V","behaviourCode":"E"}},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"patientTemplates":[{"id":"3c407f4b-012a-4314-a50b-2e334110284e","biometricInformation":{"sex":"female","externalFeatures":"1,64 m, blaue Augen, blond","age":55},"pretriageInformation":{"injuries":"starke Schmerzen im gesamten Abdomen mit gespannter Bauchdecke","bodyCheck":"Prellmarken und Wunde linke Flanke; Rippenserienfraktur links","breathing":"schwere Atemnot 30/min.","awareness":"wach, verwirrt","pulse":"114; flach","skin":"kühl, blass","pain":"starke Bauchschmerzen","pupils":"isocor","psyche":"ängstlich","hearing":"unauffällig","isWalkable":false},"image":{"url":"/assets/patient.svg","height":80,"aspectRatio":1},"healthStates":{"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec":{"id":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","functionParameters":{"constantChange":0,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[]},"7ae2585b-9256-40e7-9408-83df0720a70c":{"id":"7ae2585b-9256-40e7-9408-83df0720a70c","functionParameters":{"constantChange":-9.25925925925926,"notarztModifier":0,"notSanModifier":0,"rettSanModifier":0},"nextStateConditions":[{"matchingHealthStateId":"a9edd742-51c0-4f58-8b1c-0cdedacaa8ec","maximumHealth":0}]}},"startingHealthStateId":"7ae2585b-9256-40e7-9408-83df0720a70c","health":20000}]}],"vehicleTemplates":[{"id":"5ac07da0-c7dc-43ef-94ee-af023966eeeb","vehicleType":"RTW","name":"RTW ???","image":{"url":"/assets/rtw-vehicle.png","height":100,"aspectRatio":2.211377245508982},"patientCapacity":1,"personnel":["notSan","rettSan"],"materials":["standard"]},{"id":"a3d76307-35d8-47ee-8fda-7445c65bf909","vehicleType":"KTW","name":"KTW ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":1,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"a6e71070-6b57-45d3-8863-800428e006f4","vehicleType":"KTW (KatSchutz)","name":"KTW (KatSchutz) ???","image":{"url":"/assets/ktw-vehicle.png","height":100,"aspectRatio":2.0470588235294116},"patientCapacity":2,"personnel":["san","rettSan"],"materials":["standard"]},{"id":"3d7d1950-20a0-4625-a3c0-1dd9d5c7ccc0","vehicleType":"GW-San","name":"GW-San ???","image":{"url":"/assets/gwSan-vehicle.png","height":120,"aspectRatio":2.021018593371059},"patientCapacity":0,"personnel":["gf","rettSan","rettSan","san","san","notarzt"],"materials":["big","big","big","big"]},{"id":"fc8782ac-9567-4bcd-8a5a-8d31f608f03d","vehicleType":"NEF","name":"NEF ???","image":{"url":"/assets/nef-vehicle.png","height":70,"aspectRatio":2.4120194910665944},"patientCapacity":0,"personnel":["notarzt","notSan"],"materials":["standard"]},{"id":"c0690dad-e6be-452f-85e0-2dd942241315","vehicleType":"Tragetrupp","name":"Tragetrupp ???","image":{"url":"/assets/carrying-unit.svg","height":210,"aspectRatio":1},"patientCapacity":1,"personnel":[],"materials":[]},{"id":"cad2cc9b-a624-4020-aa5f-180ed0160f33","vehicleType":"RTH","name":"RTH ???","image":{"url":"/assets/rth-vehicle.svg","height":300,"aspectRatio":2.3846153846153846},"patientCapacity":1,"personnel":["notarzt","notSan"],"materials":["standard"]}],"materialTemplates":{"standard":{"materialType":"standard","canCaterFor":{"red":2,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/material.svg","height":40,"aspectRatio":1}},"big":{"materialType":"big","canCaterFor":{"red":2,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":10,"image":{"url":"/assets/material.svg","height":56,"aspectRatio":1}}},"personnelTemplates":{"san":{"personnelType":"san","canCaterFor":{"red":0,"yellow":0,"green":5,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/san-personnel.svg","height":80,"aspectRatio":1}},"rettSan":{"personnelType":"rettSan","canCaterFor":{"red":1,"yellow":2,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/rettSan-personnel.svg","height":80,"aspectRatio":1}},"notSan":{"personnelType":"notSan","canCaterFor":{"red":2,"yellow":1,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":5.5,"image":{"url":"/assets/notSan-personnel.svg","height":80,"aspectRatio":1}},"notarzt":{"personnelType":"notarzt","canCaterFor":{"red":2,"yellow":2,"green":2,"logicalOperator":"and"},"overrideTreatmentRange":2.5,"treatmentRange":15,"image":{"url":"/assets/notarzt-personnel.svg","height":80,"aspectRatio":1}},"gf":{"personnelType":"gf","canCaterFor":{"red":0,"yellow":0,"green":0,"logicalOperator":"and"},"overrideTreatmentRange":0,"treatmentRange":0,"image":{"url":"/assets/gf-personnel.svg","height":80,"aspectRatio":1}}},"mapImageTemplates":[{"id":"90db6ee0-b8ba-4131-bc87-264fc218fa8f","name":"Feuer","image":{"url":"/assets/fire.svg","height":427,"aspectRatio":0.7330210772833724}},{"id":"9b27ad1c-d1d0-4bd1-9e93-e62d50969085","name":"Brennendes Haus","image":{"url":"/assets/house-fire.svg","height":623,"aspectRatio":0.6308186195826645}}],"eocLog":[],"participantId":"657034","spatialTrees":{"materials":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"patients":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}},"personnel":{"spatialTreeAsJSON":{"children":[],"height":1,"leaf":true,"minX":null,"minY":null,"maxX":null,"maxY":null}}},"configuration":{"pretriageEnabled":true,"bluePatientsEnabled":false,"tileMapProperties":{"tileUrl":"https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}","maxZoom":20}}}}} \ No newline at end of file diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json new file mode 100644 index 000000000..b1c30febe --- /dev/null +++ b/benchmark/package-lock.json @@ -0,0 +1,3224 @@ +{ + "name": "digital-fuesim-manv-benchmark", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "digital-fuesim-manv-benchmark", + "version": "0.0.0", + "dependencies": { + "digital-fuesim-manv-shared": "file:../shared", + "immer": "^9.0.16", + "lodash-es": "^4.17.21" + }, + "devDependencies": { + "@types/lodash-es": "^4.17.6", + "@types/node": "^18.11.16", + "@typescript-eslint/eslint-plugin": "5.46.1", + "@typescript-eslint/parser": "5.46.1", + "eslint": "^8.29.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "~2.26.0", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "ts-node": "^10.9.1", + "typescript": "~4.8.2" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "../shared": { + "name": "digital-fuesim-manv-shared", + "version": "0.0.0", + "dependencies": { + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.16", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/jest": "^29.2.4", + "@types/lodash-es": "^4.17.6", + "@types/rbush": "^3.0.0", + "@types/uuid": "^9.0.0", + "@types/validator": "^13.7.10", + "@typescript-eslint/eslint-plugin": "5.47.0", + "@typescript-eslint/parser": "5.47.0", + "eslint": "^8.30.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "~2.26.0", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "jest": "^29.3.1", + "ts-jest": "^29.0.3", + "ts-node": "^10.9.1", + "typescript": "~4.8.2" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.15.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.191", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", + "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", + "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "18.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.16.tgz", + "integrity": "sha512-6T7P5bDkRhqRxrQtwj7vru+bWTpelgtcETAZEUSdq0YISKz8WKdoBukQLYQQ6DFHvU9JRsbFq0JH5C51X2ZdnA==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz", + "integrity": "sha512-YpzNv3aayRBwjs4J3oz65eVLXc9xx0PDbIRisHj+dYhvBn02MjYOD96P8YGiWEIFBrojaUjxvkaUpakD82phsA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/type-utils": "5.46.1", + "@typescript-eslint/utils": "5.46.1", + "debug": "^4.3.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "regexpp": "^3.2.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.46.1.tgz", + "integrity": "sha512-M79mkB+wOuiBG8jzOVNA2h5izOip5CNPZV1K3tvE/qry/1Oh/bnKYhNWQNiH2h9O3B73YK60GmiqrUpprnQ5sQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.46.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz", + "integrity": "sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", + "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.1.tgz", + "integrity": "sha512-V/zMyfI+jDmL1ADxfDxjZ0EMbtiVqj8LUGPAGyBkXXStWmCUErMpW873zEHsyguWCuq2iN4BrlWUkmuVj84yng==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.46.1", + "@typescript-eslint/utils": "5.46.1", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", + "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", + "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/visitor-keys": "5.46.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", + "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.46.1", + "@typescript-eslint/types": "5.46.1", + "@typescript-eslint/typescript-estree": "5.46.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.46.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", + "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.46.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "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/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "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/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ci-info": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/digital-fuesim-manv-shared": { + "resolved": "../shared", + "link": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", + "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.29.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", + "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.4.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/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/eslint-plugin-total-functions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-total-functions/-/eslint-plugin-total-functions-6.0.0.tgz", + "integrity": "sha512-ZgNAclR/IZcYFT7xPyvG5Iwf7HFPm1FSSSHGNq0Fs0JgKlQ1+0SWk5WWSDFDON2RUdzezKOGQpfatDt7ud2CPg==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^5.27.1", + "@typescript-eslint/experimental-utils": "^5.27.1", + "@typescript-eslint/parser": "^5.27.1", + "tsutils": "^3.17.1" + }, + "peerDependencies": { + "eslint": "^8.17.0", + "typescript": "^4.7.3" + } + }, + "node_modules/eslint-plugin-unicorn": { + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.19.1", + "@eslint-community/eslint-utils": "^4.1.2", + "ci-info": "^3.6.1", + "clean-regexp": "^1.0.0", + "esquery": "^1.4.0", + "indent-string": "^4.0.0", + "is-builtin-module": "^3.2.0", + "jsesc": "^3.0.2", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "read-pkg-up": "^7.0.1", + "regexp-tree": "^0.1.24", + "regjsparser": "^0.9.1", + "safe-regex": "^2.1.1", + "semver": "^7.3.8", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" + }, + "peerDependencies": { + "eslint": ">=8.28.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", + "integrity": "sha512-XwctdmTO6SIvCzd9810yyNzIrOrqNYV9Koizx4C/mRhf9uq0o4yHoCEU/670pOxOL/MSraektvSAji79kX90Vg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/ignore": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.1.tgz", + "integrity": "sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immer": { + "version": "9.0.16", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", + "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/js-sdsl": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "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/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "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/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "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/minimist": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "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/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/regexp-tree": { + "version": "0.1.24", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", + "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", + "dev": true, + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "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": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", + "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", + "dev": true, + "dependencies": { + "regexp-tree": "~0.1.1" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "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/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/benchmark/package.json b/benchmark/package.json new file mode 100644 index 000000000..c0285bd0b --- /dev/null +++ b/benchmark/package.json @@ -0,0 +1,35 @@ +{ + "name": "digital-fuesim-manv-benchmark", + "version": "0.0.0", + "type": "module", + "scripts": { + "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", + "lint:fix": "eslint --ignore-path .gitignore --fix \"./**/*.{ts,js,yml,html}\"", + "benchmark:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts", + "benchmark:windows": "set NODE_ENV=production&& node --experimental-specifier-resolution=node --loader ts-node/esm src/app.ts", + "benchmark": "(pwd && npm run benchmark:linux-macos) || npm run benchmark:windows" + }, + "private": true, + "engines": { + "node": ">=16", + "npm": ">=8" + }, + "dependencies": { + "immer": "^9.0.16", + "lodash-es": "^4.17.21", + "digital-fuesim-manv-shared": "file:../shared" + }, + "devDependencies": { + "@types/lodash-es": "^4.17.6", + "@types/node": "^18.11.16", + "@typescript-eslint/eslint-plugin": "5.46.1", + "@typescript-eslint/parser": "5.46.1", + "eslint": "^8.29.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-import": "~2.26.0", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "ts-node": "^10.9.1", + "typescript": "~4.8.2" + } +} diff --git a/benchmark/src/app.ts b/benchmark/src/app.ts new file mode 100644 index 000000000..465d3a526 --- /dev/null +++ b/benchmark/src/app.ts @@ -0,0 +1,99 @@ +import { promises as fs } from 'node:fs'; +import os from 'node:os'; +import { countBy } from 'lodash-es'; +import { print } from './print'; +import { steps, StepState } from './steps'; + +// Print some information about the system +console.log(` +System Information: + OS: ${os.version()} ${os.release()} + CPUs: ${Object.entries(countBy(os.cpus(), (cpu) => cpu.model)) + .map(([model, count]) => `${count} × ${model}`) + .join(', ')} + RAM: ${Math.round(os.totalmem() / 1024 / 1024)}MB + Node.js: ${process.version} + +`); + +const pathToData = 'data'; + +const filenames = await fs.readdir(pathToData); +const fileBenchmarkResults: BenchmarkResult[] = []; + +for (const filename of filenames) { + // eslint-disable-next-line no-await-in-loop + const benchmarkResult = await benchmarkFile(filename); + print('\n\n'); + if (benchmarkResult) { + fileBenchmarkResults.push(benchmarkResult); + } +} + +// Print the end results to the console +print('\n'); +console.table( + fileBenchmarkResults + .map((result) => ({ + fileName: result.fileName, + fileSize: `${(result.fileSize / 1024 / 1024).toPrecision(2)}MB`, + ...steps + .map((step) => step.getColumnToPrint(result.stepState)) + .reduce((columns, column) => ({ ...columns, ...column }), {}), + })) + // We don't want an extra column for the array index + .reduce<{ [fileName: string]: any }>((table, { fileName, ...rest }) => { + table[fileName] = rest; + return table; + }, {}) +); + +interface BenchmarkResult { + fileName: string; + /** + * Size of the file in bytes + */ + fileSize: number; + /** + * Not all steps results must be included in this state, as some steps might not be run because of an error in a previous step + */ + stepState: StepState; +} + +async function benchmarkFile( + fileName: string +): Promise { + const path = `${pathToData}/${fileName}`; + let data; + try { + // eslint-disable-next-line no-await-in-loop + data = await fs.readFile(path, 'utf8'); + } catch { + print(`Could not read file ${fileName}\n`, 'red'); + return; + } + const fileSize = (await fs.stat(path)).size; + print(`${fileName}\n`, 'blue'); + let parsedData; + try { + parsedData = JSON.parse(data); + } catch { + print('Error while parsing state export\n', 'red'); + return; + } + + const stepState = new StepState(parsedData); + for (const step of steps) { + try { + step.run(stepState); + } catch (error: any) { + print(`${error}\n`, 'red'); + break; + } + } + return { + fileName, + fileSize, + stepState, + }; +} diff --git a/benchmark/src/benchmark-step.ts b/benchmark/src/benchmark-step.ts new file mode 100644 index 000000000..73ed70dc2 --- /dev/null +++ b/benchmark/src/benchmark-step.ts @@ -0,0 +1,46 @@ +import type { BenchmarkValue } from './benchmark'; +import { benchmark } from './benchmark'; +import { print } from './print'; +import { Step } from './step'; + +/** + * A benchmark step is time measured and run multiple times + * The printed out value is the time it took to run the benchmark + */ +export class BenchmarkStep< + // TS will error during transpiling with "Type parameter 'Value' has a circular constraint.", if we use BenchmarkValue here + State extends { [Key in Name]?: BenchmarkValue | undefined }, + Name extends string & keyof State = string & keyof State, + Value extends NonNullable extends BenchmarkValue + ? T + : never = NonNullable extends BenchmarkValue + ? T + : never +> extends Step { + constructor( + name: Name, + /** + * Will be run multiple times and must therefore be deterministic + */ + private readonly functionToBenchmark: (state: State) => Value + ) { + super(name, true); + } + + protected runStep(stepState: State) { + print(` ${this.name}:`.padEnd(30, ' ')); + const endResult = benchmark(() => this.functionToBenchmark(stepState), { + onAfterIteration: (benchmarkValue) => + print(this.formatValue(benchmarkValue).padEnd(10, ' ')), + onNonDeterministicError: () => + print(' Not deterministic!', 'red'), + }); + print('\n'); + // TODO: I couldn't get the typings to work here correctly + return endResult as NonNullable; + } + + protected formatValue(value: BenchmarkValue) { + return `${Math.round(value.time)}ms`; + } +} diff --git a/benchmark/src/benchmark.ts b/benchmark/src/benchmark.ts new file mode 100644 index 000000000..67a08b483 --- /dev/null +++ b/benchmark/src/benchmark.ts @@ -0,0 +1,81 @@ +import { defaults, isEqual } from 'lodash-es'; + +export interface BenchmarkValue { + /** + * The value returned by the benchmarked function + */ + value: T; + /** + * The average time it took to run the function in ms + */ + time: number; +} + +/** + * @param functionToBenchmark the deterministic function that should be benchmarked, it will be run multiple times + * @param options additional options for the benchmark, the defaults for the respective properties are {@link defaultOptions} + */ +export function benchmark( + functionToBenchmark: () => Value, + options: BenchmarkOptions = {} +): BenchmarkValue { + // eslint-disable-next-line no-param-reassign + options = defaults(options, defaultOptions); + const benchmarkStepValues: BenchmarkValue[] = []; + for (let i = 0; i < options.numberOfIterations!; i++) { + const benchmarkStepValue = runBenchmarkOnce(functionToBenchmark); + benchmarkStepValues.push(benchmarkStepValue); + options.onAfterIteration?.(benchmarkStepValue); + } + if ( + benchmarkStepValues.length > 1 && + benchmarkStepValues.some( + ({ value }) => !isEqual(benchmarkStepValues[0]!.value, value) + ) + ) { + options.onNonDeterministicError?.(benchmarkStepValues); + } + return { + value: benchmarkStepValues[0]!.value, + time: + benchmarkStepValues.reduce( + (timeSum, { time }) => timeSum + time, + 0 + ) / options.numberOfIterations!, + }; +} + +function runBenchmarkOnce( + functionToBenchmark: () => Value +): BenchmarkValue { + const startTime = performance.now(); + const value = functionToBenchmark(); + const endTime = performance.now(); + return { + value, + time: endTime - startTime, + }; +} + +interface BenchmarkOptions { + /** + * The number of times the function to benchmark should be run + */ + numberOfIterations?: number; + /** + * Will be called after each iteration + * @param benchmarkValue the BenchmarkValue of the function to benchmark in this iteration + */ + onAfterIteration?: (benchmarkValue: BenchmarkValue) => void; + /** + * Will be called once if any of the iterations returned a different value than the first iteration (by value) + * @param benchmarkValues the BenchmarkValues of the function to benchmark in all iterations + */ + onNonDeterministicError?: ( + benchmarkValues: BenchmarkValue[] + ) => void; +} + +const defaultOptions: BenchmarkOptions = { + numberOfIterations: 3, +}; diff --git a/benchmark/src/calculation-step.ts b/benchmark/src/calculation-step.ts new file mode 100644 index 000000000..a310e354e --- /dev/null +++ b/benchmark/src/calculation-step.ts @@ -0,0 +1,29 @@ +import { Step } from './step'; + +/** + * A calculation step can be used to calculate new values from the state. + * The printed out value is the return value of the calculation function + */ +export class CalculationStep< + State extends { + [StepName: string]: any | undefined; + }, + Name extends keyof State = keyof State, + Value extends State[Name] = State[Name] +> extends Step { + constructor( + name: Name, + public readonly calculate: (state: State) => Value, + printColumn = true + ) { + super(name, printColumn); + } + + public runStep(stepState: State) { + return this.calculate(stepState); + } + + public formatValue(value: Value) { + return value; + } +} diff --git a/benchmark/src/print.ts b/benchmark/src/print.ts new file mode 100644 index 000000000..660907554 --- /dev/null +++ b/benchmark/src/print.ts @@ -0,0 +1,32 @@ +/** + * Prints a string to the console + * + * Be aware that this function does not add a newline at the end. + * This means that you can create multicolor lines by calling this function multiple times. + * ```` + * print('Hello ', 'red'); + * print('World!\n', 'green'); + * ``` + */ +export function print( + text: string, + color: keyof typeof colorEscapeCodes | null = null +) { + process.stdout.write( + `${color ? colorEscapeCodes[color] : ''}${text}${resetCode}` + ); +} + +// See https://stackoverflow.com/a/41407246/104380 +const colorEscapeCodes = { + blue: '\x1B[34m', + cyan: '\x1B[36m', + gray: '\x1B[90m', + green: '\x1B[32m', + magenta: '\x1B[35m', + red: '\x1B[31m', + white: '\x1B[37m', + yellow: '\x1B[33m', +}; + +const resetCode = '\x1B[0m'; diff --git a/benchmark/src/step.ts b/benchmark/src/step.ts new file mode 100644 index 000000000..bf2af8bed --- /dev/null +++ b/benchmark/src/step.ts @@ -0,0 +1,43 @@ +export abstract class Step< + State extends { + [StepName: string]: any | undefined; + }, + Name extends keyof State = keyof State, + Value extends State[Name] = State[Name] +> { + constructor( + public readonly name: Name, + /** + * Whether a column with the values of this step should be added to the printed table at the end + */ + private readonly printColumn: boolean + ) {} + + protected abstract runStep(state: State): NonNullable; + + /** + * This function is expected to modify the state. + * It can throw an error to stop all steps that come after it. + * It can print out information to the console. + */ + public run(state: State) { + state[this.name] = this.runStep(state); + } + + protected abstract formatValue(value: NonNullable): any; + + public getColumnToPrint(state: State): { + [columnName: string]: any; + } { + const value = state[this.name]; + return this.printColumn + ? { + [this.name]: + value === undefined + ? // If the value is undefined, the step was not run (probably because of an error in a previous step) + undefined + : this.formatValue(value), + } + : {}; + } +} diff --git a/benchmark/src/steps.ts b/benchmark/src/steps.ts new file mode 100644 index 000000000..eb1ec7341 --- /dev/null +++ b/benchmark/src/steps.ts @@ -0,0 +1,264 @@ +import type { + ExerciseAction, + ExerciseState, + StateExport, +} from 'digital-fuesim-manv-shared'; +import { + applyAction, + cloneDeepMutable, + migrateStateExport, + reduceExerciseState, + sortObject, + StrictObject, + validateExerciseExport, +} from 'digital-fuesim-manv-shared'; +import produce, { freeze } from 'immer'; +import { isEqual } from 'lodash-es'; +import type { BenchmarkValue } from './benchmark'; +import { benchmark } from './benchmark'; +import { BenchmarkStep } from './benchmark-step'; +import { CalculationStep } from './calculation-step'; +import { print } from './print'; +import type { Step } from './step'; + +export class StepState { + /** + * The end result of the state export migration + */ + public readonly migrate?: BenchmarkValue; + /** + * The end result of the exercise validation + * The value is an array of the errors + */ + public readonly validateExercise?: BenchmarkValue< + ReturnType + >; + /** + * The frozen state of the exercise + */ + public readonly freezeState?: { + initialState: ExerciseState; + actionHistory: readonly ExerciseAction[]; + }; + // There are three different ways to create the end state of the exercise + public readonly newImmerDraft?: BenchmarkValue; + public readonly sameImmerDraft?: BenchmarkValue; + public readonly noImmerDraft?: BenchmarkValue; + /** + * Whether the end states of all three methods to create them are equal + */ + public readonly endStatesAreEqual?: boolean; + /** + * The total benchmarked time it took to execute one action of each type in ms + * (sum of all benchmarked times) + * Sorted by time (descending) + */ + public readonly benchmarkActions?: { + [Key in ExerciseAction['type']]?: number; + }; + /** + * A string with the most expensive action in the exercise (by total summed-up time) and a representation of the respective time + */ + public readonly mostExpensiveAction?: string; + /** + * The number of actions of each type + * Sorted by amount (descending) + */ + public readonly numberOfActionsPerType?: { + [Key in ExerciseAction['type']]?: number; + }; + /** + * The number of actions in the exercise + */ + // The key is used as the column-name in the table, therefore the weird name + public readonly '#actions'?: number; + + constructor(public readonly data: StateExport) {} +} + +/** + * The steps are executed for each state export. + * The steps are executed in the order they are defined. + * The result of each step is stored in `stepState[stateName]`. + * Each step can only access the results of the previous steps. + *`stepState.data` is always available. + * + * Steps can print to the console and throw errors to stop the execution of the specific exercise-state. + * In addition, at the end of the benchmark, there is a summary of the results in the form of a table. + * A lot of this is specified in the individual step classes. + */ +export const steps: Step[] = [ + new BenchmarkStep( + 'migrate', + ({ data }) => migrateStateExport(data) as StateExport + ), + new BenchmarkStep('validateExercise', ({ migrate: migratedValues }) => + validateExerciseExport(migratedValues!.value) + ), + new CalculationStep( + 'freezeState', + ({ migrate: migratedValues }) => { + if (!migratedValues?.value.history) { + throw new Error('State export is missing history'); + } + const history = migratedValues.value.history; + freeze(history, true); + return history; + }, + false + ), + new BenchmarkStep('newImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply each action on a new immer draft + return actionHistory.reduce( + (state, action) => reduceExerciseState(state, action), + initialState + ); + }), + new BenchmarkStep('sameImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply all action on the same immer draft + return produce(initialState, (draftState) => { + for (const action of actionHistory) { + applyAction(draftState, action); + } + }); + }), + new BenchmarkStep('noImmerDraft', ({ freezeState }) => { + const { actionHistory, initialState } = freezeState!; + + // Apply all action on the same immer draft + return actionHistory.reduce( + (state, action) => applyAction(state, action), + cloneDeepMutable(initialState) + ); + }), + new CalculationStep( + 'endStatesAreEqual', + ({ newImmerDraft, sameImmerDraft, noImmerDraft }) => { + const endStatesAreEqual = + isEqual(newImmerDraft!.value, sameImmerDraft!.value) && + isEqual(newImmerDraft!.value, noImmerDraft!.value); + if (!endStatesAreEqual) { + print( + ` The endStates of the previous three steps are not equal! + This most likely means that a reducer is either not deterministic or makes some assumptions about immer specific stuff (use of "original()"). + To further debug this, you should log the endStates of the respective exercises and can compare them directly in vscode via "Compare file with". +`, + 'red' + ); + } + return endStatesAreEqual; + }, + false + ), + + new CalculationStep( + 'benchmarkActions', + ({ freezeState }) => { + print(` benchmarkActions: `); + const { actionHistory, initialState } = freezeState!; + const totalTimePerAction: { + [Key in ExerciseAction['type']]?: number; + } = {}; + let currentState = initialState; + for (const action of actionHistory) { + // eslint-disable-next-line @typescript-eslint/no-loop-func + const { value: newState, time } = benchmark(() => + reduceExerciseState(currentState, action) + ); + + currentState = newState; + totalTimePerAction[action.type] = + (totalTimePerAction[action.type] ?? 0) + time; + } + const sortedTotalTimePerAction = sortObject( + totalTimePerAction, + ([, timeA], [, timeB]) => timeB! - timeA! + ); + print( + // In the object are only entries we explicitly set -> no need to check for undefined + ( + StrictObject.entries(sortedTotalTimePerAction) as [ + ExerciseAction['type'], + number + ][] + ) + .map(([type, time]) => `${type}: ${time.toFixed(2)}ms`) + .join(', ') + ); + print(`\n`); + return sortedTotalTimePerAction; + }, + false + ), + new CalculationStep( + 'mostExpensiveAction', + ({ benchmarkActions, newImmerDraft }) => { + const mostExpensiveAction = StrictObject.entries( + benchmarkActions! + )[0]; + if (!mostExpensiveAction) { + return `No actions`; + } + const summedUpExerciseTime = + StrictObject.values(benchmarkActions!).reduce( + // In the object are only entries we explicitly set + (totalTime, timePerAction) => totalTime! + timePerAction!, + 0 + ) ?? 0; + const summedUpVsDirectTime = + summedUpExerciseTime / newImmerDraft!.time; + if (summedUpVsDirectTime > 1.1 || summedUpVsDirectTime < 0.9) { + print( + ` The summed up time of all actions is ${summedUpVsDirectTime.toFixed( + 2 + )} times the time of the direct benchmark ("newImmerDraft").\n`, + 'yellow' + ); + } + + return `${mostExpensiveAction[0]} ${( + (mostExpensiveAction[1]! / summedUpExerciseTime) * + 100 + ).toFixed(2)}%`; + } + ), + new CalculationStep( + 'numberOfActionsPerType', + ({ freezeState }) => { + print(` numberOfActionsPerType: `); + const { actionHistory } = freezeState!; + const numberOfActionsPerType: { + [Key in ExerciseAction['type']]?: number; + } = {}; + for (const action of actionHistory) { + numberOfActionsPerType[action.type] = + (numberOfActionsPerType[action.type] ?? 0) + 1; + } + const sortedNumberOfActionsPerType = sortObject( + numberOfActionsPerType, + ([, amountA], [, amountB]) => amountB! - amountA! + ); + print( + // In the object are only entries we explicitly set -> no need to check for undefined + ( + StrictObject.entries(sortedNumberOfActionsPerType) as [ + ExerciseAction['type'], + number + ][] + ) + .map(([type, amount]) => `${type}: ${amount}`) + .join(', ') + ); + return sortedNumberOfActionsPerType; + }, + false + ), + new CalculationStep( + '#actions', + ({ freezeState }) => freezeState!.actionHistory.length + ), +]; diff --git a/benchmark/tsconfig.json b/benchmark/tsconfig.json new file mode 100644 index 000000000..95b1850a6 --- /dev/null +++ b/benchmark/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "strict": true, + "noUncheckedIndexedAccess": true, + "module": "ESNext", + "target": "ESNext", + "declaration": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "esModuleInterop": true, + "outDir": "./dist", + "sourceMap": true, + "moduleResolution": "node", + "declarationMap": true, + "rootDir": "./src", + "skipLibCheck": true, + "types": ["node"] + }, + "references": [], + "include": ["src/**/*"], + "exclude": ["node_modules"] +} diff --git a/package.json b/package.json index 3639769b0..cabfecfec 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,9 @@ "start:all": "(cd frontend && npm run start) & (cd backend && npm run start)", "cy:ci": "cd frontend && npm run cy:run", "cy:install": "cd frontend && npm run cy:install", - "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\"", - "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\"", + "benchmark": "cd benchmark && npm run benchmark", + "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmarks && npm i --install-links=false\"", + "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", "prune": "npm prune && cd shared && npm prune && cd ../frontend && npm prune && cd ../backend && npm prune", "prune:deployment": "npm prune --production && cd shared && npm prune --production && cd ../backend && npm prune --production", "deployment": "npm run setup:ci && npm run build:deployment && npm run prune:deployment", diff --git a/shared/README.md b/shared/README.md index c4cb15433..558167bc8 100644 --- a/shared/README.md +++ b/shared/README.md @@ -12,13 +12,17 @@ Keep in mind to add new exports to the `index.ts` file in the folder. - Note that in all cases (other than validation) plain objects of these classes have to be used (instead of instance objects). You can use the `create` methods of all models for this. - [src/socket-api/](./src/socket-api) the types for [socket.io](https://socket.io/docs/v4/typescript/) - [src/state-helpers/](./src/state-helpers) utilities for working with the state. +- [src/state-migrations/](./src/state-migrations) migrations to update old states and actions to the newest version. - [src/store/](./src/store) reducers, actions and utilities that are used with the state - [src/utils/](./src/utils) general utilities -## Updates to state types +## Updates to state types and migrations Note that whenever the state types get updated you have to increase `ExerciseState.currentStateVersion` in [`state.ts`](./src/state.ts). +In addition, you have to add a migration in [`state-migrations`](./src/state-migrations). Look at [`./src/state-migrations/migration-functions.ts`](./src/state-migrations/migration-functions.ts) for more information. +To test the migrations, you can use the benchmarks in [`../benchmark`](../benchmark) and look for errors. + ## Adding new `Action`s When writing new `Action`s, note the comments in [src/store/action-reducer.ts](./src/store/action-reducer.ts) and [src/store/action-reducers/action-reducers.ts](./src/store/action-reducers/action-reducers.ts). diff --git a/shared/src/index.ts b/shared/src/index.ts index 74eff16c7..11985f979 100644 --- a/shared/src/index.ts +++ b/shared/src/index.ts @@ -26,3 +26,4 @@ export * from './http-interfaces'; export * from './state-helpers'; export * from './data'; export * from './store/action-reducers/utils'; +export * from './state-migrations'; diff --git a/backend/src/database/state-migrations/10-rename-delete-transfer-action.ts b/shared/src/state-migrations/10-rename-delete-transfer-action.ts similarity index 71% rename from backend/src/database/state-migrations/10-rename-delete-transfer-action.ts rename to shared/src/state-migrations/10-rename-delete-transfer-action.ts index 24c60b961..078956f63 100644 --- a/backend/src/database/state-migrations/10-rename-delete-transfer-action.ts +++ b/shared/src/state-migrations/10-rename-delete-transfer-action.ts @@ -1,5 +1,6 @@ -import type { Action, Mutable } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Mutable } from '../utils'; +import type { Migration } from './migration-functions'; export const renameDeleteTransferAction10: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/11-add-map-image-is-locked.ts b/shared/src/state-migrations/11-add-map-image-is-locked.ts similarity index 82% rename from backend/src/database/state-migrations/11-add-map-image-is-locked.ts rename to shared/src/state-migrations/11-add-map-image-is-locked.ts index a5f3e4efb..92a16243c 100644 --- a/backend/src/database/state-migrations/11-add-map-image-is-locked.ts +++ b/shared/src/state-migrations/11-add-map-image-is-locked.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addMapImageIsLocked11: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts b/shared/src/state-migrations/12-rename-incorrect-patient-images.ts similarity index 92% rename from backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts rename to shared/src/state-migrations/12-rename-incorrect-patient-images.ts index 42f3bd391..df1d7b7ad 100644 --- a/backend/src/database/state-migrations/12-rename-incorrect-patient-images.ts +++ b/shared/src/state-migrations/12-rename-incorrect-patient-images.ts @@ -1,5 +1,5 @@ -import { StrictObject } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { StrictObject } from '../utils'; +import type { Migration } from './migration-functions'; export const renameIncorrectPatientImages12: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/13-add-map-image-zindex.ts b/shared/src/state-migrations/13-add-map-image-zindex.ts similarity index 82% rename from backend/src/database/state-migrations/13-add-map-image-zindex.ts rename to shared/src/state-migrations/13-add-map-image-zindex.ts index 6324d80da..8f3d80a4e 100644 --- a/backend/src/database/state-migrations/13-add-map-image-zindex.ts +++ b/shared/src/state-migrations/13-add-map-image-zindex.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addMapImageZIndex13: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts b/shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts similarity index 96% rename from backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts rename to shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts index 795f14ee2..f65f020f6 100644 --- a/backend/src/database/state-migrations/14-add-personnel-and-material-templates-to-state.ts +++ b/shared/src/state-migrations/14-add-personnel-and-material-templates-to-state.ts @@ -1,5 +1,5 @@ -import { cloneDeepMutable } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { cloneDeepMutable } from '../utils'; +import type { Migration } from './migration-functions'; export const addPersonnelAndMaterialToState14: Migration = { actions: null, diff --git a/backend/src/database/state-migrations/3-update-eoc-log.ts b/shared/src/state-migrations/3-update-eoc-log.ts similarity index 90% rename from backend/src/database/state-migrations/3-update-eoc-log.ts rename to shared/src/state-migrations/3-update-eoc-log.ts index dd50b49ab..e6d52b124 100644 --- a/backend/src/database/state-migrations/3-update-eoc-log.ts +++ b/shared/src/state-migrations/3-update-eoc-log.ts @@ -1,5 +1,6 @@ -import type { Client, EocLogEntry, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Client, EocLogEntry } from '../models'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const updateEocLog3: Migration = { actions: null, diff --git a/backend/src/database/state-migrations/4-remove-set-participant-id-action.ts b/shared/src/state-migrations/4-remove-set-participant-id-action.ts similarity index 78% rename from backend/src/database/state-migrations/4-remove-set-participant-id-action.ts rename to shared/src/state-migrations/4-remove-set-participant-id-action.ts index ab8a4d88d..7b3eef26d 100644 --- a/backend/src/database/state-migrations/4-remove-set-participant-id-action.ts +++ b/shared/src/state-migrations/4-remove-set-participant-id-action.ts @@ -1,5 +1,5 @@ -import type { Action } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Migration } from './migration-functions'; export const removeSetParticipantIdAction4: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/5-remove-statistics.ts b/shared/src/state-migrations/5-remove-statistics.ts similarity index 74% rename from backend/src/database/state-migrations/5-remove-statistics.ts rename to shared/src/state-migrations/5-remove-statistics.ts index 435c349b2..a13666b0a 100644 --- a/backend/src/database/state-migrations/5-remove-statistics.ts +++ b/shared/src/state-migrations/5-remove-statistics.ts @@ -1,4 +1,4 @@ -import type { Migration } from './migrations'; +import type { Migration } from './migration-functions'; export const removeStatistics5: Migration = { actions: null, diff --git a/backend/src/database/state-migrations/6-remove-state-history.ts b/shared/src/state-migrations/6-remove-state-history.ts similarity index 89% rename from backend/src/database/state-migrations/6-remove-state-history.ts rename to shared/src/state-migrations/6-remove-state-history.ts index 4df5cd0bb..3517ab53b 100644 --- a/backend/src/database/state-migrations/6-remove-state-history.ts +++ b/shared/src/state-migrations/6-remove-state-history.ts @@ -1,5 +1,5 @@ -import type { Action } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { Migration } from './migration-functions'; export const removeStateHistory6: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/7-add-patient-remarks.ts b/shared/src/state-migrations/7-add-patient-remarks.ts similarity index 81% rename from backend/src/database/state-migrations/7-add-patient-remarks.ts rename to shared/src/state-migrations/7-add-patient-remarks.ts index a09d2fcb8..9d22efc86 100644 --- a/backend/src/database/state-migrations/7-add-patient-remarks.ts +++ b/shared/src/state-migrations/7-add-patient-remarks.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const addPatientRemarks7: Migration = { actions: (_initialState, actions) => { diff --git a/backend/src/database/state-migrations/8-treatment-system-improvements.ts b/shared/src/state-migrations/8-treatment-system-improvements.ts similarity index 95% rename from backend/src/database/state-migrations/8-treatment-system-improvements.ts rename to shared/src/state-migrations/8-treatment-system-improvements.ts index 8223a3c69..d1ead0fc4 100644 --- a/backend/src/database/state-migrations/8-treatment-system-improvements.ts +++ b/shared/src/state-migrations/8-treatment-system-improvements.ts @@ -1,9 +1,6 @@ -import { - cloneDeepMutable, - SpatialTree, - StrictObject, -} from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import { SpatialTree } from '../models/utils'; +import { cloneDeepMutable, StrictObject } from '../utils'; +import type { Migration } from './migration-functions'; export const treatmentSystemImprovements8: Migration = { actions: (_initialState, actions: any[]) => { diff --git a/backend/src/database/state-migrations/9-remove-is-being-treated.ts b/shared/src/state-migrations/9-remove-is-being-treated.ts similarity index 82% rename from backend/src/database/state-migrations/9-remove-is-being-treated.ts rename to shared/src/state-migrations/9-remove-is-being-treated.ts index d29574f1d..d3ef10ac5 100644 --- a/backend/src/database/state-migrations/9-remove-is-being-treated.ts +++ b/shared/src/state-migrations/9-remove-is-being-treated.ts @@ -1,5 +1,6 @@ -import type { Action, UUID } from 'digital-fuesim-manv-shared'; -import type { Migration } from './migrations'; +import type { Action } from '../store'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; export const removeIsBeingTreated9: Migration = { actions: (_initialState, actions) => { diff --git a/shared/src/state-migrations/impossible-migration.ts b/shared/src/state-migrations/impossible-migration.ts new file mode 100644 index 000000000..a684fdd68 --- /dev/null +++ b/shared/src/state-migrations/impossible-migration.ts @@ -0,0 +1,29 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const impossibleMigration: Migration = { + actions: (initialState, actions) => { + throw new RestoreError( + 'The migration is not possible', + (initialState as { id?: UUID }).id ?? 'unknown' + ); + }, + state: (state) => { + throw new RestoreError( + 'The migration is not possible', + (state as { id?: UUID }).id ?? 'unknown' + ); + }, +}; + +// TODO: Rename into `MigrationError` (upstream changes in the backend) +class RestoreError extends Error { + public constructor( + message: string, + public readonly exerciseId: UUID, + innerError?: Error + ) { + super(`Failed to restore exercise \`${exerciseId}\`: ${message}`); + this.cause = innerError; + } +} diff --git a/shared/src/state-migrations/index.ts b/shared/src/state-migrations/index.ts new file mode 100644 index 000000000..59cb930e6 --- /dev/null +++ b/shared/src/state-migrations/index.ts @@ -0,0 +1 @@ +export * from './migrations'; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts new file mode 100644 index 000000000..1d0b4d568 --- /dev/null +++ b/shared/src/state-migrations/migration-functions.ts @@ -0,0 +1,54 @@ +import { renameDeleteTransferAction10 } from './10-rename-delete-transfer-action'; +import { addMapImageIsLocked11 } from './11-add-map-image-is-locked'; +import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-images'; +import { addMapImageZIndex13 } from './13-add-map-image-zindex'; +import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; +import { updateEocLog3 } from './3-update-eoc-log'; +import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; +import { removeStatistics5 } from './5-remove-statistics'; +import { removeStateHistory6 } from './6-remove-state-history'; +import { addPatientRemarks7 } from './7-add-patient-remarks'; +import { treatmentSystemImprovements8 } from './8-treatment-system-improvements'; +import { removeIsBeingTreated9 } from './9-remove-is-being-treated'; +import { impossibleMigration } from './impossible-migration'; + +/** + * Such a function gets the already migrated initial state of the exercise and an array of all actions (not yet migrated). + * It is expected that afterwards the actions in the provided array are migrated. + * It is not allowed to modify the order of the actions, to add an action or to remove an action. + * To indicate that an action should be removed it can be replaced by `null`. + * It may throw a {@link RestoreError} when a migration is not possible. + */ +type MigrateActionsFunction = ( + initialState: object, + actions: (object | null)[] +) => void; + +/** + * Such a function gets the not yet migrated state and is expected to mutate it to a migrated version. + * It may throw a {@link RestoreError} when a migration is not possible. + */ +type MigrateStateFunction = (state: object) => void; + +export interface Migration { + actions: MigrateActionsFunction | null; + state: MigrateStateFunction | null; +} + +export const migrations: { + [TargetStateVersion: number]: Migration; +} = { + 2: impossibleMigration, + 3: updateEocLog3, + 4: removeSetParticipantIdAction4, + 5: removeStatistics5, + 6: removeStateHistory6, + 7: addPatientRemarks7, + 8: treatmentSystemImprovements8, + 9: removeIsBeingTreated9, + 10: renameDeleteTransferAction10, + 11: addMapImageIsLocked11, + 12: renameIncorrectPatientImages12, + 13: addMapImageZIndex13, + 14: addPersonnelAndMaterialToState14, +}; diff --git a/backend/src/database/state-migrations/migrations.spec.ts b/shared/src/state-migrations/migrations.spec.ts similarity index 76% rename from backend/src/database/state-migrations/migrations.spec.ts rename to shared/src/state-migrations/migrations.spec.ts index 69f430da3..daa9ac5ad 100644 --- a/backend/src/database/state-migrations/migrations.spec.ts +++ b/shared/src/state-migrations/migrations.spec.ts @@ -1,6 +1,6 @@ -import { ExerciseState } from 'digital-fuesim-manv-shared'; import { range } from 'lodash-es'; -import { migrations } from './migrations'; +import { ExerciseState } from '../state'; +import { migrations } from './migration-functions'; describe('migrations definition', () => { it('has the correct versions', () => { diff --git a/shared/src/state-migrations/migrations.ts b/shared/src/state-migrations/migrations.ts new file mode 100644 index 000000000..f23b01d8d --- /dev/null +++ b/shared/src/state-migrations/migrations.ts @@ -0,0 +1,76 @@ +import type { StateExport } from '../export-import/file-format'; +import { ExerciseState } from '../state'; +import type { ExerciseAction } from '../store'; +import { applyAllActions } from '../store'; +import type { Mutable } from '../utils'; +import { cloneDeepMutable } from '../utils'; +import { migrations } from './migration-functions'; + +export function migrateStateExport( + stateExportToMigrate: StateExport +): Mutable { + const stateExport = cloneDeepMutable(stateExportToMigrate); + const propertiesToMigrate = { + currentState: stateExport.currentState, + history: stateExport.history + ? { + initialState: stateExport.history.initialState, + actions: stateExport.history.actionHistory, + } + : undefined, + }; + const newVersion = applyMigrations( + stateExport.dataVersion, + propertiesToMigrate + ); + stateExport.dataVersion = newVersion; + stateExport.currentState = propertiesToMigrate.currentState; + if (stateExport.history) { + stateExport.history.actionHistory = + // Remove actions that are marked to be removed by the migrations + propertiesToMigrate.history!.actions.filter( + (action) => action !== null + ); + } + return stateExport; +} + +/** + * Migrates {@link propertiesToMigrate} to the newest version ({@link ExerciseState.currentStateVersion}) + * by mutating them. + * + * @returns The new state version + */ +export function applyMigrations( + currentStateVersion: number, + propertiesToMigrate: { + currentState: object; + history?: { initialState: object; actions: (object | null)[] }; + } +): number { + const targetVersion = ExerciseState.currentStateVersion; + for (let i = currentStateVersion + 1; i <= targetVersion; i++) { + const stateMigration = migrations[i]!.state; + if (stateMigration !== null) { + if (propertiesToMigrate.history) + stateMigration(propertiesToMigrate.history.initialState); + else stateMigration(propertiesToMigrate.currentState); + } + if (!propertiesToMigrate.history) continue; + const actionMigration = migrations[i]!.actions; + if (actionMigration !== null) { + actionMigration( + propertiesToMigrate.history.initialState, + propertiesToMigrate.history.actions + ); + } + } + if (propertiesToMigrate.history) + propertiesToMigrate.currentState = applyAllActions( + propertiesToMigrate.history.initialState as ExerciseState, + propertiesToMigrate.history.actions.filter( + (action) => action !== null + ) as ExerciseAction[] + ); + return targetVersion; +} diff --git a/shared/src/utils/index.ts b/shared/src/utils/index.ts index 9a8518c80..6d4505f4e 100644 --- a/shared/src/utils/index.ts +++ b/shared/src/utils/index.ts @@ -9,3 +9,4 @@ export * from './clone-deep'; export * from './strict-object'; export * from './sleep'; export * from './assert-exhaustiveness'; +export * from './sort-object'; diff --git a/shared/src/utils/sort-object.spec.ts b/shared/src/utils/sort-object.spec.ts new file mode 100644 index 000000000..8a00cf8c2 --- /dev/null +++ b/shared/src/utils/sort-object.spec.ts @@ -0,0 +1,55 @@ +import { cloneDeep } from 'lodash-es'; +import { sortObject } from './sort-object'; + +const tests: SortObjectTest[] = [ + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueA - valueB, + expectedObject: { a: 1, b: 2, c: 3 }, + }, + { + object: { a: 1, b: 2, c: 3 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueA - valueB, + expectedObject: { a: 1, b: 2, c: 3 }, + }, + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => valueB - valueA, + expectedObject: { c: 3, b: 2, a: 1 }, + }, + { + object: { c: 3, b: 2, a: 1 }, + compareFn: ([keyA, valueA], [keyB, valueB]) => + (keyA as string).localeCompare(keyB as string), + expectedObject: { a: 1, b: 2, c: 3 }, + }, +]; + +describe('sortObject', () => { + it.each(tests)('$# sorts %j', ({ object, compareFn, expectedObject }) => { + const objectToBeSorted = cloneDeep(object); + const sortedObj = sortObject(objectToBeSorted, compareFn); + // The sorted object should be equal to the expected object + expect(JSON.stringify(sortedObj)).toBe(JSON.stringify(expectedObject)); + expect(Object.keys(sortedObj)).toStrictEqual( + Object.keys(expectedObject) + ); + expect(Object.values(sortedObj)).toStrictEqual( + Object.values(expectedObject) + ); + // The original object should not be mutated + expect(JSON.stringify(objectToBeSorted)).toBe(JSON.stringify(object)); + expect(Object.keys(objectToBeSorted)).toStrictEqual( + Object.keys(object) + ); + expect(Object.values(objectToBeSorted)).toStrictEqual( + Object.values(object) + ); + }); +}); + +interface SortObjectTest { + object: T; + compareFn: (a: [keyof T, T[keyof T]], b: [keyof T, T[keyof T]]) => number; + expectedObject: T; +} diff --git a/shared/src/utils/sort-object.ts b/shared/src/utils/sort-object.ts new file mode 100644 index 000000000..cfbce54b9 --- /dev/null +++ b/shared/src/utils/sort-object.ts @@ -0,0 +1,24 @@ +import { StrictObject } from './strict-object'; + +/** + * + * @param obj The object to sort. It will not be mutated. + * @param compareFn Function used to determine the order of the elements. + * It gets the key and value of the elements to compare as arguments. + * It is expected to return a negative value if the first argument is less than the second argument, + * zero if they're equal, and a positive value otherwise. + * @returns A new object with the same keys as obj and the keys and values sorted according to the compareFn. + * + * @example + * ````ts + * const obj = { c: 3, b: 2, a: 1 }; + * const sortedObj = sortObject(obj, ([keyA, valueA], [keyB, valueB]) => valueA - valueB); + * // sortedObj = { a: 1, b: 2, c: 3 } + * ```` + */ +export function sortObject( + obj: T, + compareFn: (a: [keyof T, T[keyof T]], b: [keyof T, T[keyof T]]) => number +): T { + return Object.fromEntries(StrictObject.entries(obj).sort(compareFn)) as T; +} From ea80e42ed2481618a5edcdd2017d45ce6f07faef Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Mon, 9 Jan 2023 18:47:44 +0000 Subject: [PATCH 03/58] Feature/improve eslint rules (#591) * Disallow imports from "*/dist/*" * Improve smaller eslint rules * Update documentation --- .eslint/typescript.eslintrc.cjs | 102 +++++++++--------- README.md | 21 ++-- .../exercise/websocket-handler/secure-on.ts | 2 + frontend/cypress/plugins/index.ts | 1 + frontend/cypress/support/commands.ts | 1 + .../src/app/core/messages/message.service.ts | 2 +- frontend/src/app/core/time-travel-helper.ts | 3 - .../shared/core/drag-element.service.ts | 2 +- .../map-image-popup.component.ts | 7 +- .../exercise-map/utility/ol-map-manager.ts | 4 +- .../display-validation.component.ts | 2 +- .../data/default-state/patient-templates.ts | 2 +- shared/src/models/index.ts | 1 + .../src/models/utils/patient-status-code.ts | 1 + shared/src/state.ts | 2 +- shared/src/store/action-reducers/index.ts | 1 + 16 files changed, 84 insertions(+), 70 deletions(-) diff --git a/.eslint/typescript.eslintrc.cjs b/.eslint/typescript.eslintrc.cjs index 16c63261e..3bacc61cd 100644 --- a/.eslint/typescript.eslintrc.cjs +++ b/.eslint/typescript.eslintrc.cjs @@ -28,12 +28,10 @@ module.exports = { 'no-useless-backreference': 'warn', 'require-atomic-updates': 'warn', 'array-callback-return': 'warn', - // "class-methods-use-this": "warn", 'default-case-last': 'warn', eqeqeq: ['warn', 'always'], 'grouped-accessor-pairs': 'warn', 'guard-for-in': 'warn', - // "max-classes-per-file": ["warn", 3], 'no-caller': 'warn', 'no-constructor-return': 'warn', 'no-div-regex': 'warn', @@ -74,42 +72,52 @@ module.exports = { 'no-restricted-imports': [ 'error', { - name: 'lodash', - message: 'Please use lodash-es instead.', + paths: [ + 'assert', + 'buffer', + 'child_process', + 'cluster', + 'crypto', + 'dgram', + 'dns', + 'domain', + 'events', + 'freelist', + 'fs', + 'http', + 'https', + 'module', + 'net', + 'os', + 'path', + 'punycode', + 'querystring', + 'readline', + 'repl', + 'smalloc', + 'stream', + 'string_decoder', + 'sys', + 'timers', + 'tls', + 'tracing', + 'tty', + 'url', + 'util', + 'vm', + 'zlib', + { + name: 'lodash', + message: 'Please use lodash-es instead.', + }, + ], + patterns: [ + { + group: ['*/dist/*'], + message: 'Please only import from the source.', + }, + ], }, - 'assert', - 'buffer', - 'child_process', - 'cluster', - 'crypto', - 'dgram', - 'dns', - 'domain', - 'events', - 'freelist', - 'fs', - 'http', - 'https', - 'module', - 'net', - 'os', - 'path', - 'punycode', - 'querystring', - 'readline', - 'repl', - 'smalloc', - 'stream', - 'string_decoder', - 'sys', - 'timers', - 'tls', - 'tracing', - 'tty', - 'url', - 'util', - 'vm', - 'zlib', ], 'no-useless-computed-key': ['warn', { enforceForClassMembers: true }], 'no-useless-rename': 'warn', @@ -151,7 +159,7 @@ module.exports = { markers: ['/'], }, ], - // disabled because @typescript-eslint implements them + // Disabled because @typescript-eslint implements them 'dot-notation': 'off', 'no-empty-function': 'off', 'no-unused-expressions': 'off', @@ -189,7 +197,6 @@ module.exports = { 'unicorn/no-zero-fractions': 'warn', 'unicorn/number-literal-case': 'warn', 'unicorn/numeric-separators-style': 'off', - // "unicorn/prefer-add-event-listener": "warn", 'unicorn/prefer-keyboard-event-key': 'warn', 'unicorn/prefer-array-flat-map': 'warn', 'unicorn/prefer-includes': 'warn', @@ -222,7 +229,7 @@ module.exports = { 'unicorn/prefer-array-flat': 'warn', 'unicorn/prefer-node-protocol': 'warn', 'unicorn/no-array-for-each': 'off', - // "unicorn/prevent-abbreviations": "warn", + 'unicorn/prefer-at': 'warn', 'unicorn/string-content': [ 'warn', { @@ -240,7 +247,8 @@ module.exports = { /** * @typescript-eslint */ - // "@typescript-eslint/array-type": "array-simple", + // TODO: false positive + // '@typescript-eslint/array-type': ['warn', 'array'], '@typescript-eslint/prefer-as-const': 'off', '@typescript-eslint/ban-tslint-comment': 'warn', '@typescript-eslint/class-literal-property-style': ['warn', 'fields'], @@ -265,7 +273,7 @@ module.exports = { ], '@typescript-eslint/explicit-function-return-type': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', - // "@typescript-eslint/explicit-member-accessibility": "warn", + '@typescript-eslint/explicit-member-accessibility': 'warn', '@typescript-eslint/member-ordering': [ 'warn', { @@ -304,7 +312,6 @@ module.exports = { 'warn', { ignoreArrowShorthand: true }, ], - // "@typescript-eslint/no-dynamic-delete": "warn", '@typescript-eslint/no-empty-interface': 'off', '@typescript-eslint/no-explicit-any': ['off'], '@typescript-eslint/no-extraneous-class': [ @@ -322,7 +329,8 @@ module.exports = { '@typescript-eslint/no-require-imports': 'warn', '@typescript-eslint/no-type-alias': 'off', '@typescript-eslint/no-unnecessary-boolean-literal-compare': 'warn', - // Because `object[key]` is always truthy for ts + // Disabled because of incorrect typings from libraries and + // checks after type assertions without `undefined` in the type '@typescript-eslint/no-unnecessary-condition': 'off', '@typescript-eslint/no-unnecessary-qualifier': 'warn', '@typescript-eslint/no-unnecessary-type-arguments': 'warn', @@ -336,14 +344,12 @@ module.exports = { '@typescript-eslint/prefer-nullish-coalescing': 'warn', '@typescript-eslint/prefer-optional-chain': 'warn', '@typescript-eslint/prefer-readonly': 'warn', - // "@typescript-eslint/prefer-readonly-parameter-types": "warn", '@typescript-eslint/prefer-reduce-type-parameter': 'warn', '@typescript-eslint/prefer-regexp-exec': 'warn', '@typescript-eslint/prefer-string-starts-ends-with': 'warn', '@typescript-eslint/prefer-ts-expect-error': 'warn', '@typescript-eslint/promise-function-async': 'warn', '@typescript-eslint/require-array-sort-compare': 'warn', - // "@typescript-eslint/strict-boolean-expressions": "warn", '@typescript-eslint/switch-exhaustiveness-check': 'warn', '@typescript-eslint/unified-signatures': 'warn', // Extension rules that should be used instead of the eslint ones: @@ -353,8 +359,7 @@ module.exports = { '@typescript-eslint/no-duplicate-imports': 'warn', '@typescript-eslint/no-empty-function': 'warn', '@typescript-eslint/no-implied-eval': 'warn', - // TODO: temprarely disable because of an runtime error: "TypeError: rules.FunctionExpression is not a function" - // '@typescript-eslint/no-invalid-this': 'warn', + '@typescript-eslint/no-invalid-this': 'warn', '@typescript-eslint/no-loop-func': 'warn', '@typescript-eslint/no-loss-of-precision': 'warn', '@typescript-eslint/no-redeclare': 'warn', @@ -386,7 +391,6 @@ module.exports = { ], '@typescript-eslint/no-misused-new': 'warn', '@typescript-eslint/no-non-null-assertion': 'off', - // "@typescript-eslint/no-param-reassign": "warn", '@typescript-eslint/no-unnecessary-type-assertion': 'off', }, }; diff --git a/README.md b/README.md index f74d27424..0a0ed7d98 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,7 @@ This project is currently developed as a [bachelor project](https://hpi.de/en/st ## Links for collaborators -- [(internal) documentation](https://github.com/hpi-sam/BP2021HG1) -- [(internal) project-board](https://github.com/orgs/hpi-sam/projects/4). +- [(internal) Test scenarios](https://github.com/hpi-sam/digital-fuesim-manv_test-scenarios) ## Installation @@ -109,10 +108,9 @@ There are already the following [debug configurations](https://code.visualstudio - `Launch Frontend [Firefox]` (You have to install an extra extension) - `Debug Jest Tests` -In addition you can make use of the following browser extensions: +In addition, you can make use of the following browser extensions: - [Angular DevTools](https://chrome.google.com/webstore/detail/angular-devtools/ienfalfjdbdpebioblfackkekamfmbnh) -- [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension/) for [NgRx](https://ngrx.io/guide/store-devtools) ## Testing @@ -120,13 +118,15 @@ In addition you can make use of the following browser extensions: We are using [Jest](https://jestjs.io/) for our unit tests. -You can run it during development +You can run it during the development - from the terminal via `npm run test:watch` in the root, `/shared`, `/backend` or `/frontend` folder -- or via the [recommended vscode extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). +- or via the [recommended vscode extension](https://marketplace.visualstudio.com/items?itemName=Orta.vscode-jest). **(Note: this option is currently broken)** ### End to end tests +**Note: We don't really have end-to-end tests yet.** + We are using [cypress](https://www.npmjs.com/package/cypress) to run the end-to-end tests. You can find the code under `/frontend/cypress` in the repository. #### Running the tests @@ -170,6 +170,11 @@ Look at the [benchmark readme](./benchmark/README.md) for more information. */ ``` - You should use the keyword `TODO` to mark things that need to be done later. Whether an issue should be created is an individual decision. + - You are encouraged to add expiration conditions to your TODOs. Eslint will complain as soon as the condition is met. See [here](https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/expiring-todo-comments.md) for more information. + ```ts + // TODO [engine:node@>=8]: We can use async/await now. + // TODO [typescript@>=4.9]: Use satisfies https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator + ``` # Architecture @@ -257,8 +262,7 @@ A consequence of the synchronization strategy described before is that it takes This is where optimistic updates come into play. We just assume optimistically that the proposed action will be applied on the server. Therefore we can apply the action on the client directly without waiting for a `performAction` from the server. -If the server rejects the proposal or a race condition occurs, the client corrects its state again. -In our case the [optimisticActionHandler](./frontend/src/app/core/optimistic-action-handler.ts) encapsulates this functionality. +If the server rejects the proposal or a race condition occurs, the client corrects its state again. In our case, the [optimisticActionHandler](./frontend/src/app/core/optimistic-action-handler.ts) encapsulates this functionality. The state in the frontend is not guaranteed to be correct. It is only guaranteed to automatically correct itself. @@ -266,7 +270,6 @@ If you need to read from the state to change it, you should do this inside the a ### Performance considerations -- Do _not_ save a very large JS primitve (a large string like a base64 encoded image) in a part of the state that is often modified (like the root). This primitive would be copied on each change. Instead, the primitive should be saved as part of a separate object. This makes use of the performance benefits of shallow copies. - Currently, every client maintains the whole state, and every action is sent to all clients. There is no way to only subscribe to a part of the state and only receive updates for that part. ## Licenses and Attributions diff --git a/backend/src/exercise/websocket-handler/secure-on.ts b/backend/src/exercise/websocket-handler/secure-on.ts index 25f2ffa53..a14e5c678 100644 --- a/backend/src/exercise/websocket-handler/secure-on.ts +++ b/backend/src/exercise/websocket-handler/secure-on.ts @@ -1,5 +1,7 @@ import type { ClientToServerEvents } from 'digital-fuesim-manv-shared'; +// eslint-disable-next-line no-restricted-imports import type { SocketReservedEventsMap } from 'socket.io/dist/socket'; +// eslint-disable-next-line no-restricted-imports import type { ReservedOrUserEventNames, ReservedOrUserListener, diff --git a/frontend/cypress/plugins/index.ts b/frontend/cypress/plugins/index.ts index a06120efd..8ff4dd822 100644 --- a/frontend/cypress/plugins/index.ts +++ b/frontend/cypress/plugins/index.ts @@ -1,4 +1,5 @@ // @ts-expect-error there is no type definition for this package yet +// eslint-disable-next-line no-restricted-imports import * as cypressImageDiffPlugin from 'cypress-image-diff-js/dist/plugin'; // eslint-disable-next-line @typescript-eslint/no-empty-function diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts index 4e45085a9..210f5e025 100644 --- a/frontend/cypress/support/commands.ts +++ b/frontend/cypress/support/commands.ts @@ -42,6 +42,7 @@ // -- This will overwrite an existing command -- // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) // @ts-expect-error there is no type definition for this package yet +// eslint-disable-next-line no-restricted-imports import * as cypressImageDiffCommand from 'cypress-image-diff-js/dist/command'; cypressImageDiffCommand(); diff --git a/frontend/src/app/core/messages/message.service.ts b/frontend/src/app/core/messages/message.service.ts index b95244001..20a23727d 100644 --- a/frontend/src/app/core/messages/message.service.ts +++ b/frontend/src/app/core/messages/message.service.ts @@ -84,7 +84,7 @@ export class MessageService { ...(type === 'toast' ? this.toastMessages : this.alertMessages), ]; // Set/update the newest message - let newestMessage: Message | undefined = messages[messages.length - 1]; + let newestMessage: Message | undefined = messages.at(-1); if (!newestMessage || !isEqual(newestMessage.config, config)) { newestMessage = new Message(config, timeout); firstValueFrom(newestMessage.destroyed$).then(() => { diff --git a/frontend/src/app/core/time-travel-helper.ts b/frontend/src/app/core/time-travel-helper.ts index c96909420..b964e11eb 100644 --- a/frontend/src/app/core/time-travel-helper.ts +++ b/frontend/src/app/core/time-travel-helper.ts @@ -38,9 +38,6 @@ export class TimeTravelHelper { * @param exerciseTime The time to travel to, if it isn't in the timeConstraints, it will be clamped appropriately */ public async jumpToTime(exerciseTime: number): Promise { - if (!this.timeConstraints || !this.timeJumpHelper) { - throw new Error('Start the time travel before jumping to a time!'); - } const clampedTime = Math.max( this.timeConstraints.start, Math.min(this.timeConstraints.end, exerciseTime) diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts index 532ee10d0..3582fe914 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts @@ -3,6 +3,7 @@ import { Store } from '@ngrx/store'; import type { ImageProperties, MapImageTemplate, + PatientCategory, VehicleTemplate, } from 'digital-fuesim-manv-shared'; import { @@ -13,7 +14,6 @@ import { TransferPoint, Viewport, } from 'digital-fuesim-manv-shared'; -import type { PatientCategory } from 'digital-fuesim-manv-shared/dist/models/patient-category'; import type OlMap from 'ol/Map'; import { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/map-image-popup/map-image-popup.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/map-image-popup/map-image-popup.component.ts index 0e85bdfd6..8ffe62eee 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/map-image-popup/map-image-popup.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/map-image-popup/map-image-popup.component.ts @@ -1,8 +1,11 @@ import type { OnInit } from '@angular/core'; import { Component, EventEmitter, Output } from '@angular/core'; import { Store } from '@ngrx/store'; -import type { MapImage, UUID } from 'digital-fuesim-manv-shared'; -import type { ChangeZIndexMapImageAction } from 'digital-fuesim-manv-shared/dist/store/action-reducers/map-images'; +import type { + ChangeZIndexMapImageAction, + MapImage, + UUID, +} from 'digital-fuesim-manv-shared'; import type { Observable } from 'rxjs'; import { firstValueFrom } from 'rxjs'; import { ExerciseService } from 'src/app/core/exercise.service'; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index f387e0c38..7124a649c 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -543,7 +543,7 @@ export class OlMapManager { public destroy() { this.destroy$.next(); - this.olMap?.dispose(); - this.olMap?.setTarget(undefined); + this.olMap.dispose(); + this.olMap.setTarget(undefined); } } diff --git a/frontend/src/app/shared/validation/display-validation/display-validation.component.ts b/frontend/src/app/shared/validation/display-validation/display-validation.component.ts index 20d6cba45..8be5ac406 100644 --- a/frontend/src/app/shared/validation/display-validation/display-validation.component.ts +++ b/frontend/src/app/shared/validation/display-validation/display-validation.component.ts @@ -11,6 +11,6 @@ export class DisplayValidationComponent { @Input() ngModelInput!: NgModel; get errors(): CustomValidationErrors | null { - return this.ngModelInput?.errors as CustomValidationErrors | null; + return this.ngModelInput.errors as CustomValidationErrors | null; } } diff --git a/shared/src/data/default-state/patient-templates.ts b/shared/src/data/default-state/patient-templates.ts index a936d471a..15536ae8d 100644 --- a/shared/src/data/default-state/patient-templates.ts +++ b/shared/src/data/default-state/patient-templates.ts @@ -1,9 +1,9 @@ import { FunctionParameters, + PatientCategory, PatientHealthState, PatientTemplate, } from '../../models'; -import { PatientCategory } from '../../models/patient-category'; import type { ImageProperties } from '../../models/utils'; import { healthPointsDefaults } from '../../models/utils'; diff --git a/shared/src/models/index.ts b/shared/src/models/index.ts index 1c81ba726..97b09a8e7 100644 --- a/shared/src/models/index.ts +++ b/shared/src/models/index.ts @@ -14,3 +14,4 @@ export { TransferPoint } from './transfer-point'; export { Vehicle } from './vehicle'; export { VehicleTemplate } from './vehicle-template'; export { Viewport } from './viewport'; +export { PatientCategory } from './patient-category'; diff --git a/shared/src/models/utils/patient-status-code.ts b/shared/src/models/utils/patient-status-code.ts index e18deed7c..02e7b220c 100644 --- a/shared/src/models/utils/patient-status-code.ts +++ b/shared/src/models/utils/patient-status-code.ts @@ -29,6 +29,7 @@ export const colorCodeMap = { Z: 'red', } as const; +// TODO [typescript@>=4.9]: Use satisfies https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator // This is only for typesafety // eslint-disable-next-line @typescript-eslint/no-unused-vars const _colorCodeMap: { readonly [key in ColorCode]: string } = colorCodeMap; diff --git a/shared/src/state.ts b/shared/src/state.ts index 9a03c7395..e5a036037 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -25,6 +25,7 @@ import { MapImageTemplate, Material, Patient, + PatientCategory, Personnel, TransferPoint, Vehicle, @@ -33,7 +34,6 @@ import { } from './models'; import { ExerciseConfiguration } from './models/exercise-configuration'; import type { MaterialTemplate } from './models/material-template'; -import { PatientCategory } from './models/patient-category'; import type { PersonnelTemplate } from './models/personnel-template'; import type { PersonnelType } from './models/utils'; import { diff --git a/shared/src/store/action-reducers/index.ts b/shared/src/store/action-reducers/index.ts index 1d868cd03..229134134 100644 --- a/shared/src/store/action-reducers/index.ts +++ b/shared/src/store/action-reducers/index.ts @@ -5,6 +5,7 @@ export * from './patient'; export * from './personnel'; export * from './vehicle'; export * from './viewport'; +export * from './map-images'; export * from './action-reducers'; // Don't forget to register the actionReducer in `action-reducers.ts` From 81c8d5bb5a41a2139ba48dcc7b6de459cb3c48e3 Mon Sep 17 00:00:00 2001 From: Clemens <68013019+ClFeSc@users.noreply.github.com> Date: Mon, 9 Jan 2023 20:46:10 +0100 Subject: [PATCH 04/58] Update packages to mitigate https://github.com/advisories/GHSA-9c47-m6qq-7p4h (#592) --- backend/package-lock.json | 12 ++++++------ frontend/package-lock.json | 6 +++--- package-lock.json | 6 +++--- shared/package-lock.json | 12 ++++++------ 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 5372753d2..d24db31c5 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -5092,9 +5092,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -7139,9 +7139,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" diff --git a/frontend/package-lock.json b/frontend/package-lock.json index ea8ce0d3c..e05663549 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -17853,9 +17853,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" diff --git a/package-lock.json b/package-lock.json index 73fd4db64..9f3970771 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1221,9 +1221,9 @@ } }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" diff --git a/shared/package-lock.json b/shared/package-lock.json index 1383970c7..74904aa2d 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -4610,9 +4610,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "bin": { "json5": "lib/cli.js" @@ -6035,9 +6035,9 @@ } }, "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", "dev": true, "dependencies": { "minimist": "^1.2.0" From a2945b8500a226529de871db8cb7cec5dc23fbfb Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Mon, 16 Jan 2023 14:04:13 +0000 Subject: [PATCH 05/58] Update dependencies (#595) * Update dependencies * typescript@4.9 (satisfies-operator and watch-performance-improvements) * angular@15.1 * Else only patch and minor version bumps * Fix version of @types/node in benchmark and frontend (18 -> 16) * Run prettier --- backend/package-lock.json | 232 +- backend/package.json | 16 +- benchmark/package-lock.json | 488 +- benchmark/package.json | 16 +- frontend/package-lock.json | 7026 +++++++---------- frontend/package.json | 50 +- .../validation/custom-validation-errors.ts | 2 +- package-lock.json | 8 +- package.json | 2 +- shared/package-lock.json | 302 +- shared/package.json | 18 +- .../src/models/utils/patient-status-code.ts | 9 +- .../store/action-reducers/action-reducers.ts | 3 +- 13 files changed, 3702 insertions(+), 4470 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index d24db31c5..8b86b185e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -24,22 +24,22 @@ "devDependencies": { "@types/cors": "^2.8.13", "@types/express": "^4.17.15", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/node": "^16", "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "nodemon": "^2.0.20", "socket.io-client": "^4.5.4", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -52,7 +52,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -60,22 +60,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -743,9 +743,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1460,9 +1460,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1593,14 +1593,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1626,14 +1626,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -1653,13 +1653,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1670,13 +1670,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1697,9 +1697,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1710,13 +1710,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1737,16 +1737,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1763,12 +1763,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1980,6 +1980,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -2999,12 +3017,12 @@ } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -3055,9 +3073,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -3067,13 +3085,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -3112,23 +3131,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -3139,12 +3160,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -3159,11 +3180,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-unicorn": { "version": "45.0.2", @@ -6065,9 +6089,9 @@ "dev": true }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" @@ -7041,15 +7065,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -7338,9 +7362,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "devOptional": true, "bin": { "tsc": "bin/tsc", diff --git a/backend/package.json b/backend/package.json index df7285997..40b4aaeb0 100644 --- a/backend/package.json +++ b/backend/package.json @@ -49,21 +49,21 @@ "devDependencies": { "@types/cors": "^2.8.13", "@types/express": "^4.17.15", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/node": "^16", "@types/supertest": "^2.0.12", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "nodemon": "^2.0.20", "socket.io-client": "^4.5.4", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" } } diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index b1c30febe..29bab06b0 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -9,21 +9,21 @@ "version": "0.0.0", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21" }, "devDependencies": { "@types/lodash-es": "^4.17.6", - "@types/node": "^18.11.16", - "@typescript-eslint/eslint-plugin": "5.46.1", - "@typescript-eslint/parser": "5.46.1", - "eslint": "^8.29.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -36,7 +36,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -44,22 +44,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -210,15 +210,15 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -367,9 +367,9 @@ } }, "node_modules/@types/node": { - "version": "18.11.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.16.tgz", - "integrity": "sha512-6T7P5bDkRhqRxrQtwj7vru+bWTpelgtcETAZEUSdq0YISKz8WKdoBukQLYQQ6DFHvU9JRsbFq0JH5C51X2ZdnA==", + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -385,14 +385,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.46.1.tgz", - "integrity": "sha512-YpzNv3aayRBwjs4J3oz65eVLXc9xx0PDbIRisHj+dYhvBn02MjYOD96P8YGiWEIFBrojaUjxvkaUpakD82phsA==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.46.1", - "@typescript-eslint/type-utils": "5.46.1", - "@typescript-eslint/utils": "5.46.1", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -417,6 +417,106 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/experimental-utils": { "version": "5.46.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.46.1.tgz", @@ -437,14 +537,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.46.1.tgz", - "integrity": "sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.46.1", - "@typescript-eslint/types": "5.46.1", - "@typescript-eslint/typescript-estree": "5.46.1", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -463,6 +563,80 @@ } } }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.46.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", @@ -481,13 +655,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.46.1.tgz", - "integrity": "sha512-V/zMyfI+jDmL1ADxfDxjZ0EMbtiVqj8LUGPAGyBkXXStWmCUErMpW873zEHsyguWCuq2iN4BrlWUkmuVj84yng==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.46.1", - "@typescript-eslint/utils": "5.46.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -507,6 +681,106 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.48.1", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/types": { "version": "5.46.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", @@ -718,6 +992,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1033,13 +1325,13 @@ } }, "node_modules/eslint": { - "version": "8.29.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.29.0.tgz", - "integrity": "sha512-isQ4EEiyUjZFbEKvEGJKKGBwXtvXX+zJbkVKCgTuB9t/+jUBcy8avhkEwWJecI15BkRkOYmvIM5ynbhRjEkoeg==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.1", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -1058,7 +1350,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -1089,9 +1381,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -1101,13 +1393,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -1146,23 +1439,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -1173,12 +1468,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -1193,11 +1488,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-total-functions": { "version": "6.0.0", @@ -1749,9 +2047,9 @@ } }, "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -2109,6 +2407,18 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2490,9 +2800,9 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" @@ -3028,18 +3338,6 @@ "strip-bom": "^3.0.0" } }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", @@ -3095,9 +3393,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/benchmark/package.json b/benchmark/package.json index c0285bd0b..230d96dcf 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -15,21 +15,21 @@ "npm": ">=8" }, "dependencies": { - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "digital-fuesim-manv-shared": "file:../shared" }, "devDependencies": { "@types/lodash-es": "^4.17.6", - "@types/node": "^18.11.16", - "@typescript-eslint/eslint-plugin": "5.46.1", - "@typescript-eslint/parser": "5.46.1", - "eslint": "^8.29.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" } } diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e05663549..65193a990 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,24 +8,24 @@ "name": "digital-fuesim-manv-frontend", "version": "0.0.0", "dependencies": { - "@angular/animations": "~15.0.4", - "@angular/common": "~15.0.4", - "@angular/compiler": "~15.0.4", - "@angular/core": "~15.0.4", - "@angular/forms": "~15.0.4", - "@angular/material": "^15.0.3", - "@angular/platform-browser": "~15.0.4", - "@angular/platform-browser-dynamic": "~15.0.4", - "@angular/router": "~15.0.4", - "@ng-bootstrap/ng-bootstrap": "^14.0.0", + "@angular/animations": "~15.1.0", + "@angular/common": "~15.1.0", + "@angular/compiler": "~15.1.0", + "@angular/core": "~15.1.0", + "@angular/forms": "~15.1.0", + "@angular/material": "^15.1.0", + "@angular/platform-browser": "~15.1.0", + "@angular/platform-browser-dynamic": "~15.1.0", + "@angular/router": "~15.1.0", + "@ng-bootstrap/ng-bootstrap": "^14.0.1", "@ngrx/store": "^15.1.0", "bootstrap": "^5.2.3", - "bootstrap-icons": "^1.10.2", - "chart.js": "^4.1.1", + "bootstrap-icons": "^1.10.3", + "chart.js": "^4.1.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "digital-fuesim-manv-shared": "file:../shared", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "4.17.21", "ol": "^7.2.2", "rxjs": "~7.8.0", @@ -33,32 +33,32 @@ "tslib": "^2.4.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.0.4", + "@angular-devkit/build-angular": "^15.1.1", "@angular-eslint/builder": "15.1.0", "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", "@angular-eslint/schematics": "15.1.0", "@angular-eslint/template-parser": "15.1.0", - "@angular/cli": "~15.0.4", - "@angular/compiler-cli": "~15.0.4", + "@angular/cli": "~15.1.1", + "@angular/compiler-cli": "~15.1.0", "@types/chart.js": "^2.9.37", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", - "@types/node": "^18", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "cypress": "^9.5.3", "cypress-image-diff-js": "^1.21.1", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "lodash": "^4.17.21", - "ts-jest": "^29.0.3", - "typescript": "~4.8.2" + "ts-jest": "^29.0.5", + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -71,7 +71,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -79,22 +79,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -103,8 +103,7 @@ }, "node_modules/@ampproject/remapping": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.1.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -114,12 +113,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1500.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1500.4.tgz", - "integrity": "sha512-U9RQueICmmNk9c2zQjUN8qi/+H6kO2VKqeyuh3Vwj6yj4lQEINf1SNX8Ba9UFH/rxNo64iFM0k5x5vX0VajvCw==", + "version": "0.1501.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1501.1.tgz", + "integrity": "sha512-2uDa/+nVGwQ5X6UJtB14V37SbD/64WSg0hKyX5z1yp6wYrSuk7PWV8hddIsiYM3aIT5wTGqfLil6NkV4G/BzQw==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", + "@angular-devkit/core": "15.1.1", "rxjs": "6.6.7" }, "engines": { @@ -147,37 +146,37 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.0.4.tgz", - "integrity": "sha512-F1KyaZEIWcVP2xIIiu3ZnH+FzuEehR9rli1F566dPijbll8EnknnItEugFtVhyoaVTh8eJmm1SfsoQrneMbrsg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.1.1.tgz", + "integrity": "sha512-9eziOA4uZwIg8OYjebkKz/yqQ1WIqajGrXr/goaAKcKhr8BprWXs5NhkIzMrELekA/dZOkR6Gpwz8d/XwplCww==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1500.4", - "@angular-devkit/build-webpack": "0.1500.4", - "@angular-devkit/core": "15.0.4", - "@babel/core": "7.20.2", - "@babel/generator": "7.20.4", + "@angular-devkit/architect": "0.1501.1", + "@angular-devkit/build-webpack": "0.1501.1", + "@angular-devkit/core": "15.1.1", + "@babel/core": "7.20.12", + "@babel/generator": "7.20.7", "@babel/helper-annotate-as-pure": "7.18.6", - "@babel/plugin-proposal-async-generator-functions": "7.20.1", - "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.20.7", + "@babel/plugin-transform-async-to-generator": "7.20.7", "@babel/plugin-transform-runtime": "7.19.6", "@babel/preset-env": "7.20.2", - "@babel/runtime": "7.20.1", - "@babel/template": "7.18.10", + "@babel/runtime": "7.20.7", + "@babel/template": "7.20.7", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "15.0.4", + "@ngtools/webpack": "15.1.1", "ansi-colors": "4.1.3", "autoprefixer": "10.4.13", - "babel-loader": "9.1.0", + "babel-loader": "9.1.2", "babel-plugin-istanbul": "6.1.1", "browserslist": "4.21.4", - "cacache": "17.0.2", + "cacache": "17.0.4", "chokidar": "3.5.3", "copy-webpack-plugin": "11.0.0", "critters": "0.0.16", "css-loader": "6.7.3", - "esbuild-wasm": "0.15.13", + "esbuild-wasm": "0.16.17", "glob": "8.0.3", "https-proxy-agent": "5.0.1", "inquirer": "8.2.4", @@ -187,27 +186,27 @@ "less-loader": "11.1.0", "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.1", - "magic-string": "0.26.7", - "mini-css-extract-plugin": "2.6.1", + "magic-string": "0.27.0", + "mini-css-extract-plugin": "2.7.2", "open": "8.4.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", "piscina": "3.2.0", - "postcss": "8.4.19", - "postcss-loader": "7.0.1", + "postcss": "8.4.21", + "postcss-loader": "7.0.2", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.56.1", + "sass": "1.57.1", "sass-loader": "13.2.0", "semver": "7.3.8", "source-map-loader": "4.0.1", "source-map-support": "0.5.21", - "terser": "5.15.1", + "terser": "5.16.1", "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.4.1", "webpack": "5.75.0", - "webpack-dev-middleware": "5.3.3", + "webpack-dev-middleware": "6.0.1", "webpack-dev-server": "4.11.1", "webpack-merge": "5.8.0", "webpack-subresource-integrity": "5.1.0" @@ -218,7 +217,7 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.15.13" + "esbuild": "0.16.17" }, "peerDependencies": { "@angular/compiler-cli": "^15.0.0", @@ -229,7 +228,7 @@ "ng-packagr": "^15.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": "~4.8.2" + "typescript": ">=4.8.2 <5.0" }, "peerDependenciesMeta": { "@angular/localize": { @@ -255,11 +254,49 @@ } } }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz", + "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.7", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-module-transforms": "^7.20.11", + "@babel/helpers": "^7.20.7", + "@babel/parser": "^7.20.7", + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.12", + "@babel/types": "^7.20.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^1.9.0" }, @@ -269,17 +306,16 @@ }, "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1500.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1500.4.tgz", - "integrity": "sha512-ay2vHMfyhaPDkzEISlRV1ZiTD/VCUunW+uRfNIzo9/o83UjTKVcqYUOUOvbIbrsb6JbQoNY+DwkES5frG1UmnA==", + "version": "0.1501.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1501.1.tgz", + "integrity": "sha512-b2Vyhx3JRHi179kSB/zc7G+/uuWq7S/7pZAau0Ry17N6Ihg2BwpLxBe0mvKcDecLmw+1ozBv2WLRCnxKXLZ4mw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1500.4", + "@angular-devkit/architect": "0.1501.1", "rxjs": "6.6.7" }, "engines": { @@ -311,12 +347,12 @@ "dev": true }, "node_modules/@angular-devkit/core": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.0.4.tgz", - "integrity": "sha512-4ITpRAevd652SxB+qNesIQ9qfbm7wT5UBU5kJOPPwGL77I21g8CQpkmV1n5VSacPvC9Zbz90feOWexf7w7JzcA==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.1.1.tgz", + "integrity": "sha512-wss76zfw4oPHs+Dd0OIbLv8os/BXDkDErj9hCjBbycQN768EqF8z7EBNGy6SKHYhmfXJy9REUkEgt9qPMJb4CQ==", "dev": true, "dependencies": { - "ajv": "8.11.0", + "ajv": "8.12.0", "ajv-formats": "2.1.1", "jsonc-parser": "3.2.0", "rxjs": "6.6.7", @@ -355,14 +391,14 @@ "dev": true }, "node_modules/@angular-devkit/schematics": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.0.4.tgz", - "integrity": "sha512-/gXiLFS0+xFdx6wPoBpe/c6/K9I5edMpaASqPf4XheKtrsSvL+qTlIi3nsbfItzOiDXbaBmlbxGfkMHz/yg0Ig==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-15.1.1.tgz", + "integrity": "sha512-ullwoxFT9aMhQR2aNwb/66A6l4HTgp4I6thbBywt86nn+ZGbJCzLKRdv2vmYh9JaxZYh1pydxWjKLEUdlycKXg==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", + "@angular-devkit/core": "15.1.1", "jsonc-parser": "3.2.0", - "magic-string": "0.26.7", + "magic-string": "0.27.0", "ora": "5.4.1", "rxjs": "6.6.7" }, @@ -392,9 +428,8 @@ }, "node_modules/@angular-eslint/builder": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-15.1.0.tgz", - "integrity": "sha512-MoPeJv4a1wSoFj8fVA01hFb+QQke2t74CSVuc6o4EqkWI0tYMM1Wg19fPtTZnj4spkGA82j2mf/tazKGRe/nrw==", "dev": true, + "license": "MIT", "peerDependencies": { "eslint": "^7.20.0 || ^8.0.0", "typescript": "*" @@ -402,15 +437,13 @@ }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-15.1.0.tgz", - "integrity": "sha512-zcOx+PnYuVDIG3wd/JVzCYdEUarKGtgIcN4iU9ZF+BVk5e8i9cbD3U8U3EDJKbrrokbFl9GBBJMCOa6XYTGJwQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-15.1.0.tgz", - "integrity": "sha512-3RRDnxaCEI5DdKq3hipXvrxctPPssrUXnNbgczJRIJ3cssr4ndobCSNqUSepA6vWj5mWe7w+nnh4vgfhZ5keig==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/utils": "15.1.0", "@typescript-eslint/utils": "5.44.0" @@ -422,9 +455,8 @@ }, "node_modules/@angular-eslint/eslint-plugin-template": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-15.1.0.tgz", - "integrity": "sha512-WofUNiLcO/oprnzswkF+u1PC6ulmqB/m7fNKMMnbExMYuK1P38gjp59FW7E+2Ivz+A4/8a5xV+U+cy3oRgh4NQ==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "@angular-eslint/utils": "15.1.0", @@ -440,9 +472,8 @@ }, "node_modules/@angular-eslint/schematics": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-15.1.0.tgz", - "integrity": "sha512-BJm7FFVCad8TV8Gtwq+FbgtLGvjJDlpt5Rne1hCd4nCr8vlQZxSWVwnTHRkAs+qd5dYn3p7bGcKZxEZzeVkWjA==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", @@ -456,9 +487,8 @@ }, "node_modules/@angular-eslint/template-parser": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-15.1.0.tgz", - "integrity": "sha512-ctcA7OAV1wwFByW1te3uZwzySuIRlo8NblG5yUtgU5BXt3nXwIDwoSr3tvI2dRHobNHcXVQcOFVzyOdXD/vsIg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "eslint-scope": "^7.0.0" @@ -470,9 +500,8 @@ }, "node_modules/@angular-eslint/utils": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-15.1.0.tgz", - "integrity": "sha512-Vt59o7wq3UOgHSCrOaHg0SgxgbAGhG0ofNQwd7sLqNP2/w/90dWY2jwWXIVSuZ+BmfVj3wgNi3KujbSWJP1cfg==", "dev": true, + "license": "MIT", "dependencies": { "@angular-eslint/bundled-angular-compiler": "15.1.0", "@typescript-eslint/utils": "5.44.0" @@ -483,9 +512,9 @@ } }, "node_modules/@angular/animations": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.0.4.tgz", - "integrity": "sha512-fOqf7fHX9aspIUmlOsig8ZyZlalU+eIBsUgu4QpH9+vfQzGCJcKIjPClW4Yb7rkNlyLlfQqaICOxG9gOxuEI7Q==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-15.1.0.tgz", + "integrity": "sha512-uBw1iQVJ3QS5e/gypsD7M50O//9GvpphgGqt9ZClknyD8dxO/YryEB+Kt4GNvNQxRKhRTksD8r4KaodukdQ15w==", "dependencies": { "tslib": "^2.3.0" }, @@ -493,13 +522,13 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4" + "@angular/core": "15.1.0" } }, "node_modules/@angular/cdk": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.0.3.tgz", - "integrity": "sha512-iRLV6V6ksIshDL8Cdn1+DUNTRLqj+DAqmYTWYCEvH4qU6o0XSeXrAHNW5zNFqWgCZbmWt03G5jOBWBNaxa9QKw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-15.1.0.tgz", + "integrity": "sha512-6X9k/OT+L6nu1ndKTX4zsSxXR8/C6CyzVY+iIytBUZ8qYaZ6kZ385YlDHyNB9x70GaC5hJkOvR0ZVupz57x0bg==", "peer": true, "dependencies": { "tslib": "^2.3.0" @@ -514,25 +543,25 @@ } }, "node_modules/@angular/cli": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.0.4.tgz", - "integrity": "sha512-dQEus458EvBYZuM10UPO/1BYshV3cprY4os6uQj6YLdEwOogElkAedUILgtTYOo3jrwc+qjefHVJbz6R+xJCOg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-15.1.1.tgz", + "integrity": "sha512-539I3B5yTasaX/EQrXZyXOc9eZUyVBxMWiGj3/bmlCsft7/Y8J+A92uftjxIO4P8lYWzSdSxFT3Bu1zI1b6yzw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1500.4", - "@angular-devkit/core": "15.0.4", - "@angular-devkit/schematics": "15.0.4", - "@schematics/angular": "15.0.4", + "@angular-devkit/architect": "0.1501.1", + "@angular-devkit/core": "15.1.1", + "@angular-devkit/schematics": "15.1.1", + "@schematics/angular": "15.1.1", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "3.0.1", "inquirer": "8.2.4", "jsonc-parser": "3.2.0", - "npm-package-arg": "9.1.2", + "npm-package-arg": "10.1.0", "npm-pick-manifest": "8.0.1", "open": "8.4.0", "ora": "5.4.1", - "pacote": "15.0.6", + "pacote": "15.0.8", "resolve": "1.22.1", "semver": "7.3.8", "symbol-observable": "4.0.0", @@ -548,9 +577,9 @@ } }, "node_modules/@angular/common": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.0.4.tgz", - "integrity": "sha512-0x/2IhaetJqfXMeQ4DlRnOTzGWD0OvOeKORyi0q7WXPxSoD9MUezQHGmzkc5lK9tDYE9cNYyQfkUBcbJT/k6MA==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-15.1.0.tgz", + "integrity": "sha512-O0JKOeJ7dFcd/mnnfm4xQOYTAc+yL+OrRpGte7z84lKPU2fupLpGW/30tHUy1TXixsANyTLC3cTVXTY5szPdqg==", "dependencies": { "tslib": "^2.3.0" }, @@ -558,14 +587,14 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4", + "@angular/core": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.0.4.tgz", - "integrity": "sha512-KtxgRJUGZamOXpIILFG2FTUW+bbc2phi/o6955/Q4LR1HOICQrYEy8PrT1Gp+lVXFKgDG+6cb01lH14LoBQvyw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-15.1.0.tgz", + "integrity": "sha512-+ky5Cvgps725Q/KdgsYzi/fe9LbT5ujhZoT9N5k+tYTJsepMUrpExFwMFkWrdMUYTK7DaxC9ufjZ4WZmHVhFoA==", "dependencies": { "tslib": "^2.3.0" }, @@ -573,7 +602,7 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/core": "15.0.4" + "@angular/core": "15.1.0" }, "peerDependenciesMeta": { "@angular/core": { @@ -582,11 +611,11 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.0.4.tgz", - "integrity": "sha512-e6Jt4qkIiyqBg8ZlpcQaQtQ5OAnfl8gfkJnIwSvvCg0mPCJv+ZkQAL5s3SpzzM5jd7Nr0jBq3zd2Fv0eKW2ayw==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-15.1.0.tgz", + "integrity": "sha512-mKeXolM/plP9ebkHy3YGxHx0Yg63d09S0QCpdIcmvrbJpaPeM2D1SAkbDpO46T4BsfgfWHtSYByb5JcesrYrpQ==", "dependencies": { - "@babel/core": "^7.17.2", + "@babel/core": "7.19.3", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -606,25 +635,51 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "15.0.4", - "typescript": ">=4.8.2 <4.9" + "@angular/compiler": "15.1.0", + "typescript": ">=4.8.2 <5.0" } }, - "node_modules/@angular/compiler-cli/node_modules/magic-string": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", - "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "node_modules/@angular/compiler-cli/node_modules/@babel/core": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", + "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.3", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helpers": "^7.19.0", + "@babel/parser": "^7.19.3", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.3", + "@babel/types": "^7.19.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular/compiler-cli/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" } }, "node_modules/@angular/core": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.0.4.tgz", - "integrity": "sha512-Xf8Nuu0iM/VjQHPS4A0jufqTYZCfiGqc0iAD7j9zM3TD6caQ3OP4mxXVYYTpIG+APKel38+Gol8cpQB/8PVbqQ==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-15.1.0.tgz", + "integrity": "sha512-HiwctuR73MuLoLeP35j9xF8/SIg7ELx+iHZtp/TBfoH+LOmjWbdrAdVAPTbqnxvK0aJG+527dhgC6tBOXgBTcg==", "dependencies": { "tslib": "^2.3.0" }, @@ -637,9 +692,9 @@ } }, "node_modules/@angular/forms": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.0.4.tgz", - "integrity": "sha512-3Ft/p2ug/zp2p0g2rhLq9v/5F1G11xa+YujAKL5kOFa0zUoroDG6n4b6VEcsGWmDE9NR7Vkiys9rHckiJUluHg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-15.1.0.tgz", + "integrity": "sha512-MUAbruJng0iG/cHhCkDNrh31Y54upgBUjjkE4DnoHv138Wa7vba+GMYv2tTrs4rPWnB9vPziZgI0xIi/oSGxzg==", "dependencies": { "tslib": "^2.3.0" }, @@ -647,16 +702,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/localize": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.0.4.tgz", - "integrity": "sha512-IuvsPT5fUyf5yn58yzXbD/Mxk3MAbVbI78CRKN2CWew6jTXuiVmaxu4cbL/a2PHhq1led318PAdCMk//Dz4Ddg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-15.1.0.tgz", + "integrity": "sha512-BTEBMKqS4F8lK4rIsydRsxMbQ1hFnDZTZoifT33dmmOworWFJCGryYw0ZCTkeBtCnkRGgnr1aOTIHTvJPFIMiA==", "peer": true, "dependencies": { "@babel/core": "7.19.3", @@ -672,14 +727,13 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/compiler": "15.0.4", - "@angular/compiler-cli": "15.0.4" + "@angular/compiler": "15.1.0", + "@angular/compiler-cli": "15.1.0" } }, "node_modules/@angular/localize/node_modules/@babel/core": { "version": "7.19.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz", - "integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==", + "license": "MIT", "peer": true, "dependencies": { "@ampproject/remapping": "^2.1.0", @@ -708,70 +762,69 @@ }, "node_modules/@angular/localize/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "peer": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@angular/material": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.0.3.tgz", - "integrity": "sha512-x7c6Uc9SnQW0AGTFJZFMQHP80YzmrExtrNn5vYUyWB9QFiNM+jcsqAsSEoGhABU/G5xs8fd40Fj7o2HBixQ0fw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/auto-init": "15.0.0-canary.7971d6ad5.0", - "@material/banner": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/card": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/chips": "15.0.0-canary.7971d6ad5.0", - "@material/circular-progress": "15.0.0-canary.7971d6ad5.0", - "@material/data-table": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dialog": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/drawer": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/fab": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/form-field": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/image-list": "15.0.0-canary.7971d6ad5.0", - "@material/layout-grid": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/linear-progress": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/radio": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/segmented-button": "15.0.0-canary.7971d6ad5.0", - "@material/select": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/slider": "15.0.0-canary.7971d6ad5.0", - "@material/snackbar": "15.0.0-canary.7971d6ad5.0", - "@material/switch": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", - "@material/tab-bar": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/tab-scroller": "15.0.0-canary.7971d6ad5.0", - "@material/textfield": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tooltip": "15.0.0-canary.7971d6ad5.0", - "@material/top-app-bar": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-15.1.0.tgz", + "integrity": "sha512-H/SBpsjf4rzSwep9er1QUh45rSsXiWh8b/HZxCP61lJSnWDUsLP1r+icLtKBAHYMpsrJHSdrgOx1do9IG2K1uQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/auto-init": "15.0.0-canary.fd95ca7ef.0", + "@material/banner": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/card": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/chips": "15.0.0-canary.fd95ca7ef.0", + "@material/circular-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/data-table": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dialog": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/drawer": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/fab": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/form-field": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/image-list": "15.0.0-canary.fd95ca7ef.0", + "@material/layout-grid": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/linear-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/radio": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/segmented-button": "15.0.0-canary.fd95ca7ef.0", + "@material/select": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/slider": "15.0.0-canary.fd95ca7ef.0", + "@material/snackbar": "15.0.0-canary.fd95ca7ef.0", + "@material/switch": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-bar": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-scroller": "15.0.0-canary.fd95ca7ef.0", + "@material/textfield": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tooltip": "15.0.0-canary.fd95ca7ef.0", + "@material/top-app-bar": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.3.0" }, "peerDependencies": { "@angular/animations": "^15.0.0 || ^16.0.0", - "@angular/cdk": "15.0.3", + "@angular/cdk": "15.1.0", "@angular/common": "^15.0.0 || ^16.0.0", "@angular/core": "^15.0.0 || ^16.0.0", "@angular/forms": "^15.0.0 || ^16.0.0", @@ -780,9 +833,9 @@ } }, "node_modules/@angular/platform-browser": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.0.4.tgz", - "integrity": "sha512-SOLrzh9AsHzhfre95ShvHd0hBcyEcFftJuAaU+35L4GiOAY+CznFuJUq4LjITCMQDHGzdpUlRjoUyJRQFmlvXQ==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-15.1.0.tgz", + "integrity": "sha512-yuJweAR+rJhWWHM4Im3Iy6S4+W3OtcVHijcqrxfVxiA9ZHbDw/jpYDi06ZZIgfnNyGWi5/BzJbHvxH3b0lAo5Q==", "dependencies": { "tslib": "^2.3.0" }, @@ -790,9 +843,9 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/animations": "15.0.4", - "@angular/common": "15.0.4", - "@angular/core": "15.0.4" + "@angular/animations": "15.1.0", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0" }, "peerDependenciesMeta": { "@angular/animations": { @@ -801,9 +854,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.0.4.tgz", - "integrity": "sha512-SCUxsfJAHXnAyo2ulmfqs3vGnB/tWNKe+G2KKshrSLyCYIJ3UgpsoPAo1mGih64qo8TWOQk9PJgrlVEB2DoWYg==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-15.1.0.tgz", + "integrity": "sha512-ukyycXkuu4Ah/35cbN4pEB91D2PK5eZVbJ+liCD6uRb4UI3X+QVg6Qz6MoIctVAlTV6tWK20T81zoux9SzWKsg==", "dependencies": { "tslib": "^2.3.0" }, @@ -811,16 +864,16 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/compiler": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4" + "@angular/common": "15.1.0", + "@angular/compiler": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0" } }, "node_modules/@angular/router": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.0.4.tgz", - "integrity": "sha512-6cBUu1kSigORGpWq+Wc3hTLRQcJvtlaZ5OFOIzKGiBEPgezn/AzrWHi/bEccWLZAVFhbUOhcRn9GwudqiqX6+A==", + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-15.1.0.tgz", + "integrity": "sha512-78ItVVXOYdu/RRxruHwSmtNxEP2clx+afHKrkwc4e7/6uxVr4rl0VQhO6qHYme/bBtbLIcBZGJoSyoUg/xUSvQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -828,22 +881,20 @@ "node": "^14.20.0 || ^16.13.0 || >=18.10.0" }, "peerDependencies": { - "@angular/common": "15.0.4", - "@angular/core": "15.0.4", - "@angular/platform-browser": "15.0.4", + "@angular/common": "15.1.0", + "@angular/core": "15.1.0", + "@angular/platform-browser": "15.1.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@assemblyscript/loader": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", - "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@babel/code-frame": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", - "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "license": "MIT", "dependencies": { "@babel/highlight": "^7.18.6" }, @@ -853,16 +904,14 @@ }, "node_modules/@babel/compat-data": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.5.tgz", - "integrity": "sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.2.tgz", - "integrity": "sha512-w7DbG8DtMrJcFOi4VrLm+8QM4az8Mo+PuLBKLp2zrYRCow8W/f9xiXm5sN53C8HksCyDQwCKha9JiDoIyPjT2g==", + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", @@ -890,18 +939,17 @@ }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.4.tgz", - "integrity": "sha512-luCf7yk/cm7yab6CAW1aiFnmEfBJplb/JojV56MYEK7ziWfGmFlTfmL9Ehwfy4gFhbjBfWO1wj7/TuSbVNEEtA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz", + "integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==", "dependencies": { - "@babel/types": "^7.20.2", + "@babel/types": "^7.20.7", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -911,8 +959,7 @@ }, "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -924,9 +971,8 @@ }, "node_modules/@babel/helper-annotate-as-pure": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", - "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -936,9 +982,8 @@ }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", - "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-explode-assignable-expression": "^7.18.6", "@babel/types": "^7.18.9" @@ -948,13 +993,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz", - "integrity": "sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz", + "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==", "dependencies": { - "@babel/compat-data": "^7.20.0", + "@babel/compat-data": "^7.20.5", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.21.3", + "lru-cache": "^5.1.1", "semver": "^6.3.0" }, "engines": { @@ -964,19 +1010,30 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, "node_modules/@babel/helper-create-class-features-plugin": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.5.tgz", - "integrity": "sha512-3RCdA/EmEaikrhayahwToF0fpweU/8o2p8vhc1c/1kftHOdTKuC65kik/TLc+qfbS8JKw4qqJbne4ovICDhmww==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -995,9 +1052,8 @@ }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz", - "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "regexpu-core": "^5.2.1" @@ -1011,9 +1067,8 @@ }, "node_modules/@babel/helper-define-polyfill-provider": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", - "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -1028,26 +1083,23 @@ }, "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-explode-assignable-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", - "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1057,8 +1109,7 @@ }, "node_modules/@babel/helper-function-name": { "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", - "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "license": "MIT", "dependencies": { "@babel/template": "^7.18.10", "@babel/types": "^7.19.0" @@ -1069,8 +1120,7 @@ }, "node_modules/@babel/helper-hoist-variables": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1080,9 +1130,8 @@ }, "node_modules/@babel/helper-member-expression-to-functions": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", - "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.9" }, @@ -1092,8 +1141,7 @@ }, "node_modules/@babel/helper-module-imports": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1102,18 +1150,18 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.2.tgz", - "integrity": "sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==", + "version": "7.20.11", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz", + "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.20.2", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.1", - "@babel/types": "^7.20.2" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.10", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -1121,9 +1169,8 @@ }, "node_modules/@babel/helper-optimise-call-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", - "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1133,18 +1180,16 @@ }, "node_modules/@babel/helper-plugin-utils": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", - "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-environment-visitor": "^7.18.9", @@ -1160,9 +1205,8 @@ }, "node_modules/@babel/helper-replace-supers": { "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", - "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-member-expression-to-functions": "^7.18.9", @@ -1176,8 +1220,7 @@ }, "node_modules/@babel/helper-simple-access": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.20.2" }, @@ -1187,9 +1230,8 @@ }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", - "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.0" }, @@ -1199,8 +1241,7 @@ }, "node_modules/@babel/helper-split-export-declaration": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "license": "MIT", "dependencies": { "@babel/types": "^7.18.6" }, @@ -1210,33 +1251,29 @@ }, "node_modules/@babel/helper-string-parser": { "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz", - "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-function-name": "^7.19.0", "@babel/template": "^7.18.10", @@ -1248,13 +1285,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.20.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.6.tgz", - "integrity": "sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz", + "integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==", "dependencies": { - "@babel/template": "^7.18.10", - "@babel/traverse": "^7.20.5", - "@babel/types": "^7.20.5" + "@babel/template": "^7.20.7", + "@babel/traverse": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" @@ -1262,8 +1299,7 @@ }, "node_modules/@babel/highlight": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -1274,9 +1310,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", - "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz", + "integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1286,9 +1322,8 @@ }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", - "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1301,9 +1336,8 @@ }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", - "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", @@ -1317,13 +1351,13 @@ } }, "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.1.tgz", - "integrity": "sha512-Gh5rchzSwE4kC+o/6T8waD0WHEQIsDmjltY8WnWRXHUdH8axZhuH86Ov9M72YhJfDrZseQwuuWaaIT/TmePp3g==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" }, @@ -1336,9 +1370,8 @@ }, "node_modules/@babel/plugin-proposal-class-properties": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", - "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1352,9 +1385,8 @@ }, "node_modules/@babel/plugin-proposal-class-static-block": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", - "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6", @@ -1369,9 +1401,8 @@ }, "node_modules/@babel/plugin-proposal-dynamic-import": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", - "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3" @@ -1385,9 +1416,8 @@ }, "node_modules/@babel/plugin-proposal-export-namespace-from": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", - "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" @@ -1401,9 +1431,8 @@ }, "node_modules/@babel/plugin-proposal-json-strings": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", - "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-json-strings": "^7.8.3" @@ -1417,9 +1446,8 @@ }, "node_modules/@babel/plugin-proposal-logical-assignment-operators": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", - "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" @@ -1433,9 +1461,8 @@ }, "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", - "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -1449,9 +1476,8 @@ }, "node_modules/@babel/plugin-proposal-numeric-separator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", - "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-numeric-separator": "^7.10.4" @@ -1465,9 +1491,8 @@ }, "node_modules/@babel/plugin-proposal-object-rest-spread": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.2.tgz", - "integrity": "sha512-Ks6uej9WFK+fvIMesSqbAto5dD8Dz4VuuFvGJFKgIGSkJuRGcrwGECPA1fDgQK3/DbExBJpEkTeYeB8geIFCSQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.1", "@babel/helper-compilation-targets": "^7.20.0", @@ -1484,9 +1509,8 @@ }, "node_modules/@babel/plugin-proposal-optional-catch-binding": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", - "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" @@ -1500,9 +1524,8 @@ }, "node_modules/@babel/plugin-proposal-optional-chaining": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", - "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", @@ -1517,9 +1540,8 @@ }, "node_modules/@babel/plugin-proposal-private-methods": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", - "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1533,9 +1555,8 @@ }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz", - "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-create-class-features-plugin": "^7.20.5", @@ -1551,9 +1572,8 @@ }, "node_modules/@babel/plugin-proposal-unicode-property-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", - "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1567,9 +1587,8 @@ }, "node_modules/@babel/plugin-syntax-async-generators": { "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1579,9 +1598,8 @@ }, "node_modules/@babel/plugin-syntax-bigint": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1591,9 +1609,8 @@ }, "node_modules/@babel/plugin-syntax-class-properties": { "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -1603,9 +1620,8 @@ }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1618,9 +1634,8 @@ }, "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1630,9 +1645,8 @@ }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.3" }, @@ -1642,9 +1656,8 @@ }, "node_modules/@babel/plugin-syntax-import-assertions": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz", - "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -1657,9 +1670,8 @@ }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1669,9 +1681,8 @@ }, "node_modules/@babel/plugin-syntax-json-strings": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1681,9 +1692,8 @@ }, "node_modules/@babel/plugin-syntax-jsx": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz", - "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1696,9 +1706,8 @@ }, "node_modules/@babel/plugin-syntax-logical-assignment-operators": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1708,9 +1717,8 @@ }, "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1720,9 +1728,8 @@ }, "node_modules/@babel/plugin-syntax-numeric-separator": { "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1732,9 +1739,8 @@ }, "node_modules/@babel/plugin-syntax-object-rest-spread": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1744,9 +1750,8 @@ }, "node_modules/@babel/plugin-syntax-optional-catch-binding": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1756,9 +1761,8 @@ }, "node_modules/@babel/plugin-syntax-optional-chaining": { "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1768,9 +1772,8 @@ }, "node_modules/@babel/plugin-syntax-private-property-in-object": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1783,9 +1786,8 @@ }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1798,9 +1800,8 @@ }, "node_modules/@babel/plugin-syntax-typescript": { "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.20.0.tgz", - "integrity": "sha512-rd9TkG+u1CExzS4SM1BlMEhMXwFLKVjOAFFCDx9PbX5ycJWDoWMcwdJH9RhkPu1dOgn5TrxLot/Gx6lWFuAUNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0" }, @@ -1813,9 +1814,8 @@ }, "node_modules/@babel/plugin-transform-arrow-functions": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", - "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1827,14 +1827,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", - "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz", + "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==", "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6" + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9" }, "engines": { "node": ">=6.9.0" @@ -1845,9 +1845,8 @@ }, "node_modules/@babel/plugin-transform-block-scoped-functions": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", - "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1860,9 +1859,8 @@ }, "node_modules/@babel/plugin-transform-block-scoping": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.5.tgz", - "integrity": "sha512-WvpEIW9Cbj9ApF3yJCjIEEf1EiNJLtXagOrL5LNWEZOo3jv8pmPoYTSNJQvqej8OavVlgOoOPw6/htGZro6IkA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -1875,9 +1873,8 @@ }, "node_modules/@babel/plugin-transform-classes": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.2.tgz", - "integrity": "sha512-9rbPp0lCVVoagvtEyQKSo5L8oo0nQS/iif+lwlAz29MccX2642vWDlSZK+2T2buxbopotId2ld7zZAzRfz9j1g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-compilation-targets": "^7.20.0", @@ -1898,9 +1895,8 @@ }, "node_modules/@babel/plugin-transform-computed-properties": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", - "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -1913,9 +1909,8 @@ }, "node_modules/@babel/plugin-transform-destructuring": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.2.tgz", - "integrity": "sha512-mENM+ZHrvEgxLTBXUiQ621rRXZes3KWUv6NdQlrnr1TkWVw+hUjQBZuP2X32qKlrlG2BzgR95gkuCRSkJl8vIw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -1928,9 +1923,8 @@ }, "node_modules/@babel/plugin-transform-dotall-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", - "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1944,9 +1938,8 @@ }, "node_modules/@babel/plugin-transform-duplicate-keys": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", - "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -1959,9 +1952,8 @@ }, "node_modules/@babel/plugin-transform-exponentiation-operator": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", - "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1975,9 +1967,8 @@ }, "node_modules/@babel/plugin-transform-for-of": { "version": "7.18.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", - "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -1990,9 +1981,8 @@ }, "node_modules/@babel/plugin-transform-function-name": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", - "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-function-name": "^7.18.9", @@ -2007,9 +1997,8 @@ }, "node_modules/@babel/plugin-transform-literals": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", - "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2022,9 +2011,8 @@ }, "node_modules/@babel/plugin-transform-member-expression-literals": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", - "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2037,9 +2025,8 @@ }, "node_modules/@babel/plugin-transform-modules-amd": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.19.6.tgz", - "integrity": "sha512-uG3od2mXvAtIFQIh0xrpLH6r5fpSQN04gIVovl+ODLdUMANokxQLZnPBHcjmv3GxRjnqwLuHvppjjcelqUFZvg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.19.6", "@babel/helper-plugin-utils": "^7.19.0" @@ -2053,9 +2040,8 @@ }, "node_modules/@babel/plugin-transform-modules-commonjs": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.19.6.tgz", - "integrity": "sha512-8PIa1ym4XRTKuSsOUXqDG0YaOlEuTVvHMe5JCfgBMOtHvJKw/4NGovEGN33viISshG/rZNVrACiBmPQLvWN8xQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.19.6", "@babel/helper-plugin-utils": "^7.19.0", @@ -2070,9 +2056,8 @@ }, "node_modules/@babel/plugin-transform-modules-systemjs": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.6.tgz", - "integrity": "sha512-fqGLBepcc3kErfR9R3DnVpURmckXP7gj7bAlrTQyBxrigFqszZCkFkcoxzCp2v32XmwXLvbw+8Yq9/b+QqksjQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-module-transforms": "^7.19.6", @@ -2088,9 +2073,8 @@ }, "node_modules/@babel/plugin-transform-modules-umd": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", - "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-transforms": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -2104,9 +2088,8 @@ }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz", - "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.20.5", "@babel/helper-plugin-utils": "^7.20.2" @@ -2120,9 +2103,8 @@ }, "node_modules/@babel/plugin-transform-new-target": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", - "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2135,9 +2117,8 @@ }, "node_modules/@babel/plugin-transform-object-super": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", - "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/helper-replace-supers": "^7.18.6" @@ -2151,9 +2132,8 @@ }, "node_modules/@babel/plugin-transform-parameters": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.5.tgz", - "integrity": "sha512-h7plkOmcndIUWXZFLgpbrh2+fXAi47zcUX7IrOQuZdLD0I0KvjJ6cvo3BEcAOsDOcZhVKGJqv07mkSqK0y2isQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" }, @@ -2166,9 +2146,8 @@ }, "node_modules/@babel/plugin-transform-property-literals": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", - "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2181,9 +2160,8 @@ }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz", - "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "regenerator-transform": "^0.15.1" @@ -2197,9 +2175,8 @@ }, "node_modules/@babel/plugin-transform-reserved-words": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", - "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2212,9 +2189,8 @@ }, "node_modules/@babel/plugin-transform-runtime": { "version": "7.19.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz", - "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-module-imports": "^7.18.6", "@babel/helper-plugin-utils": "^7.19.0", @@ -2232,18 +2208,16 @@ }, "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/plugin-transform-shorthand-properties": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", - "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2256,9 +2230,8 @@ }, "node_modules/@babel/plugin-transform-spread": { "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", - "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.19.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" @@ -2272,9 +2245,8 @@ }, "node_modules/@babel/plugin-transform-sticky-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", - "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.6" }, @@ -2287,9 +2259,8 @@ }, "node_modules/@babel/plugin-transform-template-literals": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", - "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2302,9 +2273,8 @@ }, "node_modules/@babel/plugin-transform-typeof-symbol": { "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", - "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2317,9 +2287,8 @@ }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", - "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.18.9" }, @@ -2332,9 +2301,8 @@ }, "node_modules/@babel/plugin-transform-unicode-regex": { "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", - "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -2348,9 +2316,8 @@ }, "node_modules/@babel/preset-env": { "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz", - "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.1", "@babel/helper-compilation-targets": "^7.20.0", @@ -2437,18 +2404,16 @@ }, "node_modules/@babel/preset-env/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/preset-modules": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", @@ -2461,43 +2426,43 @@ } }, "node_modules/@babel/runtime": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.1.tgz", - "integrity": "sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz", + "integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==", "dev": true, "dependencies": { - "regenerator-runtime": "^0.13.10" + "regenerator-runtime": "^0.13.11" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/template": { - "version": "7.18.10", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", - "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", + "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.10", - "@babel/types": "^7.18.10" + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.5.tgz", - "integrity": "sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==", + "version": "7.20.12", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz", + "integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.20.5", + "@babel/generator": "^7.20.7", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.19.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.20.5", - "@babel/types": "^7.20.5", + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2505,36 +2470,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.5.tgz", - "integrity": "sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==", - "dependencies": { - "@babel/types": "^7.20.5", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@babel/types": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.5.tgz", - "integrity": "sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz", + "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -2546,15 +2485,13 @@ }, "node_modules/@bcoe/v8-coverage": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@colors/colors": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=0.1.90" @@ -2562,9 +2499,8 @@ }, "node_modules/@cypress/request": { "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -2591,9 +2527,8 @@ }, "node_modules/@cypress/xvfb": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.1.0", "lodash.once": "^4.1.1" @@ -2601,26 +2536,24 @@ }, "node_modules/@cypress/xvfb/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/@discoveryjs/json-ext": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.13.tgz", - "integrity": "sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw==", + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.17.tgz", + "integrity": "sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==", "cpu": [ "arm" ], @@ -2633,107 +2566,426 @@ "node": ">=12" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz", - "integrity": "sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag==", + "node_modules/@esbuild/android-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz", + "integrity": "sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==", "cpu": [ - "loong64" + "arm64" ], "dev": true, "optional": true, "os": [ - "linux" + "android" ], "engines": { "node": ">=12" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", - "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "node_modules/@esbuild/android-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.17.tgz", + "integrity": "sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz", + "integrity": "sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.4.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz", + "integrity": "sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz", + "integrity": "sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/@eslint/eslintrc/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==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz", + "integrity": "sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz", + "integrity": "sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz", + "integrity": "sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz", + "integrity": "sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz", + "integrity": "sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz", + "integrity": "sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz", + "integrity": "sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz", + "integrity": "sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz", + "integrity": "sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz", + "integrity": "sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz", + "integrity": "sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz", + "integrity": "sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz", + "integrity": "sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz", + "integrity": "sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz", + "integrity": "sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz", + "integrity": "sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/globals": { + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/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/@eslint/eslintrc/node_modules/json-schema-traverse": { @@ -2762,9 +3014,8 @@ }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -2776,9 +3027,8 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -2789,15 +3039,13 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -2811,18 +3059,16 @@ }, "node_modules/@istanbuljs/schema": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.3.1.tgz", - "integrity": "sha512-IRE6GD47KwcqA09RIWrabKdHPiKDGgtAL31xDxbi/RjQMsr+lY+ppxmHwY0dUEV3qvvxZzoe5Hl0RXZJOjQNUg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -2837,9 +3083,8 @@ }, "node_modules/@jest/console/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2852,9 +3097,8 @@ }, "node_modules/@jest/console/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2868,9 +3112,8 @@ }, "node_modules/@jest/console/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2880,24 +3123,21 @@ }, "node_modules/@jest/console/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/console/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/console/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -2907,9 +3147,8 @@ }, "node_modules/@jest/core": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.3.1.tgz", - "integrity": "sha512-0ohVjjRex985w5MmO5L3u5GR1O30DexhBSpuwx2P+9ftyqHdJXnk7IUWiP80oHMvt7ubHCJHxV0a0vlKVuZirw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/reporters": "^29.3.1", @@ -2954,9 +3193,8 @@ }, "node_modules/@jest/core/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -2969,9 +3207,8 @@ }, "node_modules/@jest/core/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2985,9 +3222,8 @@ }, "node_modules/@jest/core/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -2997,24 +3233,21 @@ }, "node_modules/@jest/core/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/core/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/core/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3024,9 +3257,8 @@ }, "node_modules/@jest/environment": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.3.1.tgz", - "integrity": "sha512-pMmvfOPmoa1c1QpfFW0nXYtNLpofqo4BrCIk6f2kW4JFeNlHV2t3vd+3iDLf31e2ot2Mec0uqZfmI+U0K2CFag==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.3.1", "@jest/types": "^29.3.1", @@ -3039,9 +3271,8 @@ }, "node_modules/@jest/expect": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-QivM7GlSHSsIAWzgfyP8dgeExPRZ9BIe2LsdPyEhCGkZkoyA+kGsoIzbKAfZCvvRzfZioKwPtCZIt5SaoxYCvg==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.3.1", "jest-snapshot": "^29.3.1" @@ -3052,9 +3283,8 @@ }, "node_modules/@jest/expect-utils": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.3.1.tgz", - "integrity": "sha512-wlrznINZI5sMjwvUoLVk617ll/UYfGIZNxmbU+Pa7wmkL4vYzhV9R2pwVqUh4NWWuLQWkI8+8mOkxs//prKQ3g==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.2.0" }, @@ -3064,9 +3294,8 @@ }, "node_modules/@jest/fake-timers": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.3.1.tgz", - "integrity": "sha512-iHTL/XpnDlFki9Tq0Q1GGuVeQ8BHZGIYsvCO5eN/O/oJaRzofG9Xndd9HuSDBI/0ZS79pg0iwn07OMTQ7ngF2A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@sinonjs/fake-timers": "^9.1.2", @@ -3081,9 +3310,8 @@ }, "node_modules/@jest/globals": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.3.1.tgz", - "integrity": "sha512-cTicd134vOcwO59OPaB6AmdHQMCtWOe+/DitpTZVxWgMJ+YvXL1HNAmPyiGbSHmF/mXVBkvlm8YYtQhyHPnV6Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/expect": "^29.3.1", @@ -3096,9 +3324,8 @@ }, "node_modules/@jest/reporters": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.3.1.tgz", - "integrity": "sha512-GhBu3YFuDrcAYW/UESz1JphEAbvUjaY2vShRZRoRY1mxpCMB3yGSJ4j9n0GxVlEOdCf7qjvUfBCrTUUqhVfbRA==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.3.1", @@ -3139,9 +3366,8 @@ }, "node_modules/@jest/reporters/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3154,9 +3380,8 @@ }, "node_modules/@jest/reporters/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3170,9 +3395,8 @@ }, "node_modules/@jest/reporters/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3182,15 +3406,13 @@ }, "node_modules/@jest/reporters/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/reporters/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -3208,18 +3430,16 @@ }, "node_modules/@jest/reporters/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/reporters/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3229,9 +3449,8 @@ }, "node_modules/@jest/schemas": { "version": "29.0.0", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.0.0.tgz", - "integrity": "sha512-3Ab5HgYIIAnS0HjqJHQYZS+zXc4tUmTmBH3z83ajI6afXp8X3ZtdLX+nXx+I7LNkJD7uN9LAVhgnjDgZa2z0kA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.24.1" }, @@ -3241,9 +3460,8 @@ }, "node_modules/@jest/source-map": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.2.0.tgz", - "integrity": "sha512-1NX9/7zzI0nqa6+kgpSdKPK+WU1p+SJk3TloWZf5MzPbxri9UEeXX5bWZAPCzbQcyuAzubcdUHA7hcNznmRqWQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.15", "callsites": "^3.0.0", @@ -3255,9 +3473,8 @@ }, "node_modules/@jest/test-result": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.3.1.tgz", - "integrity": "sha512-qeLa6qc0ddB0kuOZyZIhfN5q0e2htngokyTWsGriedsDhItisW7SDYZ7ceOe57Ii03sL988/03wAcBh3TChMGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/types": "^29.3.1", @@ -3270,9 +3487,8 @@ }, "node_modules/@jest/test-sequencer": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.3.1.tgz", - "integrity": "sha512-IqYvLbieTv20ArgKoAMyhLHNrVHJfzO6ARZAbQRlY4UGWfdDnLlZEF0BvKOMd77uIiIjSZRwq3Jb3Fa3I8+2UA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.3.1", "graceful-fs": "^4.2.9", @@ -3285,9 +3501,8 @@ }, "node_modules/@jest/transform": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.3.1.tgz", - "integrity": "sha512-8wmCFBTVGYqFNLWfcOWoVuMuKYPUBTnTMDkdvFtAYELwDOl9RGwOsvQWGPFxDJ8AWY9xM/8xCXdqmPK3+Q5Lug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.3.1", @@ -3311,9 +3526,8 @@ }, "node_modules/@jest/transform/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3326,9 +3540,8 @@ }, "node_modules/@jest/transform/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3342,9 +3555,8 @@ }, "node_modules/@jest/transform/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3354,30 +3566,26 @@ }, "node_modules/@jest/transform/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/transform/node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/transform/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3387,9 +3595,8 @@ }, "node_modules/@jest/types": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.3.1.tgz", - "integrity": "sha512-d0S0jmmTpjnhCmNpApgX3jrUZgZ22ivKJRvL2lli5hpCRoNnp1f85r2/wpKfXuYu8E7Jjh1hGfhPyup1NM5AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.0.0", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3404,9 +3611,8 @@ }, "node_modules/@jest/types/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -3419,9 +3625,8 @@ }, "node_modules/@jest/types/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -3435,9 +3640,8 @@ }, "node_modules/@jest/types/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3447,24 +3651,21 @@ }, "node_modules/@jest/types/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/@jest/types/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -3474,8 +3675,7 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.0", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -3486,25 +3686,22 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -3512,9 +3709,8 @@ }, "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -3526,13 +3722,11 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.17", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", - "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "3.1.0", "@jridgewell/sourcemap-codec": "1.4.14" @@ -3540,8 +3734,7 @@ }, "node_modules/@kurkle/color": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.1.tgz", - "integrity": "sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==" + "license": "MIT" }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", @@ -3551,16 +3744,13 @@ }, "node_modules/@mapbox/jsonlint-lines-primitives": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz", - "integrity": "sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==", "engines": { "node": ">= 0.6" } }, "node_modules/@mapbox/mapbox-gl-style-spec": { "version": "13.27.0", - "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.27.0.tgz", - "integrity": "sha512-wQSJCGRyf7pWknQgeGBArHEk8898UcI1BnAam7IRa3AGmHRFzlJ6DzoU24Hld9zJ0tgkNQ7OP5sJT/9hKHzavg==", + "license": "ISC", "dependencies": { "@mapbox/jsonlint-lines-primitives": "~2.0.2", "@mapbox/point-geometry": "^0.1.0", @@ -3580,766 +3770,767 @@ }, "node_modules/@mapbox/point-geometry": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz", - "integrity": "sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==" + "license": "ISC" }, "node_modules/@mapbox/unitbezier": { "version": "0.0.0", - "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz", - "integrity": "sha512-HPnRdYO0WjFjRTSwO3frz1wKaU649OBFPX3Zo/2WZvuRi6zMiRGui8SnPQiQABgqCf8YikDe5t3HViTVw1WUzA==" + "license": "BSD-2-Clause" }, "node_modules/@material/animation": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-nOCOgzp/Vdgloyw/SjFCEtpcxXWtXUjvX+JCVg7o+EEtaGLBQdgjJUj5lt+RQ6e9r0eiMYKJ6l1+1TGGebsIfA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-zMUnqghXPj65NpEHw7n70qZ2Epaue7Y/aue+EWrWYiaQo5a0zxNttYyc5XTw0KOqfHyB9Yz4wO9BTQDCKWSWtg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/auto-init": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JmST/NkQpdJ1+nyAU8qbV1eRXbOwvpaTRy096Y5mOK1CeUsagUyrKkCeLsO56pmvayxnOIkJCOhH/8gzIsmiJA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/auto-init/-/auto-init-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-CrsCatcRWu6MbZZ83wcA2e591ag2mrqbFg8lioAkOU/XypGRgObVH7mK/Jih0LTHsZrvjIq3MNJZirkpZifb2g==", "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/banner": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-OA23YGt9qTz5i+FdGgk4QpRkmby/w+k12YMlL7u+TmwWIiGom2AaOy/DbBCr2/uNJEJ6o0h+wcNBEmGe7bJutw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/banner/-/banner-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-lplDzQjQGbImfr+IYkO0USpgDsWx/vk0e6qg71jwd23m75NOZG6Pv0U1gtL2LLVr4hgedbLq/gqKSilsZkKxZQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/base": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-wXgoWl8NG4BZ2U8MCg4BLQLNla3IdyxBJIMSsJ1qvP2YswmG9HXTkS8y9mHTAhzzQEFQtlwDOyp4Ntq2Ep4WZA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/base/-/base-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pIdMbChPElwv8bsyKvd4yY1lVbpD7RJfzfPhzI6Rpud01+fAYSon3K0oTruZgMR9nRLVC83qEPFlWXGXRLvY1w==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-lyV4unJUG/onzNSLL5TjTGJxscBReG6+lNBvGSfgCafW2bfHW278BbqPDbPr52ONe6vg5INptZJ6bZx4FStGIQ==", - "dependencies": { - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/button/-/button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-EG32mxhJZmiWJAvQ1CFsAd95NQfbxFNnmRIphNfvER3koy+zEKVB7CjVAXK3XCptlvSfbn5384qfAJKYsK9HsA==", + "dependencies": { + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/card": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-0YNba4Keg+a0U4JK+siLDbTyO13s40hm88kX7uQ46SmsQlY3fbMsdOpX9+y/PaOkOXIJIgX6g+c7ASM7c/6Zyw==", - "dependencies": { - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/card/-/card-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-t+fe6ICrFzY681+qGUwHrzHGv44Hn4xldv7VCQW7jxzqvz3pa/w3deDYnVdrzLVHLntzvuTbvJEzcqmC53vQFA==", + "dependencies": { + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/checkbox": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-RSFJhMtU28BhXWyQHMrThqkGMtYb16JOuKkZ54bc1AzIndQnniQoGpkb5tHx1hOCGhOUyAGVh/w8BHczWRsLbw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/checkbox/-/checkbox-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-UPxRSildKAqnucLpB4Oh2KdAYeypjzveFFPMkWY3d/p7W6bgTmMg249jLAIFrcudBjPgrMem6J7DPBMiicud4A==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/chips": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-W8e90cxnERoP/OvsYSSkjP/HEeogYH1YJVBemKfTOQyAAMh3DmetBGdO6Gdf65/Jt7iYrvab5IPn0D7DWoMZlQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/chips/-/chips-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-M7bfcCicB58k9nSvIlsR0FYM5ahhwh25IK1ybVKWBvtCDD4dyXVgeIc+e+u9E/i8e2KVzCMclwX1P6xocHJx7w==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/circular-progress": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-dE66rFNI9T2khLejoTyONQZqnHjUXsmdzDx1lI3qO918gtdkwdBVWvFm0U7+1VdHAB9sjP4o+mVL/3rNss2Jtg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/progress-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/circular-progress/-/circular-progress-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-lsM+X5cnvvrqsdsVoxl4lySShw9w6CK7Q55VGfR2Pwd7oqid4bZX1uOOgpz7WHUxT4AOJ6PX/iHDClueEx8lrA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/progress-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/data-table": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JIg3GqnWGoiP5OXRkM7xjpoYIcal3a2vcvx8qUBK8rJZUXXShMcrFD8bpoEK+VIo7NXp5oR3baR3g063sTmv7g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/checkbox": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/linear-progress": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/select": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/data-table/-/data-table-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-eg2ohraF8LLva1rAWrJ6R5Ei06k7tp1azewL46rtRulJGjBJHCUfkstfxx21S/PdX7CsPyWwPoWDCxgk2zo1Sw==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/checkbox": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/linear-progress": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/select": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/density": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-JfRRdyewKuVGDLTxm0Bn/5MFgkPHo5fZ0JU6kCqI+SdOER/ceRti6xJtNfgV/lBPqstftARcKv116nQRy2085Q==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/density/-/density-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-3scwdXi0xIVL6CZSGVWTxg935zomwMlqEBt0/BdxG96YJ0p+G0Rxb6TVfuzld/isD9Fx8XufV+wNkx0riZ30Vg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/dialog": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-P7+nNN1YdPISSOIECyECiYNcmAJn4ezogpkcGkGBKc0KZAzG47Y1prgLNFaHat5mE20GjLL50M7T4SU7F64dqA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/dialog/-/dialog-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-szjN6QewCVN3ucnZSjfolDlUZdk5smmNRhX4RnF/OTF/6n41D3iHFTVNws10idWzBC3zZX1L9ZY910nsYy5xHA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/dom": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-h+KV0egRy7zniZElzDW5duh/VDZUTO9SmMeC8FFiqJMvPe3V8xcH0zB+jL67hueLqFixSSJebbdXMbVce4nwOA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/dom/-/dom-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-+JjOY81x3d3TlwCztSr4BRxUeEHcg5kwtlbT9Zy/UgdqNStrlTCMeTzRyLNifFnztFzoaWIc6MtF3rLelA/k6Q==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/drawer": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-LYuriNp3lecXXIj3lK22z0ym5bGHHIturofEV60BK9uHi4baBWS/ovTPAw5T8YvpADv5kyidg4mkgkPY9Ydexg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/drawer/-/drawer-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-cRSHHU03Q502iJr0iEQFYEhdsIC+Gms43qXmAnjLFUs1EPDxlf/tKiJnvQX6QI03Z5PBoiArCRFjd3/uTvp2KA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/elevation": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-M9SZKJI5wjbOwq0o8eknDrI27YE63wLg8qJHLvJWrWXdlm6yN0INilihExzmGHXpVHQ6sUdI4oyoAx1qr+vorQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/elevation/-/elevation-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-16UkRgq3weby4XaUnL1sUNdRnHgcqBEzCH8bF3JdrrnwqdH/PW74oH+MsXEVctbEsIR8s6rzldcD/0Wqlr/gnQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/fab": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-G58ZFK7M9r9xkLFP0Gufh1VKdcvRcTvYwEjBuG3+XOMDMjFzCDEMY4c54RG+tbwIiHmB8lw1Yl/dN3kFVc3kTA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/fab/-/fab-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-f6RiL76LnjNchF8FscPVOwx/q7QL8pmE+He0oT/OWWF0BK88V7ZOjNgItR1dJAXvl0fkh9LssPNkmxtHubH79Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/feature-targeting": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-xH8pdvB5oKO6OTY61vEs44eQJQY3GTobpzaxp+CIBH0UMobSl5KFee+j7MxpEbTkRGtMqWkzAA+vviT8hvmH+A==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/feature-targeting/-/feature-targeting-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Mv1BXAOhbkvwFYPU2DdiVe45Sy5JKgU5aHdkKzOu5LwyirejwvsDMnmqt22no2Q6qbh0vYeAwpdMEUWUt5JvYg==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/floating-label": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-Tjv2xnYr+VvsojRbRBVVmjxmut/y4hJrRCBMjU1982cTUYQlfqMaM7BUObt49jwRBKDLr2NjM+fwNIo0//YItA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/floating-label/-/floating-label-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-/kJMw+HJHza7BDzfqOMTmKK1MLeN3rD5tv0O+sM9zPlgsVNWIXDjQp/nWP+muqoxY4VZary9WPkz9gq0HMkKbg==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/focus-ring": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-xutZrHnrfnKftU3HUS9em8wO5Nb4zbnRrwDCGi3xnFR7bFP4u2J2ZUnVpO+RZfjr3A9l8chDavlFCL5HMfzt4A==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/focus-ring/-/focus-ring-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-xhpcqd70vSgUZFZJ2RHKoJkvEKhtg9sOehkd+MRRmm0JmDPSPFcJHEzRB1B99XVDhNWhculbMYH7Gtw+yu6C/g==", "dependencies": { - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0" + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0" } }, "node_modules/@material/form-field": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-N0UnlZ7j3GT4DGmMgJYMl9etOh7rsQjCjRRATWSnuAel+ir4a5HvLj9xQUyp0tlYuu9ZizB8ZOwbAz/XCiU94Q==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/form-field/-/form-field-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-sWXmwxjfihJbv+O43dseY5Tp/i5IAa9l7D2W6guqavrdkUvUgPO4sHXqyBpd3IGaUgtI0wxgWc7kdShbjeyblw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/icon-button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-BT+tHdRviY1o/yBgtX5NxfS7LfQtQSf7DiZfgP9eExSU5fDA6AfqJfZHyJdLmJCtFZbzlxJ0PBmt44NSlI2/DA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/icon-button/-/icon-button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-cMFLVP2QruX4deWrVZ0YuQoykY1gIHcijgkJdzuwCSLhsWPvdEeNTWEifz1mVchIJdZNqLbTtYpevM+gSH6Fxg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/image-list": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-FrBosWy9VnqWYDR8XkQPt8cE6MPNq5g7oEvULImmqjRxhktTJCPfDZSWHpjLpAvU0quYZZprPDRrwM3qw69z/A==", - "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/image-list/-/image-list-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-wd+9m5crO7xBoi8/n6OknGA0KiwxDhPAX8dvkc6dM2plSUwa4HNKfjHQiBPaGCiHsO6v5MWZg2uYSheh2Mgw/w==", + "dependencies": { + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/layout-grid": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-H4KEhaGaIuGHd3jKJqaoZkynJjqfyti4QhG6wiTt774Lv4Uri1+ZBxQ8FAFShEvETM2pfBy4mEECi/+M4V2ZTA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/layout-grid/-/layout-grid-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-ye2uJ9bjzl1YUwWsuy7OyQagYs0f+RbRC/EMX4Q8TJyk3FnVdqhDBsKcIjPB4ncx7KGG3QW62/MQlqFehx09lw==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/line-ripple": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-f4tcd82xu1OT0wAVT/kHiWDmJy9fRt9QA5b+v81fTSVFK41mYpxy8jIQ5gdoIvY/0BWLh4HzUejG6j98AkyLEQ==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/line-ripple/-/line-ripple-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-a5pmIjv0p7v85xNkbXCJFnQqrWVHucyCmXTVj5iJlR1vsqyUR6WN3vJ6F7yFJOhDMEYXZlqSvcTbZCTibR62IQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/linear-progress": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-3HlEEPv+RrtGPxq06QzCOAZoNJ8q6UtOOkRxh+buQy1F+Uv0n4BdmvUYsHZaSTn+kSlFMzIKDtRjUG2i7b4/hg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/progress-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/linear-progress/-/linear-progress-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Qxjhnia8Yy4VgJlLJgcUD1rcItAmyCYELQxrHhyB0mzmAYwYWgMGoDb+mWqHHKTWXPT1gsJHVmJ9bDq2ZH0JNA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/progress-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/list": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-rYg3cM41MJTSNoFOj8IzF1CpPFK9DDlTFMbERFakRHB1QsfnebxkuoAyI8j5G/pDdvkeAmDbz4tbKK8yJdifRw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/list/-/list-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-/MqMEidpTA/RSzdUirDSxp0BdUM3D8I1D79EXTopjLROtuqU3rKAGIuXfZopPV7t0j3vBXBLW3cv96iEAkN/pw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/menu": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-Xa+tXk8kMFMhdOYrIre1ye4L23i4LzEn48FN398742m1K/VY/IxAuslyQ5CmX77CxkOqbQFqwUarUTod0rEwjw==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/menu/-/menu-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-mJ7RNZxUeHnlv/XKwOOGbyekU0blKhUo/0d0mDHi0//VVsjZbiD1wbL2lgtQoUUwvwMxtrDE0v0/OF0AQ1unqg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/menu-surface": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-7sRmwY7+a3gB5GM6Vl0sZzVVW3iu6QNW79vRias6nZKJMXbE/JDWnhcgkl9QkxvUolBIJ0y1ChgZyntO8Val/g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/menu-surface/-/menu-surface-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-6jLY+JCcfGJKTEOKLztyp5VW1Y0Hnj6mkei6poAIZfRO6TTRE4qsdm5Yrlpo3XyRITBZYjS3M7jwz0n2naDMzQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/notched-outline": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-kMUDUqZ7ztvnwqCENZukztyA0oGZhY/mqd/WIaqRhIU58Q2mnDM6Vfd9fifeM61rIMnXHER2fvjjFzim50mw4g==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/notched-outline/-/notched-outline-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pZbDnLBNPIi/2zHzrjx92wmW77mibBrEZMyEa2ir6WfeumJY4fEgfRYiixfvwg7qBDoCAz9eNxA2aPO4ngJ0Jw==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/progress-indicator": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-CRQAM2C1weVKVr8rQeQTrOISmTupXw+l9sfpdIx8tQ14fOebZFcEbW9LRRvDAMmUNZF6W6pwL74+zk46DYIKBg==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/progress-indicator/-/progress-indicator-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-BrQ3ngFdf6Ig/lpuqAMKwOvjHXy4uiIij45ASFgF0RbVphSdKmzuZVgDZoibcCL4kbhP5CGc5G8kbpOIdmWXHA==", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/@material/radio": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-wpiLuHQtpMb846SSYvG2NQJl/wUi1NbVlCV+uGHSv5LFnbe10e537KFpjtjaDi/Y6e42bUxj8njN5cEZ3NfBUg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/radio/-/radio-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-DY0ypAxKpCBtZ2C79iPOvnXZc25OdRtc8qEHHydvNnzm1OJv56vPUvOBVhxFZj5xr4OWcAMwLZF+HiGGwZ1HgA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/ripple": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-S9S8260lwHreEgvOqg3EM0DF0y8ThuN9fFPVb+cCOAPzCn4Z2tO1pcvPfAmY8yZA7QIx9c5pt6Ci+q44LzPEYA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/ripple/-/ripple-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-md5MGooh3z4NnMXUuFtmiuJk30+MEm9Qns40qus7MUFQDVJ8/nLefwp3HgJQvxkwIB6WKUWaVN7K4KPo5lO0FA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/rtl": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-G02MQTQxHPhNlAIoOToCalxSba48VZ+CdrqkWr53eBb/P1I6Do0drMElqNmO5CYS5G/8AEScXmfJ0xSq92ABew==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/rtl/-/rtl-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-PuPdboompahdk37OXo8osyAZFOXhmMncq/PrgFNKzBSYjFCRuxYP2JzhFT90ytRUClB9Vso5DCLTX2xun1qAwA==", "dependencies": { - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/segmented-button": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-qu9nfKkPAxv6YFFObZAXHgaC0qq8i4Cr2lUbOQdL0E9HmKG+IE9ILualGJrAl2LOpCSJdwA0CjOuv2IsrscpHA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/touch-target": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/segmented-button/-/segmented-button-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-dn5VvyWnLVUo0x9CeFNrwV+NC896Ha9+jbHwMvJ44oaNorVf8OQHQDDPSj2d2Pjox3BCdf+FUU7Bx7f6cwU+XQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/touch-target": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/select": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-MgbztOBl0Y7UHVPUTuXoAAYfBh+bwbRW9lkK/EJQ4YQrmZB/0L14S7feqh52JhFXVhjFzeYPFMQg+uP2hhHSpg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/list": "15.0.0-canary.7971d6ad5.0", - "@material/menu": "15.0.0-canary.7971d6ad5.0", - "@material/menu-surface": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/select/-/select-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-8GcR11MOXR2EESTIUhm3wY3MSegBSBZ1vfo1KZEFRu75v4QfZAfrr3HF05zQoWaT6GvtAPXcKh3vwmkJSXDs6Q==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/list": "15.0.0-canary.fd95ca7ef.0", + "@material/menu": "15.0.0-canary.fd95ca7ef.0", + "@material/menu-surface": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/shape": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-mlsNFWKOK38ECoB1onCFpi8HKRGgrElk0YioF3V0Joszp1HVV2Fn+SWoKg2LwWHaJet4iBYtNoCbQC6dH2YBeA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/shape/-/shape-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-+nJg/Pv8I9ZT1c3d4b0ZJp66HzLO25DEKWqmyyzifHsuwLK0u9eeN02UguMXqNvPIBPsR2fciwBgJNcuEv+WGA==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/slider": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-OjbxB3vwZvhbTGP8EGLWoXyodbTMuwkvoFdblEiZtWrrPL0Us5hg/20n8VfUQ0N+c00mElsEv79Jsx+B0iTV+Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/slider/-/slider-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-W8yBQrKfOjFD/cZWn543L0JjFBsPAyRMHkQzN0qw89AAR/SK4cw3b6sRoJqEHIPY6aZDWBYW1bESi09WM4lpZA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/snackbar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-svNOI1Kwu9Mg259SNTaGgyJqETRIPwQPkxYhHvWT4vYiHQkJJJe9kFBcIKi+sdTxqqoMZxyjC2SwS/1mkU4/xg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/icon-button": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/snackbar/-/snackbar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-bIf0Je1aMYSlkqfceVViJGWWX/BAqzAhiBVvurvKdRoBTezMrAqEimjQOXu4O2fHiLHmKEsO7c0B3dpobM2fmA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/icon-button": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/switch": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-WBsTIq0NwccMAbt9YFcU1vhcmFOVpNDeZ9gNMJypk19ZiqDcZBZNDx0JmceRqTYrCxndqVwfD25qK0jFVplK9g==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/switch/-/switch-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-skiw+HbrUh9qh1x8Jl1hNdmzqwPKzHnvJayHC7o6M4HXpIkcBFtvYrUXUc5/XQ9cqd2Nyh7i74aDGlp47fa5fQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/tab": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-hmqRl9s7g1/8KpZ5rqANxUXrHi4PYO3GsGhASrYrB99/5ZX1ghdCGwEN1Lp9ntKIgZjd1s6qtzccBtmnW+boXA==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/focus-ring": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab/-/tab-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-pv1qil6xu2e07cAptSd8i/ejYd+nSEzgg6/p+1AXZewlqdq3eHmufXvhZOw7FajIm/nwlRKyuChSPhlPYt+rNg==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/focus-ring": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-bar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-hEMnb2C1yOQPbqdFCTCuyMmjcqO4QIvPKAsbquAwOZc0tz/U88tzmfuhv1k77FB2hbESwN9sPpImU0g4Lrvfhw==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", - "@material/tab-indicator": "15.0.0-canary.7971d6ad5.0", - "@material/tab-scroller": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-bar/-/tab-bar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-URYYOwzoRiJJtqdgufl6dNUJphdLgrmfW0e9YvSJlusfAx6SsmbTykTvrRshVRZuoJSsyAAHPHxRY747gmjd8w==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-indicator": "15.0.0-canary.fd95ca7ef.0", + "@material/tab-scroller": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-indicator": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-0X2tJf0E+CwL5Bx3Fqxi5Uuj1BgncKqd4yFpWE7cv8IZHphNReSOrCcSgUwUfirmee6MqkQ4Drk51Pf4ANj2OA==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-indicator/-/tab-indicator-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-59HZhI2VNhxL1j8yNhu+wt8X2d2lLfMSpng2plf5LXSXnuowzSA+SxL3xvU5SeRg9ovrREH0udEgD7ob0ktmQQ==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tab-scroller": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-//Ih8ZPx92PLQwXhFzv6YCQc5xW2IH84GdIeJrdBNcQN6wgbQNsbU7h9m6jymtpWQgvvLY8E0+2qkNcnWejnag==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/tab": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tab-scroller/-/tab-scroller-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-xb/o8MOw5gHCwlCr9gA2Z7pRrqjYIxj+6a62PMe75h9avm5kHG+h38LbdaNIjPpCeNbvhpoPRUUpAMAyHHcuGA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/tab": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/textfield": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-n9aWMZGyE2GBTr2Tx6n4hLp08uyIo1/xNqcZ0Kx2tKK1spPgTgp+g2fEKImGnnbfiCTJPNrcJ8bQ+Vy7Dp0n3Q==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/density": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/floating-label": "15.0.0-canary.7971d6ad5.0", - "@material/line-ripple": "15.0.0-canary.7971d6ad5.0", - "@material/notched-outline": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/textfield/-/textfield-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Tk9Ck9vnHQXGjTky6Pl3W0BYmsHa4yXfTZrtrveA3R9Ix/f1LxcVR/4o39i5VMIZQNIXlAVa1hIRgjpEcx3VtA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/density": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/floating-label": "15.0.0-canary.fd95ca7ef.0", + "@material/line-ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/notched-outline": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/theme": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-4YUyQo4SOatHHH15/h2LBIyxmVxtefo+QC8bRopF13f/qq5lHpX/stK6chf1OR/z9BUxnNHZWXd2LG5SvJGs9Q==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/theme/-/theme-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-Ho0DWUZ/JZ+NkzgdJGc5QHarTOcaqm0RnibAW/y+0BgQCgVYNQHbQ2oZjqr2u+pCOC9n2T7GVdvm4z+0xF312Q==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/tokens": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-tRa/Uki/moIP6f/QJPrad2jHbSZ5NB5TRSfAS1NZof0KNFjW8n2lJVpgcgD+f1NENin3dWM4NpfJwxulGlWE7g==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tokens/-/tokens-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-N0KbJD9BwriCR2ZcUz3kgdM1lQYixqTSFe/kU+4mdAWBZhEsE8s6S6x3qzDatYLtLIKfGgWXyG+duHtoS5iFag==", "dependencies": { - "@material/elevation": "15.0.0-canary.7971d6ad5.0" + "@material/elevation": "15.0.0-canary.fd95ca7ef.0" } }, "node_modules/@material/tooltip": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-gidVGZOGmJUNDxm3ZorNZMAFmbeFmJ+6DH2F45hi1iU/GflfyvMfvbG2VvPFGYj84YAKHs799yAjidvk1nSZZg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/button": "15.0.0-canary.7971d6ad5.0", - "@material/dom": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/tokens": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/tooltip/-/tooltip-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-mbn/dBh8hYczaxds+e5MtmQ3Gd0frH9F0EAD6EQLKnuRirBrBQ6s5zhs/u7ta2wzG1pqCZTONjW8k+uZL+OpCA==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/button": "15.0.0-canary.fd95ca7ef.0", + "@material/dom": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/tokens": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "safevalues": "^0.3.4", "tslib": "^2.1.0" } }, "node_modules/@material/top-app-bar": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-ztvglUBK0y4LDHD8xhvNGCpbsHYoAVtI06cJHu5G241WD5wAmseEnLMY+ty86FHMzs796PzhUqUmahEHeBNlEg==", - "dependencies": { - "@material/animation": "15.0.0-canary.7971d6ad5.0", - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/elevation": "15.0.0-canary.7971d6ad5.0", - "@material/ripple": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", - "@material/shape": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", - "@material/typography": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/top-app-bar/-/top-app-bar-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-ovVxOFL6/TXxjxr3IkA7Qvdy5DuhfN19BUJVbaFVwCFhnmOFEF549CKtM1TnxyExAggGVBIitwD0gK/Ao63FWg==", + "dependencies": { + "@material/animation": "15.0.0-canary.fd95ca7ef.0", + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/elevation": "15.0.0-canary.fd95ca7ef.0", + "@material/ripple": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/shape": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", + "@material/typography": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/touch-target": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-aT8GyRfH0TJuF53HWKga+vuwJbJ/euN6T8CS/+RP5F/rjzWwxSd8RtyBmVUzBjVzOxr6Os+El0c3TFfEDxRdAg==", - "dependencies": { - "@material/base": "15.0.0-canary.7971d6ad5.0", - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/rtl": "15.0.0-canary.7971d6ad5.0", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/touch-target/-/touch-target-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-0fjs8kDRws+W34zg6rTBgnqQFHvAZ1kp5be5wPA3e5Io5YIrRaD2APz9dofEfgNnSN/EoQQI/IAWwv+a4WbJRQ==", + "dependencies": { + "@material/base": "15.0.0-canary.fd95ca7ef.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/rtl": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@material/typography": { - "version": "15.0.0-canary.7971d6ad5.0", - "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.7971d6ad5.0.tgz", - "integrity": "sha512-4J5qPXbCS3wMtGl0AJIj/M9rUxHR7fRX3IKtfOyvra10lZbr4qma+4g0+t+O9cPzcCBS1NwPkJ/E4t+ijEa6gA==", + "version": "15.0.0-canary.fd95ca7ef.0", + "resolved": "https://registry.npmjs.org/@material/typography/-/typography-15.0.0-canary.fd95ca7ef.0.tgz", + "integrity": "sha512-OihvVBCvb3R9sg197ZLRSZSQaAE4wzGiIDzpajibuxbuaHzOwcSNt782Kqz27xy5uBQ0r/iQb4SdU877NQfUXw==", "dependencies": { - "@material/feature-targeting": "15.0.0-canary.7971d6ad5.0", - "@material/theme": "15.0.0-canary.7971d6ad5.0", + "@material/feature-targeting": "15.0.0-canary.fd95ca7ef.0", + "@material/theme": "15.0.0-canary.fd95ca7ef.0", "tslib": "^2.1.0" } }, "node_modules/@ng-bootstrap/ng-bootstrap": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-14.0.0.tgz", - "integrity": "sha512-QOYt1MBqAVVrjYSIf4gGXzRRJFzVKuD7ya2yFmeqN0YV2t3kB+IfUaNlfT3PTakHxLOS9ujLXeDiaTps5ST5TA==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-14.0.1.tgz", + "integrity": "sha512-JF4U4IIix+g6VBFfG8stf0Un5K//ypoN+pTuRs6kjUhsHBsa2m7yKE6bCe3fMhatFZFr2fcSswDzRUnAUiHhWg==", "dependencies": { "tslib": "^2.3.0" }, @@ -4354,8 +4545,7 @@ }, "node_modules/@ngrx/store": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/@ngrx/store/-/store-15.1.0.tgz", - "integrity": "sha512-Wxjme7yJnxD6il6fGZdFTdSs9gL+6OFW8/II9vApFokUb0E7UQBm8RYb9dYJ2IQJvWXwO+2ItSaecRUZgt39kA==", + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -4365,9 +4555,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.0.4.tgz", - "integrity": "sha512-+1riOTohRHhN2N8Y+usHFtNz+Rt6q/44puj9rwjlKwWIA+6qxAv3kQhVHivVaU3bCAB9B/3jAxSuZTNHk0wgTg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.1.1.tgz", + "integrity": "sha512-pHkVE4IfIGcrIqxxrBQJV62GBqXF+LU4sPY5MLNWIfKSctW6AdTVoO9ilx8pclaFJkMLkPMbrmfGosYw47L+lg==", "dev": true, "engines": { "node": "^14.20.0 || ^16.13.0 || >=18.10.0", @@ -4376,15 +4566,14 @@ }, "peerDependencies": { "@angular/compiler-cli": "^15.0.0", - "typescript": "~4.8.2", + "typescript": ">=4.8.2 <5.0", "webpack": "^5.54.0" } }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -4395,18 +4584,16 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -4447,15 +4634,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@npmcli/git/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/@npmcli/git/node_modules/which": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/which/-/which-3.0.0.tgz", @@ -4570,13 +4748,11 @@ }, "node_modules/@petamoriken/float16": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.7.0.tgz", - "integrity": "sha512-g7w35q4bt7MoM3nZKrk5COiIO+qevZjjS7bJO5pYrB0ZKABUXFBOgr2VBY66LmeI3FzkH5AZ+1uNmNHYjeuUjQ==" + "license": "MIT" }, "node_modules/@popperjs/core": { "version": "2.11.6", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz", - "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==", + "license": "MIT", "peer": true, "funding": { "type": "opencollective", @@ -4584,13 +4760,13 @@ } }, "node_modules/@schematics/angular": { - "version": "15.0.4", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.0.4.tgz", - "integrity": "sha512-4l4WZlr9MnhXo2B7eLczttgkeq8Agm3zfiX0trYkOdYqLtzOKxPiI+RrZSsfIDmmLSE1EillZ3PtDImMzAgQPg==", + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-15.1.1.tgz", + "integrity": "sha512-Ujo4vt/r3WzIhGn2I2Lt3eOTWSsVxoXfcXxFRuxl3cil/9mH1X66hDTQ2DVYiXPFGcQMjcNaDwlQxyor4yGbqA==", "dev": true, "dependencies": { - "@angular-devkit/core": "15.0.4", - "@angular-devkit/schematics": "15.0.4", + "@angular-devkit/core": "15.1.1", + "@angular-devkit/schematics": "15.1.1", "jsonc-parser": "3.2.0" }, "engines": { @@ -4601,32 +4777,28 @@ }, "node_modules/@sinclair/typebox": { "version": "0.24.51", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", - "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", - "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } }, "node_modules/@sinonjs/fake-timers": { "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", - "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^1.7.0" } }, "node_modules/@socket.io/component-emitter": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + "license": "MIT" }, "node_modules/@tootallnate/once": { "version": "2.0.0", @@ -4639,9 +4811,8 @@ }, "node_modules/@types/babel__core": { "version": "7.1.20", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.20.tgz", - "integrity": "sha512-PVb6Bg2QuscZ30FvOU7z4guG6c926D9YRvOxEaelzndpMsvP+YM74Q/dAFASpg2l6+XLalxSGxcq/lrgYWZtyQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -4652,18 +4823,16 @@ }, "node_modules/@types/babel__generator": { "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -4671,9 +4840,8 @@ }, "node_modules/@types/babel__traverse": { "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.3.0" } @@ -4699,9 +4867,8 @@ }, "node_modules/@types/chart.js": { "version": "2.9.37", - "resolved": "https://registry.npmjs.org/@types/chart.js/-/chart.js-2.9.37.tgz", - "integrity": "sha512-9bosRfHhkXxKYfrw94EmyDQcdjMaQPkU1fH2tDxu8DWXxf1mjzWQAV4laJF51ZbC2ycYwNDvIm1rGez8Bug0vg==", "dev": true, + "license": "MIT", "dependencies": { "moment": "^2.10.2" } @@ -4727,9 +4894,8 @@ }, "node_modules/@types/eslint": { "version": "8.4.10", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", - "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -4737,9 +4903,8 @@ }, "node_modules/@types/eslint-scope": { "version": "3.7.4", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", - "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint": "*", "@types/estree": "*" @@ -4747,9 +4912,8 @@ }, "node_modules/@types/estree": { "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/express": { "version": "4.17.15", @@ -4764,9 +4928,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.31", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", - "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "version": "4.17.32", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.32.tgz", + "integrity": "sha512-aI5h/VOkxOF2Z1saPy0Zsxs5avets/iaiAJYznQFm5By/pamU31xWKL//epiF4OfUA2qTOc9PV6tCUjhO8wlZA==", "dev": true, "dependencies": { "@types/node": "*", @@ -4776,9 +4940,8 @@ }, "node_modules/@types/graceful-fs": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", - "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -4794,32 +4957,29 @@ }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -4828,27 +4988,23 @@ }, "node_modules/@types/json-schema": { "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/json5": { "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { "version": "4.14.191", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz", - "integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash-es": { "version": "4.17.6", - "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.6.tgz", - "integrity": "sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==", "dev": true, + "license": "MIT", "dependencies": { "@types/lodash": "*" } @@ -4860,16 +5016,15 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.15.tgz", - "integrity": "sha512-VkhBbVo2+2oozlkdHXLrb3zjsRkpdnaU2bXmX8Wgle3PUi569eLRaHGlgETQHR7lLL1w7GiG3h9SnePhxNDecw==", + "version": "16.18.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.11.tgz", + "integrity": "sha512-3oJbGBUWuS6ahSnEq1eN2XrCyf4YsWI8OyCvo7c64zQJNplk3mO84t53o8lfTk+2ji59g5ycfc6qQ3fdHliHuA==", "dev": true }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4879,9 +5034,8 @@ }, "node_modules/@types/prettier": { "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ri0UmynRRvZiiUJdiz38MmIblKK+oH30MztdBVR95dv/Ubw6neWSb8u1XpRb72L4qsZOhz+L+z9JD40SJmfWow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -4903,9 +5057,8 @@ }, "node_modules/@types/semver": { "version": "7.3.13", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", - "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/serve-index": { "version": "1.9.1", @@ -4928,15 +5081,13 @@ }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/sizzle": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/sockjs": { "version": "0.3.33", @@ -4949,19 +5100,17 @@ }, "node_modules/@types/stack-utils": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/validator": { "version": "13.7.10", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.10.tgz", - "integrity": "sha512-t1yxFAR2n0+VO6hd/FJ9F2uezAZVWHLmpmlJzm1eX03+H7+HsuTAp7L8QJs+2pQCfWkP1+EXsGK9Z9v7o/qPVQ==" + "license": "MIT" }, "node_modules/@types/ws": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", - "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "version": "8.5.4", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", + "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", "dev": true, "dependencies": { "@types/node": "*" @@ -4969,38 +5118,35 @@ }, "node_modules/@types/yargs": { "version": "17.0.17", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.17.tgz", - "integrity": "sha512-72bWxFKTK6uwWJAVT+3rF6Jo6RTojiJ27FQo8Rf60AL+VZbzoVPnMFhKsUnbjR8A3BTCYQ7Mv3hnl8T0A+CX9g==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -5026,13 +5172,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5043,13 +5189,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -5070,9 +5216,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5083,13 +5229,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5110,16 +5256,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -5136,12 +5282,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -5176,9 +5322,8 @@ }, "node_modules/@typescript-eslint/experimental-utils": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.46.1.tgz", - "integrity": "sha512-M79mkB+wOuiBG8jzOVNA2h5izOip5CNPZV1K3tvE/qry/1Oh/bnKYhNWQNiH2h9O3B73YK60GmiqrUpprnQ5sQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/utils": "5.46.1" }, @@ -5195,9 +5340,8 @@ }, "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.46.1.tgz", - "integrity": "sha512-RBdBAGv3oEpFojaCYT4Ghn4775pdjvwfDOfQ2P6qzNVgQOVrnSPe5/Pb88kv7xzYQjoio0eKHKB9GJ16ieSxvA==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", @@ -5221,9 +5365,8 @@ }, "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5234,22 +5377,21 @@ }, "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -5269,13 +5411,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5286,9 +5428,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -5299,13 +5441,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -5326,12 +5468,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -5344,9 +5486,8 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.46.1.tgz", - "integrity": "sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.46.1", "@typescript-eslint/visitor-keys": "5.46.1" @@ -5361,9 +5502,8 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz", - "integrity": "sha512-A1u0Yo5wZxkXPQ7/noGkRhV4J9opcymcr31XQtOzcc5nO/IHN2E2TPMECKWYpM3e6olWEM63fq/BaL1wEYnt/w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.44.0", "@typescript-eslint/utils": "5.44.0", @@ -5388,9 +5528,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5401,9 +5540,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0", @@ -5428,9 +5566,8 @@ }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "eslint-visitor-keys": "^3.3.0" @@ -5445,9 +5582,8 @@ }, "node_modules/@typescript-eslint/types": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.46.1.tgz", - "integrity": "sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5458,9 +5594,8 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.46.1.tgz", - "integrity": "sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.46.1", "@typescript-eslint/visitor-keys": "5.46.1", @@ -5485,9 +5620,8 @@ }, "node_modules/@typescript-eslint/utils": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.44.0.tgz", - "integrity": "sha512-fMzA8LLQ189gaBjS0MZszw5HBdZgVwxVFShCO3QN+ws3GlPkcy9YuS3U4wkT6su0w+Byjq3mS3uamy9HE4Yfjw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", @@ -5511,9 +5645,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz", - "integrity": "sha512-2pKml57KusI0LAhgLKae9kwWeITZ7IsZs77YxyNyIVOwQ1kToyXRaJLl+uDEXzMN5hnobKUOo2gKntK9H1YL8g==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0" @@ -5528,9 +5661,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.44.0.tgz", - "integrity": "sha512-Tp+zDnHmGk4qKR1l+Y1rBvpjpm5tGXX339eAlRBDg+kgZkz9Bw+pqi4dyseOZMsGuSH69fYfPJCBKBrbPCxYFQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -5541,9 +5673,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", - "integrity": "sha512-M6Jr+RM7M5zeRj2maSfsZK2660HKAJawv4Ud0xT+yauyvgrsHu276VtXlKDFnEmhG+nVEd0fYZNXGoAgxwDWJw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.44.0", "@typescript-eslint/visitor-keys": "5.44.0", @@ -5568,9 +5699,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { "version": "5.44.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", - "integrity": "sha512-a48tLG8/4m62gPFbJ27FxwCOqPKxsb8KC3HkmYoq2As/4YyjQl1jDbRr1s63+g4FS/iIehjmN3L5UjmKva1HzQ==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.44.0", "eslint-visitor-keys": "^3.3.0" @@ -5585,9 +5715,8 @@ }, "node_modules/@typescript-eslint/utils/node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -5598,18 +5727,16 @@ }, "node_modules/@typescript-eslint/utils/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.46.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.46.1.tgz", - "integrity": "sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.46.1", "eslint-visitor-keys": "^3.3.0" @@ -5624,9 +5751,8 @@ }, "node_modules/@webassemblyjs/ast": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/helper-numbers": "1.11.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.1" @@ -5634,27 +5760,23 @@ }, "node_modules/@webassemblyjs/floating-point-hex-parser": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-api-error": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-buffer": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-numbers": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/floating-point-hex-parser": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", @@ -5663,15 +5785,13 @@ }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/helper-wasm-section": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5681,33 +5801,29 @@ }, "node_modules/@webassemblyjs/ieee754": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, + "license": "MIT", "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@webassemblyjs/wasm-edit": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5721,9 +5837,8 @@ }, "node_modules/@webassemblyjs/wasm-gen": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-wasm-bytecode": "1.11.1", @@ -5734,9 +5849,8 @@ }, "node_modules/@webassemblyjs/wasm-opt": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-buffer": "1.11.1", @@ -5746,9 +5860,8 @@ }, "node_modules/@webassemblyjs/wasm-parser": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/helper-api-error": "1.11.1", @@ -5760,9 +5873,8 @@ }, "node_modules/@webassemblyjs/wast-printer": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, + "license": "MIT", "dependencies": { "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" @@ -5770,27 +5882,23 @@ }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@xtuc/long": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", - "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/abab": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/abbrev": { "version": "1.1.1", @@ -5813,9 +5921,8 @@ }, "node_modules/acorn": { "version": "8.8.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", - "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -5825,9 +5932,8 @@ }, "node_modules/acorn-import-assertions": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^8" } @@ -5843,9 +5949,8 @@ }, "node_modules/adjust-sourcemap-loader": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", - "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", "dev": true, + "license": "MIT", "dependencies": { "loader-utils": "^2.0.0", "regex-parser": "^2.2.11" @@ -5856,9 +5961,8 @@ }, "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -5870,9 +5974,8 @@ }, "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, + "license": "MIT", "dependencies": { "debug": "4" }, @@ -5896,9 +5999,8 @@ }, "node_modules/aggregate-error": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -5908,9 +6010,9 @@ } }, "node_modules/ajv": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", - "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "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", @@ -5925,9 +6027,8 @@ }, "node_modules/ajv-formats": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", - "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^8.0.0" }, @@ -5942,9 +6043,8 @@ }, "node_modules/ajv-keywords": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.3" }, @@ -5954,18 +6054,16 @@ }, "node_modules/ansi-colors": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/ansi-escapes": { "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -5990,16 +6088,14 @@ }, "node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -6009,8 +6105,7 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6027,8 +6122,6 @@ }, "node_modules/arch": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", "dev": true, "funding": [ { @@ -6043,7 +6136,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/are-we-there-yet": { "version": "3.0.1", @@ -6060,24 +6154,21 @@ }, "node_modules/arg": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, "node_modules/aria-query": { "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } @@ -6090,9 +6181,8 @@ }, "node_modules/array-includes": { "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -6109,17 +6199,33 @@ }, "node_modules/array-union": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/array.prototype.flat": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -6136,56 +6242,48 @@ }, "node_modules/asn1": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": "~2.1.0" } }, "node_modules/assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "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 + "dev": true, + "license": "MIT" }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/at-least-node": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/autoprefixer": { "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", "dev": true, "funding": [ { @@ -6197,6 +6295,7 @@ "url": "https://tidelift.com/funding/github/npm/autoprefixer" } ], + "license": "MIT", "dependencies": { "browserslist": "^4.21.4", "caniuse-lite": "^1.0.30001426", @@ -6217,9 +6316,8 @@ }, "node_modules/available-typed-arrays": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6229,33 +6327,29 @@ }, "node_modules/aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/aws4": { "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/axobject-query": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "deep-equal": "^2.0.5" } }, "node_modules/babel-jest": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", - "integrity": "sha512-aard+xnMoxgjwV70t0L6wkW/3HQQtV+O0PEimxKgzNqCJnbYmroPojdP2tqKSOAt8QAKV/uSZU8851M7B5+fcA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.3.1", "@types/babel__core": "^7.1.14", @@ -6274,9 +6368,8 @@ }, "node_modules/babel-jest/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -6289,9 +6382,8 @@ }, "node_modules/babel-jest/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6305,9 +6397,8 @@ }, "node_modules/babel-jest/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -6317,24 +6408,21 @@ }, "node_modules/babel-jest/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/babel-jest/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/babel-jest/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -6343,9 +6431,9 @@ } }, "node_modules/babel-loader": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.0.tgz", - "integrity": "sha512-Antt61KJPinUMwHwIIz9T5zfMgevnfZkEVWYDWlG888fgdvRRGD0JTuf/fFozQnfT+uq64sk1bmdHDy/mOEWnA==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz", + "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==", "dev": true, "dependencies": { "find-cache-dir": "^3.3.2", @@ -6361,9 +6449,8 @@ }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -6377,9 +6464,8 @@ }, "node_modules/babel-plugin-jest-hoist": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.2.0.tgz", - "integrity": "sha512-TnspP2WNiR3GLfCsUNHqeXw0RoQ2f9U5hQ5L3XFpwuO8htQmSrhh8qsB6vi5Yi8+kuynN1yjDjQsPfkebmB6ZA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -6392,9 +6478,8 @@ }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", - "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.17.7", "@babel/helper-define-polyfill-provider": "^0.3.3", @@ -6406,18 +6491,16 @@ }, "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/babel-plugin-polyfill-corejs3": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz", - "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.3", "core-js-compat": "^3.25.1" @@ -6428,9 +6511,8 @@ }, "node_modules/babel-plugin-polyfill-regenerator": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", - "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-define-polyfill-provider": "^0.3.3" }, @@ -6440,9 +6522,8 @@ }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -6463,9 +6544,8 @@ }, "node_modules/babel-preset-jest": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.2.0.tgz", - "integrity": "sha512-z9JmMJppMxNv8N7fNRHvhMg9cvIkMxQBXgFkane3yKVEvEOP+kB50lk8DFRvF9PGqbyXxlmebKWhuDORO8RgdA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.2.0", "babel-preset-current-node-syntax": "^1.0.0" @@ -6479,13 +6559,10 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dev": true, "funding": [ { @@ -6500,7 +6577,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/batch": { "version": "0.6.1", @@ -6510,18 +6588,16 @@ }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tweetnacl": "^0.14.3" } }, "node_modules/bent": { "version": "7.3.12", - "resolved": "https://registry.npmjs.org/bent/-/bent-7.3.12.tgz", - "integrity": "sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bytesish": "^0.4.1", "caseless": "~0.12.0", @@ -6530,26 +6606,23 @@ }, "node_modules/big.js": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/binary-extensions": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -6558,15 +6631,13 @@ }, "node_modules/blob-util": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/bluebird": { "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/body-parser": { "version": "1.20.1", @@ -6641,9 +6712,9 @@ } }, "node_modules/bonjour-service": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", - "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz", + "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==", "dev": true, "dependencies": { "array-flatten": "^2.1.2", @@ -6654,14 +6725,11 @@ }, "node_modules/boolbase": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/bootstrap": { "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", - "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", "funding": [ { "type": "github", @@ -6672,20 +6740,20 @@ "url": "https://opencollective.com/bootstrap" } ], + "license": "MIT", "peerDependencies": { "@popperjs/core": "^2.11.6" } }, "node_modules/bootstrap-icons": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.2.tgz", - "integrity": "sha512-PTPYadRn1AMGr+QTSxe4ZCc+Wzv9DGZxbi3lNse/dajqV31n2/wl/7NX78ZpkvFgRNmH4ogdIQPQmxAfhEV6nA==" + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.10.3.tgz", + "integrity": "sha512-7Qvj0j0idEm/DdX9Q0CpxAnJYqBCFCiUI6qzSPYfERMcokVuV9Mdm/AJiVZI8+Gawe4h/l6zFcOzvV7oXCZArw==" }, "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, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -6693,8 +6761,7 @@ }, "node_modules/braces": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -6704,8 +6771,6 @@ }, "node_modules/browserslist": { "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", "funding": [ { "type": "opencollective", @@ -6716,6 +6781,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001400", "electron-to-chromium": "^1.4.251", @@ -6731,9 +6797,8 @@ }, "node_modules/bs-logger": { "version": "0.2.6", - "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", - "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -6743,17 +6808,14 @@ }, "node_modules/bser": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ { @@ -6769,6 +6831,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -6776,24 +6839,21 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/buffer-from": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/builtin-modules": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -6821,21 +6881,20 @@ }, "node_modules/bytesish": { "version": "0.4.4", - "resolved": "https://registry.npmjs.org/bytesish/-/bytesish-0.4.4.tgz", - "integrity": "sha512-i4uu6M4zuMUiyfZN4RU2+i9+peJh//pXhd9x1oSe1LBkZ3LEbCoygu8W0bXTukU1Jme2txKuotpCZRaC3FLxcQ==", - "dev": true + "dev": true, + "license": "(Apache-2.0 AND MIT)" }, "node_modules/cacache": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.2.tgz", - "integrity": "sha512-rYUs2x4OjSgCQND7nTrh21AHIBFgd7s/ctAYvU3a8u+nK+R5YaX/SFPDYz4Azz7SGL6+6L9ZZWI4Kawpb7grzQ==", + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz", + "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==", "dev": true, "dependencies": { "@npmcli/fs": "^3.1.0", - "fs-minipass": "^2.1.0", + "fs-minipass": "^3.0.0", "glob": "^8.0.1", "lru-cache": "^7.7.1", - "minipass": "^3.1.6", + "minipass": "^4.0.0", "minipass-collect": "^1.0.2", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", @@ -6851,18 +6910,16 @@ }, "node_modules/cachedir": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", - "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/call-bind": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -6873,26 +6930,22 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/camelcase": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { "version": "1.0.30001439", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", - "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "funding": [ { "type": "opencollective", @@ -6902,18 +6955,17 @@ "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/chalk": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -6925,23 +6977,21 @@ }, "node_modules/char-regex": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/chardet": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/chart.js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.1.1.tgz", - "integrity": "sha512-P0pCosNXp+LR8zO/QTkZKT6Hb7p0DPFtypEeVOf+6x06hX13NIb75R0DXUA4Ksx/+48chDQKtCCmRCviQRTqsA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.1.2.tgz", + "integrity": "sha512-9L1w6WLPq6ztiWVVOYtDtpo0CUsBKDWPrUEdwChAyzczaikqeSwNKEv3QpJ7EO4ICcLSi6UDVhgvcnUhRJidRA==", "dependencies": { "@kurkle/color": "^0.3.0" }, @@ -6951,23 +7001,21 @@ }, "node_modules/check-more-types": { "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/chokidar": { "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "funding": [ { "type": "individual", "url": "https://paulmillr.com/funding/" } ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -6995,37 +7043,32 @@ }, "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==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0" } }, "node_modules/ci-info": { "version": "3.7.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", - "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/class-transformer": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + "license": "MIT" }, "node_modules/class-validator": { "version": "0.14.0", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", - "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "license": "MIT", "dependencies": { "@types/validator": "^13.7.10", "libphonenumber-js": "^1.10.14", @@ -7034,9 +7077,8 @@ }, "node_modules/clean-regexp": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -7046,18 +7088,16 @@ }, "node_modules/clean-stack": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/cli-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -7067,9 +7107,8 @@ }, "node_modules/cli-spinners": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -7079,9 +7118,8 @@ }, "node_modules/cli-table3": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, + "license": "MIT", "dependencies": { "string-width": "^4.2.0" }, @@ -7094,9 +7132,8 @@ }, "node_modules/cli-truncate": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" @@ -7110,17 +7147,15 @@ }, "node_modules/cli-width": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10" } }, "node_modules/cliui": { "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -7132,18 +7167,16 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } }, "node_modules/clone-deep": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, + "license": "MIT", "dependencies": { "is-plain-object": "^2.0.4", "kind-of": "^6.0.2", @@ -7155,9 +7188,8 @@ }, "node_modules/co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -7165,22 +7197,19 @@ }, "node_modules/collect-v8-coverage": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/color-convert": { "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", "dependencies": { "color-name": "1.1.3" } }, "node_modules/color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + "license": "MIT" }, "node_modules/color-support": { "version": "1.1.3", @@ -7193,24 +7222,21 @@ }, "node_modules/colorette": { "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.1.90" } }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -7220,18 +7246,16 @@ }, "node_modules/commander": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", - "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/common-tags": { "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -7295,9 +7319,8 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/connect-history-api-fallback": { "version": "2.0.0", @@ -7337,8 +7360,7 @@ }, "node_modules/convert-source-map": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + "license": "MIT" }, "node_modules/cookie": { "version": "0.5.0", @@ -7357,9 +7379,8 @@ }, "node_modules/copy-anything": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", - "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", "dev": true, + "license": "MIT", "dependencies": { "is-what": "^3.14.1" }, @@ -7369,9 +7390,8 @@ }, "node_modules/copy-webpack-plugin": { "version": "11.0.0", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", - "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", "dev": true, + "license": "MIT", "dependencies": { "fast-glob": "^3.2.11", "glob-parent": "^6.0.1", @@ -7393,9 +7413,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -7405,9 +7424,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/globby": { "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", "dev": true, + "license": "MIT", "dependencies": { "dir-glob": "^3.0.1", "fast-glob": "^3.2.11", @@ -7424,9 +7442,8 @@ }, "node_modules/copy-webpack-plugin/node_modules/slash": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", - "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -7436,9 +7453,8 @@ }, "node_modules/core-js-compat": { "version": "3.26.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.26.1.tgz", - "integrity": "sha512-622/KzTudvXCDLRw70iHW4KKs1aGpcRcowGWyYJr2DEBfRrd6hNJybxSWJFuZYD4ma86xhrwDDHxmDaIq4EA8A==", "dev": true, + "license": "MIT", "dependencies": { "browserslist": "^4.21.4" }, @@ -7449,9 +7465,8 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cosmiconfig": { "version": "7.1.0", @@ -7471,9 +7486,8 @@ }, "node_modules/critters": { "version": "0.0.16", - "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", - "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "chalk": "^4.1.0", "css-select": "^4.2.0", @@ -7485,9 +7499,8 @@ }, "node_modules/critters/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7500,9 +7513,8 @@ }, "node_modules/critters/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7516,9 +7528,8 @@ }, "node_modules/critters/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7528,30 +7539,26 @@ }, "node_modules/critters/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/critters/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/critters/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7561,9 +7568,8 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -7575,9 +7581,8 @@ }, "node_modules/css-loader": { "version": "6.7.3", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", - "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.1.0", "postcss": "^8.4.19", @@ -7601,9 +7606,8 @@ }, "node_modules/css-select": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", - "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.0.1", @@ -7617,9 +7621,8 @@ }, "node_modules/css-what": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">= 6" }, @@ -7629,14 +7632,12 @@ }, "node_modules/csscolorparser": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz", - "integrity": "sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==" + "license": "MIT" }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "license": "MIT", "bin": { "cssesc": "bin/cssesc" }, @@ -7646,10 +7647,9 @@ }, "node_modules/cypress": { "version": "9.7.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-9.7.0.tgz", - "integrity": "sha512-+1EE1nuuuwIt/N1KXRR2iWHU+OiIt7H28jJDyyI4tiUftId/DrXYEwoDa5+kH2pki1zxnA0r6HrUGHV5eLbF5Q==", "dev": true, "hasInstallScript": true, + "license": "MIT", "dependencies": { "@cypress/request": "^2.88.10", "@cypress/xvfb": "^1.2.4", @@ -7703,9 +7703,8 @@ }, "node_modules/cypress-image-diff-js": { "version": "1.22.0", - "resolved": "https://registry.npmjs.org/cypress-image-diff-js/-/cypress-image-diff-js-1.22.0.tgz", - "integrity": "sha512-ugCXZF6mVcp+TQQBrb2xARgFsnS5Mt3MCVpAr/fiF/GG7usuuiJWbHqQ+98H0kIoPIvFJzC5Nzf6VZ1+zycHLw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.12.5", "arg": "^4.1.1", @@ -7725,24 +7724,21 @@ }, "node_modules/cypress-recurse": { "version": "1.24.0", - "resolved": "https://registry.npmjs.org/cypress-recurse/-/cypress-recurse-1.24.0.tgz", - "integrity": "sha512-yH2XF71go+muxWjUbF7onNK0rzoVn27gzOPMTV3thg+Nv//jK2tV/z4hF0FWv88O3CAtmh7JZWhVNqFq4ghMZg==", "dev": true, + "license": "MIT", "dependencies": { "humanize-duration": "^3.27.3" } }, "node_modules/cypress/node_modules/@types/node": { "version": "14.18.34", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.34.tgz", - "integrity": "sha512-hcU9AIQVHmPnmjRK+XUUYlILlr9pQrsqSrwov/JK1pnf3GTQowVBhx54FbvM0AU/VXGH4i3+vgXS5EguR7fysA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cypress/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -7755,9 +7751,8 @@ }, "node_modules/cypress/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -7771,9 +7766,8 @@ }, "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7783,9 +7777,8 @@ }, "node_modules/cypress/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -7795,24 +7788,21 @@ }, "node_modules/cypress/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cypress/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cypress/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -7825,9 +7815,8 @@ }, "node_modules/dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" }, @@ -7837,14 +7826,12 @@ }, "node_modules/dayjs": { "version": "1.11.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", - "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/debug": { "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -7859,9 +7846,8 @@ }, "node_modules/decamelize": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", - "integrity": "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7871,15 +7857,13 @@ }, "node_modules/dedent": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deep-equal": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.1.0.tgz", - "integrity": "sha512-2pxgvWu3Alv1PoWEyVg7HS8YhGlUFUV7N5oOvfL6d+7xAmLSemMwv/c8Zv/i9KFzxV5Kt5CAvQc70fLwVuf4UA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "es-get-iterator": "^1.1.2", @@ -7903,15 +7887,13 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.2.2", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", - "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7974,9 +7956,8 @@ }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -7986,18 +7967,16 @@ }, "node_modules/define-lazy-prop": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/define-properties": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", - "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, + "license": "MIT", "dependencies": { "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" @@ -8011,9 +7990,8 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -8035,8 +8013,7 @@ }, "node_modules/dependency-graph": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", - "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -8053,9 +8030,8 @@ }, "node_modules/detect-newline": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -8068,9 +8044,8 @@ }, "node_modules/diff-sequences": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.3.1.tgz", - "integrity": "sha512-hlM3QR272NXCi4pq+N4Kok4kOp6EsgOM3ZSpJI7Da3UAs+Ttsi8MRmB6trM/lhyzUxGfOgnpkHtgqm5Q/CTcfQ==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -8081,9 +8056,8 @@ }, "node_modules/dir-glob": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -8111,9 +8085,8 @@ }, "node_modules/doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -8123,9 +8096,8 @@ }, "node_modules/dom-serializer": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", - "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, + "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -8137,21 +8109,19 @@ }, "node_modules/domelementtype": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ] + ], + "license": "BSD-2-Clause" }, "node_modules/domhandler": { "version": "4.3.1", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", - "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -8164,9 +8134,8 @@ }, "node_modules/domutils": { "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -8178,14 +8147,12 @@ }, "node_modules/earcut": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + "license": "ISC" }, "node_modules/ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "license": "MIT", "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -8199,14 +8166,12 @@ }, "node_modules/electron-to-chromium": { "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8216,14 +8181,12 @@ }, "node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + "license": "MIT" }, "node_modules/emojis-list": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -8262,17 +8225,15 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, + "license": "MIT", "dependencies": { "once": "^1.4.0" } }, "node_modules/engine.io-client": { "version": "6.2.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", - "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", @@ -8283,17 +8244,15 @@ }, "node_modules/engine.io-parser": { "version": "5.0.4", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "license": "MIT", "engines": { "node": ">=10.0.0" } }, "node_modules/enhanced-resolve": { "version": "5.12.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", - "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dev": true, + "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -8304,9 +8263,8 @@ }, "node_modules/enquirer": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1" }, @@ -8316,9 +8274,8 @@ }, "node_modules/entities": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true, + "license": "BSD-2-Clause", "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -8340,9 +8297,8 @@ }, "node_modules/errno": { "version": "0.1.8", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", - "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "prr": "~1.0.1" @@ -8353,18 +8309,16 @@ }, "node_modules/error-ex": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, "node_modules/es-abstract": { "version": "1.20.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", - "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -8401,9 +8355,8 @@ }, "node_modules/es-get-iterator": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.0", @@ -8419,411 +8372,87 @@ } }, "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", - "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.13.tgz", - "integrity": "sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.15.13", - "@esbuild/linux-loong64": "0.15.13", - "esbuild-android-64": "0.15.13", - "esbuild-android-arm64": "0.15.13", - "esbuild-darwin-64": "0.15.13", - "esbuild-darwin-arm64": "0.15.13", - "esbuild-freebsd-64": "0.15.13", - "esbuild-freebsd-arm64": "0.15.13", - "esbuild-linux-32": "0.15.13", - "esbuild-linux-64": "0.15.13", - "esbuild-linux-arm": "0.15.13", - "esbuild-linux-arm64": "0.15.13", - "esbuild-linux-mips64le": "0.15.13", - "esbuild-linux-ppc64le": "0.15.13", - "esbuild-linux-riscv64": "0.15.13", - "esbuild-linux-s390x": "0.15.13", - "esbuild-netbsd-64": "0.15.13", - "esbuild-openbsd-64": "0.15.13", - "esbuild-sunos-64": "0.15.13", - "esbuild-windows-32": "0.15.13", - "esbuild-windows-64": "0.15.13", - "esbuild-windows-arm64": "0.15.13" - } - }, - "node_modules/esbuild-android-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz", - "integrity": "sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz", - "integrity": "sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz", - "integrity": "sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz", - "integrity": "sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz", - "integrity": "sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz", - "integrity": "sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz", - "integrity": "sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz", - "integrity": "sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz", - "integrity": "sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz", - "integrity": "sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz", - "integrity": "sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz", - "integrity": "sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-riscv64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz", - "integrity": "sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz", - "integrity": "sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-netbsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz", - "integrity": "sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz", - "integrity": "sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz", - "integrity": "sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } + "version": "0.9.3", + "dev": true, + "license": "MIT" }, - "node_modules/esbuild-wasm": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.13.tgz", - "integrity": "sha512-0am8fvHKACwofWQxtZLTMv4mDiDwUrdt0DyRaQ2r7YWIpkmpg4GWYy0EyW+gPjiPHzkZKqN9d3UYsZGgvaAASw==", + "node_modules/es-shim-unscopables": { + "version": "1.0.0", "dev": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "has": "^1.0.3" } }, - "node_modules/esbuild-windows-32": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz", - "integrity": "sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==", - "cpu": [ - "ia32" - ], + "node_modules/es-to-primitive": { + "version": "1.2.1", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, "engines": { - "node": ">=12" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild-windows-64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz", - "integrity": "sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==", - "cpu": [ - "x64" - ], + "node_modules/esbuild": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.17.tgz", + "integrity": "sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==", "dev": true, + "hasInstallScript": true, "optional": true, - "os": [ - "win32" - ], + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.17", + "@esbuild/android-arm64": "0.16.17", + "@esbuild/android-x64": "0.16.17", + "@esbuild/darwin-arm64": "0.16.17", + "@esbuild/darwin-x64": "0.16.17", + "@esbuild/freebsd-arm64": "0.16.17", + "@esbuild/freebsd-x64": "0.16.17", + "@esbuild/linux-arm": "0.16.17", + "@esbuild/linux-arm64": "0.16.17", + "@esbuild/linux-ia32": "0.16.17", + "@esbuild/linux-loong64": "0.16.17", + "@esbuild/linux-mips64el": "0.16.17", + "@esbuild/linux-ppc64": "0.16.17", + "@esbuild/linux-riscv64": "0.16.17", + "@esbuild/linux-s390x": "0.16.17", + "@esbuild/linux-x64": "0.16.17", + "@esbuild/netbsd-x64": "0.16.17", + "@esbuild/openbsd-x64": "0.16.17", + "@esbuild/sunos-x64": "0.16.17", + "@esbuild/win32-arm64": "0.16.17", + "@esbuild/win32-ia32": "0.16.17", + "@esbuild/win32-x64": "0.16.17" } }, - "node_modules/esbuild-windows-arm64": { - "version": "0.15.13", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz", - "integrity": "sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==", - "cpu": [ - "arm64" - ], + "node_modules/esbuild-wasm": { + "version": "0.16.17", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.16.17.tgz", + "integrity": "sha512-Tn7NuMqRcM+T/qCOxbQRq0qrwWl1sUWp6ARfJRakE8Bepew6zata4qrKgH2YqovNC5e/2fcTa7o+VL/FAOZC1Q==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "bin": { + "esbuild": "bin/esbuild" + }, "engines": { "node": ">=12" } }, "node_modules/escalade": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "license": "MIT", "engines": { "node": ">=6" } @@ -8836,19 +8465,18 @@ }, "node_modules/escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", "engines": { "node": ">=0.8.0" } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -8899,9 +8527,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -8912,9 +8540,8 @@ }, "node_modules/eslint-etc": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/eslint-etc/-/eslint-etc-5.2.0.tgz", - "integrity": "sha512-Gcm/NMa349FOXb1PEEfNMMyIANuorIc2/mI5Vfu1zENNsz+FBVhF62uY6gPUCigm/xDOc8JOnl+71WGnlzlDag==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "tsutils": "^3.17.1", @@ -8926,13 +8553,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -8946,9 +8574,8 @@ }, "node_modules/eslint-module-utils": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", - "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^3.2.7" }, @@ -8963,31 +8590,32 @@ }, "node_modules/eslint-module-utils/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "dependencies": { "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -8998,19 +8626,18 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -9018,17 +8645,19 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-rxjs": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-rxjs/-/eslint-plugin-rxjs-5.0.2.tgz", - "integrity": "sha512-Q2wsEHWInhZ3uz5df+YbD4g/NPQqAeYHjJuEsxqgVS+XAsYCuVE2pj9kADdMFy4GsQy2jt7KP+TOrnq1i6bI5Q==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "common-tags": "^1.8.0", @@ -9047,9 +8676,8 @@ }, "node_modules/eslint-plugin-rxjs-angular": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-rxjs-angular/-/eslint-plugin-rxjs-angular-2.0.0.tgz", - "integrity": "sha512-MalcYcEHOK2NT+avWSI1PsUilwGx6cprMQdw9jJRlCTkIvsUvCGFD1eTqQKVImwkK8+te732v9VsP/XcXlKZqA==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/experimental-utils": "^5.0.0", "common-tags": "^1.8.0", @@ -9064,9 +8692,8 @@ }, "node_modules/eslint-plugin-unicorn": { "version": "45.0.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", - "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", "@eslint-community/eslint-utils": "^4.1.2", @@ -9097,9 +8724,8 @@ }, "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", - "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -9109,9 +8735,8 @@ }, "node_modules/eslint-scope": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", - "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -9122,9 +8747,8 @@ }, "node_modules/eslint-utils": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^2.0.0" }, @@ -9140,27 +8764,24 @@ }, "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10" } }, "node_modules/eslint-visitor-keys": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", - "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/eslint/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -9174,9 +8795,8 @@ }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -9189,15 +8809,13 @@ }, "node_modules/eslint/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 + "dev": true, + "license": "Python-2.0" }, "node_modules/eslint/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -9211,9 +8829,8 @@ }, "node_modules/eslint/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -9223,15 +8840,13 @@ }, "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -9241,9 +8856,8 @@ }, "node_modules/eslint/node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -9257,9 +8871,8 @@ }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -9269,9 +8882,8 @@ }, "node_modules/eslint/node_modules/globals": { "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -9284,18 +8896,16 @@ }, "node_modules/eslint/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/eslint/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, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -9305,15 +8915,13 @@ }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eslint/node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -9326,9 +8934,8 @@ }, "node_modules/eslint/node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -9341,9 +8948,8 @@ }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -9353,9 +8959,8 @@ }, "node_modules/eslint/node_modules/type-fest": { "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -9382,9 +8987,8 @@ }, "node_modules/esprima": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true, + "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -9395,9 +8999,8 @@ }, "node_modules/esquery": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -9407,9 +9010,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -9419,18 +9021,16 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -9446,15 +9046,13 @@ }, "node_modules/eventemitter-asyncresource": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", - "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eventemitter2": { "version": "6.4.9", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.9.tgz", - "integrity": "sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/eventemitter3": { "version": "4.0.7", @@ -9464,18 +9062,16 @@ }, "node_modules/events": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.x" } }, "node_modules/execa": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", @@ -9496,9 +9092,8 @@ }, "node_modules/executable": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", "dev": true, + "license": "MIT", "dependencies": { "pify": "^2.2.0" }, @@ -9508,8 +9103,6 @@ }, "node_modules/exit": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -9517,9 +9110,8 @@ }, "node_modules/expect": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.3.1.tgz", - "integrity": "sha512-gGb1yTgU30Q0O/tQq+z30KBWv24ApkMgFUpvKBkyLUBL68Wv8dHdJxTBZFl/iT8K/bqDHvUYRH6IIN3rToopPA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.3.1", "jest-get-type": "^29.2.0", @@ -9620,15 +9212,13 @@ }, "node_modules/extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/external-editor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -9640,9 +9230,8 @@ }, "node_modules/external-editor/node_modules/tmp": { "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -9652,9 +9241,8 @@ }, "node_modules/extract-zip": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -9672,24 +9260,21 @@ }, "node_modules/extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -9703,21 +9288,18 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { "version": "1.14.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", - "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -9736,27 +9318,24 @@ }, "node_modules/fb-watchman": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } }, "node_modules/fd-slicer": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", "dev": true, + "license": "MIT", "dependencies": { "pend": "~1.2.0" } }, "node_modules/figures": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -9769,9 +9348,8 @@ }, "node_modules/file-entry-cache": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -9781,8 +9359,7 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -9842,9 +9419,8 @@ }, "node_modules/find-up": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -9855,9 +9431,8 @@ }, "node_modules/flat-cache": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.1.0", "rimraf": "^3.0.2" @@ -9868,9 +9443,8 @@ }, "node_modules/flatted": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.2", @@ -9894,27 +9468,24 @@ }, "node_modules/for-each": { "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", "dev": true, + "license": "MIT", "dependencies": { "is-callable": "^1.1.3" } }, "node_modules/forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "*" } }, "node_modules/form-data": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -9935,9 +9506,8 @@ }, "node_modules/fraction.js": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", "dev": true, + "license": "MIT", "engines": { "node": "*" }, @@ -9957,9 +9527,8 @@ }, "node_modules/fs-extra": { "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, + "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", @@ -9971,15 +9540,15 @@ } }, "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.0.tgz", + "integrity": "sha512-EUojgQaSPy6sxcqcZgQv6TVF6jiKvurji3AxhAivs/Ep4O1UpS8TusaxpybfFHZ2skRhLqzk6WR8nqNYIMMDeA==", "dev": true, "dependencies": { - "minipass": "^3.0.0" + "minipass": "^4.0.0" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/fs-monkey": { @@ -9990,33 +9559,17 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } + "license": "ISC" }, "node_modules/function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/function.prototype.name": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -10032,9 +9585,8 @@ }, "node_modules/functions-have-names": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10060,16 +9612,14 @@ }, "node_modules/gensync": { "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/geotiff": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.0.7.tgz", - "integrity": "sha512-FKvFTNowMU5K6lHYY2f83d4lS2rsCNdpUC28AX61x9ZzzqPNaWFElWv93xj0eJFaNyOYA63ic5OzJ88dHpoA5Q==", + "license": "MIT", "dependencies": { "@petamoriken/float16": "^3.4.7", "lerc": "^3.0.0", @@ -10085,17 +9635,15 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -10107,18 +9655,16 @@ }, "node_modules/get-package-type": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } }, "node_modules/get-stream": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, + "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -10131,9 +9677,8 @@ }, "node_modules/get-symbol-description": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -10147,26 +9692,23 @@ }, "node_modules/getos": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", "dev": true, + "license": "MIT", "dependencies": { "async": "^3.2.0" } }, "node_modules/getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0" } }, "node_modules/glob": { "version": "8.0.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", - "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10183,8 +9725,7 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -10194,22 +9735,19 @@ }, "node_modules/glob-to-regexp": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "dev": true, + "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10219,9 +9757,8 @@ }, "node_modules/global-dirs": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, + "license": "MIT", "dependencies": { "ini": "2.0.0" }, @@ -10234,26 +9771,23 @@ }, "node_modules/global-dirs/node_modules/ini": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/globals": { "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/globby": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -10271,9 +9805,8 @@ }, "node_modules/gopd": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -10283,15 +9816,13 @@ }, "node_modules/graceful-fs": { "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/grapheme-splitter": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/handle-thing": { "version": "2.0.1", @@ -10301,9 +9832,8 @@ }, "node_modules/handlebars": { "version": "4.7.7", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz", - "integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==", "dev": true, + "license": "MIT", "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.0", @@ -10322,18 +9852,16 @@ }, "node_modules/handlebars/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, + "license": "MIT", "dependencies": { "function-bind": "^1.1.1" }, @@ -10343,26 +9871,23 @@ }, "node_modules/has-bigints": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/has-property-descriptors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", - "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.1" }, @@ -10372,9 +9897,8 @@ }, "node_modules/has-symbols": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10384,9 +9908,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -10405,9 +9928,8 @@ }, "node_modules/hdr-histogram-js": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", "dev": true, + "license": "BSD", "dependencies": { "@assemblyscript/loader": "^0.10.1", "base64-js": "^1.2.0", @@ -10416,26 +9938,24 @@ }, "node_modules/hdr-histogram-js/node_modules/pako": { "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "license": "(MIT AND Zlib)" }, "node_modules/hdr-histogram-percentiles-obj": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/hosted-git-info": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", - "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/hpack.js": { @@ -10494,9 +10014,8 @@ }, "node_modules/html-escaper": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-cache-semantics": { "version": "4.1.0", @@ -10595,9 +10114,8 @@ }, "node_modules/http-signature": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", "dev": true, + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^2.0.2", @@ -10609,9 +10127,8 @@ }, "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, + "license": "MIT", "dependencies": { "agent-base": "6", "debug": "4" @@ -10622,18 +10139,16 @@ }, "node_modules/human-signals": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=8.12.0" } }, "node_modules/humanize-duration": { "version": "3.27.3", - "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.27.3.tgz", - "integrity": "sha512-iimHkHPfIAQ8zCDQLgn08pRqSVioyWvnGfaQ8gond2wf7Jq2jJ+24ykmnRyiz3fIldcn4oUuQXpjqKLhSVR7lw==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/humanize-ms": { "version": "1.2.1", @@ -10646,9 +10161,8 @@ }, "node_modules/iconv-lite": { "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -10658,9 +10172,8 @@ }, "node_modules/icss-utils": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -10670,8 +10183,6 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "funding": [ { "type": "github", @@ -10685,13 +10196,13 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -10718,9 +10229,9 @@ } }, "node_modules/ignore-walk/node_modules/minimatch": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.1.tgz", - "integrity": "sha512-362NP+zlprccbEt/SkxKfRMHnNY85V74mVnpUpNyr3F35covl09Kec7/sEFLt3RA4oXmewtoaanoIf67SE5Y5g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -10731,9 +10242,8 @@ }, "node_modules/image-size": { "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", "dev": true, + "license": "MIT", "optional": true, "bin": { "image-size": "bin/image-size.js" @@ -10743,9 +10253,9 @@ } }, "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -10753,9 +10263,8 @@ }, "node_modules/immutable": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", - "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -10784,9 +10293,8 @@ }, "node_modules/import-local": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -10803,18 +10311,16 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, "node_modules/indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10827,8 +10333,7 @@ }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -10836,23 +10341,20 @@ }, "node_modules/inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "license": "ISC" }, "node_modules/ini": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", "dev": true, + "license": "ISC", "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/inquirer": { "version": "8.2.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", - "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -10876,9 +10378,8 @@ }, "node_modules/inquirer/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -10891,9 +10392,8 @@ }, "node_modules/inquirer/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -10907,9 +10407,8 @@ }, "node_modules/inquirer/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -10919,24 +10418,21 @@ }, "node_modules/inquirer/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/inquirer/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/inquirer/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -10946,9 +10442,8 @@ }, "node_modules/internal-slot": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", - "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3", "has": "^1.0.3", @@ -10975,9 +10470,8 @@ }, "node_modules/is-arguments": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -10991,15 +10485,13 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-bigint": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", "dev": true, + "license": "MIT", "dependencies": { "has-bigints": "^1.0.1" }, @@ -11009,8 +10501,7 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -11020,9 +10511,8 @@ }, "node_modules/is-boolean-object": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11036,9 +10526,8 @@ }, "node_modules/is-builtin-module": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", - "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", "dev": true, + "license": "MIT", "dependencies": { "builtin-modules": "^3.3.0" }, @@ -11051,9 +10540,8 @@ }, "node_modules/is-callable": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11063,9 +10551,8 @@ }, "node_modules/is-ci": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "license": "MIT", "dependencies": { "ci-info": "^3.2.0" }, @@ -11075,9 +10562,8 @@ }, "node_modules/is-core-module": { "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", "dev": true, + "license": "MIT", "dependencies": { "has": "^1.0.3" }, @@ -11087,9 +10573,8 @@ }, "node_modules/is-date-object": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11102,9 +10587,8 @@ }, "node_modules/is-docker": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, + "license": "MIT", "bin": { "is-docker": "cli.js" }, @@ -11117,33 +10601,29 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/is-generator-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -11153,9 +10633,8 @@ }, "node_modules/is-installed-globally": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, + "license": "MIT", "dependencies": { "global-dirs": "^3.0.0", "is-path-inside": "^3.0.2" @@ -11169,9 +10648,8 @@ }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -11184,18 +10662,16 @@ }, "node_modules/is-map": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-negative-zero": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -11205,17 +10681,15 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-number-object": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11228,9 +10702,8 @@ }, "node_modules/is-path-inside": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -11249,9 +10722,8 @@ }, "node_modules/is-plain-object": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, + "license": "MIT", "dependencies": { "isobject": "^3.0.1" }, @@ -11261,9 +10733,8 @@ }, "node_modules/is-regex": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -11277,18 +10748,16 @@ }, "node_modules/is-set": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-shared-array-buffer": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -11298,9 +10767,8 @@ }, "node_modules/is-stream": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -11310,9 +10778,8 @@ }, "node_modules/is-string": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, + "license": "MIT", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11325,9 +10792,8 @@ }, "node_modules/is-symbol": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", "dev": true, + "license": "MIT", "dependencies": { "has-symbols": "^1.0.2" }, @@ -11340,9 +10806,8 @@ }, "node_modules/is-typed-array": { "version": "1.1.10", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", - "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -11359,15 +10824,13 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11377,18 +10840,16 @@ }, "node_modules/is-weakmap": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/is-weakref": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2" }, @@ -11398,9 +10859,8 @@ }, "node_modules/is-weakset": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.1" @@ -11411,15 +10871,13 @@ }, "node_modules/is-what": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", - "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-wsl": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, @@ -11429,45 +10887,39 @@ }, "node_modules/isarray": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isobject": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -11481,18 +10933,16 @@ }, "node_modules/istanbul-lib-instrument/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/istanbul-lib-report": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^3.0.0", @@ -11504,18 +10954,16 @@ }, "node_modules/istanbul-lib-report/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-report/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11525,9 +10973,8 @@ }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -11539,18 +10986,16 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/istanbul-reports": { "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -11561,9 +11006,8 @@ }, "node_modules/jest": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.3.1.tgz", - "integrity": "sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.3.1", "@jest/types": "^29.3.1", @@ -11587,9 +11031,8 @@ }, "node_modules/jest-changed-files": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.2.0.tgz", - "integrity": "sha512-qPVmLLyBmvF5HJrY7krDisx6Voi8DmlV3GZYX0aFNbaQsZeoz1hfxcCMbqDGuQCxU1dJy9eYc2xscE8QrCCYaA==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "p-limit": "^3.1.0" @@ -11600,9 +11043,8 @@ }, "node_modules/jest-changed-files/node_modules/execa": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -11623,9 +11065,8 @@ }, "node_modules/jest-changed-files/node_modules/get-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -11635,18 +11076,16 @@ }, "node_modules/jest-changed-files/node_modules/human-signals": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } }, "node_modules/jest-circus": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.3.1.tgz", - "integrity": "sha512-wpr26sEvwb3qQQbdlmei+gzp6yoSSoSL6GsLPxnuayZSMrSd5Ka7IjAvatpIernBvT2+Ic6RLTg+jSebScmasg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/expect": "^29.3.1", @@ -11674,9 +11113,8 @@ }, "node_modules/jest-circus/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11689,9 +11127,8 @@ }, "node_modules/jest-circus/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11705,9 +11142,8 @@ }, "node_modules/jest-circus/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11717,24 +11153,21 @@ }, "node_modules/jest-circus/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-circus/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-circus/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11744,9 +11177,8 @@ }, "node_modules/jest-cli": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.3.1.tgz", - "integrity": "sha512-TO/ewvwyvPOiBBuWZ0gm04z3WWP8TIK8acgPzE4IxgsLKQgb377NYGrQLc3Wl/7ndWzIH2CDNNsUjGxwLL43VQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.3.1", "@jest/test-result": "^29.3.1", @@ -11778,9 +11210,8 @@ }, "node_modules/jest-cli/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11793,9 +11224,8 @@ }, "node_modules/jest-cli/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11809,9 +11239,8 @@ }, "node_modules/jest-cli/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11821,24 +11250,21 @@ }, "node_modules/jest-cli/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-cli/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11848,9 +11274,8 @@ }, "node_modules/jest-config": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.3.1.tgz", - "integrity": "sha512-y0tFHdj2WnTEhxmGUK1T7fgLen7YK4RtfvpLFBXfQkh2eMJAQq24Vx9472lvn5wg0MAO6B+iPfJfzdR9hJYalg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.3.1", @@ -11893,9 +11318,8 @@ }, "node_modules/jest-config/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -11908,9 +11332,8 @@ }, "node_modules/jest-config/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11924,9 +11347,8 @@ }, "node_modules/jest-config/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -11936,15 +11358,13 @@ }, "node_modules/jest-config/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-config/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11962,18 +11382,16 @@ }, "node_modules/jest-config/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-config/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -11983,9 +11401,8 @@ }, "node_modules/jest-diff": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.3.1.tgz", - "integrity": "sha512-vU8vyiO7568tmin2lA3r2DP8oRvzhvRcD4DjpXc6uGveQodyk7CKLhQlCSiwgx3g0pFaE88/KLZ0yaTWMc4Uiw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.3.1", @@ -11998,9 +11415,8 @@ }, "node_modules/jest-diff/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12013,9 +11429,8 @@ }, "node_modules/jest-diff/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12029,9 +11444,8 @@ }, "node_modules/jest-diff/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12041,24 +11455,21 @@ }, "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-diff/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-diff/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12068,9 +11479,8 @@ }, "node_modules/jest-docblock": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.2.0.tgz", - "integrity": "sha512-bkxUsxTgWQGbXV5IENmfiIuqZhJcyvF7tU4zJ/7ioTutdz4ToB5Yx6JOFBpgI+TphRY4lhOyCWGNH/QFQh5T6A==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -12080,9 +11490,8 @@ }, "node_modules/jest-each": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.3.1.tgz", - "integrity": "sha512-qrZH7PmFB9rEzCSl00BWjZYuS1BSOH8lLuC0azQE9lQrAx3PWGKHTDudQiOSwIy5dGAJh7KA0ScYlCP7JxvFYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "chalk": "^4.0.0", @@ -12096,9 +11505,8 @@ }, "node_modules/jest-each/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12111,9 +11519,8 @@ }, "node_modules/jest-each/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12127,9 +11534,8 @@ }, "node_modules/jest-each/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12139,24 +11545,21 @@ }, "node_modules/jest-each/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-each/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-each/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12166,9 +11569,8 @@ }, "node_modules/jest-environment-node": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.3.1.tgz", - "integrity": "sha512-xm2THL18Xf5sIHoU7OThBPtuH6Lerd+Y1NLYiZJlkE3hbE+7N7r8uvHIl/FkZ5ymKXJe/11SQuf3fv4v6rUMag==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -12183,18 +11585,16 @@ }, "node_modules/jest-get-type": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.2.0.tgz", - "integrity": "sha512-uXNJlg8hKFEnDgFsrCjznB+sTxdkuqiCL6zMgA75qEbAJjJYTs9XPrvDctrEig2GDow22T/LvHgO57iJhXB/UA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-haste-map": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.3.1.tgz", - "integrity": "sha512-/FFtvoG1xjbbPXQLFef+WSU4yrc0fc0Dds6aRPBojUid7qlPqZvxdUBA03HW0fnVHXVCnCdkuoghYItKNzc/0A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/graceful-fs": "^4.1.3", @@ -12217,9 +11617,8 @@ }, "node_modules/jest-leak-detector": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.3.1.tgz", - "integrity": "sha512-3DA/VVXj4zFOPagGkuqHnSQf1GZBmmlagpguxEERO6Pla2g84Q1MaVIB3YMxgUaFIaYag8ZnTyQgiZ35YEqAQA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.2.0", "pretty-format": "^29.3.1" @@ -12230,9 +11629,8 @@ }, "node_modules/jest-matcher-utils": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.3.1.tgz", - "integrity": "sha512-fkRMZUAScup3txIKfMe3AIZZmPEjWEdsPJFK3AIy5qRohWqQFg1qrmKfYXR9qEkNc7OdAu2N4KPHibEmy4HPeQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.3.1", @@ -12245,9 +11643,8 @@ }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12260,9 +11657,8 @@ }, "node_modules/jest-matcher-utils/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12276,9 +11672,8 @@ }, "node_modules/jest-matcher-utils/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12288,24 +11683,21 @@ }, "node_modules/jest-matcher-utils/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-matcher-utils/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-matcher-utils/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12315,9 +11707,8 @@ }, "node_modules/jest-message-util": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.3.1.tgz", - "integrity": "sha512-lMJTbgNcDm5z+6KDxWtqOFWlGQxD6XaYwBqHR8kmpkP+WWWG90I35kdtQHY67Ay5CSuydkTBbJG+tH9JShFCyA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.3.1", @@ -12335,9 +11726,8 @@ }, "node_modules/jest-message-util/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12350,9 +11740,8 @@ }, "node_modules/jest-message-util/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12366,9 +11755,8 @@ }, "node_modules/jest-message-util/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12378,24 +11766,21 @@ }, "node_modules/jest-message-util/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-message-util/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-message-util/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12405,9 +11790,8 @@ }, "node_modules/jest-mock": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.3.1.tgz", - "integrity": "sha512-H8/qFDtDVMFvFP4X8NuOT3XRDzOUTz+FeACjufHzsOIBAxivLqkB1PoLCaJx9iPPQ8dZThHPp/G3WRWyMgA3JA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -12419,9 +11803,8 @@ }, "node_modules/jest-pnp-resolver": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -12436,18 +11819,16 @@ }, "node_modules/jest-regex-util": { "version": "29.2.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.2.0.tgz", - "integrity": "sha512-6yXn0kg2JXzH30cr2NlThF+70iuO/3irbaB4mh5WyqNIvLLP+B6sFdluO1/1RJmslyh/f9osnefECflHvTbwVA==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/jest-resolve": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.3.1.tgz", - "integrity": "sha512-amXJgH/Ng712w3Uz5gqzFBBjxV8WFLSmNjoreBGMqxgCz5cH7swmBZzgBaCIOsvb0NbpJ0vgaSFdJqMdT+rADw==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -12465,9 +11846,8 @@ }, "node_modules/jest-resolve-dependencies": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.3.1.tgz", - "integrity": "sha512-Vk0cYq0byRw2WluNmNWGqPeRnZ3p3hHmjJMp2dyyZeYIfiBskwq4rpiuGFR6QGAdbj58WC7HN4hQHjf2mpvrLA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.2.0", "jest-snapshot": "^29.3.1" @@ -12478,9 +11858,8 @@ }, "node_modules/jest-resolve/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12493,9 +11872,8 @@ }, "node_modules/jest-resolve/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12509,9 +11887,8 @@ }, "node_modules/jest-resolve/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12521,24 +11898,21 @@ }, "node_modules/jest-resolve/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-resolve/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-resolve/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12548,9 +11922,8 @@ }, "node_modules/jest-runner": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.3.1.tgz", - "integrity": "sha512-oFvcwRNrKMtE6u9+AQPMATxFcTySyKfLhvso7Sdk/rNpbhg4g2GAGCopiInk1OP4q6gz3n6MajW4+fnHWlU3bA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.3.1", "@jest/environment": "^29.3.1", @@ -12580,9 +11953,8 @@ }, "node_modules/jest-runner/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12595,9 +11967,8 @@ }, "node_modules/jest-runner/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12611,9 +11982,8 @@ }, "node_modules/jest-runner/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12623,33 +11993,29 @@ }, "node_modules/jest-runner/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-runner/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runner/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/jest-runner/node_modules/source-map-support": { "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -12657,9 +12023,8 @@ }, "node_modules/jest-runner/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12669,9 +12034,8 @@ }, "node_modules/jest-runtime": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.3.1.tgz", - "integrity": "sha512-jLzkIxIqXwBEOZx7wx9OO9sxoZmgT2NhmQKzHQm1xwR1kNW/dn0OjxR424VwHHf1SPN6Qwlb5pp1oGCeFTQ62A==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.3.1", "@jest/fake-timers": "^29.3.1", @@ -12702,9 +12066,8 @@ }, "node_modules/jest-runtime/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12717,9 +12080,8 @@ }, "node_modules/jest-runtime/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12733,9 +12095,8 @@ }, "node_modules/jest-runtime/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12745,15 +12106,13 @@ }, "node_modules/jest-runtime/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-runtime/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -12771,18 +12130,16 @@ }, "node_modules/jest-runtime/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-runtime/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12792,9 +12149,8 @@ }, "node_modules/jest-snapshot": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.3.1.tgz", - "integrity": "sha512-+3JOc+s28upYLI2OJM4PWRGK9AgpsMs/ekNryUV0yMBClT9B1DF2u2qay8YxcQd338PPYSFNb0lsar1B49sLDA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -12827,9 +12183,8 @@ }, "node_modules/jest-snapshot/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12842,9 +12197,8 @@ }, "node_modules/jest-snapshot/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12858,9 +12212,8 @@ }, "node_modules/jest-snapshot/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12870,24 +12223,21 @@ }, "node_modules/jest-snapshot/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-snapshot/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-snapshot/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12897,9 +12247,8 @@ }, "node_modules/jest-util": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.3.1.tgz", - "integrity": "sha512-7YOVZaiX7RJLv76ZfHt4nbNEzzTRiMW/IiOG7ZOKmTXmoGBxUDefgMAxQubu6WPVqP5zSzAdZG0FfLcC7HOIFQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "@types/node": "*", @@ -12914,9 +12263,8 @@ }, "node_modules/jest-util/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -12929,9 +12277,8 @@ }, "node_modules/jest-util/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -12945,9 +12292,8 @@ }, "node_modules/jest-util/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -12957,24 +12303,21 @@ }, "node_modules/jest-util/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-util/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -12984,9 +12327,8 @@ }, "node_modules/jest-validate": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.3.1.tgz", - "integrity": "sha512-N9Lr3oYR2Mpzuelp1F8negJR3YE+L1ebk1rYA5qYo9TTY3f9OWdptLoNSPP9itOCBIRBqjt/S5XHlzYglLN67g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.3.1", "camelcase": "^6.2.0", @@ -13001,9 +12343,8 @@ }, "node_modules/jest-validate/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13016,9 +12357,8 @@ }, "node_modules/jest-validate/node_modules/camelcase": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -13028,9 +12368,8 @@ }, "node_modules/jest-validate/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13044,9 +12383,8 @@ }, "node_modules/jest-validate/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13056,24 +12394,21 @@ }, "node_modules/jest-validate/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-validate/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-validate/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13083,9 +12418,8 @@ }, "node_modules/jest-watcher": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.3.1.tgz", - "integrity": "sha512-RspXG2BQFDsZSRKGCT/NiNa8RkQ1iKAjrO0//soTMWx/QUt+OcxMqMSBxz23PYGqUuWm2+m2mNNsmj0eIoOaFg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.3.1", "@jest/types": "^29.3.1", @@ -13102,9 +12436,8 @@ }, "node_modules/jest-watcher/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13117,9 +12450,8 @@ }, "node_modules/jest-watcher/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13133,9 +12465,8 @@ }, "node_modules/jest-watcher/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13145,24 +12476,21 @@ }, "node_modules/jest-watcher/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jest-watcher/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-watcher/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13172,9 +12500,8 @@ }, "node_modules/jest-worker": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.3.1.tgz", - "integrity": "sha512-lY4AnnmsEWeiXirAIA0c9SDPbuCBq8IYuDVL8PMm0MZ2PEs2yPvRA/J64QBXuZp7CYKrDM/rmNrc9/i3KJQncw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.3.1", @@ -13187,18 +12514,16 @@ }, "node_modules/jest-worker/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13211,9 +12536,8 @@ }, "node_modules/js-sdsl": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", - "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", "dev": true, + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/js-sdsl" @@ -13221,14 +12545,12 @@ }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + "license": "MIT" }, "node_modules/js-yaml": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -13239,14 +12561,12 @@ }, "node_modules/jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsesc": { "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -13256,43 +12576,37 @@ }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stringify-pretty-compact": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz", - "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ==" + "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/json5": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", - "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "bin": { "json5": "lib/cli.js" }, @@ -13302,15 +12616,13 @@ }, "node_modules/jsonc-parser": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/jsonfile": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, + "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -13329,12 +12641,11 @@ }, "node_modules/jsprim": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -13344,59 +12655,52 @@ }, "node_modules/karma-source-map-support": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", - "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", "dev": true, + "license": "MIT", "dependencies": { "source-map-support": "^0.5.5" } }, "node_modules/kind-of": { "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/kleur": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/klona": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", - "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/lazy-ass": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", "dev": true, + "license": "MIT", "engines": { "node": "> 0.8" } }, "node_modules/lerc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz", - "integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==" + "license": "Apache-2.0" }, "node_modules/less": { "version": "4.1.3", - "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", - "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "copy-anything": "^2.0.1", "parse-node-version": "^1.0.1", @@ -13420,9 +12724,8 @@ }, "node_modules/less-loader": { "version": "11.1.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", - "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4" }, @@ -13440,9 +12743,8 @@ }, "node_modules/less/node_modules/make-dir": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "pify": "^4.0.1", @@ -13454,9 +12756,8 @@ }, "node_modules/less/node_modules/pify": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=6" @@ -13464,9 +12765,8 @@ }, "node_modules/less/node_modules/semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, + "license": "ISC", "optional": true, "bin": { "semver": "bin/semver" @@ -13474,9 +12774,8 @@ }, "node_modules/less/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "optional": true, "engines": { "node": ">=0.10.0" @@ -13484,18 +12783,16 @@ }, "node_modules/leven": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -13506,14 +12803,12 @@ }, "node_modules/libphonenumber-js": { "version": "1.10.15", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.15.tgz", - "integrity": "sha512-sLeVLmWX17VCKKulc+aDIRHS95TxoTsKMRJi5s5gJdwlqNzMWcBCtSHHruVyXjqfi67daXM2SnLf2juSrdx5Sg==" + "license": "MIT" }, "node_modules/license-webpack-plugin": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", - "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, + "license": "ISC", "dependencies": { "webpack-sources": "^3.0.0" }, @@ -13528,15 +12823,13 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/listr2": { "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", "dev": true, + "license": "MIT", "dependencies": { "cli-truncate": "^2.1.0", "colorette": "^2.0.16", @@ -13561,27 +12854,24 @@ }, "node_modules/loader-runner": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", - "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.11.5" } }, "node_modules/loader-utils": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 12.13.0" } }, "node_modules/locate-path": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -13591,44 +12881,37 @@ }, "node_modules/lodash": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash-es": { "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", - "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + "license": "MIT" }, "node_modules/lodash.debounce": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.once": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.1.0", "is-unicode-supported": "^0.1.0" @@ -13642,9 +12925,8 @@ }, "node_modules/log-symbols/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13657,9 +12939,8 @@ }, "node_modules/log-symbols/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13673,9 +12954,8 @@ }, "node_modules/log-symbols/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13685,24 +12965,21 @@ }, "node_modules/log-symbols/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-symbols/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/log-symbols/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -13712,9 +12989,8 @@ }, "node_modules/log-update": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", @@ -13730,9 +13006,8 @@ }, "node_modules/log-update/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -13745,9 +13020,8 @@ }, "node_modules/log-update/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -13757,15 +13031,13 @@ }, "node_modules/log-update/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/log-update/node_modules/slice-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -13780,9 +13052,8 @@ }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -13802,12 +13073,11 @@ } }, "node_modules/magic-string": { - "version": "0.26.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz", - "integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==", - "dev": true, + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.13" }, "engines": { "node": ">=12" @@ -13815,9 +13085,8 @@ }, "node_modules/make-dir": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^6.0.0" }, @@ -13830,18 +13099,16 @@ }, "node_modules/make-dir/node_modules/semver": { "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/make-error": { "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/make-fetch-happen": { "version": "10.2.1", @@ -13909,7 +13176,31 @@ "unique-filename": "^2.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/make-fetch-happen/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/make-fetch-happen/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/make-fetch-happen/node_modules/ssri": { @@ -13950,17 +13241,15 @@ }, "node_modules/makeerror": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } }, "node_modules/mapbox-to-css-font": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.1.tgz", - "integrity": "sha512-QQ/iKiM43DM9+aujTL45Iz5o7gDeSFmy4LPl3HZmNcwCE++NxGazf+yFpY+wCb+YS23sDa1ghpo3zrNFOcHlow==" + "license": "BSD-2-Clause" }, "node_modules/media-typer": { "version": "0.3.0", @@ -13972,9 +13261,9 @@ } }, "node_modules/memfs": { - "version": "3.4.12", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.12.tgz", - "integrity": "sha512-BcjuQn6vfqP+k100e0E9m61Hyqa//Brp+I3f0OBmN0ATHlFA8vx3Lt8z57R3u2bPqe3WGDBC+nF72fTH7isyEw==", + "version": "3.4.13", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz", + "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==", "dev": true, "dependencies": { "fs-monkey": "^1.0.3" @@ -13991,15 +13280,13 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -14015,9 +13302,8 @@ }, "node_modules/micromatch": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -14028,9 +13314,8 @@ }, "node_modules/mime": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -14040,18 +13325,16 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -14061,26 +13344,24 @@ }, "node_modules/mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/min-indent": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/mini-css-extract-plugin": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", - "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", "dev": true, "dependencies": { "schema-utils": "^4.0.0" @@ -14104,9 +13385,8 @@ }, "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, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -14116,16 +13396,15 @@ }, "node_modules/minimist": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", - "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", + "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -14146,6 +13425,18 @@ "node": ">= 8" } }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-fetch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", @@ -14163,6 +13454,18 @@ "encoding": "^0.1.13" } }, + "node_modules/minipass-fetch/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", @@ -14175,6 +13478,18 @@ "node": ">= 8" } }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-json-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", @@ -14185,6 +13500,18 @@ "minipass": "^3.0.0" } }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", @@ -14197,6 +13524,18 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", @@ -14209,6 +13548,18 @@ "node": ">=8" } }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -14222,6 +13573,18 @@ "node": ">= 8" } }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -14236,17 +13599,15 @@ }, "node_modules/moment": { "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/ms": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "license": "MIT" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -14263,15 +13624,13 @@ }, "node_modules/mute-stream": { "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/nanoid": { "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "dev": true, + "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -14281,21 +13640,18 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/natural-compare-lite": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/needle": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", - "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "debug": "^3.2.6", @@ -14311,9 +13667,8 @@ }, "node_modules/needle/node_modules/debug": { "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "ms": "^2.1.1" @@ -14321,9 +13676,8 @@ }, "node_modules/needle/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -14343,31 +13697,8 @@ }, "node_modules/neo-async": { "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "!win32" - ], - "dependencies": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "node_modules/node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", "dev": true, - "optional": true + "license": "MIT" }, "node_modules/node-forge": { "version": "1.3.1", @@ -14379,9 +13710,9 @@ } }, "node_modules/node-gyp": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.0.tgz", - "integrity": "sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==", + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", + "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", "dev": true, "dependencies": { "env-paths": "^2.2.0", @@ -14399,19 +13730,7 @@ "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": "^12.22 || ^14.13 || >=16" - } - }, - "node_modules/node-gyp-build": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", - "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", - "dev": true, - "optional": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" + "node": "^12.13 || ^14.13 || >=16" } }, "node_modules/node-gyp/node_modules/glob": { @@ -14436,14 +13755,12 @@ }, "node_modules/node-int64": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.7", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.7.tgz", - "integrity": "sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==" + "license": "MIT" }, "node_modules/nopt": { "version": "6.0.0", @@ -14475,31 +13792,17 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/normalize-package-data/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -14538,18 +13841,18 @@ } }, "node_modules/npm-package-arg": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", - "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", "dev": true, "dependencies": { - "hosted-git-info": "^5.0.0", - "proc-log": "^2.0.1", + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^4.0.0" + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/npm-packlist": { @@ -14579,54 +13882,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-pick-manifest/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-registry-fetch": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.3.tgz", @@ -14645,18 +13900,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { "version": "11.0.2", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.0.2.tgz", @@ -14674,86 +13917,37 @@ "minipass-collect": "^1.0.2", "minipass-fetch": "^3.0.0", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", - "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", - "dev": true, - "dependencies": { - "minipass": "^4.0.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm-registry-fetch/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm-registry-fetch/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm-registry-fetch/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.1.tgz", + "integrity": "sha512-t9/wowtf7DYkwz8cfMSt0rMwiyNIBXf5CKZ3S5ZMqRqMYT0oLTp0x1WorMI9WTwvaPg21r1JbFxJMum8JrLGfw==", "dev": true, "dependencies": { - "builtins": "^5.0.0" + "minipass": "^4.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" } }, "node_modules/npm-run-path": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -14778,9 +13972,8 @@ }, "node_modules/nth-check": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "boolbase": "^1.0.0" }, @@ -14790,18 +13983,16 @@ }, "node_modules/object-inspect": { "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-is": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -14815,18 +14006,16 @@ }, "node_modules/object-keys": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/object.assign": { "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -14842,9 +14031,8 @@ }, "node_modules/object.values": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -14865,8 +14053,7 @@ }, "node_modules/ol": { "version": "7.2.2", - "resolved": "https://registry.npmjs.org/ol/-/ol-7.2.2.tgz", - "integrity": "sha512-eqJ1hhVQQ3Ap4OhYq9DRu5pz9RMpLhmoTauDoIqpn7logVi1AJE+lXjEHrPrTSuZYjtFbMgqr07sxoLNR65nrw==", + "license": "BSD-2-Clause", "dependencies": { "earcut": "^2.2.3", "geotiff": "^2.0.7", @@ -14881,8 +14068,7 @@ }, "node_modules/ol-mapbox-style": { "version": "9.2.4", - "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-9.2.4.tgz", - "integrity": "sha512-Q+G1YvYcC2XSZm9UcrSkW4hxe1K3YFTKBM7FmGhsfXaqty1wRTbsDCLUx7RBAC08RPIaPl0IkHs6SRdJx3BwsQ==", + "license": "BSD-2-Clause", "dependencies": { "@mapbox/mapbox-gl-style-spec": "^13.23.1", "mapbox-to-css-font": "^2.4.1" @@ -14911,17 +14097,15 @@ }, "node_modules/once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -14934,9 +14118,8 @@ }, "node_modules/open": { "version": "8.4.0", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", - "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", "dev": true, + "license": "MIT", "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -14951,9 +14134,8 @@ }, "node_modules/optionator": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -14968,9 +14150,8 @@ }, "node_modules/ora": { "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -14991,9 +14172,8 @@ }, "node_modules/ora/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -15006,9 +14186,8 @@ }, "node_modules/ora/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -15022,9 +14201,8 @@ }, "node_modules/ora/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -15034,24 +14212,21 @@ }, "node_modules/ora/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ora/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ora/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -15061,24 +14236,21 @@ }, "node_modules/os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/ospath": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -15091,9 +14263,8 @@ }, "node_modules/p-locate": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -15103,9 +14274,8 @@ }, "node_modules/p-locate/node_modules/p-limit": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -15118,9 +14288,8 @@ }, "node_modules/p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -15155,17 +14324,16 @@ }, "node_modules/p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/pacote": { - "version": "15.0.6", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.6.tgz", - "integrity": "sha512-dQwcz/sME7QIL+cdrw/jftQfMMXxSo17i2kJ/gnhBhUvvBAsxoBu1lw9B5IzCH/Ce8CvEkG/QYZ6txzKfn0bTw==", + "version": "15.0.8", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.0.8.tgz", + "integrity": "sha512-UlcumB/XS6xyyIMwg/WwMAyUmga+RivB5KgkRwA1hZNtrx+0Bt41KxHCvg1kr0pZ/ZeD8qjhW4fph6VaYRCbLw==", "dev": true, "dependencies": { "@npmcli/git": "^4.0.0", @@ -15173,8 +14341,8 @@ "@npmcli/promise-spawn": "^6.0.1", "@npmcli/run-script": "^6.0.0", "cacache": "^17.0.0", - "fs-minipass": "^2.1.0", - "minipass": "^3.1.6", + "fs-minipass": "^3.0.0", + "minipass": "^4.0.0", "npm-package-arg": "^10.0.0", "npm-packlist": "^7.0.0", "npm-pick-manifest": "^8.0.0", @@ -15193,58 +14361,9 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pacote/node_modules/hosted-git-info": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", - "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", - "dev": true, - "dependencies": { - "lru-cache": "^7.5.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/npm-package-arg": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", - "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/proc-log": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/pacote/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dev": true, - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/pako": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", - "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==" + "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", @@ -15260,14 +14379,12 @@ }, "node_modules/parse-headers": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", - "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + "license": "MIT" }, "node_modules/parse-json": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -15283,9 +14400,8 @@ }, "node_modules/parse-node-version": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -15305,9 +14421,8 @@ }, "node_modules/parse5-html-rewriting-stream": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", - "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1", "parse5-sax-parser": "^6.0.1" @@ -15315,39 +14430,34 @@ }, "node_modules/parse5-html-rewriting-stream/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5-htmlparser2-tree-adapter": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1" } }, "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5-sax-parser": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", - "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", "dev": true, + "license": "MIT", "dependencies": { "parse5": "^6.0.1" } }, "node_modules/parse5-sax-parser/node_modules/parse5": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/parse5/node_modules/entities": { "version": "4.4.0", @@ -15373,36 +14483,32 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -15412,17 +14518,15 @@ }, "node_modules/path-type": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pbf": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -15433,25 +14537,21 @@ }, "node_modules/pend": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/picocolors": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -15461,27 +14561,24 @@ }, "node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/pirates": { "version": "4.0.5", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", - "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } }, "node_modules/piscina": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", - "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", "dev": true, + "license": "MIT", "dependencies": { "eventemitter-asyncresource": "^1.0.0", "hdr-histogram-js": "^2.0.1", @@ -15493,9 +14590,8 @@ }, "node_modules/pixelmatch": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz", - "integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==", "dev": true, + "license": "ISC", "dependencies": { "pngjs": "^6.0.0" }, @@ -15505,18 +14601,16 @@ }, "node_modules/pixelmatch/node_modules/pngjs": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", - "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.13.0" } }, "node_modules/pkg-dir": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -15526,26 +14620,24 @@ }, "node_modules/pluralize": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/pngjs": { "version": "3.4.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", - "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", + "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", "dev": true, "funding": [ { @@ -15567,14 +14659,14 @@ } }, "node_modules/postcss-loader": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", - "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz", + "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==", "dev": true, "dependencies": { "cosmiconfig": "^7.0.0", "klona": "^2.0.5", - "semver": "^7.3.7" + "semver": "^7.3.8" }, "engines": { "node": ">= 14.15.0" @@ -15590,9 +14682,8 @@ }, "node_modules/postcss-modules-extract-imports": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "dev": true, + "license": "ISC", "engines": { "node": "^10 || ^12 || >= 14" }, @@ -15602,9 +14693,8 @@ }, "node_modules/postcss-modules-local-by-default": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", "dev": true, + "license": "MIT", "dependencies": { "icss-utils": "^5.0.0", "postcss-selector-parser": "^6.0.2", @@ -15619,9 +14709,8 @@ }, "node_modules/postcss-modules-scope": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, + "license": "ISC", "dependencies": { "postcss-selector-parser": "^6.0.4" }, @@ -15634,9 +14723,8 @@ }, "node_modules/postcss-modules-values": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, + "license": "ISC", "dependencies": { "icss-utils": "^5.0.0" }, @@ -15649,9 +14737,8 @@ }, "node_modules/postcss-selector-parser": { "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz", - "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15662,24 +14749,21 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/pretty-bytes": { "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -15689,9 +14773,8 @@ }, "node_modules/pretty-format": { "version": "29.3.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.3.1.tgz", - "integrity": "sha512-FyLnmb1cYJV8biEIiRyzRFvs2lry7PPIvOqKVe1GCUEYg4YGmlx1qG9EJNMxArYm7piII4qb8UV1Pncq5dxmcg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.0.0", "ansi-styles": "^5.0.0", @@ -15703,9 +14786,8 @@ }, "node_modules/pretty-format/node_modules/ansi-styles": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -15714,12 +14796,12 @@ } }, "node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/process-nextick-args": { @@ -15749,9 +14831,8 @@ }, "node_modules/prompts": { "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -15762,8 +14843,7 @@ }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", - "integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==" + "license": "MIT" }, "node_modules/proxy-addr": { "version": "2.0.7", @@ -15789,28 +14869,24 @@ }, "node_modules/proxy-from-env": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", - "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", "dev": true, + "license": "MIT", "optional": true }, "node_modules/psl": { "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, + "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -15818,26 +14894,22 @@ }, "node_modules/punycode": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/qs": { "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.6" } }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, "funding": [ { @@ -15852,12 +14924,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/quick-lru": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.1.tgz", - "integrity": "sha512-S27GBT+F0NTRiehtbrgaSE1idUAJ5bX8dPAQTdylEyNlrdcH5X4Lz7Edz3DYzecbsCluD5zO8ZNEe04z3D3u6Q==", + "license": "MIT", "engines": { "node": ">=12" }, @@ -15867,14 +14939,12 @@ }, "node_modules/quickselect": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" + "license": "ISC" }, "node_modules/randombytes": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -15914,17 +14984,15 @@ }, "node_modules/rbush": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", + "license": "MIT", "dependencies": { "quickselect": "^2.0.0" } }, "node_modules/react-is": { "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/read-package-json": { "version": "6.0.0", @@ -15974,9 +15042,8 @@ }, "node_modules/read-pkg": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, + "license": "MIT", "dependencies": { "@types/normalize-package-data": "^2.4.0", "normalize-package-data": "^2.5.0", @@ -15989,9 +15056,8 @@ }, "node_modules/read-pkg-up": { "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.1.0", "read-pkg": "^5.2.0", @@ -16006,24 +15072,21 @@ }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "node_modules/read-pkg/node_modules/hosted-git-info": { "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/read-pkg/node_modules/normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", @@ -16033,27 +15096,24 @@ }, "node_modules/read-pkg/node_modules/semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver" } }, "node_modules/read-pkg/node_modules/type-fest": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=8" } }, "node_modules/readable-stream": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -16065,8 +15125,7 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -16076,20 +15135,17 @@ }, "node_modules/reflect-metadata": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + "license": "Apache-2.0" }, "node_modules/regenerate": { "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerate-unicode-properties": { "version": "10.1.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", - "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2" }, @@ -16099,39 +15155,34 @@ }, "node_modules/regenerator-runtime": { "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regenerator-transform": { "version": "0.15.1", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz", - "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.8.4" } }, "node_modules/regex-parser": { "version": "2.2.11", - "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", - "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regexp-tree": { "version": "0.1.24", - "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", - "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", "dev": true, + "license": "MIT", "bin": { "regexp-tree": "bin/regexp-tree" } }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", - "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", @@ -16146,9 +15197,8 @@ }, "node_modules/regexpp": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -16158,9 +15208,8 @@ }, "node_modules/regexpu-core": { "version": "5.2.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.2.tgz", - "integrity": "sha512-T0+1Zp2wjF/juXMrMxHxidqGYn8U4R+zleSJhX9tQ1PUsS8a9UtYfbsF9LdiVgNX3kiX8RNaKM42nfSgvFJjmw==", "dev": true, + "license": "MIT", "dependencies": { "regenerate": "^1.4.2", "regenerate-unicode-properties": "^10.1.0", @@ -16175,15 +15224,13 @@ }, "node_modules/regjsgen": { "version": "0.7.1", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", - "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/regjsparser": { "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "jsesc": "~0.5.0" }, @@ -16193,8 +15240,6 @@ }, "node_modules/regjsparser/node_modules/jsesc": { "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { "jsesc": "bin/jsesc" @@ -16202,35 +15247,31 @@ }, "node_modules/request-progress": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", "dev": true, + "license": "MIT", "dependencies": { "throttleit": "^1.0.0" } }, "node_modules/require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/require-from-string": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/requireindex": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.5" } @@ -16243,9 +15284,8 @@ }, "node_modules/resolve": { "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.9.0", "path-parse": "^1.0.7", @@ -16260,9 +15300,8 @@ }, "node_modules/resolve-cwd": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -16272,26 +15311,23 @@ }, "node_modules/resolve-from": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/resolve-protobuf-schema": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz", - "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==", + "license": "MIT", "dependencies": { "protocol-buffers-schema": "^3.3.1" } }, "node_modules/resolve-url-loader": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", - "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", "dev": true, + "license": "MIT", "dependencies": { "adjust-sourcemap-loader": "^4.0.0", "convert-source-map": "^1.7.0", @@ -16305,9 +15341,8 @@ }, "node_modules/resolve-url-loader/node_modules/loader-utils": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", - "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", "dev": true, + "license": "MIT", "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", @@ -16319,27 +15354,24 @@ }, "node_modules/resolve-url-loader/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/resolve.exports": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", - "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } }, "node_modules/restore-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -16359,9 +15391,8 @@ }, "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -16369,15 +15400,13 @@ }, "node_modules/rfdc": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -16390,9 +15419,8 @@ }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16410,17 +15438,14 @@ }, "node_modules/run-async": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "funding": [ { @@ -16436,28 +15461,26 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/rw": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", - "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + "license": "BSD-3-Clause" }, "node_modules/rxjs": { "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } }, "node_modules/rxjs-report-usage": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/rxjs-report-usage/-/rxjs-report-usage-1.0.6.tgz", - "integrity": "sha512-omv1DIv5z1kV+zDAEjaDjWSkx8w5TbFp5NZoPwUipwzYVcor/4So9ZU3bUyQ1c8lxY5Q0Es/ztWW7PGjY7to0Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.10.3", "@babel/traverse": "^7.10.3", @@ -16473,9 +15496,8 @@ }, "node_modules/rxjs-report-usage/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16488,9 +15510,8 @@ }, "node_modules/rxjs-report-usage/node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16504,9 +15525,8 @@ }, "node_modules/rxjs-report-usage/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -16516,15 +15536,13 @@ }, "node_modules/rxjs-report-usage/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rxjs-report-usage/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -16542,18 +15560,16 @@ }, "node_modules/rxjs-report-usage/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/rxjs-report-usage/node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -16563,8 +15579,6 @@ }, "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": [ { @@ -16579,22 +15593,21 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safe-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-2.1.1.tgz", - "integrity": "sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==", "dev": true, + "license": "MIT", "dependencies": { "regexp-tree": "~0.1.1" } }, "node_modules/safe-regex-test": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", @@ -16606,9 +15619,8 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/safevalues": { "version": "0.3.4", @@ -16616,9 +15628,9 @@ "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, "node_modules/sass": { - "version": "1.56.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.56.1.tgz", - "integrity": "sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==", + "version": "1.57.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", + "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -16634,9 +15646,8 @@ }, "node_modules/sass-loader": { "version": "13.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", - "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", "dev": true, + "license": "MIT", "dependencies": { "klona": "^2.0.4", "neo-async": "^2.6.2" @@ -16672,16 +15683,14 @@ }, "node_modules/sax": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true, + "license": "ISC", "optional": true }, "node_modules/schema-utils": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", - "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.8.0", @@ -16716,8 +15725,7 @@ }, "node_modules/semver": { "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" }, @@ -16730,8 +15738,7 @@ }, "node_modules/semver/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==", + "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -16795,9 +15802,8 @@ }, "node_modules/serialize-javascript": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -16900,9 +15906,8 @@ }, "node_modules/shallow-clone": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "license": "MIT", "dependencies": { "kind-of": "^6.0.2" }, @@ -16912,9 +15917,8 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -16924,18 +15928,16 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/side-channel": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.0", "get-intrinsic": "^1.0.2", @@ -16947,30 +15949,26 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/sisteransi": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/slice-ansi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -16982,9 +15980,8 @@ }, "node_modules/slice-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -16997,9 +15994,8 @@ }, "node_modules/slice-ansi/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -17009,9 +16005,8 @@ }, "node_modules/slice-ansi/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/smart-buffer": { "version": "4.2.0", @@ -17025,8 +16020,7 @@ }, "node_modules/socket.io-client": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.4.tgz", - "integrity": "sha512-ZpKteoA06RzkD32IbqILZ+Cnst4xewU7ZYK12aS1mzHftFFjpoMz69IuhP/nL25pJfao/amoPI527KnuhFm01g==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", @@ -17039,8 +16033,7 @@ }, "node_modules/socket.io-parser": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", - "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "license": "MIT", "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -17090,24 +16083,18 @@ }, "node_modules/sort-asc": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz", - "integrity": "sha512-jBgdDd+rQ+HkZF2/OHCmace5dvpos/aWQpcxuyRs9QUbPRnkEJmYVo81PIGpjIdpOcsnJ4rGjStfDHsbn+UVyw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-desc": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz", - "integrity": "sha512-jfZacW5SKOP97BF5rX5kQfJmRVZP5/adDUTY8fCSPvNcXDVpUEe2pr/iKGlcyZzchRJZrswnp68fgk3qBXgkJw==", "engines": { "node": ">=0.10.0" } }, "node_modules/sort-object": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz", - "integrity": "sha512-aAQiEdqFTTdsvUFxXm3umdo04J7MRljoVGbBlkH7BgNsMvVNAJyGj7C/wV1A8wHWAJj/YikeZbfuCKqhggNWGA==", "dependencies": { "sort-asc": "^0.1.0", "sort-desc": "^0.1.1" @@ -17127,18 +16114,16 @@ }, "node_modules/source-map-js": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/source-map-loader": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz", - "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==", "dev": true, + "license": "MIT", "dependencies": { "abab": "^2.0.6", "iconv-lite": "^0.6.3", @@ -17157,9 +16142,8 @@ }, "node_modules/source-map-loader/node_modules/iconv-lite": { "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -17169,9 +16153,8 @@ }, "node_modules/source-map-support": { "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -17179,25 +16162,16 @@ }, "node_modules/source-map-support/node_modules/source-map": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead", - "dev": true - }, "node_modules/spdx-correct": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -17205,15 +16179,13 @@ }, "node_modules/spdx-exceptions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "dev": true, + "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, + "license": "MIT", "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -17221,9 +16193,8 @@ }, "node_modules/spdx-license-ids": { "version": "3.0.12", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", - "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", - "dev": true + "dev": true, + "license": "CC0-1.0" }, "node_modules/spdy": { "version": "4.0.2", @@ -17257,15 +16228,13 @@ }, "node_modules/sprintf-js": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sshpk": { "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, + "license": "MIT", "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -17298,23 +16267,10 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ssri/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/stack-utils": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -17324,9 +16280,8 @@ }, "node_modules/stack-utils/node_modules/escape-string-regexp": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -17342,18 +16297,16 @@ }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } }, "node_modules/string-length": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -17364,8 +16317,7 @@ }, "node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -17377,9 +16329,8 @@ }, "node_modules/string.prototype.trimend": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -17391,9 +16342,8 @@ }, "node_modules/string.prototype.trimstart": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.4", @@ -17405,8 +16355,7 @@ }, "node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -17416,27 +16365,24 @@ }, "node_modules/strip-bom": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/strip-final-newline": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-indent": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, + "license": "MIT", "dependencies": { "min-indent": "^1.0.0" }, @@ -17446,9 +16392,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -17458,8 +16403,7 @@ }, "node_modules/supports-color": { "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -17469,9 +16413,8 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -17481,18 +16424,16 @@ }, "node_modules/symbol-observable": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10" } }, "node_modules/tapable": { "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -17514,10 +16455,22 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/minipass": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.0.tgz", - "integrity": "sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==", + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -17527,9 +16480,9 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.2", @@ -17546,9 +16499,8 @@ }, "node_modules/terser-webpack-plugin": { "version": "5.3.6", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", - "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.14", "jest-worker": "^27.4.5", @@ -17580,9 +16532,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -17596,27 +16547,24 @@ }, "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/terser-webpack-plugin/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/terser-webpack-plugin/node_modules/jest-worker": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -17628,15 +16576,13 @@ }, "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -17652,9 +16598,8 @@ }, "node_modules/terser-webpack-plugin/node_modules/supports-color": { "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -17667,15 +16612,13 @@ }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -17687,9 +16630,8 @@ }, "node_modules/test-exclude/node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -17707,21 +16649,18 @@ }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/throttleit": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/thunky": { "version": "1.1.0", @@ -17731,9 +16670,8 @@ }, "node_modules/tmp": { "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", "dev": true, + "license": "MIT", "dependencies": { "rimraf": "^3.0.0" }, @@ -17743,22 +16681,19 @@ }, "node_modules/tmpl": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-fast-properties": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -17777,9 +16712,8 @@ }, "node_modules/tough-cookie": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -17790,23 +16724,22 @@ }, "node_modules/tree-kill": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -17842,9 +16775,8 @@ }, "node_modules/tsconfig-paths": { "version": "3.14.1", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", - "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", @@ -17866,23 +16798,20 @@ }, "node_modules/tsconfig-paths/node_modules/strip-bom": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/tslib": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", - "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -17895,9 +16824,8 @@ }, "node_modules/tsutils-etc": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/tsutils-etc/-/tsutils-etc-1.4.1.tgz", - "integrity": "sha512-6UPYgc7OXcIW5tFxlsZF3OVSBvDInl/BkS3Xsu64YITXk7WrnWTVByKWPCThFDBp5gl5IGHOzGMdQuDCE7OL4g==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs": "^17.0.0", "yargs": "^17.0.0" @@ -17913,15 +16841,13 @@ }, "node_modules/tsutils/node_modules/tslib": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "safe-buffer": "^5.0.1" }, @@ -17931,15 +16857,13 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "license": "Unlicense" }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -17949,18 +16873,16 @@ }, "node_modules/type-detect": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -17983,14 +16905,13 @@ }, "node_modules/typed-assert": { "version": "1.0.9", - "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", - "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18001,9 +16922,8 @@ }, "node_modules/uglify-js": { "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "dev": true, + "license": "BSD-2-Clause", "optional": true, "bin": { "uglifyjs": "bin/uglifyjs" @@ -18014,9 +16934,8 @@ }, "node_modules/unbox-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, + "license": "MIT", "dependencies": { "call-bind": "^1.0.2", "has-bigints": "^1.0.2", @@ -18029,18 +16948,16 @@ }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-match-property-ecmascript": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, + "license": "MIT", "dependencies": { "unicode-canonical-property-names-ecmascript": "^2.0.0", "unicode-property-aliases-ecmascript": "^2.0.0" @@ -18051,18 +16968,16 @@ }, "node_modules/unicode-match-property-value-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/unicode-property-aliases-ecmascript": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -18093,9 +17008,8 @@ }, "node_modules/universalify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -18111,17 +17025,14 @@ }, "node_modules/untildify": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/update-browserslist-db": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -18132,6 +17043,7 @@ "url": "https://tidelift.com/funding/github/npm/browserslist" } ], + "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -18145,18 +17057,16 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", @@ -18169,18 +17079,16 @@ }, "node_modules/uuid": { "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } }, "node_modules/v8-to-istanbul": { "version": "9.0.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz", - "integrity": "sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -18192,30 +17100,28 @@ }, "node_modules/validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, + "license": "Apache-2.0", "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "node_modules/validate-npm-package-name": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", - "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", "dev": true, "dependencies": { "builtins": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/validator": { "version": "13.7.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.7.0.tgz", - "integrity": "sha512-nYXQLCBkpJ8X6ltALua9dRrZDHVYxjJ1wgskNt1lH9fzGjs3tgojGSCBjmEPwkWS1y29+DrizMTW19Pr9uB2nw==", + "license": "MIT", "engines": { "node": ">= 0.10" } @@ -18231,12 +17137,11 @@ }, "node_modules/verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" ], + "license": "MIT", "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -18245,18 +17150,16 @@ }, "node_modules/walker": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/watchpack": { "version": "2.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", - "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", "dev": true, + "license": "MIT", "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" @@ -18276,23 +17179,20 @@ }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/web-worker": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", - "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + "license": "Apache-2.0" }, "node_modules/webpack": { "version": "5.75.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz", - "integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -18336,26 +17236,26 @@ } }, "node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.0.1.tgz", + "integrity": "sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==", "dev": true, "dependencies": { "colorette": "^2.0.10", - "memfs": "^3.4.3", + "memfs": "^3.4.12", "mime-types": "^2.1.31", "range-parser": "^1.2.1", "schema-utils": "^4.0.0" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "webpack": "^5.0.0" } }, "node_modules/webpack-dev-server": { @@ -18413,17 +17313,40 @@ } } }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", - "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.0.tgz", + "integrity": "sha512-kU62emKIdKVeEIOIKVegvqpXMSTAMLJozpHZaJNDYqBjzlSYXQGviYwN1osDLJ9av68qHd4a2oSjd7yD4pacig==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -18436,9 +17359,8 @@ }, "node_modules/webpack-merge": { "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", "dev": true, + "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", "wildcard": "^2.0.0" @@ -18449,18 +17371,16 @@ }, "node_modules/webpack-sources": { "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.13.0" } }, "node_modules/webpack-subresource-integrity": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", - "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", "dev": true, + "license": "MIT", "dependencies": { "typed-assert": "^1.0.8" }, @@ -18479,9 +17399,8 @@ }, "node_modules/webpack/node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -18495,18 +17414,16 @@ }, "node_modules/webpack/node_modules/ajv-keywords": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, + "license": "MIT", "peerDependencies": { "ajv": "^6.9.1" } }, "node_modules/webpack/node_modules/eslint-scope": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -18517,24 +17434,21 @@ }, "node_modules/webpack/node_modules/estraverse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, "node_modules/webpack/node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/webpack/node_modules/schema-utils": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, + "license": "MIT", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -18573,9 +17487,8 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -18588,9 +17501,8 @@ }, "node_modules/which-boxed-primitive": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", "dev": true, + "license": "MIT", "dependencies": { "is-bigint": "^1.0.1", "is-boolean-object": "^1.1.0", @@ -18604,9 +17516,8 @@ }, "node_modules/which-collection": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", "dev": true, + "license": "MIT", "dependencies": { "is-map": "^2.0.1", "is-set": "^2.0.1", @@ -18619,9 +17530,8 @@ }, "node_modules/which-typed-array": { "version": "1.1.9", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", - "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", @@ -18648,29 +17558,25 @@ }, "node_modules/wildcard": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/word-wrap": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wordwrap": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -18685,8 +17591,7 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -18699,8 +17604,7 @@ }, "node_modules/wrap-ansi/node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -18710,19 +17614,16 @@ }, "node_modules/wrap-ansi/node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "license": "MIT" }, "node_modules/wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -18733,8 +17634,7 @@ }, "node_modules/ws": { "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -18753,29 +17653,24 @@ }, "node_modules/xml-utils": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.3.0.tgz", - "integrity": "sha512-i4PIrX33Wd66dvwo4syicwlwmnr6wuvvn4f2ku9hA67C2Uk62Xubczuhct+Evnd12/DV71qKNeDdJwES8HX1RA==" + "license": "CC0-1.0" }, "node_modules/xmlhttprequest-ssl": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", "engines": { "node": ">=0.4.0" } }, "node_modules/y18n": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", @@ -18788,8 +17683,7 @@ }, "node_modules/yargs": { "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -18805,17 +17699,15 @@ }, "node_modules/yargs-parser": { "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", "engines": { "node": ">=12" } }, "node_modules/yauzl": { "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", "dev": true, + "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" @@ -18823,9 +17715,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -18835,8 +17726,7 @@ }, "node_modules/zone.js": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.12.0.tgz", - "integrity": "sha512-XtC+I5dXU14HrzidAKBNMqneIVUykLEAA1x+v4KVrd6AUPWlwYORF8KgsVqvgdHiKZ4BkxxjvYi/ksEixTPR0Q==", + "license": "MIT", "peer": true, "dependencies": { "tslib": "^2.3.0" diff --git a/frontend/package.json b/frontend/package.json index f9ec1bfe1..4907091ed 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,24 +24,24 @@ "npm": ">=8" }, "dependencies": { - "@angular/animations": "~15.0.4", - "@angular/common": "~15.0.4", - "@angular/compiler": "~15.0.4", - "@angular/core": "~15.0.4", - "@angular/forms": "~15.0.4", - "@angular/material": "^15.0.3", - "@angular/platform-browser": "~15.0.4", - "@angular/platform-browser-dynamic": "~15.0.4", - "@angular/router": "~15.0.4", - "@ng-bootstrap/ng-bootstrap": "^14.0.0", + "@angular/animations": "~15.1.0", + "@angular/common": "~15.1.0", + "@angular/compiler": "~15.1.0", + "@angular/core": "~15.1.0", + "@angular/forms": "~15.1.0", + "@angular/material": "^15.1.0", + "@angular/platform-browser": "~15.1.0", + "@angular/platform-browser-dynamic": "~15.1.0", + "@angular/router": "~15.1.0", + "@ng-bootstrap/ng-bootstrap": "^14.0.1", "@ngrx/store": "^15.1.0", "bootstrap": "^5.2.3", - "bootstrap-icons": "^1.10.2", - "chart.js": "^4.1.1", + "bootstrap-icons": "^1.10.3", + "chart.js": "^4.1.2", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "digital-fuesim-manv-shared": "file:../shared", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "4.17.21", "ol": "^7.2.2", "rxjs": "~7.8.0", @@ -49,31 +49,31 @@ "tslib": "^2.4.1" }, "devDependencies": { - "@angular-devkit/build-angular": "^15.0.4", + "@angular-devkit/build-angular": "^15.1.1", "@angular-eslint/builder": "15.1.0", "@angular-eslint/eslint-plugin": "15.1.0", "@angular-eslint/eslint-plugin-template": "15.1.0", "@angular-eslint/schematics": "15.1.0", "@angular-eslint/template-parser": "15.1.0", - "@angular/cli": "~15.0.4", - "@angular/compiler-cli": "~15.0.4", + "@angular/cli": "~15.1.1", + "@angular/compiler-cli": "~15.1.0", "@types/chart.js": "^2.9.37", - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", - "@types/node": "^18", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", + "@types/node": "^16", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", "cypress": "^9.5.3", "cypress-image-diff-js": "^1.21.1", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-rxjs": "^5.0.2", "eslint-plugin-rxjs-angular": "^2.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", "lodash": "^4.17.21", - "ts-jest": "^29.0.3", - "typescript": "~4.8.2" + "ts-jest": "^29.0.5", + "typescript": "~4.9.4" } } diff --git a/frontend/src/app/shared/validation/custom-validation-errors.ts b/frontend/src/app/shared/validation/custom-validation-errors.ts index 623631b5f..91a7d0762 100644 --- a/frontend/src/app/shared/validation/custom-validation-errors.ts +++ b/frontend/src/app/shared/validation/custom-validation-errors.ts @@ -15,7 +15,7 @@ export type CustomValidationErrors = Partial< > >; -type CustomValidator = typeof CustomValidators[keyof typeof CustomValidators]; +type CustomValidator = (typeof CustomValidators)[keyof typeof CustomValidators]; type CustomValidatorFn = ReturnType; type CustomValidationError = ReturnType extends Promise ? Awaited> diff --git a/package-lock.json b/package-lock.json index 9f3970771..22516552f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", - "prettier": "^2.8.1" + "prettier": "^2.8.3" }, "engines": { "node": ">=16", @@ -1532,9 +1532,9 @@ } }, "node_modules/prettier": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.1.tgz", - "integrity": "sha512-lqGoSJBQNJidqCHE80vqZJHWHRFoNYsSpP9AjFhlhi9ODCJA541svILes/+/1GM3VaL/abZi7cpFzOpdR9UPKg==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz", + "integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==", "dev": true, "bin": { "prettier": "bin-prettier.js" diff --git a/package.json b/package.json index cabfecfec..edd68ae4c 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,6 @@ "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", - "prettier": "^2.8.1" + "prettier": "^2.8.3" } } diff --git a/shared/package-lock.json b/shared/package-lock.json index 74904aa2d..6e3253ab5 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -18,22 +18,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "engines": { "node": ">=16", @@ -701,9 +701,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", - "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -1347,9 +1347,9 @@ } }, "node_modules/@types/jest": { - "version": "29.2.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.4.tgz", - "integrity": "sha512-PipFB04k2qTRPePduVLTRiPzQfvMeLwUN3Z21hsAKaB/W9IIzgB2pizCL466ftJlcyZqnHoC9ZHpxLGl3fS86A==", + "version": "29.2.5", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.5.tgz", + "integrity": "sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==", "dev": true, "dependencies": { "expect": "^29.0.0", @@ -1446,14 +1446,14 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.47.0.tgz", - "integrity": "sha512-AHZtlXAMGkDmyLuLZsRpH3p4G/1iARIwc/T0vIem2YB+xW6pZaXYXzCBnZSF/5fdM97R9QqZWZ+h3iW10XgevQ==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", + "integrity": "sha512-9nY5K1Rp2ppmpb9s9S2aBiF3xo5uExCehMDmYmmFqqyxgenbHJ3qbarcLt4ITgaD6r/2ypdlcFRdcuVPnks+fQ==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/type-utils": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/type-utils": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", @@ -1479,13 +1479,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1496,9 +1496,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1509,13 +1509,13 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1536,16 +1536,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1562,12 +1562,12 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1598,14 +1598,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.47.0.tgz", - "integrity": "sha512-udPU4ckK+R1JWCGdQC4Qa27NtBg7w020ffHqGyAK8pAgOVuNw7YaKXGChk+udh+iiGIJf6/E/0xhVXyPAbsczw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.48.1.tgz", + "integrity": "sha512-4yg+FJR/V1M9Xoq56SF9Iygqm+r5LMXvheo6DQ7/yUWynQ4YfCRnsKuRgqH4EQ5Ya76rVwlEpw4Xu+TgWQUcdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "debug": "^4.3.4" }, "engines": { @@ -1625,13 +1625,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1642,9 +1642,9 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1655,13 +1655,13 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1682,12 +1682,12 @@ } }, "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1716,13 +1716,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.47.0.tgz", - "integrity": "sha512-1J+DFFrYoDUXQE1b7QjrNGARZE6uVhBqIvdaXTe5IN+NmEyD68qXR1qX1g2u4voA+nCaelQyG8w30SAOihhEYg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.48.1.tgz", + "integrity": "sha512-Hyr8HU8Alcuva1ppmqSYtM/Gp0q4JOp1F+/JH5D1IZm/bUBrV0edoewQZiEc1r6I8L4JL21broddxK8HAcZiqQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.47.0", - "@typescript-eslint/utils": "5.47.0", + "@typescript-eslint/typescript-estree": "5.48.1", + "@typescript-eslint/utils": "5.48.1", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -1743,13 +1743,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.47.0.tgz", - "integrity": "sha512-dvJab4bFf7JVvjPuh3sfBUWsiD73aiftKBpWSfi3sUkysDQ4W8x+ZcFpNp7Kgv0weldhpmMOZBjx1wKN8uWvAw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.48.1.tgz", + "integrity": "sha512-S035ueRrbxRMKvSTv9vJKIWgr86BD8s3RqoRZmsSh/s8HhIs90g6UlK8ZabUSjUZQkhVxt7nmZ63VJ9dcZhtDQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0" + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1760,9 +1760,9 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.47.0.tgz", - "integrity": "sha512-eslFG0Qy8wpGzDdYKu58CEr3WLkjwC5Usa6XbuV89ce/yN5RITLe1O8e+WFEuxnfftHiJImkkOBADj58ahRxSg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.48.1.tgz", + "integrity": "sha512-xHyDLU6MSuEEdIlzrrAerCGS3T7AA/L8Hggd0RCYBi0w3JMvGYxlLlXHeg50JI9Tfg5MrtsfuNxbS/3zF1/ATg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1773,13 +1773,13 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.47.0.tgz", - "integrity": "sha512-LxfKCG4bsRGq60Sqqu+34QT5qT2TEAHvSCCJ321uBWywgE2dS0LKcu5u+3sMGo+Vy9UmLOhdTw5JHzePV/1y4Q==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.48.1.tgz", + "integrity": "sha512-Hut+Osk5FYr+sgFh8J/FHjqX6HFcDzTlWLrFqGoK5kVUN3VBHF/QzZmAsIXCQ8T/W9nQNBTqalxi1P3LSqWnRA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/visitor-keys": "5.47.0", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/visitor-keys": "5.48.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -1800,16 +1800,16 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.47.0.tgz", - "integrity": "sha512-U9xcc0N7xINrCdGVPwABjbAKqx4GK67xuMV87toI+HUqgXj26m6RBp9UshEXcTrgCkdGYFzgKLt8kxu49RilDw==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.48.1.tgz", + "integrity": "sha512-SmQuSrCGUOdmGMwivW14Z0Lj8dxG1mOFZ7soeJ0TQZEJcs3n5Ndgkg0A4bcMFzBELqLJ6GTHnEU+iIoaD6hFGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.47.0", - "@typescript-eslint/types": "5.47.0", - "@typescript-eslint/typescript-estree": "5.47.0", + "@typescript-eslint/scope-manager": "5.48.1", + "@typescript-eslint/types": "5.48.1", + "@typescript-eslint/typescript-estree": "5.48.1", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0", "semver": "^7.3.7" @@ -1826,12 +1826,12 @@ } }, "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.47.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.47.0.tgz", - "integrity": "sha512-ByPi5iMa6QqDXe/GmT/hR6MZtVPi0SqMQPDx15FczCBXJo/7M8T88xReOALAfpBLm+zxpPfmhuEvPb577JRAEg==", + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.48.1.tgz", + "integrity": "sha512-Ns0XBwmfuX7ZknznfXozgnydyR8F6ev/KEGePP4i74uL3ArsKbEhJ7raeKr1JSa997DBDwol/4a0Y+At82c9dA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.47.0", + "@typescript-eslint/types": "5.48.1", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -2093,6 +2093,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/babel-jest": { "version": "29.3.1", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.3.1.tgz", @@ -2707,12 +2725,12 @@ } }, "node_modules/eslint": { - "version": "8.30.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", - "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", + "version": "8.31.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.31.0.tgz", + "integrity": "sha512-0tQQEVdmPZ1UtUKXjX7EMm9BlgJ08G90IhWh0PKDCb3ZLsgAOHI8fYSIzYVZej92zsgq+ft0FGsxhJ3xo2tbuA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.4.0", + "@eslint/eslintrc": "^1.4.1", "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -2763,9 +2781,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", - "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.6.0.tgz", + "integrity": "sha512-bAF0eLpLVqP5oEVUFKpMA+NnRFICwn9X8B5jrR9FcqnYBuPbqWEjTEspPWMj5ye6czoSLDweCzSo3Ko7gGrZaA==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -2775,13 +2793,14 @@ } }, "node_modules/eslint-import-resolver-node": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", - "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", "dev": true, "dependencies": { "debug": "^3.2.7", - "resolve": "^1.20.0" + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" } }, "node_modules/eslint-import-resolver-node/node_modules/debug": { @@ -2820,23 +2839,25 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "version": "2.27.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.4.tgz", + "integrity": "sha512-Z1jVt1EGKia1X9CnBCkpAOhWy8FgQ7OmJ/IblEkT82yrFU/xJaxwujaTzLWqigewwynRQ9mmHfX9MtAfhxm0sA==", "dev": true, "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.0", + "debug": "^3.2.7", "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", "has": "^1.0.3", - "is-core-module": "^2.8.1", + "is-core-module": "^2.11.0", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", "tsconfig-paths": "^3.14.1" }, "engines": { @@ -2847,12 +2868,12 @@ } }, "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "node_modules/eslint-plugin-import/node_modules/doctrine": { @@ -2867,11 +2888,14 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/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/eslint-plugin-import/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } }, "node_modules/eslint-plugin-total-functions": { "version": "6.0.0", @@ -3567,9 +3591,9 @@ } }, "node_modules/immer": { - "version": "9.0.16", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.16.tgz", - "integrity": "sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==", + "version": "9.0.17", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.17.tgz", + "integrity": "sha512-+hBruaLSQvkPfxRiTLK/mi4vLH+/VQS6z2KJahdoxlleFOI8ARqzOF17uy12eFDlqWmPoygwc5evgwcp+dlHhg==", "funding": { "type": "opencollective", "url": "https://opencollective.com/immer" @@ -5245,9 +5269,9 @@ } }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.2.0.tgz", + "integrity": "sha512-LN6QV1IJ9ZhxWTNdktaPClrNfp8xdSAYS0Zk2ddX7XsXZAxckMHPCBcHRo0cTcEIgYPRiGEkmji3Idkh2yFtYw==", "dev": true, "engines": { "node": ">=6" @@ -5937,15 +5961,15 @@ } }, "node_modules/ts-jest": { - "version": "29.0.3", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.3.tgz", - "integrity": "sha512-Ibygvmuyq1qp/z3yTh9QTwVVAbFdDy/+4BtIQR2sp6baF2SJU/8CKK/hhnGIDY2L90Az2jIqTwZPnN2p+BweiQ==", + "version": "29.0.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.0.5.tgz", + "integrity": "sha512-PL3UciSgIpQ7f6XjVOmbi96vmDHUqAyqDr8YxzopDqX3kfgYtX1cuNeBjP+L9sFXi6nzsGGA6R3fP3DDDJyrxA==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", "jest-util": "^29.0.0", - "json5": "^2.2.1", + "json5": "^2.2.3", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", @@ -6110,9 +6134,9 @@ } }, "node_modules/typescript": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", - "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "version": "4.9.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", + "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", "dev": true, "bin": { "tsc": "bin/tsc", diff --git a/shared/package.json b/shared/package.json index d8a9eb57d..b4cd1627b 100644 --- a/shared/package.json +++ b/shared/package.json @@ -27,7 +27,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "immer": "^9.0.16", + "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", "rbush-knn": "github:mourner/rbush-knn", @@ -35,22 +35,22 @@ "uuid": "^9.0.0" }, "devDependencies": { - "@types/jest": "^29.2.4", + "@types/jest": "^29.2.5", "@types/lodash-es": "^4.17.6", "@types/rbush": "^3.0.0", "@types/uuid": "^9.0.0", "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.47.0", - "@typescript-eslint/parser": "5.47.0", - "eslint": "^8.30.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "~2.26.0", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", "eslint-plugin-total-functions": "6.0.0", "eslint-plugin-unicorn": "^45.0.2", "jest": "^29.3.1", - "ts-jest": "^29.0.3", + "ts-jest": "^29.0.5", "ts-node": "^10.9.1", - "typescript": "~4.8.2" + "typescript": "~4.9.4" }, "exports": { ".": { diff --git a/shared/src/models/utils/patient-status-code.ts b/shared/src/models/utils/patient-status-code.ts index 02e7b220c..618d609e0 100644 --- a/shared/src/models/utils/patient-status-code.ts +++ b/shared/src/models/utils/patient-status-code.ts @@ -27,14 +27,9 @@ export const colorCodeMap = { X: 'green', Y: 'yellow', Z: 'red', -} as const; +} as const satisfies { readonly [Key in ColorCode]: string }; -// TODO [typescript@>=4.9]: Use satisfies https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator -// This is only for typesafety -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const _colorCodeMap: { readonly [key in ColorCode]: string } = colorCodeMap; - -export const behaviourCodeMap: { [key in BehaviourCode]: string } = { +export const behaviourCodeMap: { [Key in BehaviourCode]: string } = { A: 'bi-arrow-right-square-fill', B: 'bi-heartbreak-fill', C: 'bi-exclamation-circle-fill', diff --git a/shared/src/store/action-reducers/action-reducers.ts b/shared/src/store/action-reducers/action-reducers.ts index 9ba15932c..18034b308 100644 --- a/shared/src/store/action-reducers/action-reducers.ts +++ b/shared/src/store/action-reducers/action-reducers.ts @@ -35,7 +35,8 @@ const actionReducers = { ...EmergencyOperationCenterActionReducers, }; -type ExerciseActionReducer = typeof actionReducers[keyof typeof actionReducers]; +type ExerciseActionReducer = + (typeof actionReducers)[keyof typeof actionReducers]; type ExerciseActionTypeDictionary = { [_ActionReducer in ExerciseActionReducer as InstanceType< From 5822225599fde532da61d5222de5b6c681cc9c44 Mon Sep 17 00:00:00 2001 From: Lukas Hagen <43916057+Greenscreen23@users.noreply.github.com> Date: Wed, 18 Jan 2023 10:59:46 +0100 Subject: [PATCH 06/58] Add simulated regions that can be placed on the map (#601) * Add simulated regions that can be placed on the map * Fix naming * Add migration * Fix linter error * Move simulated region to separate heading in trainer map editor * Turn isInSimulatedRegion into a stub method * Refactor ol-map-manager to reuse some features from viewport in simulatedRegion --- .../shared/core/drag-element.service.ts | 30 ++++ .../exercise-map/exercise-map.module.ts | 2 + .../delete-feature-manager.ts | 7 + .../simulated-region-feature-manager.ts | 163 ++++++++++++++++++ .../simulated-region-popup.component.html | 28 +++ .../simulated-region-popup.component.scss | 0 .../simulated-region-popup.component.ts | 43 +++++ .../exercise-map/utility/ol-map-manager.ts | 34 +++- ...viewport-modify.ts => rectangle-modify.ts} | 10 +- .../trainer-map-editor.component.html | 33 ++++ .../trainer-map-editor.component.ts | 5 + .../selectors/exercise.selectors.ts | 4 + .../application/selectors/shared.selectors.ts | 4 + frontend/src/assets/simulated-region.svg | 62 +++++++ shared/src/models/index.ts | 1 + shared/src/models/simulated-region.ts | 52 ++++++ .../15-add-simulated-regions.ts | 8 + .../state-migrations/migration-functions.ts | 2 + shared/src/state.ts | 7 +- .../store/action-reducers/action-reducers.ts | 2 + .../store/action-reducers/simulated-region.ts | 129 ++++++++++++++ .../action-reducers/utils/get-element.ts | 1 + 22 files changed, 615 insertions(+), 12 deletions(-) create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.html create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.scss create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts rename frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/{viewport-modify.ts => rectangle-modify.ts} (87%) create mode 100644 frontend/src/assets/simulated-region.svg create mode 100644 shared/src/models/simulated-region.ts create mode 100644 shared/src/state-migrations/15-add-simulated-regions.ts create mode 100644 shared/src/store/action-reducers/simulated-region.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts index 3582fe914..0b144d6c9 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts @@ -13,6 +13,7 @@ import { PatientTemplate, TransferPoint, Viewport, + SimulatedRegion, } from 'digital-fuesim-manv-shared'; import type OlMap from 'ol/Map'; import { ExerciseService } from 'src/app/core/exercise.service'; @@ -228,6 +229,29 @@ export class DragElementService { true ); break; + case 'simulatedRegion': { + // This ratio has been determined by trial and error + const height = SimulatedRegion.image.height / 23.5; + const width = height * SimulatedRegion.image.aspectRatio; + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Add simulated region', + simulatedRegion: SimulatedRegion.create( + { + x: position.x - width / 2, + y: position.y + height / 2, + }, + { + height, + width, + }, + 'Einsatzabschnitt ???' + ), + }, + true + ); + break; + } default: break; } @@ -260,6 +284,12 @@ type TransferTemplate = type: 'patient'; template: PatientCategory; } + | { + type: 'simulatedRegion'; + template: { + image: ImageProperties; + }; + } | { type: 'transferPoint'; template: { diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts index 64b114b16..d95b361d1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.module.ts @@ -14,6 +14,7 @@ import { ViewportPopupComponent } from './shared/viewport-popup/viewport-popup.c import { PersonnelPopupComponent } from './shared/personnel-popup/personnel-popup.component'; import { MaterialPopupComponent } from './shared/material-popup/material-popup.component'; import { CaterCapacityComponent } from './shared/cater-capacity/cater-capacity.component'; +import { SimulatedRegionPopupComponent } from './shared/simulated-region-popup/simulated-region-popup.component'; @NgModule({ declarations: [ @@ -27,6 +28,7 @@ import { CaterCapacityComponent } from './shared/cater-capacity/cater-capacity.c PersonnelPopupComponent, MaterialPopupComponent, CaterCapacityComponent, + SimulatedRegionPopupComponent, ], imports: [ CommonModule, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts index 79938177d..b8e423e8a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts @@ -105,6 +105,13 @@ export class DeleteFeatureManager implements FeatureManager> { }); return true; } + if (exerciseState.simulatedRegions[id]) { + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Remove simulated region', + simulatedRegionId: id, + }); + return true; + } return false; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts new file mode 100644 index 000000000..e8646e205 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -0,0 +1,163 @@ +import type { Store } from '@ngrx/store'; +import type { UUID } from 'digital-fuesim-manv-shared'; +import { Size, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import type { Feature, MapBrowserEvent } from 'ol'; +import type { Coordinate } from 'ol/coordinate'; +import type LineString from 'ol/geom/LineString'; +import type VectorLayer from 'ol/layer/Vector'; +import type OlMap from 'ol/Map'; +import type VectorSource from 'ol/source/Vector'; +import Stroke from 'ol/style/Stroke'; +import Style from 'ol/style/Style'; +import type { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import { SimulatedRegionPopupComponent } from '../shared/simulated-region-popup/simulated-region-popup.component'; +import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; +import type { FeatureManager } from '../utility/feature-manager'; +import { ModifyHelper } from '../utility/modify-helper'; +import { + createLineString, + ElementFeatureManager, + getCoordinateArray, +} from './element-feature-manager'; + +export function isInSimulatedRegion( + coordinate: Coordinate, + simulatedRegion: SimulatedRegion +): boolean { + return SimulatedRegion.isInSimulatedRegion(simulatedRegion, { + x: coordinate[0]!, + y: coordinate[1]!, + }); +} + +export class SimulatedRegionFeatureManager + extends ElementFeatureManager + implements FeatureManager> +{ + readonly type = 'simulatedRegions'; + + override unsupportedChangeProperties = new Set(['id'] as const); + + constructor( + olMap: OlMap, + layer: VectorLayer>, + private readonly exerciseService: ExerciseService, + private readonly store: Store + ) { + super( + olMap, + layer, + (targetPositions, simulatedRegion) => { + exerciseService.proposeAction({ + type: '[SimulatedRegion] Move simulated region', + simulatedRegionId: simulatedRegion.id, + targetPosition: targetPositions[0]!, + }); + }, + createLineString + ); + this.layer.setStyle(this.style); + } + private readonly modifyHelper = new ModifyHelper(); + + private readonly style = new Style({ + geometry(thisFeature) { + const modifyGeometry = thisFeature.get('modifyGeometry'); + return modifyGeometry + ? modifyGeometry.geometry + : thisFeature.getGeometry(); + }, + stroke: new Stroke({ + color: '#cccc00', + width: 2, + }), + }); + + override createFeature(element: SimulatedRegion): Feature { + const feature = super.createFeature(element); + this.modifyHelper.onModifyEnd(feature, (newPositions) => { + // Skip when not all coordinates are properly set. + if ( + !newPositions.every( + (position) => + Number.isFinite(position.x) && + Number.isFinite(position.y) + ) + ) { + const simulatedRegion = + this.getElementFromFeature(feature)!.value; + this.recreateFeature(simulatedRegion); + return; + } + const lineString = newPositions; + + // We expect the simulatedRegion LineString to have 4 points. + const topLeft = lineString[0]!; + const bottomRight = lineString[2]!; + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Resize simulated region', + simulatedRegionId: element.id, + targetPosition: topLeft, + newSize: Size.create( + bottomRight.x - topLeft.x, + topLeft.y - bottomRight.y + ), + }); + }); + return feature; + } + + override changeFeature( + oldElement: SimulatedRegion, + newElement: SimulatedRegion, + changedProperties: ReadonlySet, + elementFeature: Feature + ): void { + if ( + changedProperties.has('position') || + changedProperties.has('size') + ) { + const newFeature = this.getFeatureFromElement(newElement); + if (!newFeature) { + throw new TypeError('newFeature undefined'); + } + this.movementAnimator.animateFeatureMovement( + elementFeature, + getCoordinateArray(newElement) + ); + } + // If the style has updated, we need to redraw the feature + elementFeature.changed(); + } + + public override onFeatureClicked( + event: MapBrowserEvent, + feature: Feature + ): void { + super.onFeatureClicked(event, feature); + if (selectStateSnapshot(selectCurrentRole, this.store) !== 'trainer') { + return; + } + const zoom = this.olMap.getView().getZoom()!; + const margin = 10 / zoom; + + this.togglePopup$.next({ + component: SimulatedRegionPopupComponent, + context: { + simulatedRegionId: feature.getId() as UUID, + }, + // We want the popup to be centered on the mouse position + ...calculatePopupPositioning( + event.coordinate, + { + height: margin, + width: margin, + }, + this.olMap.getView().getCenter()! + ), + }); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.html b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.html new file mode 100644 index 000000000..bb1184ddd --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.html @@ -0,0 +1,28 @@ + +
+ Simulierter Bereich {{ simulatedRegion.name }} + +
+
+ +
+ + + +
+
+
+
diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.scss b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts new file mode 100644 index 000000000..25ac51351 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/simulated-region-popup/simulated-region-popup.component.ts @@ -0,0 +1,43 @@ +import type { OnInit } from '@angular/core'; +import { Component, EventEmitter, Output } from '@angular/core'; +import { Store } from '@ngrx/store'; +import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import type { Observable } from 'rxjs'; +import { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { createSelectSimulatedRegion } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; + +@Component({ + selector: 'app-simulated-region-popup', + templateUrl: './simulated-region-popup.component.html', + styleUrls: ['./simulated-region-popup.component.scss'], +}) +export class SimulatedRegionPopupComponent implements OnInit { + // These properties are only set after OnInit + public simulatedRegionId!: UUID; + + @Output() readonly closePopup = new EventEmitter(); + + public simulatedRegion$?: Observable; + public readonly currentRole$ = this.store.select(selectCurrentRole); + + constructor( + private readonly store: Store, + private readonly exerciseService: ExerciseService + ) {} + + ngOnInit() { + this.simulatedRegion$ = this.store.select( + createSelectSimulatedRegion(this.simulatedRegionId) + ); + } + + public renameSimulatedRegion(newName: string) { + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Rename simulatedRegion', + simulatedRegionId: this.simulatedRegionId, + newName, + }); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 7124a649c..269994170 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -36,6 +36,7 @@ import { selectVisibleMaterials, selectVisiblePatients, selectVisiblePersonnel, + selectVisibleSimulatedRegions, selectVisibleTransferPoints, selectVisibleVehicles, selectVisibleViewports, @@ -50,6 +51,7 @@ import { MapImageFeatureManager } from '../feature-managers/map-images-feature-m import { MaterialFeatureManager } from '../feature-managers/material-feature-manager'; import { PatientFeatureManager } from '../feature-managers/patient-feature-manager'; import { PersonnelFeatureManager } from '../feature-managers/personnel-feature-manager'; +import { SimulatedRegionFeatureManager } from '../feature-managers/simulated-region-feature-manager'; import { TransferLinesFeatureManager } from '../feature-managers/transfer-lines-feature-manager'; import { TransferPointFeatureManager } from '../feature-managers/transfer-point-feature-manager'; import { VehicleFeatureManager } from '../feature-managers/vehicle-feature-manager'; @@ -61,7 +63,7 @@ import type { FeatureManager } from './feature-manager'; import { ModifyHelper } from './modify-helper'; import type { OpenPopupOptions } from './popup-manager'; import { TranslateInteraction } from './translate-interaction'; -import { createViewportModify } from './viewport-modify'; +import { createRectangleModify } from './rectangle-modify'; /** * This class should run outside the Angular zone for performance reasons. @@ -127,6 +129,7 @@ export class OlMapManager { const personnelLayer = this.createElementLayer(); const materialLayer = this.createElementLayer(); const viewportLayer = this.createElementLayer(); + const simulatedRegionLayer = this.createElementLayer(); const mapImagesLayer = this.createElementLayer(10_000); const deleteFeatureLayer = this.createElementLayer(); this.popupOverlay = new Overlay({ @@ -145,6 +148,7 @@ export class OlMapManager { personnelLayer, materialLayer, viewportLayer, + simulatedRegionLayer, ]; // Interactions @@ -160,20 +164,28 @@ export class OlMapManager { : featureManager.isFeatureTranslatable(feature); }, }); - const viewportModify = createViewportModify(viewportLayer); + const viewportModify = createRectangleModify(viewportLayer); + const simulatedRegionModify = + createRectangleModify(simulatedRegionLayer); - const viewportTranslate = new TranslateInteraction({ - layers: [viewportLayer], + const rectangleTranslate = new TranslateInteraction({ + layers: [viewportLayer, simulatedRegionLayer], condition: (event) => primaryAction(event) && !shiftKeyOnly(event), hitTolerance: 10, }); ModifyHelper.registerModifyEvents(viewportModify); + ModifyHelper.registerModifyEvents(simulatedRegionModify); const alwaysInteractions = [translateInteraction]; const customInteractions = selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' - ? [...alwaysInteractions, viewportTranslate, viewportModify] + ? [ + ...alwaysInteractions, + rectangleTranslate, + viewportModify, + simulatedRegionModify, + ] : alwaysInteractions; this.olMap = new OlMap({ @@ -292,9 +304,19 @@ export class OlMapManager { this.store.select(selectVisibleViewports) ); + this.registerFeatureElementManager( + new SimulatedRegionFeatureManager( + this.olMap, + simulatedRegionLayer, + this.exerciseService, + this.store + ), + this.store.select(selectVisibleSimulatedRegions) + ); + this.registerPopupTriggers(translateInteraction); this.registerDropHandler(translateInteraction); - this.registerDropHandler(viewportTranslate); + this.registerDropHandler(rectangleTranslate); this.registerViewportRestriction(); // Register handlers that disable or enable certain interactions diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts similarity index 87% rename from frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts rename to frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts index 487b31638..bb52e552f 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/viewport-modify.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts @@ -15,14 +15,14 @@ const originCornerDict: { topRight: { originIndex: 3, cornerIndex: 1 }, }; -export function createViewportModify( - viewportLayer: VectorLayer> +export function createRectangleModify( + rectangleLayer: VectorLayer> ): Modify { - const defaultStyle = new Modify({ source: viewportLayer.getSource()! }) + const defaultStyle = new Modify({ source: rectangleLayer.getSource()! }) .getOverlay() .getStyleFunction(); return new Modify({ - source: viewportLayer.getSource()!, + source: rectangleLayer.getSource()!, condition: (event) => primaryAction(event) && shiftKeyOnly(event), deleteCondition: () => false, insertVertexCondition: () => false, @@ -60,7 +60,7 @@ export function createViewportModify( origin ); }); - // This renders the default LineString style. The function ignores all arguments. + // The OpenLayers typings are incorrect here. We have to provide a second argument, even though it is ignored return defaultStyle!(feature, 123); }, }); diff --git a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html index 4b89864a6..4d3699728 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.html @@ -87,6 +87,39 @@
Ansicht/Transferpunkt
+
  • +
    Simulierte Bereiche
    +
    +
    +
    + +
    +
    +
    + Simulierter Bereich +
    +
    +
    +
    +
  • Patienten diff --git a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts index e1258306f..6a74a0a67 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/trainer-map-editor/trainer-map-editor.component.ts @@ -6,6 +6,7 @@ import { colorCodeMap, TransferPoint, Viewport, + SimulatedRegion, } from 'digital-fuesim-manv-shared'; import type { AppState } from 'src/app/state/app.state'; import { @@ -54,6 +55,10 @@ export class TrainerMapEditorComponent { private readonly ngbModalService: NgbModal ) {} + public readonly simulatedRegionTemplate = { + image: SimulatedRegion.image, + }; + public readonly viewportTemplate = { image: Viewport.image, }; diff --git a/frontend/src/app/state/application/selectors/exercise.selectors.ts b/frontend/src/app/state/application/selectors/exercise.selectors.ts index 9b51fcfbf..0fb94a5a2 100644 --- a/frontend/src/app/state/application/selectors/exercise.selectors.ts +++ b/frontend/src/app/state/application/selectors/exercise.selectors.ts @@ -24,6 +24,7 @@ function selectPropertyFactory(key: Key) { // UUIDMap properties export const selectViewports = selectPropertyFactory('viewports'); +export const selectSimulatedRegion = selectPropertyFactory('simulatedRegions'); export const selectMapImages = selectPropertyFactory('mapImages'); export const selectPatients = selectPropertyFactory('patients'); export const selectVehicles = selectPropertyFactory('vehicles'); @@ -79,6 +80,9 @@ export const createSelectHospital = createSelectElementFromMapFactory(selectHospitals); export const createSelectViewport = createSelectElementFromMapFactory(selectViewports); +export const createSelectSimulatedRegion = createSelectElementFromMapFactory( + selectSimulatedRegion +); export const createSelectClient = createSelectElementFromMapFactory(selectClients); diff --git a/frontend/src/app/state/application/selectors/shared.selectors.ts b/frontend/src/app/state/application/selectors/shared.selectors.ts index f1afef26f..706764625 100644 --- a/frontend/src/app/state/application/selectors/shared.selectors.ts +++ b/frontend/src/app/state/application/selectors/shared.selectors.ts @@ -5,6 +5,7 @@ import type { Patient, Personnel, Position, + SimulatedRegion, TransferPoint, UUID, Vehicle, @@ -24,6 +25,7 @@ import { selectMaterials, selectPatients, selectPersonnel, + selectSimulatedRegion, selectTransferPoints, selectVehicles, selectViewports, @@ -116,6 +118,8 @@ export const selectVisibleMapImages = selectVisibleElementsFactory( ); export const selectVisibleTransferPoints = selectVisibleElementsFactory(selectTransferPoints); +export const selectVisibleSimulatedRegions = + selectVisibleElementsFactory(selectSimulatedRegion); export const selectVisibleCateringLines = createSelector( selectRestrictedViewport, diff --git a/frontend/src/assets/simulated-region.svg b/frontend/src/assets/simulated-region.svg new file mode 100644 index 000000000..75424729a --- /dev/null +++ b/frontend/src/assets/simulated-region.svg @@ -0,0 +1,62 @@ + + + + + + + + + + image/svg+xml + + + + + + + diff --git a/shared/src/models/index.ts b/shared/src/models/index.ts index 97b09a8e7..74aa9d853 100644 --- a/shared/src/models/index.ts +++ b/shared/src/models/index.ts @@ -15,3 +15,4 @@ export { Vehicle } from './vehicle'; export { VehicleTemplate } from './vehicle-template'; export { Viewport } from './viewport'; export { PatientCategory } from './patient-category'; +export { SimulatedRegion } from './simulated-region'; diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts new file mode 100644 index 000000000..6e3db79a4 --- /dev/null +++ b/shared/src/models/simulated-region.ts @@ -0,0 +1,52 @@ +import { Type } from 'class-transformer'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { getCreate, Position, Size } from './utils'; +import type { ImageProperties } from './utils'; + +export class SimulatedRegion { + @IsUUID(4, uuidValidationOptions) + public readonly id: UUID = uuid(); + + /** + * top-left position + */ + @ValidateNested() + @Type(() => Position) + public readonly position: Position; + + @ValidateNested() + @Type(() => Size) + public readonly size: Size; + + @IsString() + public readonly name: string; + + /** + * @param position top-left position + * @deprecated Use {@link create} instead + */ + constructor(position: Position, size: Size, name: string) { + this.position = position; + this.size = size; + this.name = name; + } + + static readonly create = getCreate(this); + + static image: ImageProperties = { + url: 'assets/simulated-region.svg', + height: 1800, + aspectRatio: 1600 / 900, + }; + + static isInSimulatedRegion( + region: SimulatedRegion, + position: Position + ): boolean { + // This class was copied from viewport.ts + // We will have to implement this logic differently + // later, for now, this is a stub method + return false; + } +} diff --git a/shared/src/state-migrations/15-add-simulated-regions.ts b/shared/src/state-migrations/15-add-simulated-regions.ts new file mode 100644 index 000000000..76a2e863b --- /dev/null +++ b/shared/src/state-migrations/15-add-simulated-regions.ts @@ -0,0 +1,8 @@ +import type { Migration } from './migration-functions'; + +export const addSimulatedRegions15: Migration = { + actions: null, + state: (state: any) => { + state.simulatedRegions = {}; + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index 1d0b4d568..f914113b9 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -3,6 +3,7 @@ import { addMapImageIsLocked11 } from './11-add-map-image-is-locked'; import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-images'; import { addMapImageZIndex13 } from './13-add-map-image-zindex'; import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; +import { addSimulatedRegions15 } from './15-add-simulated-regions'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -51,4 +52,5 @@ export const migrations: { 12: renameIncorrectPatientImages12, 13: addMapImageZIndex13, 14: addPersonnelAndMaterialToState14, + 15: addSimulatedRegions15, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index e5a036037..ab27ab0db 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -27,6 +27,7 @@ import { Patient, PatientCategory, Personnel, + SimulatedRegion, TransferPoint, Vehicle, VehicleTemplate, @@ -65,6 +66,10 @@ export class ExerciseState { public readonly currentStatus: ExerciseStatus = 'notStarted'; @IsIdMap(Viewport) public readonly viewports: { readonly [key: UUID]: Viewport } = {}; + @IsIdMap(SimulatedRegion) + public readonly simulatedRegions: { + readonly [key: UUID]: SimulatedRegion; + } = {}; @IsIdMap(Vehicle) public readonly vehicles: { readonly [key: UUID]: Vehicle } = {}; @IsIdMap(Personnel) @@ -143,5 +148,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 14; + static readonly currentStateVersion = 15; } diff --git a/shared/src/store/action-reducers/action-reducers.ts b/shared/src/store/action-reducers/action-reducers.ts index 18034b308..47d8c0739 100644 --- a/shared/src/store/action-reducers/action-reducers.ts +++ b/shared/src/store/action-reducers/action-reducers.ts @@ -13,6 +13,7 @@ import { TransferPointActionReducers } from './transfer-point'; import { VehicleActionReducers } from './vehicle'; import { ViewportActionReducers } from './viewport'; import { EmergencyOperationCenterActionReducers } from './emergency-operation-center'; +import { SimulatedRegionActionReducers } from './simulated-region'; /** * All action reducers of the exercise must be registered here @@ -33,6 +34,7 @@ const actionReducers = { ...TransferActionReducers, ...HospitalActionReducers, ...EmergencyOperationCenterActionReducers, + ...SimulatedRegionActionReducers, }; type ExerciseActionReducer = diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts new file mode 100644 index 000000000..390e0456e --- /dev/null +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -0,0 +1,129 @@ +import { Type } from 'class-transformer'; +import { IsString, IsUUID, ValidateNested } from 'class-validator'; +import { SimulatedRegion } from '../../models'; +import { Position, Size } from '../../models/utils'; +import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import type { Action, ActionReducer } from '../action-reducer'; +import { getElement } from './utils/get-element'; + +export class AddSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add simulated region' as const) + readonly type = '[SimulatedRegion] Add simulated region'; + @ValidateNested() + @Type(() => SimulatedRegion) + public simulatedRegion!: SimulatedRegion; +} + +export class RemoveSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Remove simulated region' as const) + public readonly type = '[SimulatedRegion] Remove simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; +} + +export class MoveSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Move simulated region' as const) + public readonly type = '[SimulatedRegion] Move simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + @ValidateNested() + @Type(() => Position) + public readonly targetPosition!: Position; +} + +export class ResizeSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Resize simulated region' as const) + public readonly type = '[SimulatedRegion] Resize simulated region'; + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + @ValidateNested() + @Type(() => Position) + public readonly targetPosition!: Position; + @ValidateNested() + @Type(() => Size) + public readonly newSize!: Size; +} + +export class RenameSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Rename simulatedRegion' as const) + public readonly type = '[SimulatedRegion] Rename simulatedRegion'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @IsString() + public readonly newName!: string; +} + +export namespace SimulatedRegionActionReducers { + export const addSimulatedRegion: ActionReducer = { + action: AddSimulatedRegionAction, + reducer: (draftState, { simulatedRegion }) => { + draftState.simulatedRegions[simulatedRegion.id] = + cloneDeepMutable(simulatedRegion); + return draftState; + }, + rights: 'trainer', + }; + + export const removeSimulatedRegion: ActionReducer = + { + action: RemoveSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId }) => { + getElement(draftState, 'simulatedRegions', simulatedRegionId); + delete draftState.simulatedRegions[simulatedRegionId]; + return draftState; + }, + rights: 'trainer', + }; + + export const moveSimulatedRegion: ActionReducer = + { + action: MoveSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, targetPosition }) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegions', + simulatedRegionId + ); + simulatedRegion.position = cloneDeepMutable(targetPosition); + return draftState; + }, + rights: 'trainer', + }; + + export const resizeSimulatedRegion: ActionReducer = + { + action: ResizeSimulatedRegionAction, + reducer: ( + draftState, + { simulatedRegionId, targetPosition, newSize } + ) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegions', + simulatedRegionId + ); + simulatedRegion.position = cloneDeepMutable(targetPosition); + simulatedRegion.size = cloneDeepMutable(newSize); + return draftState; + }, + rights: 'trainer', + }; + + export const renameSimulatedRegion: ActionReducer = + { + action: RenameSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, newName }) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegions', + simulatedRegionId + ); + simulatedRegion.name = newName; + return draftState; + }, + rights: 'trainer', + }; +} diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts index bda9e3776..721faa5dd 100644 --- a/shared/src/store/action-reducers/utils/get-element.ts +++ b/shared/src/store/action-reducers/utils/get-element.ts @@ -15,6 +15,7 @@ export function getElement< | 'materials' | 'patients' | 'personnel' + | 'simulatedRegions' | 'transferPoints' | 'vehicles' | 'viewports', From 227f0dcedc105ce2d31fe8cdd02a3ab9b0e55637 Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Wed, 18 Jan 2023 12:05:04 +0100 Subject: [PATCH 07/58] Ignore vs code config files (#606) * Rename VS Code configs to `.example` * Add new "Start all but database" task * Explain changes in readme --- .gitignore | 4 ++++ .vscode/{launch.json => launch.json.example} | 0 .vscode/{settings.json => settings.json.example} | 0 .vscode/{tasks.json => tasks.json.example} | 6 ++++++ README.md | 2 ++ 5 files changed, 12 insertions(+) rename .vscode/{launch.json => launch.json.example} (100%) rename .vscode/{settings.json => settings.json.example} (100%) rename .vscode/{tasks.json => tasks.json.example} (91%) diff --git a/.gitignore b/.gitignore index 930b28bed..61fd2d19f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,7 @@ shared/tsconfig.build.tsbuildinfo benchmark/data/* !benchmark/data/*.permanent.json + +.vscode/* +!.vscode/*.example +!.vscode/extensions.json diff --git a/.vscode/launch.json b/.vscode/launch.json.example similarity index 100% rename from .vscode/launch.json rename to .vscode/launch.json.example diff --git a/.vscode/settings.json b/.vscode/settings.json.example similarity index 100% rename from .vscode/settings.json rename to .vscode/settings.json.example diff --git a/.vscode/tasks.json b/.vscode/tasks.json.example similarity index 91% rename from .vscode/tasks.json rename to .vscode/tasks.json.example index 5fa17e1f7..3af102f51 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json.example @@ -17,6 +17,12 @@ "isBackground": true, "problemMatcher": [] }, + { + "label": "Start all but database", + "dependsOn": ["Start frontend", "Start backend", "Watch shared"], + "isBackground": true, + "problemMatcher": [] + }, { "label": "Run CI", "dependsOn": [ diff --git a/README.md b/README.md index 0a0ed7d98..5440f1270 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ This project is currently developed as a [bachelor project](https://hpi.de/en/st You can (optionally) use a database for the persistence of exercise data. Look at the [relevant section](./backend/README.md#database) in the backend README for further information. Note that to not use the database you have to edit an environment variable, see the [relevant section](./backend/README.md#without-a-database). 8. (Optional) We have a list of recommended [vscode](https://code.visualstudio.com/) extensions. We strongly recommend you to use them if you are developing. You can see them via [the `@recommended` filter in the extensions panel](https://code.visualstudio.com/docs/editor/extension-marketplace#_recommended-extensions). +9. (Optional) We have prepared default settings, tasks and debug configurations for VS Code. You can find them in `.vscode/*.example`. Crete a copy of those files removing the `.example` and adjust them to your needs. The files without `.example`-Extensions are untracked so your adjustments won't be committed automatically. ### Gotchas @@ -49,6 +50,7 @@ If you want the best developer experience, make sure to always install dependenc If you are using [vscode](https://code.visualstudio.com/), you can run the [task](https://code.visualstudio.com/docs/editor/tasks) `Start all` to start everything in one go. Note that this _tries_ to start the database using `docker compose`. In case this fails please start the database in another way (see [this section in the backend README](./backend/README.md#database)). +If you're not using a database anyway, you could use the task `Start all but database` instead. ### Option 2 From ca02ca4ea59d8358a5ab61b8e2de60082533d2b9 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Wed, 18 Jan 2023 15:50:04 +0000 Subject: [PATCH 08/58] Refactor viewport-modify to resize-rectangle-interaction (#604) * Instead of using some parts of the `Modify` interaction (side-effect in the style function) a new custom Interaction has been created. * Previously, one could switch between resizing and translating a viewport via pressing `Shift`. Instead, now one ***resizes*** if one drags an edge of the viewport (+ a bit around it), and ***translates*** if one drags any other part. This should enable touch users to resize viewports * The code should now be more readable and extendable * The unnecessary `viewportTranslateInteraction` has been removed * `feature.dispose()` now gets called when it gets deleted - this could have been a memory leak? --- .../element-feature-manager.ts | 1 + .../simulated-region-feature-manager.ts | 79 ++++----- .../viewport-feature-manager.ts | 65 ++++---- .../exercise-map/utility/modify-helper.ts | 115 ------------- .../exercise-map/utility/ol-map-manager.ts | 29 +--- .../exercise-map/utility/rectangle-modify.ts | 67 -------- .../utility/resize-rectangle-interaction.ts | 156 ++++++++++++++++++ 7 files changed, 225 insertions(+), 287 deletions(-) delete mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts delete mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts index 6d817ddfe..93c081916 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts @@ -123,6 +123,7 @@ export abstract class ElementFeatureManager< deleteFeature(element: Element, elementFeature: ElementFeature): void { this.layer.getSource()!.removeFeature(elementFeature); + elementFeature.dispose(); this.movementAnimator.stopMovementAnimation(elementFeature); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index e8646e205..acfa70e1d 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -1,8 +1,7 @@ import type { Store } from '@ngrx/store'; -import type { UUID } from 'digital-fuesim-manv-shared'; -import { Size, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import { Position, Size } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type { Coordinate } from 'ol/coordinate'; import type LineString from 'ol/geom/LineString'; import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; @@ -16,23 +15,13 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { SimulatedRegionPopupComponent } from '../shared/simulated-region-popup/simulated-region-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; -import { ModifyHelper } from '../utility/modify-helper'; +import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; import { createLineString, ElementFeatureManager, getCoordinateArray, } from './element-feature-manager'; -export function isInSimulatedRegion( - coordinate: Coordinate, - simulatedRegion: SimulatedRegion -): boolean { - return SimulatedRegion.isInSimulatedRegion(simulatedRegion, { - x: coordinate[0]!, - y: coordinate[1]!, - }); -} - export class SimulatedRegionFeatureManager extends ElementFeatureManager implements FeatureManager> @@ -61,15 +50,8 @@ export class SimulatedRegionFeatureManager ); this.layer.setStyle(this.style); } - private readonly modifyHelper = new ModifyHelper(); private readonly style = new Style({ - geometry(thisFeature) { - const modifyGeometry = thisFeature.get('modifyGeometry'); - return modifyGeometry - ? modifyGeometry.geometry - : thisFeature.getGeometry(); - }, stroke: new Stroke({ color: '#cccc00', width: 2, @@ -78,35 +60,28 @@ export class SimulatedRegionFeatureManager override createFeature(element: SimulatedRegion): Feature { const feature = super.createFeature(element); - this.modifyHelper.onModifyEnd(feature, (newPositions) => { - // Skip when not all coordinates are properly set. - if ( - !newPositions.every( - (position) => - Number.isFinite(position.x) && - Number.isFinite(position.y) - ) - ) { - const simulatedRegion = - this.getElementFromFeature(feature)!.value; - this.recreateFeature(simulatedRegion); - return; + ResizeRectangleInteraction.onResize( + feature, + ({ topLeftCoordinate, scale }) => { + const currentElement = this.getElementFromFeature(feature)! + .value as SimulatedRegion; + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Resize simulated region', + simulatedRegionId: element.id, + targetPosition: Position.create( + topLeftCoordinate[0]!, + topLeftCoordinate[1]! + ), + newSize: Size.create( + currentElement.size.width * scale.x, + currentElement.size.height * scale.y + ), + }, + true + ); } - const lineString = newPositions; - - // We expect the simulatedRegion LineString to have 4 points. - const topLeft = lineString[0]!; - const bottomRight = lineString[2]!; - this.exerciseService.proposeAction({ - type: '[SimulatedRegion] Resize simulated region', - simulatedRegionId: element.id, - targetPosition: topLeft, - newSize: Size.create( - bottomRight.x - topLeft.x, - topLeft.y - bottomRight.y - ), - }); - }); + ); return feature; } @@ -160,4 +135,10 @@ export class SimulatedRegionFeatureManager ), }); } + + public override isFeatureTranslatable( + feature: Feature + ): boolean { + return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 2179e0d90..5fa0b86d0 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -1,6 +1,6 @@ import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; -import { Size, Viewport } from 'digital-fuesim-manv-shared'; +import { Position, Size, Viewport } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { Coordinate } from 'ol/coordinate'; import type LineString from 'ol/geom/LineString'; @@ -16,7 +16,7 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ViewportPopupComponent } from '../shared/viewport-popup/viewport-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; -import { ModifyHelper } from '../utility/modify-helper'; +import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; import { createLineString, ElementFeatureManager, @@ -61,15 +61,8 @@ export class ViewportFeatureManager ); this.layer.setStyle(this.style); } - private readonly modifyHelper = new ModifyHelper(); private readonly style = new Style({ - geometry(thisFeature) { - const modifyGeometry = thisFeature.get('modifyGeometry'); - return modifyGeometry - ? modifyGeometry.geometry - : thisFeature.getGeometry(); - }, stroke: new Stroke({ color: '#fafaff', width: 2, @@ -78,34 +71,28 @@ export class ViewportFeatureManager override createFeature(element: Viewport): Feature { const feature = super.createFeature(element); - this.modifyHelper.onModifyEnd(feature, (newPositions) => { - // Skip when not all coordinates are properly set. - if ( - !newPositions.every( - (position) => - Number.isFinite(position.x) && - Number.isFinite(position.y) - ) - ) { - const viewport = this.getElementFromFeature(feature)!.value; - this.recreateFeature(viewport); - return; + ResizeRectangleInteraction.onResize( + feature, + ({ topLeftCoordinate, scale }) => { + const currentElement = this.getElementFromFeature(feature)! + .value as Viewport; + this.exerciseService.proposeAction( + { + type: '[Viewport] Resize viewport', + viewportId: element.id, + targetPosition: Position.create( + topLeftCoordinate[0]!, + topLeftCoordinate[1]! + ), + newSize: Size.create( + currentElement.size.width * scale.x, + currentElement.size.height * scale.y + ), + }, + true + ); } - const lineString = newPositions; - - // We expect the viewport LineString to have 4 points. - const topLeft = lineString[0]!; - const bottomRight = lineString[2]!; - this.exerciseService.proposeAction({ - type: '[Viewport] Resize viewport', - viewportId: element.id, - targetPosition: topLeft, - newSize: Size.create( - bottomRight.x - topLeft.x, - topLeft.y - bottomRight.y - ), - }); - }); + ); return feature; } @@ -159,4 +146,10 @@ export class ViewportFeatureManager ), }); } + + public override isFeatureTranslatable( + feature: Feature + ): boolean { + return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts deleted file mode 100644 index beeb5ccc2..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/modify-helper.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { calculateDistance, Position } from 'digital-fuesim-manv-shared'; -import type { Feature } from 'ol'; -import type { Coordinate } from 'ol/coordinate'; -import type { LineString } from 'ol/geom'; -import type { Modify } from 'ol/interaction'; - -function coordinateToPosition(coordinate: Coordinate): Position { - return Position.create(coordinate[0]!, coordinate[1]!); -} - -export type CornerName = 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topRight'; - -function getNearestCoordinateName( - referencePosition: Coordinate, - coordinates: { [name in CornerName]: Coordinate } -): CornerName { - if (Object.keys(coordinates).length === 0) { - throw new TypeError('Expected at least one coordinate'); - } - return Object.entries(coordinates) - .map( - ([name, coordinate]) => - [ - name, - calculateDistance( - coordinateToPosition(referencePosition), - coordinateToPosition(coordinate) - ), - ] as [CornerName, number] - ) - .sort( - ([, leftDistance], [, rightDistance]) => - leftDistance - rightDistance - ) - .map(([name]) => name)[0]!; -} - -export interface ModifyGeometry { - geometry: LineString; - modifyCorner: CornerName; -} - -/** - * Modifies (moves) a feature to a new position. - */ -export class ModifyHelper { - /** - * If a feature should make use of any of the helper functions in this class, - * it's layer should have a modifyInteraction that is registered via this method. - */ - public static registerModifyEvents( - modifyInteraction: Modify - ) { - // These event don't propagate to anything else by default. - // We therefore have to propagate them manually to the specific features. - modifyInteraction.on('modifystart', (event) => { - event.features.forEach((featureLike) => { - const feature = featureLike as Feature; - feature.dispatchEvent(event); - const featureGeometry = feature.getGeometry() as T; - const coordinates = featureGeometry.getCoordinates(); - // We need at least 4 coordinates - if (coordinates.length < 4) { - throw new Error( - `Got unexpected short coordinates array: ${coordinates}` - ); - } - const mousePosition = event.mapBrowserEvent.coordinate; - const corner = getNearestCoordinateName(mousePosition, { - topLeft: coordinates[0]!, - topRight: coordinates[1]!, - bottomRight: coordinates[2]!, - bottomLeft: coordinates[3]!, - }); - const modifyGeometry: ModifyGeometry = { - // We need to clone the geometry to be able to properly resize it - geometry: featureGeometry.clone(), - modifyCorner: corner, - }; - feature.set('modifyGeometry', modifyGeometry, true); - }); - }); - modifyInteraction.on('modifyend', (event) => { - event.features.forEach((featureLike) => { - const feature = featureLike as Feature; - feature.dispatchEvent(event); - const modifyGeometry = feature.get('modifyGeometry'); - if (modifyGeometry) { - feature.setGeometry(modifyGeometry.geometry); - feature.unset('modifyGeometry', true); - } - }); - }); - } - - public onModifyEnd( - feature: Feature, - callback: (newCoordinates: Position[]) => void - ) { - feature.addEventListener('modifyend', (event) => { - const modifyGeometry = feature.get( - 'modifyGeometry' - ) as ModifyGeometry; - // The end coordinates in the event are the mouse coordinates and not the feature coordinates. - const coordinates = modifyGeometry.geometry.getCoordinates(); - callback( - coordinates.map((coordinate) => - Position.create(coordinate[0]!, coordinate[1]!) - ) - ); - }); - } - - // TODO: add more functionality (highlighting, etc.) -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 269994170..2da070120 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -7,7 +7,6 @@ import type { } from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; import { Overlay, View } from 'ol'; -import { primaryAction, shiftKeyOnly } from 'ol/events/condition'; import type Geometry from 'ol/geom/Geometry'; import type LineString from 'ol/geom/LineString'; import type Point from 'ol/geom/Point'; @@ -60,10 +59,9 @@ import { ViewportFeatureManager, } from '../feature-managers/viewport-feature-manager'; import type { FeatureManager } from './feature-manager'; -import { ModifyHelper } from './modify-helper'; import type { OpenPopupOptions } from './popup-manager'; +import { ResizeRectangleInteraction } from './resize-rectangle-interaction'; import { TranslateInteraction } from './translate-interaction'; -import { createRectangleModify } from './rectangle-modify'; /** * This class should run outside the Angular zone for performance reasons. @@ -164,27 +162,19 @@ export class OlMapManager { : featureManager.isFeatureTranslatable(feature); }, }); - const viewportModify = createRectangleModify(viewportLayer); - const simulatedRegionModify = - createRectangleModify(simulatedRegionLayer); - - const rectangleTranslate = new TranslateInteraction({ - layers: [viewportLayer, simulatedRegionLayer], - condition: (event) => primaryAction(event) && !shiftKeyOnly(event), - hitTolerance: 10, - }); - - ModifyHelper.registerModifyEvents(viewportModify); - ModifyHelper.registerModifyEvents(simulatedRegionModify); - + const resizeViewportInteraction = new ResizeRectangleInteraction( + viewportLayer.getSource()! + ); + const resizeSimulatedRegionInteraction = new ResizeRectangleInteraction( + simulatedRegionLayer.getSource()! + ); const alwaysInteractions = [translateInteraction]; const customInteractions = selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' ? [ ...alwaysInteractions, - rectangleTranslate, - viewportModify, - simulatedRegionModify, + resizeViewportInteraction, + resizeSimulatedRegionInteraction, ] : alwaysInteractions; @@ -316,7 +306,6 @@ export class OlMapManager { this.registerPopupTriggers(translateInteraction); this.registerDropHandler(translateInteraction); - this.registerDropHandler(rectangleTranslate); this.registerViewportRestriction(); // Register handlers that disable or enable certain interactions diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts deleted file mode 100644 index bb52e552f..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/rectangle-modify.ts +++ /dev/null @@ -1,67 +0,0 @@ -import type { Feature } from 'ol'; -import { primaryAction, shiftKeyOnly } from 'ol/events/condition'; -import type { LineString, Point } from 'ol/geom'; -import { Modify } from 'ol/interaction'; -import type VectorLayer from 'ol/layer/Vector'; -import type VectorSource from 'ol/source/Vector'; -import type { CornerName, ModifyGeometry } from './modify-helper'; - -const originCornerDict: { - [key in CornerName]: { originIndex: number; cornerIndex: number }; -} = { - bottomRight: { originIndex: 0, cornerIndex: 2 }, - bottomLeft: { originIndex: 1, cornerIndex: 3 }, - topLeft: { originIndex: 2, cornerIndex: 0 }, - topRight: { originIndex: 3, cornerIndex: 1 }, -}; - -export function createRectangleModify( - rectangleLayer: VectorLayer> -): Modify { - const defaultStyle = new Modify({ source: rectangleLayer.getSource()! }) - .getOverlay() - .getStyleFunction(); - return new Modify({ - source: rectangleLayer.getSource()!, - condition: (event) => primaryAction(event) && shiftKeyOnly(event), - deleteCondition: () => false, - insertVertexCondition: () => false, - style: (feature) => { - (feature.get('features') as Feature[]).forEach((modifyFeature) => { - const modifyGeometry = modifyFeature.get( - 'modifyGeometry' - ) as ModifyGeometry; - if (!modifyGeometry) { - return; - } - const mouseCoordinate = ( - feature.getGeometry() as Point - ).getCoordinates(); - - const corners = modifyGeometry.geometry.getCoordinates(); - const { originIndex, cornerIndex } = - originCornerDict[modifyGeometry.modifyCorner]; - // The corners array must be big enough. - if ( - corners.length <= originIndex || - corners.length <= cornerIndex - ) { - throw new Error( - `corners must be at least as big to satisfy originIndex (${originIndex}) and cornerIndex (${cornerIndex}): ${corners}` - ); - } - const origin = corners[originIndex]!; - const corner = corners[cornerIndex]!; - modifyGeometry.geometry.scale( - (mouseCoordinate[0]! - origin[0]!) / - (corner[0]! - origin[0]!), - (origin[1]! - mouseCoordinate[1]!) / - (origin[1]! - corner[1]!), - origin - ); - }); - // The OpenLayers typings are incorrect here. We have to provide a second argument, even though it is ignored - return defaultStyle!(feature, 123); - }, - }); -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts new file mode 100644 index 000000000..88c769e3b --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts @@ -0,0 +1,156 @@ +import type { Feature, MapBrowserEvent } from 'ol'; +import type { Coordinate } from 'ol/coordinate'; +import { distance } from 'ol/coordinate'; +import BaseEvent from 'ol/events/Event'; +import type { LineString } from 'ol/geom'; +import PointerInteraction from 'ol/interaction/Pointer'; +import type VectorSource from 'ol/source/Vector'; + +/** + * Provides the ability to resize a rectangle by dragging any of its corners. + */ +export class ResizeRectangleInteraction extends PointerInteraction { + /** + * The tolerance in coordinates for hitting a corner. + */ + private readonly hitTolerance = 3; + + /** + * Temporary values for the current resize operation. + * If undefined no resize operation is currently in progress. + */ + private currentResizeValues?: CurrentResizeValues; + + constructor(private readonly source: VectorSource) { + super({ + handleDownEvent: (event) => this._handleDownEvent(event), + handleDragEvent: (event) => this._handleDragEvent(event), + handleUpEvent: (event) => this._handleUpEvent(event), + }); + } + + private _handleDownEvent(event: MapBrowserEvent): boolean { + const mouseCoordinate = event.coordinate; + const feature = + this.source.getClosestFeatureToCoordinate(mouseCoordinate); + if (!feature) { + return false; + } + const geometry = feature.getGeometry()!; + const corners = geometry.getCoordinates()!; + const distances = corners.map((corner) => + distance(corner, mouseCoordinate) + ); + const minDistance = Math.min(...distances); + if (minDistance > this.hitTolerance) { + // Only corners are relevant for us + return false; + } + const nearestCorner = corners[distances.indexOf(minDistance)]; + const maxDistance = Math.max(...distances); + const furthestCorner = corners[distances.indexOf(maxDistance)]; + if (nearestCorner === undefined || furthestCorner === undefined) { + return false; + } + this.currentResizeValues = { + draggedCorner: nearestCorner, + originCorner: furthestCorner, + feature, + currentScale: { x: 1, y: 1 }, + }; + return true; + } + + private _handleDragEvent(event: MapBrowserEvent): boolean { + if (this.currentResizeValues === undefined) { + return false; + } + const mouseCoordinate = event.coordinate; + const newXScale = + (mouseCoordinate[0]! - this.currentResizeValues.originCorner[0]!) / + (this.currentResizeValues.draggedCorner[0]! - + this.currentResizeValues.originCorner[0]!); + const newYScale = + (this.currentResizeValues.originCorner[1]! - mouseCoordinate[1]!) / + (this.currentResizeValues.originCorner[1]! - + this.currentResizeValues.draggedCorner[1]!); + this.currentResizeValues.feature + .getGeometry()! + .scale( + newXScale / this.currentResizeValues.currentScale!.x, + newYScale / this.currentResizeValues.currentScale!.y, + this.currentResizeValues.originCorner + ); + this.currentResizeValues.currentScale = { x: newXScale, y: newYScale }; + return true; + } + + private _handleUpEvent(event: MapBrowserEvent): boolean { + if (this.currentResizeValues === undefined) { + return true; + } + + const coordinates = this.currentResizeValues.feature + .getGeometry()! + .getCoordinates()!; + const topLeftCoordinate = coordinates.reduce( + (smallestCoordinate, coordinate) => + coordinate[0]! <= smallestCoordinate[0]! || + coordinate[1]! >= smallestCoordinate[1]! + ? coordinate + : smallestCoordinate, + [Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY] + ); + this.currentResizeValues.feature.dispatchEvent( + new ResizeEvent( + this.currentResizeValues.currentScale, + this.currentResizeValues.originCorner, + topLeftCoordinate + ) + ); + this.currentResizeValues = undefined; + return false; + } + + static onResize( + feature: Feature, + callback: (event: ResizeEvent) => void + ) { + feature.addEventListener( + resizeRectangleEventType, + callback as (event: BaseEvent | Event) => void + ); + } +} + +interface CurrentResizeValues { + draggedCorner: Coordinate; + /** + * The corner that doesn't move during the resize. + */ + originCorner: Coordinate; + /** + * The feature that is currently being resized. + */ + feature: Feature; + currentScale: { x: number; y: number }; +} + +// TODO: This doesn't work as a static member of ResizeEvent, because it is undefined at runtime. Why? +const resizeRectangleEventType = 'resizerectangle'; + +class ResizeEvent extends BaseEvent { + constructor( + public readonly scale: { x: number; y: number }, + /** + * The coordinate of the corner that didn't move during the resize. + */ + public readonly origin: Coordinate, + /** + * The new top left coordinate of the rectangle. + */ + public readonly topLeftCoordinate: Coordinate + ) { + super(resizeRectangleEventType); + } +} From d7a5a7aac55ec185d4182f91ab79f104e0db38ea Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Thu, 19 Jan 2023 15:32:04 +0100 Subject: [PATCH 09/58] Add link to main branch in readme (#611) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5440f1270..76b08ac5a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Digitale FüSim MANV +## If you're interested in the most recent stable release, please check out the [main](https://github.com/hpi-sam/digital-fuesim-manv/tree/main) branch. + This is the codebase for a digital implementation of the "FüSim MANV" (Führungssimulation Massenanfall von Verletzen), a German simulation system for training emergency medical services leadership personnel on how to manage [Mass Casualty Incidents](https://en.wikipedia.org/wiki/Mass-casualty_incident). **You can try it out at [https://fuesim-manv.de/](https://fuesim-manv.de/)**. From da3acf667a8287c74d405d61765a3f76daa1610f Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Fri, 20 Jan 2023 16:14:37 +0100 Subject: [PATCH 10/58] Close popups with esc (#610) * Add keydown handler to close popups on escape * Ensure input is saved even after less than 600ms * Cast event inline Co-authored-by: Julian Schmidt --- .../exercise-map/utility/ol-map-manager.ts | 6 ++++ .../app-save-on-typing.directive.ts | 28 +++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 2da070120..4a7b944fc 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -454,6 +454,12 @@ export class OlMapManager { this.olMap.getView().on(['change:resolution', 'change:center'], () => { this.changePopup$.next(undefined); }); + + this.openLayersContainer.addEventListener('keydown', (event) => { + if ((event as KeyboardEvent).key === 'Escape') { + this.changePopup$.next(undefined); + } + }); } private registerDropHandler(translateInteraction: TranslateInteraction) { diff --git a/frontend/src/app/shared/directives/app-save-on-typing.directive.ts b/frontend/src/app/shared/directives/app-save-on-typing.directive.ts index f6345c1e6..ad8111d8b 100644 --- a/frontend/src/app/shared/directives/app-save-on-typing.directive.ts +++ b/frontend/src/app/shared/directives/app-save-on-typing.directive.ts @@ -2,7 +2,7 @@ import type { OnDestroy } from '@angular/core'; import { Directive, EventEmitter, Output } from '@angular/core'; import { NgModel } from '@angular/forms'; import { Subject } from 'rxjs'; -import { debounceTime, filter, takeUntil } from 'rxjs/operators'; +import { debounceTime, filter, takeUntil, tap } from 'rxjs/operators'; /** * This directive should be used when values should be autosaved while the user types into the input. @@ -29,19 +29,43 @@ export class AppSaveOnTypingDirective implements OnDestroy { destroy$ = new Subject(); @Output() readonly appSaveOnTyping: EventEmitter = new EventEmitter(); + private lastInputValue?: any; + private lastInputValueWasValid = false; + private lastSubmittedValue?: any; + constructor(ngModel: NgModel) { ngModel.update .pipe( + tap((value) => { + this.lastInputValue = value; + this.lastInputValueWasValid = ngModel.valid === true; + }), // Keeping a key (like backspace) pressed for a more than a certain threshold will result in many key presses // The debounceTime should be above that threshold to not register the initial keypress as the first update debounceTime(600), filter(() => ngModel.valid === true), takeUntil(this.destroy$) ) - .subscribe(this.appSaveOnTyping); + .subscribe((value) => { + if (this.lastSubmittedValue === value) { + // We don't want to emit the same value twice in a row + return; + } + this.lastSubmittedValue = value; + this.appSaveOnTyping.next(value); + }); } ngOnDestroy() { + if ( + this.lastInputValueWasValid && + this.lastInputValue !== this.lastSubmittedValue + ) { + // The last input value was not submitted yet + // We want to emit this last value before the appSaveOnTyping gets + // unsubscribed from during the destruction of the parent component + this.appSaveOnTyping.next(this.lastInputValue); + } this.destroy$.next(); } } From c7ba8c171a14c53b17eda8f742096262e762f524 Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Sun, 22 Jan 2023 21:34:29 +0100 Subject: [PATCH 11/58] Add new image for big material and material (#544) * Add new image for big material and material Co-authored-by: Julian Schmidt --- frontend/src/assets/big-material.svg | 70 +++++++++++ frontend/src/assets/image-sources.md | 5 +- frontend/src/assets/material.svg | 109 +++++++++++++++++- .../data/default-state/material-templates.ts | 7 +- 4 files changed, 185 insertions(+), 6 deletions(-) create mode 100644 frontend/src/assets/big-material.svg diff --git a/frontend/src/assets/big-material.svg b/frontend/src/assets/big-material.svg new file mode 100644 index 000000000..17f963fb4 --- /dev/null +++ b/frontend/src/assets/big-material.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/image-sources.md b/frontend/src/assets/image-sources.md index 169259d6c..0271c66fd 100644 --- a/frontend/src/assets/image-sources.md +++ b/frontend/src/assets/image-sources.md @@ -35,7 +35,10 @@ Florian Greiz 23 (edited) [material.svg](material.svg): - (edited) +Benildur Nickel + +[big-material.svg](big-material.svg): +Benildur Nickel [patient.svg](patient.svg): (edited) diff --git a/frontend/src/assets/material.svg b/frontend/src/assets/material.svg index 2f96c425d..c64f1e00c 100644 --- a/frontend/src/assets/material.svg +++ b/frontend/src/assets/material.svg @@ -1 +1,108 @@ - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + diff --git a/shared/src/data/default-state/material-templates.ts b/shared/src/data/default-state/material-templates.ts index 3c1470928..c9d3327fa 100644 --- a/shared/src/data/default-state/material-templates.ts +++ b/shared/src/data/default-state/material-templates.ts @@ -10,7 +10,7 @@ const standardMaterialTemplate = MaterialTemplate.create( 'standard', { url: '/assets/material.svg', - height: 40, + height: 35, aspectRatio: 1, }, CanCaterFor.create(2, 0, 0, 'and'), @@ -21,9 +21,8 @@ const standardMaterialTemplate = MaterialTemplate.create( const bigMaterialTemplate = MaterialTemplate.create( 'big', { - url: '/assets/material.svg', - // Roughly double the area of the standard material - height: 56, + url: '/assets/big-material.svg', + height: 35, aspectRatio: 1, }, CanCaterFor.create(2, 2, 0, 'and'), From 8664f331a6abae2053e31ceb117ae6dd2afcc7ad Mon Sep 17 00:00:00 2001 From: Lukas Hagen <43916057+Greenscreen23@users.noreply.github.com> Date: Tue, 24 Jan 2023 13:07:20 +0100 Subject: [PATCH 12/58] Fix CVE-2022-25901 (#618) --- backend/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 8b86b185e..1591bd3e5 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -2623,9 +2623,9 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/cookiejar": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.3.tgz", - "integrity": "sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ==" + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==" }, "node_modules/cors": { "version": "2.8.5", From 5170e2bda8c5c415ca22b8fa6aa201a618cb6ab3 Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Wed, 25 Jan 2023 10:50:14 +0100 Subject: [PATCH 13/58] Feature/597 regions can contain personnel and patients (#607) * Add MetaPosition type * Add MetaPosition to Vehicle * Add MetaPosition ro Personnel * Add MetaPosition to Material * Add MetaPosition to Patient * Add Classes for different Position Types * Use create when applicable and fix in MetaPosition * Add migration for addition of MetaPosition * refactor literals to start with lowercase * Change nested if else to else if * Make metaPosition not optional * Fix failing Tests * Update shared/src/models/material.ts Co-authored-by: Julian Schmidt * Update shared/src/models/patient.ts Co-authored-by: Julian Schmidt * Update shared/src/models/personnel.ts Co-authored-by: Julian Schmidt * Update shared/src/store/action-reducers/patient.ts Co-authored-by: Julian Schmidt * Update shared/src/store/action-reducers/utils/calculate-treatments.spec.ts Co-authored-by: Julian Schmidt * Update shared/src/store/action-reducers/vehicle.ts Co-authored-by: Julian Schmidt * Fix Prettier Errors * Change Validation to Allow * Put personnel and material in vehicle on creation * Update shared/src/store/action-reducers/transfer.ts Co-authored-by: Julian Schmidt * Fix Pipeline dependencies * Update shared/src/state-migrations/16-add-meta-position.ts Co-authored-by: Julian Schmidt * Fix linter Error * Add validators to MetaPositions * Remove unused imports * Fix Validators * Add/Fix Action Migrations * Add Exports to Index.ts * Update shared/src/store/action-reducers/utils/spatial-elements.ts Co-authored-by: Julian Schmidt * Update shared/src/store/action-reducers/vehicle.ts Co-authored-by: Julian Schmidt * Fix Lint Co-authored-by: Nils <45318774+Nils1729@users.noreply.github.com> Co-authored-by: Julian Schmidt --- .../shared/core/drag-element.service.ts | 4 +- .../send-alarm-group-interface.component.ts | 8 +- shared/src/data/dummy-objects/patient.ts | 5 +- shared/src/models/material.ts | 15 +- shared/src/models/patient-template.ts | 7 +- shared/src/models/patient.ts | 14 +- shared/src/models/personnel.ts | 18 +- shared/src/models/utils/index.ts | 6 + shared/src/models/utils/map-coordinates.ts | 20 +++ shared/src/models/utils/map-position.ts | 23 +++ shared/src/models/utils/meta-position.ts | 10 ++ .../models/utils/simulated-region-position.ts | 19 +++ shared/src/models/utils/transfer-position.ts | 23 +++ shared/src/models/utils/vehicle-position.ts | 21 +++ shared/src/models/vehicle.ts | 12 +- .../create-vehicle-parameters.ts | 11 +- .../state-migrations/16-add-meta-position.ts | 161 ++++++++++++++++++ .../state-migrations/migration-functions.ts | 2 + shared/src/state.ts | 2 +- shared/src/store/action-reducers/patient.ts | 2 +- shared/src/store/action-reducers/transfer.ts | 15 +- .../utils/calculate-treatments.spec.ts | 64 ++++--- .../action-reducers/utils/spatial-elements.ts | 4 + shared/src/store/action-reducers/vehicle.ts | 47 ++++- .../src/utils/validators/is-metaposition.ts | 36 ++++ 25 files changed, 507 insertions(+), 42 deletions(-) create mode 100644 shared/src/models/utils/map-coordinates.ts create mode 100644 shared/src/models/utils/map-position.ts create mode 100644 shared/src/models/utils/meta-position.ts create mode 100644 shared/src/models/utils/simulated-region-position.ts create mode 100644 shared/src/models/utils/transfer-position.ts create mode 100644 shared/src/models/utils/vehicle-position.ts create mode 100644 shared/src/state-migrations/16-add-meta-position.ts create mode 100644 shared/src/utils/validators/is-metaposition.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts index 0b144d6c9..143f58bed 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts @@ -14,6 +14,7 @@ import { TransferPoint, Viewport, SimulatedRegion, + MapPosition, } from 'digital-fuesim-manv-shared'; import type OlMap from 'ol/Map'; import { ExerciseService } from 'src/app/core/exercise.service'; @@ -168,7 +169,8 @@ export class DragElementService { .patientTemplates.length ) ]!, - this.transferringTemplate.template.name + this.transferringTemplate.template.name, + MapPosition.create(position) ); this.exerciseService.proposeAction( { diff --git a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts index ef6929b26..15b9189ab 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts @@ -3,6 +3,7 @@ import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; import type { AlarmGroup, UUID } from 'digital-fuesim-manv-shared'; import { + Position, AlarmGroupStartPoint, createVehicleParameters, TransferPoint, @@ -94,7 +95,12 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy { selectStateSnapshot( selectPersonnelTemplates, this.store - ) + ), + // TODO: This position is not correct but needs to be provided. + // Here one should use a MetaPosition with the Transfer. + // But this is part of later Refactoring. + // Also it is irrelevant, because the correctMetaPosition is set immediately after this is called. + Position.create(0, 0) ); return [ diff --git a/shared/src/data/dummy-objects/patient.ts b/shared/src/data/dummy-objects/patient.ts index 809f13991..7fd5fc3c6 100644 --- a/shared/src/data/dummy-objects/patient.ts +++ b/shared/src/data/dummy-objects/patient.ts @@ -1,4 +1,6 @@ import { FunctionParameters, Patient, PatientHealthState } from '../../models'; +import { MapCoordinates } from '../../models/utils/map-coordinates'; +import { MapPosition } from '../../models/utils/map-position'; import { PatientStatusCode } from '../../models/utils/patient-status-code'; import { defaultPatientCategories } from '../default-state/patient-templates'; @@ -23,6 +25,7 @@ export function generateDummyPatient(): Patient { healthState.id, template.image, template.health, - '' + '', + MapPosition.create(MapCoordinates.create(0, 0)) ); } diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts index e82ab1ed0..10dc9e2fa 100644 --- a/shared/src/models/material.ts +++ b/shared/src/models/material.ts @@ -11,8 +11,10 @@ import { import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsUUIDSet } from '../utils/validators'; +import { IsMetaPosition } from '../utils/validators/is-metaposition'; import type { MaterialTemplate } from './material-template'; import { CanCaterFor, Position, ImageProperties, getCreate } from './utils'; +import { MetaPosition } from './utils/meta-position'; export class Material { @IsUUID(4, uuidValidationOptions) @@ -51,7 +53,12 @@ export class Material { @Max(maxTreatmentRange) public readonly treatmentRange: number; + @IsMetaPosition() + @ValidateNested() + public readonly metaPosition: MetaPosition; + /** + * @deprecated use {@link metaPosition} * if undefined, is in vehicle with {@link this.vehicleId} */ @ValidateNested() @@ -74,6 +81,7 @@ export class Material { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, + metaPosition: MetaPosition, position?: Position ) { this.vehicleId = vehicleId; @@ -84,6 +92,7 @@ export class Material { this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; + this.metaPosition = metaPosition; } static readonly create = getCreate(this); @@ -91,7 +100,8 @@ export class Material { static generateMaterial( materialTemplate: MaterialTemplate, vehicleId: UUID, - vehicleName: string + vehicleName: string, + metaPosition: MetaPosition ): Material { return this.create( vehicleId, @@ -101,11 +111,12 @@ export class Material { materialTemplate.canCaterFor, materialTemplate.treatmentRange, materialTemplate.overrideTreatmentRange, + metaPosition, undefined ); } static isInVehicle(material: Material): boolean { - return material.position === undefined; + return material.metaPosition.type === 'vehicle'; } } diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts index 65e319f09..ef8841390 100644 --- a/shared/src/models/patient-template.ts +++ b/shared/src/models/patient-template.ts @@ -16,6 +16,7 @@ import { Patient } from './patient'; import type { FunctionParameters } from './patient-health-state'; import { PretriageInformation } from './utils/pretriage-information'; import { PatientHealthState } from './patient-health-state'; +import type { MetaPosition } from './utils/meta-position'; export class PatientTemplate { @IsUUID(4, uuidValidationOptions) @@ -67,7 +68,8 @@ export class PatientTemplate { public static generatePatient( template: PatientTemplate, - patientStatusCode: PatientStatusCode + patientStatusCode: PatientStatusCode, + metaPosition: MetaPosition ): Patient { // Randomize function parameters const healthStates = Object.fromEntries( @@ -107,7 +109,8 @@ export class PatientTemplate { template.startingHealthStateId, template.image, template.health, - '' + '', + metaPosition ); } } diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index 19423c02d..29fdf2a7d 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -13,6 +13,7 @@ import { } from 'class-validator'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsLiteralUnion, IsIdMap, IsUUIDSet } from '../utils/validators'; +import { IsMetaPosition } from '../utils/validators/is-metaposition'; import { PatientHealthState } from './patient-health-state'; import { BiometricInformation, @@ -25,6 +26,7 @@ import { HealthPoints, getCreate, } from './utils'; +import { MetaPosition } from './utils/meta-position'; import { PersonalInformation } from './utils/personal-information'; import { PretriageInformation } from './utils/pretriage-information'; @@ -62,7 +64,12 @@ export class Patient { @Type(() => ImageProperties) public readonly image: ImageProperties; + @IsMetaPosition() + @ValidateNested() + public readonly metaPosition: MetaPosition; + /** + * @deprecated use {@link metaPosition} * Exclusive-or to {@link vehicleId} */ @ValidateNested() @@ -71,6 +78,7 @@ export class Patient { public readonly position?: Position; /** + * @deprecated use {@link metaPosition} * Exclusive-or to {@link position} */ @IsUUID(4, uuidValidationOptions) @@ -155,7 +163,8 @@ export class Patient { currentHealthStateId: UUID, image: ImageProperties, health: HealthPoints, - remarks: string + remarks: string, + metaPosition: MetaPosition ) { this.personalInformation = personalInformation; this.biometricInformation = biometricInformation; @@ -168,6 +177,7 @@ export class Patient { this.image = image; this.health = health; this.remarks = remarks; + this.metaPosition = metaPosition; } static readonly create = getCreate(this); @@ -190,7 +200,7 @@ export class Patient { } static isInVehicle(patient: Patient): boolean { - return patient.position === undefined; + return patient.metaPosition.type === 'vehicle'; } static isTreatedByPersonnel(patient: Patient) { diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts index afe24d0e4..9ed6b4f79 100644 --- a/shared/src/models/personnel.ts +++ b/shared/src/models/personnel.ts @@ -11,6 +11,7 @@ import { import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsLiteralUnion, IsUUIDSet } from '../utils/validators'; +import { IsMetaPosition } from '../utils/validators/is-metaposition'; import type { PersonnelTemplate } from './personnel-template'; import { PersonnelType, @@ -20,6 +21,7 @@ import { Transfer, getCreate, } from './utils'; +import { MetaPosition } from './utils/meta-position'; import { personnelTypeAllowedValues } from './utils/personnel-type'; export class Personnel { @@ -66,7 +68,12 @@ export class Personnel { @Type(() => ImageProperties) public readonly image: ImageProperties; + @IsMetaPosition() + @ValidateNested() + public readonly metaPosition: MetaPosition; + /** + * @deprecated use {@link metaPosition} * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or in transfer. */ @ValidateNested() @@ -75,6 +82,7 @@ export class Personnel { public readonly position?: Position; /** + * * @deprecated use {@link metaPosition} * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or has a {@link position}. */ @ValidateNested() @@ -94,6 +102,7 @@ export class Personnel { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, + metaPosition: MetaPosition, position?: Position ) { this.vehicleId = vehicleId; @@ -105,6 +114,7 @@ export class Personnel { this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; + this.metaPosition = metaPosition; } static readonly create = getCreate(this); @@ -112,7 +122,8 @@ export class Personnel { static generatePersonnel( personnelTemplate: PersonnelTemplate, vehicleId: UUID, - vehicleName: string + vehicleName: string, + metaPosition: MetaPosition ): Personnel { return this.create( vehicleId, @@ -123,13 +134,12 @@ export class Personnel { personnelTemplate.canCaterFor, personnelTemplate.treatmentRange, personnelTemplate.overrideTreatmentRange, + metaPosition, undefined ); } static isInVehicle(personnel: Personnel): boolean { - return ( - personnel.position === undefined && personnel.transfer === undefined - ); + return personnel.metaPosition.type === 'vehicle'; } } diff --git a/shared/src/models/utils/index.ts b/shared/src/models/utils/index.ts index d4b477f34..3f5f846fd 100644 --- a/shared/src/models/utils/index.ts +++ b/shared/src/models/utils/index.ts @@ -1,4 +1,10 @@ export { Position } from './position'; +export { MetaPosition } from './meta-position'; +export { MapPosition } from './map-position'; +export { VehiclePosition } from './vehicle-position'; +export { TransferPosition } from './transfer-position'; +export { SimulatedRegionPosition } from './simulated-region-position'; +export { MapCoordinates } from './map-coordinates'; export * from './patient-status'; export { Size } from './size'; export { Role } from './role'; diff --git a/shared/src/models/utils/map-coordinates.ts b/shared/src/models/utils/map-coordinates.ts new file mode 100644 index 000000000..cab5696bd --- /dev/null +++ b/shared/src/models/utils/map-coordinates.ts @@ -0,0 +1,20 @@ +import { IsNumber } from 'class-validator'; +import { getCreate } from './get-create'; + +export class MapCoordinates { + @IsNumber() + public readonly x: number; + + @IsNumber() + public readonly y: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/map-position.ts b/shared/src/models/utils/map-position.ts new file mode 100644 index 000000000..726e0525f --- /dev/null +++ b/shared/src/models/utils/map-position.ts @@ -0,0 +1,23 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../utils/validators'; +import { getCreate } from './get-create'; +import { MapCoordinates } from './map-coordinates'; + +export class MapPosition { + @IsValue('coordinates') + public readonly type = 'coordinates'; + + @Type(() => MapCoordinates) + @ValidateNested() + public readonly position: MapCoordinates; + + /** + * @deprecated Use {@link create} instead + */ + constructor(position: MapCoordinates) { + this.position = position; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/meta-position.ts b/shared/src/models/utils/meta-position.ts new file mode 100644 index 000000000..888ee823b --- /dev/null +++ b/shared/src/models/utils/meta-position.ts @@ -0,0 +1,10 @@ +import type { MapPosition } from './map-position'; +import type { SimulatedRegionPosition } from './simulated-region-position'; +import type { TransferPosition } from './transfer-position'; +import type { VehiclePosition } from './vehicle-position'; + +export type MetaPosition = + | MapPosition + | SimulatedRegionPosition + | TransferPosition + | VehiclePosition; diff --git a/shared/src/models/utils/simulated-region-position.ts b/shared/src/models/utils/simulated-region-position.ts new file mode 100644 index 000000000..d797cdc66 --- /dev/null +++ b/shared/src/models/utils/simulated-region-position.ts @@ -0,0 +1,19 @@ +import type { UUID } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { getCreate } from './get-create'; + +export class SimulatedRegionPosition { + @IsValue('simulatedRegion') + public readonly type = 'simulatedRegion'; + + public readonly simulatedRegionId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(simulatedRegionId: UUID) { + this.simulatedRegionId = simulatedRegionId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/transfer-position.ts b/shared/src/models/utils/transfer-position.ts new file mode 100644 index 000000000..26e9b1a43 --- /dev/null +++ b/shared/src/models/utils/transfer-position.ts @@ -0,0 +1,23 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../utils/validators'; +import { getCreate } from './get-create'; +import { Transfer } from './transfer'; + +export class TransferPosition { + @IsValue('transfer') + public readonly type = 'transfer'; + + @Type(() => Transfer) + @ValidateNested() + public readonly transfer: Transfer; + + /** + * @deprecated Use {@link create} instead + */ + constructor(transfer: Transfer) { + this.transfer = transfer; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/vehicle-position.ts b/shared/src/models/utils/vehicle-position.ts new file mode 100644 index 000000000..80970ae93 --- /dev/null +++ b/shared/src/models/utils/vehicle-position.ts @@ -0,0 +1,21 @@ +import { IsUUID } from 'class-validator'; +import { UUID } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { getCreate } from './get-create'; + +export class VehiclePosition { + @IsValue('vehicle') + public readonly type = 'vehicle'; + + @IsUUID() + public readonly vehicleId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(vehicleId: UUID) { + this.vehicleId = vehicleId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index 95141b20b..8c18b39da 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -8,8 +8,10 @@ import { } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; import { IsUUIDSet } from '../utils/validators'; +import { IsMetaPosition } from '../utils/validators/is-metaposition'; import { getCreate, Position, Transfer } from './utils'; import { ImageProperties } from './utils/image-properties'; +import { MetaPosition } from './utils/meta-position'; export class Vehicle { @IsUUID(4, uuidValidationOptions) @@ -27,7 +29,12 @@ export class Vehicle { @IsNumber() public readonly patientCapacity: number; + @IsMetaPosition() + @ValidateNested() + public readonly metaPosition: MetaPosition; + /** + * @deprecated use {@link metaPosition} * Exclusive-or to {@link transfer} */ @ValidateNested() @@ -40,6 +47,7 @@ export class Vehicle { public readonly image: ImageProperties; /** + * @deprecated use {@link metaPosition} * Exclusive-or to {@link position} */ @ValidateNested() @@ -61,13 +69,15 @@ export class Vehicle { name: string, materialIds: UUIDSet, patientCapacity: number, - image: ImageProperties + image: ImageProperties, + metaPosition: MetaPosition ) { this.vehicleType = vehicleType; this.name = name; this.materialIds = materialIds; this.patientCapacity = patientCapacity; this.image = image; + this.metaPosition = metaPosition; } static readonly create = getCreate(this); diff --git a/shared/src/state-helpers/create-vehicle-parameters.ts b/shared/src/state-helpers/create-vehicle-parameters.ts index d4d9951ad..e6f0021a3 100644 --- a/shared/src/state-helpers/create-vehicle-parameters.ts +++ b/shared/src/state-helpers/create-vehicle-parameters.ts @@ -3,7 +3,9 @@ import { Material, Personnel } from '../models'; import type { MaterialTemplate } from '../models/material-template'; import type { PersonnelTemplate } from '../models/personnel-template'; import type { PersonnelType, Position } from '../models/utils'; +import { MapPosition } from '../models/utils/map-position'; import type { MaterialType } from '../models/utils/material-type'; +import { VehiclePosition } from '../models/utils/vehicle-position'; import { uuid } from '../utils'; import { arrayToUUIDSet } from '../utils/array-to-uuid-set'; @@ -20,7 +22,7 @@ export function createVehicleParameters( personnelTemplates: { [Key in PersonnelType]: PersonnelTemplate; }, - vehiclePosition?: Position + vehiclePosition: Position ): { materials: Material[]; personnel: Personnel[]; @@ -31,14 +33,16 @@ export function createVehicleParameters( Material.generateMaterial( materialTemplates[currentMaterial], vehicleId, - vehicleTemplate.name + vehicleTemplate.name, + VehiclePosition.create(vehicleId) ) ); const personnel = vehicleTemplate.personnel.map((currentPersonnel) => Personnel.generatePersonnel( personnelTemplates[currentPersonnel], vehicleId, - vehicleTemplate.name + vehicleTemplate.name, + VehiclePosition.create(vehicleId) ) ); @@ -52,6 +56,7 @@ export function createVehicleParameters( patientIds: {}, personnelIds: arrayToUUIDSet(personnel.map((p) => p.id)), position: vehiclePosition, + metaPosition: MapPosition.create(vehiclePosition), }; return { materials, diff --git a/shared/src/state-migrations/16-add-meta-position.ts b/shared/src/state-migrations/16-add-meta-position.ts new file mode 100644 index 000000000..bca88a103 --- /dev/null +++ b/shared/src/state-migrations/16-add-meta-position.ts @@ -0,0 +1,161 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addMetaPosition16: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Patient] Add patient' + ) { + const typedAction = action as { + patient: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + if (typedAction.patient.position) { + typedAction.patient.metaPosition = { + type: 'coordinates', + position: { + x: typedAction.patient.position.x, + y: typedAction.patient.position.y, + }, + }; + } else if (typedAction.patient.vehicleId) { + typedAction.patient.metaPosition = { + type: 'vehicle', + vehicleId: typedAction.patient.vehicleId, + }; + } + } + if ( + (action as { type: string } | null)?.type === + '[Vehicle] Add vehicle' + ) { + const typedAction = action as { + vehicle: { + position?: { x: number; y: number }; + transfer?: any; + metaPosition?: any; + }; + }; + if (typedAction.vehicle.position) { + typedAction.vehicle.metaPosition = { + type: 'coordinates', + position: { + x: typedAction.vehicle.position.x, + y: typedAction.vehicle.position.y, + }, + }; + } else if (typedAction.vehicle.transfer) { + typedAction.vehicle.metaPosition = { + type: 'transfer', + transfer: typedAction.vehicle.transfer, + }; + } + } + }); + }, + state: (state) => { + const typedState = state as { + patients: { + [patientId: UUID]: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + materials: { + [materialId: UUID]: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + vehicles: { + [vehicleId: UUID]: { + position?: { x: number; y: number }; + transfer?: any; + metaPosition?: any; + }; + }; + personnel: { + [personnelId: UUID]: { + position?: { x: number; y: number }; + transfer?: any; + vehicleId?: UUID; + metaPosition?: any; + }; + }; + }; + + Object.values(typedState.patients).forEach((patient) => { + if (patient.position) { + patient.metaPosition = { + type: 'coordinates', + position: { x: patient.position.x, y: patient.position.y }, + }; + } else if (patient.vehicleId) { + patient.metaPosition = { + type: 'vehicle', + vehicleId: patient.vehicleId, + }; + } + }); + + Object.values(typedState.materials).forEach((material) => { + if (material.position) { + material.metaPosition = { + type: 'coordinates', + position: { + x: material.position.x, + y: material.position.y, + }, + }; + } else if (material.vehicleId) { + material.metaPosition = { + type: 'vehicle', + vehicleId: material.vehicleId, + }; + } + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + if (vehicle.position) { + vehicle.metaPosition = { + type: 'coordinates', + position: { x: vehicle.position.x, y: vehicle.position.y }, + }; + } else if (vehicle.transfer) { + vehicle.metaPosition = { + type: 'transfer', + transfer: vehicle.transfer, + }; + } + }); + + Object.values(typedState.personnel).forEach((personnel) => { + if (personnel.position) { + personnel.metaPosition = { + type: 'coordinates', + position: { + x: personnel.position.x, + y: personnel.position.y, + }, + }; + } else if (personnel.transfer) { + personnel.metaPosition = { + type: 'transfer', + transfer: personnel.transfer, + }; + } else if (personnel.vehicleId) { + personnel.metaPosition = { + type: 'vehicle', + vehicleId: personnel.vehicleId, + }; + } + }); + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index f914113b9..8bbed2f7b 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -4,6 +4,7 @@ import { renameIncorrectPatientImages12 } from './12-rename-incorrect-patient-im import { addMapImageZIndex13 } from './13-add-map-image-zindex'; import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; import { addSimulatedRegions15 } from './15-add-simulated-regions'; +import { addMetaPosition16 } from './16-add-meta-position'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -53,4 +54,5 @@ export const migrations: { 13: addMapImageZIndex13, 14: addPersonnelAndMaterialToState14, 15: addSimulatedRegions15, + 16: addMetaPosition16, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index ab27ab0db..0f05987f2 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -148,5 +148,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 15; + static readonly currentStateVersion = 16; } diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts index 277ab6e50..d25fca861 100644 --- a/shared/src/store/action-reducers/patient.ts +++ b/shared/src/store/action-reducers/patient.ts @@ -155,7 +155,7 @@ export namespace PatientActionReducers { const patient = getElement(draftState, 'patients', patientId); patient.pretriageStatus = patientStatus; - if (patient.position !== undefined) { + if (patient.metaPosition.type === 'coordinates') { updateTreatments(draftState, patient); } diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index cd9f88fa9..9dc2eee4d 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -52,6 +52,10 @@ export function letElementArrive( updateElementPosition(draftState, 'personnel', element.id, newPosition); } else { element.position = newPosition; + element.metaPosition = { + type: 'coordinates', + position: newPosition, + }; } delete element.transfer; } @@ -167,7 +171,6 @@ export namespace TransferActionReducers { } else { element.position = undefined; } - // Set the element to transfer element.transfer = { startPoint: cloneDeepMutable(startPoint), @@ -176,6 +179,16 @@ export namespace TransferActionReducers { isPaused: false, }; + element.metaPosition = { + type: 'transfer', + transfer: { + startPoint: cloneDeepMutable(startPoint), + targetTransferPointId, + endTimeStamp: draftState.currentTime + duration, + isPaused: false, + }, + }; + return draftState; }, rights: 'participant', diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts index 450294a7e..e811becfc 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts @@ -4,9 +4,11 @@ import { defaultMaterialTemplates } from '../../../data/default-state/material-t import { defaultPersonnelTemplates } from '../../../data/default-state/personnel-templates'; import type { Patient } from '../../../models'; import { Material, Personnel } from '../../../models'; -import type { PatientStatus } from '../../../models/utils'; +import type { MetaPosition, PatientStatus } from '../../../models/utils'; import { CanCaterFor, Position } from '../../../models/utils'; +import { MapPosition } from '../../../models/utils/map-position'; import { SpatialTree } from '../../../models/utils/spatial-tree'; +import { VehiclePosition } from '../../../models/utils/vehicle-position'; import { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable, uuid } from '../../../utils'; @@ -76,6 +78,10 @@ function addPatient( patient.realStatus = realStatus; if (position) { patient.position = cloneDeepMutable(position); + patient.metaPosition = { + type: 'coordinates', + position: cloneDeepMutable(position), + }; SpatialTree.addElement( state.spatialTrees.patients, patient.id, @@ -86,12 +92,16 @@ function addPatient( return patient; } -function addPersonnel(state: Mutable, position?: Position) { +function addPersonnel( + state: Mutable, + metaPosition: MetaPosition +) { const personnel = cloneDeepMutable( Personnel.generatePersonnel( defaultPersonnelTemplates.notSan, uuid(), - 'RTW 3/83/1' + 'RTW 3/83/1', + metaPosition ) ); personnel.canCaterFor = { @@ -100,8 +110,8 @@ function addPersonnel(state: Mutable, position?: Position) { green: 0, logicalOperator: 'and', }; - if (position) { - personnel.position = cloneDeepMutable(position); + if (metaPosition.type === 'coordinates') { + personnel.position = cloneDeepMutable(metaPosition.position); SpatialTree.addElement( state.spatialTrees.personnel, personnel.id, @@ -112,12 +122,16 @@ function addPersonnel(state: Mutable, position?: Position) { return personnel; } -function addMaterial(state: Mutable, position?: Position) { +function addMaterial( + state: Mutable, + metaPosition: MetaPosition +) { const material = cloneDeepMutable( Material.generateMaterial( defaultMaterialTemplates.standard, uuid(), - 'RTW 3/83/1' + 'RTW 3/83/1', + metaPosition ) ); material.canCaterFor = { @@ -126,8 +140,8 @@ function addMaterial(state: Mutable, position?: Position) { green: 0, logicalOperator: 'and', }; - if (position) { - material.position = cloneDeepMutable(position); + if (metaPosition.type === 'coordinates') { + material.position = cloneDeepMutable(metaPosition.position); SpatialTree.addElement( state.spatialTrees.materials, material.id, @@ -170,7 +184,7 @@ describe('calculate treatment', () => { it('does nothing when there is only personnel in vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPersonnel(state); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -179,7 +193,7 @@ describe('calculate treatment', () => { it('does nothing when there is only personnel outside vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPersonnel(state, Position.create(0, 0)); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -188,7 +202,7 @@ describe('calculate treatment', () => { it('does nothing when there is only material in vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addMaterial(state); + addMaterial(state, MapPosition.create({ x: 0, y: 0 })); } ); expect(newState).toStrictEqual(beforeState); @@ -197,7 +211,7 @@ describe('calculate treatment', () => { it('does nothing when there is only material outside vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addMaterial(state, Position.create(0, 0)); + addMaterial(state, MapPosition.create({ x: 0, y: 0 })); } ); expect(newState).toStrictEqual(beforeState); @@ -229,7 +243,7 @@ describe('calculate treatment', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { addPatient(state, 'green', 'green', Position.create(0, 0)); - addPersonnel(state); + addPersonnel(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -239,7 +253,7 @@ describe('calculate treatment', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { addPatient(state, 'green', 'green', Position.create(0, 0)); - addMaterial(state); + addMaterial(state, VehiclePosition.create('')); } ); expect(newState).toStrictEqual(beforeState); @@ -265,7 +279,10 @@ describe('calculate treatment', () => { 'red', Position.create(2, 2) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) + ).id; } ); assertCatering(beforeState, newState, [ @@ -297,7 +314,10 @@ describe('calculate treatment', () => { 'red', Position.create(3, 3) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) + ).id; } ); console.log(ids); @@ -330,7 +350,10 @@ describe('calculate treatment', () => { 'red', Position.create(20, 20) ).id; - ids.material = addMaterial(state, Position.create(0, 0)).id; + ids.material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) + ).id; } ); assertCatering(beforeState, newState, []); @@ -356,7 +379,10 @@ describe('calculate treatment', () => { 'red', Position.create(2, 2) ).id; - const material = addMaterial(state, Position.create(0, 0)); + const material = addMaterial( + state, + MapPosition.create({ x: 0, y: 0 }) + ); material.canCaterFor = cloneDeepMutable( CanCaterFor.create(1, 0, 1, 'and') ); diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts index 49e84c6da..6a88929cf 100644 --- a/shared/src/store/action-reducers/utils/spatial-elements.ts +++ b/shared/src/store/action-reducers/utils/spatial-elements.ts @@ -60,6 +60,10 @@ export function updateElementPosition( ); } element.position = cloneDeepMutable(targetPosition); + element.metaPosition = { + type: 'coordinates', + position: cloneDeepMutable(targetPosition), + }; updateTreatments(state, element); } diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts index 6db4d99bb..c0704b6b3 100644 --- a/shared/src/store/action-reducers/vehicle.ts +++ b/shared/src/store/action-reducers/vehicle.ts @@ -150,10 +150,18 @@ export namespace VehicleActionReducers { } draftState.vehicles[vehicle.id] = cloneDeepMutable(vehicle); for (const material of cloneDeepMutable(materials)) { + material.metaPosition = { + type: 'vehicle', + vehicleId: vehicle.id, + }; draftState.materials[material.id] = material; addElementPosition(draftState, 'materials', material.id); } for (const person of cloneDeepMutable(personnel)) { + person.metaPosition = { + type: 'vehicle', + vehicleId: vehicle.id, + }; draftState.personnel[person.id] = person; addElementPosition(draftState, 'personnel', person.id); } @@ -167,6 +175,10 @@ export namespace VehicleActionReducers { reducer: (draftState, { vehicleId, targetPosition }) => { const vehicle = getElement(draftState, 'vehicles', vehicleId); vehicle.position = cloneDeepMutable(targetPosition); + vehicle.metaPosition = { + type: 'coordinates', + position: cloneDeepMutable(targetPosition), + }; return draftState; }, rights: 'participant', @@ -201,12 +213,13 @@ export namespace VehicleActionReducers { action: UnloadVehicleAction, reducer: (draftState, { vehicleId }) => { const vehicle = getElement(draftState, 'vehicles', vehicleId); - const unloadPosition = vehicle.position; - if (!unloadPosition) { + const unloadMetaPosition = vehicle.metaPosition; + if (unloadMetaPosition.type !== 'coordinates') { throw new ReducerError( - `Vehicle with id ${vehicleId} is currently in transfer` + `Vehicle with id ${vehicleId} is currently not on the map` ); } + const unloadPosition = unloadMetaPosition.position; const materialIds = Object.keys(vehicle.materialIds); const personnelIds = Object.keys(vehicle.personnelIds); const patientIds = Object.keys(vehicle.patientIds); @@ -292,6 +305,10 @@ export namespace VehicleActionReducers { `Material with id ${material.id} is not assignable to the vehicle with id ${vehicle.id}` ); } + material.metaPosition = { + type: 'vehicle', + vehicleId, + }; removeElementPosition(draftState, 'materials', material.id); break; } @@ -311,6 +328,10 @@ export namespace VehicleActionReducers { `Personnel with id ${personnel.id} is not assignable to the vehicle with id ${vehicle.id}` ); } + personnel.metaPosition = { + type: 'vehicle', + vehicleId, + }; removeElementPosition( draftState, 'personnel', @@ -334,10 +355,22 @@ export namespace VehicleActionReducers { } vehicle.patientIds[elementToBeLoadedId] = true; + patient.metaPosition = { + type: 'vehicle', + vehicleId, + }; removeElementPosition(draftState, 'patients', patient.id); // Load in all materials Object.keys(vehicle.materialIds).forEach((materialId) => { + getElement( + draftState, + 'materials', + materialId + ).metaPosition = { + type: 'vehicle', + vehicleId, + }; removeElementPosition( draftState, 'materials', @@ -354,6 +387,14 @@ export namespace VehicleActionReducers { .transfer === undefined ) .forEach((personnelId) => { + getElement( + draftState, + 'personnel', + personnelId + ).metaPosition = { + type: 'vehicle', + vehicleId, + }; removeElementPosition( draftState, 'personnel', diff --git a/shared/src/utils/validators/is-metaposition.ts b/shared/src/utils/validators/is-metaposition.ts new file mode 100644 index 000000000..e9999b011 --- /dev/null +++ b/shared/src/utils/validators/is-metaposition.ts @@ -0,0 +1,36 @@ +import { Type } from 'class-transformer'; +import { MapPosition } from '../../models/utils/map-position'; +import type { MetaPosition } from '../../models/utils/meta-position'; +import { SimulatedRegionPosition } from '../../models/utils/simulated-region-position'; +import { TransferPosition } from '../../models/utils/transfer-position'; +import { VehiclePosition } from '../../models/utils/vehicle-position'; +import { IsLiteralUnion } from './is-literal-union'; + +class MetaPositionBase { + @IsLiteralUnion({ + coordinates: true, + simulatedRegion: true, + transfer: true, + vehicle: true, + }) + public type: MetaPosition['type']; + + constructor(type: MetaPosition['type']) { + this.type = type; + } +} + +// eslint-disable-next-line @typescript-eslint/naming-convention +export const IsMetaPosition = () => + Type(() => MetaPositionBase, { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: [ + { name: 'coordinates', value: MapPosition }, + { name: 'simulatedRegion', value: SimulatedRegionPosition }, + { name: 'transfer', value: TransferPosition }, + { name: 'vehicle', value: VehiclePosition }, + ], + }, + }); From 952303ee21e3e81fd17bbfc6e4af3ea8635d316f Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Wed, 25 Jan 2023 11:13:56 +0000 Subject: [PATCH 14/58] Initialize the optimisticUpdateHandler only after the store has the exercise (#622) * Fixes "Features disappear from the map in imported exercises" #621 * Can be observed when two actions are simultaneously optimistically proposed, and the client didn't receive any other action from the server before --- frontend/src/app/core/exercise.service.ts | 54 ++++++++++++++--------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/core/exercise.service.ts b/frontend/src/app/core/exercise.service.ts index a64c2aeb4..2e9de72de 100644 --- a/frontend/src/app/core/exercise.service.ts +++ b/frontend/src/app/core/exercise.service.ts @@ -54,28 +54,11 @@ export class ExerciseService { ...socketIoTransports, }); - private readonly optimisticActionHandler = new OptimisticActionHandler< + private optimisticActionHandler?: OptimisticActionHandler< ExerciseAction, ExerciseState, SocketResponse - >( - (exercise) => - this.store.dispatch(createSetExerciseStateAction(exercise)), - () => selectStateSnapshot(selectExerciseState, this.store), - (action) => this.store.dispatch(createApplyServerActionAction(action)), - async (action) => { - const response = await new Promise((resolve) => { - this.socket.emit('proposeAction', action, resolve); - }); - if (!response.success) { - this.messageService.postError({ - title: 'Fehler beim Senden der Aktion', - error: response.message, - }); - } - return response; - } - ); + >; constructor( private readonly store: Store, @@ -83,7 +66,7 @@ export class ExerciseService { ) { this.socket.on('performAction', (action: ExerciseAction) => { freeze(action, true); - this.optimisticActionHandler.performAction(action); + this.optimisticActionHandler?.performAction(action); }); this.socket.on('disconnect', (reason) => { if (reason === 'io client disconnect') { @@ -156,7 +139,32 @@ export class ExerciseService { clientName ) ); - // Only start them after the correct state is in the store + // Only do this after the correct state is in the store + this.optimisticActionHandler = new OptimisticActionHandler< + ExerciseAction, + ExerciseState, + SocketResponse + >( + (exercise) => + this.store.dispatch(createSetExerciseStateAction(exercise)), + () => selectStateSnapshot(selectExerciseState, this.store), + (action) => + this.store.dispatch(createApplyServerActionAction(action)), + async (action) => { + const response = await new Promise( + (resolve) => { + this.socket.emit('proposeAction', action, resolve); + } + ); + if (!response.success) { + this.messageService.postError({ + title: 'Fehler beim Senden der Aktion', + error: response.message, + }); + } + return response; + } + ); this.startNotifications(); return true; } @@ -167,6 +175,7 @@ export class ExerciseService { public leaveExercise() { this.socket.disconnect(); this.stopNotifications(); + this.optimisticActionHandler = undefined; this.store.dispatch(createLeaveExerciseAction()); } @@ -178,7 +187,8 @@ export class ExerciseService { public async proposeAction(action: ExerciseAction, optimistic = false) { if ( selectStateSnapshot(selectExerciseStateMode, this.store) !== - 'exercise' + 'exercise' || + this.optimisticActionHandler === undefined ) { // Especially during timeTravel, buttons that propose actions are only deactivated via best effort this.messageService.postError({ From bd560a7d4b181fa5697843641d977df1dcaf1ca1 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Thu, 26 Jan 2023 08:37:58 +0000 Subject: [PATCH 15/58] Patients are automatically triaged without any personnel on the map (#624) * Fix incorrect import of isEmpty This caused "Patients are automatically triaged without any personnel on the map" #623 * Disallow isEmpty imports from class-validator via eslint --- .eslint/typescript.eslintrc.cjs | 6 ++++++ shared/src/models/patient.ts | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/.eslint/typescript.eslintrc.cjs b/.eslint/typescript.eslintrc.cjs index 3bacc61cd..acabc7cd0 100644 --- a/.eslint/typescript.eslintrc.cjs +++ b/.eslint/typescript.eslintrc.cjs @@ -110,6 +110,12 @@ module.exports = { name: 'lodash', message: 'Please use lodash-es instead.', }, + { + name: 'class-validator', + importNames: ['isEmpty'], + message: + 'You probably want to import this from lodash-es instead.', + }, ], patterns: [ { diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index 29fdf2a7d..4942509ed 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -9,8 +9,8 @@ import { IsBoolean, IsString, MaxLength, - isEmpty, } from 'class-validator'; +import { isEmpty } from 'lodash-es'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsLiteralUnion, IsIdMap, IsUUIDSet } from '../utils/validators'; import { IsMetaPosition } from '../utils/validators/is-metaposition'; From 4e8af6d0f93291eccaf3248f01b4865ae9851d5a Mon Sep 17 00:00:00 2001 From: Lukas Hagen <43916057+Greenscreen23@users.noreply.github.com> Date: Thu, 26 Jan 2023 11:14:40 +0100 Subject: [PATCH 16/58] =?UTF-8?q?Add=20Image=20for=20Johanniter=20Akademie?= =?UTF-8?q?=20NRW,=20Campus=20M=C3=BCnster=20der=20Johanniter-Unfall-Hilfe?= =?UTF-8?q?=20e.V.=20(JUH)=20(#619)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Image for Johanniter Akademie NRW, Campus Münster der Johanniter-Unfall-Hilfe e.V. (JUH) * Fix linter * Mention JUH in Readme * Scale down the malteser logo and add the new 22/23 project team to the landing page * Add our year to the landing page --- README.md | 2 +- .../landing-page/landing-page.component.html | 34 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 76b08ac5a..946347136 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The concept is as follows: - After the exercise is started, _patients_ that are not adequately treated by _personnel_ and _material_ can deteriorate and die. The goal of the _participants_ is to prevent the _patients_ from dying and transport them to the _hospitals_. To do this effectively they have to communicate with each other (via real radio devices, or remote via third-party services) and make the right decisions. - Afterward, the exercise can be evaluated via statistics and a "time-travel" feature. -This simulation has been designed in cooperation with and with support from the [Federal Academy for Civil Protection and Civil Defence](https://www.bbk.bund.de/DE/Themen/Akademie-BABZ/akademie-babz_node.html) of the [Federal Office of Civil Protection and Disaster Assistance Germany](https://www.bbk.bund.de/DE/Home/home_node.html), who are the original copyright holders of the analog "FüSim MANV" simulation system, and the [Malteser Hilfsdienst e.V. Berlin](https://www.malteser-berlin.de/). +This simulation has been designed in cooperation with and with support from the [Federal Academy for Civil Protection and Civil Defence](https://www.bbk.bund.de/DE/Themen/Akademie-BABZ/akademie-babz_node.html) of the [Federal Office of Civil Protection and Disaster Assistance Germany](https://www.bbk.bund.de/DE/Home/home_node.html), who are the original copyright holders of the analog "FüSim MANV" simulation system, and the [Malteser Hilfsdienst e.V. Berlin](https://www.malteser-berlin.de/) as well as the [Johanniter Akademie NRW, Campus Münster der Johanniter-Unfall-Hilfe e.V.](https://www.johanniter.de/bildungseinrichtungen/johanniter-akademie/johanniter-akademie-nordrhein-westfalen/standorte-der-akademie-in-nordrhein-westfalen/campus-muenster/) The simulation is implemented as a web application with an Angular frontend and NodeJS backend. diff --git a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html index 66e862e4d..b1c122745 100644 --- a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html +++ b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html @@ -91,7 +91,7 @@

    Ãœber dieses Projekt

    Diese Webseite entstand im Rahmen eines sogenannten Bachelorprojekts am Hasso-Plattner-Institut Potsdam in den Jahren - 2021 und 2022. Sie stellt eine digitale Umsetzung der + 2021, 2022 und 2023. Sie stellt eine digitale Umsetzung der Führungssimulation MANV (FüSim MANV) dar, einer von der Projektbeteiligte
    /> Malteser Berlin + + Johanniter Akademie NRW, Campus Münster
    - Projektteam: - Julian Schmidt, Clemens Schielicke, - Florian Krummrey, Marvin Müller-Mettnau, + Projektteam 2022/23: + Lukas Hagen, + Nils Hanff, + Benildur Nickel und + Lukas Radermacher +
    + + Projektteam 2021/22: + Julian Schmidt, + Clemens Schielicke, Florian + Krummrey und Marvin Müller-Mettnau +
    + + Betreuende: Matthias Barkowsky From c2992d5da3a577c80bcf1786874f22cd3ff76f97 Mon Sep 17 00:00:00 2001 From: Lukas Hagen <43916057+Greenscreen23@users.noreply.github.com> Date: Thu, 26 Jan 2023 15:17:28 +0100 Subject: [PATCH 17/58] Feature/603 use opaque fill style for simulated regions (#608) * Refactor viewports and simulated regions to be polygons instead of lines * Add opaque fill to simulated regions * Fix linter * WIP * Refactor Coordinates and Points to Compositions * Update readme accordingly * Change default type of SubstituteCoordinateForPoint to never as it should never happen * Fix typo * Increase alpha value to 80% * Fix bug where features did not sync their movement to other clients * Fix linter * Refactor lambda function to geometry helpers and refactor ElementFeature ElementFeature (which had to extend Feature) has been replaced by Feature because according to ol docs there are no classes extending Feature * Remove ElementManager.recreateFeature() * Refactor lambdas to function in Geometry Helper subclasses * Rename getNextPosition to interpolateCoordinates * Refactor polygon geometry helper names in map lambda function * Remove comment and type cast Co-authored-by: Julian Schmidt --- frontend/README.md | 2 +- .../catering-lines-feature-manager.ts | 3 +- .../delete-feature-manager.ts | 2 +- .../element-feature-manager.ts | 198 ------------------ .../feature-managers/element-manager.ts | 20 +- .../map-images-feature-manager.ts | 7 +- .../material-feature-manager.ts | 7 +- .../moveable-feature-manager.ts | 126 +++++++++++ .../patient-feature-manager.ts | 7 +- .../personnel-feature-manager.ts | 7 +- .../simulated-region-feature-manager.ts | 37 ++-- .../transfer-lines-feature-manager.ts | 3 +- .../transfer-point-feature-manager.ts | 7 +- .../vehicle-feature-manager.ts | 7 +- .../viewport-feature-manager.ts | 34 ++- .../exercise-map/utility/feature-manager.ts | 9 +- .../exercise-map/utility/geometry-helper.ts | 71 +++++++ .../exercise-map/utility/movement-animator.ts | 85 ++------ .../exercise-map/utility/ol-map-manager.ts | 7 +- .../utility/point-geometry-helper.ts | 43 ++++ .../utility/polygon-geometry-helper.ts | 61 ++++++ .../utility/resize-rectangle-interaction.ts | 12 +- .../utility/translate-interaction.ts | 28 +-- frontend/src/assets/simulated-region.svg | 8 +- 24 files changed, 407 insertions(+), 384 deletions(-) delete mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts diff --git a/frontend/README.md b/frontend/README.md index 7b1fafa4c..1c0cfb571 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -110,7 +110,7 @@ The [ExerciseMapComponent](src/app/pages/exercises/exercise/shared/exercise-map/ The [OlMapManager](src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts) manages all the OpenLayers stuff and renders the map on the canvas. The map consists of different layers. Each layer only displays one kind of element. How an element in this layer should be rendered and what interactions are possible is defined in the [specific ElementFeatureManagers](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers). -They all inherit from [ElementFeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts) and make mostly use of `Helper` classes to add additional functionality via composition. +The feature managers for features that should be moveable by the user extend [MoveableFeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts), which is the central point for all movement logic. They have a custom API that allows reacting to changes in an element ([ElementManager](src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts)) and an API that allows for interaction with other elements via the OlMapManager ([FeatureManager](src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts)). ## Action proposals diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index 388e360ee..d3088c938 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -14,10 +14,9 @@ export class CateringLinesFeatureManager extends ElementManager< CateringLine, LineString, - Feature, ReadonlySet > - implements FeatureManager> + implements FeatureManager { readonly type = 'cateringLines'; readonly unsupportedChangeProperties = new Set(['id'] as const); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts index b8e423e8a..b4b2f07f3 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts @@ -21,7 +21,7 @@ function calculateTopRightViewPoint(view: View) { return new Point([extent[0]!, extent[1]!]); } -export class DeleteFeatureManager implements FeatureManager> { +export class DeleteFeatureManager implements FeatureManager { constructor( private readonly store: Store, public readonly layer: VectorLayer>, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts deleted file mode 100644 index 93c081916..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-feature-manager.ts +++ /dev/null @@ -1,198 +0,0 @@ -import type { - ExerciseState, - Position, - Size, - UUID, -} from 'digital-fuesim-manv-shared'; -import { isArray } from 'lodash-es'; -import type { MapBrowserEvent } from 'ol'; -import { Feature } from 'ol'; -import type { Coordinate } from 'ol/coordinate'; -import { LineString } from 'ol/geom'; -import Point from 'ol/geom/Point'; -import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; -import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; -import { Subject } from 'rxjs'; -import type { WithPosition } from '../../utility/types/with-position'; -import type { FeatureManager } from '../utility/feature-manager'; -import type { Coordinates } from '../utility/movement-animator'; -import { MovementAnimator } from '../utility/movement-animator'; -import type { OpenPopupOptions } from '../utility/popup-manager'; -import { TranslateInteraction } from '../utility/translate-interaction'; -import { ElementManager } from './element-manager'; - -export interface PositionableElement { - readonly id: UUID; - readonly position: Position; -} - -export interface ResizableElement extends PositionableElement { - size: Size; -} - -function isLineString( - feature: Feature -): feature is Feature { - return feature.getGeometry()!.getType() === 'LineString'; -} - -export function isCoordinateArray( - coordinates: Coordinate | Coordinate[] -): coordinates is Coordinate[] { - return isArray(coordinates[0]); -} - -export const createPoint = (element: WithPosition): Feature => - new Feature(new Point([element.position.x, element.position.y])); - -export const createLineString = ( - element: ResizableElement -): Feature => - new Feature(new LineString(getCoordinateArray(element))); - -export function getCoordinateArray(element: ResizableElement) { - return [ - [element.position.x, element.position.y], - [element.position.x + element.size.width, element.position.y], - [ - element.position.x + element.size.width, - element.position.y - element.size.height, - ], - [element.position.x, element.position.y - element.size.height], - [element.position.x, element.position.y], - ]; -} - -/** - * The base class for all element feature managers. - * * manages the position of the element - * * manages the default interactions of the element - */ -export abstract class ElementFeatureManager< - Element extends PositionableElement, - FeatureType extends LineString | Point = Point, - ElementFeature extends Feature = Feature - > - extends ElementManager< - Element, - FeatureType, - ElementFeature, - ReadonlySet - > - implements FeatureManager -{ - abstract override readonly type: keyof ExerciseState; - public readonly togglePopup$ = new Subject>(); - protected readonly movementAnimator = new MovementAnimator( - this.olMap, - this.layer - ); - constructor( - protected readonly olMap: OlMap, - public readonly layer: VectorLayer>, - private readonly proposeMovementAction: ( - newPosition: FeatureType extends Point ? Position : Position[], - element: Element - ) => void, - private readonly createElement: (element: Element) => ElementFeature - ) { - super(); - } - - override unsupportedChangeProperties: ReadonlySet = new Set( - [] as const - ); - createFeature(element: Element): ElementFeature { - const elementFeature = this.createElement(element); - elementFeature.setId(element.id); - this.layer.getSource()!.addFeature(elementFeature); - TranslateInteraction.onTranslateEnd( - elementFeature, - (newPosition) => { - this.proposeMovementAction(newPosition, element); - } - ); - return elementFeature; - } - - isFeatureTranslatable(feature: ElementFeature) { - return true; - } - - deleteFeature(element: Element, elementFeature: ElementFeature): void { - this.layer.getSource()!.removeFeature(elementFeature); - elementFeature.dispose(); - this.movementAnimator.stopMovementAnimation(elementFeature); - } - - changeFeature( - oldElement: Element, - newElement: Element, - // It is too much work to correctly type this param with {@link unsupportedChangeProperties} - changedProperties: ReadonlySet, - elementFeature: ElementFeature - ): void { - if (changedProperties.has('position')) { - const newFeature = this.getFeatureFromElement(newElement); - if (!newFeature) { - throw new TypeError('newFeature undefined'); - } - this.movementAnimator.animateFeatureMovement( - elementFeature, - (isLineString(newFeature) - ? (newFeature.getGeometry()! as LineString).getCoordinates() - : [ - newElement.position.x, - newElement.position.y, - ]) as Coordinates - ); - } - // If the style has updated, we need to redraw the feature - elementFeature.changed(); - } - - getFeatureFromElement(element: Element): ElementFeature | undefined { - return ( - (this.layer - .getSource()! - .getFeatureById(element.id) as ElementFeature | null) ?? - undefined - ); - } - - public getCenter(feature: ElementFeature): Coordinate { - const coordinates = feature.getGeometry()!.getCoordinates(); - if (!isCoordinateArray(coordinates)) { - return coordinates; - } - // We need index 0 and 2 for the center - if (coordinates.length < 3) { - throw new Error(`Unexpectedly short array: ${coordinates}`); - } - return [ - coordinates[0]![0]! + - (coordinates[2]![0]! - coordinates[0]![0]!) / 2, - coordinates[0]![1]! + - (coordinates[2]![1]! - coordinates[0]![1]!) / 2, - ]; - } - - public onFeatureClicked( - event: MapBrowserEvent, - feature: ElementFeature - // eslint-disable-next-line @typescript-eslint/no-empty-function - ): void {} - - /** - * The standard implementation is to ignore these events. - */ - public onFeatureDrop( - dropEvent: TranslateEvent, - droppedFeature: Feature, - droppedOnFeature: ElementFeature - ): boolean { - return false; - } -} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index 4fae9eb95..4ff6e3b48 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -1,18 +1,17 @@ import type { ImmutableJsonObject } from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; -import type { LineString, Point } from 'ol/geom'; +import type { Geometry } from 'ol/geom'; import { generateChangedProperties } from '../utility/generate-changed-properties'; /** * Provides an Api to update a feature based on changes to an element (patient, vehicle, etc.). * * {@link Element} is the immutable JSON object (Patient, Vehicle, etc.) - * {@link ElementFeature} is the OpenLayers Feature that should be rendered to represent the {@link Element}. + * {@link Feature} is the OpenLayers Feature that should be rendered to represent the {@link Element}. */ export abstract class ElementManager< Element extends ImmutableJsonObject, - FeatureType extends LineString | Point, - ElementFeature extends Feature, + FeatureType extends Geometry, UnsupportedChangeProperties extends ReadonlySet, SupportedChangeProperties extends Exclude< ReadonlySet, @@ -78,22 +77,17 @@ export abstract class ElementManager< ); } - public recreateFeature(element: Element) { - this.onElementDeleted(element); - this.onElementCreated(element); - } - /** * Adds a new feature representing the {@link element} to the map. */ - abstract createFeature(element: Element): ElementFeature; + abstract createFeature(element: Element): Feature; /** * Delete the {@link elementFeature} representing the {@link element} from the map. */ abstract deleteFeature( element: Element, - elementFeature: ElementFeature + elementFeature: Feature ): void; /** @@ -109,12 +103,12 @@ export abstract class ElementManager< oldElement: Element, newElement: Element, changedProperties: SupportedChangeProperties, - elementFeature: ElementFeature + elementFeature: Feature ): void; abstract getFeatureFromElement( element: Element - ): ElementFeature | undefined; + ): Feature | undefined; public getElementFromFeature(feature: Feature) { return { diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts index 43d58bc70..cee02e94a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts @@ -10,11 +10,12 @@ import type { AppState } from 'src/app/state/app.state'; import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { MapImagePopupComponent } from '../shared/map-image-popup/map-image-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class MapImageFeatureManager extends ElementFeatureManager { +export class MapImageFeatureManager extends MoveableFeatureManager { readonly type = 'mapImages'; private readonly imageStyleHelper = new ImageStyleHelper( (feature) => this.getElementFromFeature(feature)!.value.image @@ -37,7 +38,7 @@ export class MapImageFeatureManager extends ElementFeatureManager { targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => { const style = this.imageStyleHelper.getStyle( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts index b6da79e5a..44888b48e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts @@ -8,12 +8,13 @@ import type VectorSource from 'ol/source/Vector'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { WithPosition } from '../../utility/types/with-position'; import { MaterialPopupComponent } from '../shared/material-popup/material-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class MaterialFeatureManager extends ElementFeatureManager< +export class MaterialFeatureManager extends MoveableFeatureManager< WithPosition > { readonly type = 'materials'; @@ -49,7 +50,7 @@ export class MaterialFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ this.nameStyleHelper.getStyle(feature as Feature, resolution), diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts new file mode 100644 index 000000000..4e8f56ea5 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -0,0 +1,126 @@ +import type { ExerciseState } from 'digital-fuesim-manv-shared'; +import type { MapBrowserEvent, Feature } from 'ol'; +import type Point from 'ol/geom/Point'; +import type { TranslateEvent } from 'ol/interaction/Translate'; +import type VectorLayer from 'ol/layer/Vector'; +import type OlMap from 'ol/Map'; +import type VectorSource from 'ol/source/Vector'; +import { Subject } from 'rxjs'; +import type { FeatureManager } from '../utility/feature-manager'; +import { MovementAnimator } from '../utility/movement-animator'; +import type { + GeometryHelper, + GeometryWithCoordinates, + PositionableElement, + Positions, +} from '../utility/geometry-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; +import { TranslateInteraction } from '../utility/translate-interaction'; +import { ElementManager } from './element-manager'; + +/** + * The base class for all element feature managers. + * * manages the position of the element + * * manages the default interactions of the element + */ +export abstract class MoveableFeatureManager< + Element extends PositionableElement, + FeatureType extends GeometryWithCoordinates = Point + > + extends ElementManager> + implements FeatureManager +{ + abstract override readonly type: keyof ExerciseState; + public readonly togglePopup$ = new Subject>(); + protected readonly movementAnimator: MovementAnimator; + constructor( + protected readonly olMap: OlMap, + public readonly layer: VectorLayer>, + private readonly proposeMovementAction: ( + newPosition: Positions, + element: Element + ) => void, + protected readonly geometryHelper: GeometryHelper + ) { + super(); + this.movementAnimator = new MovementAnimator( + this.olMap, + this.layer, + this.geometryHelper.interpolateCoordinates, + this.geometryHelper.getFeatureCoordinates + ); + } + + override unsupportedChangeProperties: ReadonlySet = new Set( + [] as const + ); + createFeature(element: Element): Feature { + const elementFeature = this.geometryHelper.create(element); + elementFeature.setId(element.id); + this.layer.getSource()!.addFeature(elementFeature); + TranslateInteraction.onTranslateEnd( + elementFeature, + (newPosition) => { + this.proposeMovementAction(newPosition, element); + }, + this.geometryHelper.getFeaturePosition + ); + return elementFeature; + } + + isFeatureTranslatable(feature: Feature) { + return true; + } + + deleteFeature( + element: Element, + elementFeature: Feature + ): void { + this.layer.getSource()!.removeFeature(elementFeature); + elementFeature.dispose(); + this.movementAnimator.stopMovementAnimation(elementFeature); + } + + changeFeature( + oldElement: Element, + newElement: Element, + // It is too much work to correctly type this param with {@link unsupportedChangeProperties} + changedProperties: ReadonlySet, + elementFeature: Feature + ): void { + if (changedProperties.has('position')) { + this.movementAnimator.animateFeatureMovement( + elementFeature, + this.geometryHelper.getElementCoordinates(newElement) + ); + } + // If the style has updated, we need to redraw the feature + elementFeature.changed(); + } + + getFeatureFromElement(element: Element): Feature | undefined { + return ( + (this.layer + .getSource()! + .getFeatureById(element.id) as Feature | null) ?? + undefined + ); + } + + public onFeatureClicked( + event: MapBrowserEvent, + feature: Feature + // eslint-disable-next-line @typescript-eslint/no-empty-function + ): void {} + + /** + * The standard implementation is to ignore these events. + */ + public onFeatureDrop( + dropEvent: TranslateEvent, + droppedFeature: Feature, + droppedOnFeature: Feature + ): boolean { + return false; + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts index e2ff69fee..69acb7ba9 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts @@ -13,12 +13,13 @@ import { selectConfiguration } from 'src/app/state/application/selectors/exercis import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type { WithPosition } from '../../utility/types/with-position'; import { PatientPopupComponent } from '../shared/patient-popup/patient-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { CircleStyleHelper } from '../utility/style-helper/circle-style-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class PatientFeatureManager extends ElementFeatureManager< +export class PatientFeatureManager extends MoveableFeatureManager< WithPosition > { readonly type = 'patients'; @@ -81,7 +82,7 @@ export class PatientFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ this.imageStyleHelper.getStyle(feature as Feature, resolution), diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts index 3d42f47ee..183443f19 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts @@ -8,12 +8,13 @@ import type VectorSource from 'ol/source/Vector'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { WithPosition } from '../../utility/types/with-position'; import { PersonnelPopupComponent } from '../shared/personnel-popup/personnel-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class PersonnelFeatureManager extends ElementFeatureManager< +export class PersonnelFeatureManager extends MoveableFeatureManager< WithPosition > { readonly type = 'personnel'; @@ -49,7 +50,7 @@ export class PersonnelFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index acfa70e1d..f4cd2894c 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -2,10 +2,11 @@ import type { Store } from '@ngrx/store'; import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; import { Position, Size } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type LineString from 'ol/geom/LineString'; +import type { Polygon } from 'ol/geom'; import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; import type VectorSource from 'ol/source/Vector'; +import { Fill } from 'ol/style'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; import type { ExerciseService } from 'src/app/core/exercise.service'; @@ -15,16 +16,13 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { SimulatedRegionPopupComponent } from '../shared/simulated-region-popup/simulated-region-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; +import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; -import { - createLineString, - ElementFeatureManager, - getCoordinateArray, -} from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; export class SimulatedRegionFeatureManager - extends ElementFeatureManager - implements FeatureManager> + extends MoveableFeatureManager + implements FeatureManager { readonly type = 'simulatedRegions'; @@ -32,7 +30,7 @@ export class SimulatedRegionFeatureManager constructor( olMap: OlMap, - layer: VectorLayer>, + layer: VectorLayer>, private readonly exerciseService: ExerciseService, private readonly store: Store ) { @@ -43,22 +41,25 @@ export class SimulatedRegionFeatureManager exerciseService.proposeAction({ type: '[SimulatedRegion] Move simulated region', simulatedRegionId: simulatedRegion.id, - targetPosition: targetPositions[0]!, + targetPosition: targetPositions[0]![0]!, }); }, - createLineString + new PolygonGeometryHelper() ); this.layer.setStyle(this.style); } private readonly style = new Style({ + fill: new Fill({ + color: '#808080cc', + }), stroke: new Stroke({ color: '#cccc00', width: 2, }), }); - override createFeature(element: SimulatedRegion): Feature { + override createFeature(element: SimulatedRegion): Feature { const feature = super.createFeature(element); ResizeRectangleInteraction.onResize( feature, @@ -89,19 +90,15 @@ export class SimulatedRegionFeatureManager oldElement: SimulatedRegion, newElement: SimulatedRegion, changedProperties: ReadonlySet, - elementFeature: Feature + elementFeature: Feature ): void { if ( changedProperties.has('position') || changedProperties.has('size') ) { - const newFeature = this.getFeatureFromElement(newElement); - if (!newFeature) { - throw new TypeError('newFeature undefined'); - } this.movementAnimator.animateFeatureMovement( elementFeature, - getCoordinateArray(newElement) + this.geometryHelper.getElementCoordinates(newElement) ); } // If the style has updated, we need to redraw the feature @@ -136,9 +133,7 @@ export class SimulatedRegionFeatureManager }); } - public override isFeatureTranslatable( - feature: Feature - ): boolean { + public override isFeatureTranslatable(feature: Feature): boolean { return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index 999de802b..97aa951f2 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -14,10 +14,9 @@ export class TransferLinesFeatureManager extends ElementManager< TransferLine, LineString, - Feature, ReadonlySet > - implements FeatureManager> + implements FeatureManager { readonly type = 'transferLines'; readonly unsupportedChangeProperties = new Set(['id'] as const); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 3682c6c10..1dfcda572 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -13,12 +13,13 @@ import { selectCurrentRole } from 'src/app/state/application/selectors/shared.se import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ChooseTransferTargetPopupComponent } from '../shared/choose-transfer-target-popup/choose-transfer-target-popup.component'; import { TransferPointPopupComponent } from '../shared/transfer-point-popup/transfer-point-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class TransferPointFeatureManager extends ElementFeatureManager { +export class TransferPointFeatureManager extends MoveableFeatureManager { readonly type = 'transferPoints'; private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); @@ -38,7 +39,7 @@ export class TransferPointFeatureManager extends ElementFeatureManager [ this.imageStyleHelper.getStyle( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts index 0a6e489f2..c2f77b025 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts @@ -9,12 +9,13 @@ import type VectorSource from 'ol/source/Vector'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { WithPosition } from '../../utility/types/with-position'; import { VehiclePopupComponent } from '../shared/vehicle-popup/vehicle-popup.component'; +import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; -import { createPoint, ElementFeatureManager } from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; -export class VehicleFeatureManager extends ElementFeatureManager< +export class VehicleFeatureManager extends MoveableFeatureManager< WithPosition > { readonly type = 'vehicles'; @@ -50,7 +51,7 @@ export class VehicleFeatureManager extends ElementFeatureManager< targetPosition, }); }, - createPoint + new PointGeometryHelper() ); this.layer.setStyle((feature, resolution) => [ this.nameStyleHelper.getStyle(feature as Feature, resolution), diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 5fa0b86d0..5cc97963b 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -3,7 +3,7 @@ import type { UUID } from 'digital-fuesim-manv-shared'; import { Position, Size, Viewport } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { Coordinate } from 'ol/coordinate'; -import type LineString from 'ol/geom/LineString'; +import type { Polygon } from 'ol/geom'; import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; import type VectorSource from 'ol/source/Vector'; @@ -16,12 +16,9 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ViewportPopupComponent } from '../shared/viewport-popup/viewport-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; +import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; -import { - createLineString, - ElementFeatureManager, - getCoordinateArray, -} from './element-feature-manager'; +import { MoveableFeatureManager } from './moveable-feature-manager'; export function isInViewport( coordinate: Coordinate, @@ -34,8 +31,8 @@ export function isInViewport( } export class ViewportFeatureManager - extends ElementFeatureManager - implements FeatureManager> + extends MoveableFeatureManager + implements FeatureManager { readonly type = 'viewports'; @@ -43,7 +40,7 @@ export class ViewportFeatureManager constructor( olMap: OlMap, - layer: VectorLayer>, + layer: VectorLayer>, private readonly exerciseService: ExerciseService, private readonly store: Store ) { @@ -54,22 +51,23 @@ export class ViewportFeatureManager exerciseService.proposeAction({ type: '[Viewport] Move viewport', viewportId: viewport.id, - targetPosition: targetPositions[0]!, + targetPosition: targetPositions[0]![0]!, }); }, - createLineString + new PolygonGeometryHelper() ); this.layer.setStyle(this.style); } private readonly style = new Style({ + fill: undefined, stroke: new Stroke({ color: '#fafaff', width: 2, }), }); - override createFeature(element: Viewport): Feature { + override createFeature(element: Viewport): Feature { const feature = super.createFeature(element); ResizeRectangleInteraction.onResize( feature, @@ -100,19 +98,15 @@ export class ViewportFeatureManager oldElement: Viewport, newElement: Viewport, changedProperties: ReadonlySet, - elementFeature: Feature + elementFeature: Feature ): void { if ( changedProperties.has('position') || changedProperties.has('size') ) { - const newFeature = this.getFeatureFromElement(newElement); - if (!newFeature) { - throw new TypeError('newFeature undefined'); - } this.movementAnimator.animateFeatureMovement( elementFeature, - getCoordinateArray(newElement) + this.geometryHelper.getElementCoordinates(newElement) ); } // If the style has updated, we need to redraw the feature @@ -147,9 +141,7 @@ export class ViewportFeatureManager }); } - public override isFeatureTranslatable( - feature: Feature - ): boolean { + public override isFeatureTranslatable(feature: Feature): boolean { return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts index 1f1ff45d1..463e3e83d 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts @@ -1,4 +1,5 @@ import type { Feature, MapBrowserEvent } from 'ol'; +import type { Geometry } from 'ol/geom'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; @@ -8,7 +9,7 @@ import type { OpenPopupOptions } from './popup-manager'; /** * The Api to interact with a feature */ -export interface FeatureManager> { +export interface FeatureManager { readonly layer: VectorLayer; /** @@ -23,13 +24,13 @@ export interface FeatureManager> { */ onFeatureClicked: ( event: MapBrowserEvent, - feature: ElementFeature + feature: Feature ) => void; /** * @returns whether the feature can be moved by the user */ - isFeatureTranslatable: (feature: ElementFeature) => boolean; + isFeatureTranslatable: (feature: Feature) => boolean; /** * @param dropEvent The drop event that triggered the call @@ -40,6 +41,6 @@ export interface FeatureManager> { onFeatureDrop: ( dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: ElementFeature + droppedOnFeature: Feature ) => boolean; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts new file mode 100644 index 000000000..539119712 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/geometry-helper.ts @@ -0,0 +1,71 @@ +import type { Position, Size, UUID } from 'digital-fuesim-manv-shared'; +import type { Feature } from 'ol'; +import type { Coordinate } from 'ol/coordinate'; +import type { Geometry } from 'ol/geom'; + +export interface PositionableElement { + readonly id: UUID; + readonly position: Position; +} + +export type ResizableElement = PositionableElement & { + size: Size; +}; + +export type GeometryWithCoordinates = Geometry & { + getCoordinates: () => unknown; + setCoordinates: (coordinates: any[]) => void; +}; +/** + * Typescript doesn't error when T doesn't satisfy + * getCoordinates: () => unknown. + * Instead, the inferred type is null. We exclude this type + * to exchange it with never + */ +export type Coordinates = Exclude< + ReturnType, + null +>; + +type ArrayElement = ArrayType extends readonly (infer ElementType)[] + ? ElementType + : never; + +type SubstituteCoordinateForPoint = T extends Coordinate + ? Position + : T extends Array> + ? SubstituteCoordinateForPoint>[] + : never; + +export type Positions = + SubstituteCoordinateForPoint>; + +export interface CoordinatePair { + startPosition: Coordinates; + endPosition: Coordinates; +} + +export interface GeometryHelper< + T extends GeometryWithCoordinates, + Element extends PositionableElement = PositionableElement +> { + create: (element: Element) => Feature; + getElementCoordinates: (element: Element) => Coordinates; + getFeatureCoordinates: (feature: Feature) => Coordinates; + interpolateCoordinates: ( + positions: CoordinatePair, + progress: number + ) => Coordinates; + getFeaturePosition: (feature: Feature) => Positions; +} + +export const interpolate = ( + startCoordinate: Coordinate, + endCoordinate: Coordinate, + lerpFactor: number +): Coordinate => [ + startCoordinate[0]! + + (endCoordinate[0]! - startCoordinate[0]!) * lerpFactor, + startCoordinate[1]! + + (endCoordinate[1]! - startCoordinate[1]!) * lerpFactor, +]; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts index ea7f248bb..2a8945414 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/movement-animator.ts @@ -4,25 +4,18 @@ import type OlMap from 'ol/Map'; import type RenderEvent from 'ol/render/Event'; import type { Feature } from 'ol'; import { getVectorContext } from 'ol/render'; -import type Point from 'ol/geom/Point'; import type { UUID } from 'digital-fuesim-manv-shared'; -import { isArray, isEqual } from 'lodash-es'; -import type { LineString } from 'ol/geom'; -import type { Coordinate } from 'ol/coordinate'; - -export type Coordinates = T extends Point - ? Coordinate - : Coordinate[]; - -interface CoordinatePair { - startPosition: T; - endPosition: T; -} +import { isEqual } from 'lodash-es'; +import type { + Coordinates, + CoordinatePair, + GeometryWithCoordinates, +} from './geometry-helper'; /** * Animates the movement of a feature to a new position. */ -export class MovementAnimator { +export class MovementAnimator { /** * The time in milliseconds how long the moving animation should take */ @@ -30,7 +23,12 @@ export class MovementAnimator { constructor( private readonly olMap: OlMap, - private readonly layer: VectorLayer + private readonly layer: VectorLayer, + private readonly interpolateCoordinates: ( + positions: CoordinatePair, + progress: number + ) => Coordinates, + private readonly getCoordinates: (feature: Feature) => Coordinates ) {} /** @@ -52,12 +50,8 @@ export class MovementAnimator { endPosition: Coordinates ) { const startTime = Date.now(); - const featureGeometry = feature.getGeometry()!; - const startPosition = - featureGeometry.getCoordinates() as Coordinates; - // Stop an ongoing movement animation - this.stopMovementAnimation(feature as Feature); - // We don't have to animate this + const startPosition = this.getCoordinates(feature); + this.stopMovementAnimation(feature); if (isEqual(startPosition, endPosition)) { return; } @@ -76,25 +70,6 @@ export class MovementAnimator { this.olMap.render(); } - private isCoordinateArrayPair( - coordinates: CoordinatePair> - ): coordinates is CoordinatePair> { - return isArray(coordinates.startPosition[0]); - } - - private interpolate( - startCoordinate: Coordinate, - endCoordinate: Coordinate, - lerpFactor: number - ): Coordinate { - return [ - startCoordinate[0]! + - (endCoordinate[0]! - startCoordinate[0]!) * lerpFactor, - startCoordinate[1]! + - (endCoordinate[1]! - startCoordinate[1]!) * lerpFactor, - ]; - } - private setCoordinates(featureGeometry: T, coordinates: Coordinates) { // The ol typings are incorrect featureGeometry.setCoordinates(coordinates as any); @@ -107,7 +82,7 @@ export class MovementAnimator { private animationTick( event: RenderEvent, startTime: number, - positions: CoordinatePair>, + positions: CoordinatePair, feature: Feature ) { const featureGeometry = feature.getGeometry()!; @@ -124,33 +99,7 @@ export class MovementAnimator { this.olMap.render(); return; } - // If we have coordinate arrays, there must be at least as many endCoordinates as startCoordinates - if ( - this.isCoordinateArrayPair(positions) && - positions.startPosition.length > positions.endPosition.length - ) { - throw new Error( - `Got unexpected too few endPositions: ${JSON.stringify( - positions - )}` - ); - } - // The next position is calculated by a linear interpolation between the start and end position(s) - const nextPosition = ( - this.isCoordinateArrayPair(positions) - ? positions.startPosition.map((startPos, index) => - this.interpolate( - startPos, - positions.endPosition[index]!, - progress - ) - ) - : this.interpolate( - positions.startPosition as Coordinates, - positions.endPosition as Coordinates, - progress - ) - ) as Coordinates; + const nextPosition = this.interpolateCoordinates(positions, progress); this.setCoordinates(featureGeometry, nextPosition); getVectorContext(event).drawGeometry(featureGeometry); this.olMap.render(); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 4a7b944fc..a6946ebc4 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -7,6 +7,7 @@ import type { } from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; import { Overlay, View } from 'ol'; +import type { Polygon } from 'ol/geom'; import type Geometry from 'ol/geom/Geometry'; import type LineString from 'ol/geom/LineString'; import type Point from 'ol/geom/Point'; @@ -126,8 +127,8 @@ export class OlMapManager { const patientLayer = this.createElementLayer(); const personnelLayer = this.createElementLayer(); const materialLayer = this.createElementLayer(); - const viewportLayer = this.createElementLayer(); - const simulatedRegionLayer = this.createElementLayer(); + const viewportLayer = this.createElementLayer(); + const simulatedRegionLayer = this.createElementLayer(); const mapImagesLayer = this.createElementLayer(10_000); const deleteFeatureLayer = this.createElementLayer(); this.popupOverlay = new Overlay({ @@ -377,7 +378,7 @@ export class OlMapManager { private registerFeatureElementManager< Element extends ImmutableJsonObject, T extends MergeIntersection< - ElementManager & FeatureManager + ElementManager & FeatureManager > >( featureManager: T, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts new file mode 100644 index 000000000..406bdce5d --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts @@ -0,0 +1,43 @@ +import { Position } from 'digital-fuesim-manv-shared'; +import { Feature } from 'ol'; +import { Point } from 'ol/geom'; +import type { WithPosition } from '../../utility/types/with-position'; +import type { + CoordinatePair, + Coordinates, + GeometryHelper, + Positions, +} from './geometry-helper'; +import { interpolate } from './geometry-helper'; + +export class PointGeometryHelper implements GeometryHelper { + create(element: WithPosition): Feature { + return new Feature(new Point(this.getElementCoordinates(element))); + } + + getElementCoordinates(element: WithPosition): Coordinates { + return [element.position.x, element.position.y]; + } + + getFeatureCoordinates(feature: Feature): Coordinates { + return feature.getGeometry()!.getCoordinates(); + } + + interpolateCoordinates( + positions: CoordinatePair, + progress: number + ): Coordinates { + return interpolate( + positions.startPosition, + positions.endPosition, + progress + ); + } + + getFeaturePosition(feature: Feature): Positions { + return Position.create( + this.getFeatureCoordinates(feature)[0]!, + this.getFeatureCoordinates(feature)[1]! + ); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts new file mode 100644 index 000000000..4cd61e95c --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts @@ -0,0 +1,61 @@ +import { Position } from 'digital-fuesim-manv-shared'; +import { Feature } from 'ol'; +import { Polygon } from 'ol/geom'; +import type { + CoordinatePair, + Coordinates, + GeometryHelper, + Positions, + ResizableElement, +} from './geometry-helper'; +import { interpolate } from './geometry-helper'; + +export class PolygonGeometryHelper + implements GeometryHelper +{ + create(element: ResizableElement): Feature { + return new Feature(new Polygon(this.getElementCoordinates(element))); + } + + getElementCoordinates(element: ResizableElement): Coordinates { + return [ + [ + [element.position.x, element.position.y], + [element.position.x + element.size.width, element.position.y], + [ + element.position.x + element.size.width, + element.position.y - element.size.height, + ], + [element.position.x, element.position.y - element.size.height], + [element.position.x, element.position.y], + ], + ]; + } + + getFeatureCoordinates(feature: Feature): Coordinates { + return feature.getGeometry()!.getCoordinates(); + } + + interpolateCoordinates( + positions: CoordinatePair, + progress: number + ): Coordinates { + return positions.startPosition.map((coordinates, coordinatesIndex) => + coordinates.map((startCoordinate, coordinateIndex) => + interpolate( + startCoordinate, + positions.endPosition[coordinatesIndex]![coordinateIndex]!, + progress + ) + ) + ); + } + + getFeaturePosition(feature: Feature): Positions { + return this.getFeatureCoordinates(feature).map((coordinates) => + coordinates.map((coordinate) => + Position.create(coordinate[0]!, coordinate[1]!) + ) + ); + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts index 88c769e3b..38865567d 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/resize-rectangle-interaction.ts @@ -2,7 +2,7 @@ import type { Feature, MapBrowserEvent } from 'ol'; import type { Coordinate } from 'ol/coordinate'; import { distance } from 'ol/coordinate'; import BaseEvent from 'ol/events/Event'; -import type { LineString } from 'ol/geom'; +import type { Polygon } from 'ol/geom'; import PointerInteraction from 'ol/interaction/Pointer'; import type VectorSource from 'ol/source/Vector'; @@ -21,7 +21,7 @@ export class ResizeRectangleInteraction extends PointerInteraction { */ private currentResizeValues?: CurrentResizeValues; - constructor(private readonly source: VectorSource) { + constructor(private readonly source: VectorSource) { super({ handleDownEvent: (event) => this._handleDownEvent(event), handleDragEvent: (event) => this._handleDragEvent(event), @@ -37,7 +37,7 @@ export class ResizeRectangleInteraction extends PointerInteraction { return false; } const geometry = feature.getGeometry()!; - const corners = geometry.getCoordinates()!; + const corners = geometry.getCoordinates()![0]!; const distances = corners.map((corner) => distance(corner, mouseCoordinate) ); @@ -92,7 +92,7 @@ export class ResizeRectangleInteraction extends PointerInteraction { const coordinates = this.currentResizeValues.feature .getGeometry()! - .getCoordinates()!; + .getCoordinates()![0]!; const topLeftCoordinate = coordinates.reduce( (smallestCoordinate, coordinate) => coordinate[0]! <= smallestCoordinate[0]! || @@ -113,7 +113,7 @@ export class ResizeRectangleInteraction extends PointerInteraction { } static onResize( - feature: Feature, + feature: Feature, callback: (event: ResizeEvent) => void ) { feature.addEventListener( @@ -132,7 +132,7 @@ interface CurrentResizeValues { /** * The feature that is currently being resized. */ - feature: Feature; + feature: Feature; currentScale: { x: number; y: number }; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts index b78f05b38..0b949eed7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/translate-interaction.ts @@ -1,9 +1,8 @@ -import { Position } from 'digital-fuesim-manv-shared'; import { isEqual } from 'lodash-es'; import type { Feature, MapBrowserEvent } from 'ol'; -import type { LineString, Point } from 'ol/geom'; +import type { Point } from 'ol/geom'; import { Translate } from 'ol/interaction'; -import { isCoordinateArray } from '../feature-managers/element-feature-manager'; +import type { GeometryWithCoordinates, Positions } from './geometry-helper'; /** * Translates (moves) a feature to a new position. @@ -47,29 +46,14 @@ export class TranslateInteraction extends Translate { * * You can only call this function if the layer of the feature has this Interaction. */ - public static onTranslateEnd( + public static onTranslateEnd( feature: Feature, - callback: ( - newCoordinates: T extends Point ? Position : Position[] - ) => void + callback: (newCoordinates: Positions) => void, + getPosition: (feature: Feature) => Positions ) { feature.addEventListener('translateend', (event) => { // The end coordinates in the event are the mouse coordinates and not the feature coordinates. - const coordinates = feature.getGeometry()!.getCoordinates(); - if (isCoordinateArray(coordinates)) { - callback( - coordinates.map((coordinate) => - Position.create(coordinate[0]!, coordinate[1]!) - ) as T extends Point ? never : Position[] - ); - return; - } - callback( - Position.create( - coordinates[0]!, - coordinates[1]! - ) as T extends Point ? Position : never - ); + callback(getPosition(feature)); }); } diff --git a/frontend/src/assets/simulated-region.svg b/frontend/src/assets/simulated-region.svg index 75424729a..dc30aa683 100644 --- a/frontend/src/assets/simulated-region.svg +++ b/frontend/src/assets/simulated-region.svg @@ -26,15 +26,15 @@ inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="5.8956711" - inkscape:cx="68.27043" + inkscape:cx="67.252734" inkscape:cy="38.418018" inkscape:document-units="mm" inkscape:current-layer="svg8" showgrid="false" units="px" inkscape:window-width="1920" - inkscape:window-height="1121" - inkscape:window-x="1920" + inkscape:window-height="1001" + inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:showpageshadow="2" @@ -53,7 +53,7 @@ Date: Thu, 26 Jan 2023 15:38:37 +0100 Subject: [PATCH 18/58] Change functions to arrow functions in Geometry Helpers to preserve `this` (#629) --- .../utility/point-geometry-helper.ts | 32 +++++-------- .../utility/polygon-geometry-helper.ts | 46 +++++++++---------- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts index 406bdce5d..8280d565b 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/point-geometry-helper.ts @@ -11,33 +11,25 @@ import type { import { interpolate } from './geometry-helper'; export class PointGeometryHelper implements GeometryHelper { - create(element: WithPosition): Feature { - return new Feature(new Point(this.getElementCoordinates(element))); - } + create = (element: WithPosition): Feature => + new Feature(new Point(this.getElementCoordinates(element))); - getElementCoordinates(element: WithPosition): Coordinates { - return [element.position.x, element.position.y]; - } + getElementCoordinates = ( + element: WithPosition + ): Coordinates => [element.position.x, element.position.y]; - getFeatureCoordinates(feature: Feature): Coordinates { - return feature.getGeometry()!.getCoordinates(); - } + getFeatureCoordinates = (feature: Feature): Coordinates => + feature.getGeometry()!.getCoordinates(); - interpolateCoordinates( + interpolateCoordinates = ( positions: CoordinatePair, progress: number - ): Coordinates { - return interpolate( - positions.startPosition, - positions.endPosition, - progress - ); - } + ): Coordinates => + interpolate(positions.startPosition, positions.endPosition, progress); - getFeaturePosition(feature: Feature): Positions { - return Position.create( + getFeaturePosition = (feature: Feature): Positions => + Position.create( this.getFeatureCoordinates(feature)[0]!, this.getFeatureCoordinates(feature)[1]! ); - } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts index 4cd61e95c..12ef3428c 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/polygon-geometry-helper.ts @@ -13,34 +13,32 @@ import { interpolate } from './geometry-helper'; export class PolygonGeometryHelper implements GeometryHelper { - create(element: ResizableElement): Feature { - return new Feature(new Polygon(this.getElementCoordinates(element))); - } + create = (element: ResizableElement): Feature => + new Feature(new Polygon(this.getElementCoordinates(element))); - getElementCoordinates(element: ResizableElement): Coordinates { - return [ + getElementCoordinates = ( + element: ResizableElement + ): Coordinates => [ + [ + [element.position.x, element.position.y], + [element.position.x + element.size.width, element.position.y], [ - [element.position.x, element.position.y], - [element.position.x + element.size.width, element.position.y], - [ - element.position.x + element.size.width, - element.position.y - element.size.height, - ], - [element.position.x, element.position.y - element.size.height], - [element.position.x, element.position.y], + element.position.x + element.size.width, + element.position.y - element.size.height, ], - ]; - } + [element.position.x, element.position.y - element.size.height], + [element.position.x, element.position.y], + ], + ]; - getFeatureCoordinates(feature: Feature): Coordinates { - return feature.getGeometry()!.getCoordinates(); - } + getFeatureCoordinates = (feature: Feature): Coordinates => + feature.getGeometry()!.getCoordinates(); - interpolateCoordinates( + interpolateCoordinates = ( positions: CoordinatePair, progress: number - ): Coordinates { - return positions.startPosition.map((coordinates, coordinatesIndex) => + ): Coordinates => + positions.startPosition.map((coordinates, coordinatesIndex) => coordinates.map((startCoordinate, coordinateIndex) => interpolate( startCoordinate, @@ -49,13 +47,11 @@ export class PolygonGeometryHelper ) ) ); - } - getFeaturePosition(feature: Feature): Positions { - return this.getFeatureCoordinates(feature).map((coordinates) => + getFeaturePosition = (feature: Feature): Positions => + this.getFeatureCoordinates(feature).map((coordinates) => coordinates.map((coordinate) => Position.create(coordinate[0]!, coordinate[1]!) ) ); - } } From ede96192761533218298e756c5964230d3669d1f Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:32:18 +0100 Subject: [PATCH 19/58] Add type property to elements in the state (#616) * WIP * Pick specific selectors from TypeSelectorMap * Fix linter * Remove type property from feature * Fix bug after merge * Rename selector map to plural map and add validation * Simplify featureKeys * Fix tests by adding type property to demo objects * WIP: Add migration * Update shared/src/utils/type-state-selector-map.ts Co-authored-by: Julian Schmidt * Rename file to reflect variable name change * Replace type literals by element property * Run prettier * Finish migration * Fix migration to set correct type on EocLogEntry * Make imports consistent * Reuse literal union from transfer in exercise * Fix linter Co-authored-by: Julian Schmidt --- backend/src/fuesim-server.spec.ts | 1 + .../create-image-template-modal.component.ts | 1 + .../send-alarm-group-interface.component.ts | 2 +- .../catering-lines-feature-manager.ts | 1 - .../feature-managers/element-manager.ts | 22 +- .../map-images-feature-manager.ts | 8 +- .../material-feature-manager.ts | 5 +- .../moveable-feature-manager.ts | 2 - .../patient-feature-manager.ts | 9 +- .../personnel-feature-manager.ts | 5 +- .../simulated-region-feature-manager.ts | 7 +- .../transfer-lines-feature-manager.ts | 1 - .../transfer-point-feature-manager.ts | 15 +- .../vehicle-feature-manager.ts | 27 +- .../viewport-feature-manager.ts | 7 +- .../transfer-overview-table.component.html | 4 +- .../transfer-target-input.component.ts | 2 +- .../transfer-time-input.component.ts | 2 +- shared/src/models/alarm-group.ts | 4 + shared/src/models/client.ts | 5 +- shared/src/models/element.ts | 26 ++ shared/src/models/eoc-log-entry.ts | 4 + shared/src/models/exercise-configuration.ts | 4 + shared/src/models/hospital-patient.ts | 5 +- shared/src/models/hospital.ts | 5 +- shared/src/models/map-image-template.ts | 4 + shared/src/models/map-image.ts | 4 + shared/src/models/material-template.ts | 5 +- shared/src/models/material.ts | 5 +- shared/src/models/patient-category.ts | 4 + shared/src/models/patient-health-state.ts | 4 + shared/src/models/patient-template.ts | 5 +- shared/src/models/patient.ts | 10 +- shared/src/models/personnel-template.ts | 5 +- shared/src/models/personnel.ts | 5 +- shared/src/models/simulated-region.ts | 4 + shared/src/models/transfer-point.ts | 9 +- shared/src/models/vehicle-template.ts | 5 +- shared/src/models/vehicle.ts | 5 +- shared/src/models/viewport.ts | 4 + .../create-vehicle-parameters.ts | 1 + .../state-migrations/17-add-type-property.ts | 329 ++++++++++++++++++ .../state-migrations/migration-functions.ts | 2 + shared/src/state.ts | 6 +- .../src/store/action-reducers/alarm-group.ts | 10 +- shared/src/store/action-reducers/client.ts | 8 +- shared/src/store/action-reducers/exercise.ts | 16 +- shared/src/store/action-reducers/hospital.ts | 20 +- .../src/store/action-reducers/map-images.ts | 16 +- shared/src/store/action-reducers/material.ts | 2 +- shared/src/store/action-reducers/patient.ts | 10 +- .../store/action-reducers/simulated-region.ts | 8 +- .../store/action-reducers/transfer-point.ts | 32 +- shared/src/store/action-reducers/transfer.ts | 14 +- .../utils/calculate-treatments.spec.ts | 12 +- .../utils/calculate-treatments.ts | 49 +-- .../action-reducers/utils/get-element.ts | 21 +- .../action-reducers/utils/spatial-elements.ts | 14 +- shared/src/store/action-reducers/vehicle.ts | 48 ++- shared/src/store/action-reducers/viewport.ts | 8 +- .../src/store/reduce-exercise-state.spec.ts | 1 + .../store/validate-exercise-action.spec.ts | 2 + shared/src/utils/element-type-plural-map.ts | 21 ++ 63 files changed, 657 insertions(+), 245 deletions(-) create mode 100644 shared/src/models/element.ts create mode 100644 shared/src/state-migrations/17-add-type-property.ts create mode 100644 shared/src/utils/element-type-plural-map.ts diff --git a/backend/src/fuesim-server.spec.ts b/backend/src/fuesim-server.spec.ts index 0d4cd3528..ae28339a5 100644 --- a/backend/src/fuesim-server.spec.ts +++ b/backend/src/fuesim-server.spec.ts @@ -38,6 +38,7 @@ describe('Exercise saving', () => { alarmGroup: { alarmGroupVehicles: {}, id: uuid(), + type: 'alarmGroup', name: 'Alarm Group', }, }, diff --git a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts index 11a6aead7..134360443 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/editor-panel/create-image-template-modal/create-image-template-modal.component.ts @@ -35,6 +35,7 @@ export class CreateImageTemplateModalComponent { type: '[MapImageTemplate] Add mapImageTemplate', mapImageTemplate: { id: uuid(), + type: 'mapImageTemplate', image: { url, height, diff --git a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts index 15b9189ab..06755aa93 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/emergency-operations-center/send-alarm-group-interface/send-alarm-group-interface.component.ts @@ -112,7 +112,7 @@ export class SendAlarmGroupInterfaceComponent implements OnDestroy { }), this.exerciseService.proposeAction({ type: '[Transfer] Add to transfer', - elementType: 'vehicles', + elementType: vehicleParameters.vehicle.type, elementId: vehicleParameters.vehicle.id, startPoint: AlarmGroupStartPoint.create( alarmGroup.name, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index d3088c938..8272b8807 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -18,7 +18,6 @@ export class CateringLinesFeatureManager > implements FeatureManager { - readonly type = 'cateringLines'; readonly unsupportedChangeProperties = new Set(['id'] as const); private readonly lineStyleHelper = new LineStyleHelper( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index 4ff6e3b48..d341b294e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -18,19 +18,12 @@ export abstract class ElementManager< UnsupportedChangeProperties > = Exclude, UnsupportedChangeProperties> > { - /** - * When an element gets (dragged &) dropped, this identifies the type of the dropped element. - * @example `patients` - */ - abstract readonly type: string; - /** * This should be called if a new element is added. */ public onElementCreated(element: Element) { const feature = this.createFeature(element); - feature.set(featureKeys.type, this.type); - feature.set(featureKeys.value, element); + feature.set(featureElementKey, element); } /** @@ -68,7 +61,7 @@ export abstract class ElementManager< this.onElementCreated(newElement); return; } - elementFeature.set(featureKeys.value, newElement); + elementFeature.set(featureElementKey, newElement); this.changeFeature( oldElement, newElement, @@ -111,10 +104,7 @@ export abstract class ElementManager< ): Feature | undefined; public getElementFromFeature(feature: Feature) { - return { - type: feature.get(featureKeys.type), - value: feature.get(featureKeys.value), - }; + return feature.get(featureElementKey); } private areAllPropertiesSupported( @@ -132,8 +122,4 @@ export abstract class ElementManager< /** * The keys of the feature, where the type and most recent value of the respective element are saved to */ -const featureKeys = { - value: 'elementValue', - // TODO: In the future the type should be saved in the element itself - type: 'elementType', -}; +const featureElementKey = 'element'; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts index cee02e94a..1d34bd8ae 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts @@ -16,9 +16,8 @@ import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class MapImageFeatureManager extends MoveableFeatureManager { - readonly type = 'mapImages'; private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as MapImage).image ); private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); @@ -46,7 +45,8 @@ export class MapImageFeatureManager extends MoveableFeatureManager { resolution ); style.setZIndex( - this.getElementFromFeature(feature as Feature)!.value.zIndex + (this.getElementFromFeature(feature as Feature) as MapImage) + .zIndex ); return style; }); @@ -69,7 +69,7 @@ export class MapImageFeatureManager extends MoveableFeatureManager { } override isFeatureTranslatable(feature: Feature): boolean { - const mapImage = this.getElementFromFeature(feature).value as MapImage; + const mapImage = this.getElementFromFeature(feature) as MapImage; return ( selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' && !mapImage.isLocked diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts index 44888b48e..42bd0446e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts @@ -17,13 +17,12 @@ import { MoveableFeatureManager } from './moveable-feature-manager'; export class MaterialFeatureManager extends MoveableFeatureManager< WithPosition > { - readonly type = 'materials'; private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Material).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const material = this.getElementFromFeature(feature)!.value; + const material = this.getElementFromFeature(feature) as Material; return { name: material.vehicleName, offsetY: material.image.height / 2 / normalZoom, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts index 4e8f56ea5..94034d561 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -1,4 +1,3 @@ -import type { ExerciseState } from 'digital-fuesim-manv-shared'; import type { MapBrowserEvent, Feature } from 'ol'; import type Point from 'ol/geom/Point'; import type { TranslateEvent } from 'ol/interaction/Translate'; @@ -30,7 +29,6 @@ export abstract class MoveableFeatureManager< extends ElementManager> implements FeatureManager { - abstract override readonly type: keyof ExerciseState; public readonly togglePopup$ = new Subject>(); protected readonly movementAnimator: MovementAnimator; constructor( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts index 69acb7ba9..c2a3e70be 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts @@ -22,11 +22,10 @@ import { MoveableFeatureManager } from './moveable-feature-manager'; export class PatientFeatureManager extends MoveableFeatureManager< WithPosition > { - readonly type = 'patients'; private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); private readonly imageStyleHelper = new ImageStyleHelper((feature) => { - const patient = this.getElementFromFeature(feature)!.value; + const patient = this.getElementFromFeature(feature) as Patient; return { ...patient.image, rotation: patient.pretriageInformation.isWalkable @@ -37,7 +36,7 @@ export class PatientFeatureManager extends MoveableFeatureManager< private readonly circleStyleHelper = new CircleStyleHelper( (feature) => { - const patient = this.getElementFromFeature(feature)!.value; + const patient = this.getElementFromFeature(feature) as Patient; const configuration = selectStateSnapshot( selectConfiguration, this.store @@ -60,8 +59,8 @@ export class PatientFeatureManager extends MoveableFeatureManager< }, 0.025, (feature) => - this.getElementFromFeature(feature)!.value.pretriageInformation - .isWalkable + (this.getElementFromFeature(feature) as Patient) + .pretriageInformation.isWalkable ? [0, 0.25] : [-0.25, 0] ); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts index 183443f19..98f6a144a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts @@ -17,13 +17,12 @@ import { MoveableFeatureManager } from './moveable-feature-manager'; export class PersonnelFeatureManager extends MoveableFeatureManager< WithPosition > { - readonly type = 'personnel'; private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Personnel).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const personnel = this.getElementFromFeature(feature)!.value; + const personnel = this.getElementFromFeature(feature) as Personnel; return { name: personnel.vehicleName, offsetY: personnel.image.height / 2 / normalZoom, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index f4cd2894c..58c820119 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -24,8 +24,6 @@ export class SimulatedRegionFeatureManager extends MoveableFeatureManager implements FeatureManager { - readonly type = 'simulatedRegions'; - override unsupportedChangeProperties = new Set(['id'] as const); constructor( @@ -64,8 +62,9 @@ export class SimulatedRegionFeatureManager ResizeRectangleInteraction.onResize( feature, ({ topLeftCoordinate, scale }) => { - const currentElement = this.getElementFromFeature(feature)! - .value as SimulatedRegion; + const currentElement = this.getElementFromFeature( + feature + ) as SimulatedRegion; this.exerciseService.proposeAction( { type: '[SimulatedRegion] Resize simulated region', diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index 97aa951f2..be10f0b39 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -18,7 +18,6 @@ export class TransferLinesFeatureManager > implements FeatureManager { - readonly type = 'transferLines'; readonly unsupportedChangeProperties = new Set(['id'] as const); constructor(public readonly layer: VectorLayer>) { diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 1dfcda572..8012a443c 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -20,7 +20,6 @@ import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class TransferPointFeatureManager extends MoveableFeatureManager { - readonly type = 'transferPoints'; private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); constructor( @@ -62,7 +61,8 @@ export class TransferPointFeatureManager extends MoveableFeatureManager ({ - name: this.getElementFromFeature(feature)!.value.internalName, + name: (this.getElementFromFeature(feature) as TransferPoint) + .internalName, offsetY: 0, }), 0.2, @@ -76,14 +76,15 @@ export class TransferPointFeatureManager extends MoveableFeatureManager fix getElementFromFeature typings const droppedElement = this.getElementFromFeature(droppedFeature); - const droppedOnTransferPoint: TransferPoint = - this.getElementFromFeature(droppedOnFeature)!.value!; + const droppedOnTransferPoint = this.getElementFromFeature( + droppedOnFeature + ) as TransferPoint; if (!droppedElement || !droppedOnTransferPoint) { console.error('Could not find element for the features'); return false; } if ( - droppedElement.type !== 'vehicles' && + droppedElement.type !== 'vehicle' && droppedElement.type !== 'personnel' ) { return false; @@ -107,7 +108,7 @@ export class TransferPointFeatureManager extends MoveableFeatureManager > { - readonly type = 'vehicles'; - private readonly imageStyleHelper = new ImageStyleHelper( - (feature) => this.getElementFromFeature(feature)!.value.image + (feature) => (this.getElementFromFeature(feature) as Vehicle).image ); private readonly nameStyleHelper = new NameStyleHelper( (feature) => { - const vehicle = this.getElementFromFeature(feature)!.value; + const vehicle = this.getElementFromFeature(feature) as Vehicle; return { name: vehicle.name, offsetY: vehicle.image.height / 2 / normalZoom, @@ -67,29 +65,26 @@ export class VehicleFeatureManager extends MoveableFeatureManager< const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnVehicle = this.getElementFromFeature( droppedOnFeature - ) as { - type: 'vehicles'; - value: Vehicle; - }; + ) as Vehicle; if (!droppedElement || !droppedOnVehicle) { console.error('Could not find element for the features'); return false; } if ( (droppedElement.type === 'personnel' && - droppedOnVehicle.value.personnelIds[droppedElement.value.id]) || - (droppedElement.type === 'materials' && - droppedOnVehicle.value.materialIds[droppedElement.value.id]) || - (droppedElement.type === 'patients' && - Object.keys(droppedOnVehicle.value.patientIds).length < - droppedOnVehicle.value.patientCapacity) + droppedOnVehicle.personnelIds[droppedElement.id]) || + (droppedElement.type === 'material' && + droppedOnVehicle.materialIds[droppedElement.id]) || + (droppedElement.type === 'patient' && + Object.keys(droppedOnVehicle.patientIds).length < + droppedOnVehicle.patientCapacity) ) { // TODO: user feedback (e.g. toast) this.exerciseService.proposeAction( { type: '[Vehicle] Load vehicle', - vehicleId: droppedOnVehicle.value.id, - elementToBeLoadedId: droppedElement.value.id, + vehicleId: droppedOnVehicle.id, + elementToBeLoadedId: droppedElement.id, elementToBeLoadedType: droppedElement.type, }, true diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 5cc97963b..5f2ceef63 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -34,8 +34,6 @@ export class ViewportFeatureManager extends MoveableFeatureManager implements FeatureManager { - readonly type = 'viewports'; - override unsupportedChangeProperties = new Set(['id'] as const); constructor( @@ -72,8 +70,9 @@ export class ViewportFeatureManager ResizeRectangleInteraction.onResize( feature, ({ topLeftCoordinate, scale }) => { - const currentElement = this.getElementFromFeature(feature)! - .value as Viewport; + const currentElement = this.getElementFromFeature( + feature + ) as Viewport; this.exerciseService.proposeAction( { type: '[Viewport] Resize viewport', diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html index b17308b0d..4d592c856 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.html @@ -42,14 +42,14 @@ diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts index 2bd0ab98f..dd84fa34e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-target-input/transfer-target-input.component.ts @@ -11,7 +11,7 @@ import { selectTransferPoints } from 'src/app/state/application/selectors/exerci styleUrls: ['./transfer-target-input.component.scss'], }) export class TransferTargetInputComponent { - @Input() elementType!: 'personnel' | 'vehicles'; + @Input() elementType!: 'personnel' | 'vehicle'; @Input() elementId!: UUID; @Input() transfer!: Transfer; diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts index 011a25963..f01016989 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-time-input/transfer-time-input.component.ts @@ -11,7 +11,7 @@ import { selectCurrentTime } from 'src/app/state/application/selectors/exercise. styleUrls: ['./transfer-time-input.component.scss'], }) export class TransferTimeInputComponent { - @Input() elementType!: 'personnel' | 'vehicles'; + @Input() elementType!: 'personnel' | 'vehicle'; @Input() elementId!: UUID; diff --git a/shared/src/models/alarm-group.ts b/shared/src/models/alarm-group.ts index 3d4d58d72..2d6ed8dc1 100644 --- a/shared/src/models/alarm-group.ts +++ b/shared/src/models/alarm-group.ts @@ -1,5 +1,6 @@ import { IsString, IsUUID } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { IsIdMap } from '../utils/validators/is-id-map'; import { getCreate } from './utils'; import { AlarmGroupVehicle } from './utils/alarm-group-vehicle'; @@ -8,6 +9,9 @@ export class AlarmGroup { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('alarmGroup' as const) + public readonly type = 'alarmGroup'; + @IsString() public readonly name: string; diff --git a/shared/src/models/client.ts b/shared/src/models/client.ts index aac8ec2eb..ae42a3546 100644 --- a/shared/src/models/client.ts +++ b/shared/src/models/client.ts @@ -6,7 +6,7 @@ import { MaxLength, } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; -import { IsLiteralUnion } from '../utils/validators'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { getCreate, Role } from './utils'; import { roleAllowedValues } from './utils/role'; @@ -14,6 +14,9 @@ export class Client { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('client' as const) + public readonly type = 'client'; + @IsString() // Required by database @MaxLength(255) diff --git a/shared/src/models/element.ts b/shared/src/models/element.ts new file mode 100644 index 000000000..9aa445366 --- /dev/null +++ b/shared/src/models/element.ts @@ -0,0 +1,26 @@ +import type { + AlarmGroup, + Client, + Hospital, + MapImage, + Material, + Patient, + Personnel, + SimulatedRegion, + TransferPoint, + Vehicle, + Viewport, +} from '.'; + +export type Element = + | AlarmGroup + | Client + | Hospital + | MapImage + | Material + | Patient + | Personnel + | SimulatedRegion + | TransferPoint + | Vehicle + | Viewport; diff --git a/shared/src/models/eoc-log-entry.ts b/shared/src/models/eoc-log-entry.ts index f6b7c0113..ed83508e9 100644 --- a/shared/src/models/eoc-log-entry.ts +++ b/shared/src/models/eoc-log-entry.ts @@ -1,11 +1,15 @@ import { IsInt, IsString, IsUUID, MaxLength } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate } from './utils'; export class EocLogEntry { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('eocLogEntry' as const) + public readonly type = 'eocLogEntry'; + /** * The time in the exercise */ diff --git a/shared/src/models/exercise-configuration.ts b/shared/src/models/exercise-configuration.ts index 9899cdc3d..dce59e0a9 100644 --- a/shared/src/models/exercise-configuration.ts +++ b/shared/src/models/exercise-configuration.ts @@ -1,9 +1,13 @@ import { Type } from 'class-transformer'; import { IsBoolean, ValidateNested } from 'class-validator'; import { defaultTileMapProperties } from '../data'; +import { IsValue } from '../utils/validators'; import { getCreate, TileMapProperties } from './utils'; export class ExerciseConfiguration { + @IsValue('exerciseConfiguration' as const) + public readonly type = 'exerciseConfiguration'; + @IsBoolean() public readonly pretriageEnabled: boolean = true; @IsBoolean() diff --git a/shared/src/models/hospital-patient.ts b/shared/src/models/hospital-patient.ts index b9aa4655f..17a2588ac 100644 --- a/shared/src/models/hospital-patient.ts +++ b/shared/src/models/hospital-patient.ts @@ -8,7 +8,7 @@ import { } from 'class-validator'; import type { Mutable } from '../utils'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../utils'; -import { IsIdMap, IsLiteralUnion } from '../utils/validators'; +import { IsIdMap, IsLiteralUnion, IsValue } from '../utils/validators'; import { getCreate, HealthPoints, @@ -29,6 +29,9 @@ export class HospitalPatient { @IsUUID(4, uuidValidationOptions) public readonly patientId: UUID; + @IsValue('hospitalPatient' as const) + public readonly type = 'hospitalPatient'; + /** * the vehicle that a patient was transported with */ diff --git a/shared/src/models/hospital.ts b/shared/src/models/hospital.ts index 80797693a..528e35c83 100644 --- a/shared/src/models/hospital.ts +++ b/shared/src/models/hospital.ts @@ -1,12 +1,15 @@ import { IsNumber, IsString, IsUUID, Min } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; -import { IsUUIDSet } from '../utils/validators'; +import { IsUUIDSet, IsValue } from '../utils/validators'; import { getCreate } from './utils'; export class Hospital { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('hospital' as const) + public readonly type = 'hospital'; + @IsString() public readonly name: string; diff --git a/shared/src/models/map-image-template.ts b/shared/src/models/map-image-template.ts index c701df501..9a2f4ab90 100644 --- a/shared/src/models/map-image-template.ts +++ b/shared/src/models/map-image-template.ts @@ -1,12 +1,16 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, ImageProperties } from './utils'; export class MapImageTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('mapImageTemplate' as const) + public readonly type = 'mapImageTemplate'; + @IsString() public readonly name: string; diff --git a/shared/src/models/map-image.ts b/shared/src/models/map-image.ts index 6dc0c3e46..ad15022a7 100644 --- a/shared/src/models/map-image.ts +++ b/shared/src/models/map-image.ts @@ -1,12 +1,16 @@ import { Type } from 'class-transformer'; import { IsBoolean, IsInt, IsUUID, ValidateNested } from 'class-validator'; import { uuid, UUID, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { Position, getCreate, ImageProperties } from './utils'; export class MapImage { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('mapImage' as const) + public readonly type = 'mapImage'; + @ValidateNested() @Type(() => Position) public readonly position: Position; diff --git a/shared/src/models/material-template.ts b/shared/src/models/material-template.ts index 95f6ba6ec..39b45da3e 100644 --- a/shared/src/models/material-template.ts +++ b/shared/src/models/material-template.ts @@ -1,11 +1,14 @@ import { Type } from 'class-transformer'; import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { IsLiteralUnion } from '../utils/validators'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { CanCaterFor, getCreate, ImageProperties } from './utils'; import { MaterialType, materialTypeAllowedValues } from './utils/material-type'; export class MaterialTemplate { + @IsValue('materialTemplate' as const) + public readonly type = 'materialTemplate'; + @IsLiteralUnion(materialTypeAllowedValues) public readonly materialType: MaterialType; diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts index 10dc9e2fa..4fea13d4d 100644 --- a/shared/src/models/material.ts +++ b/shared/src/models/material.ts @@ -10,7 +10,7 @@ import { } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; -import { IsUUIDSet } from '../utils/validators'; +import { IsUUIDSet, IsValue } from '../utils/validators'; import { IsMetaPosition } from '../utils/validators/is-metaposition'; import type { MaterialTemplate } from './material-template'; import { CanCaterFor, Position, ImageProperties, getCreate } from './utils'; @@ -20,6 +20,9 @@ export class Material { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('material' as const) + public readonly type = 'material'; + @IsUUID(4, uuidValidationOptions) public readonly vehicleId: UUID; diff --git a/shared/src/models/patient-category.ts b/shared/src/models/patient-category.ts index 6b9d8b683..d6161453c 100644 --- a/shared/src/models/patient-category.ts +++ b/shared/src/models/patient-category.ts @@ -1,10 +1,14 @@ import { Type } from 'class-transformer'; import { ArrayNotEmpty, IsArray, ValidateNested } from 'class-validator'; +import { IsValue } from '../utils/validators'; import { PatientTemplate } from './patient-template'; import { getCreate, ImageProperties } from './utils'; import { PatientStatusCode } from './utils/patient-status-code'; export class PatientCategory { + @IsValue('patientCategory' as const) + public readonly type = 'patientCategory'; + @ValidateNested() @Type(() => PatientStatusCode) public readonly name: PatientStatusCode; diff --git a/shared/src/models/patient-health-state.ts b/shared/src/models/patient-health-state.ts index 60810920e..9e04c85ea 100644 --- a/shared/src/models/patient-health-state.ts +++ b/shared/src/models/patient-health-state.ts @@ -7,6 +7,7 @@ import { ValidateNested, } from 'class-validator'; import { uuid, UUID, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, HealthPoints, IsValidHealthPoint } from './utils'; /** @@ -109,6 +110,9 @@ export class PatientHealthState { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patientHealthState' as const) + public readonly type = 'patientHealthState'; + @Type(() => FunctionParameters) @ValidateNested() public readonly functionParameters: FunctionParameters; diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts index ef8841390..82a4905c4 100644 --- a/shared/src/models/patient-template.ts +++ b/shared/src/models/patient-template.ts @@ -1,7 +1,7 @@ import { Type } from 'class-transformer'; import { IsUUID, ValidateNested } from 'class-validator'; import { cloneDeepMutable, UUID, uuid, uuidValidationOptions } from '../utils'; -import { IsIdMap } from '../utils/validators'; +import { IsIdMap, IsValue } from '../utils/validators'; import type { PatientStatusCode } from './utils'; import { BiometricInformation, @@ -22,6 +22,9 @@ export class PatientTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patientTemplate' as const) + public readonly type = 'patientTemplate'; + @ValidateNested() @Type(() => BiometricInformation) public readonly biometricInformation: BiometricInformation; diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index 4942509ed..6c5cecee4 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -12,7 +12,12 @@ import { } from 'class-validator'; import { isEmpty } from 'lodash-es'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; -import { IsLiteralUnion, IsIdMap, IsUUIDSet } from '../utils/validators'; +import { + IsLiteralUnion, + IsIdMap, + IsUUIDSet, + IsValue, +} from '../utils/validators'; import { IsMetaPosition } from '../utils/validators/is-metaposition'; import { PatientHealthState } from './patient-health-state'; import { @@ -34,6 +39,9 @@ export class Patient { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('patient') + public readonly type = 'patient'; + @ValidateNested() @Type(() => PersonalInformation) public readonly personalInformation: PersonalInformation; diff --git a/shared/src/models/personnel-template.ts b/shared/src/models/personnel-template.ts index ccc06782a..fc3e3c101 100644 --- a/shared/src/models/personnel-template.ts +++ b/shared/src/models/personnel-template.ts @@ -1,7 +1,7 @@ import { Type } from 'class-transformer'; import { IsNumber, Max, Min, ValidateNested } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; -import { IsLiteralUnion } from '../utils/validators'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import { PersonnelType, CanCaterFor, @@ -12,6 +12,9 @@ import { personnelTypeAllowedValues } from './utils/personnel-type'; // TODO: These are not (yet) saved in the state -> Decide whether they should and if not move this file from the models folder away export class PersonnelTemplate { + @IsValue('personnelTemplate' as const) + public readonly type = 'personnelTemplate'; + @IsLiteralUnion(personnelTypeAllowedValues) public readonly personnelType: PersonnelType; diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts index 9ed6b4f79..16ebc287c 100644 --- a/shared/src/models/personnel.ts +++ b/shared/src/models/personnel.ts @@ -10,7 +10,7 @@ import { } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; -import { IsLiteralUnion, IsUUIDSet } from '../utils/validators'; +import { IsLiteralUnion, IsUUIDSet, IsValue } from '../utils/validators'; import { IsMetaPosition } from '../utils/validators/is-metaposition'; import type { PersonnelTemplate } from './personnel-template'; import { @@ -28,6 +28,9 @@ export class Personnel { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('personnel' as const) + public readonly type = 'personnel'; + @IsUUID(4, uuidValidationOptions) public readonly vehicleId: UUID; diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts index 6e3db79a4..8d4f47cc4 100644 --- a/shared/src/models/simulated-region.ts +++ b/shared/src/models/simulated-region.ts @@ -1,6 +1,7 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, Position, Size } from './utils'; import type { ImageProperties } from './utils'; @@ -8,6 +9,9 @@ export class SimulatedRegion { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('simulatedRegion' as const) + public readonly type = 'simulatedRegion'; + /** * top-left position */ diff --git a/shared/src/models/transfer-point.ts b/shared/src/models/transfer-point.ts index b825b36be..5aa895ca5 100644 --- a/shared/src/models/transfer-point.ts +++ b/shared/src/models/transfer-point.ts @@ -1,7 +1,11 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; -import { IsReachableTransferPoints, IsUUIDSet } from '../utils/validators'; +import { + IsReachableTransferPoints, + IsUUIDSet, + IsValue, +} from '../utils/validators'; import type { ImageProperties } from './utils'; import { getCreate, Position } from './utils'; @@ -9,6 +13,9 @@ export class TransferPoint { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('transferPoint' as const) + public readonly type = 'transferPoint'; + @ValidateNested() @Type(() => Position) public readonly position: Position; diff --git a/shared/src/models/vehicle-template.ts b/shared/src/models/vehicle-template.ts index f0dd3157b..c2956dd40 100644 --- a/shared/src/models/vehicle-template.ts +++ b/shared/src/models/vehicle-template.ts @@ -7,7 +7,7 @@ import { IsArray, } from 'class-validator'; import { uuidValidationOptions, UUID, uuid } from '../utils'; -import { IsLiteralUnion } from '../utils/validators'; +import { IsLiteralUnion, IsValue } from '../utils/validators'; import type { PersonnelType } from './utils'; import { ImageProperties, @@ -21,6 +21,9 @@ export class VehicleTemplate { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('vehicleTemplate' as const) + public readonly type = 'vehicleTemplate'; + @IsString() public readonly vehicleType: string; diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index 8c18b39da..e053b021a 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -7,7 +7,7 @@ import { ValidateNested, } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; -import { IsUUIDSet } from '../utils/validators'; +import { IsUUIDSet, IsValue } from '../utils/validators'; import { IsMetaPosition } from '../utils/validators/is-metaposition'; import { getCreate, Position, Transfer } from './utils'; import { ImageProperties } from './utils/image-properties'; @@ -17,6 +17,9 @@ export class Vehicle { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('vehicle' as const) + public readonly type = 'vehicle'; + @IsString() public readonly vehicleType: string; diff --git a/shared/src/models/viewport.ts b/shared/src/models/viewport.ts index fc31482b7..4a147e472 100644 --- a/shared/src/models/viewport.ts +++ b/shared/src/models/viewport.ts @@ -1,6 +1,7 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsValue } from '../utils/validators'; import { getCreate, Position, Size } from './utils'; import type { ImageProperties } from './utils'; @@ -8,6 +9,9 @@ export class Viewport { @IsUUID(4, uuidValidationOptions) public readonly id: UUID = uuid(); + @IsValue('viewport' as const) + public readonly type = 'viewport'; + /** * top-left position */ diff --git a/shared/src/state-helpers/create-vehicle-parameters.ts b/shared/src/state-helpers/create-vehicle-parameters.ts index e6f0021a3..bacbb4ef4 100644 --- a/shared/src/state-helpers/create-vehicle-parameters.ts +++ b/shared/src/state-helpers/create-vehicle-parameters.ts @@ -48,6 +48,7 @@ export function createVehicleParameters( const vehicle: Vehicle = { id: vehicleId, + type: 'vehicle', materialIds: arrayToUUIDSet(materials.map((m) => m.id)), vehicleType: vehicleTemplate.vehicleType, name: vehicleTemplate.name, diff --git a/shared/src/state-migrations/17-add-type-property.ts b/shared/src/state-migrations/17-add-type-property.ts new file mode 100644 index 000000000..afd36843f --- /dev/null +++ b/shared/src/state-migrations/17-add-type-property.ts @@ -0,0 +1,329 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addTypeProperty17: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + const actionType = (action as { type: string } | null)?.type; + + if (actionType === '[AlarmGroup] Add AlarmGroup') { + const typedAction = action as { + alarmGroup: { + type: 'alarmGroup'; + }; + }; + + typedAction.alarmGroup.type = 'alarmGroup'; + } + + if (actionType === '[Client] Add client') { + const typedAction = action as { + client: { + type: 'client'; + }; + }; + + typedAction.client.type = 'client'; + } + + if (actionType === '[Hospital] Add hospital') { + const typedAction = action as { + hospital: { + type: 'hospital'; + }; + }; + + typedAction.hospital.type = 'hospital'; + } + + if (actionType === '[MapImageTemplate] Add mapImageTemplate') { + const typedAction = action as { + mapImageTemplate: { + type: 'mapImageTemplate'; + }; + }; + + typedAction.mapImageTemplate.type = 'mapImageTemplate'; + } + + if (actionType === '[MapImage] Add MapImage') { + const typedAction = action as { + mapImage: { + type: 'mapImage'; + }; + }; + + typedAction.mapImage.type = 'mapImage'; + } + + if (actionType === '[Patient] Add patient') { + const typedAction = action as { + patient: { + type: 'patient'; + healthStates: { + [key: UUID]: { type: 'patientHealthState' }; + }; + }; + }; + + typedAction.patient.type = 'patient'; + Object.values(typedAction.patient.healthStates).forEach( + (healthState) => { + healthState.type = 'patientHealthState'; + } + ); + } + + if (actionType === '[SimulatedRegion] Add simulated region') { + const typedAction = action as { + simulatedRegion: { + type: 'simulatedRegion'; + }; + }; + + typedAction.simulatedRegion.type = 'simulatedRegion'; + } + + if ( + actionType === '[Transfer] Add to transfer' || + actionType === '[Transfer] Edit transfer' || + actionType === '[Transfer] Finish transfer' || + actionType === '[Transfer] Toggle pause transfer' + ) { + const typedAction = action as { + elementType: 'personnel' | 'vehicle' | 'vehicles'; + }; + + if (typedAction.elementType === 'vehicles') { + typedAction.elementType = 'vehicle'; + } + } + + if (actionType === '[TransferPoint] Add TransferPoint') { + const typedAction = action as { + transferPoint: { + type: 'transferPoint'; + }; + }; + + typedAction.transferPoint.type = 'transferPoint'; + } + + if (actionType === '[Vehicle] Add vehicle') { + const typedAction = action as { + vehicle: { + type: 'vehicle'; + }; + materials: { type: 'material' }[]; + personnel: { type: 'personnel' }[]; + }; + + typedAction.vehicle.type = 'vehicle'; + typedAction.materials.forEach((material) => { + material.type = 'material'; + }); + typedAction.personnel.forEach((personnel) => { + personnel.type = 'personnel'; + }); + } + + if (actionType === '[Vehicle] Load vehicle') { + const typedAction = action as { + elementToBeLoadedType: + | 'material' + | 'materials' + | 'patient' + | 'patients' + | 'personnel'; + }; + + if (typedAction.elementToBeLoadedType === 'materials') { + typedAction.elementToBeLoadedType = 'material'; + } else if (typedAction.elementToBeLoadedType === 'patients') { + typedAction.elementToBeLoadedType = 'patient'; + } + } + + if (actionType === '[Viewport] Add viewport') { + const typedAction = action as { + viewport: { + type: 'viewport'; + }; + }; + + typedAction.viewport.type = 'viewport'; + } + }); + }, + state: (state) => { + const typedState = state as { + alarmGroups: { + [key: UUID]: { + type: 'alarmGroup'; + }; + }; + clients: { + [key: UUID]: { + type: 'client'; + }; + }; + eocLog: { type: 'eocLogEntry' }[]; + configuration: { type: 'exerciseConfiguration' }; + hospitalPatients: { + [key: UUID]: { + type: 'hospitalPatient'; + }; + }; + hospitals: { + [key: UUID]: { + type: 'hospital'; + }; + }; + mapImageTemplates: { type: 'mapImageTemplate' }[]; + mapImages: { + [key: UUID]: { + type: 'mapImage'; + }; + }; + materialTemplates: { type: 'materialTemplate' }[]; + materials: { + [key: UUID]: { + type: 'material'; + }; + }; + patientCategories: { + type: 'patientCategory'; + patientTemplates: { type: 'patientTemplate' }[]; + }[]; + patients: { + [key: UUID]: { + type: 'patient'; + healthStates: { + [key: UUID]: { type: 'patientHealthState' }; + }; + }; + }; + personnelTemplates: { type: 'personnelTemplate' }[]; + personnel: { + [key: UUID]: { + type: 'personnel'; + }; + }; + simulatedRegions: { + [key: UUID]: { + type: 'simulatedRegion'; + }; + }; + transferPoints: { + [key: UUID]: { + type: 'transferPoint'; + }; + }; + vehicleTemplates: { type: 'vehicleTemplate' }[]; + vehicles: { + [key: UUID]: { + type: 'vehicle'; + }; + }; + viewports: { + [key: UUID]: { + type: 'viewport'; + }; + }; + }; + + Object.values(typedState.alarmGroups).forEach((alarmGroup) => { + alarmGroup.type = 'alarmGroup'; + }); + + Object.values(typedState.clients).forEach((client) => { + client.type = 'client'; + }); + + Object.values(typedState.eocLog).forEach((logEntry) => { + logEntry.type = 'eocLogEntry'; + }); + + typedState.configuration.type = 'exerciseConfiguration'; + + Object.values(typedState.hospitalPatients).forEach( + (hospitalPatient) => { + hospitalPatient.type = 'hospitalPatient'; + } + ); + + Object.values(typedState.hospitals).forEach((hospital) => { + hospital.type = 'hospital'; + }); + + Object.values(typedState.mapImageTemplates).forEach( + (mapImageTemplate) => { + mapImageTemplate.type = 'mapImageTemplate'; + } + ); + + Object.values(typedState.mapImages).forEach((mapImage) => { + mapImage.type = 'mapImage'; + }); + + Object.values(typedState.materialTemplates).forEach( + (materialTemplate) => { + materialTemplate.type = 'materialTemplate'; + } + ); + + Object.values(typedState.materials).forEach((material) => { + material.type = 'material'; + }); + + Object.values(typedState.patientCategories).forEach( + (patientCategory) => { + patientCategory.type = 'patientCategory'; + patientCategory.patientTemplates.forEach((patientTemplate) => { + patientTemplate.type = 'patientTemplate'; + }); + } + ); + + Object.values(typedState.patients).forEach((patient) => { + patient.type = 'patient'; + Object.values(patient.healthStates).forEach((healthState) => { + healthState.type = 'patientHealthState'; + }); + }); + + Object.values(typedState.personnelTemplates).forEach( + (personnelTemplates) => { + personnelTemplates.type = 'personnelTemplate'; + } + ); + + Object.values(typedState.personnel).forEach((personnel) => { + personnel.type = 'personnel'; + }); + + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.type = 'simulatedRegion'; + } + ); + + Object.values(typedState.transferPoints).forEach((transferPoint) => { + transferPoint.type = 'transferPoint'; + }); + + Object.values(typedState.vehicleTemplates).forEach( + (vehicleTemplate) => { + vehicleTemplate.type = 'vehicleTemplate'; + } + ); + + Object.values(typedState.vehicles).forEach((vehicle) => { + vehicle.type = 'vehicle'; + }); + + Object.values(typedState.viewports).forEach((viewport) => { + viewport.type = 'viewport'; + }); + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index 8bbed2f7b..965436bb5 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -5,6 +5,7 @@ import { addMapImageZIndex13 } from './13-add-map-image-zindex'; import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-material-templates-to-state'; import { addSimulatedRegions15 } from './15-add-simulated-regions'; import { addMetaPosition16 } from './16-add-meta-position'; +import { addTypeProperty17 } from './17-add-type-property'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -55,4 +56,5 @@ export const migrations: { 14: addPersonnelAndMaterialToState14, 15: addSimulatedRegions15, 16: addMetaPosition16, + 17: addTypeProperty17, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index 0f05987f2..de96e2b71 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -44,7 +44,7 @@ import { SpatialTree, } from './models/utils'; import type { MaterialType } from './models/utils/material-type'; -import type { SpatialElementType } from './store/action-reducers/utils/spatial-elements'; +import type { SpatialElementPlural } from './store/action-reducers/utils/spatial-elements'; import type { UUID } from './utils'; import { uuid, uuidValidationOptions } from './utils'; import { IsIdMap, IsLiteralUnion } from './utils/validators'; @@ -123,7 +123,7 @@ export class ExerciseState { // Mutable` could still have immutable objects in spatialTree @IsObject() public readonly spatialTrees: { - [type in SpatialElementType]: SpatialTree; + [type in SpatialElementPlural]: SpatialTree; } = { materials: SpatialTree.create(), patients: SpatialTree.create(), @@ -148,5 +148,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 16; + static readonly currentStateVersion = 17; } diff --git a/shared/src/store/action-reducers/alarm-group.ts b/shared/src/store/action-reducers/alarm-group.ts index 598c30c63..cf4d3cead 100644 --- a/shared/src/store/action-reducers/alarm-group.ts +++ b/shared/src/store/action-reducers/alarm-group.ts @@ -96,7 +96,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, name }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); alarmGroup.name = name; @@ -108,7 +108,7 @@ export namespace AlarmGroupActionReducers { export const removeAlarmGroup: ActionReducer = { action: RemoveAlarmGroupAction, reducer: (draftState, { alarmGroupId }) => { - getElement(draftState, 'alarmGroups', alarmGroupId); + getElement(draftState, 'alarmGroup', alarmGroupId); delete draftState.alarmGroups[alarmGroupId]; return draftState; }, @@ -121,7 +121,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, alarmGroupVehicle }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); alarmGroup.alarmGroupVehicles[alarmGroupVehicle.id] = @@ -140,7 +140,7 @@ export namespace AlarmGroupActionReducers { ) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); const alarmGroupVehicle = getAlarmGroupVehicle( @@ -160,7 +160,7 @@ export namespace AlarmGroupActionReducers { reducer: (draftState, { alarmGroupId, alarmGroupVehicleId }) => { const alarmGroup = getElement( draftState, - 'alarmGroups', + 'alarmGroup', alarmGroupId ); getAlarmGroupVehicle(alarmGroup, alarmGroupVehicleId); diff --git a/shared/src/store/action-reducers/client.ts b/shared/src/store/action-reducers/client.ts index 5c1438f22..55208470e 100644 --- a/shared/src/store/action-reducers/client.ts +++ b/shared/src/store/action-reducers/client.ts @@ -53,7 +53,7 @@ export namespace ClientActionReducers { export const removeClient: ActionReducer = { action: RemoveClientAction, reducer: (draftState, { clientId }) => { - getElement(draftState, 'clients', clientId); + getElement(draftState, 'client', clientId); delete draftState.clients[clientId]; return draftState; }, @@ -64,12 +64,12 @@ export namespace ClientActionReducers { { action: RestrictViewToViewportAction, reducer: (draftState, { clientId, viewportId }) => { - const client = getElement(draftState, 'clients', clientId); + const client = getElement(draftState, 'client', clientId); if (viewportId === undefined) { client.viewRestrictedToViewportId = viewportId; return draftState; } - getElement(draftState, 'viewports', viewportId); + getElement(draftState, 'viewport', viewportId); client.viewRestrictedToViewportId = viewportId; return draftState; }, @@ -79,7 +79,7 @@ export namespace ClientActionReducers { export const setWaitingRoom: ActionReducer = { action: SetWaitingRoomAction, reducer: (draftState, { clientId, shouldBeInWaitingRoom }) => { - const client = getElement(draftState, 'clients', clientId); + const client = getElement(draftState, 'client', clientId); client.isInWaitingRoom = shouldBeInWaitingRoom; return draftState; }, diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts index 55a1fbba3..1fd29a514 100644 --- a/shared/src/store/action-reducers/exercise.ts +++ b/shared/src/store/action-reducers/exercise.ts @@ -11,9 +11,12 @@ import { Patient } from '../../models'; import { getStatus } from '../../models/utils'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; +import type { ElementTypePluralMap } from '../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../utils/element-type-plural-map'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; +import type { TransferableElementType } from './transfer'; import { letElementArrive } from './transfer'; import { updateTreatments } from './utils/calculate-treatments'; import { PatientUpdate } from './utils/patient-updates'; @@ -122,7 +125,7 @@ export namespace ExerciseActionReducers { }); // Refresh transfers - refreshTransfer(draftState, 'vehicles', tickInterval); + refreshTransfer(draftState, 'vehicle', tickInterval); refreshTransfer(draftState, 'personnel', tickInterval); return draftState; }, @@ -130,12 +133,17 @@ export namespace ExerciseActionReducers { }; } +type TransferTypePluralMap = Pick< + ElementTypePluralMap, + TransferableElementType +>; + function refreshTransfer( draftState: Mutable, - key: 'personnel' | 'vehicles', + type: keyof TransferTypePluralMap, tickInterval: number ): void { - const elements = draftState[key]; + const elements = draftState[elementTypePluralMap[type]]; Object.values(elements).forEach((element: Mutable) => { if (!element.transfer) { return; @@ -148,6 +156,6 @@ function refreshTransfer( if (element.transfer.endTimeStamp > draftState.currentTime) { return; } - letElementArrive(draftState, key, element.id); + letElementArrive(draftState, type, element.id); }); } diff --git a/shared/src/store/action-reducers/hospital.ts b/shared/src/store/action-reducers/hospital.ts index 0f2214691..b5bb8e559 100644 --- a/shared/src/store/action-reducers/hospital.ts +++ b/shared/src/store/action-reducers/hospital.ts @@ -74,11 +74,7 @@ export namespace HospitalActionReducers { { action: EditTransportDurationToHospitalAction, reducer: (draftState, { hospitalId, transportDuration }) => { - const hospital = getElement( - draftState, - 'hospitals', - hospitalId - ); + const hospital = getElement(draftState, 'hospital', hospitalId); hospital.transportDuration = transportDuration; return draftState; }, @@ -88,7 +84,7 @@ export namespace HospitalActionReducers { export const renameHospital: ActionReducer = { action: RenameHospitalAction, reducer: (draftState, { hospitalId, name }) => { - const hospital = getElement(draftState, 'hospitals', hospitalId); + const hospital = getElement(draftState, 'hospital', hospitalId); hospital.name = name; return draftState; }, @@ -98,7 +94,7 @@ export namespace HospitalActionReducers { export const removeHospital: ActionReducer = { action: RemoveHospitalAction, reducer: (draftState, { hospitalId }) => { - const hospital = getElement(draftState, 'hospitals', hospitalId); + const hospital = getElement(draftState, 'hospital', hospitalId); // TODO: maybe make a hospital undeletable (if at least one patient is in it) for (const patientId of Object.keys(hospital.patientIds)) { delete draftState.hospitalPatients[patientId]; @@ -118,17 +114,13 @@ export namespace HospitalActionReducers { { action: TransportPatientToHospitalAction, reducer: (draftState, { hospitalId, vehicleId }) => { - const hospital = getElement( - draftState, - 'hospitals', - hospitalId - ); - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const hospital = getElement(draftState, 'hospital', hospitalId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); // TODO: Block vehicles whose material and personnel are unloaded for (const patientId of Object.keys(vehicle.patientIds)) { const patient = getElement( draftState, - 'patients', + 'patient', patientId ); draftState.hospitalPatients[patientId] = diff --git a/shared/src/store/action-reducers/map-images.ts b/shared/src/store/action-reducers/map-images.ts index 26bce6329..7384033ff 100644 --- a/shared/src/store/action-reducers/map-images.ts +++ b/shared/src/store/action-reducers/map-images.ts @@ -133,7 +133,7 @@ export namespace MapImagesActionReducers { export const moveMapImage: ActionReducer = { action: MoveMapImageAction, reducer: (draftState, { mapImageId, targetPosition }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); mapImage.position = cloneDeepMutable(targetPosition); return draftState; }, @@ -143,7 +143,7 @@ export namespace MapImagesActionReducers { export const scaleMapImage: ActionReducer = { action: ScaleMapImageAction, reducer: (draftState, { mapImageId, newHeight, newAspectRatio }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); if (newHeight) { mapImage.image.height = newHeight; } @@ -158,7 +158,7 @@ export namespace MapImagesActionReducers { export const removeMapImage: ActionReducer = { action: RemoveMapImageAction, reducer: (draftState, { mapImageId }) => { - getElement(draftState, 'mapImages', mapImageId); + getElement(draftState, 'mapImage', mapImageId); delete draftState.mapImages[mapImageId]; return draftState; }, @@ -169,11 +169,7 @@ export namespace MapImagesActionReducers { { action: ReconfigureMapImageUrlAction, reducer: (draftState, { mapImageId, newUrl }) => { - const mapImage = getElement( - draftState, - 'mapImages', - mapImageId - ); + const mapImage = getElement(draftState, 'mapImage', mapImageId); mapImage.image.url = newUrl; return draftState; }, @@ -183,7 +179,7 @@ export namespace MapImagesActionReducers { export const setLockedMapImage: ActionReducer = { action: SetIsLockedMapImageAction, reducer: (draftState, { mapImageId, newLocked }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); mapImage.isLocked = newLocked; return draftState; }, @@ -193,7 +189,7 @@ export namespace MapImagesActionReducers { export const changeZIndex: ActionReducer = { action: ChangeZIndexMapImageAction, reducer: (draftState, { mapImageId, mode }) => { - const mapImage = getElement(draftState, 'mapImages', mapImageId); + const mapImage = getElement(draftState, 'mapImage', mapImageId); switch (mode) { case 'bringToFront': case 'bringToBack': { diff --git a/shared/src/store/action-reducers/material.ts b/shared/src/store/action-reducers/material.ts index a38b201ab..4d1847dc4 100644 --- a/shared/src/store/action-reducers/material.ts +++ b/shared/src/store/action-reducers/material.ts @@ -24,7 +24,7 @@ export namespace MaterialActionReducers { reducer: (draftState, { materialId, targetPosition }) => { updateElementPosition( draftState, - 'materials', + 'material', materialId, targetPosition ); diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts index d25fca861..b3953393a 100644 --- a/shared/src/store/action-reducers/patient.ts +++ b/shared/src/store/action-reducers/patient.ts @@ -29,7 +29,7 @@ export function deletePatient( draftState: Mutable, patientId: UUID ) { - removeElementPosition(draftState, 'patients', patientId); + removeElementPosition(draftState, 'patient', patientId); delete draftState.patients[patientId]; } @@ -120,7 +120,7 @@ export namespace PatientActionReducers { } const mutablePatient = cloneDeepMutable(patient); draftState.patients[mutablePatient.id] = mutablePatient; - addElementPosition(draftState, 'patients', mutablePatient.id); + addElementPosition(draftState, 'patient', mutablePatient.id); return draftState; }, rights: 'trainer', @@ -131,7 +131,7 @@ export namespace PatientActionReducers { reducer: (draftState, { patientId, targetPosition }) => { updateElementPosition( draftState, - 'patients', + 'patient', patientId, targetPosition ); @@ -152,7 +152,7 @@ export namespace PatientActionReducers { export const setVisibleStatus: ActionReducer = { action: SetVisibleStatusAction, reducer: (draftState, { patientId, patientStatus }) => { - const patient = getElement(draftState, 'patients', patientId); + const patient = getElement(draftState, 'patient', patientId); patient.pretriageStatus = patientStatus; if (patient.metaPosition.type === 'coordinates') { @@ -167,7 +167,7 @@ export namespace PatientActionReducers { export const setUserTextAction: ActionReducer = { action: SetUserTextAction, reducer: (draftState, { patientId, remarks }) => { - const patient = getElement(draftState, 'patients', patientId); + const patient = getElement(draftState, 'patient', patientId); patient.remarks = remarks; return draftState; }, diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts index 390e0456e..4de91f2ec 100644 --- a/shared/src/store/action-reducers/simulated-region.ts +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -71,7 +71,7 @@ export namespace SimulatedRegionActionReducers { { action: RemoveSimulatedRegionAction, reducer: (draftState, { simulatedRegionId }) => { - getElement(draftState, 'simulatedRegions', simulatedRegionId); + getElement(draftState, 'simulatedRegion', simulatedRegionId); delete draftState.simulatedRegions[simulatedRegionId]; return draftState; }, @@ -84,7 +84,7 @@ export namespace SimulatedRegionActionReducers { reducer: (draftState, { simulatedRegionId, targetPosition }) => { const simulatedRegion = getElement( draftState, - 'simulatedRegions', + 'simulatedRegion', simulatedRegionId ); simulatedRegion.position = cloneDeepMutable(targetPosition); @@ -102,7 +102,7 @@ export namespace SimulatedRegionActionReducers { ) => { const simulatedRegion = getElement( draftState, - 'simulatedRegions', + 'simulatedRegion', simulatedRegionId ); simulatedRegion.position = cloneDeepMutable(targetPosition); @@ -118,7 +118,7 @@ export namespace SimulatedRegionActionReducers { reducer: (draftState, { simulatedRegionId, newName }) => { const simulatedRegion = getElement( draftState, - 'simulatedRegions', + 'simulatedRegion', simulatedRegionId ); simulatedRegion.name = newName; diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts index dd55cbae0..f72d916c9 100644 --- a/shared/src/store/action-reducers/transfer-point.ts +++ b/shared/src/store/action-reducers/transfer-point.ts @@ -124,7 +124,7 @@ export namespace TransferPointActionReducers { reducer: (draftState, { transferPointId, targetPosition }) => { const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); transferPoint.position = cloneDeepMutable(targetPosition); @@ -142,7 +142,7 @@ export namespace TransferPointActionReducers { ) => { const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); // Empty strings are ignored @@ -173,12 +173,12 @@ export namespace TransferPointActionReducers { } const transferPoint1 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId1 ); const transferPoint2 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId2 ); const _duration = @@ -210,12 +210,12 @@ export namespace TransferPointActionReducers { } const transferPoint1 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId1 ); const transferPoint2 = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId2 ); delete transferPoint1.reachableTransferPoints[transferPointId2]; @@ -230,20 +230,20 @@ export namespace TransferPointActionReducers { action: RemoveTransferPointAction, reducer: (draftState, { transferPointId }) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', transferPointId); + getElement(draftState, 'transferPoint', transferPointId); // TODO: make it dynamic (if at any time something else is able to transfer this part needs to be changed accordingly) // Let all vehicles and personnel arrive that are on transfer to this transferPoint before deleting it for (const vehicleId of Object.keys(draftState.vehicles)) { const vehicle = getElement( draftState, - 'vehicles', + 'vehicle', vehicleId ); if ( vehicle.transfer?.targetTransferPointId === transferPointId ) { - letElementArrive(draftState, 'vehicles', vehicleId); + letElementArrive(draftState, vehicle.type, vehicleId); } } for (const personnelId of Object.keys(draftState.personnel)) { @@ -256,7 +256,11 @@ export namespace TransferPointActionReducers { personnel.transfer?.targetTransferPointId === transferPointId ) { - letElementArrive(draftState, 'personnel', personnelId); + letElementArrive( + draftState, + personnel.type, + personnelId + ); } } // TODO: If we can assume that the transfer points are always connected to each other, @@ -286,10 +290,10 @@ export namespace TransferPointActionReducers { action: ConnectHospitalAction, reducer: (draftState, { transferPointId, hospitalId }) => { // Check if hospital with this Id exists - getElement(draftState, 'hospitals', hospitalId); + getElement(draftState, 'hospital', hospitalId); const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); transferPoint.reachableHospitals[hospitalId] = true; @@ -302,10 +306,10 @@ export namespace TransferPointActionReducers { action: DisconnectHospitalAction, reducer: (draftState, { hospitalId, transferPointId }) => { // Check if hospital with this Id exists - getElement(draftState, 'hospitals', hospitalId); + getElement(draftState, 'hospital', hospitalId); const transferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', transferPointId ); delete transferPoint.reachableHospitals[hospitalId]; diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index 9dc2eee4d..eb0b2f5f1 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -17,9 +17,9 @@ import { updateElementPosition, } from './utils/spatial-elements'; -type TransferableElementType = 'personnel' | 'vehicles'; +export type TransferableElementType = 'personnel' | 'vehicle'; const transferableElementTypeAllowedValues: AllowedValues = - { personnel: true, vehicles: true }; + { personnel: true, vehicle: true }; /** * Personnel/Vehicle in transfer will arrive immediately at new targetTransferPoint @@ -38,7 +38,7 @@ export function letElementArrive( } const targetTransferPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', element.transfer.targetTransferPointId ); const newPosition: Mutable = { @@ -135,7 +135,7 @@ export namespace TransferActionReducers { { elementType, elementId, startPoint, targetTransferPointId } ) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); + getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); if (element.transfer) { throw new ReducerError( @@ -148,7 +148,7 @@ export namespace TransferActionReducers { if (startPoint.type === 'transferPoint') { const transferStartPoint = getElement( draftState, - 'transferPoints', + 'transferPoint', startPoint.transferPointId ); const connection = @@ -206,7 +206,7 @@ export namespace TransferActionReducers { } if (targetTransferPointId) { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); + getElement(draftState, 'transferPoint', targetTransferPointId); element.transfer.targetTransferPointId = targetTransferPointId; } if (timeToAdd) { @@ -228,7 +228,7 @@ export namespace TransferActionReducers { { elementType, elementId, targetTransferPointId } ) => { // check if transferPoint exists - getElement(draftState, 'transferPoints', targetTransferPointId); + getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); if (!element.transfer) { throw getNotInTransferError(element.id); diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts index e811becfc..ca0fde55a 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts @@ -22,7 +22,7 @@ interface Catering { * The id of the material or personnel catering */ catererId: UUID; - catererType: 'materials' | 'personnel'; + catererType: 'material' | 'personnel'; /** * All patients treated by {@link catererId} */ @@ -43,11 +43,11 @@ function assertCatering( for (const catering of caterings) { // Update all the patients const patients = catering.patientIds.map((patientId) => - getElement(draftState, 'patients', patientId) + getElement(draftState, 'patient', patientId) ); for (const patient of patients) { patient[ - catering.catererType === 'materials' + catering.catererType === 'material' ? 'assignedMaterialIds' : 'assignedPersonnelIds' ][catering.catererId] = true; @@ -288,7 +288,7 @@ describe('calculate treatment', () => { assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.greenPatient], }, ]); @@ -324,7 +324,7 @@ describe('calculate treatment', () => { assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.redPatient], }, ]); @@ -392,7 +392,7 @@ describe('calculate treatment', () => { assertCatering(beforeState, newState, [ { catererId: ids.material, - catererType: 'materials', + catererType: 'material', patientIds: [ids.redPatient, ids.greenPatient], }, ]); diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts index fbc9fd9d7..090729406 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts @@ -6,6 +6,7 @@ import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range'; import type { Mutable, UUID } from '../../../utils'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; import { getElement } from './get-element'; // TODO: `caterFor` and `treat` are currently used as synonyms without a clear distinction. @@ -82,7 +83,7 @@ function tryToCaterFor( cateringElement.assignedPatientIds[patient.id] = true; - if (isPersonnel(cateringElement)) { + if (cateringElement.type === 'personnel') { patient.assignedPersonnelIds[cateringElement.id] = true; } else { patient.assignedMaterialIds[cateringElement.id] = true; @@ -92,26 +93,6 @@ function tryToCaterFor( return true; } -// TODO: Instead, give each Element a "type" property -> discriminated union -function isPatient( - element: Mutable -): element is Mutable { - return (element as Patient).personalInformation !== undefined; -} - -function isPersonnel( - element: Mutable -): element is Mutable { - return (element as Personnel).personnelType !== undefined; -} - -function isMaterial( - element: Mutable -): element is Mutable { - // as Material does not include any distinguishable properties, we will check if it is not of type Personnel or Patient - return !isPersonnel(element) && !isPatient(element); -} - /** * @param position of the patient where all elements of {@link elementType} should be recalculated * @param elementIdsToBeSkipped the elements whose treatment should not be updated @@ -119,11 +100,11 @@ function isMaterial( function updateCateringAroundPatient( state: Mutable, position: Position, - elementType: 'materials' | 'personnel', + elementType: 'material' | 'personnel', elementIdsToBeSkipped: Set ) { const elementsInTreatmentRange = SpatialTree.findAllElementsInCircle( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], position, maxTreatmentRange ).filter((elementId) => !elementIdsToBeSkipped.has(elementId)); @@ -140,7 +121,7 @@ function removeTreatmentsOfElement( // TODO: when elements have their own type saved don't use const patient = getElement(state, 'patients', element.id); // instead use const patient = element; // same for personnel and material in the other if statements - if (isPatient(element)) { + if (element.type === 'patient') { const patient = element; // Make all personnel stop treating this patient for (const personnelId of Object.keys(patient.assignedPersonnelIds)) { @@ -150,23 +131,23 @@ function removeTreatmentsOfElement( patient.assignedPersonnelIds = {}; // Make all material stop treating this patient for (const materialId of Object.keys(patient.assignedMaterialIds)) { - const material = getElement(state, 'materials', materialId); + const material = getElement(state, 'material', materialId); delete material.assignedPatientIds[patient.id]; } patient.assignedMaterialIds = {}; - } else if (isPersonnel(element)) { + } else if (element.type === 'personnel') { const personnel = element; // This personnel doesn't treat any patients anymore for (const patientId of Object.keys(personnel.assignedPatientIds)) { - const patient = getElement(state, 'patients', patientId); + const patient = getElement(state, 'patient', patientId); delete patient.assignedPersonnelIds[personnel.id]; } personnel.assignedPatientIds = {}; - } else if (isMaterial(element)) { + } else if (element.type === 'material') { const material = element; // This material doesn't treat any patients anymore for (const patientId of Object.keys(material.assignedPatientIds)) { - const patient = getElement(state, 'patients', patientId); + const patient = getElement(state, 'patient', patientId); delete patient.assignedMaterialIds[material.id]; } material.assignedPatientIds = {}; @@ -194,7 +175,7 @@ export function updateTreatments( return; } - if (isPersonnel(element) || isMaterial(element)) { + if (element.type === 'personnel' || element.type === 'material') { updateCatering(state, element); return; } @@ -208,7 +189,7 @@ export function updateTreatments( alreadyUpdatedElementIds.add(personnelId); } for (const materialId of Object.keys(element.assignedMaterialIds)) { - updateCatering(state, getElement(state, 'materials', materialId)); + updateCatering(state, getElement(state, 'material', materialId)); // Saving materialIds of material that already got calculated - makes small movements of patients more efficient alreadyUpdatedElementIds.add(materialId); } @@ -222,7 +203,7 @@ export function updateTreatments( updateCateringAroundPatient( state, element.position, - 'materials', + 'material', alreadyUpdatedElementIds ); // The treatment of the patient has just been updated -> hence the visible status hasn't been changed since the last update @@ -270,7 +251,7 @@ function updateCatering( tryToCaterFor( cateringElement, catersFor, - getElement(state, 'patients', patientId), + getElement(state, 'patient', patientId), state.configuration.pretriageEnabled, state.configuration.bluePatientsEnabled ); @@ -296,7 +277,7 @@ function updateCatering( ) // Filter out every patient in the overrideTreatmentRange .filter((patientId) => !cateredForPatients.has(patientId)) - .map((patientId) => getElement(state, 'patients', patientId)); + .map((patientId) => getElement(state, 'patient', patientId)); const patientsPerStatus = groupBy(patientsInTreatmentRange, (patient) => getCateringStatus( diff --git a/shared/src/store/action-reducers/utils/get-element.ts b/shared/src/store/action-reducers/utils/get-element.ts index 721faa5dd..653f6087c 100644 --- a/shared/src/store/action-reducers/utils/get-element.ts +++ b/shared/src/store/action-reducers/utils/get-element.ts @@ -1,5 +1,7 @@ import type { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; +import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; import { ReducerError } from '../../reducer-error'; /** @@ -7,25 +9,16 @@ import { ReducerError } from '../../reducer-error'; * @throws ReducerError if the element does not exist */ export function getElement< - ElementType extends - | 'alarmGroups' - | 'clients' - | 'hospitals' - | 'mapImages' - | 'materials' - | 'patients' - | 'personnel' - | 'simulatedRegions' - | 'transferPoints' - | 'vehicles' - | 'viewports', + ElementType extends keyof ElementTypePluralMap, State extends ExerciseState | Mutable >( state: State, elementType: ElementType, elementId: UUID -): State[ElementType][UUID] { - const element = state[elementType][elementId] as State[ElementType][UUID]; +): State[ElementTypePluralMap[ElementType]][UUID] { + const element = state[elementTypePluralMap[elementType]][ + elementId + ] as State[ElementTypePluralMap[ElementType]][UUID]; if (!element) { throw new ReducerError( `Element of type ${elementType} with id ${elementId} does not exist` diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts index 6a88929cf..43fa7a604 100644 --- a/shared/src/store/action-reducers/utils/spatial-elements.ts +++ b/shared/src/store/action-reducers/utils/spatial-elements.ts @@ -3,6 +3,8 @@ import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable } from '../../../utils'; +import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; import { updateTreatments } from './calculate-treatments'; import { getElement } from './get-element'; @@ -11,7 +13,9 @@ import { getElement } from './get-element'; * The position of the element must be changed via one of the function in this file. * In addition, the respective functions must be called when an element gets added or removed. */ -export type SpatialElementType = 'materials' | 'patients' | 'personnel'; +type SpatialElementType = 'material' | 'patient' | 'personnel'; +type SpatialTypePluralMap = Pick; +export type SpatialElementPlural = SpatialTypePluralMap[SpatialElementType]; /** * Adds an element with a position and executes side effects to guarantee the consistency of the state. @@ -27,7 +31,7 @@ export function addElementPosition( return; } SpatialTree.addElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, element.position ); @@ -47,14 +51,14 @@ export function updateElementPosition( const startPosition = element.position; if (startPosition !== undefined) { SpatialTree.moveElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, startPosition, targetPosition ); } else { SpatialTree.addElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, targetPosition ); @@ -81,7 +85,7 @@ export function removeElementPosition( return; } SpatialTree.removeElement( - state.spatialTrees[elementType], + state.spatialTrees[elementTypePluralMap[elementType]], element.id, element.position ); diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts index c0704b6b3..227586a35 100644 --- a/shared/src/store/action-reducers/vehicle.ts +++ b/shared/src/store/action-reducers/vehicle.ts @@ -26,10 +26,10 @@ export function deleteVehicle( draftState: Mutable, vehicleId: UUID ) { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); // Delete related material and personnel Object.keys(vehicle.materialIds).forEach((materialId) => { - removeElementPosition(draftState, 'materials', materialId); + removeElementPosition(draftState, 'material', materialId); delete draftState.materials[materialId]; }); Object.keys(vehicle.personnelIds).forEach((personnelId) => { @@ -105,13 +105,13 @@ export class LoadVehicleAction implements Action { public readonly vehicleId!: UUID; @IsLiteralUnion({ - materials: true, - patients: true, + material: true, + patient: true, personnel: true, }) public readonly elementToBeLoadedType!: - | 'materials' - | 'patients' + | 'material' + | 'patient' | 'personnel'; @IsUUID(4, uuidValidationOptions) @@ -155,7 +155,7 @@ export namespace VehicleActionReducers { vehicleId: vehicle.id, }; draftState.materials[material.id] = material; - addElementPosition(draftState, 'materials', material.id); + addElementPosition(draftState, 'material', material.id); } for (const person of cloneDeepMutable(personnel)) { person.metaPosition = { @@ -173,7 +173,7 @@ export namespace VehicleActionReducers { export const moveVehicle: ActionReducer = { action: MoveVehicleAction, reducer: (draftState, { vehicleId, targetPosition }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); vehicle.position = cloneDeepMutable(targetPosition); vehicle.metaPosition = { type: 'coordinates', @@ -187,7 +187,7 @@ export namespace VehicleActionReducers { export const renameVehicle: ActionReducer = { action: RenameVehicleAction, reducer: (draftState, { vehicleId, name }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); vehicle.name = name; for (const personnelId of Object.keys(vehicle.personnelIds)) { draftState.personnel[personnelId]!.vehicleName = name; @@ -212,7 +212,7 @@ export namespace VehicleActionReducers { export const unloadVehicle: ActionReducer = { action: UnloadVehicleAction, reducer: (draftState, { vehicleId }) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); const unloadMetaPosition = vehicle.metaPosition; if (unloadMetaPosition.type !== 'coordinates') { throw new ReducerError( @@ -239,7 +239,7 @@ export namespace VehicleActionReducers { for (const patientId of patientIds) { x += space; - updateElementPosition(draftState, 'patients', patientId, { + updateElementPosition(draftState, 'patient', patientId, { x, y: unloadPosition.y, }); @@ -268,13 +268,9 @@ export namespace VehicleActionReducers { for (const materialId of materialIds) { x += space; - const material = getElement( - draftState, - 'materials', - materialId - ); + const material = getElement(draftState, 'material', materialId); if (Material.isInVehicle(material)) { - updateElementPosition(draftState, 'materials', materialId, { + updateElementPosition(draftState, 'material', materialId, { x, y: unloadPosition.y, }); @@ -292,12 +288,12 @@ export namespace VehicleActionReducers { draftState, { vehicleId, elementToBeLoadedId, elementToBeLoadedType } ) => { - const vehicle = getElement(draftState, 'vehicles', vehicleId); + const vehicle = getElement(draftState, 'vehicle', vehicleId); switch (elementToBeLoadedType) { - case 'materials': { + case 'material': { const material = getElement( draftState, - 'materials', + 'material', elementToBeLoadedId ); if (!vehicle.materialIds[elementToBeLoadedId]) { @@ -309,7 +305,7 @@ export namespace VehicleActionReducers { type: 'vehicle', vehicleId, }; - removeElementPosition(draftState, 'materials', material.id); + removeElementPosition(draftState, 'material', material.id); break; } case 'personnel': { @@ -339,10 +335,10 @@ export namespace VehicleActionReducers { ); break; } - case 'patients': { + case 'patient': { const patient = getElement( draftState, - 'patients', + 'patient', elementToBeLoadedId ); if ( @@ -359,13 +355,13 @@ export namespace VehicleActionReducers { type: 'vehicle', vehicleId, }; - removeElementPosition(draftState, 'patients', patient.id); + removeElementPosition(draftState, patient.type, patient.id); // Load in all materials Object.keys(vehicle.materialIds).forEach((materialId) => { getElement( draftState, - 'materials', + 'material', materialId ).metaPosition = { type: 'vehicle', @@ -373,7 +369,7 @@ export namespace VehicleActionReducers { }; removeElementPosition( draftState, - 'materials', + 'material', materialId ); }); diff --git a/shared/src/store/action-reducers/viewport.ts b/shared/src/store/action-reducers/viewport.ts index 13c3b1919..f81ee56a3 100644 --- a/shared/src/store/action-reducers/viewport.ts +++ b/shared/src/store/action-reducers/viewport.ts @@ -69,7 +69,7 @@ export namespace ViewportActionReducers { export const removeViewport: ActionReducer = { action: RemoveViewportAction, reducer: (draftState, { viewportId }) => { - getElement(draftState, 'viewports', viewportId); + getElement(draftState, 'viewport', viewportId); delete draftState.viewports[viewportId]; return draftState; }, @@ -79,7 +79,7 @@ export namespace ViewportActionReducers { export const moveViewport: ActionReducer = { action: MoveViewportAction, reducer: (draftState, { viewportId, targetPosition }) => { - const viewport = getElement(draftState, 'viewports', viewportId); + const viewport = getElement(draftState, 'viewport', viewportId); viewport.position = cloneDeepMutable(targetPosition); return draftState; }, @@ -89,7 +89,7 @@ export namespace ViewportActionReducers { export const resizeViewport: ActionReducer = { action: ResizeViewportAction, reducer: (draftState, { viewportId, targetPosition, newSize }) => { - const viewport = getElement(draftState, 'viewports', viewportId); + const viewport = getElement(draftState, 'viewport', viewportId); viewport.position = cloneDeepMutable(targetPosition); viewport.size = cloneDeepMutable(newSize); return draftState; @@ -100,7 +100,7 @@ export namespace ViewportActionReducers { export const renameViewport: ActionReducer = { action: RenameViewportAction, reducer: (draftState, { viewportId, newName }) => { - const viewport = getElement(draftState, 'viewports', viewportId); + const viewport = getElement(draftState, 'viewport', viewportId); viewport.name = newName; return draftState; }, diff --git a/shared/src/store/reduce-exercise-state.spec.ts b/shared/src/store/reduce-exercise-state.spec.ts index 49afadc2d..ac72e6cdd 100644 --- a/shared/src/store/reduce-exercise-state.spec.ts +++ b/shared/src/store/reduce-exercise-state.spec.ts @@ -12,6 +12,7 @@ describe('exerciseReducer', () => { function generateViewport(): Viewport { return { id: uuid(), + type: 'viewport', name: 'Test', size: { width: 100, height: 100 }, position: { x: 0, y: 0 }, diff --git a/shared/src/store/validate-exercise-action.spec.ts b/shared/src/store/validate-exercise-action.spec.ts index 9bc74a97d..da9aab590 100644 --- a/shared/src/store/validate-exercise-action.spec.ts +++ b/shared/src/store/validate-exercise-action.spec.ts @@ -71,6 +71,7 @@ describe('validateExerciseAction', () => { type: '[Viewport] Add viewport', viewport: { id: 'b02c7756-ea52-427f-9fc3-0e163799544d', + type: 'viewport', name: '', size: { height: 1, @@ -112,6 +113,7 @@ describe('validateExerciseAction', () => { type: '[Viewport] Add viewport', viewport: { id: 'b02c7756-ea52-427f-9fc3-0e163799544d', + type: 'viewport', name: '', size: { height: 1, diff --git a/shared/src/utils/element-type-plural-map.ts b/shared/src/utils/element-type-plural-map.ts new file mode 100644 index 000000000..630dcd7ef --- /dev/null +++ b/shared/src/utils/element-type-plural-map.ts @@ -0,0 +1,21 @@ +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from '../models/element'; +import type { ExerciseState } from '../state'; + +type ElementType = Element['type']; + +export const elementTypePluralMap = { + alarmGroup: 'alarmGroups', + client: 'clients', + hospital: 'hospitals', + mapImage: 'mapImages', + material: 'materials', + patient: 'patients', + personnel: 'personnel', + simulatedRegion: 'simulatedRegions', + transferPoint: 'transferPoints', + vehicle: 'vehicles', + viewport: 'viewports', +} as const satisfies { [Key in ElementType]: keyof ExerciseState }; + +export type ElementTypePluralMap = typeof elementTypePluralMap; From 028ecd98ca77a03dfa365fa1fe5b0d87b4e10da6 Mon Sep 17 00:00:00 2001 From: Julian Schmidt Date: Tue, 31 Jan 2023 09:50:32 +0000 Subject: [PATCH 20/58] Remove unsupportedChangeProperties (#630) --- .../catering-lines-feature-manager.ts | 8 +---- .../feature-managers/element-manager.ts | 34 ++----------------- .../map-images-feature-manager.ts | 2 -- .../material-feature-manager.ts | 2 -- .../moveable-feature-manager.ts | 14 +++----- .../patient-feature-manager.ts | 2 -- .../personnel-feature-manager.ts | 2 -- .../simulated-region-feature-manager.ts | 2 -- .../transfer-lines-feature-manager.ts | 8 +---- .../transfer-point-feature-manager.ts | 5 --- .../vehicle-feature-manager.ts | 2 -- .../viewport-feature-manager.ts | 2 -- .../exercise-map/utility/ol-map-manager.ts | 2 +- 13 files changed, 10 insertions(+), 75 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index 8272b8807..bdf33f8b8 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -11,15 +11,9 @@ import { LineStyleHelper } from '../utility/style-helper/line-style-helper'; import { ElementManager } from './element-manager'; export class CateringLinesFeatureManager - extends ElementManager< - CateringLine, - LineString, - ReadonlySet - > + extends ElementManager implements FeatureManager { - readonly unsupportedChangeProperties = new Set(['id'] as const); - private readonly lineStyleHelper = new LineStyleHelper( (feature) => ({ color: rgbColorPalette.cyan, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index d341b294e..35ca3076d 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -11,12 +11,7 @@ import { generateChangedProperties } from '../utility/generate-changed-propertie */ export abstract class ElementManager< Element extends ImmutableJsonObject, - FeatureType extends Geometry, - UnsupportedChangeProperties extends ReadonlySet, - SupportedChangeProperties extends Exclude< - ReadonlySet, - UnsupportedChangeProperties - > = Exclude, UnsupportedChangeProperties> + FeatureType extends Geometry > { /** * This should be called if a new element is added. @@ -40,10 +35,6 @@ export abstract class ElementManager< /** * This should be called if an element is changed. - * - * The best way to reflect the changes on the feature is mostly to update the already created feature directly. This is done in {@link changeFeature}. - * But, because this requires extra code for each changed property, it is not feasible to do for all properties. - * If any property in {@link unsupportedChangeProperties} has changed, we deleted the old feature and create a new one instead. */ public onElementChanged(oldElement: Element, newElement: Element): void { const elementFeature = this.getFeatureFromElement(oldElement); @@ -56,11 +47,6 @@ export abstract class ElementManager< oldElement, newElement ); - if (!this.areAllPropertiesSupported(changedProperties)) { - this.onElementDeleted(oldElement); - this.onElementCreated(newElement); - return; - } elementFeature.set(featureElementKey, newElement); this.changeFeature( oldElement, @@ -84,18 +70,13 @@ export abstract class ElementManager< ): void; /** - * The properties of {@link Element} for which custom changes cannot be handled in {@link changeFeature}. - */ - abstract readonly unsupportedChangeProperties: UnsupportedChangeProperties; - /** - * This method must only be called if no properties in {@link unsupportedChangeProperties} are different between the two elements * @param changedProperties The properties that have changed between the {@link oldElement} and the {@link newElement} * @param elementFeature The openLayers feature that should be updated to reflect the changes */ abstract changeFeature( oldElement: Element, newElement: Element, - changedProperties: SupportedChangeProperties, + changedProperties: ReadonlySet, elementFeature: Feature ): void; @@ -106,17 +87,6 @@ export abstract class ElementManager< public getElementFromFeature(feature: Feature) { return feature.get(featureElementKey); } - - private areAllPropertiesSupported( - changedProperties: ReadonlySet - ): changedProperties is SupportedChangeProperties { - for (const changedProperty of changedProperties) { - if (this.unsupportedChangeProperties.has(changedProperty)) { - return false; - } - } - return true; - } } /** diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts index 1d34bd8ae..35e1a46d3 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts @@ -75,6 +75,4 @@ export class MapImageFeatureManager extends MoveableFeatureManager { !mapImage.isLocked ); } - - override unsupportedChangeProperties = new Set(['id', 'image'] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts index 42bd0446e..a93e7e716 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts @@ -57,8 +57,6 @@ export class MaterialFeatureManager extends MoveableFeatureManager< ]); } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts index 94034d561..daabb3566 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -18,15 +18,15 @@ import { TranslateInteraction } from '../utility/translate-interaction'; import { ElementManager } from './element-manager'; /** - * The base class for all element feature managers. - * * manages the position of the element - * * manages the default interactions of the element + * Manages the position of the element. + * Manages the default interactions of the element. + * Automatically redraws a feature (= reevaluates its style function) when an element property has changed. */ export abstract class MoveableFeatureManager< Element extends PositionableElement, FeatureType extends GeometryWithCoordinates = Point > - extends ElementManager> + extends ElementManager implements FeatureManager { public readonly togglePopup$ = new Subject>(); @@ -49,9 +49,6 @@ export abstract class MoveableFeatureManager< ); } - override unsupportedChangeProperties: ReadonlySet = new Set( - [] as const - ); createFeature(element: Element): Feature { const elementFeature = this.geometryHelper.create(element); elementFeature.setId(element.id); @@ -82,7 +79,6 @@ export abstract class MoveableFeatureManager< changeFeature( oldElement: Element, newElement: Element, - // It is too much work to correctly type this param with {@link unsupportedChangeProperties} changedProperties: ReadonlySet, elementFeature: Feature ): void { @@ -92,7 +88,7 @@ export abstract class MoveableFeatureManager< this.geometryHelper.getElementCoordinates(newElement) ); } - // If the style has updated, we need to redraw the feature + // Redraw the feature to reevaluate its style function elementFeature.changed(); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts index c2a3e70be..f1595228a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts @@ -101,6 +101,4 @@ export class PatientFeatureManager extends MoveableFeatureManager< }) ); } - - override unsupportedChangeProperties = new Set(['id', 'image'] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts index 98f6a144a..e9c25dfb3 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts @@ -58,8 +58,6 @@ export class PersonnelFeatureManager extends MoveableFeatureManager< ]); } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index 58c820119..bfb8af563 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -24,8 +24,6 @@ export class SimulatedRegionFeatureManager extends MoveableFeatureManager implements FeatureManager { - override unsupportedChangeProperties = new Set(['id'] as const); - constructor( olMap: OlMap, layer: VectorLayer>, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index be10f0b39..19dece1da 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -11,15 +11,9 @@ import type { FeatureManager } from '../utility/feature-manager'; import { ElementManager } from './element-manager'; export class TransferLinesFeatureManager - extends ElementManager< - TransferLine, - LineString, - ReadonlySet - > + extends ElementManager implements FeatureManager { - readonly unsupportedChangeProperties = new Set(['id'] as const); - constructor(public readonly layer: VectorLayer>) { super(); layer.setStyle( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 8012a443c..686b30eee 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -156,9 +156,4 @@ export class TransferPointFeatureManager extends MoveableFeatureManager): boolean { return selectStateSnapshot(selectCurrentRole, this.store) === 'trainer'; } - - override unsupportedChangeProperties = new Set([ - 'id', - 'internalName', - ] as const); } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts index a1aaaa123..314d0a1a7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts @@ -94,8 +94,6 @@ export class VehicleFeatureManager extends MoveableFeatureManager< return false; } - override unsupportedChangeProperties = new Set(['id', 'image'] as const); - public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 5f2ceef63..ab1050d9f 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -34,8 +34,6 @@ export class ViewportFeatureManager extends MoveableFeatureManager implements FeatureManager { - override unsupportedChangeProperties = new Set(['id'] as const); - constructor( olMap: OlMap, layer: VectorLayer>, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index a6946ebc4..b125d3b95 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -378,7 +378,7 @@ export class OlMapManager { private registerFeatureElementManager< Element extends ImmutableJsonObject, T extends MergeIntersection< - ElementManager & FeatureManager + ElementManager & FeatureManager > >( featureManager: T, From a485e41fd87410bf624d8ce2b2a774f928e57986 Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Tue, 31 Jan 2023 15:10:07 +0100 Subject: [PATCH 21/58] Fix the Bug (#635) --- .../choose-transfer-target-popup.component.html | 2 +- .../choose-transfer-target-popup.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html index b015592ad..d92e204c7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/shared/choose-transfer-target-popup/choose-transfer-target-popup.component.html @@ -21,7 +21,7 @@ [transferPointId]="reachableTransferPoint.id" > - +
    @@ -37,21 +38,21 @@ @@ -71,21 +72,21 @@ diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts index 35fdd6a1a..da2e76397 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/transfer-overview-table/transfer-overview-table.component.ts @@ -1,5 +1,6 @@ import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; +import { currentTransferOf } from 'digital-fuesim-manv-shared'; import type { AppState } from 'src/app/state/app.state'; import { selectExerciseStatus, @@ -20,6 +21,8 @@ export class TransferOverviewTableComponent { selectPersonnelInTransfer ); + public currentTransferOf = currentTransferOf; + public readonly exerciseStatus$ = this.store.select(selectExerciseStatus); constructor(private readonly store: Store) {} diff --git a/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts b/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts deleted file mode 100644 index 64c7c42dd..000000000 --- a/frontend/src/app/pages/exercises/exercise/shared/utility/types/with-position.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { Position } from 'digital-fuesim-manv-shared'; - -export type WithPosition = T & { - position: Position; -}; diff --git a/frontend/src/app/shared/types/catering-line.ts b/frontend/src/app/shared/types/catering-line.ts index 673762727..8326a5261 100644 --- a/frontend/src/app/shared/types/catering-line.ts +++ b/frontend/src/app/shared/types/catering-line.ts @@ -1,8 +1,8 @@ -import type { UUID, Position } from 'digital-fuesim-manv-shared'; +import type { UUID, MapCoordinates } from 'digital-fuesim-manv-shared'; export interface CateringLine { readonly id: `${UUID}:${UUID}`; - readonly catererPosition: Position; - readonly patientPosition: Position; + readonly catererPosition: MapCoordinates; + readonly patientPosition: MapCoordinates; } diff --git a/frontend/src/app/shared/types/transfer-line.ts b/frontend/src/app/shared/types/transfer-line.ts index 3c615d376..2769f4d7e 100644 --- a/frontend/src/app/shared/types/transfer-line.ts +++ b/frontend/src/app/shared/types/transfer-line.ts @@ -1,9 +1,9 @@ -import type { Position, UUID } from 'digital-fuesim-manv-shared'; +import type { MapCoordinates, UUID } from 'digital-fuesim-manv-shared'; export interface TransferLine { readonly id: `${UUID}:${UUID}`; - readonly startPosition: Position; - readonly endPosition: Position; + readonly startPosition: MapCoordinates; + readonly endPosition: MapCoordinates; readonly duration: number; } diff --git a/frontend/src/app/state/application/selectors/exercise.selectors.ts b/frontend/src/app/state/application/selectors/exercise.selectors.ts index 0fb94a5a2..42e6ab4a8 100644 --- a/frontend/src/app/state/application/selectors/exercise.selectors.ts +++ b/frontend/src/app/state/application/selectors/exercise.selectors.ts @@ -2,10 +2,10 @@ import { createSelector } from '@ngrx/store'; import type { ExerciseState, Personnel, - Transfer, UUID, Vehicle, } from 'digital-fuesim-manv-shared'; +import { isInTransfer, currentCoordinatesOf } from 'digital-fuesim-manv-shared'; import type { TransferLine } from 'src/app/shared/types/transfer-line'; import type { AppState } from '../../app.state'; @@ -119,8 +119,10 @@ export const selectTransferLines = createSelector( Object.entries(transferPoint.reachableTransferPoints).map( ([connectedId, { duration }]) => ({ id: `${transferPoint.id}:${connectedId}` as const, - startPosition: transferPoint.position, - endPosition: transferPoints[connectedId]!.position, + startPosition: currentCoordinatesOf(transferPoint), + endPosition: currentCoordinatesOf( + transferPoints[connectedId]! + ), duration, }) ) @@ -159,15 +161,15 @@ export function createSelectReachableHospitals(transferPointId: UUID) { export const selectVehiclesInTransfer = createSelector( selectVehicles, (vehicles) => - Object.values(vehicles).filter( - (vehicle) => vehicle.transfer !== undefined - ) as (Vehicle & { transfer: Transfer })[] + Object.values(vehicles).filter((vehicle) => + isInTransfer(vehicle) + ) as Vehicle[] ); export const selectPersonnelInTransfer = createSelector( selectPersonnel, (personnel) => - Object.values(personnel).filter( - (_personnel) => _personnel.transfer !== undefined - ) as (Personnel & { transfer: Transfer })[] + Object.values(personnel).filter((_personnel) => + isInTransfer(_personnel) + ) as Personnel[] ); diff --git a/frontend/src/app/state/application/selectors/shared.selectors.ts b/frontend/src/app/state/application/selectors/shared.selectors.ts index 706764625..fbd0c8421 100644 --- a/frontend/src/app/state/application/selectors/shared.selectors.ts +++ b/frontend/src/app/state/application/selectors/shared.selectors.ts @@ -4,15 +4,18 @@ import type { Material, Patient, Personnel, - Position, SimulatedRegion, TransferPoint, UUID, Vehicle, + WithPosition, +} from 'digital-fuesim-manv-shared'; +import { + currentCoordinatesOf, + isOnMap, + Viewport, } from 'digital-fuesim-manv-shared'; -import { Viewport } from 'digital-fuesim-manv-shared'; import { pickBy } from 'lodash-es'; -import type { WithPosition } from 'src/app/pages/exercises/exercise/shared/utility/types/with-position'; import type { CateringLine } from 'src/app/shared/types/catering-line'; import type { AppState } from '../../app.state'; import { @@ -63,20 +66,16 @@ export const selectRestrictedViewport = createSelector( * @returns a selector that returns a UUIDMap of all elements that have a position and are in the viewport restriction */ function selectVisibleElementsFactory< - Element extends { readonly position?: Position }, + Element extends WithPosition, Elements extends { readonly [key: UUID]: Element } = { readonly [key: UUID]: Element; - }, - ElementsWithPosition extends { - [Id in keyof Elements]: WithPosition; - } = { [Id in keyof Elements]: WithPosition } + } >( selectElements: (state: AppState) => Elements, - isInViewport: ( - element: WithPosition, - viewport: Viewport - ) => boolean = (element, viewport) => - Viewport.isInViewport(viewport, element.position) + isInViewport: (element: Element, viewport: Viewport) => boolean = ( + element, + viewport + ) => Viewport.isInViewport(viewport, currentCoordinatesOf(element)) ) { return createSelector( selectRestrictedViewport, @@ -86,14 +85,11 @@ function selectVisibleElementsFactory< elements, (element) => // Is placed on the map - element.position && + isOnMap(element) && // No viewport restriction (!restrictedViewport || - isInViewport( - element as WithPosition, - restrictedViewport - )) - ) as ElementsWithPosition + isInViewport(element, restrictedViewport)) + ) ); } @@ -129,7 +125,7 @@ export const selectVisibleCateringLines = createSelector( (viewport, materials, personnel, patients) => // Mostly, there are fewer untreated patients than materials and personnel that are not treating Object.values(patients) - .filter((patient) => patient.position !== undefined) + .filter((patient) => isOnMap(patient)) .flatMap((patient) => [ ...Object.keys(patient.assignedPersonnelIds).map( @@ -140,9 +136,9 @@ export const selectVisibleCateringLines = createSelector( ), ].map((caterer) => ({ id: `${caterer.id}:${patient.id}` as const, - patientPosition: patient.position!, + patientPosition: currentCoordinatesOf(patient), // If the catering element is treating a patient, it must have a position - catererPosition: caterer.position!, + catererPosition: currentCoordinatesOf(caterer), })) ) // To improve performance, all Lines where both ends are not in the viewport diff --git a/shared/src/data/dummy-objects/patient.ts b/shared/src/data/dummy-objects/patient.ts index 7fd5fc3c6..dfeb9b58b 100644 --- a/shared/src/data/dummy-objects/patient.ts +++ b/shared/src/data/dummy-objects/patient.ts @@ -1,6 +1,6 @@ import { FunctionParameters, Patient, PatientHealthState } from '../../models'; -import { MapCoordinates } from '../../models/utils/map-coordinates'; -import { MapPosition } from '../../models/utils/map-position'; +import { MapCoordinates } from '../../models/utils/position/map-coordinates'; +import { MapPosition } from '../../models/utils/position/map-position'; import { PatientStatusCode } from '../../models/utils/patient-status-code'; import { defaultPatientCategories } from '../default-state/patient-templates'; diff --git a/shared/src/models/map-image.ts b/shared/src/models/map-image.ts index ad15022a7..9d8f158a5 100644 --- a/shared/src/models/map-image.ts +++ b/shared/src/models/map-image.ts @@ -2,7 +2,9 @@ import { Type } from 'class-transformer'; import { IsBoolean, IsInt, IsUUID, ValidateNested } from 'class-validator'; import { uuid, UUID, uuidValidationOptions } from '../utils'; import { IsValue } from '../utils/validators'; -import { Position, getCreate, ImageProperties } from './utils'; +import { IsPosition } from '../utils/validators/is-position'; +import type { MapCoordinates } from './utils'; +import { MapPosition, getCreate, ImageProperties, Position } from './utils'; export class MapImage { @IsUUID(4, uuidValidationOptions) @@ -11,8 +13,11 @@ export class MapImage { @IsValue('mapImage' as const) public readonly type = 'mapImage'; + /** + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. + */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @ValidateNested() @@ -38,12 +43,12 @@ export class MapImage { * @deprecated Use {@link create} instead */ constructor( - topLeft: Position, + topLeft: MapCoordinates, image: ImageProperties, isLocked: boolean, zIndex: number ) { - this.position = topLeft; + this.position = MapPosition.create(topLeft); this.image = image; this.isLocked = isLocked; this.zIndex = zIndex; diff --git a/shared/src/models/material.ts b/shared/src/models/material.ts index 4fea13d4d..0df36780c 100644 --- a/shared/src/models/material.ts +++ b/shared/src/models/material.ts @@ -6,15 +6,14 @@ import { IsNumber, Min, Max, - IsOptional, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsUUIDSet, IsValue } from '../utils/validators'; -import { IsMetaPosition } from '../utils/validators/is-metaposition'; +import { IsPosition } from '../utils/validators/is-position'; import type { MaterialTemplate } from './material-template'; -import { CanCaterFor, Position, ImageProperties, getCreate } from './utils'; -import { MetaPosition } from './utils/meta-position'; +import { CanCaterFor, ImageProperties, getCreate } from './utils'; +import { Position } from './utils/position/position'; export class Material { @IsUUID(4, uuidValidationOptions) @@ -56,18 +55,12 @@ export class Material { @Max(maxTreatmentRange) public readonly treatmentRange: number; - @IsMetaPosition() - @ValidateNested() - public readonly metaPosition: MetaPosition; - /** - * @deprecated use {@link metaPosition} - * if undefined, is in vehicle with {@link this.vehicleId} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; + public readonly position: Position; @ValidateNested() @Type(() => ImageProperties) @@ -84,18 +77,16 @@ export class Material { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, - metaPosition: MetaPosition, - position?: Position + position: Position ) { this.vehicleId = vehicleId; this.vehicleName = vehicleName; this.assignedPatientIds = assignedPatientIds; - this.position = position; this.image = image; this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; - this.metaPosition = metaPosition; + this.position = position; } static readonly create = getCreate(this); @@ -104,7 +95,7 @@ export class Material { materialTemplate: MaterialTemplate, vehicleId: UUID, vehicleName: string, - metaPosition: MetaPosition + position: Position ): Material { return this.create( vehicleId, @@ -114,12 +105,7 @@ export class Material { materialTemplate.canCaterFor, materialTemplate.treatmentRange, materialTemplate.overrideTreatmentRange, - metaPosition, - undefined + position ); } - - static isInVehicle(material: Material): boolean { - return material.metaPosition.type === 'vehicle'; - } } diff --git a/shared/src/models/patient-template.ts b/shared/src/models/patient-template.ts index 82a4905c4..0c3140dbd 100644 --- a/shared/src/models/patient-template.ts +++ b/shared/src/models/patient-template.ts @@ -16,7 +16,7 @@ import { Patient } from './patient'; import type { FunctionParameters } from './patient-health-state'; import { PretriageInformation } from './utils/pretriage-information'; import { PatientHealthState } from './patient-health-state'; -import type { MetaPosition } from './utils/meta-position'; +import type { Position } from './utils/position/position'; export class PatientTemplate { @IsUUID(4, uuidValidationOptions) @@ -72,7 +72,7 @@ export class PatientTemplate { public static generatePatient( template: PatientTemplate, patientStatusCode: PatientStatusCode, - metaPosition: MetaPosition + position: Position ): Patient { // Randomize function parameters const healthStates = Object.fromEntries( @@ -113,7 +113,7 @@ export class PatientTemplate { template.image, template.health, '', - metaPosition + position ); } } diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index 6c5cecee4..a8f015149 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -2,7 +2,6 @@ import { Type } from 'class-transformer'; import { IsUUID, ValidateNested, - IsOptional, IsNumber, Max, Min, @@ -18,7 +17,7 @@ import { IsUUIDSet, IsValue, } from '../utils/validators'; -import { IsMetaPosition } from '../utils/validators/is-metaposition'; +import { IsPosition } from '../utils/validators/is-position'; import { PatientHealthState } from './patient-health-state'; import { BiometricInformation, @@ -26,12 +25,11 @@ import { PatientStatus, patientStatusAllowedValues, ImageProperties, - Position, healthPointsDefaults, HealthPoints, getCreate, } from './utils'; -import { MetaPosition } from './utils/meta-position'; +import { Position } from './utils/position/position'; import { PersonalInformation } from './utils/personal-information'; import { PretriageInformation } from './utils/pretriage-information'; @@ -72,26 +70,12 @@ export class Patient { @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsMetaPosition() - @ValidateNested() - public readonly metaPosition: MetaPosition; - /** - * @deprecated use {@link metaPosition} - * Exclusive-or to {@link vehicleId} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; - - /** - * @deprecated use {@link metaPosition} - * Exclusive-or to {@link position} - */ - @IsUUID(4, uuidValidationOptions) - @IsOptional() - public readonly vehicleId?: UUID; + public readonly position: Position; /** * The time the patient already is in the current state @@ -172,7 +156,7 @@ export class Patient { image: ImageProperties, health: HealthPoints, remarks: string, - metaPosition: MetaPosition + position: Position ) { this.personalInformation = personalInformation; this.biometricInformation = biometricInformation; @@ -185,7 +169,7 @@ export class Patient { this.image = image; this.health = health; this.remarks = remarks; - this.metaPosition = metaPosition; + this.position = position; } static readonly create = getCreate(this); @@ -207,10 +191,6 @@ export class Patient { return patient.treatmentTime >= this.pretriageTimeThreshold; } - static isInVehicle(patient: Patient): boolean { - return patient.metaPosition.type === 'vehicle'; - } - static isTreatedByPersonnel(patient: Patient) { return !isEmpty(patient.assignedPersonnelIds); } diff --git a/shared/src/models/personnel.ts b/shared/src/models/personnel.ts index 16ebc287c..7e5d55bd7 100644 --- a/shared/src/models/personnel.ts +++ b/shared/src/models/personnel.ts @@ -6,22 +6,19 @@ import { IsNumber, Min, Max, - IsOptional, } from 'class-validator'; import { maxTreatmentRange } from '../state-helpers/max-treatment-range'; import { uuidValidationOptions, UUID, uuid, UUIDSet } from '../utils'; import { IsLiteralUnion, IsUUIDSet, IsValue } from '../utils/validators'; -import { IsMetaPosition } from '../utils/validators/is-metaposition'; +import { IsPosition } from '../utils/validators/is-position'; import type { PersonnelTemplate } from './personnel-template'; import { PersonnelType, CanCaterFor, ImageProperties, - Position, - Transfer, getCreate, } from './utils'; -import { MetaPosition } from './utils/meta-position'; +import { Position } from './utils/position/position'; import { personnelTypeAllowedValues } from './utils/personnel-type'; export class Personnel { @@ -71,27 +68,12 @@ export class Personnel { @Type(() => ImageProperties) public readonly image: ImageProperties; - @IsMetaPosition() - @ValidateNested() - public readonly metaPosition: MetaPosition; - - /** - * @deprecated use {@link metaPosition} - * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or in transfer. - */ - @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; - /** - * * @deprecated use {@link metaPosition} - * If undefined, the personnel is either in the vehicle with {@link this.vehicleId} or has a {@link position}. + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Transfer) - @IsOptional() - public readonly transfer?: Transfer; + public readonly position: Position; /** * @deprecated Use {@link create} instead @@ -105,19 +87,17 @@ export class Personnel { canCaterFor: CanCaterFor, treatmentRange: number, overrideTreatmentRange: number, - metaPosition: MetaPosition, - position?: Position + position: Position ) { this.vehicleId = vehicleId; this.vehicleName = vehicleName; this.personnelType = personnelType; this.assignedPatientIds = assignedPatientIds; - this.position = position; this.image = image; this.canCaterFor = canCaterFor; this.treatmentRange = treatmentRange; this.overrideTreatmentRange = overrideTreatmentRange; - this.metaPosition = metaPosition; + this.position = position; } static readonly create = getCreate(this); @@ -126,7 +106,7 @@ export class Personnel { personnelTemplate: PersonnelTemplate, vehicleId: UUID, vehicleName: string, - metaPosition: MetaPosition + position: Position ): Personnel { return this.create( vehicleId, @@ -137,12 +117,7 @@ export class Personnel { personnelTemplate.canCaterFor, personnelTemplate.treatmentRange, personnelTemplate.overrideTreatmentRange, - metaPosition, - undefined + position ); } - - static isInVehicle(personnel: Personnel): boolean { - return personnel.metaPosition.type === 'vehicle'; - } } diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts index 8d4f47cc4..1e170c7f5 100644 --- a/shared/src/models/simulated-region.ts +++ b/shared/src/models/simulated-region.ts @@ -1,9 +1,18 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsPosition } from '../utils/validators/is-position'; import { IsValue } from '../utils/validators'; -import { getCreate, Position, Size } from './utils'; -import type { ImageProperties } from './utils'; +import { + getCreate, + isInSimulatedRegion, + MapPosition, + Position, + currentSimulatedRegionIdOf, + Size, +} from './utils'; +import type { ImageProperties, MapCoordinates } from './utils'; +import type { WithPosition } from './utils/position/with-position'; export class SimulatedRegion { @IsUUID(4, uuidValidationOptions) @@ -14,9 +23,11 @@ export class SimulatedRegion { /** * top-left position + * + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @ValidateNested() @@ -30,8 +41,8 @@ export class SimulatedRegion { * @param position top-left position * @deprecated Use {@link create} instead */ - constructor(position: Position, size: Size, name: string) { - this.position = position; + constructor(position: MapCoordinates, size: Size, name: string) { + this.position = MapPosition.create(position); this.size = size; this.name = name; } @@ -46,11 +57,11 @@ export class SimulatedRegion { static isInSimulatedRegion( region: SimulatedRegion, - position: Position + withPosition: WithPosition ): boolean { - // This class was copied from viewport.ts - // We will have to implement this logic differently - // later, for now, this is a stub method - return false; + return ( + isInSimulatedRegion(withPosition) && + currentSimulatedRegionIdOf(withPosition) === region.id + ); } } diff --git a/shared/src/models/transfer-point.ts b/shared/src/models/transfer-point.ts index 5aa895ca5..3691a5cac 100644 --- a/shared/src/models/transfer-point.ts +++ b/shared/src/models/transfer-point.ts @@ -1,4 +1,3 @@ -import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, UUIDSet, uuidValidationOptions } from '../utils'; import { @@ -6,8 +5,9 @@ import { IsUUIDSet, IsValue, } from '../utils/validators'; -import type { ImageProperties } from './utils'; -import { getCreate, Position } from './utils'; +import { IsPosition } from '../utils/validators/is-position'; +import type { ImageProperties, MapCoordinates } from './utils'; +import { MapPosition, Position, getCreate } from './utils'; export class TransferPoint { @IsUUID(4, uuidValidationOptions) @@ -16,8 +16,11 @@ export class TransferPoint { @IsValue('transferPoint' as const) public readonly type = 'transferPoint'; + /** + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. + */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @IsReachableTransferPoints() @@ -36,13 +39,13 @@ export class TransferPoint { * @deprecated Use {@link create} instead */ constructor( - position: Position, + position: MapCoordinates, reachableTransferPoints: ReachableTransferPoints, reachableHospitals: UUIDSet, internalName: string, externalName: string ) { - this.position = position; + this.position = MapPosition.create(position); this.reachableTransferPoints = reachableTransferPoints; this.reachableHospitals = reachableHospitals; this.internalName = internalName; diff --git a/shared/src/models/utils/get-create.ts b/shared/src/models/utils/get-create.ts index 5cccc3042..4dab6f921 100644 --- a/shared/src/models/utils/get-create.ts +++ b/shared/src/models/utils/get-create.ts @@ -9,7 +9,7 @@ import type { Constructor } from '../../utils'; * * @example * ```typescript - * export class Position { + * export class Coordinates { * @IsNumber() * public a: number; * /** diff --git a/shared/src/models/utils/index.ts b/shared/src/models/utils/index.ts index 3f5f846fd..7199bde54 100644 --- a/shared/src/models/utils/index.ts +++ b/shared/src/models/utils/index.ts @@ -1,10 +1,11 @@ -export { Position } from './position'; -export { MetaPosition } from './meta-position'; -export { MapPosition } from './map-position'; -export { VehiclePosition } from './vehicle-position'; -export { TransferPosition } from './transfer-position'; -export { SimulatedRegionPosition } from './simulated-region-position'; -export { MapCoordinates } from './map-coordinates'; +export { Position } from './position/position'; +export { WithPosition } from './position/with-position'; +export { MapPosition } from './position/map-position'; +export { VehiclePosition } from './position/vehicle-position'; +export { TransferPosition } from './position/transfer-position'; +export { SimulatedRegionPosition } from './position/simulated-region-position'; +export { MapCoordinates } from './position/map-coordinates'; +export * from './position/position-helpers'; export * from './patient-status'; export { Size } from './size'; export { Role } from './role'; diff --git a/shared/src/models/utils/map-position.ts b/shared/src/models/utils/map-position.ts deleted file mode 100644 index 726e0525f..000000000 --- a/shared/src/models/utils/map-position.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Type } from 'class-transformer'; -import { ValidateNested } from 'class-validator'; -import { IsValue } from '../../utils/validators'; -import { getCreate } from './get-create'; -import { MapCoordinates } from './map-coordinates'; - -export class MapPosition { - @IsValue('coordinates') - public readonly type = 'coordinates'; - - @Type(() => MapCoordinates) - @ValidateNested() - public readonly position: MapCoordinates; - - /** - * @deprecated Use {@link create} instead - */ - constructor(position: MapCoordinates) { - this.position = position; - } - - static readonly create = getCreate(this); -} diff --git a/shared/src/models/utils/position.ts b/shared/src/models/utils/position.ts deleted file mode 100644 index f61d5a5f9..000000000 --- a/shared/src/models/utils/position.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { IsNumber } from 'class-validator'; -import { getCreate } from './get-create'; - -export class Position { - @IsNumber() - public readonly x: number; - - @IsNumber() - public readonly y: number; - - /** - * @deprecated Use {@link create} instead - */ - constructor(x: number, y: number) { - this.x = x; - this.y = y; - } - - static readonly create = getCreate(this); -} diff --git a/shared/src/models/utils/map-coordinates.ts b/shared/src/models/utils/position/map-coordinates.ts similarity index 89% rename from shared/src/models/utils/map-coordinates.ts rename to shared/src/models/utils/position/map-coordinates.ts index cab5696bd..75963fef0 100644 --- a/shared/src/models/utils/map-coordinates.ts +++ b/shared/src/models/utils/position/map-coordinates.ts @@ -1,5 +1,5 @@ import { IsNumber } from 'class-validator'; -import { getCreate } from './get-create'; +import { getCreate } from '../get-create'; export class MapCoordinates { @IsNumber() diff --git a/shared/src/models/utils/position/map-position.ts b/shared/src/models/utils/position/map-position.ts new file mode 100644 index 000000000..9dd5a121f --- /dev/null +++ b/shared/src/models/utils/position/map-position.ts @@ -0,0 +1,32 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { MapCoordinates } from './map-coordinates'; +// import needed to display @link Links in Comments +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { isOnMap, isNotOnMap, currentCoordinatesOf } from './position-helpers'; + +export class MapPosition { + /** + * @deprecated Use {@link isOnMap } or {@link isNotOnMap} instead + */ + @IsValue('coordinates') + public readonly type = 'coordinates'; + + /** + * @deprecated Use {@link currentCoordinatesOf} instead + */ + @Type(() => MapCoordinates) + @ValidateNested() + public readonly coordinates: MapCoordinates; + + /** + * @deprecated Use {@link create} instead + */ + constructor(position: MapCoordinates) { + this.coordinates = position; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/position-helpers-mutable.ts b/shared/src/models/utils/position/position-helpers-mutable.ts new file mode 100644 index 000000000..862fa8f22 --- /dev/null +++ b/shared/src/models/utils/position/position-helpers-mutable.ts @@ -0,0 +1,97 @@ +import type { ExerciseState } from '../../../state'; +import { getElement } from '../../../store/action-reducers/utils'; +import { updateTreatments } from '../../../store/action-reducers/utils/calculate-treatments'; +import type { SpatialElementType } from '../../../store/action-reducers/utils/spatial-elements'; +import { + removeElementPosition, + updateElementPosition, +} from '../../../store/action-reducers/utils/spatial-elements'; +import type { Mutable, UUID } from '../../../utils'; +import { cloneDeepMutable } from '../../../utils'; +import type { Position } from './position'; +import { + coordinatesOfPosition, + isPositionNotOnMap, + isPositionOnMap, + isNotOnMap, + isOnMap, +} from './position-helpers'; + +type MutablePosition = Mutable; + +interface WithMutablePosition { + position: MutablePosition; + type: MovableType; +} +interface WithMutablePositionAndId extends WithMutablePosition { + id: UUID; +} +type MovableType = + | 'alarmGroup' + | 'client' + | 'hospital' + | 'mapImage' + | 'material' + | 'patient' + | 'personnel' + | 'simulatedRegion' + | 'transferPoint' + | 'vehicle' + | 'viewport'; + +export function changePositionWithId( + of: UUID, + to: Position, + type: MovableType, + inState: Mutable +) { + changePosition(getElement(inState, type, of) as any, to, inState); +} + +export function changePosition( + of: WithMutablePosition, + to: Position, + inState: Mutable +) { + if ( + of.type === 'patient' || + of.type === 'personnel' || + of.type === 'material' + ) { + updateSpatialElementTree( + of as WithMutablePositionAndId, + to, + of.type, + inState + ); + of.position = cloneDeepMutable(to); + updateTreatments(inState, of as any); + return; + } + of.position = cloneDeepMutable(to); +} + +function updateSpatialElementTree( + element: WithMutablePositionAndId, + to: Position, + type: SpatialElementType, + state: Mutable +) { + if (isOnMap(element) && isPositionOnMap(to)) { + updateElementPosition( + state, + type, + element.id, + coordinatesOfPosition(to) + ); + } else if (isOnMap(element) && isPositionNotOnMap(to)) { + removeElementPosition(state, type, element.id); + } else if (isNotOnMap(element) && isPositionOnMap(to)) { + updateElementPosition( + state, + type, + element.id, + coordinatesOfPosition(to) + ); + } +} diff --git a/shared/src/models/utils/position/position-helpers.ts b/shared/src/models/utils/position/position-helpers.ts new file mode 100644 index 000000000..a87984a24 --- /dev/null +++ b/shared/src/models/utils/position/position-helpers.ts @@ -0,0 +1,133 @@ +import type { UUID } from '../../../utils'; +import type { Transfer } from '../transfer'; +import type { MapCoordinates } from './map-coordinates'; +import type { MapPosition } from './map-position'; +import type { Position } from './position'; +import type { SimulatedRegionPosition } from './simulated-region-position'; +import type { TransferPosition } from './transfer-position'; +import type { VehiclePosition } from './vehicle-position'; +import type { WithPosition } from './with-position'; + +export function isOnMap(withPosition: WithPosition): boolean { + return isPositionOnMap(withPosition.position); +} +export function isInVehicle(withPosition: WithPosition): boolean { + return isPositionInVehicle(withPosition.position); +} +export function isInTransfer(withPosition: WithPosition): boolean { + return isPositionInTransfer(withPosition.position); +} +export function isInSimulatedRegion(withPosition: WithPosition): boolean { + return isPositionInSimulatedRegion(withPosition.position); +} +export function isNotOnMap(withPosition: WithPosition): boolean { + return !isOnMap(withPosition); +} +export function isNotInVehicle(withPosition: WithPosition): boolean { + return !isInVehicle(withPosition); +} +export function isNotInTransfer(withPosition: WithPosition): boolean { + return !isInTransfer(withPosition); +} +export function isNotInSimulatedRegion(withPosition: WithPosition): boolean { + return !isInSimulatedRegion(withPosition); +} + +export function currentCoordinatesOf( + withPosition: WithPosition +): MapCoordinates { + if (isOnMap(withPosition)) { + return coordinatesOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be on Map. Was of type ${withPosition.position.type}.` + ); +} + +export function currentVehicleIdOf(withPosition: WithPosition): UUID { + if (isInVehicle(withPosition)) { + return vehicleIdOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in vehicle. Was of type ${withPosition.position.type}.` + ); +} + +export function currentTransferOf(withPosition: WithPosition): Transfer { + if (isInTransfer(withPosition)) { + return transferOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in transfer. Was of type ${withPosition.position.type}.` + ); +} + +export function currentSimulatedRegionIdOf(withPosition: WithPosition): UUID { + if (isInSimulatedRegion(withPosition)) { + return simulatedRegionIdOfPosition(withPosition.position); + } + throw new TypeError( + `Expected position of object to be in simulatedRegion. Was of type ${withPosition.position.type}.` + ); +} + +export function isPositionOnMap(position: Position): boolean { + return position.type === 'coordinates'; +} +export function isPositionInVehicle(position: Position): boolean { + return position.type === 'vehicle'; +} +export function isPositionInTransfer(position: Position): boolean { + return position.type === 'transfer'; +} +export function isPositionInSimulatedRegion(position: Position): boolean { + return position.type === 'simulatedRegion'; +} +export function isPositionNotOnMap(position: Position): boolean { + return !isPositionOnMap(position); +} +export function isPositionNotInVehicle(position: Position): boolean { + return !isPositionInVehicle(position); +} +export function isPositionNotInTransfer(position: Position): boolean { + return !isPositionInTransfer(position); +} +export function isPositionNotInSimulatedRegion(position: Position): boolean { + return !isPositionInSimulatedRegion(position); +} + +export function coordinatesOfPosition(position: Position): MapCoordinates { + if (isPositionOnMap(position)) { + return (position as MapPosition).coordinates; + } + throw new TypeError( + `Expected position to be on Map. Was of type ${position.type}.` + ); +} + +export function vehicleIdOfPosition(position: Position): UUID { + if (isPositionInVehicle(position)) { + return (position as VehiclePosition).vehicleId; + } + throw new TypeError( + `Expected position to be in vehicle. Was of type ${position.type}.` + ); +} + +export function transferOfPosition(position: Position): Transfer { + if (isPositionInTransfer(position)) { + return (position as TransferPosition).transfer; + } + throw new TypeError( + `Expected position to be in transfer. Was of type ${position.type}.` + ); +} + +export function simulatedRegionIdOfPosition(position: Position): UUID { + if (isPositionInSimulatedRegion(position)) { + return (position as SimulatedRegionPosition).simulatedRegionId; + } + throw new TypeError( + `Expected position to be in simulatedRegion. Was of type ${position.type}.` + ); +} diff --git a/shared/src/models/utils/meta-position.ts b/shared/src/models/utils/position/position.ts similarity index 92% rename from shared/src/models/utils/meta-position.ts rename to shared/src/models/utils/position/position.ts index 888ee823b..055c0f545 100644 --- a/shared/src/models/utils/meta-position.ts +++ b/shared/src/models/utils/position/position.ts @@ -3,7 +3,7 @@ import type { SimulatedRegionPosition } from './simulated-region-position'; import type { TransferPosition } from './transfer-position'; import type { VehiclePosition } from './vehicle-position'; -export type MetaPosition = +export type Position = | MapPosition | SimulatedRegionPosition | TransferPosition diff --git a/shared/src/models/utils/position/simulated-region-position.ts b/shared/src/models/utils/position/simulated-region-position.ts new file mode 100644 index 000000000..fc1dc9fc6 --- /dev/null +++ b/shared/src/models/utils/position/simulated-region-position.ts @@ -0,0 +1,38 @@ +import { IsUUID } from 'class-validator'; +import { UUID } from '../../../utils'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInSimulatedRegion, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInSimulatedRegion, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentSimulatedRegionIdOf, +} from './position-helpers'; + +export class SimulatedRegionPosition { + /** + * @deprecated Use {@link isInSimulatedRegion } or {@link isNotInSimulatedRegion} instead + */ + @IsValue('simulatedRegion') + public readonly type = 'simulatedRegion'; + + /** + * @deprecated Use {@link currentSimulatedRegionIdOf } instead + */ + @IsUUID() + public readonly simulatedRegionId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(simulatedRegionId: UUID) { + this.simulatedRegionId = simulatedRegionId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/transfer-position.ts b/shared/src/models/utils/position/transfer-position.ts new file mode 100644 index 000000000..f2f8b9672 --- /dev/null +++ b/shared/src/models/utils/position/transfer-position.ts @@ -0,0 +1,40 @@ +import { Type } from 'class-transformer'; +import { ValidateNested } from 'class-validator'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { Transfer } from '../transfer'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInTransfer, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInTransfer, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentTransferOf, +} from './position-helpers'; + +export class TransferPosition { + /** + * @deprecated Use {@link isInTransfer } or {@link isNotInTransfer} instead + */ + @IsValue('transfer') + public readonly type = 'transfer'; + + /** + * @deprecated Use {@link currentTransferOf } instead + */ + @Type(() => Transfer) + @ValidateNested() + public readonly transfer: Transfer; + + /** + * @deprecated Use {@link create} instead + */ + constructor(transfer: Transfer) { + this.transfer = transfer; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/vehicle-position.ts b/shared/src/models/utils/position/vehicle-position.ts new file mode 100644 index 000000000..4f91a3e0b --- /dev/null +++ b/shared/src/models/utils/position/vehicle-position.ts @@ -0,0 +1,38 @@ +import { IsUUID } from 'class-validator'; +import { UUID } from '../../../utils'; +import { IsValue } from '../../../utils/validators'; +import { getCreate } from '../get-create'; +import { + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isInVehicle, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + isNotInVehicle, + // import needed to display @link Links in Comments + // eslint-disable-next-line @typescript-eslint/no-unused-vars + currentVehicleIdOf, +} from './position-helpers'; + +export class VehiclePosition { + /** + * @deprecated Use {@link isInVehicle } or {@link isNotInVehicle} instead + */ + @IsValue('vehicle') + public readonly type = 'vehicle'; + + /** + * @deprecated Use {@link currentVehicleIdOf } instead + */ + @IsUUID() + public readonly vehicleId: UUID; + + /** + * @deprecated Use {@link create} instead + */ + constructor(vehicleId: UUID) { + this.vehicleId = vehicleId; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/models/utils/position/with-position.ts b/shared/src/models/utils/position/with-position.ts new file mode 100644 index 000000000..9fca34434 --- /dev/null +++ b/shared/src/models/utils/position/with-position.ts @@ -0,0 +1,5 @@ +import type { Position } from './position'; + +export interface WithPosition { + readonly position: Position; +} diff --git a/shared/src/models/utils/simulated-region-position.ts b/shared/src/models/utils/simulated-region-position.ts deleted file mode 100644 index d797cdc66..000000000 --- a/shared/src/models/utils/simulated-region-position.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { UUID } from '../../utils'; -import { IsValue } from '../../utils/validators'; -import { getCreate } from './get-create'; - -export class SimulatedRegionPosition { - @IsValue('simulatedRegion') - public readonly type = 'simulatedRegion'; - - public readonly simulatedRegionId: UUID; - - /** - * @deprecated Use {@link create} instead - */ - constructor(simulatedRegionId: UUID) { - this.simulatedRegionId = simulatedRegionId; - } - - static readonly create = getCreate(this); -} diff --git a/shared/src/models/utils/spatial-tree.ts b/shared/src/models/utils/spatial-tree.ts index b617941aa..33ea781dc 100644 --- a/shared/src/models/utils/spatial-tree.ts +++ b/shared/src/models/utils/spatial-tree.ts @@ -9,7 +9,7 @@ import RBush from 'rbush'; import knn from 'rbush-knn'; import type { Mutable, UUID } from '../../utils'; import { ImmutableJsonObject } from '../../utils'; -import type { Position, Size } from '.'; +import type { MapCoordinates, Size } from '.'; import { getCreate } from '.'; /** @@ -64,7 +64,7 @@ export class SpatialTree { public static addElement( spatialTree: Mutable, elementId: UUID, - position: Position + position: MapCoordinates ) { const pointRBush = this.getPointRBush(spatialTree); pointRBush.insert({ @@ -77,7 +77,7 @@ export class SpatialTree { public static removeElement( spatialTree: Mutable, elementId: UUID, - position: Mutable | Position + position: MapCoordinates | Mutable ) { const pointRBush = this.getPointRBush(spatialTree); pointRBush.remove( @@ -93,8 +93,8 @@ export class SpatialTree { public static moveElement( spatialTree: Mutable, elementId: UUID, - startPosition: Mutable | Position, - targetPosition: Position + startPosition: MapCoordinates | Mutable, + targetPosition: MapCoordinates ) { // TODO: use the move function from RBush, when available: https://github.com/mourner/rbush/issues/28 this.removeElement(spatialTree, elementId, startPosition); @@ -109,7 +109,7 @@ export class SpatialTree { */ public static findAllElementsInCircle( spatialTree: Mutable, - circlePosition: Position, + circlePosition: MapCoordinates, radius: number ): UUID[] { // knn does not work great with `0`|`undefined` as it interprets either as `infinity` @@ -136,7 +136,7 @@ export class SpatialTree { */ public static findAllElementsInRectangle( spatialTree: Mutable, - topLeftPosition: Position, + topLeftPosition: MapCoordinates, size: Size ) { return this.getPointRBush(spatialTree).search({ @@ -154,12 +154,12 @@ export class SpatialTree { * @param id of the element */ interface PointRBushElement { - position: Position; + position: MapCoordinates; id: UUID; } /** - * An RBush that works with our {@link Position} format (elements being points) + * An RBush that works with our {@link MapCoordinates} format (elements being points) * @see https://github.com/mourner/rbush#data-format */ class PointRBush extends RBush { diff --git a/shared/src/models/utils/transfer-position.ts b/shared/src/models/utils/transfer-position.ts deleted file mode 100644 index 26e9b1a43..000000000 --- a/shared/src/models/utils/transfer-position.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Type } from 'class-transformer'; -import { ValidateNested } from 'class-validator'; -import { IsValue } from '../../utils/validators'; -import { getCreate } from './get-create'; -import { Transfer } from './transfer'; - -export class TransferPosition { - @IsValue('transfer') - public readonly type = 'transfer'; - - @Type(() => Transfer) - @ValidateNested() - public readonly transfer: Transfer; - - /** - * @deprecated Use {@link create} instead - */ - constructor(transfer: Transfer) { - this.transfer = transfer; - } - - static readonly create = getCreate(this); -} diff --git a/shared/src/models/utils/vehicle-position.ts b/shared/src/models/utils/vehicle-position.ts deleted file mode 100644 index 80970ae93..000000000 --- a/shared/src/models/utils/vehicle-position.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { IsUUID } from 'class-validator'; -import { UUID } from '../../utils'; -import { IsValue } from '../../utils/validators'; -import { getCreate } from './get-create'; - -export class VehiclePosition { - @IsValue('vehicle') - public readonly type = 'vehicle'; - - @IsUUID() - public readonly vehicleId: UUID; - - /** - * @deprecated Use {@link create} instead - */ - constructor(vehicleId: UUID) { - this.vehicleId = vehicleId; - } - - static readonly create = getCreate(this); -} diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index e053b021a..cdc6fba41 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -1,17 +1,11 @@ import { Type } from 'class-transformer'; -import { - IsNumber, - IsOptional, - IsString, - IsUUID, - ValidateNested, -} from 'class-validator'; +import { IsNumber, IsString, IsUUID, ValidateNested } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; import { IsUUIDSet, IsValue } from '../utils/validators'; -import { IsMetaPosition } from '../utils/validators/is-metaposition'; -import { getCreate, Position, Transfer } from './utils'; +import { IsPosition } from '../utils/validators/is-position'; +import { getCreate } from './utils'; import { ImageProperties } from './utils/image-properties'; -import { MetaPosition } from './utils/meta-position'; +import { Position } from './utils/position/position'; export class Vehicle { @IsUUID(4, uuidValidationOptions) @@ -32,32 +26,17 @@ export class Vehicle { @IsNumber() public readonly patientCapacity: number; - @IsMetaPosition() - @ValidateNested() - public readonly metaPosition: MetaPosition; - /** - * @deprecated use {@link metaPosition} - * Exclusive-or to {@link transfer} + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ + @IsPosition() @ValidateNested() - @Type(() => Position) - @IsOptional() - public readonly position?: Position; + public readonly position: Position; @ValidateNested() @Type(() => ImageProperties) public readonly image: ImageProperties; - /** - * @deprecated use {@link metaPosition} - * Exclusive-or to {@link position} - */ - @ValidateNested() - @Type(() => Transfer) - @IsOptional() - public readonly transfer?: Transfer; - @IsUUIDSet() public readonly personnelIds: UUIDSet = {}; @@ -73,14 +52,14 @@ export class Vehicle { materialIds: UUIDSet, patientCapacity: number, image: ImageProperties, - metaPosition: MetaPosition + position: Position ) { this.vehicleType = vehicleType; this.name = name; this.materialIds = materialIds; this.patientCapacity = patientCapacity; this.image = image; - this.metaPosition = metaPosition; + this.position = position; } static readonly create = getCreate(this); diff --git a/shared/src/models/viewport.ts b/shared/src/models/viewport.ts index 4a147e472..081635bc4 100644 --- a/shared/src/models/viewport.ts +++ b/shared/src/models/viewport.ts @@ -1,9 +1,16 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; +import { IsPosition } from '../utils/validators/is-position'; import { IsValue } from '../utils/validators'; -import { getCreate, Position, Size } from './utils'; -import type { ImageProperties } from './utils'; +import { + currentCoordinatesOf, + getCreate, + MapPosition, + Position, + Size, +} from './utils'; +import type { ImageProperties, MapCoordinates } from './utils'; export class Viewport { @IsUUID(4, uuidValidationOptions) @@ -14,9 +21,11 @@ export class Viewport { /** * top-left position + * + * @deprecated Do not access directly, use helper methods from models/utils/position/position-helpers(-mutable) instead. */ @ValidateNested() - @Type(() => Position) + @IsPosition() public readonly position: Position; @ValidateNested() @@ -30,8 +39,8 @@ export class Viewport { * @param position top-left position * @deprecated Use {@link create} instead */ - constructor(position: Position, size: Size, name: string) { - this.position = position; + constructor(position: MapCoordinates, size: Size, name: string) { + this.position = MapPosition.create(position); this.size = size; this.name = name; } @@ -44,12 +53,14 @@ export class Viewport { aspectRatio: 1600 / 900, }; - static isInViewport(viewport: Viewport, position: Position): boolean { + static isInViewport(viewport: Viewport, position: MapCoordinates): boolean { return ( - viewport.position.x <= position.x && - position.x <= viewport.position.x + viewport.size.width && - viewport.position.y - viewport.size.height <= position.y && - position.y <= viewport.position.y + currentCoordinatesOf(viewport).x <= position.x && + position.x <= + currentCoordinatesOf(viewport).x + viewport.size.width && + currentCoordinatesOf(viewport).y - viewport.size.height <= + position.y && + position.y <= currentCoordinatesOf(viewport).y ); } } diff --git a/shared/src/state-helpers/create-vehicle-parameters.ts b/shared/src/state-helpers/create-vehicle-parameters.ts index bacbb4ef4..661973a9a 100644 --- a/shared/src/state-helpers/create-vehicle-parameters.ts +++ b/shared/src/state-helpers/create-vehicle-parameters.ts @@ -2,10 +2,10 @@ import type { Vehicle, VehicleTemplate } from '../models'; import { Material, Personnel } from '../models'; import type { MaterialTemplate } from '../models/material-template'; import type { PersonnelTemplate } from '../models/personnel-template'; -import type { PersonnelType, Position } from '../models/utils'; -import { MapPosition } from '../models/utils/map-position'; +import type { PersonnelType, MapCoordinates } from '../models/utils'; +import { MapPosition } from '../models/utils/position/map-position'; import type { MaterialType } from '../models/utils/material-type'; -import { VehiclePosition } from '../models/utils/vehicle-position'; +import { VehiclePosition } from '../models/utils/position/vehicle-position'; import { uuid } from '../utils'; import { arrayToUUIDSet } from '../utils/array-to-uuid-set'; @@ -22,7 +22,7 @@ export function createVehicleParameters( personnelTemplates: { [Key in PersonnelType]: PersonnelTemplate; }, - vehiclePosition: Position + vehiclePosition: MapCoordinates ): { materials: Material[]; personnel: Personnel[]; @@ -56,8 +56,7 @@ export function createVehicleParameters( image: vehicleTemplate.image, patientIds: {}, personnelIds: arrayToUUIDSet(personnel.map((p) => p.id)), - position: vehiclePosition, - metaPosition: MapPosition.create(vehiclePosition), + position: MapPosition.create(vehiclePosition), }; return { materials, diff --git a/shared/src/state-migrations/16-add-meta-position.ts b/shared/src/state-migrations/16-add-meta-position.ts index bca88a103..344228c2d 100644 --- a/shared/src/state-migrations/16-add-meta-position.ts +++ b/shared/src/state-migrations/16-add-meta-position.ts @@ -40,6 +40,17 @@ export const addMetaPosition16: Migration = { transfer?: any; metaPosition?: any; }; + materials: { + position?: { x: number; y: number }; + vehicleId?: UUID; + metaPosition?: any; + }[]; + personnel: { + position?: { x: number; y: number }; + transfer?: any; + vehicleId?: UUID; + metaPosition?: any; + }[]; }; if (typedAction.vehicle.position) { typedAction.vehicle.metaPosition = { @@ -54,6 +65,52 @@ export const addMetaPosition16: Migration = { type: 'transfer', transfer: typedAction.vehicle.transfer, }; + } else { + typedAction.vehicle.metaPosition = { + type: 'coordinates', + position: { + x: 0, + y: 0, + }, + }; + } + for (const personnel of typedAction.personnel) { + if (personnel.position) { + personnel.metaPosition = { + type: 'coordinates', + position: { + x: personnel.position.x, + y: personnel.position.y, + }, + }; + } else if (personnel.transfer) { + personnel.metaPosition = { + type: 'transfer', + transfer: personnel.transfer, + }; + } else if (personnel.vehicleId) { + personnel.metaPosition = { + type: 'vehicle', + vehicleId: personnel.vehicleId, + }; + } + } + + for (const material of typedAction.materials) { + if (material.position) { + material.metaPosition = { + type: 'coordinates', + position: { + x: material.position.x, + y: material.position.y, + }, + }; + } else if (material.vehicleId) { + material.metaPosition = { + type: 'vehicle', + vehicleId: material.vehicleId, + }; + } } } }); diff --git a/shared/src/state-migrations/18-replace-position-with-meta-position.ts b/shared/src/state-migrations/18-replace-position-with-meta-position.ts new file mode 100644 index 000000000..df30f0ea4 --- /dev/null +++ b/shared/src/state-migrations/18-replace-position-with-meta-position.ts @@ -0,0 +1,386 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const replacePositionWithMetaPosition18: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Patient] Add patient' + ) { + const typedAction = action as { + patient: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + if (typedAction.patient.metaPosition?.type === 'coordinates') { + typedAction.patient.metaPosition.coordinates = + typedAction.patient.metaPosition.position; + delete typedAction.patient.metaPosition.position; + } + typedAction.patient.position = typedAction.patient.metaPosition; + delete typedAction.patient.metaPosition; + } + if ( + (action as { type: string } | null)?.type === + '[Vehicle] Add vehicle' + ) { + const typedAction = action as { + vehicle: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + materials: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }[]; + personnel: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }[]; + }; + for (const material of typedAction.materials) { + if (material.metaPosition?.type === 'coordinates') { + material.metaPosition.coordinates = + material.metaPosition.position; + delete material.metaPosition.position; + } + material.position = material.metaPosition; + delete material.metaPosition; + } + + for (const personnel of typedAction.personnel) { + delete personnel.transfer; + if (personnel.metaPosition?.type === 'coordinates') { + personnel.metaPosition.coordinates = + personnel.metaPosition.position; + delete personnel.metaPosition.position; + } + personnel.position = personnel.metaPosition; + delete personnel.metaPosition; + } + + if (typedAction.vehicle.metaPosition?.type === 'coordinates') { + typedAction.vehicle.metaPosition.coordinates = + typedAction.vehicle.metaPosition.position; + delete typedAction.vehicle.metaPosition.position; + } + typedAction.vehicle.position = typedAction.vehicle.metaPosition; + delete typedAction.vehicle.metaPosition; + } + if ( + (action as { type: string } | null)?.type === + '[Viewport] Add viewport' + ) { + const typedAction = action as { + viewport: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.viewport.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.viewport.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.viewport.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[SimulatedRegion] Add simulated region' + ) { + const typedAction = action as { + simulatedRegion: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.simulatedRegion.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.simulatedRegion.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.simulatedRegion.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[MapImage] Add MapImage' + ) { + const typedAction = action as { + mapImage: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.mapImage.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.mapImage.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.mapImage.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + if ( + (action as { type: string } | null)?.type === + '[TransferPoint] Add TransferPoint' + ) { + const typedAction = action as { + transferPoint: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + typedAction.transferPoint.position = { + type: 'coordinates', + coordinates: { + x: ( + typedAction.transferPoint.position as { + x: number; + y: number; + } + ).x, + y: ( + typedAction.transferPoint.position as { + x: number; + y: number; + } + ).y, + }, + }; + } + }); + }, + state: (state) => { + const typedState = state as { + patients: { + [patientId: UUID]: { + vehicleId?: any; + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + materials: { + [materialId: UUID]: { + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + vehicles: { + [vehicleId: UUID]: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + personnel: { + [personnelId: UUID]: { + transfer?: any; + metaPosition?: + | any + | { type: 'coordinates'; position: any } + | { type: any }; + position: any; + }; + }; + viewports: { + [viewportId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + simulatedRegions: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + mapImages: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + transferPoints: { + [simulatedRegionId: UUID]: { + position: + | { + type: 'coordinates'; + coordinates: { x: number; y: number }; + } + | { x: number; y: number }; + }; + }; + }; + + Object.values(typedState.patients).forEach((patient) => { + delete patient.transfer; + delete patient.vehicleId; + if (patient.metaPosition?.type === 'coordinates') { + patient.metaPosition.coordinates = + patient.metaPosition.position; + delete patient.metaPosition.position; + } + patient.position = patient.metaPosition; + delete patient.metaPosition; + }); + + Object.values(typedState.materials).forEach((material) => { + if (material.metaPosition?.type === 'coordinates') { + material.metaPosition.coordinates = + material.metaPosition.position; + delete material.metaPosition.position; + } + material.position = material.metaPosition; + delete material.metaPosition; + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + delete vehicle.transfer; + + if (vehicle.metaPosition?.type === 'coordinates') { + vehicle.metaPosition.coordinates = + vehicle.metaPosition.position; + delete vehicle.metaPosition.position; + } + vehicle.position = vehicle.metaPosition; + delete vehicle.metaPosition; + }); + + Object.values(typedState.personnel).forEach((personnel) => { + delete personnel.transfer; + if (personnel.metaPosition?.type === 'coordinates') { + personnel.metaPosition.coordinates = + personnel.metaPosition.position; + delete personnel.metaPosition.position; + } + personnel.position = personnel.metaPosition; + delete personnel.metaPosition; + }); + Object.values(typedState.viewports).forEach((viewport) => { + viewport.position = { + type: 'coordinates', + coordinates: { + x: (viewport.position as { x: number; y: number }).x, + y: (viewport.position as { x: number; y: number }).y, + }, + }; + }); + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.position = { + type: 'coordinates', + coordinates: { + x: ( + simulatedRegion.position as { x: number; y: number } + ).x, + y: ( + simulatedRegion.position as { x: number; y: number } + ).y, + }, + }; + } + ); + Object.values(typedState.mapImages).forEach((mapImage) => { + mapImage.position = { + type: 'coordinates', + coordinates: { + x: (mapImage.position as { x: number; y: number }).x, + y: (mapImage.position as { x: number; y: number }).y, + }, + }; + }); + Object.values(typedState.transferPoints).forEach((transferPoint) => { + transferPoint.position = { + type: 'coordinates', + coordinates: { + x: (transferPoint.position as { x: number; y: number }).x, + y: (transferPoint.position as { x: number; y: number }).y, + }, + }; + }); + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index 965436bb5..780cdf86d 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -6,6 +6,7 @@ import { addPersonnelAndMaterialToState14 } from './14-add-personnel-and-materia import { addSimulatedRegions15 } from './15-add-simulated-regions'; import { addMetaPosition16 } from './16-add-meta-position'; import { addTypeProperty17 } from './17-add-type-property'; +import { replacePositionWithMetaPosition18 } from './18-replace-position-with-meta-position'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -57,4 +58,5 @@ export const migrations: { 15: addSimulatedRegions15, 16: addMetaPosition16, 17: addTypeProperty17, + 18: replacePositionWithMetaPosition18, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index de96e2b71..646d02c7b 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -148,5 +148,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 17; + static readonly currentStateVersion = 18; } diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts index 1fd29a514..c20d48425 100644 --- a/shared/src/store/action-reducers/exercise.ts +++ b/shared/src/store/action-reducers/exercise.ts @@ -8,9 +8,16 @@ import { } from 'class-validator'; import type { Personnel, Vehicle } from '../../models'; import { Patient } from '../../models'; -import { getStatus } from '../../models/utils'; +import { + getStatus, + isNotInTransfer, + currentTransferOf, + TransferPosition, +} from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; +import { cloneDeepMutable } from '../../utils'; import type { ElementTypePluralMap } from '../../utils/element-type-plural-map'; import { elementTypePluralMap } from '../../utils/element-type-plural-map'; import { IsValue } from '../../utils/validators'; @@ -145,15 +152,21 @@ function refreshTransfer( ): void { const elements = draftState[elementTypePluralMap[type]]; Object.values(elements).forEach((element: Mutable) => { - if (!element.transfer) { + if (isNotInTransfer(element)) { return; } - if (element.transfer.isPaused) { - element.transfer.endTimeStamp += tickInterval; + if (currentTransferOf(element).isPaused) { + const newTransfer = cloneDeepMutable(currentTransferOf(element)); + newTransfer.endTimeStamp += tickInterval; + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return; } // Not transferred yet - if (element.transfer.endTimeStamp > draftState.currentTime) { + if (currentTransferOf(element).endTimeStamp > draftState.currentTime) { return; } letElementArrive(draftState, type, element.id); diff --git a/shared/src/store/action-reducers/map-images.ts b/shared/src/store/action-reducers/map-images.ts index 7384033ff..d564fbaad 100644 --- a/shared/src/store/action-reducers/map-images.ts +++ b/shared/src/store/action-reducers/map-images.ts @@ -9,7 +9,8 @@ import { ValidateNested, } from 'class-validator'; import { MapImage } from '../../models'; -import { Position } from '../../models/utils'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { @@ -39,8 +40,8 @@ export class MoveMapImageAction implements Action { public readonly mapImageId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class ScaleMapImageAction implements Action { @@ -134,7 +135,11 @@ export namespace MapImagesActionReducers { action: MoveMapImageAction, reducer: (draftState, { mapImageId, targetPosition }) => { const mapImage = getElement(draftState, 'mapImage', mapImageId); - mapImage.position = cloneDeepMutable(targetPosition); + changePosition( + mapImage, + MapPosition.create(targetPosition), + draftState + ); return draftState; }, rights: 'trainer', diff --git a/shared/src/store/action-reducers/material.ts b/shared/src/store/action-reducers/material.ts index 4d1847dc4..681107209 100644 --- a/shared/src/store/action-reducers/material.ts +++ b/shared/src/store/action-reducers/material.ts @@ -1,10 +1,10 @@ import { Type } from 'class-transformer'; import { IsUUID, ValidateNested } from 'class-validator'; -import { Position } from '../../models/utils'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; import { UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; -import { updateElementPosition } from './utils/spatial-elements'; export class MoveMaterialAction implements Action { @IsValue('[Material] Move material' as const) @@ -14,19 +14,19 @@ export class MoveMaterialAction implements Action { public readonly materialId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export namespace MaterialActionReducers { export const moveMaterial: ActionReducer = { action: MoveMaterialAction, reducer: (draftState, { materialId, targetPosition }) => { - updateElementPosition( - draftState, - 'material', + changePositionWithId( materialId, - targetPosition + MapPosition.create(targetPosition), + 'material', + draftState ); return draftState; }, diff --git a/shared/src/store/action-reducers/patient.ts b/shared/src/store/action-reducers/patient.ts index b3953393a..e8df777d5 100644 --- a/shared/src/store/action-reducers/patient.ts +++ b/shared/src/store/action-reducers/patient.ts @@ -2,10 +2,16 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, MaxLength, ValidateNested } from 'class-validator'; import { Patient } from '../../models'; import { + isOnMap, + MapPosition, PatientStatus, patientStatusAllowedValues, - Position, + MapCoordinates, } from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { @@ -19,11 +25,7 @@ import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { updateTreatments } from './utils/calculate-treatments'; import { getElement } from './utils/get-element'; -import { - addElementPosition, - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; +import { removeElementPosition } from './utils/spatial-elements'; export function deletePatient( draftState: Mutable, @@ -49,8 +51,8 @@ export class MovePatientAction implements Action { public readonly patientId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RemovePatientAction implements Action { @@ -120,7 +122,7 @@ export namespace PatientActionReducers { } const mutablePatient = cloneDeepMutable(patient); draftState.patients[mutablePatient.id] = mutablePatient; - addElementPosition(draftState, 'patient', mutablePatient.id); + changePosition(mutablePatient, patient.position, draftState); return draftState; }, rights: 'trainer', @@ -129,11 +131,11 @@ export namespace PatientActionReducers { export const movePatient: ActionReducer = { action: MovePatientAction, reducer: (draftState, { patientId, targetPosition }) => { - updateElementPosition( - draftState, - 'patient', + changePositionWithId( patientId, - targetPosition + MapPosition.create(targetPosition), + 'patient', + draftState ); return draftState; }, @@ -155,7 +157,7 @@ export namespace PatientActionReducers { const patient = getElement(draftState, 'patient', patientId); patient.pretriageStatus = patientStatus; - if (patient.metaPosition.type === 'coordinates') { + if (isOnMap(patient)) { updateTreatments(draftState, patient); } diff --git a/shared/src/store/action-reducers/personnel.ts b/shared/src/store/action-reducers/personnel.ts index 843c122ed..0078da337 100644 --- a/shared/src/store/action-reducers/personnel.ts +++ b/shared/src/store/action-reducers/personnel.ts @@ -1,10 +1,10 @@ import { Type } from 'class-transformer'; import { IsUUID, ValidateNested } from 'class-validator'; -import { Position } from '../../models/utils'; +import { MapPosition, MapCoordinates } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; import { UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; -import { updateElementPosition } from './utils/spatial-elements'; export class MovePersonnelAction implements Action { @IsValue('[Personnel] Move personnel' as const) @@ -14,19 +14,19 @@ export class MovePersonnelAction implements Action { public readonly personnelId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export namespace PersonnelActionReducers { export const movePersonnel: ActionReducer = { action: MovePersonnelAction, reducer: (draftState, { personnelId, targetPosition }) => { - updateElementPosition( - draftState, - 'personnel', + changePositionWithId( personnelId, - targetPosition + MapPosition.create(targetPosition), + 'personnel', + draftState ); return draftState; }, diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts index 4de91f2ec..b36f437f6 100644 --- a/shared/src/store/action-reducers/simulated-region.ts +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -1,7 +1,11 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { SimulatedRegion } from '../../models'; -import { Position, Size } from '../../models/utils'; +import { MapCoordinates, MapPosition, Size } from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; @@ -28,8 +32,8 @@ export class MoveSimulatedRegionAction implements Action { @IsUUID(4, uuidValidationOptions) public readonly simulatedRegionId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class ResizeSimulatedRegionAction implements Action { @@ -38,8 +42,8 @@ export class ResizeSimulatedRegionAction implements Action { @IsUUID(4, uuidValidationOptions) public readonly simulatedRegionId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; @ValidateNested() @Type(() => Size) public readonly newSize!: Size; @@ -82,12 +86,12 @@ export namespace SimulatedRegionActionReducers { { action: MoveSimulatedRegionAction, reducer: (draftState, { simulatedRegionId, targetPosition }) => { - const simulatedRegion = getElement( - draftState, + changePositionWithId( + simulatedRegionId, + MapPosition.create(targetPosition), 'simulatedRegion', - simulatedRegionId + draftState ); - simulatedRegion.position = cloneDeepMutable(targetPosition); return draftState; }, rights: 'trainer', @@ -105,7 +109,11 @@ export namespace SimulatedRegionActionReducers { 'simulatedRegion', simulatedRegionId ); - simulatedRegion.position = cloneDeepMutable(targetPosition); + changePosition( + simulatedRegion, + MapPosition.create(targetPosition), + draftState + ); simulatedRegion.size = cloneDeepMutable(newSize); return draftState; }, diff --git a/shared/src/store/action-reducers/transfer-point.ts b/shared/src/store/action-reducers/transfer-point.ts index f72d916c9..2e2abf06d 100644 --- a/shared/src/store/action-reducers/transfer-point.ts +++ b/shared/src/store/action-reducers/transfer-point.ts @@ -7,7 +7,14 @@ import { ValidateNested, } from 'class-validator'; import { TransferPoint } from '../../models'; -import { Position } from '../../models/utils'; +import { + currentCoordinatesOf, + isInTransfer, + MapCoordinates, + MapPosition, + currentTransferOf, +} from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; @@ -34,8 +41,8 @@ export class MoveTransferPointAction implements Action { public readonly transferPointId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RenameTransferPointAction implements Action { @@ -122,12 +129,12 @@ export namespace TransferPointActionReducers { export const moveTransferPoint: ActionReducer = { action: MoveTransferPointAction, reducer: (draftState, { transferPointId, targetPosition }) => { - const transferPoint = getElement( - draftState, + changePositionWithId( + transferPointId, + MapPosition.create(targetPosition), 'transferPoint', - transferPointId + draftState ); - transferPoint.position = cloneDeepMutable(targetPosition); return draftState; }, rights: 'trainer', @@ -184,8 +191,8 @@ export namespace TransferPointActionReducers { const _duration = duration ?? estimateDuration( - transferPoint1.position, - transferPoint2.position + currentCoordinatesOf(transferPoint1), + currentCoordinatesOf(transferPoint2) ); transferPoint1.reachableTransferPoints[transferPointId2] = { duration: _duration, @@ -240,8 +247,9 @@ export namespace TransferPointActionReducers { vehicleId ); if ( - vehicle.transfer?.targetTransferPointId === - transferPointId + isInTransfer(vehicle) && + currentTransferOf(vehicle).targetTransferPointId === + transferPointId ) { letElementArrive(draftState, vehicle.type, vehicleId); } @@ -253,8 +261,9 @@ export namespace TransferPointActionReducers { personnelId ); if ( - personnel.transfer?.targetTransferPointId === - transferPointId + isInTransfer(personnel) && + currentTransferOf(personnel).targetTransferPointId === + transferPointId ) { letElementArrive( draftState, @@ -326,7 +335,10 @@ export namespace TransferPointActionReducers { * @returns an estimated duration in ms to drive between the the two given positions * The resulting value is a multiple of 0.1 minutes. */ -function estimateDuration(startPosition: Position, targetPosition: Position) { +function estimateDuration( + startPosition: MapCoordinates, + targetPosition: MapCoordinates +) { // TODO: tweak these values more // How long in ms it takes to start + stop moving const overheadSummand = 10 * 1000; diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index eb0b2f5f1..d21a3304f 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -1,8 +1,18 @@ import { Type } from 'class-transformer'; import { IsInt, IsOptional, IsUUID, ValidateNested } from 'class-validator'; import { TransferPoint } from '../../models'; -import type { Position } from '../../models/utils'; -import { StartPoint, startPointTypeOptions } from '../../models/utils'; +import type { MapCoordinates } from '../../models/utils'; +import { + isInTransfer, + isNotInTransfer, + currentTransferOf, + TransferPosition, + currentCoordinatesOf, + MapPosition, + StartPoint, + startPointTypeOptions, +} from '../../models/utils'; +import { changePosition } from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import { imageSizeToPosition } from '../../state-helpers'; import type { Mutable } from '../../utils'; @@ -12,10 +22,6 @@ import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { getElement } from './utils'; -import { - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; export type TransferableElementType = 'personnel' | 'vehicle'; const transferableElementTypeAllowedValues: AllowedValues = @@ -33,31 +39,22 @@ export function letElementArrive( ) { const element = getElement(draftState, elementType, elementId); // check that element is in transfer, this should be always the case where this function is used - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } const targetTransferPoint = getElement( draftState, 'transferPoint', - element.transfer.targetTransferPointId + currentTransferOf(element).targetTransferPointId ); - const newPosition: Mutable = { - x: targetTransferPoint.position.x, + const newPosition: Mutable = { + x: currentCoordinatesOf(targetTransferPoint).x, y: - targetTransferPoint.position.y + + currentCoordinatesOf(targetTransferPoint).y + // Position it in the upper half of the transferPoint imageSizeToPosition(TransferPoint.image.height / 3), }; - if (elementType === 'personnel') { - updateElementPosition(draftState, 'personnel', element.id, newPosition); - } else { - element.position = newPosition; - element.metaPosition = { - type: 'coordinates', - position: newPosition, - }; - } - delete element.transfer; + changePosition(element, MapPosition.create(newPosition), draftState); } export class AddToTransferAction implements Action { @@ -137,7 +134,8 @@ export namespace TransferActionReducers { // check if transferPoint exists getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); - if (element.transfer) { + + if (isInTransfer(element)) { throw new ReducerError( `Element with id ${element.id} is already in transfer` ); @@ -165,29 +163,17 @@ export namespace TransferActionReducers { duration = startPoint.duration; } - // Remove the position of the element - if (elementType === 'personnel') { - removeElementPosition(draftState, 'personnel', element.id); - } else { - element.position = undefined; - } // Set the element to transfer - element.transfer = { - startPoint: cloneDeepMutable(startPoint), - targetTransferPointId, - endTimeStamp: draftState.currentTime + duration, - isPaused: false, - }; - - element.metaPosition = { - type: 'transfer', - transfer: { + changePosition( + element, + TransferPosition.create({ startPoint: cloneDeepMutable(startPoint), targetTransferPointId, endTimeStamp: draftState.currentTime + duration, isPaused: false, - }, - }; + }), + draftState + ); return draftState; }, @@ -201,21 +187,28 @@ export namespace TransferActionReducers { { elementType, elementId, targetTransferPointId, timeToAdd } ) => { const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } + const newTransfer = cloneDeepMutable(currentTransferOf(element)); if (targetTransferPointId) { // check if transferPoint exists + getElement(draftState, 'transferPoint', targetTransferPointId); - element.transfer.targetTransferPointId = targetTransferPointId; + newTransfer.targetTransferPointId = targetTransferPointId; } if (timeToAdd) { // The endTimeStamp shouldn't be less then the current time - element.transfer.endTimeStamp = Math.max( + newTransfer.endTimeStamp = Math.max( draftState.currentTime, - element.transfer.endTimeStamp + timeToAdd + newTransfer.endTimeStamp + timeToAdd ); } + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return draftState; }, rights: 'trainer', @@ -230,7 +223,7 @@ export namespace TransferActionReducers { // check if transferPoint exists getElement(draftState, 'transferPoint', targetTransferPointId); const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } letElementArrive(draftState, elementType, elementId); @@ -244,10 +237,18 @@ export namespace TransferActionReducers { action: TogglePauseTransferAction, reducer: (draftState, { elementType, elementId }) => { const element = getElement(draftState, elementType, elementId); - if (!element.transfer) { + if (isNotInTransfer(element)) { throw getNotInTransferError(element.id); } - element.transfer.isPaused = !element.transfer.isPaused; + const newTransfer = cloneDeepMutable( + currentTransferOf(element) + ); + newTransfer.isPaused = !newTransfer.isPaused; + changePosition( + element, + TransferPosition.create(newTransfer), + draftState + ); return draftState; }, rights: 'trainer', diff --git a/shared/src/store/action-reducers/utils/calculate-distance.ts b/shared/src/store/action-reducers/utils/calculate-distance.ts index 66fd06b9b..986f53d8a 100644 --- a/shared/src/store/action-reducers/utils/calculate-distance.ts +++ b/shared/src/store/action-reducers/utils/calculate-distance.ts @@ -1,8 +1,8 @@ -import type { Position } from '../../../models/utils'; +import type { MapCoordinates } from '../../../models/utils'; /** * @returns the distance between the two positions in meters. */ -export function calculateDistance(a: Position, b: Position) { +export function calculateDistance(a: MapCoordinates, b: MapCoordinates) { return Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2); } diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts index ca0fde55a..d48852cd7 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.spec.ts @@ -4,11 +4,16 @@ import { defaultMaterialTemplates } from '../../../data/default-state/material-t import { defaultPersonnelTemplates } from '../../../data/default-state/personnel-templates'; import type { Patient } from '../../../models'; import { Material, Personnel } from '../../../models'; -import type { MetaPosition, PatientStatus } from '../../../models/utils'; -import { CanCaterFor, Position } from '../../../models/utils'; -import { MapPosition } from '../../../models/utils/map-position'; +import type { Position, PatientStatus } from '../../../models/utils'; +import { + currentCoordinatesOf, + isPositionOnMap, + CanCaterFor, + MapCoordinates, +} from '../../../models/utils'; +import { MapPosition } from '../../../models/utils/position/map-position'; import { SpatialTree } from '../../../models/utils/spatial-tree'; -import { VehiclePosition } from '../../../models/utils/vehicle-position'; +import { VehiclePosition } from '../../../models/utils/position/vehicle-position'; import { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable, uuid } from '../../../utils'; @@ -71,37 +76,33 @@ function addPatient( state: Mutable, pretriageStatus: PatientStatus, realStatus: PatientStatus, - position?: Position + position?: MapCoordinates ): Mutable { const patient = cloneDeepMutable(generateDummyPatient()); patient.pretriageStatus = pretriageStatus; patient.realStatus = realStatus; if (position) { - patient.position = cloneDeepMutable(position); - patient.metaPosition = { + patient.position = { type: 'coordinates', - position: cloneDeepMutable(position), + coordinates: cloneDeepMutable(position), }; SpatialTree.addElement( state.spatialTrees.patients, patient.id, - patient.position + position ); } state.patients[patient.id] = patient; return patient; } -function addPersonnel( - state: Mutable, - metaPosition: MetaPosition -) { +function addPersonnel(state: Mutable, position: Position) { const personnel = cloneDeepMutable( Personnel.generatePersonnel( defaultPersonnelTemplates.notSan, uuid(), 'RTW 3/83/1', - metaPosition + position ) ); personnel.canCaterFor = { @@ -110,28 +111,24 @@ function addPersonnel( green: 0, logicalOperator: 'and', }; - if (metaPosition.type === 'coordinates') { - personnel.position = cloneDeepMutable(metaPosition.position); + if (isPositionOnMap(position)) { SpatialTree.addElement( state.spatialTrees.personnel, personnel.id, - personnel.position + currentCoordinatesOf(personnel) ); } state.personnel[personnel.id] = personnel; return personnel; } -function addMaterial( - state: Mutable, - metaPosition: MetaPosition -) { +function addMaterial(state: Mutable, position: Position) { const material = cloneDeepMutable( Material.generateMaterial( defaultMaterialTemplates.standard, uuid(), 'RTW 3/83/1', - metaPosition + position ) ); material.canCaterFor = { @@ -140,12 +137,11 @@ function addMaterial( green: 0, logicalOperator: 'and', }; - if (metaPosition.type === 'coordinates') { - material.position = cloneDeepMutable(metaPosition.position); + if (isPositionOnMap(position)) { SpatialTree.addElement( state.spatialTrees.materials, material.id, - material.position + currentCoordinatesOf(material) ); } state.materials[material.id] = material; @@ -222,7 +218,12 @@ describe('calculate treatment', () => { (state) => { (['green', 'yellow', 'red'] as PatientStatus[]).forEach( (color) => { - addPatient(state, color, color, Position.create(0, 0)); + addPatient( + state, + color, + color, + MapCoordinates.create(0, 0) + ); } ); } @@ -233,7 +234,12 @@ describe('calculate treatment', () => { it('does nothing when there are only dead patients', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'black', 'black', Position.create(0, 0)); + addPatient( + state, + 'black', + 'black', + MapCoordinates.create(0, 0) + ); } ); expect(newState).toStrictEqual(beforeState); @@ -242,7 +248,12 @@ describe('calculate treatment', () => { it('does nothing when all personnel is in a vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'green', 'green', Position.create(0, 0)); + addPatient( + state, + 'green', + 'green', + MapCoordinates.create(0, 0) + ); addPersonnel(state, VehiclePosition.create('')); } ); @@ -252,7 +263,12 @@ describe('calculate treatment', () => { it('does nothing when all material is in a vehicle', () => { const { beforeState, newState } = setupStateAndApplyTreatments( (state) => { - addPatient(state, 'green', 'green', Position.create(0, 0)); + addPatient( + state, + 'green', + 'green', + MapCoordinates.create(0, 0) + ); addMaterial(state, VehiclePosition.create('')); } ); @@ -271,13 +287,13 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(0, 0) + MapCoordinates.create(0, 0) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(2, 2) + MapCoordinates.create(2, 2) ).id; ids.material = addMaterial( state, @@ -306,13 +322,13 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-3, -3) + MapCoordinates.create(-3, -3) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(3, 3) + MapCoordinates.create(3, 3) ).id; ids.material = addMaterial( state, @@ -320,7 +336,6 @@ describe('calculate treatment', () => { ).id; } ); - console.log(ids); assertCatering(beforeState, newState, [ { catererId: ids.material, @@ -342,13 +357,13 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-10, -10) + MapCoordinates.create(-10, -10) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(20, 20) + MapCoordinates.create(20, 20) ).id; ids.material = addMaterial( state, @@ -371,13 +386,13 @@ describe('calculate treatment', () => { state, 'green', 'green', - Position.create(-1, -1) + MapCoordinates.create(-1, -1) ).id; ids.redPatient = addPatient( state, 'red', 'red', - Position.create(2, 2) + MapCoordinates.create(2, 2) ).id; const material = addMaterial( state, diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts index 090729406..514c07cd1 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts @@ -1,7 +1,8 @@ import { groupBy } from 'lodash-es'; import type { Material, Personnel } from '../../../models'; import { Patient } from '../../../models'; -import type { PatientStatus, Position } from '../../../models/utils'; +import type { MapCoordinates, PatientStatus } from '../../../models/utils'; +import { currentCoordinatesOf, isNotOnMap } from '../../../models/utils'; import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range'; @@ -99,7 +100,7 @@ function tryToCaterFor( */ function updateCateringAroundPatient( state: Mutable, - position: Position, + position: MapCoordinates, elementType: 'material' | 'personnel', elementIdsToBeSkipped: Set ) { @@ -169,7 +170,7 @@ export function updateTreatments( // Currently, the treatment pattern algorithm is stable. This means that completely done from scratch, // the result would semantically be the same. This could be changed later. - if (element.position === undefined) { + if (isNotOnMap(element)) { // The element is no longer in a position (get it?!) to be treated or treat a patient removeTreatmentsOfElement(state, element); return; @@ -196,13 +197,13 @@ export function updateTreatments( updateCateringAroundPatient( state, - element.position, + currentCoordinatesOf(element), 'personnel', alreadyUpdatedElementIds ); updateCateringAroundPatient( state, - element.position, + currentCoordinatesOf(element), 'material', alreadyUpdatedElementIds ); @@ -225,7 +226,7 @@ function updateCatering( cateringElement.canCaterFor.yellow === 0 && cateringElement.canCaterFor.green === 0) || // The element is no longer in a position to treat a patient - cateringElement.position === undefined + isNotOnMap(cateringElement) ) { return; } @@ -243,7 +244,7 @@ function updateCatering( if (cateringElement.overrideTreatmentRange > 0) { const patientIdsInOverrideRange = SpatialTree.findAllElementsInCircle( state.spatialTrees.patients, - cateringElement.position, + currentCoordinatesOf(cateringElement), cateringElement.overrideTreatmentRange ); // In the overrideTreatmentRange (the override circle) only the distance to the patient is important - his/her injuries are ignored @@ -272,7 +273,7 @@ function updateCatering( const patientsInTreatmentRange: Mutable[] = SpatialTree.findAllElementsInCircle( state.spatialTrees.patients, - cateringElement.position, + currentCoordinatesOf(cateringElement), cateringElement.treatmentRange ) // Filter out every patient in the overrideTreatmentRange diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts index 43fa7a604..04f03bec4 100644 --- a/shared/src/store/action-reducers/utils/spatial-elements.ts +++ b/shared/src/store/action-reducers/utils/spatial-elements.ts @@ -1,11 +1,15 @@ -import type { Position } from '../../../models/utils'; +import type { MapCoordinates } from '../../../models/utils'; +import { + isOnMap, + isNotOnMap, + currentCoordinatesOf, +} from '../../../models/utils'; import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable } from '../../../utils'; import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; -import { updateTreatments } from './calculate-treatments'; import { getElement } from './get-element'; /** @@ -13,7 +17,7 @@ import { getElement } from './get-element'; * The position of the element must be changed via one of the function in this file. * In addition, the respective functions must be called when an element gets added or removed. */ -type SpatialElementType = 'material' | 'patient' | 'personnel'; +export type SpatialElementType = 'material' | 'patient' | 'personnel'; type SpatialTypePluralMap = Pick; export type SpatialElementPlural = SpatialTypePluralMap[SpatialElementType]; @@ -27,15 +31,14 @@ export function addElementPosition( elementId: UUID ) { const element = getElement(state, elementType, elementId); - if (element.position === undefined) { + if (isNotOnMap(element)) { return; } SpatialTree.addElement( state.spatialTrees[elementTypePluralMap[elementType]], element.id, - element.position + currentCoordinatesOf(element) ); - updateTreatments(state, element); } /** @@ -45,11 +48,11 @@ export function updateElementPosition( state: Mutable, elementType: SpatialElementType, elementId: UUID, - targetPosition: Position + targetPosition: MapCoordinates ) { const element = getElement(state, elementType, elementId); - const startPosition = element.position; - if (startPosition !== undefined) { + if (isOnMap(element)) { + const startPosition = cloneDeepMutable(currentCoordinatesOf(element)); SpatialTree.moveElement( state.spatialTrees[elementTypePluralMap[elementType]], element.id, @@ -63,12 +66,6 @@ export function updateElementPosition( targetPosition ); } - element.position = cloneDeepMutable(targetPosition); - element.metaPosition = { - type: 'coordinates', - position: cloneDeepMutable(targetPosition), - }; - updateTreatments(state, element); } /** @@ -81,14 +78,12 @@ export function removeElementPosition( elementId: UUID ) { const element = getElement(state, elementType, elementId); - if (element.position === undefined) { + if (isNotOnMap(element)) { return; } SpatialTree.removeElement( state.spatialTrees[elementTypePluralMap[elementType]], element.id, - element.position + cloneDeepMutable(currentCoordinatesOf(element)) ); - element.position = undefined; - updateTreatments(state, element); } diff --git a/shared/src/store/action-reducers/vehicle.ts b/shared/src/store/action-reducers/vehicle.ts index 227586a35..6716c9326 100644 --- a/shared/src/store/action-reducers/vehicle.ts +++ b/shared/src/store/action-reducers/vehicle.ts @@ -1,7 +1,20 @@ import { Type } from 'class-transformer'; import { IsArray, IsString, IsUUID, ValidateNested } from 'class-validator'; import { Material, Personnel, Vehicle } from '../../models'; -import { Position } from '../../models/utils'; +import { + currentCoordinatesOf, + isInTransfer, + isInVehicle, + isNotInTransfer, + isNotOnMap, + MapCoordinates, + MapPosition, + VehiclePosition, +} from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import type { ExerciseState } from '../../state'; import { imageSizeToPosition } from '../../state-helpers'; import type { Mutable } from '../../utils'; @@ -16,11 +29,7 @@ import type { Action, ActionReducer } from '../action-reducer'; import { ReducerError } from '../reducer-error'; import { deletePatient } from './patient'; import { getElement } from './utils/get-element'; -import { - addElementPosition, - removeElementPosition, - updateElementPosition, -} from './utils/spatial-elements'; +import { removeElementPosition } from './utils/spatial-elements'; export function deleteVehicle( draftState: Mutable, @@ -79,8 +88,8 @@ export class MoveVehicleAction implements Action { public readonly vehicleId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class RemoveVehicleAction implements Action { @@ -150,20 +159,20 @@ export namespace VehicleActionReducers { } draftState.vehicles[vehicle.id] = cloneDeepMutable(vehicle); for (const material of cloneDeepMutable(materials)) { - material.metaPosition = { - type: 'vehicle', - vehicleId: vehicle.id, - }; + changePosition( + material, + VehiclePosition.create(vehicle.id), + draftState + ); draftState.materials[material.id] = material; - addElementPosition(draftState, 'material', material.id); } for (const person of cloneDeepMutable(personnel)) { - person.metaPosition = { - type: 'vehicle', - vehicleId: vehicle.id, - }; + changePosition( + person, + VehiclePosition.create(vehicle.id), + draftState + ); draftState.personnel[person.id] = person; - addElementPosition(draftState, 'personnel', person.id); } return draftState; }, @@ -173,12 +182,12 @@ export namespace VehicleActionReducers { export const moveVehicle: ActionReducer = { action: MoveVehicleAction, reducer: (draftState, { vehicleId, targetPosition }) => { - const vehicle = getElement(draftState, 'vehicle', vehicleId); - vehicle.position = cloneDeepMutable(targetPosition); - vehicle.metaPosition = { - type: 'coordinates', - position: cloneDeepMutable(targetPosition), - }; + changePositionWithId( + vehicleId, + MapPosition.create(targetPosition), + 'vehicle', + draftState + ); return draftState; }, rights: 'participant', @@ -213,13 +222,12 @@ export namespace VehicleActionReducers { action: UnloadVehicleAction, reducer: (draftState, { vehicleId }) => { const vehicle = getElement(draftState, 'vehicle', vehicleId); - const unloadMetaPosition = vehicle.metaPosition; - if (unloadMetaPosition.type !== 'coordinates') { + if (isNotOnMap(vehicle)) { throw new ReducerError( `Vehicle with id ${vehicleId} is currently not on the map` ); } - const unloadPosition = unloadMetaPosition.position; + const unloadPosition = currentCoordinatesOf(vehicle); const materialIds = Object.keys(vehicle.materialIds); const personnelIds = Object.keys(vehicle.personnelIds); const patientIds = Object.keys(vehicle.patientIds); @@ -239,10 +247,14 @@ export namespace VehicleActionReducers { for (const patientId of patientIds) { x += space; - updateElementPosition(draftState, 'patient', patientId, { - x, - y: unloadPosition.y, - }); + changePositionWithId( + patientId, + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + 'patient', + draftState + ); delete vehicle.patientIds[patientId]; } @@ -253,15 +265,14 @@ export namespace VehicleActionReducers { 'personnel', personnelId ); - if (Personnel.isInVehicle(personnel)) { - updateElementPosition( - draftState, - 'personnel', + if (isInVehicle(personnel)) { + changePositionWithId( personnelId, - { - x, - y: unloadPosition.y, - } + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + 'personnel', + draftState ); } } @@ -269,11 +280,14 @@ export namespace VehicleActionReducers { for (const materialId of materialIds) { x += space; const material = getElement(draftState, 'material', materialId); - if (Material.isInVehicle(material)) { - updateElementPosition(draftState, 'material', materialId, { - x, - y: unloadPosition.y, - }); + if (isInVehicle(material)) { + changePosition( + material, + MapPosition.create( + MapCoordinates.create(x, unloadPosition.y) + ), + draftState + ); } } @@ -301,11 +315,11 @@ export namespace VehicleActionReducers { `Material with id ${material.id} is not assignable to the vehicle with id ${vehicle.id}` ); } - material.metaPosition = { - type: 'vehicle', - vehicleId, - }; - removeElementPosition(draftState, 'material', material.id); + changePosition( + material, + VehiclePosition.create(vehicleId), + draftState + ); break; } case 'personnel': { @@ -314,7 +328,7 @@ export namespace VehicleActionReducers { 'personnel', elementToBeLoadedId ); - if (personnel.transfer !== undefined) { + if (isInTransfer(personnel)) { throw new ReducerError( `Personnel with id ${elementToBeLoadedId} is currently in transfer` ); @@ -324,14 +338,10 @@ export namespace VehicleActionReducers { `Personnel with id ${personnel.id} is not assignable to the vehicle with id ${vehicle.id}` ); } - personnel.metaPosition = { - type: 'vehicle', - vehicleId, - }; - removeElementPosition( - draftState, - 'personnel', - personnel.id + changePosition( + personnel, + VehiclePosition.create(vehicleId), + draftState ); break; } @@ -350,27 +360,17 @@ export namespace VehicleActionReducers { ); } vehicle.patientIds[elementToBeLoadedId] = true; - - patient.metaPosition = { - type: 'vehicle', - vehicleId, - }; - removeElementPosition(draftState, patient.type, patient.id); - + changePosition( + patient, + VehiclePosition.create(vehicleId), + draftState + ); // Load in all materials Object.keys(vehicle.materialIds).forEach((materialId) => { - getElement( - draftState, - 'material', - materialId - ).metaPosition = { - type: 'vehicle', - vehicleId, - }; - removeElementPosition( - draftState, - 'material', - materialId + changePosition( + getElement(draftState, 'material', materialId), + VehiclePosition.create(vehicleId), + draftState ); }); @@ -379,22 +379,23 @@ export namespace VehicleActionReducers { .filter( // Skip personnel currently in transfer (personnelId) => - getElement(draftState, 'personnel', personnelId) - .transfer === undefined + isNotInTransfer( + getElement( + draftState, + 'personnel', + personnelId + ) + ) ) .forEach((personnelId) => { - getElement( - draftState, - 'personnel', - personnelId - ).metaPosition = { - type: 'vehicle', - vehicleId, - }; - removeElementPosition( - draftState, - 'personnel', - personnelId + changePosition( + getElement( + draftState, + 'personnel', + personnelId + ), + VehiclePosition.create(vehicleId), + draftState ); }); } diff --git a/shared/src/store/action-reducers/viewport.ts b/shared/src/store/action-reducers/viewport.ts index f81ee56a3..3719ab8a1 100644 --- a/shared/src/store/action-reducers/viewport.ts +++ b/shared/src/store/action-reducers/viewport.ts @@ -1,7 +1,11 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { Viewport } from '../../models'; -import { Position, Size } from '../../models/utils'; +import { MapCoordinates, MapPosition, Size } from '../../models/utils'; +import { + changePosition, + changePositionWithId, +} from '../../models/utils/position/position-helpers-mutable'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; @@ -28,8 +32,8 @@ export class MoveViewportAction implements Action { @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; } export class ResizeViewportAction implements Action { @@ -38,8 +42,8 @@ export class ResizeViewportAction implements Action { @IsUUID(4, uuidValidationOptions) public readonly viewportId!: UUID; @ValidateNested() - @Type(() => Position) - public readonly targetPosition!: Position; + @Type(() => MapCoordinates) + public readonly targetPosition!: MapCoordinates; @ValidateNested() @Type(() => Size) public readonly newSize!: Size; @@ -79,8 +83,12 @@ export namespace ViewportActionReducers { export const moveViewport: ActionReducer = { action: MoveViewportAction, reducer: (draftState, { viewportId, targetPosition }) => { - const viewport = getElement(draftState, 'viewport', viewportId); - viewport.position = cloneDeepMutable(targetPosition); + changePositionWithId( + viewportId, + MapPosition.create(targetPosition), + 'viewport', + draftState + ); return draftState; }, rights: 'trainer', @@ -90,7 +98,11 @@ export namespace ViewportActionReducers { action: ResizeViewportAction, reducer: (draftState, { viewportId, targetPosition, newSize }) => { const viewport = getElement(draftState, 'viewport', viewportId); - viewport.position = cloneDeepMutable(targetPosition); + changePosition( + viewport, + MapPosition.create(targetPosition), + draftState + ); viewport.size = cloneDeepMutable(newSize); return draftState; }, diff --git a/shared/src/store/reduce-exercise-state.spec.ts b/shared/src/store/reduce-exercise-state.spec.ts index ac72e6cdd..317638bcc 100644 --- a/shared/src/store/reduce-exercise-state.spec.ts +++ b/shared/src/store/reduce-exercise-state.spec.ts @@ -1,5 +1,6 @@ import type { Viewport } from '../models'; import type { ExerciseStatus } from '../models/utils'; +import { MapCoordinates, MapPosition } from '../models/utils'; import { ExerciseState } from '../state'; import type { UUID } from '../utils'; import { uuid } from '../utils'; @@ -15,7 +16,7 @@ describe('exerciseReducer', () => { type: 'viewport', name: 'Test', size: { width: 100, height: 100 }, - position: { x: 0, y: 0 }, + position: MapPosition.create(MapCoordinates.create(0, 0)), } as const; } diff --git a/shared/src/store/validate-exercise-action.spec.ts b/shared/src/store/validate-exercise-action.spec.ts index da9aab590..f5486b287 100644 --- a/shared/src/store/validate-exercise-action.spec.ts +++ b/shared/src/store/validate-exercise-action.spec.ts @@ -1,5 +1,5 @@ -import type { Position } from '../models/utils'; import { Viewport } from '../models'; +import type { MapCoordinates } from '../models/utils'; import type { ExerciseAction } from './action-reducers'; import { validateExerciseAction } from '.'; @@ -78,9 +78,12 @@ describe('validateExerciseAction', () => { width: 1, }, position: { - // this is of type string instead of number - x: '0' as unknown as number, - y: 0, + type: 'coordinates', + coordinates: { + // this is of type string instead of number + x: '0' as unknown as number, + y: 0, + }, }, }, }) @@ -120,10 +123,13 @@ describe('validateExerciseAction', () => { width: 1, }, position: { - x: 0, - y: 0, - z: 0, - } as unknown as Position, + type: 'coordinates', + coordinates: { + x: 0, + y: 0, + z: 0, + } as unknown as MapCoordinates, + }, }, }) ).not.toEqual([]); diff --git a/shared/src/utils/validators/is-metaposition.ts b/shared/src/utils/validators/is-position.ts similarity index 55% rename from shared/src/utils/validators/is-metaposition.ts rename to shared/src/utils/validators/is-position.ts index e9999b011..cf72d7f66 100644 --- a/shared/src/utils/validators/is-metaposition.ts +++ b/shared/src/utils/validators/is-position.ts @@ -1,28 +1,28 @@ import { Type } from 'class-transformer'; -import { MapPosition } from '../../models/utils/map-position'; -import type { MetaPosition } from '../../models/utils/meta-position'; -import { SimulatedRegionPosition } from '../../models/utils/simulated-region-position'; -import { TransferPosition } from '../../models/utils/transfer-position'; -import { VehiclePosition } from '../../models/utils/vehicle-position'; +import { MapPosition } from '../../models/utils/position/map-position'; +import type { Position } from '../../models/utils/position/position'; +import { SimulatedRegionPosition } from '../../models/utils/position/simulated-region-position'; +import { TransferPosition } from '../../models/utils/position/transfer-position'; +import { VehiclePosition } from '../../models/utils/position/vehicle-position'; import { IsLiteralUnion } from './is-literal-union'; -class MetaPositionBase { - @IsLiteralUnion({ +class PositionBase { + @IsLiteralUnion({ coordinates: true, simulatedRegion: true, transfer: true, vehicle: true, }) - public type: MetaPosition['type']; + public type: Position['type']; - constructor(type: MetaPosition['type']) { + constructor(type: Position['type']) { this.type = type; } } // eslint-disable-next-line @typescript-eslint/naming-convention -export const IsMetaPosition = () => - Type(() => MetaPositionBase, { +export const IsPosition = () => + Type(() => PositionBase, { keepDiscriminatorProperty: true, discriminator: { property: 'type', From 23eb42096fb083182725e832f07257d1244a462c Mon Sep 17 00:00:00 2001 From: Lukas Hagen <43916057+Greenscreen23@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:17:13 +0100 Subject: [PATCH 24/58] Fix GHSA-rc47-6667-2j5j (#645) --- frontend/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 65193a990..7f2aca405 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10018,9 +10018,9 @@ "license": "MIT" }, "node_modules/http-cache-semantics": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", - "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, "node_modules/http-deceiver": { From 37ca94660ed11ffa2188a46e24ab68237385af24 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Thu, 2 Feb 2023 12:31:41 +0100 Subject: [PATCH 25/58] Allow elements to be added to simulated regions (#626) * Allow elements to be added to simulated regions * Adapt Add to Simulated Region Action to type tags * Make linter happy * Use new position and bugfixes * Use proper function to create position --- .../simulated-region-feature-manager.ts | 33 +++++++++++ .../exercise-map/utility/ol-map-manager.ts | 39 ++++++++----- .../store/action-reducers/simulated-region.ts | 58 ++++++++++++++++++- 3 files changed, 114 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index b9c3dd49c..3d9234608 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -2,6 +2,7 @@ import type { Store } from '@ngrx/store'; import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; import { MapCoordinates, Size } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; +import type { TranslateEvent } from 'ol/interaction/Translate'; import type { Polygon } from 'ol/geom'; import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; @@ -102,6 +103,38 @@ export class SimulatedRegionFeatureManager elementFeature.changed(); } + public override onFeatureDrop( + dropEvent: TranslateEvent, + droppedFeature: Feature, + droppedOnFeature: Feature + ) { + const droppedElement = this.getElementFromFeature(droppedFeature); + const droppedOnSimulatedRegion = this.getElementFromFeature( + droppedOnFeature + ) as SimulatedRegion; + if (!droppedElement || !droppedOnSimulatedRegion) { + console.error('Could not find element for the features'); + return false; + } + if ( + ['vehicle', 'personnel', 'material', 'patient'].includes( + droppedElement.type + ) + ) { + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Add Element', + simulatedRegionId: droppedOnSimulatedRegion.id, + elementToBeAddedType: droppedElement.type, + elementToBeAddedId: droppedElement.id, + }, + true + ); + return true; + } + return false; + } + public override onFeatureClicked( event: MapBrowserEvent, feature: Feature diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 722590345..1556ff0c6 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -139,6 +139,7 @@ export class OlMapManager { // The order in this array represents the order of the layers on the map (last element is on top) const featureLayers = [ deleteFeatureLayer, + simulatedRegionLayer, mapImagesLayer, transferLinesLayer, transferPointLayer, @@ -148,7 +149,6 @@ export class OlMapManager { personnelLayer, materialLayer, viewportLayer, - simulatedRegionLayer, ]; // Interactions @@ -460,20 +460,31 @@ export class OlMapManager { private registerDropHandler(translateInteraction: TranslateInteraction) { translateInteraction.on('translateend', (event) => { const pixel = this.olMap.getPixelFromCoordinate(event.coordinate); - this.olMap.forEachFeatureAtPixel(pixel, (feature, layer) => { - // Skip layer when unset - if (layer === null) { - return; + const droppedFeature: Feature = event.features.getArray()[0]!; + + this.olMap.forEachFeatureAtPixel( + pixel, + (droppedOnFeature, layer) => { + // Skip layer when unset + if (layer === null) { + return; + } + + // Do not drop a feature on itself + if (droppedFeature === droppedOnFeature) { + return; + } + + // We stop propagating the event as soon as the onFeatureDropped function returns true + return this.layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureDrop( + event, + droppedFeature, + droppedOnFeature as Feature + ); } - // We stop propagating the event as soon as the onFeatureDropped function returns true - return this.layerFeatureManagerDictionary - .get(layer as VectorLayer)! - .onFeatureDrop( - event, - event.features.getArray()[0]!, - feature as Feature - ); - }); + ); }); } diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts index b36f437f6..da85e9c94 100644 --- a/shared/src/store/action-reducers/simulated-region.ts +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -1,13 +1,18 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { SimulatedRegion } from '../../models'; -import { MapCoordinates, MapPosition, Size } from '../../models/utils'; +import { + MapCoordinates, + MapPosition, + SimulatedRegionPosition, + Size, +} from '../../models/utils'; import { changePosition, changePositionWithId, } from '../../models/utils/position/position-helpers-mutable'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; -import { IsValue } from '../../utils/validators'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; import { getElement } from './utils/get-element'; @@ -60,6 +65,29 @@ export class RenameSimulatedRegionAction implements Action { public readonly newName!: string; } +export class AddElementToSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add Element' as const) + public readonly type = '[SimulatedRegion] Add Element'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @IsLiteralUnion({ + material: true, + patient: true, + personnel: true, + vehicle: true, + }) + public readonly elementToBeAddedType!: + | 'material' + | 'patient' + | 'personnel' + | 'vehicle'; + + @IsUUID(4, uuidValidationOptions) + public readonly elementToBeAddedId!: UUID; +} + export namespace SimulatedRegionActionReducers { export const addSimulatedRegion: ActionReducer = { action: AddSimulatedRegionAction, @@ -134,4 +162,30 @@ export namespace SimulatedRegionActionReducers { }, rights: 'trainer', }; + + export const addElementToSimulatedRegion: ActionReducer = + { + action: AddElementToSimulatedRegionAction, + reducer: ( + draftState, + { simulatedRegionId, elementToBeAddedId, elementToBeAddedType } + ) => { + // Test for existence of the simulate + getElement(draftState, 'simulatedRegion', simulatedRegionId); + const element = getElement( + draftState, + elementToBeAddedType, + elementToBeAddedId + ); + + changePosition( + element, + SimulatedRegionPosition.create(simulatedRegionId), + draftState + ); + + return draftState; + }, + rights: 'participant', + }; } From 4f8cf341a3a9193c448e1bd7c2e09a6942ea03f0 Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Thu, 2 Feb 2023 14:24:26 +0100 Subject: [PATCH 26/58] Refactor Start Point Literals (#642) * Refactor Start Point Literals * Add Migration * Enable Migration * Implement Feedback * Remove not needed types --- .../start-point-name.component.html | 4 +- .../start-point-name.component.ts | 7 +- shared/src/models/utils/start-points.ts | 12 +- .../19-rename-start-point-types.ts | 131 ++++++++++++++++++ .../state-migrations/migration-functions.ts | 2 + shared/src/state.ts | 2 +- shared/src/store/action-reducers/transfer.ts | 2 +- 7 files changed, 145 insertions(+), 15 deletions(-) create mode 100644 shared/src/state-migrations/19-rename-start-point-types.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html index ce930f714..fee500aee 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.html @@ -1,7 +1,7 @@ - + {{ startPoint.alarmGroupName }} diff --git a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts index ab0ec5e45..e68432c17 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/transfer-overview/start-point-name/start-point-name.component.ts @@ -1,8 +1,5 @@ import { Component, Input } from '@angular/core'; -import type { - AlarmGroupStartPoint, - TransferStartPoint, -} from 'digital-fuesim-manv-shared'; +import { StartPoint } from 'digital-fuesim-manv-shared'; @Component({ selector: 'app-start-point-name', @@ -10,5 +7,5 @@ import type { styleUrls: ['./start-point-name.component.scss'], }) export class StartPointNameComponent { - @Input() startPoint!: AlarmGroupStartPoint | TransferStartPoint; + @Input() startPoint!: StartPoint; } diff --git a/shared/src/models/utils/start-points.ts b/shared/src/models/utils/start-points.ts index 604c54344..d976dcd1e 100644 --- a/shared/src/models/utils/start-points.ts +++ b/shared/src/models/utils/start-points.ts @@ -7,8 +7,8 @@ import { getCreate } from './get-create'; export type StartPoint = AlarmGroupStartPoint | TransferStartPoint; export class TransferStartPoint { - @IsValue('transferPoint' as const) - public readonly type = 'transferPoint'; + @IsValue('transferStartPoint' as const) + public readonly type = 'transferStartPoint'; @IsUUID(4, uuidValidationOptions) public readonly transferPointId: UUID; @@ -24,8 +24,8 @@ export class TransferStartPoint { } export class AlarmGroupStartPoint { - @IsValue('alarmGroup' as const) - public readonly type = 'alarmGroup'; + @IsValue('alarmGroupStartPoint' as const) + public readonly type = 'alarmGroupStartPoint'; @IsString() public readonly alarmGroupName: string; @@ -51,11 +51,11 @@ export const startPointTypeOptions: TypeOptions = { property: 'type', subTypes: [ { - name: 'alarmGroup', + name: 'alarmGroupStartPoint', value: AlarmGroupStartPoint, }, { - name: 'transferPoint', + name: 'transferStartPoint', value: TransferStartPoint, }, ], diff --git a/shared/src/state-migrations/19-rename-start-point-types.ts b/shared/src/state-migrations/19-rename-start-point-types.ts new file mode 100644 index 000000000..fdd5179b1 --- /dev/null +++ b/shared/src/state-migrations/19-rename-start-point-types.ts @@ -0,0 +1,131 @@ +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const renameStartPointTypes19: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[Transfer] Add to transfer' + ) { + const typedAction = action as { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + if (typedAction.startPoint.type === 'alarmGroup') { + typedAction.startPoint.type = 'alarmGroupStartPoint'; + } else if (typedAction.startPoint.type === 'transferPoint') { + typedAction.startPoint.type = 'transferStartPoint'; + } + } + }); + }, + state: (state) => { + const typedState = state as { + materials: { + [materialId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + vehicles: { + [vehicleId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + personnel: { + [personnelId: UUID]: { + position: { + type: 'transfer'; + transfer: { + startPoint: { + type: + | 'alarmGroup' + | 'alarmGroupStartPoint' + | 'transferPoint' + | 'transferStartPoint'; + }; + }; + }; + }; + }; + }; + + Object.values(typedState.materials).forEach((material) => { + if (material.position.type === 'transfer') { + if ( + material.position.transfer.startPoint.type === 'alarmGroup' + ) { + material.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + material.position.transfer.startPoint.type === + 'transferPoint' + ) { + material.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + + Object.values(typedState.vehicles).forEach((vehicle) => { + if (vehicle.position.type === 'transfer') { + if ( + vehicle.position.transfer.startPoint.type === 'alarmGroup' + ) { + vehicle.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + vehicle.position.transfer.startPoint.type === + 'transferPoint' + ) { + vehicle.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + + Object.values(typedState.personnel).forEach((personnel) => { + if (personnel.position.type === 'transfer') { + if ( + personnel.position.transfer.startPoint.type === 'alarmGroup' + ) { + personnel.position.transfer.startPoint.type = + 'alarmGroupStartPoint'; + } else if ( + personnel.position.transfer.startPoint.type === + 'transferPoint' + ) { + personnel.position.transfer.startPoint.type = + 'transferStartPoint'; + } + } + }); + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index 780cdf86d..59c83d3bd 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -7,6 +7,7 @@ import { addSimulatedRegions15 } from './15-add-simulated-regions'; import { addMetaPosition16 } from './16-add-meta-position'; import { addTypeProperty17 } from './17-add-type-property'; import { replacePositionWithMetaPosition18 } from './18-replace-position-with-meta-position'; +import { renameStartPointTypes19 } from './19-rename-start-point-types'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -59,4 +60,5 @@ export const migrations: { 16: addMetaPosition16, 17: addTypeProperty17, 18: replacePositionWithMetaPosition18, + 19: renameStartPointTypes19, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index 646d02c7b..c206c4302 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -148,5 +148,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 18; + static readonly currentStateVersion = 19; } diff --git a/shared/src/store/action-reducers/transfer.ts b/shared/src/store/action-reducers/transfer.ts index d21a3304f..c124beabd 100644 --- a/shared/src/store/action-reducers/transfer.ts +++ b/shared/src/store/action-reducers/transfer.ts @@ -143,7 +143,7 @@ export namespace TransferActionReducers { // Get the duration let duration: number; - if (startPoint.type === 'transferPoint') { + if (startPoint.type === 'transferStartPoint') { const transferStartPoint = getElement( draftState, 'transferPoint', From 517f8e79451a8f53b45709f0127fff6ba94e9aec Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Tue, 7 Feb 2023 10:54:52 +0100 Subject: [PATCH 27/58] Add footer and about pages (#643) * Add basic footer and empty about pages * Refactor structure of about pages * Add footer to 404 page * Add links from footer to exercise page * Run prettier * Display version number * Explain overwriting the pages in Docker deployment * Do not lint HTML files for about pages * Refactor template component * Rename title property since it's an html attribute * Make content observable * Rename template component Avoids confusion with angular concepts * Remove accidentally committed imprint dummy file * Remove commented-out footer from exercise page --- docker-compose.yml | 4 + frontend/.eslintrc.json | 2 +- frontend/src/app/app-routing.module.ts | 5 ++ frontend/src/app/app.module.ts | 2 + .../about-placeholder.component.html | 28 ++++++ .../about-placeholder.component.scss | 0 .../about-placeholder.component.ts | 45 ++++++++++ .../app/pages/about/about-routing.module.ts | 32 +++++++ frontend/src/app/pages/about/about.module.ts | 20 +++++ .../about/imprint/imprint.component.html | 1 + .../about/imprint/imprint.component.scss | 0 .../pages/about/imprint/imprint.component.ts | 8 ++ .../about/license/license.component.html | 1 + .../about/license/license.component.scss | 0 .../pages/about/license/license.component.ts | 8 ++ .../about/privacy/privacy.component.html | 1 + .../about/privacy/privacy.component.scss | 0 .../pages/about/privacy/privacy.component.ts | 8 ++ .../pages/error-404/error-404.component.html | 4 + .../app/pages/error-404/error-404.module.ts | 3 +- .../exercise/exercise/exercise.component.html | 86 +++++++++++++------ .../exercise/exercise/exercise.component.ts | 3 + .../landing-page/landing-page.component.html | 4 + .../components/footer/footer.component.html | 17 ++++ .../components/footer/footer.component.scss | 0 .../components/footer/footer.component.ts | 11 +++ frontend/src/app/shared/shared.module.ts | 6 +- frontend/tsconfig.json | 3 +- 28 files changed, 273 insertions(+), 29 deletions(-) create mode 100644 frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html create mode 100644 frontend/src/app/pages/about/about-placeholder/about-placeholder.component.scss create mode 100644 frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts create mode 100644 frontend/src/app/pages/about/about-routing.module.ts create mode 100644 frontend/src/app/pages/about/about.module.ts create mode 100644 frontend/src/app/pages/about/imprint/imprint.component.html create mode 100644 frontend/src/app/pages/about/imprint/imprint.component.scss create mode 100644 frontend/src/app/pages/about/imprint/imprint.component.ts create mode 100644 frontend/src/app/pages/about/license/license.component.html create mode 100644 frontend/src/app/pages/about/license/license.component.scss create mode 100644 frontend/src/app/pages/about/license/license.component.ts create mode 100644 frontend/src/app/pages/about/privacy/privacy.component.html create mode 100644 frontend/src/app/pages/about/privacy/privacy.component.scss create mode 100644 frontend/src/app/pages/about/privacy/privacy.component.ts create mode 100644 frontend/src/app/shared/components/footer/footer.component.html create mode 100644 frontend/src/app/shared/components/footer/footer.component.scss create mode 100644 frontend/src/app/shared/components/footer/footer.component.ts diff --git a/docker-compose.yml b/docker-compose.yml index 0cffe9704..610b7c785 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,6 +18,10 @@ services: - .env volumes: - dfm-data:/${DFM_PERSISTENT_DATA_PATH} + # To overwrite the contents of the about pages, mount a directory into the container + # The directory can contain imprint.html, privacy.html and license.html + # Example + # - ./about:/usr/local/app/frontend/dist/digital-fuesim-manv/assets/about db: image: postgres:14 container_name: dfm_postgres diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 57dcba438..722c4bc07 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -1,6 +1,6 @@ { "root": true, - "ignorePatterns": "index.html", + "ignorePatterns": ["index.html", "**/assets/about/*.html"], "overrides": [ { "files": ["*.ts", "*.js"], diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 72d59dba0..ab0bba4a3 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,6 +1,7 @@ import { NgModule } from '@angular/core'; import type { Routes } from '@angular/router'; import { RouterModule } from '@angular/router'; +import { AboutModule } from './pages/about/about.module'; import { Error404Component } from './pages/error-404/error-404.component'; import { HealthPageComponent } from './pages/health/health-page/health-page.component'; import { LandingPageComponent } from './pages/landing-page/landing-page/landing-page.component'; @@ -10,6 +11,10 @@ const routes: Routes = [ path: '', component: LandingPageComponent, }, + { + path: 'about', + loadChildren: () => AboutModule, + }, { path: 'exercises', // eslint-disable-next-line @typescript-eslint/promise-function-async diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 8489d7e93..3a649cb7c 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -15,6 +15,7 @@ import { LandingPageModule } from './pages/landing-page/landing-page.module'; import { SharedModule } from './shared/shared.module'; import { appReducers } from './state/app.reducer'; import type { AppState } from './state/app.state'; +import { AboutModule } from './pages/about/about.module'; @NgModule({ declarations: [AppComponent, HealthPageComponent], @@ -30,6 +31,7 @@ import type { AppState } from './state/app.state'; SharedModule, ConfirmationModalModule, MessagesModule, + AboutModule, ], providers: [], bootstrap: [AppComponent], diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html new file mode 100644 index 000000000..edcc44e1c --- /dev/null +++ b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html @@ -0,0 +1,28 @@ +
    +

    Digitale FüSim MANV

    +

    {{ pageTitle }}

    + +

    + Zurück zur vorherigen Seite +

    + +
    + +

    + Sie können den Inhalt der Seite unter + frontend/src/assets/about/{{ contentFile }} bearbeiten. +

    +

    + Falls Sie das Docker-Deployment verwenden, finden Sie in der + docker-compose.yml Beispiel-Datei eine Anleitung, wie + Sie Inhalte für diese Seite bereitstellen können. +

    +
    + +
    + +
    +
    diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.scss b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts new file mode 100644 index 000000000..2a15041b0 --- /dev/null +++ b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.ts @@ -0,0 +1,45 @@ +import { Location as NgLocation } from '@angular/common'; +import { HttpClient } from '@angular/common/http'; +import type { OnInit } from '@angular/core'; +import { Component, Input } from '@angular/core'; +import type { Observable } from 'rxjs'; + +@Component({ + selector: 'app-about-placeholder', + templateUrl: './about-placeholder.component.html', + styleUrls: ['./about-placeholder.component.scss'], +}) +export class AboutPlaceholderComponent implements OnInit { + content$!: Observable; + + /** + * The title of the page shown as h2 headline. + */ + @Input() pageTitle = ''; + + /** + * The filename in the assets/about/ directory where the page content should be loaded from. + */ + @Input() contentFile = ''; + + constructor( + private readonly location: NgLocation, + private readonly http: HttpClient + ) {} + + ngOnInit(): void { + this.content$ = this.http.get(`assets/about/${this.contentFile}`, { + responseType: 'text', + }); + } + + back(event: MouseEvent): void { + event.preventDefault(); + + if (history.length > 1) { + this.location.back(); + } else { + window.close(); + } + } +} diff --git a/frontend/src/app/pages/about/about-routing.module.ts b/frontend/src/app/pages/about/about-routing.module.ts new file mode 100644 index 000000000..8da5c5cf8 --- /dev/null +++ b/frontend/src/app/pages/about/about-routing.module.ts @@ -0,0 +1,32 @@ +import { NgModule } from '@angular/core'; +import type { Routes } from '@angular/router'; +import { RouterModule } from '@angular/router'; +import { ImprintComponent } from './imprint/imprint.component'; +import { LicenseComponent } from './license/license.component'; +import { PrivacyComponent } from './privacy/privacy.component'; + +const routes: Routes = [ + { + path: 'imprint', + component: ImprintComponent, + }, + { + path: 'license', + component: LicenseComponent, + }, + { + path: 'privacy', + component: PrivacyComponent, + }, + { + path: '', + redirectTo: 'imprint', + pathMatch: 'full', + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class AboutRoutingModule {} diff --git a/frontend/src/app/pages/about/about.module.ts b/frontend/src/app/pages/about/about.module.ts new file mode 100644 index 000000000..8166f0aad --- /dev/null +++ b/frontend/src/app/pages/about/about.module.ts @@ -0,0 +1,20 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { SharedModule } from 'src/app/shared/shared.module'; +import { AboutRoutingModule } from './about-routing.module'; +import { ImprintComponent } from './imprint/imprint.component'; +import { PrivacyComponent } from './privacy/privacy.component'; +import { LicenseComponent } from './license/license.component'; +import { AboutPlaceholderComponent } from './about-placeholder/about-placeholder.component'; + +@NgModule({ + declarations: [ + ImprintComponent, + PrivacyComponent, + LicenseComponent, + AboutPlaceholderComponent, + ], + imports: [CommonModule, AboutRoutingModule, SharedModule], +}) +export class AboutModule {} diff --git a/frontend/src/app/pages/about/imprint/imprint.component.html b/frontend/src/app/pages/about/imprint/imprint.component.html new file mode 100644 index 000000000..c5b47d09f --- /dev/null +++ b/frontend/src/app/pages/about/imprint/imprint.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/imprint/imprint.component.scss b/frontend/src/app/pages/about/imprint/imprint.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/imprint/imprint.component.ts b/frontend/src/app/pages/about/imprint/imprint.component.ts new file mode 100644 index 000000000..7acdad8f7 --- /dev/null +++ b/frontend/src/app/pages/about/imprint/imprint.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-imprint', + templateUrl: './imprint.component.html', + styleUrls: ['./imprint.component.scss'], +}) +export class ImprintComponent {} diff --git a/frontend/src/app/pages/about/license/license.component.html b/frontend/src/app/pages/about/license/license.component.html new file mode 100644 index 000000000..b9b0839ed --- /dev/null +++ b/frontend/src/app/pages/about/license/license.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/license/license.component.scss b/frontend/src/app/pages/about/license/license.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/license/license.component.ts b/frontend/src/app/pages/about/license/license.component.ts new file mode 100644 index 000000000..8b2641fc9 --- /dev/null +++ b/frontend/src/app/pages/about/license/license.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-license', + templateUrl: './license.component.html', + styleUrls: ['./license.component.scss'], +}) +export class LicenseComponent {} diff --git a/frontend/src/app/pages/about/privacy/privacy.component.html b/frontend/src/app/pages/about/privacy/privacy.component.html new file mode 100644 index 000000000..d24c3b101 --- /dev/null +++ b/frontend/src/app/pages/about/privacy/privacy.component.html @@ -0,0 +1 @@ + diff --git a/frontend/src/app/pages/about/privacy/privacy.component.scss b/frontend/src/app/pages/about/privacy/privacy.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/pages/about/privacy/privacy.component.ts b/frontend/src/app/pages/about/privacy/privacy.component.ts new file mode 100644 index 000000000..4a584f5c6 --- /dev/null +++ b/frontend/src/app/pages/about/privacy/privacy.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-privacy', + templateUrl: './privacy.component.html', + styleUrls: ['./privacy.component.scss'], +}) +export class PrivacyComponent {} diff --git a/frontend/src/app/pages/error-404/error-404.component.html b/frontend/src/app/pages/error-404/error-404.component.html index ecb51e696..511d339e9 100644 --- a/frontend/src/app/pages/error-404/error-404.component.html +++ b/frontend/src/app/pages/error-404/error-404.component.html @@ -12,5 +12,9 @@

    Seite nicht gefunden!

    + +
    + +
    diff --git a/frontend/src/app/pages/error-404/error-404.module.ts b/frontend/src/app/pages/error-404/error-404.module.ts index 5262349dc..94b04865c 100644 --- a/frontend/src/app/pages/error-404/error-404.module.ts +++ b/frontend/src/app/pages/error-404/error-404.module.ts @@ -1,10 +1,11 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; import { RouterModule } from '@angular/router'; +import { SharedModule } from 'src/app/shared/shared.module'; import { Error404Component } from './error-404.component'; @NgModule({ - imports: [CommonModule, RouterModule], + imports: [CommonModule, RouterModule, SharedModule], declarations: [Error404Component], exports: [Error404Component], }) diff --git a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html index b1ae522c6..a693c6bd0 100644 --- a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html +++ b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html @@ -3,7 +3,7 @@ class="p-2 d-flex flex-column" style="height: 100vh" > -
    +

    Ãœbung: {{ @@ -36,34 +36,70 @@

    Ãœbung wieder beitreten -
    - - -
    +
    +
    - + +
    + + +
    +
    + + Feedback + +

    diff --git a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts index c856ac27e..bfdbc7e2d 100644 --- a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts +++ b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.ts @@ -23,6 +23,7 @@ import { } from 'src/app/state/application/selectors/exercise.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { selectOwnClient } from 'src/app/state/application/selectors/shared.selectors'; +import Package from 'package.json'; @Component({ selector: 'app-exercise', @@ -39,6 +40,8 @@ export class ExerciseComponent implements OnDestroy { public readonly timeConstraints$ = this.store.select(selectTimeConstraints); public readonly ownClient$ = this.store.select(selectOwnClient); + readonly version: string = Package.version; + constructor( private readonly store: Store, private readonly apiService: ApiService, diff --git a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html index b1c122745..186981c59 100644 --- a/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html +++ b/frontend/src/app/pages/landing-page/landing-page/landing-page.component.html @@ -175,4 +175,8 @@

    Projektbeteiligte

    >

    + +
    + +
    diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html new file mode 100644 index 000000000..2f7a9e720 --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -0,0 +1,17 @@ +
    +
    + Digitale FüSim MANV, Version {{ version }} – + Feedback geben +
    + + +
    diff --git a/frontend/src/app/shared/components/footer/footer.component.scss b/frontend/src/app/shared/components/footer/footer.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts new file mode 100644 index 000000000..eedc3f56c --- /dev/null +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -0,0 +1,11 @@ +import { Component } from '@angular/core'; +import Package from 'package.json'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'], +}) +export class FooterComponent { + version = Package.version; +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 2e9c57f21..d6f58dd38 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -1,5 +1,6 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { RouterModule } from '@angular/router'; import { HospitalNameComponent } from './components/hospital-name/hospital-name.component'; import { PatientStatusDataFieldComponent } from './components/patient-status-displayl/patient-status-data-field/patient-status-data-field.component'; import { PatientStatusDisplayComponent } from './components/patient-status-displayl/patient-status-display/patient-status-display.component'; @@ -24,6 +25,7 @@ import { FileInputDirective } from './directives/file-input.directive'; import { JoinIdDirective } from './validation/join-id-validator.directive'; import { PersonnelNamePipe } from './pipes/personnel-name.pipe'; import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; +import { FooterComponent } from './components/footer/footer.component'; @NgModule({ declarations: [ @@ -51,8 +53,9 @@ import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; PersonnelNamePipe, CaterCapacityCountPipe, FileInputDirective, + FooterComponent, ], - imports: [CommonModule], + imports: [CommonModule, RouterModule], exports: [ AutofocusDirective, AppSaveOnTypingDirective, @@ -77,6 +80,7 @@ import { CaterCapacityCountPipe } from './pipes/cater-capacity-count.pipe'; IntegerValidatorDirective, PatientStatusBadgeComponent, FileInputDirective, + FooterComponent, ], }) export class SharedModule {} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 5bf4417c6..852510e1d 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -24,7 +24,8 @@ "lib": ["ES2022", "dom"], // needed for https://github.com/typescript-eslint/typescript-eslint/issues/2559#issuecomment-692882427 "emitDecoratorMetadata": true, - "useDefineForClassFields": false + "useDefineForClassFields": false, + "resolveJsonModule": true }, // this fixes jest globals in .spec.ts being overwritten by cypress globals "include": ["src"], From ac373debc9948b367d3a34b995b49dcfc25697a0 Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:36:00 +0100 Subject: [PATCH 28/58] Make Map movable on Drag with Pop Up (#649) * Make Map movable on Drag with Pop Up --- .../exercise-map/utility/ol-map-manager.ts | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 1556ff0c6..48ec61569 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -306,7 +306,7 @@ export class OlMapManager { this.store.select(selectVisibleSimulatedRegions) ); - this.registerPopupTriggers(translateInteraction); + this.registerPopupTriggers(); this.registerDropHandler(translateInteraction); this.registerViewportRestriction(); @@ -411,7 +411,7 @@ export class OlMapManager { }); } - private registerPopupTriggers(translateInteraction: TranslateInteraction) { + private registerPopupTriggers() { this.olMap.on('singleclick', (event) => { if (!this.popupsEnabled) { return; @@ -436,20 +436,6 @@ export class OlMapManager { } }); - // Automatically close the popup - translateInteraction.on('translating', (event) => { - if ( - event.coordinate[0] === event.startCoordinate[0] && - event.coordinate[1] === event.startCoordinate[1] - ) { - return; - } - this.changePopup$.next(undefined); - }); - this.olMap.getView().on(['change:resolution', 'change:center'], () => { - this.changePopup$.next(undefined); - }); - this.openLayersContainer.addEventListener('keydown', (event) => { if ((event as KeyboardEvent).key === 'Escape') { this.changePopup$.next(undefined); From b458be325d600ea5f5456b5c743695b972c0a553 Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Tue, 7 Feb 2023 12:46:11 +0100 Subject: [PATCH 29/58] Update pipeline actions to node 16 (#627) * Update pipeline actions to node 16 The old actions were based on Node 12, which has reached EOL. https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/ * Test previous version of cypress action again * Try cypress action v3 * Do not use cached cypress * Try a Cypress Config without actually calling Cypress * Try some more stuff... * Add Cypress as DevDependency to root * Re-enable default cypress tests * Remove version tag from cypress cache The tag was there for debugging purposes only * Invoke cypress in frontend subfolder * Try working-directory for cypress * Try --prefix for start * Retry --prefix before 'run' * Restore 5a9692d9 * Update package-lock.json --------- Co-authored-by: ClFeSc <68013019+ClFeSc@users.noreply.github.com> Co-authored-by: Nils <45318774+Nils1729@users.noreply.github.com> --- .github/workflows/pipeline.yml | 71 +++++++++++++++++----------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index d177a66af..7d62bd3cd 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -15,12 +15,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -32,7 +32,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -57,12 +57,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -74,7 +74,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -101,12 +101,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -118,7 +118,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -168,12 +168,12 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -185,7 +185,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -209,7 +209,7 @@ jobs: run: npm run merge-coverage if: always() - name: Upload coverage - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: always() with: name: coverage-output @@ -244,17 +244,17 @@ jobs: # Don't pull LFS to reduce bandwidth usage steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # with: # lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 # - run: git lfs pull - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v3 with: node-version: '16' - name: Cache node modules - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-node-modules env: cache-name: cache-node-modules @@ -266,7 +266,7 @@ jobs: backend/node_modules key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('package-lock.json') }} - name: Cache shared/dist - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-shared-dist env: cache-name: cache-shared-dist @@ -274,7 +274,7 @@ jobs: path: shared/dist key: ${{ secrets.CACHE_VERSION }}-${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('shared/src/**') }} - name: Cache Cypress binary - uses: actions/cache@v2 + uses: actions/cache@v3 id: cache-cypress with: path: ~/.cache/Cypress @@ -287,14 +287,15 @@ jobs: - name: Run migrations run: cd backend && npm run migration:run && cd .. - name: Run Cypress - uses: cypress-io/github-action@v2 + uses: cypress-io/github-action@v5 with: - start: npm run start:all - command: npm run cy:ci + start: npm --prefix .. -- run start:all + command: npm run cy:run + working-directory: frontend wait-on: 'http://localhost:4200/health, http://localhost:3201/api/health' - name: Archive cypress if: always() - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: cypress-output path: frontend/cypress-visual-screenshots @@ -313,20 +314,20 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: git lfs pull # Source: https://docs.docker.com/ci-cd/github-actions/ - name: Login to docker - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: docker/Dockerfile @@ -347,20 +348,20 @@ jobs: fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: lfs: 'true' - name: checkoutLFS - uses: actions/checkout@v2 + uses: actions/checkout@v3 - run: git lfs pull # Source: https://docs.docker.com/ci-cd/github-actions/ - name: Login to docker - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_HUB_USERNAME }} password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} - name: Build and push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v3 with: context: . file: docker/Dockerfile From 0c1ff5b1df68befd3e45ecabb31cedc731a074be Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Wed, 8 Feb 2023 10:17:23 +0100 Subject: [PATCH 30/58] Change mail address to feedback mailing list (#659) --- .../pages/exercises/exercise/exercise/exercise.component.html | 2 +- frontend/src/app/shared/components/footer/footer.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html index a693c6bd0..8d8a06777 100644 --- a/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html +++ b/frontend/src/app/pages/exercises/exercise/exercise/exercise.component.html @@ -72,7 +72,7 @@

    diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html index 2f7a9e720..dc6bc542a 100644 --- a/frontend/src/app/shared/components/footer/footer.component.html +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -2,7 +2,7 @@
    Digitale FüSim MANV, Version {{ version }} – Feedback geben Date: Wed, 8 Feb 2023 10:43:19 +0100 Subject: [PATCH 31/58] Adapt treatment system to account for simulated regions (#658) * Adapt treatment system to account for simulated regions The treatment system no longer asserts that patients can only be treated on the map. * Please linter * Enable patient ticking in simulated regions --- backend/src/exercise/patient-ticking.ts | 4 +-- shared/src/models/patient.ts | 10 +++++++ .../position/position-helpers-mutable.ts | 30 +++++++++++-------- .../utils/calculate-treatments.ts | 18 ++++++----- .../action-reducers/utils/spatial-elements.ts | 2 ++ 5 files changed, 42 insertions(+), 22 deletions(-) diff --git a/backend/src/exercise/patient-ticking.ts b/backend/src/exercise/patient-ticking.ts index 38f130b0d..de3f323ab 100644 --- a/backend/src/exercise/patient-ticking.ts +++ b/backend/src/exercise/patient-ticking.ts @@ -5,10 +5,8 @@ import type { PersonnelType, } from 'digital-fuesim-manv-shared'; import { - isOnMap, getElement, healthPointsDefaults, - isAlive, Patient, } from 'digital-fuesim-manv-shared'; @@ -30,7 +28,7 @@ export function patientTick( return ( Object.values(state.patients) // Only look at patients that are alive and have a position, i.e. are not in a vehicle - .filter((patient) => isAlive(patient.health) && isOnMap(patient)) + .filter((patient) => Patient.canBeTreated(patient)) .map((patient) => { // update the time a patient is being treated, to check for pretriage later const treatmentTime = Patient.isTreatedByPersonnel(patient) diff --git a/shared/src/models/patient.ts b/shared/src/models/patient.ts index a8f015149..168f9b77f 100644 --- a/shared/src/models/patient.ts +++ b/shared/src/models/patient.ts @@ -28,6 +28,9 @@ import { healthPointsDefaults, HealthPoints, getCreate, + isAlive, + isOnMap, + isInSimulatedRegion, } from './utils'; import { Position } from './utils/position/position'; import { PersonalInformation } from './utils/personal-information'; @@ -194,4 +197,11 @@ export class Patient { static isTreatedByPersonnel(patient: Patient) { return !isEmpty(patient.assignedPersonnelIds); } + + static canBeTreated(patient: Patient) { + return ( + isAlive(patient.health) && + (isOnMap(patient) || isInSimulatedRegion(patient)) + ); + } } diff --git a/shared/src/models/utils/position/position-helpers-mutable.ts b/shared/src/models/utils/position/position-helpers-mutable.ts index 862fa8f22..d13030065 100644 --- a/shared/src/models/utils/position/position-helpers-mutable.ts +++ b/shared/src/models/utils/position/position-helpers-mutable.ts @@ -1,6 +1,9 @@ import type { ExerciseState } from '../../../state'; import { getElement } from '../../../store/action-reducers/utils'; -import { updateTreatments } from '../../../store/action-reducers/utils/calculate-treatments'; +import { + removeTreatmentsOfElement, + updateTreatments, +} from '../../../store/action-reducers/utils/calculate-treatments'; import type { SpatialElementType } from '../../../store/action-reducers/utils/spatial-elements'; import { removeElementPosition, @@ -49,26 +52,29 @@ export function changePositionWithId( } export function changePosition( - of: WithMutablePosition, + element: WithMutablePosition, to: Position, - inState: Mutable + state: Mutable ) { if ( - of.type === 'patient' || - of.type === 'personnel' || - of.type === 'material' + element.type === 'patient' || + element.type === 'personnel' || + element.type === 'material' ) { updateSpatialElementTree( - of as WithMutablePositionAndId, + element as WithMutablePositionAndId, to, - of.type, - inState + element.type, + state ); - of.position = cloneDeepMutable(to); - updateTreatments(inState, of as any); + if (element.position.type !== to.type) { + removeTreatmentsOfElement(state, element as any); + } + element.position = cloneDeepMutable(to); + updateTreatments(state, element as any); return; } - of.position = cloneDeepMutable(to); + element.position = cloneDeepMutable(to); } function updateSpatialElementTree( diff --git a/shared/src/store/action-reducers/utils/calculate-treatments.ts b/shared/src/store/action-reducers/utils/calculate-treatments.ts index 514c07cd1..a1d9fa16a 100644 --- a/shared/src/store/action-reducers/utils/calculate-treatments.ts +++ b/shared/src/store/action-reducers/utils/calculate-treatments.ts @@ -2,7 +2,11 @@ import { groupBy } from 'lodash-es'; import type { Material, Personnel } from '../../../models'; import { Patient } from '../../../models'; import type { MapCoordinates, PatientStatus } from '../../../models/utils'; -import { currentCoordinatesOf, isNotOnMap } from '../../../models/utils'; +import { + currentCoordinatesOf, + isNotOnMap, + isInSimulatedRegion, +} from '../../../models/utils'; import { SpatialTree } from '../../../models/utils/spatial-tree'; import type { ExerciseState } from '../../../state'; import { maxTreatmentRange } from '../../../state-helpers/max-treatment-range'; @@ -115,13 +119,10 @@ function updateCateringAroundPatient( } } -function removeTreatmentsOfElement( +export function removeTreatmentsOfElement( state: Mutable, element: Mutable ) { - // TODO: when elements have their own type saved don't use const patient = getElement(state, 'patients', element.id); - // instead use const patient = element; - // same for personnel and material in the other if statements if (element.type === 'patient') { const patient = element; // Make all personnel stop treating this patient @@ -170,8 +171,11 @@ export function updateTreatments( // Currently, the treatment pattern algorithm is stable. This means that completely done from scratch, // the result would semantically be the same. This could be changed later. + if (isInSimulatedRegion(element)) { + return; + } + if (isNotOnMap(element)) { - // The element is no longer in a position (get it?!) to be treated or treat a patient removeTreatmentsOfElement(state, element); return; } @@ -225,7 +229,7 @@ function updateCatering( (cateringElement.canCaterFor.red === 0 && cateringElement.canCaterFor.yellow === 0 && cateringElement.canCaterFor.green === 0) || - // The element is no longer in a position to treat a patient + // The element is no longer in a position to treat a patient on the map isNotOnMap(cateringElement) ) { return; diff --git a/shared/src/store/action-reducers/utils/spatial-elements.ts b/shared/src/store/action-reducers/utils/spatial-elements.ts index 04f03bec4..1a1e897f9 100644 --- a/shared/src/store/action-reducers/utils/spatial-elements.ts +++ b/shared/src/store/action-reducers/utils/spatial-elements.ts @@ -10,6 +10,7 @@ import type { Mutable, UUID } from '../../../utils'; import { cloneDeepMutable } from '../../../utils'; import type { ElementTypePluralMap } from '../../../utils/element-type-plural-map'; import { elementTypePluralMap } from '../../../utils/element-type-plural-map'; +import { removeTreatmentsOfElement } from './calculate-treatments'; import { getElement } from './get-element'; /** @@ -78,6 +79,7 @@ export function removeElementPosition( elementId: UUID ) { const element = getElement(state, elementType, elementId); + removeTreatmentsOfElement(state, element); if (isNotOnMap(element)) { return; } From f8ff1124f96a426e7471f56fc572d7a029160669 Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Wed, 8 Feb 2023 16:51:06 +0100 Subject: [PATCH 32/58] Fix extent calculation of viewports and simulated regions (#663) * Include simulated regions when fitting to view Also fixing a bug with negative extents * Fix viewport restriction with negative extent * Rename fit view method * Rename function at all occurrences * Fix isInViewport for negative extents * Satisfy linter * Avoid duplication in type definitions --- .../exercise-map/exercise-map.component.html | 2 +- .../exercise-map/utility/ol-map-manager.ts | 47 ++++++++++--------- .../models/utils/position/position-helpers.ts | 31 +++++++++++- .../src/models/utils/position/with-extent.ts | 6 +++ shared/src/models/viewport.ts | 15 +++--- 5 files changed, 70 insertions(+), 31 deletions(-) create mode 100644 shared/src/models/utils/position/with-extent.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html index 53b241efb..917f38959 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.html @@ -25,7 +25,7 @@ (currentRole$ | async) !== 'participant' && (restrictedToViewport$ | async) === undefined " - (click)="olMapManager?.tryToFitViewToViewports()" + (click)="olMapManager?.tryToFitViewForOverview()" class="btn btn-sm btn-light" title="Alle Ansichten anzeigen" > diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 48ec61569..c42adc7be 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -5,7 +5,10 @@ import type { MergeIntersection, UUID, } from 'digital-fuesim-manv-shared'; -import { currentCoordinatesOf } from 'digital-fuesim-manv-shared'; +import { + upperLeftCornerOf, + lowerRightCornerOf, +} from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; import { Overlay, View } from 'ol'; import type { Polygon } from 'ol/geom'; @@ -25,6 +28,7 @@ import { handleChanges } from 'src/app/shared/functions/handle-changes'; import type { AppState } from 'src/app/state/app.state'; import { selectExerciseStatus, + selectSimulatedRegion, selectTileMapProperties, selectTransferLines, selectViewports, @@ -341,7 +345,7 @@ export class OlMapManager { } private registerViewportRestriction() { - this.tryToFitViewToViewports(false); + this.tryToFitViewForOverview(false); this.store .select(selectRestrictedViewport) .pipe(takeUntil(this.destroy$)) @@ -356,11 +360,13 @@ export class OlMapManager { } const center = view.getCenter()!; const previousZoom = view.getZoom()!; + const targetUpperLeftCorner = upperLeftCornerOf(viewport); + const targetLowerRightCorner = lowerRightCornerOf(viewport); const targetExtent = [ - currentCoordinatesOf(viewport).x, - currentCoordinatesOf(viewport).y - viewport.size.height, - currentCoordinatesOf(viewport).x + viewport.size.width, - currentCoordinatesOf(viewport).y, + targetUpperLeftCorner.x, + targetLowerRightCorner.y, + targetLowerRightCorner.x, + targetUpperLeftCorner.y, ]; view.fit(targetExtent); const matchingZoom = view.getZoom()!; @@ -496,9 +502,9 @@ export class OlMapManager { } /** - * Sets the map's view to see all viewports. + * Sets the map's view to see all viewports and simulated regions. */ - public tryToFitViewToViewports(animate = true) { + public tryToFitViewForOverview(animate = true) { if ( selectStateSnapshot(selectRestrictedViewport, this.store) !== undefined @@ -506,31 +512,28 @@ export class OlMapManager { // We are restricted to a viewport -> you can't fit the view return; } - const viewports = Object.values( - selectStateSnapshot(selectViewports, this.store) - ); + const elements = [ + ...Object.values(selectStateSnapshot(selectViewports, this.store)), + ...Object.values( + selectStateSnapshot(selectSimulatedRegion, this.store) + ), + ]; const view = this.olMap.getView(); - if (viewports.length === 0) { + if (elements.length === 0) { view.setCenter([startingPosition.x, startingPosition.y]); return; } const minX = Math.min( - ...viewports.map((viewport) => currentCoordinatesOf(viewport).x) + ...elements.map((element) => upperLeftCornerOf(element).x) ); const minY = Math.min( - ...viewports.map( - (viewport) => - currentCoordinatesOf(viewport).y - viewport.size.height - ) + ...elements.map((element) => lowerRightCornerOf(element).y) ); const maxX = Math.max( - ...viewports.map( - (viewport) => - currentCoordinatesOf(viewport).x + viewport.size.width - ) + ...elements.map((element) => lowerRightCornerOf(element).x) ); const maxY = Math.max( - ...viewports.map((viewport) => currentCoordinatesOf(viewport).y) + ...elements.map((element) => upperLeftCornerOf(element).y) ); const padding = 25; view.fit([minX, minY, maxX, maxY], { diff --git a/shared/src/models/utils/position/position-helpers.ts b/shared/src/models/utils/position/position-helpers.ts index a87984a24..819a1b9e5 100644 --- a/shared/src/models/utils/position/position-helpers.ts +++ b/shared/src/models/utils/position/position-helpers.ts @@ -1,11 +1,12 @@ import type { UUID } from '../../../utils'; import type { Transfer } from '../transfer'; -import type { MapCoordinates } from './map-coordinates'; +import { MapCoordinates } from './map-coordinates'; import type { MapPosition } from './map-position'; import type { Position } from './position'; import type { SimulatedRegionPosition } from './simulated-region-position'; import type { TransferPosition } from './transfer-position'; import type { VehiclePosition } from './vehicle-position'; +import type { WithExtent } from './with-extent'; import type { WithPosition } from './with-position'; export function isOnMap(withPosition: WithPosition): boolean { @@ -131,3 +132,31 @@ export function simulatedRegionIdOfPosition(position: Position): UUID { `Expected position to be in simulatedRegion. Was of type ${position.type}.` ); } + +export function upperLeftCornerOf(element: WithExtent): MapCoordinates { + const corner = { ...currentCoordinatesOf(element) }; + + if (element.size.width < 0) { + corner.x += element.size.width; + } + + if (element.size.height < 0) { + corner.y -= element.size.height; + } + + return MapCoordinates.create(corner.x, corner.y); +} + +export function lowerRightCornerOf(element: WithExtent): MapCoordinates { + const corner = { ...currentCoordinatesOf(element) }; + + if (element.size.width > 0) { + corner.x += element.size.width; + } + + if (element.size.height > 0) { + corner.y -= element.size.height; + } + + return MapCoordinates.create(corner.x, corner.y); +} diff --git a/shared/src/models/utils/position/with-extent.ts b/shared/src/models/utils/position/with-extent.ts new file mode 100644 index 000000000..a85914f2d --- /dev/null +++ b/shared/src/models/utils/position/with-extent.ts @@ -0,0 +1,6 @@ +import type { Size } from '../size'; +import type { WithPosition } from './with-position'; + +export interface WithExtent extends WithPosition { + readonly size: Size; +} diff --git a/shared/src/models/viewport.ts b/shared/src/models/viewport.ts index 081635bc4..400cebdbd 100644 --- a/shared/src/models/viewport.ts +++ b/shared/src/models/viewport.ts @@ -4,11 +4,12 @@ import { UUID, uuid, uuidValidationOptions } from '../utils'; import { IsPosition } from '../utils/validators/is-position'; import { IsValue } from '../utils/validators'; import { - currentCoordinatesOf, getCreate, + lowerRightCornerOf, MapPosition, Position, Size, + upperLeftCornerOf, } from './utils'; import type { ImageProperties, MapCoordinates } from './utils'; @@ -54,13 +55,13 @@ export class Viewport { }; static isInViewport(viewport: Viewport, position: MapCoordinates): boolean { + const upperLeftCorner = upperLeftCornerOf(viewport); + const lowerRightCorner = lowerRightCornerOf(viewport); return ( - currentCoordinatesOf(viewport).x <= position.x && - position.x <= - currentCoordinatesOf(viewport).x + viewport.size.width && - currentCoordinatesOf(viewport).y - viewport.size.height <= - position.y && - position.y <= currentCoordinatesOf(viewport).y + upperLeftCorner.x <= position.x && + position.x <= lowerRightCorner.x && + lowerRightCorner.y <= position.y && + position.y <= upperLeftCorner.y ); } } From c481afebdd6fd0c3f95401b7ab2b81c4397bfd2f Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Tue, 14 Feb 2023 17:52:16 +0100 Subject: [PATCH 33/58] Refactoring/609 refactor functionality from olmapmanager to featuremanagers (#662) * WIP * Move Layer Creation to Feature Managers * Move Registration into Feature managers * Complete Merge * Move Interactions to Interaction Manager * Move Popup Handling to Popup Manager * Move Satellite Layer to Satellite Layer manager * Minor Cleanup * Move files * Move Files * More Cleanup * More Cleanup * Fix a bug in participant mode * Clean up Map Interactions manager * Clean up Satellite Layer Manager * Fix Lint * Implement Feedback * Implement Feedback and change Parameter Order in onFeatureDropped * Implement Feedback and change Parameter Order in onFeatureDropped --------- Co-authored-by: Julian Schmidt --- .../exercise-map/exercise-map.component.ts | 15 +- .../catering-lines-feature-manager.ts | 42 +- .../delete-feature-manager.ts | 38 +- .../feature-managers/element-manager.ts | 44 +- .../map-images-feature-manager.ts | 30 +- .../material-feature-manager.ts | 27 +- .../moveable-feature-manager.ts | 50 +- .../patient-feature-manager.ts | 24 +- .../personnel-feature-manager.ts | 27 +- .../simulated-region-feature-manager.ts | 34 +- .../transfer-lines-feature-manager.ts | 52 +- .../transfer-point-feature-manager.ts | 37 +- .../vehicle-feature-manager.ts | 33 +- .../viewport-feature-manager.ts | 30 +- .../exercise-map/utility/feature-manager.ts | 13 +- .../utility/ol-map-interactions-manager.ts | 177 ++++++ .../exercise-map/utility/ol-map-manager.ts | 516 +++++------------- .../exercise-map/utility/popup-manager.ts | 73 ++- .../utility/satellite-layer-manager.ts | 36 ++ 19 files changed, 836 insertions(+), 462 deletions(-) create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts create mode 100644 frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts index 3064e3746..de473149a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts @@ -49,23 +49,24 @@ export class ExerciseMapComponent implements AfterViewInit, OnDestroy { ) {} ngAfterViewInit(): void { + this.popupManager = new PopupManager( + this.popoverContent, + this.popoverContainer.nativeElement + ); // run outside angular zone for better performance this.ngZone.runOutsideAngular(() => { this.olMapManager = new OlMapManager( this.store, this.exerciseService, this.openLayersContainer.nativeElement, - this.popoverContainer.nativeElement, this.ngZone, - this.transferLinesService + this.transferLinesService, + this.popupManager! ); this.dragElementService.registerMap(this.olMapManager.olMap); }); - this.popupManager = new PopupManager( - this.olMapManager!.popupOverlay, - this.popoverContent - ); - this.olMapManager!.changePopup$.pipe( + + this.popupManager!.changePopup$.pipe( takeUntil(this.destroy$) ).subscribe((options) => { // Because changePopup$ is coming from outside the angular zone, we need to wrap it in a zone diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index bdf33f8b8..d38006350 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -1,12 +1,20 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { MapBrowserEvent } from 'ol'; import { Feature } from 'ol'; import LineString from 'ol/geom/LineString'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import { rgbColorPalette } from 'src/app/shared/functions/colors'; import type { CateringLine } from 'src/app/shared/types/catering-line'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleCateringLines } from 'src/app/state/application/selectors/shared.selectors'; +import type OlMap from 'ol/Map'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { LineStyleHelper } from '../utility/style-helper/line-style-helper'; import { ElementManager } from './element-manager'; @@ -20,13 +28,39 @@ export class CateringLinesFeatureManager }), 0.05 ); + public readonly layer: VectorLayer>; - constructor(public readonly layer: VectorLayer>) { + constructor( + private readonly store: Store, + private readonly olMap: OlMap + ) { super(); - layer.setStyle((feature, currentZoom) => + this.layer = super.createElementLayer(); + this.layer.setStyle((feature, currentZoom) => this.lineStyleHelper.getStyle(feature as Feature, currentZoom) ); } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + // Propagate the changes on an element to the featureManager + this.registerChangeHandlers( + this.store.select(selectVisibleCateringLines), + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + } public isFeatureTranslatable(feature: Feature) { return false; @@ -76,9 +110,9 @@ export class CateringLinesFeatureManager ) {} onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { return false; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts index b4b2f07f3..8178c3d12 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts @@ -1,3 +1,4 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; import type { MapBrowserEvent, View } from 'ol'; @@ -5,16 +6,20 @@ import { Feature } from 'ol'; import { getTopRight } from 'ol/extent'; import { Point } from 'ol/geom'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; +import VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import VectorSource from 'ol/source/Vector'; import Icon from 'ol/style/Icon'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; import { selectExerciseState } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; function calculateTopRightViewPoint(view: View) { const extent = getTopRight(view.calculateExtent()); @@ -22,12 +27,34 @@ function calculateTopRightViewPoint(view: View) { } export class DeleteFeatureManager implements FeatureManager { + readonly layer: VectorLayer>; constructor( private readonly store: Store, - public readonly layer: VectorLayer>, private readonly olMap: OlMap, private readonly exerciseService: ExerciseService ) { + this.layer = new VectorLayer({ + // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed + updateWhileAnimating: true, + updateWhileInteracting: true, + renderBuffer: 250, + source: new VectorSource(), + }); + } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { + this.makeVisible(); + } + } + public makeVisible() { this.layer.setStyle( new Style({ image: new Icon({ @@ -49,6 +76,7 @@ export class DeleteFeatureManager implements FeatureManager { ); }); } + public onFeatureClicked( event: MapBrowserEvent, feature: Feature @@ -60,9 +88,9 @@ export class DeleteFeatureManager implements FeatureManager { } public onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { const id = droppedFeature.getId() as UUID; const exerciseState = selectStateSnapshot( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index 35ca3076d..aeca69e91 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -1,6 +1,12 @@ +import type { NgZone } from '@angular/core'; import type { ImmutableJsonObject } from 'digital-fuesim-manv-shared'; import type { Feature } from 'ol'; -import type { Geometry } from 'ol/geom'; +import type { Geometry, Point } from 'ol/geom'; +import VectorLayer from 'ol/layer/Vector'; +import VectorSource from 'ol/source/Vector'; +import type { Observable, Subject } from 'rxjs'; +import { pairwise, startWith, takeUntil } from 'rxjs'; +import { handleChanges } from 'src/app/shared/functions/handle-changes'; import { generateChangedProperties } from '../utility/generate-changed-properties'; /** @@ -87,6 +93,42 @@ export abstract class ElementManager< public getElementFromFeature(feature: Feature) { return feature.get(featureElementKey); } + /** + * @param renderBuffer The size of the largest symbol, line width or label on the highest zoom level. + */ + protected createElementLayer( + renderBuffer = 250 + ) { + return new VectorLayer({ + // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed + updateWhileAnimating: true, + updateWhileInteracting: true, + renderBuffer, + source: new VectorSource(), + }); + } + + protected registerChangeHandlers( + elementDictionary$: Observable<{ [id: string]: Element }>, + destroy$: Subject, + ngZone: NgZone, + createHandler?: (newElement: Element) => void, + deleteHandler?: (deletedElement: Element) => void, + changeHandler?: (oldElement: Element, newElement: Element) => void + ) { + elementDictionary$ + .pipe(startWith({}), pairwise(), takeUntil(destroy$)) + .subscribe(([oldElementDictionary, newElementDictionary]) => { + // run outside angular zone for better performance + ngZone.runOutsideAngular(() => { + handleChanges(oldElementDictionary, newElementDictionary, { + createHandler, + deleteHandler, + changeHandler, + }); + }); + }); + } } /** diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts index 35e1a46d3..4e1d81f6a 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/map-images-feature-manager.ts @@ -1,21 +1,40 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { MapImage, UUID } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleMapImages, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { MapImagePopupComponent } from '../shared/map-image-popup/map-image-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class MapImageFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleMapImages), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( (feature) => (this.getElementFromFeature(feature) as MapImage).image ); @@ -23,13 +42,11 @@ export class MapImageFeatureManager extends MoveableFeatureManager { constructor( olMap: OlMap, - layer: VectorLayer>, exerciseService: ExerciseService, private readonly store: Store ) { super( olMap, - layer, (targetPosition, mapImage) => { exerciseService.proposeAction({ type: '[MapImage] Move MapImage', @@ -37,7 +54,8 @@ export class MapImageFeatureManager extends MoveableFeatureManager { targetPosition, }); }, - new PointGeometryHelper() + new PointGeometryHelper(), + 10_000 ); this.layer.setStyle((feature, resolution) => { const style = this.imageStyleHelper.getStyle( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts index d4561aeb0..cfca5500b 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/material-feature-manager.ts @@ -1,19 +1,37 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { Material, UUID } from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleMaterials } from 'src/app/state/application/selectors/shared.selectors'; import { MaterialPopupComponent } from '../shared/material-popup/material-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class MaterialFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleMaterials), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( (feature) => (this.getElementFromFeature(feature) as Material).image ); @@ -33,12 +51,11 @@ export class MaterialFeatureManager extends MoveableFeatureManager { constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, material) => { exerciseService.proposeAction({ type: '[Material] Move material', diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts index daabb3566..a89e8b2ba 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -4,7 +4,10 @@ import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; import type VectorSource from 'ol/source/Vector'; +import type { Observable } from 'rxjs'; import { Subject } from 'rxjs'; +import type { NgZone } from '@angular/core'; +import type { UUID } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; import { MovementAnimator } from '../utility/movement-animator'; import type { @@ -15,6 +18,7 @@ import type { } from '../utility/geometry-helper'; import type { OpenPopupOptions } from '../utility/popup-manager'; import { TranslateInteraction } from '../utility/translate-interaction'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { ElementManager } from './element-manager'; /** @@ -30,18 +34,24 @@ export abstract class MoveableFeatureManager< implements FeatureManager { public readonly togglePopup$ = new Subject>(); - protected readonly movementAnimator: MovementAnimator; + protected movementAnimator: MovementAnimator; + public layer: VectorLayer>; constructor( protected readonly olMap: OlMap, - public readonly layer: VectorLayer>, private readonly proposeMovementAction: ( newPosition: Positions, element: Element ) => void, - protected readonly geometryHelper: GeometryHelper + protected readonly geometryHelper: GeometryHelper, + renderBuffer?: number ) { super(); - this.movementAnimator = new MovementAnimator( + this.layer = super.createElementLayer(renderBuffer); + this.movementAnimator = this.createMovementAnimator(); + } + + createMovementAnimator() { + return new MovementAnimator( this.olMap, this.layer, this.geometryHelper.interpolateCoordinates, @@ -111,10 +121,38 @@ export abstract class MoveableFeatureManager< * The standard implementation is to ignore these events. */ public onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ): boolean { return false; } + + public abstract register( + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void; + + protected registerFeatureElementManager( + elementDictionary$: Observable<{ [id: UUID]: Element }>, + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + this.registerChangeHandlers( + elementDictionary$, + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts index 71067000a..344e4282f 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/patient-feature-manager.ts @@ -1,24 +1,40 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; import { Patient } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; import { Fill, Stroke } from 'ol/style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; import { selectConfiguration } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectVisiblePatients } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { PatientPopupComponent } from '../shared/patient-popup/patient-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { CircleStyleHelper } from '../utility/style-helper/circle-style-helper'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class PatientFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisiblePatients), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly popupHelper = new ImagePopupHelper(this.olMap, this.layer); private readonly imageStyleHelper = new ImageStyleHelper((feature) => { @@ -65,12 +81,10 @@ export class PatientFeatureManager extends MoveableFeatureManager { constructor( private readonly store: Store, olMap: OlMap, - layer: VectorLayer>, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, patient) => { exerciseService.proposeAction({ type: '[Patient] Move patient', diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts index 54dcd2e18..861d70390 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/personnel-feature-manager.ts @@ -1,19 +1,37 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { Personnel, UUID } from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; -import type Point from 'ol/geom/Point'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisiblePersonnel } from 'src/app/state/application/selectors/shared.selectors'; import { PersonnelPopupComponent } from '../shared/personnel-popup/personnel-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class PersonnelFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisiblePersonnel), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( (feature) => (this.getElementFromFeature(feature) as Personnel).image ); @@ -33,12 +51,11 @@ export class PersonnelFeatureManager extends MoveableFeatureManager { constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, personnel) => { exerciseService.proposeAction({ type: '[Personnel] Move personnel', diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index 3d9234608..8554a4f1b 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -4,36 +4,56 @@ import { MapCoordinates, Size } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type { Polygon } from 'ol/geom'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; import { Fill } from 'ol/style'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleSimulatedRegions, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { Type, NgZone } from '@angular/core'; +import type { Subject } from 'rxjs'; import { SimulatedRegionPopupComponent } from '../shared/simulated-region-popup/simulated-region-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; +import type { OpenPopupOptions } from '../utility/popup-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class SimulatedRegionFeatureManager extends MoveableFeatureManager implements FeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleSimulatedRegions), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + mapInteractionsManager.addTrainerInteraction( + new ResizeRectangleInteraction(this.layer.getSource()!) + ); + } constructor( olMap: OlMap, - layer: VectorLayer>, private readonly exerciseService: ExerciseService, private readonly store: Store ) { super( olMap, - layer, (targetPositions, simulatedRegion) => { exerciseService.proposeAction({ type: '[SimulatedRegion] Move simulated region', @@ -104,9 +124,9 @@ export class SimulatedRegionFeatureManager } public override onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnSimulatedRegion = this.getElementFromFeature( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index 19dece1da..313ef2a29 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -1,3 +1,5 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { MapBrowserEvent } from 'ol'; import { Feature } from 'ol'; import LineString from 'ol/geom/LineString'; @@ -6,17 +8,32 @@ import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { TransferLine } from 'src/app/shared/types/transfer-line'; +import type { AppState } from 'src/app/state/app.state'; +import { selectTransferLines } from 'src/app/state/application/selectors/exercise.selectors'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type OlMap from 'ol/Map'; +import type { TransferLinesService } from '../../core/transfer-lines.service'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ElementManager } from './element-manager'; export class TransferLinesFeatureManager extends ElementManager implements FeatureManager { - constructor(public readonly layer: VectorLayer>) { + public readonly layer: VectorLayer>; + constructor( + private readonly store: Store, + private readonly transferLinesService: TransferLinesService, + private readonly olMap: OlMap + ) { super(); - layer.setStyle( + this.layer = this.createElementLayer(); + this.layer.setStyle( new Style({ stroke: new Stroke({ color: '#fd7e14', @@ -26,6 +43,33 @@ export class TransferLinesFeatureManager }) ); } + togglePopup$?: Subject>> | undefined; + register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + this.olMap.addLayer(this.layer); + mapInteractionsManager.addFeatureLayer(this.layer); + this.togglePopup$?.subscribe(changePopup$); + if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { + this.registerChangeHandlers( + this.store.select(selectTransferLines), + destroy$, + ngZone, + (element) => this.onElementCreated(element), + (element) => this.onElementDeleted(element), + (oldElement, newElement) => + this.onElementChanged(oldElement, newElement) + ); + this.transferLinesService.displayTransferLines$.subscribe( + (display) => { + this.layer.setVisible(display); + } + ); + } + } createFeature(element: TransferLine): Feature { const feature = new Feature( @@ -71,9 +115,9 @@ export class TransferLinesFeatureManager ) {} onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { return false; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 686b30eee..251882e74 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -1,20 +1,25 @@ +import type { NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; import { TransferPoint, TransferStartPoint } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleTransferPoints, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ChooseTransferTargetPopupComponent } from '../shared/choose-transfer-target-popup/choose-transfer-target-popup.component'; import { TransferPointPopupComponent } from '../shared/transfer-point-popup/transfer-point-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; @@ -24,13 +29,11 @@ export class TransferPointFeatureManager extends MoveableFeatureManager>, private readonly store: Store, private readonly exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, transferPoint) => { exerciseService.proposeAction({ type: '[TransferPoint] Move TransferPoint', @@ -38,9 +41,10 @@ export class TransferPointFeatureManager extends MoveableFeatureManager [ + this.layer.setStyle((thisFeature, currentZoom) => [ this.imageStyleHelper.getStyle( thisFeature as Feature, currentZoom @@ -52,6 +56,21 @@ export class TransferPointFeatureManager extends MoveableFeatureManager | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) { + super.registerFeatureElementManager( + this.store.select(selectVisibleTransferPoints), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } + private readonly imageStyleHelper = new ImageStyleHelper( (feature: Feature) => ({ url: TransferPoint.image.url, @@ -70,9 +89,9 @@ export class TransferPointFeatureManager extends MoveableFeatureManager, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { // TODO: droppedElement isn't necessarily a transfer point -> fix getElementFromFeature typings const droppedElement = this.getElementFromFeature(droppedFeature); diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts index 04cd680a2..2f1e8284c 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts @@ -1,20 +1,39 @@ +import type { Type, NgZone } from '@angular/core'; +import type { Store } from '@ngrx/store'; import type { UUID, Vehicle } from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; import type { TranslateEvent } from 'ol/interaction/Translate'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; +import type { AppState } from 'src/app/state/app.state'; +import { selectVisibleVehicles } from 'src/app/state/application/selectors/shared.selectors'; import { VehiclePopupComponent } from '../shared/vehicle-popup/vehicle-popup.component'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PointGeometryHelper } from '../utility/point-geometry-helper'; import { ImagePopupHelper } from '../utility/popup-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ImageStyleHelper } from '../utility/style-helper/image-style-helper'; import { NameStyleHelper } from '../utility/style-helper/name-style-helper'; import { MoveableFeatureManager } from './moveable-feature-manager'; export class VehicleFeatureManager extends MoveableFeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleVehicles), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + } private readonly imageStyleHelper = new ImageStyleHelper( (feature) => (this.getElementFromFeature(feature) as Vehicle).image ); @@ -33,12 +52,11 @@ export class VehicleFeatureManager extends MoveableFeatureManager { constructor( olMap: OlMap, - layer: VectorLayer>, + private readonly store: Store, private readonly exerciseService: ExerciseService ) { super( olMap, - layer, (targetPosition, vehicle) => { exerciseService.proposeAction({ type: '[Vehicle] Move vehicle', @@ -46,7 +64,8 @@ export class VehicleFeatureManager extends MoveableFeatureManager { targetPosition, }); }, - new PointGeometryHelper() + new PointGeometryHelper(), + 1000 ); this.layer.setStyle((feature, resolution) => [ this.nameStyleHelper.getStyle(feature as Feature, resolution), @@ -55,9 +74,9 @@ export class VehicleFeatureManager extends MoveableFeatureManager { } public override onFeatureDrop( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) { const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnVehicle = this.getElementFromFeature( diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts index 15807372f..5e41c5af1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/viewport-feature-manager.ts @@ -1,22 +1,27 @@ +import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; import type { UUID } from 'digital-fuesim-manv-shared'; import { MapCoordinates, Size, Viewport } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { Coordinate } from 'ol/coordinate'; import type { Polygon } from 'ol/geom'; -import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; -import type VectorSource from 'ol/source/Vector'; import Stroke from 'ol/style/Stroke'; import Style from 'ol/style/Style'; +import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import { + selectCurrentRole, + selectVisibleViewports, +} from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import { ViewportPopupComponent } from '../shared/viewport-popup/viewport-popup.component'; import { calculatePopupPositioning } from '../utility/calculate-popup-positioning'; import type { FeatureManager } from '../utility/feature-manager'; +import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import { PolygonGeometryHelper } from '../utility/polygon-geometry-helper'; +import type { OpenPopupOptions } from '../utility/popup-manager'; import { ResizeRectangleInteraction } from '../utility/resize-rectangle-interaction'; import { MoveableFeatureManager } from './moveable-feature-manager'; @@ -34,15 +39,30 @@ export class ViewportFeatureManager extends MoveableFeatureManager implements FeatureManager { + public register( + changePopup$: Subject> | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ): void { + super.registerFeatureElementManager( + this.store.select(selectVisibleViewports), + changePopup$, + destroy$, + ngZone, + mapInteractionsManager + ); + mapInteractionsManager.addTrainerInteraction( + new ResizeRectangleInteraction(this.layer.getSource()!) + ); + } constructor( olMap: OlMap, - layer: VectorLayer>, private readonly exerciseService: ExerciseService, private readonly store: Store ) { super( olMap, - layer, (targetPositions, viewport) => { exerciseService.proposeAction({ type: '[Viewport] Move viewport', diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts index 463e3e83d..0f225b23e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts @@ -1,9 +1,11 @@ +import type { NgZone } from '@angular/core'; import type { Feature, MapBrowserEvent } from 'ol'; import type { Geometry } from 'ol/geom'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; import type { Subject } from 'rxjs'; +import type { OlMapInteractionsManager } from './ol-map-interactions-manager'; import type { OpenPopupOptions } from './popup-manager'; /** @@ -39,8 +41,15 @@ export interface FeatureManager { * @returns wether the event should not propagate further (to the features behind {@link droppedOnFeature}). */ onFeatureDrop: ( - dropEvent: TranslateEvent, droppedFeature: Feature, - droppedOnFeature: Feature + droppedOnFeature: Feature, + dropEvent?: TranslateEvent ) => boolean; + + register: ( + changePopup$: Subject | undefined>, + destroy$: Subject, + ngZone: NgZone, + mapInteractionsManager: OlMapInteractionsManager + ) => void; } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts new file mode 100644 index 000000000..f5b004bd7 --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts @@ -0,0 +1,177 @@ +import type VectorLayer from 'ol/layer/Vector'; +import type VectorSource from 'ol/source/Vector'; +import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; +import type { Interaction } from 'ol/interaction'; +import { defaults as defaultInteractions } from 'ol/interaction'; +import type { Subject } from 'rxjs'; +import { combineLatest, takeUntil } from 'rxjs'; +import { selectExerciseStatus } from 'src/app/state/application/selectors/exercise.selectors'; +import type { Feature } from 'ol'; +import { Collection } from 'ol'; +import type OlMap from 'ol/Map'; +import type { AppState } from 'src/app/state/app.state'; +import type { Store } from '@ngrx/store'; +import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { ExerciseStatus, Role } from 'digital-fuesim-manv-shared'; +import type { TranslateEvent } from 'ol/interaction/Translate'; +import type { Pixel } from 'ol/pixel'; +import { TranslateInteraction } from './translate-interaction'; +import type { PopupManager } from './popup-manager'; +import type { FeatureManager } from './feature-manager'; + +export class OlMapInteractionsManager { + private readonly featureLayers: VectorLayer[] = []; + private readonly trainerInteractions: Interaction[] = []; + private translateInteraction: TranslateInteraction = + new TranslateInteraction(); + private participantInteractions: Interaction[] = []; + private interactions: Collection = + new Collection(); + private lastStatus: ExerciseStatus | undefined; + private lastRole: Role | 'timeTravel' | undefined; + + constructor( + private readonly mapInteractions: Collection, + private readonly store: Store, + private readonly popupManager: PopupManager, + private readonly olMap: OlMap, + private readonly layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + >, + private readonly destroy$: Subject + ) { + this.updateInteractions(); + this.registerInteractionEnablementHandler(); + } + + public addFeatureLayer(layer: VectorLayer) { + this.featureLayers.push(layer); + this.syncInteractionsAndHandler(); + } + + public addTrainerInteraction(interaction: Interaction) { + this.trainerInteractions.push(interaction); + this.syncInteractionsAndHandler(); + } + + private syncInteractionsAndHandler() { + this.updateInteractions(); + this.registerDropHandler(); + this.applyInteractions(); + this.updateInteractionEnablement(this.lastStatus, this.lastRole); + } + + private updateTranslateInteraction() { + this.translateInteraction = new TranslateInteraction({ + layers: this.featureLayers, + hitTolerance: 10, + filter: (feature, layer) => { + const featureManager = this.layerFeatureManagerDictionary.get( + layer as VectorLayer + ); + return featureManager === undefined + ? false + : featureManager.isFeatureTranslatable(feature); + }, + }); + } + + private updateParticipantInteractions() { + this.participantInteractions = [this.translateInteraction]; + } + + private updateInteractions() { + this.updateTranslateInteraction(); + this.updateParticipantInteractions(); + this.interactions = defaultInteractions({ + pinchRotate: false, + altShiftDragRotate: false, + keyboard: true, + }).extend( + selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' + ? [...this.participantInteractions, ...this.trainerInteractions] + : [...this.participantInteractions] + ); + } + + private applyInteractions() { + this.mapInteractions.clear(); + // We just want to modify this for the Map not do anything with it after so we ignore the returned value + // eslint-disable-next-line rxjs/no-ignored-observable + this.mapInteractions.extend(this.interactions.getArray()); + } + + // Register handlers that disable or enable certain interactions + private registerInteractionEnablementHandler() { + combineLatest([ + this.store.select(selectExerciseStatus), + this.store.select(selectCurrentRole), + ]) + .pipe(takeUntil(this.destroy$)) + .subscribe(([status, currentRole]) => { + this.updateInteractionEnablement(status, currentRole); + }); + } + + // this shows a paused overlay and disables interactions for participants when the exercise is paused + private updateInteractionEnablement( + status: ExerciseStatus | undefined, + currentRole: Role | 'timeTravel' | undefined + ) { + this.lastRole = currentRole; + this.lastStatus = status; + const isPausedAndParticipant = + status !== 'running' && currentRole === 'participant'; + const areInteractionsActive = + !isPausedAndParticipant && currentRole !== 'timeTravel'; + this.participantInteractions.forEach((interaction) => { + interaction.setActive(areInteractionsActive); + }); + this.popupManager.setPopupsEnabled(!isPausedAndParticipant); + this.getOlViewportElement().style.filter = isPausedAndParticipant + ? 'brightness(50%)' + : ''; + } + + private registerDropHandler() { + this.translateInteraction.on('translateend', (event) => { + const pixel = this.olMap.getPixelFromCoordinate(event.coordinate); + const droppedFeature: Feature = event.features.getArray()[0]!; + this.handleTranslateEnd(pixel, droppedFeature, event); + }); + } + + private handleTranslateEnd( + pixel: Pixel, + droppedFeature: Feature, + event: TranslateEvent + ) { + this.olMap.forEachFeatureAtPixel(pixel, (droppedOnFeature, layer) => { + // Skip layer when unset + if (layer === null) { + return; + } + + // Do not drop a feature on itself + if (droppedFeature === droppedOnFeature) { + return; + } + + // We stop propagating the event as soon as the onFeatureDropped function returns true + return this.layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureDrop( + droppedFeature, + droppedOnFeature as Feature, + event + ); + }); + } + + public getOlViewportElement(): HTMLElement { + return this.olMap + .getTargetElement() + .querySelectorAll('.ol-viewport')[0] as HTMLElement; + } +} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index c42adc7be..81ce4296d 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -1,57 +1,27 @@ import type { NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { - ImmutableJsonObject, - MergeIntersection, - UUID, -} from 'digital-fuesim-manv-shared'; import { upperLeftCornerOf, lowerRightCornerOf, } from 'digital-fuesim-manv-shared'; -import type { Feature } from 'ol'; -import { Overlay, View } from 'ol'; -import type { Polygon } from 'ol/geom'; -import type Geometry from 'ol/geom/Geometry'; -import type LineString from 'ol/geom/LineString'; -import type Point from 'ol/geom/Point'; -import { defaults as defaultInteractions } from 'ol/interaction'; -import TileLayer from 'ol/layer/Tile'; -import VectorLayer from 'ol/layer/Vector'; +import { Collection, View } from 'ol'; +import type { Interaction } from 'ol/interaction'; +import type VectorLayer from 'ol/layer/Vector'; import OlMap from 'ol/Map'; -import VectorSource from 'ol/source/Vector'; -import XYZ from 'ol/source/XYZ'; -import type { Observable } from 'rxjs'; -import { combineLatest, pairwise, startWith, Subject, takeUntil } from 'rxjs'; +import type VectorSource from 'ol/source/Vector'; +import { Subject, takeUntil } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; -import { handleChanges } from 'src/app/shared/functions/handle-changes'; import type { AppState } from 'src/app/state/app.state'; import { - selectExerciseStatus, selectSimulatedRegion, - selectTileMapProperties, - selectTransferLines, selectViewports, } from 'src/app/state/application/selectors/exercise.selectors'; -import { - selectCurrentRole, - selectRestrictedViewport, - selectVisibleCateringLines, - selectVisibleMapImages, - selectVisibleMaterials, - selectVisiblePatients, - selectVisiblePersonnel, - selectVisibleSimulatedRegions, - selectVisibleTransferPoints, - selectVisibleVehicles, - selectVisibleViewports, -} from 'src/app/state/application/selectors/shared.selectors'; +import { selectRestrictedViewport } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type { TransferLinesService } from '../../core/transfer-lines.service'; import { startingPosition } from '../../starting-position'; import { CateringLinesFeatureManager } from '../feature-managers/catering-lines-feature-manager'; import { DeleteFeatureManager } from '../feature-managers/delete-feature-manager'; -import type { ElementManager } from '../feature-managers/element-manager'; import { MapImageFeatureManager } from '../feature-managers/map-images-feature-manager'; import { MaterialFeatureManager } from '../feature-managers/material-feature-manager'; import { PatientFeatureManager } from '../feature-managers/patient-feature-manager'; @@ -65,26 +35,21 @@ import { ViewportFeatureManager, } from '../feature-managers/viewport-feature-manager'; import type { FeatureManager } from './feature-manager'; -import type { OpenPopupOptions } from './popup-manager'; -import { ResizeRectangleInteraction } from './resize-rectangle-interaction'; -import { TranslateInteraction } from './translate-interaction'; +import type { PopupManager } from './popup-manager'; +import { OlMapInteractionsManager } from './ol-map-interactions-manager'; +import { SatelliteLayerManager } from './satellite-layer-manager'; /** * This class should run outside the Angular zone for performance reasons. */ + export class OlMapManager { + private readonly _olMap: OlMap; + private featureManagers: FeatureManager[]; + private readonly mapInteractionsManager: OlMapInteractionsManager; + private static readonly defaultZoom = 20; private readonly destroy$ = new Subject(); - public readonly olMap: OlMap; - /** - * If this subject emits options, the specified popup should be toggled. - * If it emits undefined, the currently open popup should be closed. - */ - public readonly changePopup$ = new Subject< - OpenPopupOptions | undefined - >(); - - public readonly popupOverlay: Overlay; /** * key: the layer that is passed to the featureManager, that is saved in the value * ```ts @@ -98,105 +63,23 @@ export class OlMapManager { FeatureManager >(); - private static readonly defaultZoom = 20; - constructor( private readonly store: Store, private readonly exerciseService: ExerciseService, private readonly openLayersContainer: HTMLDivElement, - private readonly popoverContainer: HTMLDivElement, private readonly ngZone: NgZone, - transferLinesService: TransferLinesService + private readonly transferLinesService: TransferLinesService, + private readonly popupManager: PopupManager ) { - // Layers - const satelliteLayer = new TileLayer({ - preload: Number.POSITIVE_INFINITY, - }); - this.store - .select(selectTileMapProperties) - .pipe(takeUntil(this.destroy$)) - .subscribe((tileMapProperties) => { - satelliteLayer.setSource( - new XYZ({ - url: tileMapProperties.tileUrl, - maxZoom: tileMapProperties.maxZoom, - // We want to keep the tiles cached if we are zooming in and out fast - cacheSize: 1000, - }) - ); - }); - const transferPointLayer = this.createElementLayer(600); - const vehicleLayer = this.createElementLayer(1000); - const cateringLinesLayer = this.createElementLayer(); - const transferLinesLayer = this.createElementLayer(); - const patientLayer = this.createElementLayer(); - const personnelLayer = this.createElementLayer(); - const materialLayer = this.createElementLayer(); - const viewportLayer = this.createElementLayer(); - const simulatedRegionLayer = this.createElementLayer(); - const mapImagesLayer = this.createElementLayer(10_000); - const deleteFeatureLayer = this.createElementLayer(); - this.popupOverlay = new Overlay({ - element: this.popoverContainer, - }); - - // The order in this array represents the order of the layers on the map (last element is on top) - const featureLayers = [ - deleteFeatureLayer, - simulatedRegionLayer, - mapImagesLayer, - transferLinesLayer, - transferPointLayer, - vehicleLayer, - cateringLinesLayer, - patientLayer, - personnelLayer, - materialLayer, - viewportLayer, - ]; - - // Interactions - const translateInteraction = new TranslateInteraction({ - layers: featureLayers, - hitTolerance: 10, - filter: (feature, layer) => { - const featureManager = this.layerFeatureManagerDictionary.get( - layer as VectorLayer - ); - return featureManager === undefined - ? false - : featureManager.isFeatureTranslatable(feature); - }, - }); - const resizeViewportInteraction = new ResizeRectangleInteraction( - viewportLayer.getSource()! - ); - const resizeSimulatedRegionInteraction = new ResizeRectangleInteraction( - simulatedRegionLayer.getSource()! - ); - const alwaysInteractions = [translateInteraction]; - const customInteractions = - selectStateSnapshot(selectCurrentRole, this.store) === 'trainer' - ? [ - ...alwaysInteractions, - resizeViewportInteraction, - resizeSimulatedRegionInteraction, - ] - : alwaysInteractions; - - this.olMap = new OlMap({ - interactions: defaultInteractions({ - pinchRotate: false, - altShiftDragRotate: false, - keyboard: true, - }).extend(customInteractions), + this._olMap = new OlMap({ + interactions: new Collection(), // We use Angular buttons instead controls: [], target: this.openLayersContainer, // Note: The order of this array determines the order of the objects on the map. // The most bottom objects must be at the top of the array. - layers: [satelliteLayer, ...featureLayers], - overlays: [this.popupOverlay], + layers: [], + overlays: [this.popupManager.popupOverlay], view: new View({ center: [startingPosition.x, startingPosition.y], zoom: OlMapManager.defaultZoom, @@ -207,141 +90,40 @@ export class OlMapManager { }), }); - // FeatureManagers - if (selectStateSnapshot(selectCurrentRole, this.store) === 'trainer') { - this.registerFeatureElementManager( - new TransferLinesFeatureManager(transferLinesLayer), - this.store.select(selectTransferLines) - ); - transferLinesService.displayTransferLines$.subscribe((display) => { - transferLinesLayer.setVisible(display); - }); - - const deleteHelper = new DeleteFeatureManager( - this.store, - deleteFeatureLayer, - this.olMap, - this.exerciseService - ); - this.layerFeatureManagerDictionary.set( - deleteFeatureLayer, - deleteHelper - ); - } - this.registerFeatureElementManager( - new TransferPointFeatureManager( - this.olMap, - transferPointLayer, - this.store, - this.exerciseService - ), - this.store.select(selectVisibleTransferPoints) - ); - - this.registerFeatureElementManager( - new PatientFeatureManager( - this.store, - this.olMap, - patientLayer, - this.exerciseService - ), - this.store.select(selectVisiblePatients) - ); - - this.registerFeatureElementManager( - new VehicleFeatureManager( - this.olMap, - vehicleLayer, - this.exerciseService - ), - this.store.select(selectVisibleVehicles) - ); - - this.registerFeatureElementManager( - new PersonnelFeatureManager( - this.olMap, - personnelLayer, - this.exerciseService - ), - this.store.select(selectVisiblePersonnel) - ); - - this.registerFeatureElementManager( - new MaterialFeatureManager( - this.olMap, - materialLayer, - this.exerciseService - ), - this.store.select(selectVisibleMaterials) - ); + this.featureManagers = []; + this.initializeFeatureManagers(); - this.registerFeatureElementManager( - new MapImageFeatureManager( - this.olMap, - mapImagesLayer, - this.exerciseService, - this.store - ), - this.store.select(selectVisibleMapImages) + this.mapInteractionsManager = new OlMapInteractionsManager( + this.olMap.getInteractions(), + store, + popupManager, + this.olMap, + this.layerFeatureManagerDictionary, + this.destroy$ ); - this.registerFeatureElementManager( - new CateringLinesFeatureManager(cateringLinesLayer), - this.store.select(selectVisibleCateringLines) + const satelliteLayerManager = new SatelliteLayerManager( + store, + this.destroy$ ); - this.registerFeatureElementManager( - new ViewportFeatureManager( - this.olMap, - viewportLayer, - this.exerciseService, - this.store - ), - this.store.select(selectVisibleViewports) - ); + this.olMap.getLayers().clear(); + this.olMap.addLayer(satelliteLayerManager.satelliteLayer); - this.registerFeatureElementManager( - new SimulatedRegionFeatureManager( - this.olMap, - simulatedRegionLayer, - this.exerciseService, - this.store - ), - this.store.select(selectVisibleSimulatedRegions) - ); + // the mapInteractionsManager needs to be set and the satelliteLayer needs to be added before this is possible + this.registerFeatureManagers(); - this.registerPopupTriggers(); - this.registerDropHandler(translateInteraction); this.registerViewportRestriction(); - // Register handlers that disable or enable certain interactions - combineLatest([ - this.store.select(selectExerciseStatus), - this.store.select(selectCurrentRole), - ]) - .pipe(takeUntil(this.destroy$)) - .subscribe(([status, currentRole]) => { - const showPausedOverlay = - status !== 'running' && currentRole === 'participant'; - customInteractions.forEach((interaction) => { - interaction.setActive( - !showPausedOverlay && currentRole !== 'timeTravel' - ); - }); - this.setPopupsEnabled(!showPausedOverlay); - this.getOlViewportElement().style.filter = showPausedOverlay - ? 'brightness(50%)' - : ''; - }); + popupManager.registerPopupTriggers( + this.olMap, + openLayersContainer, + this.layerFeatureManagerDictionary + ); } - private popupsEnabled = true; - private setPopupsEnabled(enabled: boolean) { - this.popupsEnabled = enabled; - if (!enabled) { - // Close all open popups - this.changePopup$.next(undefined); - } + public get olMap(): OlMap { + return this._olMap; } private registerViewportRestriction() { @@ -382,125 +164,6 @@ export class OlMapManager { }); } - private registerFeatureElementManager< - Element extends ImmutableJsonObject, - T extends MergeIntersection< - ElementManager & FeatureManager - > - >( - featureManager: T, - elementDictionary$: Observable<{ [id: UUID]: Element }> - ) { - this.layerFeatureManagerDictionary.set( - featureManager.layer, - featureManager - ); - featureManager.togglePopup$?.subscribe(this.changePopup$); - // Propagate the changes on an element to the featureManager - elementDictionary$ - .pipe(startWith({}), pairwise(), takeUntil(this.destroy$)) - .subscribe(([oldElementDictionary, newElementDictionary]) => { - // run outside angular zone for better performance - this.ngZone.runOutsideAngular(() => { - handleChanges(oldElementDictionary, newElementDictionary, { - createHandler: (element) => - featureManager.onElementCreated(element), - deleteHandler: (element) => - featureManager.onElementDeleted(element), - changeHandler: (oldElement, newElement) => - featureManager.onElementChanged( - oldElement, - newElement - ), - }); - }); - }); - } - - private registerPopupTriggers() { - this.olMap.on('singleclick', (event) => { - if (!this.popupsEnabled) { - return; - } - this.olMap.forEachFeatureAtPixel( - event.pixel, - (feature, layer) => { - // Skip layer when unset - if (layer === null) { - return false; - } - this.layerFeatureManagerDictionary - .get(layer as VectorLayer)! - .onFeatureClicked(event, feature as Feature); - // we only want the top one -> a truthy return breaks this loop - return true; - }, - { hitTolerance: 10 } - ); - if (!this.olMap!.hasFeatureAtPixel(event.pixel)) { - this.changePopup$.next(undefined); - } - }); - - this.openLayersContainer.addEventListener('keydown', (event) => { - if ((event as KeyboardEvent).key === 'Escape') { - this.changePopup$.next(undefined); - } - }); - } - - private registerDropHandler(translateInteraction: TranslateInteraction) { - translateInteraction.on('translateend', (event) => { - const pixel = this.olMap.getPixelFromCoordinate(event.coordinate); - const droppedFeature: Feature = event.features.getArray()[0]!; - - this.olMap.forEachFeatureAtPixel( - pixel, - (droppedOnFeature, layer) => { - // Skip layer when unset - if (layer === null) { - return; - } - - // Do not drop a feature on itself - if (droppedFeature === droppedOnFeature) { - return; - } - - // We stop propagating the event as soon as the onFeatureDropped function returns true - return this.layerFeatureManagerDictionary - .get(layer as VectorLayer)! - .onFeatureDrop( - event, - droppedFeature, - droppedOnFeature as Feature - ); - } - ); - }); - } - - /** - * @param renderBuffer The size of the largest symbol, line width or label on the highest zoom level. - */ - private createElementLayer( - renderBuffer = 250 - ) { - return new VectorLayer({ - // These two settings prevent clipping during animation/interaction but cause a performance hit -> disable if needed - updateWhileAnimating: true, - updateWhileInteracting: true, - renderBuffer, - source: new VectorSource(), - }); - } - - private getOlViewportElement(): HTMLElement { - return this.olMap - .getTargetElement() - .querySelectorAll('.ol-viewport')[0] as HTMLElement; - } - /** * Sets the map's view to see all viewports and simulated regions. */ @@ -556,4 +219,97 @@ export class OlMapManager { this.olMap.dispose(); this.olMap.setTarget(undefined); } + + // This lets featureManagers register themselves and adds them to the layerFeatureManagerDictionary + + private registerFeatureManagers() { + this.featureManagers.forEach((featureManager) => { + this.layerFeatureManagerDictionary.set( + featureManager.layer, + featureManager + ); + featureManager.register( + this.popupManager.changePopup$, + this.destroy$, + this.ngZone, + this.mapInteractionsManager + ); + }); + } + + private initializeFeatureManagers() { + const transferLinesFeatureManager = new TransferLinesFeatureManager( + this.store, + this.transferLinesService, + this.olMap + ); + const transferPointFeatureManager = new TransferPointFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const patientFeatureManager = new PatientFeatureManager( + this.store, + this.olMap, + this.exerciseService + ); + const vehicleFeatureManager = new VehicleFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const personnelFeatureManager = new PersonnelFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const materialFeatureManager = new MaterialFeatureManager( + this.olMap, + this.store, + this.exerciseService + ); + const mapImageFeatureManager = new MapImageFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + const cateringLinesFeatureManager = new CateringLinesFeatureManager( + this.store, + this.olMap + ); + + const viewportFeatureManager = new ViewportFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + const simulatedRegionFeatureManager = new SimulatedRegionFeatureManager( + this.olMap, + this.exerciseService, + this.store + ); + + const deleteFeatureManager = new DeleteFeatureManager( + this.store, + this.olMap, + this.exerciseService + ); + + // Register the Feature Managers in the correct Order + // The order represents the order of the layers on the map (last element is on top) + + this.featureManagers = [ + deleteFeatureManager, + simulatedRegionFeatureManager, + mapImageFeatureManager, + transferLinesFeatureManager, + transferPointFeatureManager, + vehicleFeatureManager, + cateringLinesFeatureManager, + patientFeatureManager, + personnelFeatureManager, + materialFeatureManager, + viewportFeatureManager, + ]; + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts index d2d87e97a..4aa9af2c9 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/popup-manager.ts @@ -5,22 +5,87 @@ import type { ViewContainerRef, } from '@angular/core'; import { isEqual } from 'lodash-es'; -import type { Overlay } from 'ol'; +import type { Feature } from 'ol'; +import { Overlay } from 'ol'; +import type VectorLayer from 'ol/layer/Vector'; +import type VectorSource from 'ol/source/Vector'; import { Subject, takeUntil } from 'rxjs'; +import type OlMap from 'ol/Map'; import type { Positioning } from '../../utility/types/positioning'; +import type { FeatureManager } from './feature-manager'; /** * A class that manages the creation and destruction of a single popup with freely customizable content * that should appear on the {@link popupOverlay}. */ export class PopupManager { + /** + * If this subject emits options, the specified popup should be toggled. + * If it emits undefined, the currently open popup should be closed. + */ + public readonly changePopup$ = new Subject< + OpenPopupOptions | undefined + >(); + + public readonly popupOverlay: Overlay; private readonly destroy$ = new Subject(); private currentlyOpenPopupOptions?: OpenPopupOptions; + private popupsEnabled = true; constructor( - private readonly popupOverlay: Overlay, - private readonly popoverContent: ViewContainerRef - ) {} + private readonly popoverContent: ViewContainerRef, + private readonly popoverContainer: HTMLDivElement + ) { + this.popupOverlay = new Overlay({ + element: this.popoverContainer, + }); + } + public setPopupsEnabled(enabled: boolean) { + this.popupsEnabled = enabled; + if (!enabled) { + // Close all open popups + this.changePopup$.next(undefined); + } + } + + public registerPopupTriggers( + olMap: OlMap, + openLayersContainer: HTMLDivElement, + layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + > + ) { + olMap.on('singleclick', (event) => { + if (!this.popupsEnabled) { + return; + } + const hasBeenHandled = olMap.forEachFeatureAtPixel( + event.pixel, + (feature, layer) => { + // Skip layer when unset + if (layer === null) { + return false; + } + layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureClicked(event, feature as Feature); + // we only want the top one -> a truthy return breaks this loop + return true; + }, + { hitTolerance: 10 } + ); + if (!hasBeenHandled) { + this.changePopup$.next(undefined); + } + }); + + openLayersContainer.addEventListener('keydown', (event) => { + if ((event as KeyboardEvent).key === 'Escape') { + this.changePopup$.next(undefined); + } + }); + } /** * Toggles the popup with the given options. diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts new file mode 100644 index 000000000..8ae8a9f3e --- /dev/null +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/satellite-layer-manager.ts @@ -0,0 +1,36 @@ +import type { Store } from '@ngrx/store'; +import TileLayer from 'ol/layer/Tile'; +import XYZ from 'ol/source/XYZ'; +import { takeUntil } from 'rxjs'; +import type { AppState } from 'src/app/state/app.state'; +import { selectTileMapProperties } from 'src/app/state/application/selectors/exercise.selectors'; + +export class SatelliteLayerManager { + private readonly _satelliteLayer: TileLayer; + + public get satelliteLayer(): TileLayer { + return this._satelliteLayer; + } + + constructor( + private readonly store: Store, + private readonly destroy$: any + ) { + this._satelliteLayer = new TileLayer({ + preload: Number.POSITIVE_INFINITY, + }); + this.store + .select(selectTileMapProperties) + .pipe(takeUntil(this.destroy$)) + .subscribe((tileMapProperties) => { + this._satelliteLayer.setSource( + new XYZ({ + url: tileMapProperties.tileUrl, + maxZoom: tileMapProperties.maxZoom, + // We want to keep the tiles cached if we are zooming in and out fast + cacheSize: 1000, + }) + ); + }); + } +} From cbcc1fd4b59304d214f5e8e739dcad6c52129552 Mon Sep 17 00:00:00 2001 From: Lukas Radermacher <49586507+lukasrad02@users.noreply.github.com> Date: Wed, 15 Feb 2023 18:45:05 +0100 Subject: [PATCH 34/58] Adjust nginx configuration for about pages (#657) * Adjust nginx configuration for about pages * Redirect invalid requests for a uniform 404 page * Add link to landing page on about pages * Improve error pages in nginx setup The error pages do not rely on a non-existing URL any longer --------- Co-authored-by: Marvin <68286419+anonym-HPI@users.noreply.github.com> --- docker/nginx/locations | 17 ++++++++++++----- .../about-placeholder.component.html | 3 ++- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/docker/nginx/locations b/docker/nginx/locations index e041da004..609378103 100644 --- a/docker/nginx/locations +++ b/docker/nginx/locations @@ -1,12 +1,19 @@ # Frontend + root /usr/local/app/frontend/dist/digital-fuesim-manv; + error_page 404 /index.html; + error_page 403 /index.html; + + location /assets/about { + # Requests to this location should not fall back to index.html + } + location / { - alias /usr/local/app/frontend/dist/digital-fuesim-manv/; try_files $uri $uri/ /index.html; } # API location /api { - proxy_pass http://localhost:3201; + proxy_pass http://localhost:3201; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; @@ -14,10 +21,10 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; include conf.d/upload-limit; - } + } # Websocket - location /socket.io { + location /socket.io { proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_pass http://localhost:3200; @@ -28,4 +35,4 @@ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; include conf.d/upload-limit; - } + } diff --git a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html index edcc44e1c..6d37bf282 100644 --- a/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html +++ b/frontend/src/app/pages/about/about-placeholder/about-placeholder.component.html @@ -3,7 +3,8 @@

    Digitale FüSim MANV

    {{ pageTitle }}

    - Zurück zur vorherigen Seite + Zurück zur vorherigen Seite | + Zur Startseite

    Date: Thu, 16 Feb 2023 12:22:24 +0100 Subject: [PATCH 35/58] Set up simulation framework (#664) * Create draft for simulation data types * WIP: Simulate unloading of vehicles * WIP add debug helpers and make simulation work * WIP add typings and lint * Validate events * Fix never parameter in activity and behavior functions * Validate activities and behaviors * Introduce pseudo randomness for deterministic uuids * Add migrations for simulation * Rename SimulationActivity.terminate to onTerminate * Remove simulatedRegionId from VehicleArrivedEvent * Slight improvement to debugging buttons * Fix typo * Validate state in AddBehaviorAction * Incorporate suggestions from review * Fix randomness * Add generic DelayEventActivity * Fix DelayEventActivity * Please linter * Remove debug UI --- shared/package-lock.json | 18 +++- shared/package.json | 1 + shared/src/index.ts | 1 + shared/src/models/simulated-region.ts | 22 ++++- shared/src/models/vehicle.ts | 10 +- .../src/simulation/activities/delay-event.ts | 48 +++++++++ .../exercise-simulation-activity.ts | 48 +++++++++ shared/src/simulation/activities/index.ts | 2 + .../activities/simulation-activity.ts | 24 +++++ .../simulation/activities/unload-vehicle.ts | 74 ++++++++++++++ .../behaviors/exercise-simulation-behavior.ts | 40 ++++++++ shared/src/simulation/behaviors/index.ts | 2 + .../behaviors/simulation-behavior.ts | 19 ++++ .../behaviors/unload-arrived-vehicles.ts | 52 ++++++++++ .../events/exercise-simulation-event.ts | 37 +++++++ shared/src/simulation/events/index.ts | 3 + .../src/simulation/events/simulation-event.ts | 3 + shared/src/simulation/events/tick.ts | 22 +++++ .../src/simulation/events/vehicle-arrived.ts | 27 ++++++ shared/src/simulation/index.ts | 4 + shared/src/simulation/utils/index.ts | 3 + shared/src/simulation/utils/randomness.ts | 77 +++++++++++++++ .../src/simulation/utils/simulated-region.ts | 97 +++++++++++++++++++ shared/src/simulation/utils/vehicle.ts | 40 ++++++++ .../20-add-simulation-properties.ts | 46 +++++++++ .../state-migrations/migration-functions.ts | 2 + shared/src/state.ts | 8 +- shared/src/store/action-reducers/exercise.ts | 3 + .../store/action-reducers/simulated-region.ts | 50 +++++++++- shared/src/utils/validators/is-id-map.ts | 46 ++++++--- 30 files changed, 810 insertions(+), 19 deletions(-) create mode 100644 shared/src/simulation/activities/delay-event.ts create mode 100644 shared/src/simulation/activities/exercise-simulation-activity.ts create mode 100644 shared/src/simulation/activities/index.ts create mode 100644 shared/src/simulation/activities/simulation-activity.ts create mode 100644 shared/src/simulation/activities/unload-vehicle.ts create mode 100644 shared/src/simulation/behaviors/exercise-simulation-behavior.ts create mode 100644 shared/src/simulation/behaviors/index.ts create mode 100644 shared/src/simulation/behaviors/simulation-behavior.ts create mode 100644 shared/src/simulation/behaviors/unload-arrived-vehicles.ts create mode 100644 shared/src/simulation/events/exercise-simulation-event.ts create mode 100644 shared/src/simulation/events/index.ts create mode 100644 shared/src/simulation/events/simulation-event.ts create mode 100644 shared/src/simulation/events/tick.ts create mode 100644 shared/src/simulation/events/vehicle-arrived.ts create mode 100644 shared/src/simulation/index.ts create mode 100644 shared/src/simulation/utils/index.ts create mode 100644 shared/src/simulation/utils/randomness.ts create mode 100644 shared/src/simulation/utils/simulated-region.ts create mode 100644 shared/src/simulation/utils/vehicle.ts create mode 100644 shared/src/state-migrations/20-add-simulation-properties.ts diff --git a/shared/package-lock.json b/shared/package-lock.json index 6e3253ab5..61469266e 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "hash.js": "^1.1.7", "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", @@ -3560,6 +3561,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -3665,8 +3675,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/internal-slot": { "version": "1.0.4", @@ -4822,6 +4831,11 @@ "node": ">=4" } }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", diff --git a/shared/package.json b/shared/package.json index b4cd1627b..d9bf5553a 100644 --- a/shared/package.json +++ b/shared/package.json @@ -27,6 +27,7 @@ "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "hash.js": "^1.1.7", "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", diff --git a/shared/src/index.ts b/shared/src/index.ts index 11985f979..dadb0e5f2 100644 --- a/shared/src/index.ts +++ b/shared/src/index.ts @@ -19,6 +19,7 @@ export * from './export-import/file-format'; export * from './models'; export * from './models/utils'; export * from './utils'; +export * from './simulation'; export * from './state'; export * from './store'; export * from './socket-api'; diff --git a/shared/src/models/simulated-region.ts b/shared/src/models/simulated-region.ts index 1e170c7f5..8dba7803d 100644 --- a/shared/src/models/simulated-region.ts +++ b/shared/src/models/simulated-region.ts @@ -2,7 +2,13 @@ import { Type } from 'class-transformer'; import { IsString, IsUUID, ValidateNested } from 'class-validator'; import { UUID, uuid, uuidValidationOptions } from '../utils'; import { IsPosition } from '../utils/validators/is-position'; -import { IsValue } from '../utils/validators'; +import { IsMultiTypedIdMap, IsValue } from '../utils/validators'; +import type { ExerciseSimulationEvent } from '../simulation'; +import { simulationEventTypeOptions } from '../simulation'; +import type { ExerciseSimulationActivityState } from '../simulation/activities'; +import { getSimulationActivityConstructor } from '../simulation/activities'; +import type { ExerciseSimulationBehaviorState } from '../simulation/behaviors'; +import { simulationBehaviorTypeOptions } from '../simulation/behaviors'; import { getCreate, isInSimulatedRegion, @@ -47,6 +53,20 @@ export class SimulatedRegion { this.name = name; } + @Type(...simulationEventTypeOptions) + @ValidateNested() + public readonly inEvents: readonly ExerciseSimulationEvent[] = []; + + @Type(...simulationBehaviorTypeOptions) + @ValidateNested() + public readonly behaviors: readonly ExerciseSimulationBehaviorState[] = []; + + @IsMultiTypedIdMap(getSimulationActivityConstructor) + @ValidateNested() + public readonly activities: { + readonly [stateId: UUID]: ExerciseSimulationActivityState; + } = {}; + static readonly create = getCreate(this); static image: ImageProperties = { diff --git a/shared/src/models/vehicle.ts b/shared/src/models/vehicle.ts index cdc6fba41..3e0b4c330 100644 --- a/shared/src/models/vehicle.ts +++ b/shared/src/models/vehicle.ts @@ -3,7 +3,8 @@ import { IsNumber, IsString, IsUUID, ValidateNested } from 'class-validator'; import { uuid, uuidValidationOptions, UUID, UUIDSet } from '../utils'; import { IsUUIDSet, IsValue } from '../utils/validators'; import { IsPosition } from '../utils/validators/is-position'; -import { getCreate } from './utils'; +import type { WithPosition } from './utils'; +import { currentVehicleIdOf, getCreate, isInVehicle } from './utils'; import { ImageProperties } from './utils/image-properties'; import { Position } from './utils/position/position'; @@ -63,4 +64,11 @@ export class Vehicle { } static readonly create = getCreate(this); + + static isInVehicle(vehicle: Vehicle, withPosition: WithPosition): boolean { + return ( + isInVehicle(withPosition) && + currentVehicleIdOf(withPosition) === vehicle.id + ); + } } diff --git a/shared/src/simulation/activities/delay-event.ts b/shared/src/simulation/activities/delay-event.ts new file mode 100644 index 000000000..32914a992 --- /dev/null +++ b/shared/src/simulation/activities/delay-event.ts @@ -0,0 +1,48 @@ +import { Type } from 'class-transformer'; +import { IsInt, IsUUID, Min, ValidateNested } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { ExerciseSimulationEvent, simulationEventTypeOptions } from '../events'; +import { sendSimulationEvent } from '../utils/simulated-region'; +import type { + SimulationActivity, + SimulationActivityState, +} from './simulation-activity'; + +export class DelayEventActivityState implements SimulationActivityState { + @IsValue('delayEventActivity' as const) + public readonly type = 'delayEventActivity'; + + @IsUUID(4, uuidValidationOptions) + public readonly id!: UUID; + + @Type(...simulationEventTypeOptions) + @ValidateNested() + public readonly event!: ExerciseSimulationEvent; + + @IsInt() + @Min(0) + public readonly endTime!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(id: UUID, event: ExerciseSimulationEvent, endTime: number) { + this.id = id; + this.event = event; + this.endTime = endTime; + } + + static readonly create = getCreate(this); +} + +export const delayEventActivity: SimulationActivity = { + activityState: DelayEventActivityState, + tick(draftState, simulatedRegion, activityState, _tickInterval, terminate) { + if (draftState.currentTime >= activityState.endTime) { + sendSimulationEvent(simulatedRegion, activityState.event); + terminate(); + } + }, +}; diff --git a/shared/src/simulation/activities/exercise-simulation-activity.ts b/shared/src/simulation/activities/exercise-simulation-activity.ts new file mode 100644 index 000000000..1f713cca5 --- /dev/null +++ b/shared/src/simulation/activities/exercise-simulation-activity.ts @@ -0,0 +1,48 @@ +import type { Type } from 'class-transformer'; +import { delayEventActivity } from './delay-event'; +import { SimulationActivityState } from './simulation-activity'; +import { unloadVehicleActivity } from './unload-vehicle'; + +export const simulationActivities = { + unloadVehicleActivity, + delayEventActivity, +}; + +export type ExerciseSimulationActivity = + (typeof simulationActivities)[keyof typeof simulationActivities]; + +export type ExerciseSimulationActivityState = InstanceType< + ExerciseSimulationActivity['activityState'] +>; + +type ExerciseSimulationActivityDictionary = { + [Activity in ExerciseSimulationActivity as InstanceType< + Activity['activityState'] + >['type']]: Activity; +}; + +export const simulationActivityDictionary = Object.fromEntries( + Object.values(simulationActivities).map((activity) => [ + new activity.activityState().type, + activity, + ]) +) as ExerciseSimulationActivityDictionary; + +export function getSimulationActivityConstructor( + state: ExerciseSimulationActivityState +) { + return simulationActivityDictionary[state.type]?.activityState; +} + +export const simulationActivityTypeOptions: Parameters = [ + () => SimulationActivityState, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationActivityDictionary).map( + ([name, value]) => ({ name, value: value.activityState }) + ), + }, + }, +]; diff --git a/shared/src/simulation/activities/index.ts b/shared/src/simulation/activities/index.ts new file mode 100644 index 000000000..7a9ff4061 --- /dev/null +++ b/shared/src/simulation/activities/index.ts @@ -0,0 +1,2 @@ +export * from './exercise-simulation-activity'; +export * from './unload-vehicle'; diff --git a/shared/src/simulation/activities/simulation-activity.ts b/shared/src/simulation/activities/simulation-activity.ts new file mode 100644 index 000000000..928c2103c --- /dev/null +++ b/shared/src/simulation/activities/simulation-activity.ts @@ -0,0 +1,24 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Constructor, Mutable, UUID } from '../../utils'; + +export class SimulationActivityState { + readonly type!: `${string}Activity`; + readonly id!: UUID; +} + +export interface SimulationActivity { + readonly activityState: Constructor; + readonly tick: ( + draftState: Mutable, + simulatedRegion: Mutable, + activityState: Mutable, + tickInterval: number, + terminate: () => void + ) => void; + readonly onTerminate?: ( + draftState: Mutable, + simulatedRegion: Mutable, + activityId: UUID + ) => void; +} diff --git a/shared/src/simulation/activities/unload-vehicle.ts b/shared/src/simulation/activities/unload-vehicle.ts new file mode 100644 index 000000000..7af6ee032 --- /dev/null +++ b/shared/src/simulation/activities/unload-vehicle.ts @@ -0,0 +1,74 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { SimulatedRegion } from '../../models'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { unloadVehicle } from '../utils/vehicle'; +import type { + SimulationActivity, + SimulationActivityState, +} from './simulation-activity'; + +export class UnloadVehicleActivityState implements SimulationActivityState { + @IsValue('unloadVehicleActivity' as const) + public readonly type = 'unloadVehicleActivity'; + + @IsUUID(4, uuidValidationOptions) + public readonly id!: UUID; + + @IsUUID(4, uuidValidationOptions) + public readonly vehicleId!: UUID; + + @IsInt() + @Min(0) + public readonly startTime!: number; + + @IsInt() + @Min(0) + public readonly duration!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor( + id: UUID, + vehicleId: UUID, + startTime: number, + duration: number + ) { + this.vehicleId = vehicleId; + this.startTime = startTime; + this.duration = duration; + this.id = id; + } + + static readonly create = getCreate(this); +} + +// Because this activity relies on a cancel condition, we cannot model it as a DelayEventActivity +export const unloadVehicleActivity: SimulationActivity = + { + activityState: UnloadVehicleActivityState, + tick( + draftState, + simulatedRegion, + activityState, + _tickInterval, + terminate + ) { + const vehicle = draftState.vehicles[activityState.vehicleId]; + if ( + !vehicle || + !SimulatedRegion.isInSimulatedRegion(simulatedRegion, vehicle) + ) { + // The vehicle has left the region or was deleted for some reason. Cancel unloading. + terminate(); + } else if ( + draftState.currentTime >= + activityState.startTime + activityState.duration + ) { + unloadVehicle(draftState, simulatedRegion, vehicle); + terminate(); + } + }, + }; diff --git a/shared/src/simulation/behaviors/exercise-simulation-behavior.ts b/shared/src/simulation/behaviors/exercise-simulation-behavior.ts new file mode 100644 index 000000000..8e53b31b1 --- /dev/null +++ b/shared/src/simulation/behaviors/exercise-simulation-behavior.ts @@ -0,0 +1,40 @@ +import type { Type } from 'class-transformer'; +import { SimulationBehaviorState } from './simulation-behavior'; +import { unloadArrivingVehiclesBehavior } from './unload-arrived-vehicles'; + +export const simulationBehaviors = { + unloadArrivingVehiclesBehavior, +}; + +export type ExerciseSimulationBehavior = + (typeof simulationBehaviors)[keyof typeof simulationBehaviors]; + +export type ExerciseSimulationBehaviorState = InstanceType< + ExerciseSimulationBehavior['behaviorState'] +>; + +type ExerciseSimulationBehaviorDictionary = { + [Behavior in ExerciseSimulationBehavior as InstanceType< + Behavior['behaviorState'] + >['type']]: Behavior; +}; + +export const simulationBehaviorDictionary = Object.fromEntries( + Object.values(simulationBehaviors).map((behavior) => [ + new behavior.behaviorState().type, + behavior, + ]) +) as ExerciseSimulationBehaviorDictionary; + +export const simulationBehaviorTypeOptions: Parameters = [ + () => SimulationBehaviorState, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationBehaviorDictionary).map( + ([name, value]) => ({ name, value: value.behaviorState }) + ), + }, + }, +]; diff --git a/shared/src/simulation/behaviors/index.ts b/shared/src/simulation/behaviors/index.ts new file mode 100644 index 000000000..19dff8af3 --- /dev/null +++ b/shared/src/simulation/behaviors/index.ts @@ -0,0 +1,2 @@ +export * from './exercise-simulation-behavior'; +export * from './unload-arrived-vehicles'; diff --git a/shared/src/simulation/behaviors/simulation-behavior.ts b/shared/src/simulation/behaviors/simulation-behavior.ts new file mode 100644 index 000000000..5b436008d --- /dev/null +++ b/shared/src/simulation/behaviors/simulation-behavior.ts @@ -0,0 +1,19 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Constructor, Mutable, UUID } from '../../utils'; +import type { ExerciseSimulationEvent } from '../events'; + +export class SimulationBehaviorState { + readonly type!: `${string}Behavior`; + readonly id!: UUID; +} + +export interface SimulationBehavior { + readonly behaviorState: Constructor; + readonly handleEvent: ( + draftState: Mutable, + simulatedRegion: Mutable, + behaviorState: Mutable, + event: Mutable + ) => void; +} diff --git a/shared/src/simulation/behaviors/unload-arrived-vehicles.ts b/shared/src/simulation/behaviors/unload-arrived-vehicles.ts new file mode 100644 index 000000000..8644ed585 --- /dev/null +++ b/shared/src/simulation/behaviors/unload-arrived-vehicles.ts @@ -0,0 +1,52 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuid, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import { UnloadVehicleActivityState } from '../activities/unload-vehicle'; +import { nextUUID } from '../utils/randomness'; +import { addActivity } from '../utils/simulated-region'; +import type { + SimulationBehavior, + SimulationBehaviorState, +} from './simulation-behavior'; + +export class UnloadArrivingVehiclesBehaviorState + implements SimulationBehaviorState +{ + @IsValue('unloadArrivingVehiclesBehavior' as const) + readonly type = 'unloadArrivingVehiclesBehavior'; + + @IsUUID(4, uuidValidationOptions) + public readonly id: UUID = uuid(); + + @IsInt() + @Min(0) + public readonly unloadDelay!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(unloadDelay: number) { + this.unloadDelay = unloadDelay; + } + + static readonly create = getCreate(this); +} + +export const unloadArrivingVehiclesBehavior: SimulationBehavior = + { + behaviorState: UnloadArrivingVehiclesBehaviorState, + handleEvent(draftState, simulatedRegion, behaviorState, event) { + if (event.type === 'vehicleArrivedEvent') { + addActivity( + simulatedRegion, + UnloadVehicleActivityState.create( + nextUUID(draftState), + event.vehicleId, + event.arrivalTime, + behaviorState.unloadDelay + ) + ); + } + }, + }; diff --git a/shared/src/simulation/events/exercise-simulation-event.ts b/shared/src/simulation/events/exercise-simulation-event.ts new file mode 100644 index 000000000..85781c6e9 --- /dev/null +++ b/shared/src/simulation/events/exercise-simulation-event.ts @@ -0,0 +1,37 @@ +import type { Type } from 'class-transformer'; +import type { Constructor } from '../../utils'; +import { SimulationEvent } from './simulation-event'; +import { TickEvent } from './tick'; +import { VehicleArrivedEvent } from './vehicle-arrived'; + +export const simulationEvents = { + TickEvent, + VehicleArrivedEvent, +}; + +export type ExerciseSimulationEvent = InstanceType< + (typeof simulationEvents)[keyof typeof simulationEvents] +>; + +type ExerciseSimulationEventDictionary = { + [EventType in ExerciseSimulationEvent as EventType['type']]: Constructor; +}; + +// TODO: compute dynamically +export const simulationEventDictionary: ExerciseSimulationEventDictionary = { + tickEvent: TickEvent, + vehicleArrivedEvent: VehicleArrivedEvent, +}; + +export const simulationEventTypeOptions: Parameters = [ + () => SimulationEvent, + { + keepDiscriminatorProperty: true, + discriminator: { + property: 'type', + subTypes: Object.entries(simulationEventDictionary).map( + ([name, value]) => ({ name, value }) + ), + }, + }, +]; diff --git a/shared/src/simulation/events/index.ts b/shared/src/simulation/events/index.ts new file mode 100644 index 000000000..7b3bea99f --- /dev/null +++ b/shared/src/simulation/events/index.ts @@ -0,0 +1,3 @@ +export * from './exercise-simulation-event'; +export * from './vehicle-arrived'; +export * from './tick'; diff --git a/shared/src/simulation/events/simulation-event.ts b/shared/src/simulation/events/simulation-event.ts new file mode 100644 index 000000000..744952f52 --- /dev/null +++ b/shared/src/simulation/events/simulation-event.ts @@ -0,0 +1,3 @@ +export class SimulationEvent { + readonly type!: `${string}Event`; +} diff --git a/shared/src/simulation/events/tick.ts b/shared/src/simulation/events/tick.ts new file mode 100644 index 000000000..f0ee03304 --- /dev/null +++ b/shared/src/simulation/events/tick.ts @@ -0,0 +1,22 @@ +import { IsInt, IsPositive } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { IsValue } from '../../utils/validators'; +import type { SimulationEvent } from './simulation-event'; + +export class TickEvent implements SimulationEvent { + @IsValue('tickEvent') + readonly type = 'tickEvent'; + + @IsInt() + @IsPositive() + public readonly tickInterval!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(tickInterval: number) { + this.tickInterval = tickInterval; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/simulation/events/vehicle-arrived.ts b/shared/src/simulation/events/vehicle-arrived.ts new file mode 100644 index 000000000..bff048dbc --- /dev/null +++ b/shared/src/simulation/events/vehicle-arrived.ts @@ -0,0 +1,27 @@ +import { IsInt, IsUUID, Min } from 'class-validator'; +import { getCreate } from '../../models/utils'; +import { UUID, uuidValidationOptions } from '../../utils'; +import { IsValue } from '../../utils/validators'; +import type { SimulationEvent } from './simulation-event'; + +export class VehicleArrivedEvent implements SimulationEvent { + @IsValue('vehicleArrivedEvent') + readonly type = 'vehicleArrivedEvent'; + + @IsUUID(4, uuidValidationOptions) + readonly vehicleId!: UUID; + + @IsInt() + @Min(0) + readonly arrivalTime!: number; + + /** + * @deprecated Use {@link create} instead + */ + constructor(vehicleId: UUID, arrivalTime: number) { + this.vehicleId = vehicleId; + this.arrivalTime = arrivalTime; + } + + static readonly create = getCreate(this); +} diff --git a/shared/src/simulation/index.ts b/shared/src/simulation/index.ts new file mode 100644 index 000000000..4090dc283 --- /dev/null +++ b/shared/src/simulation/index.ts @@ -0,0 +1,4 @@ +export * from './activities'; +export * from './behaviors'; +export * from './events'; +export * from './utils'; diff --git a/shared/src/simulation/utils/index.ts b/shared/src/simulation/utils/index.ts new file mode 100644 index 000000000..f67c90177 --- /dev/null +++ b/shared/src/simulation/utils/index.ts @@ -0,0 +1,3 @@ +export * from './simulated-region'; +export * from './vehicle'; +export * from './randomness'; diff --git a/shared/src/simulation/utils/randomness.ts b/shared/src/simulation/utils/randomness.ts new file mode 100644 index 000000000..6e4d8ad1f --- /dev/null +++ b/shared/src/simulation/utils/randomness.ts @@ -0,0 +1,77 @@ +/* eslint-disable no-bitwise */ +import { IsInt, Min, ValidateIf } from 'class-validator'; +import hash from 'hash.js'; +import { v4 } from 'uuid'; +import { getCreate } from '../../models/utils'; +import type { ExerciseState } from '../../state'; +import type { Mutable, UUID } from '../../utils'; +import { IsLiteralUnion, IsValue } from '../../utils/validators'; + +export class RandomState { + @IsValue('randomState' as const) + readonly type = 'randomState'; + + @IsLiteralUnion({ 'sha256-id-ctr': true }) + readonly algo = 'sha256-id-ctr'; + + @ValidateIf((o) => o.algo === 'sha256-id-ctr') + @IsInt() + @Min(0) + readonly counter: number = 0; + + static readonly create = getCreate(this); +} + +export function seededRandomState() { + return RandomState.create(); +} + +export function nextBool( + draftState: Mutable, + probability: number = 0.5 +): boolean { + return nextInt(draftState, 4294967296) / 4294967296 < probability; +} + +export function nextUUID(draftState: Mutable): UUID { + return v4({ + random: advance(draftState), + }); +} + +/** + * Draws the next integer from a pseudo random number generator persisted in `draftState`. + * @param draftState The exercise state where the pseudo random number generator state is stored + * @param upperBound The exclusive upper bound of the return value + * Must be a positive integer not greater than `4294967296`, or `2**32` + * @returns An integer from `0` (inclusive) to `upperBound` (exclusive) + */ +export function nextInt( + draftState: Mutable, + upperBound: number +): number { + const state = advance(draftState) + .slice(0, 4) + .map((b, i) => Math.trunc(b * 256 ** i)) + .reduce((a, b) => a | b); + return Math.trunc(state % upperBound); +} + +/** + * Draws the next bytes from a pseudo random number generator persisted in `draftState`. + * @param draftState The exercise state where the pseudo random number generator state is stored + * @returns An array of length 32 (specific to sha256) of numbers from 0-255 + */ +function advance(draftState: Mutable): number[] { + const state = draftState.randomState; + + const result = hash + .sha256() + .update(draftState.id) + .update(state.counter.toString()) + .digest() + .map((b) => b & 0xff); + + state.counter++; + return result; +} diff --git a/shared/src/simulation/utils/simulated-region.ts b/shared/src/simulation/utils/simulated-region.ts new file mode 100644 index 000000000..4b429a20a --- /dev/null +++ b/shared/src/simulation/utils/simulated-region.ts @@ -0,0 +1,97 @@ +import type { SimulatedRegion } from '../../models'; +import type { ExerciseState } from '../../state'; +import type { Mutable, UUID } from '../../utils'; +import { cloneDeepMutable } from '../../utils'; +import type { ExerciseSimulationActivityState } from '../activities'; +import { simulationActivityDictionary } from '../activities'; +import { simulationBehaviorDictionary } from '../behaviors'; +import type { ExerciseSimulationEvent } from '../events'; +import { TickEvent } from '../events/tick'; + +export function simulateAllRegions( + draftState: Mutable, + tickInterval: number +) { + Object.values(draftState.simulatedRegions).forEach((simulatedRegion) => { + simulateSingleRegion(draftState, simulatedRegion, tickInterval); + }); +} + +function simulateSingleRegion( + draftState: Mutable, + simulatedRegion: Mutable, + tickInterval: number +) { + sendSimulationEvent(simulatedRegion, TickEvent.create(tickInterval)); + handleSimulationEvents(draftState, simulatedRegion); + tickActivities(draftState, simulatedRegion, tickInterval); +} + +function tickActivities( + draftState: Mutable, + simulatedRegion: Mutable, + tickInterval: number +) { + Object.values(simulatedRegion.activities).forEach((activityState) => { + simulationActivityDictionary[activityState.type].tick( + draftState, + simulatedRegion, + activityState as any, + tickInterval, + () => { + terminateActivity( + draftState, + simulatedRegion, + activityState.id + ); + } + ); + }); +} + +function handleSimulationEvents( + draftState: Mutable, + simulatedRegion: Mutable +) { + simulatedRegion.behaviors.forEach((behaviorState) => { + simulatedRegion.inEvents.forEach((event) => { + simulationBehaviorDictionary[behaviorState.type].handleEvent( + draftState, + simulatedRegion, + behaviorState as any, + event + ); + }); + }); + simulatedRegion.inEvents = []; +} + +export function sendSimulationEvent( + simulatedRegion: Mutable, + event: ExerciseSimulationEvent +) { + simulatedRegion.inEvents.push(cloneDeepMutable(event)); +} + +export function addActivity( + simulatedRegion: Mutable, + activityState: ExerciseSimulationActivityState +) { + simulatedRegion.activities[activityState.id] = + cloneDeepMutable(activityState); +} + +export function terminateActivity( + draftState: Mutable, + simulatedRegion: Mutable, + activityId: UUID +) { + const activityType = simulatedRegion.activities[activityId]?.type; + if (activityType) { + const activity = simulationActivityDictionary[activityType]; + if (activity.onTerminate) { + activity.onTerminate(draftState, simulatedRegion, activityId); + } + delete simulatedRegion.activities[activityId]; + } +} diff --git a/shared/src/simulation/utils/vehicle.ts b/shared/src/simulation/utils/vehicle.ts new file mode 100644 index 000000000..c4f794fb0 --- /dev/null +++ b/shared/src/simulation/utils/vehicle.ts @@ -0,0 +1,40 @@ +import { SimulatedRegion, Vehicle } from '../../models'; +import { SimulatedRegionPosition } from '../../models/utils'; +import { changePositionWithId } from '../../models/utils/position/position-helpers-mutable'; +import type { ExerciseState } from '../../state'; +import { getElement } from '../../store/action-reducers/utils'; +import type { Mutable } from '../../utils'; + +export function unloadVehicle( + draftState: Mutable, + simulatedRegion: Mutable, + vehicle: Mutable +) { + if (!SimulatedRegion.isInSimulatedRegion(simulatedRegion, vehicle)) { + console.error( + `Trying to unload a vehicle with id ${vehicle.id} into simulated region with id ${simulatedRegion.id} but the vehicle is not in that region.` + ); + return; + } + + const loadedElements = [ + { uuidSet: vehicle.materialIds, elementType: 'material' }, + { uuidSet: vehicle.personnelIds, elementType: 'personnel' }, + { uuidSet: vehicle.patientIds, elementType: 'patient' }, + ] as const; + + for (const { uuidSet, elementType } of loadedElements) { + for (const elementId of Object.keys(uuidSet)) { + const element = getElement(draftState, elementType, elementId); + if (Vehicle.isInVehicle(vehicle, element)) { + changePositionWithId( + elementId, + SimulatedRegionPosition.create(simulatedRegion.id), + elementType, + draftState + ); + } + } + } + vehicle.patientIds = {}; +} diff --git a/shared/src/state-migrations/20-add-simulation-properties.ts b/shared/src/state-migrations/20-add-simulation-properties.ts new file mode 100644 index 000000000..34b6be3b0 --- /dev/null +++ b/shared/src/state-migrations/20-add-simulation-properties.ts @@ -0,0 +1,46 @@ +import { seededRandomState } from '../simulation'; +import type { UUID } from '../utils'; +import type { Migration } from './migration-functions'; + +export const addSimulationProperties20: Migration = { + actions: (_initialState, actions) => { + actions.forEach((action) => { + if ( + (action as { type: string } | null)?.type === + '[SimulatedRegion] Add simulated region' + ) { + const typedAction = action as { + simulatedRegion: { + inEvents: any[]; + behaviors: any[]; + activities: object; + }; + }; + typedAction.simulatedRegion.inEvents = []; + typedAction.simulatedRegion.behaviors = []; + typedAction.simulatedRegion.activities = {}; + } + }); + }, + state: (state: any) => { + state.randomState = seededRandomState(); + + const typedState = state as { + simulatedRegions: { + [simulatedRegionId: UUID]: { + inEvents: any[]; + behaviors: any[]; + activities: object; + }; + }; + }; + + Object.values(typedState.simulatedRegions).forEach( + (simulatedRegion) => { + simulatedRegion.inEvents = []; + simulatedRegion.behaviors = []; + simulatedRegion.activities = {}; + } + ); + }, +}; diff --git a/shared/src/state-migrations/migration-functions.ts b/shared/src/state-migrations/migration-functions.ts index 59c83d3bd..63a9e586c 100644 --- a/shared/src/state-migrations/migration-functions.ts +++ b/shared/src/state-migrations/migration-functions.ts @@ -8,6 +8,7 @@ import { addMetaPosition16 } from './16-add-meta-position'; import { addTypeProperty17 } from './17-add-type-property'; import { replacePositionWithMetaPosition18 } from './18-replace-position-with-meta-position'; import { renameStartPointTypes19 } from './19-rename-start-point-types'; +import { addSimulationProperties20 } from './20-add-simulation-properties'; import { updateEocLog3 } from './3-update-eoc-log'; import { removeSetParticipantIdAction4 } from './4-remove-set-participant-id-action'; import { removeStatistics5 } from './5-remove-statistics'; @@ -61,4 +62,5 @@ export const migrations: { 17: addTypeProperty17, 18: replacePositionWithMetaPosition18, 19: renameStartPointTypes19, + 20: addSimulationProperties20, }; diff --git a/shared/src/state.ts b/shared/src/state.ts index c206c4302..b54476fe7 100644 --- a/shared/src/state.ts +++ b/shared/src/state.ts @@ -44,6 +44,7 @@ import { SpatialTree, } from './models/utils'; import type { MaterialType } from './models/utils/material-type'; +import { seededRandomState, RandomState } from './simulation/utils'; import type { SpatialElementPlural } from './store/action-reducers/utils/spatial-elements'; import type { UUID } from './utils'; import { uuid, uuidValidationOptions } from './utils'; @@ -64,6 +65,11 @@ export class ExerciseState { public readonly currentTime = 0; @IsLiteralUnion(exerciseStatusAllowedValues) public readonly currentStatus: ExerciseStatus = 'notStarted'; + + @Type(() => RandomState) + @ValidateNested() + public readonly randomState: RandomState = seededRandomState(); + @IsIdMap(Viewport) public readonly viewports: { readonly [key: UUID]: Viewport } = {}; @IsIdMap(SimulatedRegion) @@ -148,5 +154,5 @@ export class ExerciseState { * * This number MUST be increased every time a change to any object (that is part of the state or the state itself) is made in a way that there may be states valid before that are no longer valid. */ - static readonly currentStateVersion = 19; + static readonly currentStateVersion = 20; } diff --git a/shared/src/store/action-reducers/exercise.ts b/shared/src/store/action-reducers/exercise.ts index c20d48425..ea4d45ece 100644 --- a/shared/src/store/action-reducers/exercise.ts +++ b/shared/src/store/action-reducers/exercise.ts @@ -15,6 +15,7 @@ import { TransferPosition, } from '../../models/utils'; import { changePosition } from '../../models/utils/position/position-helpers-mutable'; +import { simulateAllRegions } from '../../simulation/utils/simulated-region'; import type { ExerciseState } from '../../state'; import type { Mutable } from '../../utils'; import { cloneDeepMutable } from '../../utils'; @@ -134,6 +135,8 @@ export namespace ExerciseActionReducers { // Refresh transfers refreshTransfer(draftState, 'vehicle', tickInterval); refreshTransfer(draftState, 'personnel', tickInterval); + + simulateAllRegions(draftState, tickInterval); return draftState; }, rights: 'server', diff --git a/shared/src/store/action-reducers/simulated-region.ts b/shared/src/store/action-reducers/simulated-region.ts index da85e9c94..4199e4ade 100644 --- a/shared/src/store/action-reducers/simulated-region.ts +++ b/shared/src/store/action-reducers/simulated-region.ts @@ -11,6 +11,12 @@ import { changePosition, changePositionWithId, } from '../../models/utils/position/position-helpers-mutable'; +import { + ExerciseSimulationBehaviorState, + sendSimulationEvent, + simulationBehaviorTypeOptions, + VehicleArrivedEvent, +} from '../../simulation'; import { cloneDeepMutable, UUID, uuidValidationOptions } from '../../utils'; import { IsLiteralUnion, IsValue } from '../../utils/validators'; import type { Action, ActionReducer } from '../action-reducer'; @@ -88,6 +94,18 @@ export class AddElementToSimulatedRegionAction implements Action { public readonly elementToBeAddedId!: UUID; } +export class AddBehaviorToSimulatedRegionAction implements Action { + @IsValue('[SimulatedRegion] Add Behavior' as const) + public readonly type = '[SimulatedRegion] Add Behavior'; + + @IsUUID(4, uuidValidationOptions) + public readonly simulatedRegionId!: UUID; + + @Type(...simulationBehaviorTypeOptions) + @ValidateNested() + public readonly behaviorState!: ExerciseSimulationBehaviorState; +} + export namespace SimulatedRegionActionReducers { export const addSimulatedRegion: ActionReducer = { action: AddSimulatedRegionAction, @@ -170,8 +188,11 @@ export namespace SimulatedRegionActionReducers { draftState, { simulatedRegionId, elementToBeAddedId, elementToBeAddedType } ) => { - // Test for existence of the simulate - getElement(draftState, 'simulatedRegion', simulatedRegionId); + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); const element = getElement( draftState, elementToBeAddedType, @@ -184,6 +205,31 @@ export namespace SimulatedRegionActionReducers { draftState ); + if (element.type === 'vehicle') { + sendSimulationEvent( + simulatedRegion, + VehicleArrivedEvent.create( + element.id, + draftState.currentTime + ) + ); + } + + return draftState; + }, + rights: 'participant', + }; + + export const addBehaviorToSimulatedRegion: ActionReducer = + { + action: AddBehaviorToSimulatedRegionAction, + reducer: (draftState, { simulatedRegionId, behaviorState }) => { + const simulatedRegion = getElement( + draftState, + 'simulatedRegion', + simulatedRegionId + ); + simulatedRegion.behaviors.push(cloneDeepMutable(behaviorState)); return draftState; }, rights: 'participant', diff --git a/shared/src/utils/validators/is-id-map.ts b/shared/src/utils/validators/is-id-map.ts index 3b2e201e7..e4fbd5e2c 100644 --- a/shared/src/utils/validators/is-id-map.ts +++ b/shared/src/utils/validators/is-id-map.ts @@ -22,24 +22,46 @@ export function IsIdMap( getId: (value: T) => UUID = (value) => (value as { id: UUID }).id, validationOptions?: ValidationOptions & { each?: Each } ): GenericPropertyDecorator<{ readonly [key: UUID]: T }, Each> { + return IsMultiTypedIdMap(() => type, getId, validationOptions); +} + +/** + * An `IdMap` is of type `{ readonly [key: UUID]: T }` + * This validates IdMaps that can contain multiple types. + * + * @property getConstructor A function to get the constructor for a given plain object. Return a falsy value if the constructor cannot be determined which is invalid. Usually dispatches on the `.type` property. + * @property getId A function to get the id that is used as the key in the object. Defaults to `.id`, this might be wrong for some types, though. + */ +// eslint-disable-next-line @typescript-eslint/naming-convention +export function IsMultiTypedIdMap< + T extends Constructor, + Each extends boolean = false +>( + getConstructor: (value: InstanceType) => T | undefined, + getId: (value: InstanceType) => UUID = (value) => + (value as { id: UUID }).id, + validationOptions?: ValidationOptions & { each?: Each } +): GenericPropertyDecorator<{ readonly [key: UUID]: InstanceType }, Each> { const transform = Transform( - (params) => { - const plainChildren = params.value as { [key: UUID]: T }; - if (Object.keys(plainChildren).some((key) => !isUUID(key, 4))) { - return 'invalid'; - } - const instanceChildrenWithKey = Object.entries(plainChildren).map( - ([key, plainChild]) => - [key, plainToInstance(type, plainChild)] as const - ); + ({ value }) => { + const plainMap = value as { [key: UUID]: InstanceType }; if ( - instanceChildrenWithKey.some( - ([key, child]) => getId(child) !== key + Object.entries(plainMap).some( + ([key, plain]) => !isUUID(key, 4) || key !== getId(plain) ) ) { return 'invalid'; } - return instanceChildrenWithKey.map(([, child]) => child); + const plainWithConstructor = Object.values(plainMap).map( + (entry) => [entry, getConstructor(entry)] as const + ); + if (plainWithConstructor.some(([_, constr]) => !constr)) { + return 'invalid'; + } + const instances = plainWithConstructor.map(([entry, constr]) => + plainToInstance(constr!, entry) + ); + return instances; }, { toClassOnly: true } ); From 41c44e3ff86ac2af0c572db69dce8cd947cde20f Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:34:11 +0100 Subject: [PATCH 36/58] Dragging onto the Map now triggers Drop Events (#671) * Dragging onto the Map now triggers Drop Events --- .../shared/core/drag-element.service.ts | 239 ++++++++++++------ .../exercise-map/exercise-map.component.ts | 4 + .../catering-lines-feature-manager.ts | 4 +- .../delete-feature-manager.ts | 101 ++++---- .../feature-managers/element-manager.ts | 2 +- .../moveable-feature-manager.ts | 32 ++- .../simulated-region-feature-manager.ts | 17 +- .../transfer-lines-feature-manager.ts | 4 +- .../transfer-point-feature-manager.ts | 6 +- .../vehicle-feature-manager.ts | 10 +- .../exercise-map/utility/feature-manager.ts | 4 +- .../utility/ol-map-interactions-manager.ts | 9 +- .../exercise-map/utility/ol-map-manager.ts | 2 +- shared/src/models/index.ts | 1 + 14 files changed, 274 insertions(+), 161 deletions(-) diff --git a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts index 2da6f3c52..a813a6f22 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/core/drag-element.service.ts @@ -1,6 +1,8 @@ import { Injectable } from '@angular/core'; import { Store } from '@ngrx/store'; import type { + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, ImageProperties, MapImageTemplate, PatientCategory, @@ -16,7 +18,11 @@ import { SimulatedRegion, MapPosition, } from 'digital-fuesim-manv-shared'; +import type { Feature } from 'ol'; +import type VectorLayer from 'ol/layer/Vector'; import type OlMap from 'ol/Map'; +import type { Pixel } from 'ol/pixel'; +import type VectorSource from 'ol/source/Vector'; import { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; import { @@ -24,6 +30,7 @@ import { selectPersonnelTemplates, } from 'src/app/state/application/selectors/exercise.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +import type { FeatureManager } from '../exercise-map/utility/feature-manager'; @Injectable({ providedIn: 'root', @@ -33,20 +40,37 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; */ export class DragElementService { private olMap?: OlMap; + layerFeatureManagerDictionary?: Map< + VectorLayer, + FeatureManager + >; constructor( private readonly exerciseService: ExerciseService, private readonly store: Store ) {} - public registerMap(map: OlMap) { - this.olMap = map; + public registerMap(olMap: OlMap) { + this.olMap = olMap; + } + + public registerLayerFeatureManagerDictionary( + layerFeatureManagerDictionary: Map< + VectorLayer, + FeatureManager + > + ) { + this.layerFeatureManagerDictionary = layerFeatureManagerDictionary; } public unregisterMap() { this.olMap = undefined; } + public unregisterLayerFeatureManagerDictionary() { + this.layerFeatureManagerDictionary = undefined; + } + private dragElement?: HTMLImageElement; private imageDimensions?: { width: number; height: number }; private transferringTemplate?: TransferTemplate; @@ -133,31 +157,38 @@ export class DragElementService { return; } // Get the position of the mouse on the map - const [x, y] = this.olMap.getCoordinateFromPixel( - this.olMap.getEventPixel(event) - ) as [number, number]; + const pixel = this.olMap.getEventPixel(event); + const [x, y] = this.olMap.getCoordinateFromPixel(pixel) as [ + number, + number + ]; const position = { x, y }; // create the element + let createdElement: Element | null = null; switch (this.transferringTemplate.type) { case 'vehicle': - this.exerciseService.proposeAction( - { - type: '[Vehicle] Add vehicle', - ...createVehicleParameters( - this.transferringTemplate.template, - selectStateSnapshot( - selectMaterialTemplates, - this.store - ), - selectStateSnapshot( - selectPersonnelTemplates, - this.store - ), - position + { + const params = createVehicleParameters( + this.transferringTemplate.template, + selectStateSnapshot( + selectMaterialTemplates, + this.store ), - }, - true - ); + selectStateSnapshot( + selectPersonnelTemplates, + this.store + ), + position + ); + this.exerciseService.proposeAction( + { + ...params, + type: '[Vehicle] Add vehicle', + }, + true + ); + createdElement = params.vehicle; + } break; case 'patient': { @@ -179,83 +210,131 @@ export class DragElementService { }, true ); + createdElement = patient; } break; - case 'viewport': { - // This ratio has been determined by trial and error - const height = Viewport.image.height / 23.5; - const width = height * Viewport.image.aspectRatio; - this.exerciseService.proposeAction( - { - type: '[Viewport] Add viewport', - viewport: Viewport.create( - { - x: position.x - width / 2, - y: position.y + height / 2, - }, - { - height, - width, - }, - 'Einsatzabschnitt' - ), - }, - true - ); + case 'viewport': + { + // This ratio has been determined by trial and error + const height = Viewport.image.height / 23.5; + const width = height * Viewport.image.aspectRatio; + const viewport = Viewport.create( + { + x: position.x - width / 2, + y: position.y + height / 2, + }, + { + height, + width, + }, + 'Einsatzabschnitt' + ); + this.exerciseService.proposeAction( + { + type: '[Viewport] Add viewport', + viewport, + }, + true + ); + createdElement = viewport; + } break; - } + case 'mapImage': { const template = this.transferringTemplate.template.image; + const mapImage = MapImage.create( + position, + template, + false, + 0 + ); this.exerciseService.proposeAction({ type: '[MapImage] Add MapImage', - mapImage: MapImage.create(position, template, false, 0), + mapImage, }); + createdElement = mapImage; } break; case 'transferPoint': - this.exerciseService.proposeAction( - { - type: '[TransferPoint] Add TransferPoint', - transferPoint: TransferPoint.create( - position, - {}, - {}, - '???', - '???' - ), - }, - true - ); + { + const transferPoint = TransferPoint.create( + position, + {}, + {}, + '???', + '???' + ); + this.exerciseService.proposeAction( + { + type: '[TransferPoint] Add TransferPoint', + transferPoint, + }, + true + ); + createdElement = transferPoint; + } break; - case 'simulatedRegion': { - // This ratio has been determined by trial and error - const height = SimulatedRegion.image.height / 23.5; - const width = height * SimulatedRegion.image.aspectRatio; - this.exerciseService.proposeAction( - { - type: '[SimulatedRegion] Add simulated region', - simulatedRegion: SimulatedRegion.create( - { - x: position.x - width / 2, - y: position.y + height / 2, - }, - { - height, - width, - }, - 'Einsatzabschnitt ???' - ), - }, - true - ); + case 'simulatedRegion': + { + // This ratio has been determined by trial and error + const height = SimulatedRegion.image.height / 23.5; + const width = height * SimulatedRegion.image.aspectRatio; + const simulatedRegion = SimulatedRegion.create( + { + x: position.x - width / 2, + y: position.y + height / 2, + }, + { + height, + width, + }, + 'Einsatzabschnitt ???' + ); + this.exerciseService.proposeAction( + { + type: '[SimulatedRegion] Add simulated region', + simulatedRegion, + }, + true + ); + createdElement = simulatedRegion; + } break; - } + default: break; } + + this.executeDropSideEffects(pixel, createdElement); }; + private executeDropSideEffects( + pixel: Pixel, + createdElement: Element | null + ) { + if ( + createdElement === null || + !this.olMap || + !this.layerFeatureManagerDictionary + ) { + return; + } + this.olMap.forEachFeatureAtPixel(pixel, (droppedOnFeature, layer) => { + // Skip layer when unset + if (layer === null || !this.layerFeatureManagerDictionary) { + return; + } + // We stop propagating the event as soon as the onFeatureDropped function returns true + return this.layerFeatureManagerDictionary + .get(layer as VectorLayer)! + .onFeatureDrop( + createdElement as Element, + droppedOnFeature as Feature + ); + }); + } + /** * * @returns wether {@link coordinates} are in {@link element} diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts index de473149a..3e17cc37e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/exercise-map.component.ts @@ -64,6 +64,9 @@ export class ExerciseMapComponent implements AfterViewInit, OnDestroy { this.popupManager! ); this.dragElementService.registerMap(this.olMapManager.olMap); + this.dragElementService.registerLayerFeatureManagerDictionary( + this.olMapManager.layerFeatureManagerDictionary + ); }); this.popupManager!.changePopup$.pipe( @@ -99,5 +102,6 @@ export class ExerciseMapComponent implements AfterViewInit, OnDestroy { ngOnDestroy(): void { this.destroy$.next(); this.dragElementService.unregisterMap(); + this.dragElementService.unregisterLayerFeatureManagerDictionary(); } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts index d38006350..d122347e4 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/catering-lines-feature-manager.ts @@ -12,6 +12,8 @@ import type { CateringLine } from 'src/app/shared/types/catering-line'; import type { AppState } from 'src/app/state/app.state'; import { selectVisibleCateringLines } from 'src/app/state/application/selectors/shared.selectors'; import type OlMap from 'ol/Map'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import type { OpenPopupOptions } from '../utility/popup-manager'; @@ -110,7 +112,7 @@ export class CateringLinesFeatureManager ) {} onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts index 8178c3d12..aa517f222 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/delete-feature-manager.ts @@ -1,6 +1,5 @@ import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { UUID } from 'digital-fuesim-manv-shared'; import type { MapBrowserEvent, View } from 'ol'; import { Feature } from 'ol'; import { getTopRight } from 'ol/extent'; @@ -14,9 +13,10 @@ import Style from 'ol/style/Style'; import type { Subject } from 'rxjs'; import type { ExerciseService } from 'src/app/core/exercise.service'; import type { AppState } from 'src/app/state/app.state'; -import { selectExerciseState } from 'src/app/state/application/selectors/exercise.selectors'; import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; import type { OpenPopupOptions } from '../utility/popup-manager'; @@ -88,58 +88,57 @@ export class DeleteFeatureManager implements FeatureManager { } public onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { - const id = droppedFeature.getId() as UUID; - const exerciseState = selectStateSnapshot( - selectExerciseState, - this.store - ); - // We expect the id to be globally unique - if (exerciseState.patients[id]) { - this.exerciseService.proposeAction({ - type: '[Patient] Remove patient', - patientId: id, - }); - return true; - } - if (exerciseState.vehicles[id]) { - this.exerciseService.proposeAction({ - type: '[Vehicle] Remove vehicle', - vehicleId: id, - }); - return true; - } - if (exerciseState.mapImages[id]) { - this.exerciseService.proposeAction({ - type: '[MapImage] Remove MapImage', - mapImageId: id, - }); - return true; - } - if (exerciseState.viewports[id]) { - this.exerciseService.proposeAction({ - type: '[Viewport] Remove viewport', - viewportId: id, - }); - return true; + const id = droppedElement.id; + switch (droppedElement.type) { + case 'patient': { + this.exerciseService.proposeAction({ + type: '[Patient] Remove patient', + patientId: id, + }); + return true; + } + case 'vehicle': { + this.exerciseService.proposeAction({ + type: '[Vehicle] Remove vehicle', + vehicleId: id, + }); + return true; + } + case 'mapImage': { + this.exerciseService.proposeAction({ + type: '[MapImage] Remove MapImage', + mapImageId: id, + }); + return true; + } + case 'viewport': { + this.exerciseService.proposeAction({ + type: '[Viewport] Remove viewport', + viewportId: id, + }); + return true; + } + case 'transferPoint': { + this.exerciseService.proposeAction({ + type: '[TransferPoint] Remove TransferPoint', + transferPointId: id, + }); + return true; + } + case 'simulatedRegion': { + this.exerciseService.proposeAction({ + type: '[SimulatedRegion] Remove simulated region', + simulatedRegionId: id, + }); + return true; + } + default: { + return false; + } } - if (exerciseState.transferPoints[id]) { - this.exerciseService.proposeAction({ - type: '[TransferPoint] Remove TransferPoint', - transferPointId: id, - }); - return true; - } - if (exerciseState.simulatedRegions[id]) { - this.exerciseService.proposeAction({ - type: '[SimulatedRegion] Remove simulated region', - simulatedRegionId: id, - }); - return true; - } - return false; } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts index aeca69e91..e4ffc9f14 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/element-manager.ts @@ -134,4 +134,4 @@ export abstract class ElementManager< /** * The keys of the feature, where the type and most recent value of the respective element are saved to */ -const featureElementKey = 'element'; +export const featureElementKey = 'element'; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts index a89e8b2ba..af8277d30 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/moveable-feature-manager.ts @@ -7,7 +7,8 @@ import type VectorSource from 'ol/source/Vector'; import type { Observable } from 'rxjs'; import { Subject } from 'rxjs'; import type { NgZone } from '@angular/core'; -import type { UUID } from 'digital-fuesim-manv-shared'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { UUID, Element } from 'digital-fuesim-manv-shared'; import type { FeatureManager } from '../utility/feature-manager'; import { MovementAnimator } from '../utility/movement-animator'; import type { @@ -27,10 +28,10 @@ import { ElementManager } from './element-manager'; * Automatically redraws a feature (= reevaluates its style function) when an element property has changed. */ export abstract class MoveableFeatureManager< - Element extends PositionableElement, + ManagedElement extends PositionableElement, FeatureType extends GeometryWithCoordinates = Point > - extends ElementManager + extends ElementManager implements FeatureManager { public readonly togglePopup$ = new Subject>(); @@ -40,9 +41,12 @@ export abstract class MoveableFeatureManager< protected readonly olMap: OlMap, private readonly proposeMovementAction: ( newPosition: Positions, - element: Element + element: ManagedElement ) => void, - protected readonly geometryHelper: GeometryHelper, + protected readonly geometryHelper: GeometryHelper< + FeatureType, + ManagedElement + >, renderBuffer?: number ) { super(); @@ -59,7 +63,7 @@ export abstract class MoveableFeatureManager< ); } - createFeature(element: Element): Feature { + createFeature(element: ManagedElement): Feature { const elementFeature = this.geometryHelper.create(element); elementFeature.setId(element.id); this.layer.getSource()!.addFeature(elementFeature); @@ -78,7 +82,7 @@ export abstract class MoveableFeatureManager< } deleteFeature( - element: Element, + element: ManagedElement, elementFeature: Feature ): void { this.layer.getSource()!.removeFeature(elementFeature); @@ -87,9 +91,9 @@ export abstract class MoveableFeatureManager< } changeFeature( - oldElement: Element, - newElement: Element, - changedProperties: ReadonlySet, + oldElement: ManagedElement, + newElement: ManagedElement, + changedProperties: ReadonlySet, elementFeature: Feature ): void { if (changedProperties.has('position')) { @@ -102,7 +106,9 @@ export abstract class MoveableFeatureManager< elementFeature.changed(); } - getFeatureFromElement(element: Element): Feature | undefined { + getFeatureFromElement( + element: ManagedElement + ): Feature | undefined { return ( (this.layer .getSource()! @@ -121,7 +127,7 @@ export abstract class MoveableFeatureManager< * The standard implementation is to ignore these events. */ public onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ): boolean { @@ -136,7 +142,7 @@ export abstract class MoveableFeatureManager< ): void; protected registerFeatureElementManager( - elementDictionary$: Observable<{ [id: UUID]: Element }>, + elementDictionary$: Observable<{ [id: UUID]: ManagedElement }>, changePopup$: Subject | undefined>, destroy$: Subject, ngZone: NgZone, diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts index 8554a4f1b..08a3ddd40 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/simulated-region-feature-manager.ts @@ -1,5 +1,11 @@ import type { Store } from '@ngrx/store'; -import type { UUID, SimulatedRegion } from 'digital-fuesim-manv-shared'; +import type { + UUID, + SimulatedRegion, + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, +} from 'digital-fuesim-manv-shared'; + import { MapCoordinates, Size } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type { TranslateEvent } from 'ol/interaction/Translate'; @@ -124,11 +130,10 @@ export class SimulatedRegionFeatureManager } public override onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { - const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnSimulatedRegion = this.getElementFromFeature( droppedOnFeature ) as SimulatedRegion; @@ -145,7 +150,11 @@ export class SimulatedRegionFeatureManager { type: '[SimulatedRegion] Add Element', simulatedRegionId: droppedOnSimulatedRegion.id, - elementToBeAddedType: droppedElement.type, + elementToBeAddedType: droppedElement.type as + | 'material' + | 'patient' + | 'personnel' + | 'vehicle', elementToBeAddedId: droppedElement.id, }, true diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts index 313ef2a29..c003671f1 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-lines-feature-manager.ts @@ -15,6 +15,8 @@ import { selectTransferLines } from 'src/app/state/application/selectors/exercis import { selectCurrentRole } from 'src/app/state/application/selectors/shared.selectors'; import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type OlMap from 'ol/Map'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { TransferLinesService } from '../../core/transfer-lines.service'; import type { FeatureManager } from '../utility/feature-manager'; import type { OlMapInteractionsManager } from '../utility/ol-map-interactions-manager'; @@ -115,7 +117,7 @@ export class TransferLinesFeatureManager ) {} onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts index 251882e74..fafe48c84 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/transfer-point-feature-manager.ts @@ -1,6 +1,7 @@ import type { NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { UUID } from 'digital-fuesim-manv-shared'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { UUID, Element } from 'digital-fuesim-manv-shared'; import { TransferPoint, TransferStartPoint } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; @@ -89,12 +90,11 @@ export class TransferPointFeatureManager extends MoveableFeatureManager, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { // TODO: droppedElement isn't necessarily a transfer point -> fix getElementFromFeature typings - const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnTransferPoint = this.getElementFromFeature( droppedOnFeature ) as TransferPoint; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts index 2f1e8284c..aa8fb8675 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/feature-managers/vehicle-feature-manager.ts @@ -1,6 +1,11 @@ import type { Type, NgZone } from '@angular/core'; import type { Store } from '@ngrx/store'; -import type { UUID, Vehicle } from 'digital-fuesim-manv-shared'; +import type { + UUID, + Vehicle, + // eslint-disable-next-line @typescript-eslint/no-shadow + Element, +} from 'digital-fuesim-manv-shared'; import { normalZoom } from 'digital-fuesim-manv-shared'; import type { Feature, MapBrowserEvent } from 'ol'; import type Point from 'ol/geom/Point'; @@ -74,11 +79,10 @@ export class VehicleFeatureManager extends MoveableFeatureManager { } public override onFeatureDrop( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) { - const droppedElement = this.getElementFromFeature(droppedFeature); const droppedOnVehicle = this.getElementFromFeature( droppedOnFeature ) as Vehicle; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts index 0f225b23e..008f84c82 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/feature-manager.ts @@ -5,6 +5,8 @@ import type { TranslateEvent } from 'ol/interaction/Translate'; import type VectorLayer from 'ol/layer/Vector'; import type VectorSource from 'ol/source/Vector'; import type { Subject } from 'rxjs'; +// eslint-disable-next-line @typescript-eslint/no-shadow +import type { Element } from 'digital-fuesim-manv-shared'; import type { OlMapInteractionsManager } from './ol-map-interactions-manager'; import type { OpenPopupOptions } from './popup-manager'; @@ -41,7 +43,7 @@ export interface FeatureManager { * @returns wether the event should not propagate further (to the features behind {@link droppedOnFeature}). */ onFeatureDrop: ( - droppedFeature: Feature, + droppedElement: Element, droppedOnFeature: Feature, dropEvent?: TranslateEvent ) => boolean; diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts index f5b004bd7..a942112f7 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-interactions-manager.ts @@ -15,6 +15,7 @@ import { selectStateSnapshot } from 'src/app/state/get-state-snapshot'; import type { ExerciseStatus, Role } from 'digital-fuesim-manv-shared'; import type { TranslateEvent } from 'ol/interaction/Translate'; import type { Pixel } from 'ol/pixel'; +import { featureElementKey } from '../feature-managers/element-manager'; import { TranslateInteraction } from './translate-interaction'; import type { PopupManager } from './popup-manager'; import type { FeatureManager } from './feature-manager'; @@ -162,16 +163,20 @@ export class OlMapInteractionsManager { return this.layerFeatureManagerDictionary .get(layer as VectorLayer)! .onFeatureDrop( - droppedFeature, + this.getElementFromFeature(droppedFeature), droppedOnFeature as Feature, event ); }); } - public getOlViewportElement(): HTMLElement { + private getOlViewportElement(): HTMLElement { return this.olMap .getTargetElement() .querySelectorAll('.ol-viewport')[0] as HTMLElement; } + + private getElementFromFeature(feature: Feature) { + return feature.get(featureElementKey); + } } diff --git a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts index 81ce4296d..d04cb7d0e 100644 --- a/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts +++ b/frontend/src/app/pages/exercises/exercise/shared/exercise-map/utility/ol-map-manager.ts @@ -58,7 +58,7 @@ export class OlMapManager { * featureManager.layer === layer * ``` */ - private readonly layerFeatureManagerDictionary = new Map< + public readonly layerFeatureManagerDictionary = new Map< VectorLayer, FeatureManager >(); diff --git a/shared/src/models/index.ts b/shared/src/models/index.ts index 74aa9d853..555a44389 100644 --- a/shared/src/models/index.ts +++ b/shared/src/models/index.ts @@ -16,3 +16,4 @@ export { VehicleTemplate } from './vehicle-template'; export { Viewport } from './viewport'; export { PatientCategory } from './patient-category'; export { SimulatedRegion } from './simulated-region'; +export { Element } from './element'; From 38b9d166ca5cd84532c7f3a3ecb0970af676e8ad Mon Sep 17 00:00:00 2001 From: benn02 <82985280+benn02@users.noreply.github.com> Date: Thu, 16 Feb 2023 13:51:50 +0100 Subject: [PATCH 37/58] Add our names to the readme (#672) --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 946347136..c1139d1f9 100644 --- a/README.md +++ b/README.md @@ -287,6 +287,83 @@ If you need to read from the state to change it, you should do this inside the a + + + + + +
    + + +
    + Lukas Hagen +
    +
    + 💻 + 👀 +
    + Student 2022/23 +
    + + +
    + Nils Hanff +
    +
    + 💻 + 👀 +
    + Student 2022/23 +
    + + +
    + Benildur Nickel +
    +
    + 💻 + 👀 +
    + Student 2022/23 +
    + + +
    + Lukas Radermacher +
    +
    + 💻 + 👀 +
    + Student 2022/23 +
    Student 2021/22
    📆
    - Supervisor 2021/22 + Supervisor 2021-23
    @@ -388,7 +466,7 @@ If you need to read from the state to change it, you should do this inside the a
    📆
    - Supervisor 2021/22 + Supervisor 2021-23
    From 618c012fe2e595c16c069a56221852fa34d99e23 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:21:51 +0100 Subject: [PATCH 38/58] Use @noble/hashes instead of hash.js (#674) * Use @noble/hashes instead of hash.js * Fix install:all script --- backend/package-lock.json | 1 + benchmark/package-lock.json | 1 + frontend/package-lock.json | 1 + package.json | 2 +- shared/package-lock.json | 30 +++++++++++------------ shared/package.json | 2 +- shared/src/simulation/utils/randomness.ts | 13 +++------- 7 files changed, 22 insertions(+), 28 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 1591bd3e5..e44b1d144 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -50,6 +50,7 @@ "name": "digital-fuesim-manv-shared", "version": "0.0.0", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "immer": "^9.0.17", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 29bab06b0..5bb47b942 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -34,6 +34,7 @@ "name": "digital-fuesim-manv-shared", "version": "0.0.0", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "immer": "^9.0.17", diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7f2aca405..d7cf60e67 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -69,6 +69,7 @@ "name": "digital-fuesim-manv-shared", "version": "0.0.0", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", "immer": "^9.0.17", diff --git a/package.json b/package.json index edd68ae4c..ffa3fdcee 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "cy:ci": "cd frontend && npm run cy:run", "cy:install": "cd frontend && npm run cy:install", "benchmark": "cd benchmark && npm run benchmark", - "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmarks && npm i --install-links=false\"", + "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", "prune": "npm prune && cd shared && npm prune && cd ../frontend && npm prune && cd ../backend && npm prune", "prune:deployment": "npm prune --production && cd shared && npm prune --production && cd ../backend && npm prune --production", diff --git a/shared/package-lock.json b/shared/package-lock.json index 61469266e..f7aea2406 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -8,9 +8,9 @@ "name": "digital-fuesim-manv-shared", "version": "0.0.0", "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "hash.js": "^1.1.7", "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", @@ -1190,6 +1190,17 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3561,15 +3572,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -3675,7 +3677,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/internal-slot": { "version": "1.0.4", @@ -4831,11 +4834,6 @@ "node": ">=4" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", diff --git a/shared/package.json b/shared/package.json index d9bf5553a..6a78196a4 100644 --- a/shared/package.json +++ b/shared/package.json @@ -25,9 +25,9 @@ "npm": ">=8" }, "dependencies": { + "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", - "hash.js": "^1.1.7", "immer": "^9.0.17", "lodash-es": "^4.17.21", "rbush": "^3.0.1", diff --git a/shared/src/simulation/utils/randomness.ts b/shared/src/simulation/utils/randomness.ts index 6e4d8ad1f..3fd7a431d 100644 --- a/shared/src/simulation/utils/randomness.ts +++ b/shared/src/simulation/utils/randomness.ts @@ -1,6 +1,6 @@ /* eslint-disable no-bitwise */ import { IsInt, Min, ValidateIf } from 'class-validator'; -import hash from 'hash.js'; +import { sha256 } from '@noble/hashes/sha256'; import { v4 } from 'uuid'; import { getCreate } from '../../models/utils'; import type { ExerciseState } from '../../state'; @@ -62,16 +62,9 @@ export function nextInt( * @param draftState The exercise state where the pseudo random number generator state is stored * @returns An array of length 32 (specific to sha256) of numbers from 0-255 */ -function advance(draftState: Mutable): number[] { +function advance(draftState: Mutable): Uint8Array { const state = draftState.randomState; - - const result = hash - .sha256() - .update(draftState.id) - .update(state.counter.toString()) - .digest() - .map((b) => b & 0xff); - + const result = sha256(`${draftState.id}${state.counter.toString()}`); state.counter++; return result; } From 2a1307038b9bab3e73238b7d8296321b3f74cb82 Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 13:48:19 +0100 Subject: [PATCH 39/58] Add release workflow --- .github/update-version.sh | 19 +++++++++ .github/workflows/create-release-pr.yml | 56 +++++++++++++++++++++++++ .github/workflows/pipeline.yml | 35 +++++++++++++++- CHANGELOG.md | 20 +++++++++ README.md | 44 +++++++++++++------ docs/swagger.yml | 2 - package.json | 3 +- 7 files changed, 163 insertions(+), 16 deletions(-) create mode 100644 .github/update-version.sh create mode 100644 .github/workflows/create-release-pr.yml create mode 100644 CHANGELOG.md diff --git a/.github/update-version.sh b/.github/update-version.sh new file mode 100644 index 000000000..ffd29e790 --- /dev/null +++ b/.github/update-version.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +function update_package() { + local tmpfile=`mktemp` + jq -M --indent 4 ".version = \"$2\"" "$1" > "$tmpfile" + cat "$tmpfile" > "$1" +} + +function update_swagger() { + yq eval --no-colors --indent 4 --inplace --output-format yaml ".info.version = \"$2\"" "$1" +} + +update_package "package.json" "$1" +update_package "shared/package.json" "$1" +update_package "frontend/package.json" "$1" +update_package "backend/package.json" "$1" +update_package "benchmark/package.json" "$1" + +update_swagger "docs/swagger.yml" "$1" diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml new file mode 100644 index 000000000..6a614f6bb --- /dev/null +++ b/.github/workflows/create-release-pr.yml @@ -0,0 +1,56 @@ +name: Create Release PRs + +on: + workflow_dispatch: + inputs: + versionName: + description: 'Name of version (i.e. 1.2.3)' + required: true + +jobs: + create-release: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@v3 + - name: Create release branch + run: git checkout -b release/v${{ github.event.inputs.versionName }} + - name: Initialize git config + run: | + git config user.name "GitHub Actions" + git config user.email noreply@github.com + - name: Update version in packages + run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" + - name: Update versions in package-locks + run: npm run setup:package-lock-only + - name: Update Changelog + uses: thomaseizinger/keep-a-changelog-new-release@v1 + with: + version: v${{ github.event.inputs.versionName }} + - name: Commit packages and changelog + run: | + git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" + - name: Push new branch + run: git push origin release/v${{ github.event.inputs.versionName }} + - name: Create pull request into main + uses: thomaseizinger/create-pull-request@1.3.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + head: release/v${{ github.event.inputs.versionName }} + base: main + title: Release v${{ github.event.inputs.versionName }} + reviewers: ${{ github.event.issue.user.login }} + body: | + This PR was created in response to a running workflow. + I've updated the version name and changelog. + - name: Create pull request into dev + uses: thomaseizinger/create-pull-request@1.3.0 + with: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + head: release/v${{ github.event.inputs.versionName }} + base: dev + title: Release v${{ github.event.inputs.versionName }} into dev + reviewers: ${{ github.event.issue.user.login }} + body: | + This PR was created in response to a running workflow. + I've updated the version name and changelog. diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 7d62bd3cd..0ddf4af51 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -353,6 +353,10 @@ jobs: lfs: 'true' - name: checkoutLFS uses: actions/checkout@v3 + - name: Extract version + run: | + versionName=`jq -jM .version package.json` + echo "version_name=$versionName" >> "$GITHUB_ENV" - run: git lfs pull # Source: https://docs.docker.com/ci-cd/github-actions/ - name: Login to docker @@ -366,4 +370,33 @@ jobs: context: . file: docker/Dockerfile push: true - tags: ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:latest + tags: ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:latest , ${{ secrets.DOCKER_HUB_USERNAME }}/dfm:${{ env.version_name }} + + release-main: + timeout-minutes: 2 + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/main' + needs: [test, cypress] + steps: + - uses: actions/checkout@v3 + - name: Initialize mandatory git config + run: | + git config user.name "GitHub Actions" + git config user.email noreply@github.com + - name: Extract version + run: | + versionName=`jq -jM .version package.json` + echo "VERSION_NAME=$versionName" >> "$GITHUB_ENV" + - name: Extract release notes + id: extract_release_notes + uses: ffurrer2/extract-release-notes@v1 + - name: Create Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: v${{ env.VERSION_NAME }} + release_name: v${{ env.VERSION_NAME }} + body: ${{ steps.extract_release_notes.outputs.release_notes }} + draft: false + prerelease: false diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..8e9a3bb88 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project does **not** adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- TODO + +### Changed + +- TODO + +### Fixed + +- TODO diff --git a/README.md b/README.md index c1139d1f9..9a48e082b 100644 --- a/README.md +++ b/README.md @@ -180,7 +180,27 @@ Look at the [benchmark readme](./benchmark/README.md) for more information. // TODO [typescript@>=4.9]: Use satisfies https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html#the-satisfies-operator ``` -# Architecture +## Releases + +### Versions + +Version numbers follow the pattern `${major}.${minor}.${patch}`. `major`, `minor` and `patch` are decimal numbers without leading zeroes, similar to [SemVer](https://semver.org/). But since we do not have a public API, we do not adhere to SemVer. +The major version is updated for breaking changes, i.e. old state exports of configured exercises that have never been started, cannot be imported. +The minor version is updated with every release on `main`. State exports of configured exercises from older minor versions that have never been started must successfully import and started exercises should be importable and behave consistently with older versions, although this is not strictly required. +The patch versions is incremented if and only if critical issues on `main` are being fixed during a milestone. + +Every time a part of the version number is updated, all numbers to the right are reset to zero. +For each new release, pull requests both to `main` and `dev` are created from the same `release/` branch. For scheduled releases, such PRs are created by the `Create Release PR` workflow. + +### Workflows + +With every significant PR into `dev`, the change must be briefly described in [CHANGELOG.md](./CHANGELOG.md). Pay attention to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +The `Create Release PR` workflow accepts a new version number and prepares two PRs, one into `dev` and one into `main`. It also updates the version number in all relevant source files and moves the `Unreleased` section in [CHANGELOG.md](./CHANGELOG.md) to a release heading, creating a new `Unreleased` section. + +Upon pushing to `main` or `dev`, GitHub Actions will build and push docker containers to Docker Hub tagged `latest` and `dev`. `latest` is additionally tagged with the current version number on `main` and a GitHub release is created. + +## Architecture This repository is a monorepo that consists of the following packages: @@ -193,31 +213,31 @@ Each package has its own `README.md` file with additional documentation. Please One server can host multiple _exercises_. Multiple clients can join an exercise. A client can only join one exercise at a time. -## State management and synchronization +### State management and synchronization This is a real-time application. Each client is connected to the server via a [WebSocket connection](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). This means you can send and listen for events over a two-way communication channel. Via [socket.io](https://socket.io/docs) it is also possible to make use of a more classic request-response API via [acknowledgments](https://socket.io/docs/v4/emitting-events/#acknowledgements). -### State, actions and reducers +#### State, actions and reducers We borrow these core concepts from [Redux](https://redux.js.org/). -#### What is an immutable JSON object? +##### What is an immutable JSON object? A JSON object is an object whose properties are only the primitives `string`, `number`, `boolean` or `null` or another JSON object or an array of any of these (only state - no `functions`). Any object reference can't occur more than once anywhere in a JSON object (including nested objects). This means especially that no circular references are possible. [An immutable object is an object whose state cannot be modified after it is created](https://en.wikipedia.org/wiki/Immutable_object). In the code immutability is conveyed via typescripts [readonly](https://www.typescriptlang.org/docs/handbook/2/objects.html#readonly-properties) and the helper type `Immutable`. -#### State +##### State A state is an immutable JSON object. Each client as well as the server has a global state for an exercise. The single point of truth for all states of an exercise is the server. All these states should be synchronized. You can find the exercise state [here](./shared/src/state.ts). -#### Action +##### Action An action is an immutable JSON object that describes what should change in a state. The changes described by each action are [atomic]() - this means either all or none of the changes described by an action are applied. @@ -225,7 +245,7 @@ Actions cannot be applied in parallel. The order of actions is important. It is a bad practice to encode part of the state in the action (or values derived/calculated from it). Instead, you should only read the state in the accompanying reducer. -#### Reducer +##### Reducer A reducer is a [pure function](https://en.wikipedia.org/wiki/Pure_function) (no side effects!) that takes a state and an action of a specific type and returns a new state where the changes described in the action are applied. A state can only be modified by a reducer. @@ -233,7 +253,7 @@ To be able to apply certain optimizations, it is advisable (but not necessary or You can find all exercise actions and reducers [here](./shared/src/store/action-reducers). Please orient yourself on the already implemented actions, and don't forget to register them in [shared/src/store/action-reducers/action-reducers.ts](shared/src/store/action-reducers/action-reducers.ts) -### Immutability +#### Immutability It isn't necessary to copy the whole immutable object by value if it should be updated. Instead, only the objects that were modified should be shallow copied recursively. [Immer](https://immerjs.github.io/immer/) provides a simple way to do this. @@ -242,7 +262,7 @@ Because the state is immutable and reducers (should) only update the properties To save a state it is enough to save its reference. Therefore it is very performant as well. If the state would have to be changed, a new reference is created as the state is immutable. -### Large values (WIP) +#### Large values (WIP) Large values (images, large text, binary, etc.) are not directly stored in the state. Instead, the store only contains UUIDs that identify the blob. The blob can be retrieved via a separate (yet to be implemented) REST API. @@ -252,7 +272,7 @@ If an action would add a new blobId to the state, the blob should have previousl A blob should only be downloaded on demand (lazy) and cached. -### Synchronisation +#### Synchronisation 1. A client gets a snapshot of the state from the server via `getState`. 2. Any time an action is applied on the server, it is sent to all clients via `performAction` and applied to them too. Due to the maintained packet ordering via a WebSocket and the fact that the synchronization of the state in the backend works synchronously, it is impossible for a client to receive actions out of order or receive actions already included in the state received by `getState`. @@ -260,7 +280,7 @@ A blob should only be downloaded on demand (lazy) and cached. 4. If the proposal was accepted, the action is applied on the server and sent to all clients via `performAction`. 5. The server responds to a proposal with a response that indicates a success or rejection via an [acknowledgment](https://socket.io/docs/v4/emitting-events/#acknowledgements). A successful response is always sent after the `performAction` was broadcasted. -### Optimistic updates +#### Optimistic updates A consequence of the synchronization strategy described before is that it takes one roundtrip from the client to the server and back to get the correct state on the client that initiated the action. This can lead to a bad user experience because of high latency. @@ -272,7 +292,7 @@ The state in the frontend is not guaranteed to be correct. It is only guaranteed If you need to read from the state to change it, you should do this inside the action reducer because the `currentState` passed into a reducer is always guaranteed to be correct. -### Performance considerations +#### Performance considerations - Currently, every client maintains the whole state, and every action is sent to all clients. There is no way to only subscribe to a part of the state and only receive updates for that part. diff --git a/docs/swagger.yml b/docs/swagger.yml index 9e5d85c9f..16a945307 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -38,7 +38,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' - /api/exercise/{exerciseId}: parameters: - $ref: '#/components/parameters/ExerciseId' @@ -68,7 +67,6 @@ paths: application/json: schema: $ref: '#/components/schemas/ErrorResponse' - /api/exercise/{exerciseId}/history: parameters: - $ref: '#/components/parameters/ExerciseId' diff --git a/package.json b/package.json index edd68ae4c..65c4c36b3 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,9 @@ "cy:ci": "cd frontend && npm run cy:run", "cy:install": "cd frontend && npm run cy:install", "benchmark": "cd benchmark && npm run benchmark", - "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmarks && npm i --install-links=false\"", + "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", + "setup:package-lock-only": "npm i --package-lock-only && cd shared && npm i --package-lock-only && cd ../frontend && npm i --package-lock-only && cd ../backend && npm i --package-lock-only && cd ../benchmark && npm i --package-lock-only", "prune": "npm prune && cd shared && npm prune && cd ../frontend && npm prune && cd ../backend && npm prune", "prune:deployment": "npm prune --production && cd shared && npm prune --production && cd ../backend && npm prune --production", "deployment": "npm run setup:ci && npm run build:deployment && npm run prune:deployment", From d564efe5fe99092f1109e58f63259a2d61e68e2d Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 14:18:29 +0100 Subject: [PATCH 40/58] Populate CHANGELOG.md --- CHANGELOG.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e9a3bb88..67007d0ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,26 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ### Added -- TODO +- A new team of contributors joined the project! +- Even better, we are happy to welcome a new partner: Johanniter Akademie NRW, Campus Münster der Johanniter-Unfall-Hilfe e.V. (JUH). +- Simulated regions are new elements on the map that behave similar to viewports. + - They have a flexible simulation framework for defining behaviors. + - These can contain personnel, vehicles, material and patients. +- Added customizable pages for imprint and privacy notice. +- The frontend now displays the current software version and shows a feedback button on most pages. +- Added [CHANGELOG.md](./CHANGELOG.md), a [release and versioning guide](./README.md#releases) and release actions. ### Changed -- TODO +- Elements that are dragged to the map can be deleted or added to a transfer point directly instead of having to drop and move them. +- Various internal refactoring: + - Marked VS Code configs as examples. + - Introduced uniform abstract representation for positions. + - Added property for type distinction to all objects in the state. + - Moved lots of functionality from `OlMapManager` to feature managers. ### Fixed -- TODO +- Moving the map no longer closes popups but can be closed with ESC. +- Minor dependency updates +- Updated deprecated actions From 493f479d2202c9d9dd7fe790d6d6066b2b293ad9 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:34:54 +0100 Subject: [PATCH 41/58] Update create-release-pr.yml --- .github/workflows/create-release-pr.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 6a614f6bb..4483293a9 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -10,6 +10,9 @@ on: jobs: create-release: runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write steps: - name: Check out code uses: actions/checkout@v3 From 7908fccc27ce7e89d05ed9c4be186d33c92601f4 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:39:17 +0100 Subject: [PATCH 42/58] trigger pipeline --- .github/workflows/create-release-pr.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 4483293a9..49d93a4b3 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -57,3 +57,4 @@ jobs: body: | This PR was created in response to a running workflow. I've updated the version name and changelog. + From d18f2a25b6d12364be70c2e5638901fa0b6cde3d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 15:58:09 +0100 Subject: [PATCH 43/58] Prepare release v0.0.1-review (#3) Co-authored-by: GitHub Actions --- CHANGELOG.md | 6 ++ backend/package-lock.json | 114 +++++++++++++++++----------- backend/package.json | 2 +- benchmark/package-lock.json | 143 +++++++++++++++++++++++++----------- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 92 ++++++++++++----------- frontend/package.json | 2 +- package-lock.json | 4 +- package.json | 2 +- shared/package-lock.json | 4 +- shared/package.json | 2 +- 12 files changed, 242 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67007d0ca..fa3d416ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ## [Unreleased] +## [v0.0.1-review] - 2023-02-22 + ### Added - A new team of contributors joined the project! @@ -32,3 +34,7 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org - Moving the map no longer closes popups but can be closed with ESC. - Minor dependency updates - Updated deprecated actions + +[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v0.0.1-review...HEAD + +[v0.0.1-review]: https://github.com/Nils1729/digital-fuesim-manv/compare/7908fccc27ce7e89d05ed9c4be186d33c92601f4...v0.0.1-review diff --git a/backend/package-lock.json b/backend/package-lock.json index e44b1d144..ce267b506 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "0.0.1-review", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "0.0.1-review", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -46,43 +46,6 @@ "npm": ">=8" } }, - "../shared": { - "name": "digital-fuesim-manv-shared", - "version": "0.0.0", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "devDependencies": { - "@types/jest": "^29.2.5", - "@types/lodash-es": "^4.17.6", - "@types/rbush": "^3.0.0", - "@types/uuid": "^9.0.0", - "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.48.1", - "@typescript-eslint/parser": "5.48.1", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.6.0", - "eslint-plugin-import": "~2.27.4", - "eslint-plugin-total-functions": "6.0.0", - "eslint-plugin-unicorn": "^45.0.2", - "jest": "^29.3.1", - "ts-jest": "^29.0.5", - "ts-node": "^10.9.1", - "typescript": "~4.9.4" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } - }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -1232,6 +1195,17 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2787,8 +2761,31 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "resolved": "../shared", - "link": true + "version": "0.0.1-review", + "resolved": "file:../shared", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "node_modules/digital-fuesim-manv-shared/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } }, "node_modules/dir-glob": { "version": "3.0.1", @@ -4066,6 +4063,15 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, + "node_modules/immer": { + "version": "9.0.19", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", + "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6132,6 +6138,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/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6154,6 +6165,22 @@ "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/rbush-knn": { + "version": "3.0.1", + "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", + "license": "ISC", + "dependencies": { + "tinyqueue": "^2.0.3" + } + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -7018,6 +7045,11 @@ "node": ">=0.8" } }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/backend/package.json b/backend/package.json index 40b4aaeb0..1b5386d7e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.0", + "version": "0.0.1-review", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 5bb47b942..71408bb32 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.0", + "version": "0.0.1-review", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.0", + "version": "0.0.1-review", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", @@ -30,43 +30,6 @@ "npm": ">=8" } }, - "../shared": { - "name": "digital-fuesim-manv-shared", - "version": "0.0.0", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "devDependencies": { - "@types/jest": "^29.2.5", - "@types/lodash-es": "^4.17.6", - "@types/rbush": "^3.0.0", - "@types/uuid": "^9.0.0", - "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.48.1", - "@typescript-eslint/parser": "5.48.1", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.6.0", - "eslint-plugin-import": "~2.27.4", - "eslint-plugin-total-functions": "6.0.0", - "eslint-plugin-unicorn": "^45.0.2", - "jest": "^29.3.1", - "ts-jest": "^29.0.5", - "ts-node": "^10.9.1", - "typescript": "~4.9.4" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } - }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -281,6 +244,17 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -385,6 +359,11 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, + "node_modules/@types/validator": { + "version": "13.7.12", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.12.tgz", + "integrity": "sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.48.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", @@ -1098,6 +1077,21 @@ "node": ">=8" } }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" + }, + "node_modules/class-validator": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", + "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", + "dependencies": { + "@types/validator": "^13.7.10", + "libphonenumber-js": "^1.10.14", + "validator": "^13.7.0" + } + }, "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -1212,8 +1206,23 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "resolved": "../shared", - "link": true + "version": "0.0.1-review", + "resolved": "file:../shared", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } }, "node_modules/dir-glob": { "version": "3.0.1", @@ -2433,6 +2442,11 @@ "node": ">= 0.8.0" } }, + "node_modules/libphonenumber-js": { + "version": "1.10.20", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.20.tgz", + "integrity": "sha512-kQovlKNdLcVzerbTPmJ+Fx4R+7/pYXmPDIllHjg7IxL4X6MsMG7jaT5opfYrBok0uqkByVif//JUR8e11l/V7w==" + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -2829,6 +2843,27 @@ } ] }, + "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/rbush-knn": { + "version": "3.0.1", + "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", + "license": "ISC", + "dependencies": { + "tinyqueue": "^2.0.3" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -2931,6 +2966,11 @@ "node": ">=8" } }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + }, "node_modules/regexp-tree": { "version": "0.1.24", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", @@ -3272,6 +3312,11 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3430,6 +3475,14 @@ "punycode": "^2.1.0" } }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -3446,6 +3499,14 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validator": { + "version": "13.9.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", + "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/benchmark/package.json b/benchmark/package.json index 230d96dcf..e8a9b9621 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.0", + "version": "0.0.1-review", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 16a945307..0146e2607 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 0.0.0 + version: 0.0.1-review paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index d7cf60e67..29890b5d2 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", + "version": "0.0.1-review", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", + "version": "0.0.1-review", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", @@ -65,43 +65,6 @@ "npm": ">=8" } }, - "../shared": { - "name": "digital-fuesim-manv-shared", - "version": "0.0.0", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "devDependencies": { - "@types/jest": "^29.2.5", - "@types/lodash-es": "^4.17.6", - "@types/rbush": "^3.0.0", - "@types/uuid": "^9.0.0", - "@types/validator": "^13.7.10", - "@typescript-eslint/eslint-plugin": "5.48.1", - "@typescript-eslint/parser": "5.48.1", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.6.0", - "eslint-plugin-import": "~2.27.4", - "eslint-plugin-total-functions": "6.0.0", - "eslint-plugin-unicorn": "^45.0.2", - "jest": "^29.3.1", - "ts-jest": "^29.0.5", - "ts-node": "^10.9.1", - "typescript": "~4.9.4" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } - }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "license": "Apache-2.0", @@ -4571,6 +4534,17 @@ "webpack": "^5.54.0" } }, + "node_modules/@noble/hashes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", + "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -8052,8 +8026,31 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "resolved": "../shared", - "link": true + "version": "0.0.1-review", + "resolved": "file:../shared", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, + "node_modules/digital-fuesim-manv-shared/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } }, "node_modules/dir-glob": { "version": "3.0.1", @@ -14990,6 +14987,14 @@ "quickselect": "^2.0.0" } }, + "node_modules/rbush-knn": { + "version": "3.0.1", + "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", + "license": "ISC", + "dependencies": { + "tinyqueue": "^2.0.3" + } + }, "node_modules/react-is": { "version": "18.2.0", "dev": true, @@ -16669,6 +16674,11 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "node_modules/tinyqueue": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", + "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" + }, "node_modules/tmp": { "version": "0.2.1", "dev": true, diff --git a/frontend/package.json b/frontend/package.json index 4907091ed..cc20a3bdf 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.0", + "version": "0.0.1-review", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index 22516552f..92342e157 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "0.0.1-review", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "0.0.1-review", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 65c4c36b3..88ae3663e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "0.0.0", + "version": "0.0.1-review", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index f7aea2406..1cd64c52e 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "0.0.1-review", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "0.0.1-review", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 6a78196a4..23dfcce15 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.0", + "version": "0.0.1-review", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From a741b9cee67c2bfd0c6e14e3b8fb490249a53905 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:12:14 +0100 Subject: [PATCH 44/58] Prepare release v123-test (#5) Co-authored-by: GitHub Actions --- CHANGELOG.md | 6 +++++- backend/package-lock.json | 4 ++-- backend/package.json | 2 +- benchmark/package-lock.json | 4 ++-- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 12 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa3d416ec..21ecf560a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ## [Unreleased] +## [v123-test] - 2023-02-22 + ## [v0.0.1-review] - 2023-02-22 ### Added @@ -35,6 +37,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org - Minor dependency updates - Updated deprecated actions -[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v0.0.1-review...HEAD +[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v123-test...HEAD + +[v123-test]: https://github.com/Nils1729/digital-fuesim-manv/compare/v0.0.1-review...v123-test [v0.0.1-review]: https://github.com/Nils1729/digital-fuesim-manv/compare/7908fccc27ce7e89d05ed9c4be186d33c92601f4...v0.0.1-review diff --git a/backend/package-lock.json b/backend/package-lock.json index ce267b506..c6b3e2db3 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.1-review", + "version": "123-test", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "0.0.1-review", + "version": "123-test", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", diff --git a/backend/package.json b/backend/package.json index 1b5386d7e..b35e11082 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "0.0.1-review", + "version": "123-test", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 71408bb32..a571cd1f8 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.1-review", + "version": "123-test", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.1-review", + "version": "123-test", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", diff --git a/benchmark/package.json b/benchmark/package.json index e8a9b9621..d0c1bd81f 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "0.0.1-review", + "version": "123-test", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 0146e2607..e4a91e4f5 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 0.0.1-review + version: 123-test paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 29890b5d2..6405f0b35 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.1-review", + "version": "123-test", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "0.0.1-review", + "version": "123-test", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", diff --git a/frontend/package.json b/frontend/package.json index cc20a3bdf..d267b963f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "0.0.1-review", + "version": "123-test", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index 92342e157..865337f87 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "0.0.1-review", + "version": "123-test", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "0.0.1-review", + "version": "123-test", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 88ae3663e..b73f95392 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "0.0.1-review", + "version": "123-test", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index 1cd64c52e..a4b5ae33b 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.1-review", + "version": "123-test", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "0.0.1-review", + "version": "123-test", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 23dfcce15..ebc16316b 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "0.0.1-review", + "version": "123-test", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 27aa83d4f9566dd2324373e1b3923570991ccd99 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:33:33 +0100 Subject: [PATCH 45/58] Prepare release v1.2.3-test2 (#7) Co-authored-by: GitHub Actions --- CHANGELOG.md | 6 +++++- backend/package-lock.json | 4 ++-- backend/package.json | 2 +- benchmark/package-lock.json | 4 ++-- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 12 files changed, 21 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21ecf560a..e8e2c4b88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ## [Unreleased] +## [v1.2.3-test2] - 2023-02-22 + ## [v123-test] - 2023-02-22 ## [v0.0.1-review] - 2023-02-22 @@ -37,7 +39,9 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org - Minor dependency updates - Updated deprecated actions -[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v123-test...HEAD +[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v1.2.3-test2...HEAD + +[v1.2.3-test2]: https://github.com/Nils1729/digital-fuesim-manv/compare/v123-test...v1.2.3-test2 [v123-test]: https://github.com/Nils1729/digital-fuesim-manv/compare/v0.0.1-review...v123-test diff --git a/backend/package-lock.json b/backend/package-lock.json index c6b3e2db3..82b3880cf 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "123-test", + "version": "1.2.3-test2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "123-test", + "version": "1.2.3-test2", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", diff --git a/backend/package.json b/backend/package.json index b35e11082..07210e86d 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "123-test", + "version": "1.2.3-test2", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index a571cd1f8..811c86af6 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "123-test", + "version": "1.2.3-test2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "123-test", + "version": "1.2.3-test2", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", diff --git a/benchmark/package.json b/benchmark/package.json index d0c1bd81f..69b1f9e1b 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "123-test", + "version": "1.2.3-test2", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index e4a91e4f5..bd59c960e 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 123-test + version: 1.2.3-test2 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 6405f0b35..a50b3a003 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "123-test", + "version": "1.2.3-test2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "123-test", + "version": "1.2.3-test2", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", diff --git a/frontend/package.json b/frontend/package.json index d267b963f..580d99493 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "123-test", + "version": "1.2.3-test2", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index 865337f87..2af73de21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "123-test", + "version": "1.2.3-test2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "123-test", + "version": "1.2.3-test2", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index b73f95392..2dcc9c2b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "123-test", + "version": "1.2.3-test2", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index a4b5ae33b..38ebebd0e 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "123-test", + "version": "1.2.3-test2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "123-test", + "version": "1.2.3-test2", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index ebc16316b..049c5e197 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "123-test", + "version": "1.2.3-test2", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 5097d1b4cc90aa5266101ac1dc742192276bd1e2 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:45:14 +0100 Subject: [PATCH 46/58] Update create-release-pr.yml debug --- .github/workflows/create-release-pr.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 49d93a4b3..a16b35021 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -31,8 +31,9 @@ jobs: with: version: v${{ github.event.inputs.versionName }} - name: Commit packages and changelog - run: | - git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" + run: git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" + - name: debug setup + run: npm run setup:ci - name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} - name: Create pull request into main From 0ac415a652f2f61bf4bcb4f79f9cda8bb34fded4 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:51:13 +0100 Subject: [PATCH 47/58] Update create-release-pr.yml debug --- .github/workflows/create-release-pr.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index a16b35021..e29d5cce0 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -26,13 +26,11 @@ jobs: run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" - name: Update versions in package-locks run: npm run setup:package-lock-only - - name: Update Changelog - uses: thomaseizinger/keep-a-changelog-new-release@v1 - with: - version: v${{ github.event.inputs.versionName }} - name: Commit packages and changelog run: git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" - - name: debug setup + - name: debug setup 1 + run: npm run setup:ci + - name: debug setup 2 run: npm run setup:ci - name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} From c851a3795e5ccb94ea65a3fc318929154c6f39c1 Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:55:48 +0100 Subject: [PATCH 48/58] debug --- .github/workflows/create-release-pr.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index e29d5cce0..b588d7b8f 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -26,12 +26,12 @@ jobs: run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" - name: Update versions in package-locks run: npm run setup:package-lock-only + - name: Debug commit + run: git commit -a --message "Debug v${{ github.event.inputs.versionName }}" + - name: debug setup + run: npm run setup:ci - name: Commit packages and changelog run: git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" - - name: debug setup 1 - run: npm run setup:ci - - name: debug setup 2 - run: npm run setup:ci - name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} - name: Create pull request into main From 3e9d08c20c8ead46f183a01d81dfb159b79768eb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Feb 2023 17:57:43 +0100 Subject: [PATCH 49/58] Prepare release v1.2.3-test4 (#11) Co-authored-by: GitHub Actions --- backend/package-lock.json | 4 ++-- backend/package.json | 2 +- benchmark/package-lock.json | 4 ++-- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 82b3880cf..37809dc55 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", diff --git a/backend/package.json b/backend/package.json index 07210e86d..440167a84 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 811c86af6..40f8209e8 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", diff --git a/benchmark/package.json b/benchmark/package.json index 69b1f9e1b..218295f8d 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index bd59c960e..073ce344e 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 1.2.3-test2 + version: 1.2.3-test4 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a50b3a003..e4a014a90 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", diff --git a/frontend/package.json b/frontend/package.json index 580d99493..6d02d20f6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index 2af73de21..f74fe1a8f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 2dcc9c2b3..18cbf07ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index 38ebebd0e..5af217b8f 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 049c5e197..0c2898ca4 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test2", + "version": "1.2.3-test4", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 65bfbcea6b85d08a596c54b338fb4fbef5d0a69a Mon Sep 17 00:00:00 2001 From: Nils1729 <45318774+Nils1729@users.noreply.github.com> Date: Thu, 23 Feb 2023 08:49:19 +0100 Subject: [PATCH 50/58] diff --- .github/workflows/create-release-pr.yml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index b588d7b8f..74bd10cee 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -26,12 +26,18 @@ jobs: run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" - name: Update versions in package-locks run: npm run setup:package-lock-only - - name: Debug commit - run: git commit -a --message "Debug v${{ github.event.inputs.versionName }}" + - name: stage changes + run: git add . + - name: show changes + run: git diff --staged - name: debug setup run: npm run setup:ci - - name: Commit packages and changelog - run: git commit -a --message "Prepare release v${{ github.event.inputs.versionName }}" + - name: show changes 2 + run: | + git diff + git diff --staged + - name: Debug commit + run: git commit --message "Debug v${{ github.event.inputs.versionName }}" - name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} - name: Create pull request into main From 93b55cfde9788a85077b6a384e7c73ca43b67f4e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:13:10 +0100 Subject: [PATCH 51/58] Debug v1.2.3-test6 (#13) Co-authored-by: GitHub Actions --- backend/package-lock.json | 4 ++-- backend/package.json | 2 +- benchmark/package-lock.json | 4 ++-- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 37809dc55..1840848bd 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", diff --git a/backend/package.json b/backend/package.json index 440167a84..d632a9398 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 40f8209e8..1ed4dc1f8 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", diff --git a/benchmark/package.json b/benchmark/package.json index 218295f8d..df9b2ca5a 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 073ce344e..3735e42cc 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 1.2.3-test4 + version: 1.2.3-test6 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index e4a014a90..971f9447a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", diff --git a/frontend/package.json b/frontend/package.json index 6d02d20f6..b36fe1514 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index f74fe1a8f..d2053ee9a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 18cbf07ba..26d27ebad 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index 5af217b8f..6f3e51bca 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 0c2898ca4..1b3621b93 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test4", + "version": "1.2.3-test6", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 2cb6fea9c069a335edbe12a15cb551fb6cf8edb5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:27:24 +0100 Subject: [PATCH 52/58] Debug v1.2.3-test7 (#15) Co-authored-by: GitHub Actions --- backend/package-lock.json | 4 ++-- backend/package.json | 2 +- benchmark/package-lock.json | 4 ++-- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 4 ++-- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 1840848bd..d35659e20 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", diff --git a/backend/package.json b/backend/package.json index d632a9398..1c034fe8f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 1ed4dc1f8..e1adfd2f3 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", diff --git a/benchmark/package.json b/benchmark/package.json index df9b2ca5a..07a94ccbf 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 3735e42cc..85c653ed0 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 1.2.3-test6 + version: 1.2.3-test7 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 971f9447a..388068529 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", diff --git a/frontend/package.json b/frontend/package.json index b36fe1514..4780d6c0a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index d2053ee9a..fb8b6a5bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 26d27ebad..4c9cd021b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index 6f3e51bca..f2f77fc20 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 1b3621b93..25f18fae6 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test6", + "version": "1.2.3-test7", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 82edf73d46e1e78af29869d299aa61aa4a65bfac Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:46:18 +0100 Subject: [PATCH 53/58] Fix npm i --- .npmrc | 1 + backend/.npmrc | 1 + benchmark/.npmrc | 1 + frontend/.npmrc | 1 + package.json | 4 ++-- shared/.npmrc | 1 + 6 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .npmrc create mode 100644 backend/.npmrc create mode 100644 benchmark/.npmrc create mode 100644 frontend/.npmrc create mode 100644 shared/.npmrc diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/backend/.npmrc b/backend/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/backend/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/benchmark/.npmrc b/benchmark/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/benchmark/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/frontend/.npmrc b/frontend/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/frontend/.npmrc @@ -0,0 +1 @@ +install-links=false diff --git a/package.json b/package.json index 4c9cd021b..841f6d08b 100644 --- a/package.json +++ b/package.json @@ -9,8 +9,8 @@ "cy:ci": "cd frontend && npm run cy:run", "cy:install": "cd frontend && npm run cy:install", "benchmark": "cd benchmark && npm run benchmark", - "install:all": "npm i --install-links=false && concurrently \"cd shared && npm i --install-links=false\" \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", - "setup": "npm i --install-links=false && cd shared && npm i --install-links=false && npm run build && cd .. && concurrently \"cd frontend && npm i --install-links=false\" \"cd backend && npm i --install-links=false\" \"cd benchmark && npm i --install-links=false\"", + "install:all": "npm i && concurrently \"cd shared && npm i \" \"cd frontend && npm i \" \"cd backend && npm i \" \"cd benchmark && npm i \"", + "setup": "npm i && cd shared && npm i && npm run build && cd .. && concurrently \"cd frontend && npm i \" \"cd backend && npm i \" \"cd benchmark && npm i \"", "setup:package-lock-only": "npm i --package-lock-only && cd shared && npm i --package-lock-only && cd ../frontend && npm i --package-lock-only && cd ../backend && npm i --package-lock-only && cd ../benchmark && npm i --package-lock-only", "prune": "npm prune && cd shared && npm prune && cd ../frontend && npm prune && cd ../backend && npm prune", "prune:deployment": "npm prune --production && cd shared && npm prune --production && cd ../backend && npm prune --production", diff --git a/shared/.npmrc b/shared/.npmrc new file mode 100644 index 000000000..a6ee44b04 --- /dev/null +++ b/shared/.npmrc @@ -0,0 +1 @@ +install-links=false From 7d286534dfa043301e8adf341e96bc2e7c8450c7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 23 Feb 2023 09:49:57 +0100 Subject: [PATCH 54/58] Debug v1.2.3-test8 (#17) Co-authored-by: GitHub Actions --- backend/package-lock.json | 113 ++++++++++------------------ backend/package.json | 2 +- benchmark/package-lock.json | 142 ++++++++++-------------------------- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 91 ++++++++++------------- frontend/package.json | 2 +- package-lock.json | 4 +- package.json | 2 +- shared/package-lock.json | 4 +- shared/package.json | 2 +- 11 files changed, 130 insertions(+), 236 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index d35659e20..2002a8b76 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -46,6 +46,42 @@ "npm": ">=8" } }, + "../shared": { + "version": "1.2.3-test8", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/jest": "^29.2.5", + "@types/lodash-es": "^4.17.6", + "@types/rbush": "^3.0.0", + "@types/uuid": "^9.0.0", + "@types/validator": "^13.7.10", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "jest": "^29.3.1", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", @@ -1195,17 +1231,6 @@ "@jridgewell/sourcemap-codec": "1.4.14" } }, - "node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2761,31 +2786,8 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "version": "0.0.1-review", - "resolved": "file:../shared", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } - }, - "node_modules/digital-fuesim-manv-shared/node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } + "resolved": "../shared", + "link": true }, "node_modules/dir-glob": { "version": "3.0.1", @@ -4063,15 +4065,6 @@ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", "dev": true }, - "node_modules/immer": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.19.tgz", - "integrity": "sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -6138,11 +6131,6 @@ } ] }, - "node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" - }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -6165,22 +6153,6 @@ "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/rbush-knn": { - "version": "3.0.1", - "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", - "license": "ISC", - "dependencies": { - "tinyqueue": "^2.0.3" - } - }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -7045,11 +7017,6 @@ "node": ">=0.8" } }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", diff --git a/backend/package.json b/backend/package.json index 1c034fe8f..960eea2f1 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index e1adfd2f3..0f5280715 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", @@ -30,6 +30,42 @@ "npm": ">=8" } }, + "../shared": { + "version": "1.2.3-test8", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/jest": "^29.2.5", + "@types/lodash-es": "^4.17.6", + "@types/rbush": "^3.0.0", + "@types/uuid": "^9.0.0", + "@types/validator": "^13.7.10", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "jest": "^29.3.1", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, "node_modules/@babel/code-frame": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", @@ -244,17 +280,6 @@ "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, - "node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -359,11 +384,6 @@ "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", "dev": true }, - "node_modules/@types/validator": { - "version": "13.7.12", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.7.12.tgz", - "integrity": "sha512-YVtyAPqpefU+Mm/qqnOANW6IkqKpCSrarcyV269C8MA8Ux0dbkEuQwM/4CjL47kVEM2LgBef/ETfkH+c6+moFA==" - }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.48.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.48.1.tgz", @@ -1077,21 +1097,6 @@ "node": ">=8" } }, - "node_modules/class-transformer": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", - "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==" - }, - "node_modules/class-validator": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz", - "integrity": "sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A==", - "dependencies": { - "@types/validator": "^13.7.10", - "libphonenumber-js": "^1.10.14", - "validator": "^13.7.0" - } - }, "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -1206,23 +1211,8 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "version": "0.0.1-review", - "resolved": "file:../shared", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } + "resolved": "../shared", + "link": true }, "node_modules/dir-glob": { "version": "3.0.1", @@ -2442,11 +2432,6 @@ "node": ">= 0.8.0" } }, - "node_modules/libphonenumber-js": { - "version": "1.10.20", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.10.20.tgz", - "integrity": "sha512-kQovlKNdLcVzerbTPmJ+Fx4R+7/pYXmPDIllHjg7IxL4X6MsMG7jaT5opfYrBok0uqkByVif//JUR8e11l/V7w==" - }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -2843,27 +2828,6 @@ } ] }, - "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/rbush-knn": { - "version": "3.0.1", - "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", - "license": "ISC", - "dependencies": { - "tinyqueue": "^2.0.3" - } - }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -2966,11 +2930,6 @@ "node": ">=8" } }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" - }, "node_modules/regexp-tree": { "version": "0.1.24", "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.24.tgz", @@ -3312,11 +3271,6 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -3475,14 +3429,6 @@ "punycode": "^2.1.0" } }, - "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -3499,14 +3445,6 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/validator": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.9.0.tgz", - "integrity": "sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA==", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/benchmark/package.json b/benchmark/package.json index 07a94ccbf..69f23b91b 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index 85c653ed0..e1c4203e8 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 1.2.3-test7 + version: 1.2.3-test8 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 388068529..b052ae1e6 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", @@ -65,6 +65,42 @@ "npm": ">=8" } }, + "../shared": { + "version": "1.2.3-test8", + "dependencies": { + "@noble/hashes": "^1.2.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.0", + "immer": "^9.0.17", + "lodash-es": "^4.17.21", + "rbush": "^3.0.1", + "rbush-knn": "github:mourner/rbush-knn", + "reflect-metadata": "^0.1.13", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@types/jest": "^29.2.5", + "@types/lodash-es": "^4.17.6", + "@types/rbush": "^3.0.0", + "@types/uuid": "^9.0.0", + "@types/validator": "^13.7.10", + "@typescript-eslint/eslint-plugin": "5.48.1", + "@typescript-eslint/parser": "5.48.1", + "eslint": "^8.31.0", + "eslint-config-prettier": "^8.6.0", + "eslint-plugin-import": "~2.27.4", + "eslint-plugin-total-functions": "6.0.0", + "eslint-plugin-unicorn": "^45.0.2", + "jest": "^29.3.1", + "ts-jest": "^29.0.5", + "ts-node": "^10.9.1", + "typescript": "~4.9.4" + }, + "engines": { + "node": ">=16", + "npm": ">=8" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.0", "license": "Apache-2.0", @@ -4534,17 +4570,6 @@ "webpack": "^5.54.0" } }, - "node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, @@ -8026,31 +8051,8 @@ } }, "node_modules/digital-fuesim-manv-shared": { - "version": "0.0.1-review", - "resolved": "file:../shared", - "dependencies": { - "@noble/hashes": "^1.2.0", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.0", - "immer": "^9.0.17", - "lodash-es": "^4.17.21", - "rbush": "^3.0.1", - "rbush-knn": "github:mourner/rbush-knn", - "reflect-metadata": "^0.1.13", - "uuid": "^9.0.0" - }, - "engines": { - "node": ">=16", - "npm": ">=8" - } - }, - "node_modules/digital-fuesim-manv-shared/node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", - "bin": { - "uuid": "dist/bin/uuid" - } + "resolved": "../shared", + "link": true }, "node_modules/dir-glob": { "version": "3.0.1", @@ -14987,14 +14989,6 @@ "quickselect": "^2.0.0" } }, - "node_modules/rbush-knn": { - "version": "3.0.1", - "resolved": "git+ssh://git@github.com/mourner/rbush-knn.git#cd195a33304860bbcb0b57931080af41034a7d27", - "license": "ISC", - "dependencies": { - "tinyqueue": "^2.0.3" - } - }, "node_modules/react-is": { "version": "18.2.0", "dev": true, @@ -16674,11 +16668,6 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, "node_modules/tmp": { "version": "0.2.1", "dev": true, diff --git a/frontend/package.json b/frontend/package.json index 4780d6c0a..76fc3c99e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index fb8b6a5bc..d3d548997 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index 841f6d08b..ec40ec940 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index f2f77fc20..357958b4c 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 25f18fae6..952d7ead8 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test7", + "version": "1.2.3-test8", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js", From 5b047793af4c3bcd74d9aa58735fce8f808e8e62 Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:21:30 +0100 Subject: [PATCH 55/58] call pipeline from release --- .github/workflows/create-release-pr.yml | 29 +++++++++++++------------ .github/workflows/pipeline.yml | 4 +++- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 74bd10cee..617092340 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -8,7 +8,7 @@ on: required: true jobs: - create-release: + create-release-branch: runs-on: ubuntu-latest permissions: contents: write @@ -26,20 +26,18 @@ jobs: run: bash .github/update-version.sh "${{ github.event.inputs.versionName }}" - name: Update versions in package-locks run: npm run setup:package-lock-only - - name: stage changes - run: git add . - - name: show changes - run: git diff --staged - - name: debug setup - run: npm run setup:ci - - name: show changes 2 - run: | - git diff - git diff --staged - - name: Debug commit - run: git commit --message "Debug v${{ github.event.inputs.versionName }}" + - name: Update changelog + uses: thomaseizinger/keep-a-changelog-new-release@v1 + with: + version: v${{ github.event.inputs.versionName }} + - name: Commit updated version and changelog + run: git commit -a --message "Debug v${{ github.event.inputs.versionName }}" - name: Push new branch run: git push origin release/v${{ github.event.inputs.versionName }} + create-pull-requests: + runs-on: ubuntu-latest + needs: create-release-branch + steps: - name: Create pull request into main uses: thomaseizinger/create-pull-request@1.3.0 with: @@ -62,4 +60,7 @@ jobs: body: | This PR was created in response to a running workflow. I've updated the version name and changelog. - + run-pipeline: + needs: create-pull-requests + uses: ./.github/workflows/pipeline.yml + secrets: inherit diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 0ddf4af51..90460ff6a 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -1,6 +1,8 @@ name: Complete pipeline -on: push +on: + push: + workflow_call: jobs: build: From 085967a9628e782aea43c82849373cefde52c0fc Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Thu, 23 Feb 2023 10:33:16 +0100 Subject: [PATCH 56/58] fix permissions --- .github/workflows/create-release-pr.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 617092340..414d0a16d 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -12,7 +12,6 @@ jobs: runs-on: ubuntu-latest permissions: contents: write - pull-requests: write steps: - name: Check out code uses: actions/checkout@v3 @@ -37,6 +36,8 @@ jobs: create-pull-requests: runs-on: ubuntu-latest needs: create-release-branch + permissions: + pull-requests: write steps: - name: Create pull request into main uses: thomaseizinger/create-pull-request@1.3.0 From 5845ce86d53d7986844e31bfb24cb032b620e7a5 Mon Sep 17 00:00:00 2001 From: Nils <45318774+Nils1729@users.noreply.github.com> Date: Thu, 23 Feb 2023 12:09:02 +0100 Subject: [PATCH 57/58] remove auto pipeline --- .github/workflows/create-release-pr.yml | 4 ---- .github/workflows/pipeline.yml | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/create-release-pr.yml b/.github/workflows/create-release-pr.yml index 414d0a16d..007b9c6b0 100644 --- a/.github/workflows/create-release-pr.yml +++ b/.github/workflows/create-release-pr.yml @@ -61,7 +61,3 @@ jobs: body: | This PR was created in response to a running workflow. I've updated the version name and changelog. - run-pipeline: - needs: create-pull-requests - uses: ./.github/workflows/pipeline.yml - secrets: inherit diff --git a/.github/workflows/pipeline.yml b/.github/workflows/pipeline.yml index 90460ff6a..d892df549 100644 --- a/.github/workflows/pipeline.yml +++ b/.github/workflows/pipeline.yml @@ -2,7 +2,7 @@ name: Complete pipeline on: push: - workflow_call: + workflow_dispatch: jobs: build: From 48c350a00d1294c5e3b65f99e38d7c2c2aa9ddb3 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Thu, 23 Feb 2023 11:44:08 +0000 Subject: [PATCH 58/58] Debug v1.2.3-test12 --- CHANGELOG.md | 6 +++++- backend/package-lock.json | 7 ++++--- backend/package.json | 2 +- benchmark/package-lock.json | 7 ++++--- benchmark/package.json | 2 +- docs/swagger.yml | 2 +- frontend/package-lock.json | 7 ++++--- frontend/package.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- shared/package-lock.json | 4 ++-- shared/package.json | 2 +- 12 files changed, 27 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e2c4b88..aa7f5ccc8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,8 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org ## [Unreleased] +## [v1.2.3-test12] - 2023-02-23 + ## [v1.2.3-test2] - 2023-02-22 ## [v123-test] - 2023-02-22 @@ -39,7 +41,9 @@ and this project does **not** adhere to [Semantic Versioning](https://semver.org - Minor dependency updates - Updated deprecated actions -[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v1.2.3-test2...HEAD +[Unreleased]: https://github.com/Nils1729/digital-fuesim-manv/compare/v1.2.3-test12...HEAD + +[v1.2.3-test12]: https://github.com/Nils1729/digital-fuesim-manv/compare/v1.2.3-test2...v1.2.3-test12 [v1.2.3-test2]: https://github.com/Nils1729/digital-fuesim-manv/compare/v123-test...v1.2.3-test2 diff --git a/backend/package-lock.json b/backend/package-lock.json index 2002a8b76..93fb36668 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "dependencies": { "class-transformer": "^0.5.1", "class-validator": "^0.14.0", @@ -47,7 +47,8 @@ } }, "../shared": { - "version": "1.2.3-test8", + "name": "digital-fuesim-manv-shared", + "version": "1.2.3-test12", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/backend/package.json b/backend/package.json index 960eea2f1..3ba05f24e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-backend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "type": "module", "scripts": { "start:once:linux-macos": "NODE_ENV=production node --experimental-specifier-resolution=node dist/src/index.js", diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json index 0f5280715..a98361fa0 100644 --- a/benchmark/package-lock.json +++ b/benchmark/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "dependencies": { "digital-fuesim-manv-shared": "file:../shared", "immer": "^9.0.17", @@ -31,7 +31,8 @@ } }, "../shared": { - "version": "1.2.3-test8", + "name": "digital-fuesim-manv-shared", + "version": "1.2.3-test12", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/benchmark/package.json b/benchmark/package.json index 69f23b91b..420746fdc 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-benchmark", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "type": "module", "scripts": { "lint": "eslint --max-warnings 0 --ignore-path .gitignore \"./**/*.{ts,js,yml,html}\"", diff --git a/docs/swagger.yml b/docs/swagger.yml index e1c4203e8..4db7c902e 100644 --- a/docs/swagger.yml +++ b/docs/swagger.yml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Digital Fuesim MANV HTTP API description: HTTP API of the digital-fuesim-manv project - version: 1.2.3-test8 + version: 1.2.3-test12 paths: /api/health: get: diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b052ae1e6..6655f157a 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "dependencies": { "@angular/animations": "~15.1.0", "@angular/common": "~15.1.0", @@ -66,7 +66,8 @@ } }, "../shared": { - "version": "1.2.3-test8", + "name": "digital-fuesim-manv-shared", + "version": "1.2.3-test12", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/frontend/package.json b/frontend/package.json index 76fc3c99e..ee882fc0a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-frontend", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "type": "module", "scripts": { "cy:open": "cypress open", diff --git a/package-lock.json b/package-lock.json index d3d548997..0c51fd98c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "devDependencies": { "concurrently": "^7.6.0", "nyc": "^15.1.0", diff --git a/package.json b/package.json index ec40ec940..94df35fa6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "type": "module", "scripts": { "build": "cd shared && npm run build && cd .. && concurrently \"cd frontend && npm run build\" \"cd backend && npm run build\"", diff --git a/shared/package-lock.json b/shared/package-lock.json index 357958b4c..91caec56f 100644 --- a/shared/package-lock.json +++ b/shared/package-lock.json @@ -1,12 +1,12 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "dependencies": { "@noble/hashes": "^1.2.0", "class-transformer": "^0.5.1", diff --git a/shared/package.json b/shared/package.json index 952d7ead8..1dc30438f 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,6 +1,6 @@ { "name": "digital-fuesim-manv-shared", - "version": "1.2.3-test8", + "version": "1.2.3-test12", "type": "module", "main": "./dist/index.js", "esnext": "./dist/index.js",