diff --git a/.github/workflows/typescript-bindings.yml b/.github/workflows/typescript-bindings.yml new file mode 100644 index 000000000..f2a6ad3cd --- /dev/null +++ b/.github/workflows/typescript-bindings.yml @@ -0,0 +1,184 @@ +name: TypeScript bindings + +on: + push: + branches: [master] + paths: + - "typescript/**" + - ".github/workflows/typescript-bindings.yml" + pull_request: + branches: [master] + paths: + - "typescript/**" + - ".github/workflows/typescript-bindings.yml" + workflow_dispatch: + +env: + CARGO_TERM_COLOR: always + +# The JS/Wasm bindings live under `typescript/`, which is a self-contained Cargo +# workspace (it pulls `rapier2d`/`rapier3d` from crates.io, not from the crates +# in this repo). Every step therefore runs inside that directory. + +concurrency: + group: typescript-bindings-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +jobs: + check-fmt: + runs-on: ubuntu-latest + defaults: + run: + working-directory: typescript + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: "22.x" + - run: npm ci + - name: Check formatting + run: npm run fmt -- --check + - name: Check Rust formatting + run: cargo fmt -- --check + build: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: typescript + env: + RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + typescript/target/ + key: ${{ runner.os }}-cargo-js-${{ hashFiles('typescript/builds/prepare_builds/templates/Cargo.toml.tera') }} + restore-keys: | + ${{ runner.os }}-cargo-js- + - run: npm ci; + - name: Prepare no-compat builds + run: | + ./builds/prepare_builds/prepare_all_projects.sh + - name: Build all no-compat projects + run: | + ./builds/prepare_builds/build_all_projects.sh + # Install dependencies to check simd for builds + - name: Install wabt + run: | + sudo apt install wabt; + if: matrix.os == 'ubuntu-latest' + - name: Install wabt + run: | + brew install wabt; + if: matrix.os == 'macos-latest' + # Check simd for rust builds + - name: Check 2d simd rust build + run: | + if ! wasm-objdump -d builds/rapier2d-simd/pkg/rapier_wasm2d_bg.wasm | grep :\\sfd ; then + >&2 echo "ERROR: 2d simd compat build does not include simd opcode prefix." && exit 1 + fi + - name: Check 3d simd compat build + run: | + if ! wasm-objdump -d builds/rapier3d-simd/pkg/rapier_wasm3d_bg.wasm | grep :\\sfd ; then + >&2 echo "ERROR: 3d simd compat build does not include simd opcode prefix." && exit 1 + fi + - uses: actions/upload-artifact@v4 + with: + name: pkg no-compat ${{ matrix.os }} + path: | + typescript/builds/*/pkg + overwrite: true + build-compat: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + defaults: + run: + working-directory: typescript + env: + RUSTFLAGS: -D warnings + steps: + - uses: actions/checkout@v4 + - uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + typescript/target/ + key: ${{ runner.os }}-cargo-js-${{ hashFiles('typescript/builds/prepare_builds/templates/Cargo.toml.tera') }} + restore-keys: | + ${{ runner.os }}-cargo-js- + - run: npm ci; + - name: Prepare compat builds + run: | + ./builds/prepare_builds/prepare_all_projects.sh + - name: Build rapier-compat + run: | + cd rapier-compat; + npm ci; + npm run build; + npm run test; + # Install dependencies to check simd for builds + - name: Install wabt + run: | + sudo apt install wabt; + if: matrix.os == 'ubuntu-latest' + - name: Install wabt + run: | + brew install wabt; + if: matrix.os == 'macos-latest' + # Check simd for compat builds + - name: Check 2d simd compat build + run: | + if ! wasm-objdump -d rapier-compat/builds/2d-simd/pkg/rapier_wasm2d_bg.wasm | grep :\\sfd ; then + >&2 echo "ERROR: 2d simd compat build does not include simd opcode prefix." && exit 1; + fi + - name: Check 3d simd compat build + run: | + if ! wasm-objdump -d rapier-compat/builds/3d-simd/pkg/rapier_wasm3d_bg.wasm | grep :\\sfd ; then + >&2 echo "ERROR: 3d simd compat build does not include simd opcode prefix." && exit 1; + fi + # Upload + - uses: actions/upload-artifact@v4 + with: + name: pkg compat ${{ matrix.os }} + path: | + typescript/rapier-compat/builds/*/pkg + overwrite: true + publish: + runs-on: ubuntu-latest + needs: [build, build-compat] + if: github.ref == 'refs/heads/master' + defaults: + run: + working-directory: typescript + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: pkg no-compat ubuntu-latest + path: typescript/builds + - uses: actions/download-artifact@v4 + with: + name: pkg compat ubuntu-latest + path: typescript/rapier-compat/builds + - uses: actions/setup-node@v4 + with: + node-version: "22.x" + registry-url: "https://registry.npmjs.org" + - name: Publish projects + run: | + ./publish_all_canary.sh + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.typos.toml b/.typos.toml index ca5c20cf4..b0123245a 100644 --- a/.typos.toml +++ b/.typos.toml @@ -30,6 +30,8 @@ Shepperd = "Shepperd" # with `bb`) and `typ` (a "type" value — `type` is reserved in Rust/Python). ba = "ba" typ = "typ" +# Voxel grid coordinate index in the JS bindings, paired with `ix`/`iz`. +iy = "iy" # Template mesh data in the testbed instancer: `tpos`/`tnrm`/`tidx` # (template positions/normals/indices). Only `tpos` collides with a word. tpos = "tpos" diff --git a/Cargo.toml b/Cargo.toml index ac588c7d9..e881c8049 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,9 @@ default-members = [ "crates/mjcf-rs", "crates/rapier3d-mjcf", ] +# `typescript/` is the JS/Wasm bindings' own Cargo workspace; keep it out of +# this one so root-level `cargo` commands never try to absorb its crates. +exclude = ["typescript"] resolver = "2" [workspace.package] diff --git a/typescript/.gitignore b/typescript/.gitignore new file mode 100644 index 000000000..3b3fe48a7 --- /dev/null +++ b/typescript/.gitignore @@ -0,0 +1,27 @@ +# Ignore rules specific to the TypeScript/Wasm bindings. Generic entries +# (node_modules, target, .idea, .DS_Store) already live in the repository-root +# .gitignore and are not repeated here. + +# The root .gitignore excludes `package-lock.json`, but the JS bindings must +# commit it: `npm ci` (used throughout the JS CI) requires the lockfile. The +# Rust `Cargo.lock` stays ignored (matching the repo root): the workspace's only +# members are the `prepare_builds`-generated crates, so a committed lock would +# just churn with generated entries; CI regenerates it. +!package-lock.json + +**/*.rs.bk +dist +pkg +gen2d/ +gen3d/ +docs +*.swp +*.d.ts + +# Per-target crates generated by the `prepare_builds` crate; only the +# generator itself is tracked. +builds/* +!builds/prepare_builds + +# Compat package's generated wasm builds. +rapier-compat/builds/ diff --git a/typescript/.prettierignore b/typescript/.prettierignore new file mode 100644 index 000000000..24ed3cdd9 --- /dev/null +++ b/typescript/.prettierignore @@ -0,0 +1,7 @@ +pkg +gen2d +gen3d +docs +target +**/CHANGELOG.md +**/README.md \ No newline at end of file diff --git a/typescript/.prettierrc b/typescript/.prettierrc new file mode 100644 index 000000000..5a3e14301 --- /dev/null +++ b/typescript/.prettierrc @@ -0,0 +1,5 @@ +{ + "tabWidth": 4, + "bracketSpacing": false, + "trailingComma": "all" +} diff --git a/typescript/CHANGELOG.md b/typescript/CHANGELOG.md new file mode 100644 index 000000000..ef3052b96 --- /dev/null +++ b/typescript/CHANGELOG.md @@ -0,0 +1,937 @@ +## 0.19.3 (05 Nov. 2025) + +- Significantly improve performances of `combineVoxelStates`. + +### 0.19.2 (17 Oct. 2025) + +- Fix bug where kinematic bodies would not wake up when setting its velocity. +- Fix bug where slow-moving kinematic bodies would fall asleep. +- Fix point-projection on voxels shapes. + +### 0.19.1 (03 Oct. 2025) + +### Modified + +- Update to Rapier 0.30.0. The only change is a [switch to a sparse storage](https://github.com/dimforge/parry/pull/380) + for the Voxels shapes. This allows support for orders of magnitudes larger maps without reaching the 4GB WASM memory + limit. + +### 0.19.0 (05 Sept. 2025) + +### Modified + +- Update to Rapier 0.29.0 which includes performance improvements for scenes involving a lot of contact constraints. + See https://github.com/dimforge/rapier/pull/876 for details. +- Renamed the `RigidBody.invPrincipalInertiaSqrt` and `.effectiveWorldInvInertiaSqrt` methods to + `RigidBody.invPrincipalInertia` and `.effectiveWorldInvInertia` (removed the `Sqrt` suffix). These methods will now + return the actual inverse angular inertia matrix rather than its square root. +- Removed methods related to the legacy PGS solver: `World.numAdditionalFrictionIterations`, + `switchToStandardPgsSolver`, `switchToSmallStepsPgsSolver`, `switchToSmallStepsPgsSolverWithoutWarmstart`. + +### 0.18.2 (13 August 2025) + +### Fixed + +- Fix rollup configuration adding `types: "./rapier.d.ts"` to the export config. + +### 0.18.1 (8 August 2025) + +### Modified + +- Update to Rapier 0.28.0 which includes performance improvements when CCD is active and when + the user applies modification to a collider or rigid-body. + +### Fix + +- Another attempt to fix bundlerless module import with rapier-compat. + +### 0.18.0 (24 July 2025) + +### Added + +- Add `World.timing*` functions to access the internal performances measurements if the internal + profiler is enabled with `World.profilerEnabled = true`. +- Add `World.maxCcdSubsteps` to get/set the max number of CCD substeps run by the engine. + +### Fix + +- Fixed crash that would happen when removing colliders in a particular order (e.g. in the same order + as their insertion). + +### 0.18.0-beta.0 (12 July 2025) + +#### Modified + +- Update to Rapier 0.27.0-beta.1 which includes a fully reworked broad-phase that supports scene queries. + This implies a performance gain on large scenes by avoiding the need to re-build the underlying acceleration + structure at each frame. +- Un-deprecate methods for reading shape properties (for example `collider.radius()`). It turned out that these + methods are more convenient as they are guaranteed to always be in sync with rapier’s state on wasm. +- Add `collider.translationWrtParent()` and `collider.rotationWrtParent()` to get the collider’s translation/rotation + relative to its parent rigid-body. + +#### Fix + +- rapier-compat top level javascript files extensions have been changed from `.cjs.js` and `.es.js` to `.cjs` and `mjs` + respectively. This results in better compatibility with NPM. + +### 0.17.3 (30 May 2025) + +#### Fix + +- The published package for 0.17.2 had a broken package.json. It is fixed on this release. + +### 0.17.2 (30 May 2025) + +#### Added + +- Added the function `RAPIER.reserveMemory` to instruct the internal allocator to pre-allocate more memory in preparation + for future operations. This typically called only once after initializing the WASM module. + +### 0.17.1 (23 May 2025) + +#### Added + +- Added optional arguments to `World.debugRender(filterFlags, filterPredicate)` to prevent some colliders from being + rendered. +- Added `Collider.combineVoxelStates` to ensure two adjacent voxels colliders don’t suffer from the internal edges + problem, and `Collider.propagateVoxelChange` to maintain that coupling after modifications with `.setVoxel`. + +### 0.17.0 (16 May 2025) + +#### Fixed + +- Fix sensor events not triggering when hitting a voxels collider. + +#### Added + +- Added support for voxels colliders attached to dynamic rigid-bodies. +- Added force calculation between colliding voxels/voxels and voxels/compound shapes. + +### 0.16.2 (5 May 2025) + +#### Fixed + +- Fixed infinite loop in `collider.setVoxel`. + +### 0.16.1 (2 May 2025) + +#### Added + +- Added `Collider.clearShapeCache` to release the reference to the JS shape stored in the collider, oor too force its + recomputation the next time the collider shape is accessed. +- Added support for shape-casting involving Voxels colliders. +- Added support for CCD involving Voxels colliders. + +### 0.16.0 (24 April 2025) + +#### Added + +- Added `ColliderDesc.voxels` to create a collider with a shape optimized for voxels. +- Added `Collider.setVoxel` for adding or removing a voxel from a collider with a voxel shape. +- Added the `Voxels` shape class. + +The support or voxels is still experimental. In particular the following features will currently **not** work on +colliders with voxel shapes: + +- Voxels colliders attached to dynamic rigid-bodies will not run the automatic mass/angular inertia calculation. +- Shape-casting on voxel shapes/colliders. +- Collision-detection between two-voxels colliders, or a voxels collider and a mesh, polyline, or heightfield. + +See [parry#336](https://github.com/dimforge/parry/pull/336) for additional information. + +### 0.15.1 (10 April 2025) + +#### Added + +- Added `RigidBody.velocityAtPoint` function to retrieve the velocity of a given world-space point on a rigid-body. + +#### Modified + +- Update to Rapier 0.25. The main notable change is that the `TriMeshFlags.FIX_INTERNAL_EDGES` flag will no longer + imply that the `TriMeshFlags.ORIENTED` flag is set, avoiding edge-cases where enabling `FIX_INTERNAL_EDGES` + results in unexpected collisions between open meshes and balls. + +#### Fixed + +- Fixed `*-simd-compat` builds not actually emitting SIMD instructions. + +### 0.15.0 (06 March 2025) + +#### Added + +- Added `PidController`, `World.createPidController`, `World.removePidController` to create a Position-Integral-Derivative + controller; a building block for building velocity-based dynamic character controllers. + +#### Modified + +- Update to Rapier 0.24. +- Package tree shaking has been disabled to avoid a crash on certain build configuration (#289). +- Multiple packages with different feature sets are now released, and their build process has been automated (#309) + - Released packages are: + - rapier2d + - rapier2d-compat + - rapier2d-simd + - rapier2d-simd-compat + - rapier2d-deterministic + - rapier2d-deterministic-compat + - rapier3d + - rapier3d-compat + - rapier2d + - rapier2d-compat + - rapier3d-simd + - rapier3d-simd-compat + - rapier3d-deterministic + - rapier3d-deterministic-compat + - :warning: To this occasion, existing packages `rapier2d` and `rapier3d` are now built without `enhanced-determinism` feature enabled, + so if you rely on that feature, you should migrate to the new `-deterministic` flavor. + + +### 0.14.0 (20 July 2024) + +#### Modified + +- Update from the rust library of rapier 0.19 to 0.22, see [rapier's changelog](https://github.com/dimforge/rapier/blob/master/CHANGELOG.md#v0210-23-june-2024) for more context. + +#### Added + +- Added `RigidBody.userForce` function to retrieve the constant force(s) the user added to a rigid-body +- Added `RigidBody.userTorque` function to retrieve the constant torque(s) the user added to a rigid-body + +### 0.13.1 (2024-05-08) + +#### Fixed + +- Fix regression that could cause missed contact between a ball and another shape type. + +### 0.13.0 (2024-05-05) + +Several stability improvements are added as part of this release. +See [rapier#625](https://github.com/dimforge/rapier/pull/625) for overviews of the most important improvements. + +#### Modified + +- The `castShape` and `castCollider` functions have been modified to add a `targetDistance` parameter. This parameter + indicates the distance below which a hit is detected. +- Rename `RayIntersection.toi` to `.timeOfImpact` for better clarity. +- Rename `RayColliderIntersection.toi` to `.timeOfImpact` for better clarity. +- Rename `RayColliderToi` to `RayColliderHit`. +- Rename `RayColliderHit.toi` to `.timeOfImpact` for better clarity. +- Rename `ShapeTOI` to `ShapeCastHit`. +- Rename `ShapeColliderTOI` to `ColliderShapeCastHit`. +- Rename `ShapeCastHit.toi` to `.timeOfImpact`. + +#### Added + +- Fix the kinematic character controller getting stuck against vertical walls. +- Add `KinematicCharacterController.normalNudgeFactor` and `.setNormalNudgeFactor` so set a coefficient used for + avoiding having the character controller get stuck on penetrations. +- Add `RigidBody.softCcdPrediction`, `.setSoftCcdPrediction`, and `RigidBodyDesc.setSoftCcdPrediction` for configuring + soft-ccd on the rigid-body. See [rapier#625](https://github.com/dimforge/rapier/pull/625) for additional details on + soft-ccd. +- 3D version only: add `TriMeshFlags::FIX_INTERNAL_EDGES` and `HeightFieldFlags::FIX_INTERNAL_EDGES` for enabling + internal edges correction (which is no longer enabled by default). The flags have been added as an optional parameter + when building the shapes. +- Add `Collider.contactSkin`, `.setContactSkin`, and `ColliderDesc.setContactSkin` for configuring the collider’s + contact skin. See [rapier#625](https://github.com/dimforge/rapier/pull/625) for additional details on contact skins. +- Add `World.lengthUnit` which can be used to indicate the typical size of dynamic objects (e.g. 100 pixels instead of + 1 meter). This helps the physics engine adjust internal thresholds for better results. + +#### Fixed + +- Fix an issue where the reported contact force are lower than their actual value. + +### 0.12.0 (2024-01-28) + +The main highlight of this release is the implementation of a new non-linear constraints solver for better stability +and increased convergence rates. See [#579](https://github.com/dimforge/rapier/pull/579) for additional information. + +In order to adjust the number of iterations of the new solver, simply adjust `World.numSolverIterations`. +If recovering the old solver behavior is useful to you, call `World.switchToStandardPgsSolver()`. + +It is now possible to specify some additional solver iteration for specific rigid-bodies (and everything interacting +with it directly or indirectly through contacts and joints): `RigidBodyDesc.additionalSolverIterations` and +`RigidBody::setAdditionalSolverIterations`. This allows for higher-accuracy on subsets of the physics scene +without affecting performance of the other parts of the simulation. + +#### Modified + +- Renamed `CharacterController.translationApplied`, `.translationRemaining` and the `desiredTranslation` + method argument to `CharacterController.translationDeltaApplied`, `.translationDeltaRemaining` and the + `desiredTranslationDelta` to avoid confusion with the usage of the `translation` world in `RigidBody.translation()`. + +#### Added + +- Added `DynamicRayCastVehicleController` to simulate vehicles based on ray-casting. +- Added `JointData.generic` (3D only) to create a generic 6-dof joint and manually specify the locked axes. + +### 0.11.2 + +#### Fixed + +- Fix bug that made dynamic rigid-bodies behave like kinematic bodies after being disabled and then re-enabled. +- Fix issue with convex polyhedron jitter due to missing contacts. +- Fix character controller getting stuck against vertical walls. +- Fix character controller’s snapping to ground not triggering sometimes. +- Fix character controller’s horizontal offset being mostly ignored and some instances of vertical offset being ignored. + +#### Added + +- Add `JointData.spring` and `JointData.rope` joints. +- Add access to the mass-properties of a rigid-body: `RigidBody.effectiveInvMass`, `.invMass()`, `.localCom()`, + `.worldCom()`, `.invPrincipalInertiaSqrt()`, `.principalInertia()`, `.principalInertiaLocalFrame()`, + `.effectiveWorldInvInertiaSqrt()`, `.effectiveAngularInertia()`. +- Add `DynamicRayCastVehicleController.siteFrictionStiffness` to customize the side friction applied to the vehicle + controller’s wheel. + +#### Modified + +- Rename `World.contactsWith` to `World.contactPairsWith`. +- Rename `World.intersectionsWith` to `World.intersectionPairsWith`. + +### 0.11.1 (2023-01-16) + +#### Fixed + +- Fix bug that disabled all colliders at construction time. + +### 0.11.0 (2023-01-15) + +#### Added + +- Add `World.propagateModifiedBodyPositionsToColliders` to propagate rigid-bodies position changes to their attached + colliders. +- Add `World.updateSceneQueries` to update the scene queries data structures without stepping the whole simulation. +- Add `RigidBody.isEnabled, RigidBody.setEnabled, RigidBodyDesc.setEnabled` to disable a rigid-body (and all its + attached colliders) without removing it from the physics world. +- Add `Collider.isEnabled, Collider.setEnabled, ColliderDesc.setEnabled` to disable a collider without removing it + from the physics world. +- Add shape-specific methods to modify a collider’s + size: `Collider.setRadius, setHalfExtents, setRoundRadius, setHalfHeight`. + +#### Modified + +- Add a boolean argument to `RigidBody.setBodyType` to indicate if the rigid-body should awaken after changing + its type. + +#### Fixed + +- Fix rigid-bodies automatically waking up at creation even if they were explicitly created sleeping. + +### 0.10.0 (2022-11-06) + +#### Added + +- Add `World.createCharacterController`, `World.removeCharacterController` to create/remove a kinematic character + controller. +- Add a character-controller implementation with the `KinematicCharacterController` class and its method + `KinematicCharacterController.computeColliderMovement`. The character controller features currently supported are: + - Slide on uneven terrains + - Interaction with dynamic bodies. + - Climb stairs automatically. + - Automatically snap the body to the floor when going downstairs. + - Prevent sliding up slopes that are too steep + - Prevent sliding down slopes that are not steep enough + - Interactions with moving platforms. + - Report information on the obstacles it hit on its path. +- Add the `HalfSpace` (infinite plane) shape. Colliders with this shape can be built using `ColliderDesc.halfspace`. + +#### Modified + +- Change the signature of `Collider.castShape` and World.castShape by adding a boolean argument `stop_at_penetration` + before the filter-related arguments. Set this argument to `true` to get the same result as before. If this is set to + `false` and the shape being cast starts it path already intersecting another shape, then a hit won’t be returned + with that intersecting shape unless the casting movement would result in more penetrations. +- Reduce rounding errors in 3D when setting the rotation of a rigid-body or collider. + +#### Fixed + +- Fix incorrect application of torque if the torque is applies right after setting the rigid-body’s + position, but before calling `World.step`. + +### 0.9.0 (2022-10-07) + +#### Fixed + +- Fix unpredictable broad-phase panic when using small colliders in the simulation. +- Fix collision events being incorrectly generated for any shape that produces multiple + contact manifolds (like triangle meshes). + +#### Modified + +- The `RigidBodyDesc.setAdditionalMass` method will now result in the additional angular inertia + being automatically computed based on the shapes of the colliders attached to the rigid-body. +- Removed the method `RigidBodyDesc.setAdditionalPrincipalAngularInertia`. Use + `RigidBodyDesc.setAdditionalMassProperties` instead. +- The methods of `RigidBodyDesc` and `ColliderDesc` will now always copy the object provided by + the user instead of storing the object itself. +- The following method will now copy the user’s objects instead of storing it: `ColliderDesc.setRotation`, + `ColliderDesc.setMassProperties`, `RigidBodyDesc.setRotation`, `RigidBodyDesc.setAdditionalMassProperties`, + `RigidBodyDesc.setAngvel`. +- Rename `RigidBody.restrictRotations` and `RigidBody.restrictTranslations` to + `RigidBody.setEnabledRotations` and `RigidBody.setEnabledTranslations`. +- Rename `RigidBodyDesc.restrictRotations` and `RigidBodyDesc.restrictTranslations` to + `RigidBodyDesc.enabledRotations` and `RigidBodyDesc.enabledTranslations`. + +#### Added + +- Add `ImpulseJoint.setContactsEnabled`, and `MultibodyJoint.setContactsEnabled` to set whether + contacts are enabled between colliders attached to rigid-bodies linked by this joint. +- Add `UnitImpulseJoint.setLimits` to set the limits of a unit joint. +- Add `RigidBody.recomputeMassPropertiesFromColliders` to force the immediate computation + of a rigid-body’s mass properties (instead of waiting for them to be recomputed during the next + timestep). This is useful to be able to read immediately the result of a change of a rigid-body + additional mass-properties or a change of one of its collider’s mass-properties. +- Add `RigidBody::setAdditionalMass` to set the additional mass for the rigid-body. The additional + angular inertia is automatically computed based on the attached colliders shapes. If this automatic + angular inertia computation isn’t desired, use `RigidBody::setAdditionalMassProperties` instead. +- Add `Collider.setDensity`, `.setMass`, `.setMassProperties`, to alter a collider’s mass + properties. Note that `.setMass` will result in the collider’s angular inertia being automatically + computed based on this mass and on its shape. +- Add `ColliderDesc.setMass` to set the mass of the collider instead of its density. Its angular + inertia tensor will be automatically computed based on this mass and its shape. +- Add more filtering options for scene-queries. All the scene query methods now take additional optional + arguments to indicate if one particular collider, rigid-body, or type of colliders/rigid-bodies have to + be ignored by the query. +- Add force reporting based on contact force events. The `EventHandler` trait has been modified to include + the method `EventQueue.drainContactForceEvents`. Contact force events are generated whenever the sum of the + magnitudes of all the forces between two colliders is greater than any of their + `Collider.contactForceEventThreshold` values (only the colliders with the `ActiveEvents.CONTACT_FORCE_EVENT` + flag set are taken into account for this threshold). + +### 0.8.1 (2022-04-06) + +Starting with this release, all the examples in `testbed2d` and `testbed3d` have been updated to `webpack 5`, +and are written in Typescript. In addition, canary `0.0.0` releases will be generated automatically after each merge +to the `master` branch. + +#### Fixed + +- Fix bug causing `World.intersectionPair` to always return `false`. + +### 0.8.0 (2022-03-31) + +#### Breaking changes + +- Most APIs that relied on rigid-body handles or collider handles have been modified to rely on `RigidBody` + or `Collider` objects instead. Handles are now only needed for events and hooks. +- Rename STATIC to FIXED in the `ActiveCollisionTypes` flags. +- The `RigidBody.applyForce` and `.applyTorque` methods have been replaced by `.addForce` and `.addTorque`. These + force/torques are no longer automatically zeroed after a timestep. To zero them manually, call `.resetForce` or + `.resetTorque`. +- The `EventQueue.drainContactEvents` and `EventQueue.drainIntersectionEvents` have been merged into a single + method: `EventQueue:drainCollisionEvents`. + +#### Added + +- Add a lines-based debug-renderer. See [#119](https://github.com/dimforge/rapier.js/pull/119) for examples of + integration of the debug-renderer with `THREE.js` and `PIXI.js`. +- Each rigid-body, collider, impulse joint, and multibody joint now have a unique object instance. This instance + in only valid as long as the corresponding objects is inserted to the `World`. +- Add a `wakeUp: bool` argument to the `World.createImpulseJoint` and `MultibodyJointSet::createMultibodyJoint` to + automatically wake-up the rigid-bodies attached to the inserted joint. +- Add a `filter` callback to all the scene queries. Use this for filtering more fine-grained than collision groups. +- Add `collider.shape` that represents the shape of a collider. This is a more convenient way of reading the collider’s + shape properties. Modifying this shape will have no effect unless `collider.setShape` is called with the modified + shape. +- Add `Collider.containsPoint`, `.projectPoint`, `.intersectsRay`, `.castShape`, `.castCollider`, `.intersectsShape`, + `.contactShape`, `.contactCollider`, `.castRay`, `.castRayAndGetNormal`. +- Add `Shape.containsPoint`, `.projectPoint`, `.intersectsRay`, `.castShape`, `.intersectsShape`, + `.contactShape`, `.castRay`, `.castRayAndGetNormal`. +- Add `World.projectPointAndGetFeature` which includes the feature Id the projected point lies on. +- Add `RigidBodyDesc.sleeping` to initialize the rigid-body in a sleeping state. + +### 0.8.0-alpha.2 (2022-03-20) + +The changelog hasn’t been updated yet. +For an overview of the changes, refer to the changelog for the unreleased Rust version: +https://github.com/dimforge/rapier/blob/master/CHANGELOG.md#unreleased + +### 0.8.0-alpha.1 (2022-01-28) + +#### Fixed + +- Fix a crash when calling `collider.setShape`. +- Fix a crash when calling `world.collidersWithAabbIntersectingAabb`. +- Fix damping not being applied properly to some rigid-bodies. + +### 0.8.0-alpha.0 (2022-01-16) + +This release updates to Rapier 0.12.0-alpha.0 which contains: + +- A **complete rewrite** of the joint and contact constraint solver. +- The support for locking individual translation axes. +- The support for multibody joint. + +This is an **alpha** release because the new solver still needs some tuning, +and the spherical joint motors/limits is currently not working. + +#### Breaking changes + +- In 3D: renamed `BallJoint` to `SphericalJoint`. +- In 2D: renamed `BallJoint` to `RevoluteJoint`. +- Remove the joint motors and limits for the spherical joint (this is a temporary removal until with leave alpha). +- All the joint-related structures and methods (`RevoluteJoint`, `PrismaticJoint`, `createJoint`, etc.) have renamed to + include `impulse` in the names: `RevoluteImpulseJoint`, `PrismaticImpulseJoint`, `createImpulseJoint`, etc. This is + to differentiate them from the new multibody joints. +- Remove from the integration parameters all the parameters that are no longer meaningful (`maxPositionIterations`, + `jointErp`, `warmstartCoeff`, `allowedAngularError`, `maxLinearCorrection`, `maxAngularCorrection`). + +#### Added + +- Add multibody joints. They are created the same way as impulse joints, except that they are created + by `world.createMultibodyJoint` instead of `world.createImpulseJoint`. +- Add the ability to lock individual translation axes. Use `rigidBody.restrictTranslation`. + +#### Fixed + +- Fixed an issue with velocity-based kinematic bodies applying kinematic rotation improperly. +- Fixed the second witness points and normals returned by shape-casts. +- Fixed the second local contact normal and points returned by contact manifolds. + +### 0.7.6 + +This release updates to Rapier 0.11.1 which contains several bug fixes. + +#### Fixed + +- Fix a bug causing large moving colliders to miss some collisions after some time. +- Fix invalid forces generated by contacts with position-based kinematic bodies. +- Fix a bug where two colliders without parent would not have their collision computed even if the + appropriate flags were set. + +### 0.7.5 + +#### Fixed + +- Fixed an issue where a collider with no parent attached would not be created + under some conditions. + +### 0.7.4 + +This release was broken and has been unpublished. + +### 0.7.3 + +#### Fixed + +- The `collider.halfExtents()` methods now returns a valid value for round cuboids. + +### 0.7.2 (rapier-compat only) + +#### Modified + +- The `rapier-compat` packages don’t need the `Buffer` polyfill anymore. + +### 0.7.1 + +#### Modified + +- Update to use Rapier 0.11.0. +- The `rapier-compat` packages are now generated by rollup. + +### v0.7.0 + +The typescripts bindings for Rapier have +a [brand new user-guide](https://rapier.rs/docs/user_guides/javascript/getting_started_js) +covering all the features of the physics engine! + +### Breaking change + +- The `World.castRay` and `World.castRayAndGetNormal` methods have a different signature now, making them + more flexible. +- Rename `ActiveHooks::FILTER_CONTACT_PAIR` to `ActiveHooks.FILTER_CONTACT_PAIRS`. +- Rename `ActiveHooks::FILTER_INTERSECTION_PAIR` to `ActiveHooks.FILTER_INTERSECTION_PAIRS`. +- Rename `BodyStatus` to `RigidBodyType`. +- Rename `RigidBody.bodyStatus()` to `RigidBody.bodyType()`. +- Rename `RigidBodyDesc.setMassProperties` to `RigidBodyDesc.setAdditionalMassProperties`. +- Rename `RigidBodyDesc.setPrincipalAngularInertia` to `RigidBodyDesc.setAdditionalPrincipalAngularInertia`. +- Rename `ColliderDesc.setIsSensor` to `ColliderDesc.setSensor. + +#### Added + +- Add `Ray.pointAt(t)` that conveniently computes `ray.origin + ray.dir * t`. +- Add access to joint motors by defining each joint with its own class deriving from `Joint`. Each joint now + have its relevant motor configuration + methods: `configurMotorModel, configureMotorVelocity, configureMotorPosition, configureMotor`. +- Add `World.collidersWithAabbIntersectingAabb` for retrieving the handles of all the colliders intersecting the given + AABB. +- Add many missing methods for reading/modifying a rigid-body state after its creation: + - `RigidBody.lockTranslations` + - `RigidBody.lockRotations` + - `RigidBody.restrictRotations` + - `RigidBody.dominanceGroup` + - `RigidBody.setDominanceGroup` + - `RigidBody.enableCcd` +- Add `RigidBodyDesc.setDominanceGroup` for setting the dominance group of the rigid-body being built. +- Add many missing methods for reading/modifying a collider state after its creation: + - `Collider.setSendor` + - `Collider.setShape` + - `Collider.setRestitution` + - `Collider.setFriction` + - `Collider.frictionCombineRule` + - `Collider.setFrictionCombineRule` + - `Collider.restitutionCombineRule` + - `Collider.setRestitutionCombineRule` + - `Collider.setCollisionGroups` + - `Collider.setSolverGroups` + - `Collider.activeHooks` + - `Collider.setActiveHooks` + - `Collider.activeEvents` + - `Collider.setActiveEvents` + - `Collider.activeCollisionTypes` + - `Collider.setTranslation` + - `Collider.setTranslationWrtParent` + - `Collider.setRotation` + - `Collider.setRotationWrtParent` +- Add `ColliderDesc.setMassProperties` for setting explicitly the mass properties of the collider being built (instead + of relying on density). + +#### Modified + +- Colliders are no longer required to be attached to a rigid-body. Therefore, the second argument + of `World.createCollider` + is now optional. + +### v0.6.0 + +#### Breaking changes + +- The `BodyStatus::Kinematic` variant has been replaced by `BodyStatus::KinematicPositionBased` and + `BodyStatus::KinematicVelocityBased`. Position-based kinematic bodies are controlled by setting (at each frame) the + next + kinematic position of the rigid-body (just like before), and the velocity-based kinematic bodies are controlled + by setting (at each frame) the velocity of the rigid-body. +- The `RigidBodyDesc.newKinematic` has been replaced by `RigidBodyDesc.newKinematicPositionBased` and + `RigidBodyDesc.newKinematicVelocityBased` in order to build a position-based or velocity-based kinematic body. +- All contact and intersection events are now disabled by default. The can be enabled for each collider individually + by setting + its `ActiveEvents`: `ColliderDesc.setActiveEvents(ActiveEvents.PROXIMITY_EVENTS | ActiveEvents.ContactEvents)`. + +#### Added + +- It is now possible to read contact information from the narrow-phase using: + - `world.narrowPhase.contactsWith(collider1, callback)` + - `world.narrowPhase.intersectionsWith(collider1, callback)` + - `world.narrowPhase.contactPair(collider1, collider2, callback)` + - `world.narrowPhase.intersectionPair(collider1, collider2, callback)` +- It is now possible to apply custom collision-detection filtering rules (more flexible than collision groups) + based on a JS object by doing the following: + - Enable physics hooks for the colliders you want the custom rules to apply to: + `ColliderDesc.setActiveHooks(ActiveHooks.FILTER_CONTACT_PAIR | ActiveHooks.FILTER_CONTACT_PAIR)` + - Define an object that implements the `PhysicsHooks` interface. + - Pass and instance of your physics hooks object as the second argument of the `World.step` method. +- It is now possible to enable collision-detection between two non-dynamic bodies (e.g. between a kinematic + body and a fixed body) by setting the active collision types of a collider: + `ColliderDesc.setActiveCollisionTypes(ActiveCollisionTypes.ALL)` + +### v0.5.3 + +- Fix a crash when loading the WASM file on iOS safari. + +### v0.5.2 + +- Fix a crash that could happen after adding and then removing a collider right away, + before stepping the simulation. + +### v0.5.1 + +- Fix a determinism issue after snapshot restoration. + +### v0.5.0 + +- Significantly improve the broad-phase performances when very large colliders are used. +- Add `RigidBodyDesc::setCcdEnabled` to enable Continuous Collision Detection (CCD) for this rigid-body. CCD ensures + that a fast-moving rigid-body doesn't miss a collision (the tunneling problem). + +#### Breaking changes: + +- Removed multiple fields from `IntegrationParameters`. These were unused parameters. + +### v0.4.0 + +- Fix a bug in ball/convex shape collision detection causing the ball to ignore penetrations with depths greater than + its radius. + +Breaking changes: + +- Removed `IntegrationParameters.restitutionVelocityThreshold` + and `IntegrationParameters.set_restitutionVelocityThreshold`. + +### v0.3.1 + +- Fix crash happening when creating a collider with a `ColliderDesc.convexHull` shape. +- Actually remove the second argument of `RigidBodyDesc.setMass` as mentioned in the 0.3.0 changelog. +- Improve snapshotting performances. + +### v0.3.0 + +#### Added + +- Added a `RAPIER.version()` function at the root of the package to retrieve the version of Rapier as a string. + +Several geometric queries have been added (the same methods have been added to the +`QueryPipeline` too): + +- `World.intersectionsWithRay`: get all colliders intersecting a ray. +- `World.intersectionWithShape`: get one collider intersecting a shape. +- `World.projectPoint`: get the projection of a point on the closest collider. +- `World.intersectionsWithPoint`: get all the colliders containing a point. +- `World.castShape`: get the first collider intersecting a shape moving linearly + (aka. sweep test). +- `World.intersectionsWithShape`: get all the colliders intersecting a shape. + +Several new shape types are now supported: + +- `RoundCuboid`, `Segment`, `Triangle`, `RoundTriangle`, `Polyline`, `ConvexPolygon` (2D only), + `RoundConvexPolygon` (2D only), `ConvexPolyhedron` (3D only), `RoundConvexPolyhedron` (3D only), + `RoundCone` (3D only). + +It is possible to build `ColliderDesc` using these new shapes: + +- `ColliderDesc.roundCuboid`, `ColliderDesc.segment`, `ColliderDesc.triangle`, `ColliderDesc.roundTriangle`, + `ColliderDesc.convexHull`, `ColliderDesc.roundConvexHull`, `ColliderDesc.Polyline`, + `ColliderDesc.convexPolyline` (2D only), `ColliderDesc.roundConvexPolyline` (2D only), + `ColliderDesc.convexMesh` (3D only),`ColliderDesc.roundConvexMesh` (3D only), `ColliderDesc.roundCone` (3D only). + +It is possible to specify different rules for combining friction and restitution coefficients of the two colliders +involved in a contact with: + +- `ColliderDesc.frictionCombineRule`, and `ColliderDesc.restitutionCombineRule`. + +Various RigidBody-related getter and setters have been added: + +- `RigidBodyDesc.newStatic`, `RigidBodyDesc.newDynamic`, and `RigidBodyDesc.newKinematic` are new static method, short + equivalent to `new RigidBodyDesc(BodyStatus.Static)`, etc. +- `RigidBodyDesc.setGravityScale`, `RigidBody.gravityScale`, `RigidBody.setGravityScale` to get/set the scale factor + applied to the gravity affecting a rigid-body. Setting this to 0.0 will make the rigid-body ignore gravity. +- `RigidBody.setLinearDamping` and `RigidBody.setAngularDamping` to set the linear and angular damping of the + rigid-body. +- `RigidBodyDesc.restrictRotations` to prevent rotations along specific coordinate axes. This replaces the three boolean + arguments previously passed to `.setPrincipalAngularInertia`. + +#### Breaking changes + +Breaking changes related to rigid-bodies: + +- The `RigidBodyDesc.setTranslation` and `RigidBodyDesc.setLinvel` methods now take the components of the translation + directly as arguments instead of a single `Vector`. +- The `RigidBodyDesc.setMass` takes only one argument now. Use `RigidBodyDesc.lockTranslations` to lock the + translational motion of the rigid-body. +- The `RigidBodyDesc.setPrincipalAngularInertia` no longer have boolean parameters to lock rotations. + Use `RigidBodyDesc.lockRotations` or `RigidBodyDesc.restrictRotations` to lock the rotational motion of the + rigid-body. + +Breaking changes related to colliders: + +- The `ColliderDesc.setTranslation` method now take the components of the translation directly as arguments instead of a + single `Vector`. +- The `roundRadius` fields have been renamed `borderRadius`. +- The `RawShapeType.Polygon` no longer exists. For a 2D convex polygon, use `RawShapeType.ConvexPolygon` + instead. +- All occurrences of `Trimesh` have been replaced by `TriMesh` (note the change in case). + +Breaking changes related to events: + +- Rename all occurrences of `Proximity` to `Intersection`. +- The `Proximity` enum has been removed. +- The `drainIntersectionEvents` (previously called `drainProximityEvent`) will now call a callback with + arguments `(number, number, boolean)`: two collider handles, and a boolean indicating if they are intersecting. + +Breaking changes related to scene queries: + +- The `QueryPipeline.castRay` method now takes two additional parameters: a boolean indicating if the ray should not + propagate if it starts inside of a shape, and a bit mask indicating the group the ray is part of and these it + interacts with. +- The `World.castRay` and `QueryPipeline.castRay` now return a struct of type `RayColliderHit` + which no longer contains the normal at the hit point. Use the new methods `World.castRayAndGetNormal` + or `QueryPipeline.castRayAndGetNormal` in order to retrieve the normal too. + +### v0.2.13 + +- Fix a bug where `RigidBodyDesc.setMass(m)` with `m != 0.0` would cause the rotations of the created rigid-body to be + locked. + +### v0.2.12 + +- Add a boolean argument to `RigidBodyDesc.setMass` to indicate if the mass contribution of colliders should be enabled + for this rigid-body or not. +- Add a `RigidBody.lockRotations` method to lock all the rigid-body rotations resulting from forces. +- Add a `RigidBody.lockTranslations` method to lock all the rigid-body translations resulting from forces. +- Add a `RigidBody.setPrincipalAngularInertia` method to set the principal inertia of the rigid-body. This gives the + ability to lock individual rotation axes of one rigid-body. + +### v0.2.11 + +- Fix a bug where removing when immediately adding a collider would cause collisions to fail with the new collider. +- Fix a regression causing some colliders added after a few timesteps not to be properly taken into account. + +### v0.2.10 + +- Fix a bug where removing a collider would result in a rigid-body being removed instead. +- Fix a determinism issue when running simulation on the Apple M1 processor. +- Add `JointData.prismatic` and `JointData.fixed` for creating prismatic joint or fixed joints. + +### v0.2.9 + +- Add `RigidBody.setLinvel` to set the linear velocity of a rigid-body. +- Add `RigidBody.setAngvel` to set the angular velocity of a rigid-body. + +### v0.2.8 + +- Add `RigidBodySet.remove` to remove a rigid-body from the set. +- Add `ColliderSet.remove` to remove a collider from the set. +- Add `JointSet.remove` to remove a joint from the set. +- Add `RigidBodyDesc.setLinearDamping` and `RigidBodyDesc.setAngularDamping` for setting the linear and angular damping + coefficient of the rigid-body to create. +- Add `RigidBodyDesc.setMass`, and `RigidBodyDesc.setMassProperties` for setting the initial mass properties of a + rigid-body. +- Add `ColliderDesc.setCollisionGroups` to use bit-masks for collision filtering between some pairs of colliders. +- Add `ColliderDesc.setSolverGroups` to use bit-masks for making the constraints solver ignore contacts between some + pairs of colliders. +- Add `ColliderDesc.heightfield` to build a collider with an heightfield shape. +- Add `ColliderDesc.trimesh` to build a collider with a triangle mesh shape. + +### v0.2.7 + +- Reduce snapshot size and computation times. + +### v0.2.6 + +- Fix bug causing an unbounded memory usage when an objects falls indefinitely. + +### v0.2.5 + +- Fix wrong result given by `RigidBody.isKinematic()` and `RigidBody.isDynamic()`. + +### v0.2.4 + +- Add the support for round cylinder colliders (i.e. cylinders with round edges). + +### v0.2.3 + +- Add the support for cone, cylinder, and capsule colliders. + +### v0.2.2 + +- Fix regression causing the density and `isSensor` properties of `ColliderDesc` to not be taken into account. +- Throw an exception when the parent handle passed to `world.createCollider` is not a number. + +### v0.2.1 + +This is a significant rewrite of the JavaScript bindings for rapier. The objective of this rewrite is to make the API +closer to Rapier's and remove most need for manual memory management. + +- Calling `.free()` is now required only for objects that live for the whole duration of the simulation. This means that + it is no longer necessary to `.free()` vectors, rays, ray intersections, colliders, rigid-bodies, etc. Object that + continue to require an explicit `.free()` are: + - `World` and `EventQueue`. + - Or, if you are not using the `World` directly: + `RigidBodySet`, `ColliderSet`, `JointSet`, `IntegrationParameters`, `PhysicsPipeline`, `QueryPipeline` + , `SerializationPipeline`, and `EventQueue`. +- Collider.parent() now returns the `RigidBodyHandle` of its parent (instead of the `RigidBody` directly). +- Colliders are now built with `world.createCollider`, i.e., `body.createCollider(colliderDesc)` + becomes `world.createCollider(colliderDesc, bodyHandle)`. +- Shape types are not an enumeration instead of strings: `ShapeType.Ball` and `ShapeType.Cuboid` instead of `"ball"` + and `"cuboid"`. +- `collider.handle` is now a field instead of a function. +- `body.handle` is now a field instead of a function. +- The world's gravity is now a `Vector` instead of individual components, i.e., `let world = new RAPIER.World(x, y, z);` + becomes `let world = new RAPIER.World(new RAPIER.Vector3(x, y, z))`. +- Most methods that took individual components as argument (`setPosition`, `setKinematicPosition`, `setRotation`, etc.) + now take a `Vector` or `Rotation` structure instead. For example `rigid_body.setKinematicPosition(x, y, z)` + becomes `rigid_body.setKinematicPosition(new RAPIER.Vector3(x, y, z))`. +- `world.stepWithEvents` becomes `world.step` (the event queue is the last optional argument). +- `RigidBodyDesc` and `ColliderDesc` now use the builder pattern. For example + `let bodyDesc = new RAPIER.RigidBodyDesc("dynamic"); bodyDesc.setTranslation(x, y, z)` becomes + `new RigidBodyDesc(BodyStatus.Dynamic).setTranslation(new Vector(x, y, z))`. +- `ray.dir` and `ray.origin` are now fields instead of methods. +- 2D rotations are now just a `number` instead of a `Rotation` struct. So instead of doing `rotation.angle`, single use + the number as the rotation angle. +- 3D rotations are now represented by the interface `Rotation` (with fields `{x,y,z,w}`) or the class `Quaternion`. Any + object with these `{x, y, z, w}` fields can be used wherever a `Rotation` is required. +- 2D vectors are now represented by the interface `Vector` (with fields `{x,y}`) or the class `Vector2`). Any object + with these `{x,y}` fields can be used wherever a `Vector` is required. +- 3D vectors are now represented by the interface `Vector` (with fields `{x,y,z}`) or the class `Vector3`). Any object + with these `{x,y,z}` fields can be used wherever a `Vector` is required. + +### v0.2.0 + +See changelogs for v0.2.1 instead. The NPM package for v0.2.0 were missing some files. + +### v0.1.17 + +- Fix bug when ghost forces and/or crashes could be observed when a kinematic body touches a fixed body. + +### v0.1.16 + +- Fix kinematic rigid-body not waking up dynamic bodies it touches. +- Added `new Ray(origin, direction)` constructor instead of `Ray.new(origin, direction)`. + +### v0.1.15 + +- Fix crash when removing a kinematic rigid-body from the World. + +### v0.1.14 + +- Fix issues where force application functions took ownership of the JS vector, preventing the user from freeing + with `Vector.free()` afterwards. + +### v0.1.13 + +- Added `rigidBody.setNextKinematicTranslation` to set the translation of a kinematic rigid-body at the next timestep. +- Added `rigidBody.setNextKinematicRotation` to set the rotation of a kinematic rigid-body at the next timestep. +- Added `rigidBody.predictedTranslation` to get the translation of a kinematic rigid-body at the next timestep. +- Added `rigidBody.predictedRotation` to set the rotation of a kinematic rigid-body at the next timestep. +- Added `Ray` and `RayIntersection` structures for ray-casting. +- Added `world.castRay` to compute the first hit of a ray with the physics scene. +- Fix a bug causing a kinematic rigid-body not to teleport as expected after a `rigidBody.setPosition`. + +### v0.1.12 + +- Added `world.removeCollider(collider)` to remove a collider from the physics world. +- Added `colliderDesc.setTranslation(...)` to set the relative translation of the collider to build wrt. the rigid-body + it is attached to. +- Added `colliderDesc.setRotation(...)` to set the relative rotation of the collider to build wrt. the rigid-body it is + attached to. + +### v0.1.11 + +- Fix a bug causing a crash when the broad-phase proxy handles were recycled. + +### v0.1.10 + +- Fix a determinism problem that could cause rigid-body handle allocation to be non-deterministic after a snapshot + restoration. + +### v0.1.9 + +- Added `world.getCollider(handle)` that retrieves a collider from its integer handle. +- Added `joint.handle()` that returns the integer handle of the joint. + +### v0.1.8 + +- Added `world.forEachRigidBodyHandle(f)` to apply a closure on the integer handle of each rigid-body on the world. +- Added `world.forEachActiveRigidBody(f)` to apply a closure on each rigid-body on the world. +- Added `world.forEachActiveRigidBodyHandle(f)` to apply a closure on the integer handle of each rigid-body on the + world. +- Added `rigidBody.applyForce`, `.applyTorque`, `.applyImpulse`, `.applyTorqueImpulse`, `.applyForceAtPoint`, and + `.applyImpulseAtPoint` to apply a manual force or torque to a rigid-body. +- Added the `EventQueue` structure that can be used to collect and iterate through physics events. +- Added the `Proximity` enum that represents the proximity state of a sensor collider and another collider. +- Added the `world.stepWithEvents(eventQueue)` which executes a physics timestep and collects the physics events into + the given event queue. + +### v0.1.7 + +- Added `world.getRigidBody(handle)` to retrieve a rigid-body from its handle. +- Added `world.getJoint(handle)` to retrieve a joint from its handle. +- Added `rigidBody.rotation()` to retrieve its world-space orientation as a quaternion. +- Added `rigidBody.setTranslation(...)` to set the translation of a rigid-body. +- Added `rigidBody.setRotation(...)` to set the orientation of a rigid-body. +- Added `rigidBody.wakeUp()` to manually wake up a rigid-body. +- Added `rigidBody_desc.setRotation(...)` to set tho orientation of the rigid-body to be created. + +### v0.1.6 + +- Added `world.removeRigidBody(...)` to remove a rigid-body from the world. diff --git a/typescript/Cargo.toml b/typescript/Cargo.toml new file mode 100644 index 000000000..6b4d76565 --- /dev/null +++ b/typescript/Cargo.toml @@ -0,0 +1,26 @@ +[workspace] +members = ["builds/*"] +resolver = "2" + +[profile.release] +debug = false +codegen-units = 1 +#lto = true +strip = true # Workaround for https://github.com/bevyengine/bevy/issues/16030 (the bug only happens in 2D) + +[patch.crates-io] +# Build the JS/Wasm bindings against the rapier crates in this repository rather +# than the versions published on crates.io, so the bindings always stay in sync +# with the engine they ship alongside. The build crates' `rapier{2,3}d` +# dependency requirement (see builds/prepare_builds/templates/Cargo.toml.tera) +# must stay semver-compatible with the in-repo crate version for this to apply. +rapier2d = { path = "../crates/rapier2d" } +rapier3d = { path = "../crates/rapier3d" } + +# parry, nalgebra and simba are still pulled from crates.io, matching the +# versions the in-repo rapier crates depend on. Uncomment to build against local +# checkouts placed next to this repository during development. +#parry2d = { path = "../../parry/crates/parry2d" } +#parry3d = { path = "../../parry/crates/parry3d" } +#nalgebra = { path = "../../nalgebra" } +#simba = { path = "../../simba" } diff --git a/typescript/LICENSE b/typescript/LICENSE new file mode 100644 index 000000000..e579674df --- /dev/null +++ b/typescript/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Dimforge EURL + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/typescript/README.md b/typescript/README.md new file mode 100644 index 000000000..d04cc4bf4 --- /dev/null +++ b/typescript/README.md @@ -0,0 +1,82 @@ +

+ crates.io +

+

+ + + + + Build status + + + + +

+

+ + Website | Documentation | + 2D examples (sources) | + 3D examples (sources) + +

+ +--- + +

+2D and 3D physics engines +for the JavaScript programming language (official bindings). +

+ +--- + +## Building packages manually + +From the root of the repository, run: + +```shell +./builds/prepare_builds/prepare_all_projects.sh +./builds/prepare_builds/build_all_projects.sh +``` + +Note that `prepare_all_projects.sh` only needs to be run once. It needs to be re-run if any file from the +`builds/prepare_builds` directory (and subdirectories) are modified. + +The built packages will be in `builds/rapier2d/pkg`, `builds/rapier3d/pkg`, etc. To build the `-compat` variant of the +packages, run `npm run build` in the `rapier-compat` directory. Note that this will only work if you already ran +`prepare_all_projects.sh`. The compat packages are then generated in, e.g., `rapier-compat/builds/3d/pkg`. + +## Feature selection + +Multiple NPM packages exist for Rapier, depending on your needs: +- [`@dimforge/rapier2d`](https://www.npmjs.com/package/@dimforge/rapier2d) or + [`@dimforge/rapier3d`](https://www.npmjs.com/package/@dimforge/rapier3d): + The main build of the Rapier physics engine for 2D or 3D physics simulation. This should have wide browser + support while offering great performances. This does **not** guarantee cross-platform determinism of the physics + simulation (but it is still locally deterministic, on the same machine). +- [`@dimforge/rapier2d-simd`](https://www.npmjs.com/package/@dimforge/rapier2d-simd) or + [`@dimforge/rapier3d-simd`](https://www.npmjs.com/package/@dimforge/rapier3d-simd): + A build with internal SIMD optimizations enabled. More limited browser support (requires support for [simd128](https://caniuse.com/?search=simd)). +- [`@dimforge/rapier2d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic) or + [`@dimforge/rapier3d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic): + A less optimized build but with a guarantee of a cross-platform deterministic execution of the physics simulation. + +## Bundler support + +Some bundlers will struggle with the `.wasm` file package into the builds above. Alternative `-compat` versions exist +which embed the `.wasm` file into the `.js` sources encoded with base64. This results in a bigger package size, but +much wider bundler support. + +Just append `-compat` to the build you are interested in: +[`rapier2d-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-compat), +[`rapier2d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-simd-compat), +[`rapier2d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic-compat), +[`rapier3d-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-compat), +[`rapier3d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-simd-compat), +[`rapier3d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic-compat). + +## Nightly builds + +Each time a new Pull Request is merged to the `main` branch of the [`rapier.js` repository](https://github.com/dimforge/rapier.js), +an automatic _canary_ build is triggered. Builds published to npmjs under the _canary_ tag does not come with any +stability guarantee and does not follow semver versioning. But it can be a useful solution to try out the latest +features until a proper release is cut. \ No newline at end of file diff --git a/typescript/builds/prepare_builds/Cargo.toml b/typescript/builds/prepare_builds/Cargo.toml new file mode 100644 index 000000000..905de28fe --- /dev/null +++ b/typescript/builds/prepare_builds/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "prepare_builds" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5" } +clap_derive = { version = "4.5" } +tera = "1.20" diff --git a/typescript/builds/prepare_builds/README.md b/typescript/builds/prepare_builds/README.md new file mode 100644 index 000000000..4d05a2faa --- /dev/null +++ b/typescript/builds/prepare_builds/README.md @@ -0,0 +1,17 @@ +# Prepare builds + +This project helps with making specific package: it takes a few parameter to create a (1) folder ready to compile. + +It uses clap so you can pass `-h` to get more info about its parameters. + +## usage + +At workspace root: `cargo run -p prepare_builds -- -d dim2 -f simd`. + +Or use provided scripts: `./builds/prepare_builds/prepare_all_projects.sh && ./builds/prepare_builds/build_all_projects.sh` + +## Technical considerations + +Askama/rinja was not chosen because compiled templates make it difficult to iterate on a folder and parse all templates. + +This folder is in `builds/` only for the workspace member glob to not complain if `builds/` is inexistent or empty. diff --git a/typescript/builds/prepare_builds/build_all_projects.sh b/typescript/builds/prepare_builds/build_all_projects.sh new file mode 100755 index 000000000..0f799a028 --- /dev/null +++ b/typescript/builds/prepare_builds/build_all_projects.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +for entry in builds/* +do + if [[ "$(basename "$entry")" == $(basename $(dirname "${BASH_SOURCE[0]}")) ]]; then + echo "skipping directory: $entry" + continue; + fi + ( + cd $entry + echo "building $entry" + # FIXME: ideally we'd use `npm ci` + # but we'd need to have generated the `package-lock` beforehand and committed them in the repository. + # I'm not sure yet how to store those `package-lock`s yet though. + # They should probably be similar to all packages, but I'm not sure. + npm i; + npm run build; + ) +done diff --git a/typescript/builds/prepare_builds/prepare_all_projects.sh b/typescript/builds/prepare_builds/prepare_all_projects.sh new file mode 100755 index 000000000..bed9c147d --- /dev/null +++ b/typescript/builds/prepare_builds/prepare_all_projects.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +features=(non-deterministic deterministic simd) +dims=(dim2 dim3) + +for feature in ${features[@]}; do + for dim in ${dims[@]}; do + echo "preparing dimension $dim with feature $feature" + cargo run -p prepare_builds -- -d ${dim} -f ${feature} + done +done diff --git a/typescript/builds/prepare_builds/src/main.rs b/typescript/builds/prepare_builds/src/main.rs new file mode 100644 index 000000000..56675e8e1 --- /dev/null +++ b/typescript/builds/prepare_builds/src/main.rs @@ -0,0 +1,182 @@ +use std::{ + error::Error, + fs::{self, File}, + io::Write, + path::{Path, PathBuf}, +}; + +use clap::Parser; +use clap_derive::{Parser, ValueEnum}; +use tera::{Context, Tera}; + +/// Simple program to greet a person +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +pub struct Args { + /// Dimension to use + #[arg(short, long)] + dim: Dimension, + + /// Features to enable + #[arg(short, long)] + feature_set: FeatureSet, +} + +#[derive(ValueEnum, Debug, Clone, Copy)] +pub enum Dimension { + Dim2, + Dim3, +} + +#[derive(ValueEnum, Default, Debug, Clone, Copy)] +pub enum FeatureSet { + #[default] + NonDeterministic, + Deterministic, + Simd, +} + +/// Values to use when creating the new build folder. +pub struct BuildValues { + /// Only the number of dimensions, as sometimes it will be prefixed by "dim" and sometimes post-fixed by "d". + pub dim: String, + /// real name of the additional features to enable in the project + pub feature_set: Vec, + pub target_dir: PathBuf, + pub template_dir: PathBuf, + pub additional_rust_flags: String, + pub additional_wasm_opt_flags: Vec, + pub js_package_name: String, +} + +impl BuildValues { + pub fn new(args: Args) -> Self { + let dim = match args.dim { + Dimension::Dim2 => "2", + Dimension::Dim3 => "3", + }; + let feature_set = match args.feature_set { + FeatureSet::NonDeterministic => vec![], + FeatureSet::Deterministic => vec!["enhanced-determinism"], + FeatureSet::Simd => vec!["simd-stable"], + }; + let js_package_name = match args.feature_set { + FeatureSet::NonDeterministic => format!("rapier{dim}d"), + FeatureSet::Deterministic => format!("rapier{dim}d-deterministic"), + FeatureSet::Simd => format!("rapier{dim}d-simd"), + }; + + let root: PathBuf = env!("CARGO_MANIFEST_DIR").into(); + + Self { + dim: dim.to_string(), + feature_set: feature_set.iter().map(|f| f.to_string()).collect(), + template_dir: root.join("templates/").clone(), + target_dir: root.parent().unwrap().join(&js_package_name).into(), + additional_rust_flags: match args.feature_set { + FeatureSet::Simd => "RUSTFLAGS='-C target-feature=+simd128'".to_string(), + _ => "".to_string(), + }, + additional_wasm_opt_flags: match args.feature_set { + FeatureSet::Simd => vec!["--enable-simd".to_string()], + _ => vec![], + }, + js_package_name, + } + } +} + +fn main() { + let args = Args::parse(); + dbg!(&args); + + let build_values = BuildValues::new(args); + copy_top_level_files_in_directory(&build_values.template_dir, &build_values.target_dir) + .expect("Failed to copy directory"); + process_templates(&build_values).expect("Failed to process templates"); +} + +fn copy_top_level_files_in_directory( + src: impl AsRef, + dest: impl AsRef, +) -> std::io::Result<()> { + let src = src.as_ref(); + let dest = Path::new(&dest); + if dest.exists() { + fs::remove_dir_all(&dest)?; + } + fs::create_dir_all(&dest)?; + + for entry in fs::read_dir(src)? { + let entry = entry?; + let path = entry.path(); + let dest_path = dest.join(path.file_name().unwrap()); + + if !path.is_dir() { + fs::copy(&path, &dest_path)?; + } + } + Ok(()) +} + +/// Process all tera templates in the target directory: +/// - Remove the extension +/// - Render the templates to +/// +fn process_templates(build_values: &BuildValues) -> std::io::Result<()> { + let target_dir = build_values.target_dir.clone(); + + let mut context = Context::new(); + context.insert("dimension", &build_values.dim); + context.insert("additional_features", &build_values.feature_set); + context.insert("additional_rust_flags", &build_values.additional_rust_flags); + context.insert( + "additional_wasm_opt_flags", + &build_values.additional_wasm_opt_flags, + ); + context.insert("js_package_name", &build_values.js_package_name); + + let tera = match Tera::new(target_dir.join("**/*.tera").to_str().unwrap()) { + Ok(t) => t, + Err(e) => { + eprintln!("Parsing error(s): {}", e); + ::std::process::exit(1); + } + }; + dbg!(tera.templates.keys(), &context); + + for entry in fs::read_dir(target_dir)? { + let entry = entry?; + let path = entry.path(); + // For tera templates, remove extension. + if path.extension() == Some(std::ffi::OsStr::new("tera")) { + let mut i = path.iter(); + + // Get path from target directory + for _ in i + .by_ref() + .take_while(|c| *c != build_values.target_dir.file_name().unwrap()) + {} + let path_template = i.as_path(); + match tera.render(path_template.to_str().unwrap(), &context) { + Ok(s) => { + let old_path = path.clone(); + let new_path = path.with_extension(""); + let mut file = File::create(path.join(new_path))?; + file.write_all(s.as_bytes())?; + std::fs::remove_file(old_path)?; + } + Err(e) => { + eprintln!("Error: {}", e); + let mut cause = e.source(); + while let Some(e) = cause { + eprintln!("Reason: {}", e); + cause = e.source(); + } + } + }; + } + } + + Ok(()) +} diff --git a/typescript/builds/prepare_builds/templates/Cargo.toml.tera b/typescript/builds/prepare_builds/templates/Cargo.toml.tera new file mode 100644 index 000000000..da4702979 --- /dev/null +++ b/typescript/builds/prepare_builds/templates/Cargo.toml.tera @@ -0,0 +1,66 @@ +[package] +name = "dimforge_{{ js_package_name }}" # Can't be named rapier{{ dimension }}d which conflicts with the dependency. +version = "0.19.3" +authors = ["Sébastien Crozet "] +description = "{{ dimension }}-dimensional physics engine in Rust - official JS bindings." +documentation = "https://rapier.rs/rustdoc/rapier{{ dimension }}d/index.html" +homepage = "https://rapier.rs" +repository = "https://github.com/dimforge/rapier.js" +readme = "README.md" +keywords = ["physics", "dynamics", "rigid", "real-time", "joints"] +license = "Apache-2.0" +edition = "2018" + +[features] +default = ["dim{{ dimension }}"] +dim{{ dimension }} = [] + +[lib] +name = "rapier_wasm{{ dimension }}d" +path = "../../src/lib.rs" +crate-type = ["cdylib", "rlib"] +required-features = ["dim{{ dimension }}"] + +[lints] +rust.unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(feature, values("dim{% if dimension == "2" %}3{% else %}2{% endif %}"))', +] } + +[dependencies] +# `rapier{2,3}d` is patched to the in-repo crate (see the workspace +# `[patch.crates-io]` in ../../Cargo.toml); this version requirement must stay +# semver-compatible with that crate's version for the patch to take effect. +rapier{{ dimension }}d = { version = "0.34", features = [ + "serde-serialize", + "debug-render", + "profiler", + {%- for feature in additional_features %} + "{{ feature }}", + {%- endfor %} +] } +# The explicit dependency to parry only needed to pin the version; it must match +# the version (and math-backend feature set) the in-repo rapier crate depends on. +parry{{ dimension }}d = { version = "0.29", default-features = false, features = [ + "required-features", +] } +ref-cast = "1" +wasm-bindgen = "0.2.109" +js-sys = "0.3" +nalgebra = "0.35" +serde = { version = "1", features = ["derive", "rc"] } +bincode = "1" +palette = "0.7" + +[package.metadata.wasm-pack.profile.release] +# add -g to keep debug symbols +wasm-opt = [ + '-O4', + '--dce', + # The two options below are needed because of: https://github.com/rustwasm/wasm-pack/issues/1501 + '--enable-bulk-memory', + '--enable-nontrapping-float-to-int', + {%- for flag in additional_wasm_opt_flags %} + '{{ flag }}', + {%- endfor %} +] +#wasm-opt = ['-g'] diff --git a/typescript/builds/prepare_builds/templates/LICENSE b/typescript/builds/prepare_builds/templates/LICENSE new file mode 100644 index 000000000..e579674df --- /dev/null +++ b/typescript/builds/prepare_builds/templates/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2020 Dimforge EURL + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/typescript/builds/prepare_builds/templates/README.md.tera b/typescript/builds/prepare_builds/templates/README.md.tera new file mode 100644 index 000000000..3455eab2b --- /dev/null +++ b/typescript/builds/prepare_builds/templates/README.md.tera @@ -0,0 +1,70 @@ +

+ crates.io +

+

+ + + + + Build status + + + crates.io + + + npm version + + + + +

+

+ + Website | Documentation + +

+ +--- + +

+{{ dimension }}D physics engine +for the JavaScript programming language (official bindings). +

+ +--- + +## Feature selection + +Multiple NPM packages exist for Rapier, depending on your needs: +- [`@dimforge/rapier2d`](https://www.npmjs.com/package/@dimforge/rapier2d) or + [`@dimforge/rapier3d`](https://www.npmjs.com/package/@dimforge/rapier3d): + The main build of the Rapier physics engine for 2D or 3D physics simulation. This should have wide browser + support while offering great performances. This does **not** guarantee cross-platform determinism of the physics + simulation (but it is still locally deterministic, on the same machine). +- [`@dimforge/rapier2d-simd`](https://www.npmjs.com/package/@dimforge/rapier2d-simd) or + [`@dimforge/rapier3d-simd`](https://www.npmjs.com/package/@dimforge/rapier3d-simd): + A build with internal SIMD optimizations enabled. More limited browser support (requires support for [simd128](https://caniuse.com/?search=simd)). +- [`@dimforge/rapier2d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic) or + [`@dimforge/rapier3d-deterministic`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic): + A less optimized build but with a guarantee of a cross-platform deterministic execution of the physics simulation. + +## Bundler support + +Some bundlers will struggle with the `.wasm` file package into the builds above. Alternative `-compat` versions exist +which embed the `.wasm` file into the `.js` sources encoded with base64. This results in a bigger package size, but +much wider bundler support. + +Just append `-compat` to the build you are interested in: +[`rapier2d-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-compat), +[`rapier2d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-simd-compat), +[`rapier2d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier2d-deterministic-compat), +[`rapier3d-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-compat), +[`rapier3d-simd-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-simd-compat), +[`rapier3d-deterministic-compat`](https://www.npmjs.com/package/@dimforge/rapier3d-deterministic-compat). + +## Nightly builds + +Each time a new Pull Request is merged to the `main` branch of the [`rapier.js` repository](https://github.com/dimforge/rapier.js), +an automatic _canary_ build is triggered. Builds published to npmjs under the _canary_ tag does not come with any +stability guarantee and does not follow semver versioning. But it can be a useful solution to try out the latest +features until a proper release is cut. \ No newline at end of file diff --git a/typescript/builds/prepare_builds/templates/build_rust.sh.tera b/typescript/builds/prepare_builds/templates/build_rust.sh.tera new file mode 100755 index 000000000..6fd6ae824 --- /dev/null +++ b/typescript/builds/prepare_builds/templates/build_rust.sh.tera @@ -0,0 +1,15 @@ +#!/bin/sh + +# Cleaning rust because changing rust flags may lead to different build results. +cargo clean + +{{ additional_rust_flags }} npx wasm-pack build +sed -i.bak 's#dimforge_rapier#@dimforge/rapier#g' pkg/package.json +sed -i.bak 's/"rapier_wasm{{ dimension }}d_bg.wasm"/"*"/g' pkg/package.json +( + cd pkg + npm pkg delete sideEffects + npm pkg set 'sideEffects[0]'="./*.js" +) +rm pkg/*.bak +rm pkg/.gitignore diff --git a/typescript/builds/prepare_builds/templates/build_typescript.sh.tera b/typescript/builds/prepare_builds/templates/build_typescript.sh.tera new file mode 100755 index 000000000..8fcce98bc --- /dev/null +++ b/typescript/builds/prepare_builds/templates/build_typescript.sh.tera @@ -0,0 +1,13 @@ +#! /bin/sh + +mkdir -p ./pkg/src +cp -r ../../src.ts/* pkg/src/. +rm -f ./pkg/raw.ts +echo 'export * from "./rapier_wasm{{ dimension }}d"' > pkg/src/raw.ts +# See https://serverfault.com/a/137848 +find pkg/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM{% if dimension == "2" %}3{% else %}2{% endif %}:,\:#endif:d' +npx tsc +# NOTE: we keep the typescripts files into the NPM package for source mapping: see #3 +sed -i.bak 's/"module": "rapier_wasm{{ dimension }}d.js"/"module": "rapier.js"/g' pkg/package.json +sed -i.bak 's/"types": "rapier_wasm{{ dimension }}d.d.ts"/"types": "rapier.d.ts"/g' pkg/package.json +find pkg/ -type f -name '*.bak' | xargs rm diff --git a/typescript/builds/prepare_builds/templates/package.json.tera b/typescript/builds/prepare_builds/templates/package.json.tera new file mode 100644 index 000000000..d596c1960 --- /dev/null +++ b/typescript/builds/prepare_builds/templates/package.json.tera @@ -0,0 +1,26 @@ +{ + "name": "@dimforge/{{ js_package_name }}", + "description": "", + "private": true, + "exports": "./pkg", + "types": "./pkg/rapier.d.ts", + "scripts": { + "build": "npm run clean && npm run build:wasm && npm run build:ts && npm run build:doc", + "build:doc": "typedoc --tsconfig tsconfig_typedoc.json", + "build:wasm": "sh ./build_rust.sh", + "build:ts": "sh ./build_typescript.sh", + "clean": "rimraf pkg" + }, + "//": "Better keep rimraf version in sync with wasm-pack, see https://github.com/rustwasm/wasm-pack/issues/1444", + "devDependencies": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13", + "typescript": "~5.4.5" + }, + "dependencies": { + "wasm-pack": "^0.12.1" + }, + "sideEffects": [ + "./*.js" + ] +} \ No newline at end of file diff --git a/typescript/builds/prepare_builds/templates/tsconfig.json b/typescript/builds/prepare_builds/templates/tsconfig.json new file mode 100644 index 000000000..1614ac78e --- /dev/null +++ b/typescript/builds/prepare_builds/templates/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "outDir": "./pkg", + "module": "ES6", + "target": "es6", + "lib": ["es6", "ESNext.Disposable"], + "moduleResolution": "node", + "sourceMap": true, + "declaration": true, + "rootDirs": ["./pkg", "./pkg/src"] + }, + "files": ["./pkg/src/rapier.ts"] +} diff --git a/typescript/builds/prepare_builds/templates/tsconfig_typedoc.json b/typescript/builds/prepare_builds/templates/tsconfig_typedoc.json new file mode 100644 index 000000000..f6958d5cf --- /dev/null +++ b/typescript/builds/prepare_builds/templates/tsconfig_typedoc.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "./pkg", + "moduleResolution": "node", + "sourceMap": true, + "declaration": true, + "lib": ["es6", "ESNext.Disposable"] + }, + "files": ["./pkg/rapier.d.ts"] +} diff --git a/typescript/builds/prepare_builds/templates/typedoc.json.tera b/typescript/builds/prepare_builds/templates/typedoc.json.tera new file mode 100644 index 000000000..d96bb7a64 --- /dev/null +++ b/typescript/builds/prepare_builds/templates/typedoc.json.tera @@ -0,0 +1,42 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": [ + "./pkg/rapier.d.ts" + ], + "out": "./docs", + "readme": "none", + "excludeExternals": true, + "excludeNotDocumented": false, + "intentionallyNotExported": [ + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawBroadPhase", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawCCDSolver", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawColliderSet", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawEventQueue", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawImpulseJointSet", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawMultibodyJointSet", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawIntegrationParameters", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawIslandManager", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawNarrowPhase", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawPhysicsPipeline", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawRigidBodySet", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawSerializationPipeline", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawContactManifold", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawShape", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawGenericJoint", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawJointAxis", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawRotation", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawVector", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawPointColliderProjection", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawPointProjection", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayColliderIntersection", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayColliderHit", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawRayIntersection", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawColliderShapeCastHit", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawShapeContact", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawShapeCastHit", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawQueryPipeline", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawDeserializedWorld", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawDebugRenderPipeline", + "pkg/rapier_wasm{{ dimension }}d.d.ts:RawContactForceEvent" + ] +} \ No newline at end of file diff --git a/typescript/package-lock.json b/typescript/package-lock.json new file mode 100644 index 000000000..f82e399b4 --- /dev/null +++ b/typescript/package-lock.json @@ -0,0 +1,506 @@ +{ + "name": "rapier.js", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "prettier": "2.7.1", + "typedoc": "0.23.19", + "typescript": "4.8.4", + "wasm-opt": "1.4.0", + "wasm-pack": "0.12.1" + } + }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "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, + "license": "MIT" + }, + "node_modules/binary-install": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/binary-install/-/binary-install-1.1.0.tgz", + "integrity": "sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "axios": "^0.26.1", + "rimraf": "^3.0.2", + "tar": "^6.1.11" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "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, + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "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, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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/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" + } + }, + "node_modules/glob/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" + }, + "engines": { + "node": "*" + } + }, + "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/marked": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", + "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "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, + "license": "ISC", + "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", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "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, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "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/prettier": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", + "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shiki": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz", + "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jsonc-parser": "^3.0.0", + "vscode-oniguruma": "^1.6.1", + "vscode-textmate": "^6.0.0" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/typedoc": { + "version": "0.23.19", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.19.tgz", + "integrity": "sha512-70jPL0GQnSJtgQqI7ifOWxpTXrB3sxc4SWPPRn3K0wdx3txI6ZIT/ZYMF39dNg2Gjmql45cO+cAKXJp0TpqOVA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "lunr": "^2.3.9", + "marked": "^4.0.19", + "minimatch": "^5.1.0", + "shiki": "^0.11.1" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 14.14" + }, + "peerDependencies": { + "typescript": "4.6.x || 4.7.x || 4.8.x" + } + }, + "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, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/vscode-oniguruma": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", + "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-textmate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz", + "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/wasm-opt": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/wasm-opt/-/wasm-opt-1.4.0.tgz", + "integrity": "sha512-wIsxxp0/FOSphokH4VOONy1zPkVREQfALN+/JTvJPK8gFSKbsmrcfECu2hT7OowqPfb4WEMSMceHgNL0ipFRyw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.9", + "tar": "^6.1.13" + }, + "bin": { + "wasm-opt": "bin/wasm-opt.js" + } + }, + "node_modules/wasm-pack": { + "version": "0.12.1", + "resolved": "https://registry.npmjs.org/wasm-pack/-/wasm-pack-0.12.1.tgz", + "integrity": "sha512-dIyKWUumPFsGohdndZjDXRFaokUT/kQS+SavbbiXVAvA/eN4riX5QNdB6AhXQx37zNxluxQkuixZUgJ8adKjOg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT OR Apache-2.0", + "dependencies": { + "binary-install": "^1.0.1" + }, + "bin": { + "wasm-pack": "run.js" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.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, + "license": "ISC" + }, + "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, + "license": "ISC" + } + } +} diff --git a/typescript/package.json b/typescript/package.json new file mode 100644 index 000000000..ce0eec04c --- /dev/null +++ b/typescript/package.json @@ -0,0 +1,12 @@ +{ + "scripts": { + "fmt": "prettier ." + }, + "devDependencies": { + "prettier": "2.7.1", + "typedoc": "0.23.19", + "typescript": "4.8.4", + "wasm-opt": "1.4.0", + "wasm-pack": "0.12.1" + } +} diff --git a/typescript/publish_all_canary.sh b/typescript/publish_all_canary.sh new file mode 100755 index 000000000..211554299 --- /dev/null +++ b/typescript/publish_all_canary.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +for entry in builds/*/pkg +do + ( + echo "Publishing $entry" + cd $entry; npm version 0.0.0-$(git rev-parse --short HEAD)-$(date '+%Y%m%d') --git-tag-version false; + npm publish --tag canary --access public; + ) +done; + +for entry in rapier-compat/builds/*/pkg +do + ( + echo "Publishing $entry" + cd $entry; npm version 0.0.0-$(git rev-parse --short HEAD)-$(date '+%Y%m%d') --git-tag-version false; + npm publish --tag canary --access public; + ) +done; \ No newline at end of file diff --git a/typescript/publish_all_prod.sh b/typescript/publish_all_prod.sh new file mode 100755 index 000000000..f04915cb5 --- /dev/null +++ b/typescript/publish_all_prod.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +for entry in builds/*/pkg +do + ( + echo "Publishing $entry" + cd $entry; + npm publish --access public; + ) +done; + +for entry in rapier-compat/builds/*/pkg +do + ( + echo "Publishing $entry" + cd $entry; + npm publish --access public; + ) +done; \ No newline at end of file diff --git a/typescript/rapier-compat/README.md b/typescript/rapier-compat/README.md new file mode 100644 index 000000000..5d440ec26 --- /dev/null +++ b/typescript/rapier-compat/README.md @@ -0,0 +1,16 @@ +# tsconfig json files + +- tsconfig.common.json - shared TypeScript options +- tsconfig.pkg2d.json - config for compiling rapier2d-compat +- tsconfig.pkg3d.json - config for compiling rapier3d-compat +- tconfig.json - for IDE (VSCode) and unit tests. Includes Jest types. + +## Generation steps + +Check `./package.json scripts`, which are used by CI. + +Summary: + +- build rust wasm projects into their dedicated folder in `./builds/` +- copy common javascript and generate dimension specific javascript into a common `./pkg` folder +- copy that `pkg` folder in each folder from `./builds` diff --git a/typescript/rapier-compat/build-rust.sh b/typescript/rapier-compat/build-rust.sh new file mode 100755 index 000000000..2acd18f88 --- /dev/null +++ b/typescript/rapier-compat/build-rust.sh @@ -0,0 +1,50 @@ +#!/bin/bash + + +help() +{ + printf "Usage: %s: [-d 2|3] [-f deterministim|non-deterministic|simd]\n" $0 +} + +while getopts :d:f: name +do + case $name in + d) + dimension="$OPTARG";; + f) + feature="$OPTARG";; + ?) help ; exit 1;; + esac +done + +if [[ -z "$dimension" ]]; then + help; exit 2; +fi +if [[ -z "$feature" ]]; then + help; exit 3; +fi + +if [[ $feature == "non-deterministic" ]]; then + feature_postfix="" +else + feature_postfix="-${feature}" +fi + +rust_source_directory="../builds/rapier${dimension}d${feature_postfix}" + +if [ ! -d "$rust_source_directory" ]; then + echo "Directory $rust_source_directory does not exist"; + echo "You may want to generate rust projects first."; + help + exit 4; +fi + +# Working dir in wasm-pack is the project root so we need that "../../" + +if [[ $feature == "simd" ]]; then + export additional_rustflags='-C target-feature=+simd128' +else + export additional_rustflags='' +fi + +RUSTFLAGS="${additional_rustflags}" wasm-pack --verbose build --target web --out-dir "../../rapier-compat/builds/${dimension}d${feature_postfix}/wasm-build" "$rust_source_directory" diff --git a/typescript/rapier-compat/fix_raw_file.sh b/typescript/rapier-compat/fix_raw_file.sh new file mode 100644 index 000000000..66f8bfafc --- /dev/null +++ b/typescript/rapier-compat/fix_raw_file.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +for feature in \ +2d 2d-deterministic 2d-simd \ +3d 3d-deterministic 3d-simd +do + +echo 'export * from "'"./rapier_wasm$feature"'"' > builds/${feature}/pkg/raw.d.ts +echo 'export * from "'"./rapier_wasm$feature"'"' > builds/${feature}/pkg/raw.d.ts + +done; \ No newline at end of file diff --git a/typescript/rapier-compat/gen_src.sh b/typescript/rapier-compat/gen_src.sh new file mode 100755 index 000000000..24ccc4418 --- /dev/null +++ b/typescript/rapier-compat/gen_src.sh @@ -0,0 +1,58 @@ +# Copy source and remove #if sections - similar to script in ../rapierXd +set -e + +gen_js() { + DIM=$1 + GENOUT="./gen${DIM}" + + # Make output directories + mkdir -p ${GENOUT} + + # Copy common sources + cp -r ../src.ts/* $GENOUT + + # Copy compat mode override sources + rm -f "${GENOUT}/raw.ts" "${GENOUT}/init.ts" + cp -r ./src${DIM}/* $GENOUT +} + +gen_js "2d" +gen_js "3d" + +# See https://serverfault.com/a/137848 +find gen2d/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM3:,\:#endif:d' +find gen3d/ -type f -print0 | LC_ALL=C xargs -0 sed -i.bak '\:#if DIM2:,\:#endif:d' + +# Clean up backup files. +find gen2d/ -type f -name '*.bak' | xargs rm +find gen3d/ -type f -name '*.bak' | xargs rm + +for features_set in \ +"2" "2 deterministic" "2 simd" \ +"3" "3 deterministic" "3 simd" +do + + set -- $features_set # Convert the "tuple" into the param args $1 $2... + dimension=$1 + if [ -z "$2" ]; then + feature="${1}d"; + else + feature="${1}d-${2}"; + fi + + mkdir -p ./builds/${feature}/pkg/ + + cp ./builds/${feature}/wasm-build/rapier_wasm* ./builds/${feature}/pkg/ + cp -r ./gen${dimension}d ./builds/${feature}/ + + # copy tsconfig, as they contain paths + cp ./tsconfig.common.json ./tsconfig.json ./builds/${feature}/ + cp ./tsconfig.pkg${dimension}d.json ./builds/${feature}/tsconfig.pkg.json + + # "import.meta" causes Babel to choke, but the code path is never taken so just remove it. + sed -i.bak 's/import.meta.url/""/g' ./builds/${feature}/pkg/rapier_wasm${dimension}d.js + + # Clean up backup files. + find ./builds/${feature}/pkg/ -type f -name '*.bak' | xargs rm + +done diff --git a/typescript/rapier-compat/package-lock.json b/typescript/rapier-compat/package-lock.json new file mode 100644 index 000000000..22b6f0231 --- /dev/null +++ b/typescript/rapier-compat/package-lock.json @@ -0,0 +1,10500 @@ +{ + "name": "build-rapier", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "build-rapier", + "dependencies": { + "base64-js": "^1.5.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^23.0.2", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-terser": "0.1.0", + "@rollup/plugin-typescript": "^9.0.2", + "@types/jest": "^29.2.1", + "jest": "^29.2.2", + "rimraf": "^3.0.2", + "rollup": "^3.2.5", + "rollup-plugin-base64": "^1.0.1", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-filesize": "^9.1.2", + "ts-jest": "^29.0.3", + "tslib": "^2.4.1", + "typescript": "^4.8.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.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==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "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": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "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/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==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + }, + "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/@babel/parser": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", + "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "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==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@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.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "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 + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "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, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.2.1.tgz", + "integrity": "sha512-MF8Adcw+WPLZGBiNxn76DOuczG3BhODTcMlDCA4+cFi41OkaY/lyI0XUUhi73F88Y+7IHoGmD80pN5CtxQUdSw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.2.2.tgz", + "integrity": "sha512-susVl8o2KYLcZhhkvSB+b7xX575CX3TmSvxfeDjpRko7KmT89rHkXj6XkDkNpSeFMBzIENw5qIchO9HC9Sem+A==", + "dev": true, + "dependencies": { + "@jest/console": "^29.2.1", + "@jest/reporters": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.2.0", + "jest-config": "^29.2.2", + "jest-haste-map": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-resolve-dependencies": "^29.2.2", + "jest-runner": "^29.2.2", + "jest-runtime": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "jest-watcher": "^29.2.2", + "micromatch": "^4.0.4", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.2.2.tgz", + "integrity": "sha512-OWn+Vhu0I1yxuGBJEFFekMYc8aGBGrY4rt47SOh/IFaI+D7ZHCk7pKRiSoZ2/Ml7b0Ony3ydmEHRx/tEOC7H1A==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-mock": "^29.2.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.2.2.tgz", + "integrity": "sha512-zwblIZnrIVt8z/SiEeJ7Q9wKKuB+/GS4yZe9zw7gMqfGf4C5hBLGrVyxu1SzDbVSqyMSlprKl3WL1r80cBNkgg==", + "dev": true, + "dependencies": { + "expect": "^29.2.2", + "jest-snapshot": "^29.2.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.2.2.tgz", + "integrity": "sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.2.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.2.2.tgz", + "integrity": "sha512-nqaW3y2aSyZDl7zQ7t1XogsxeavNpH6kkdq+EpXncIDvAkjvFD7hmhcIs1nWloengEWUoWqkqSA6MSbf9w6DgA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.2.1", + "jest-mock": "^29.2.2", + "jest-util": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.2.2.tgz", + "integrity": "sha512-/nt+5YMh65kYcfBhj38B3Hm0Trk4IsuMXNDGKE/swp36yydBWfz3OXkLqkSvoAtPW8IJMSJDFCbTM2oj5SNprw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.2.2", + "@jest/expect": "^29.2.2", + "@jest/types": "^29.2.1", + "jest-mock": "^29.2.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.2.2.tgz", + "integrity": "sha512-AzjL2rl2zJC0njIzcooBvjA4sJjvdoq98sDuuNs4aNugtLPSQ+91nysGKRF0uY1to5k0MdGMdOBggUsPqvBcpA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.2.1", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "jest-worker": "^29.2.1", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "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, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.2.1.tgz", + "integrity": "sha512-lS4+H+VkhbX6z64tZP7PAUwPqhwj3kbuEHcaLuaBuB+riyaX7oa1txe0tXgrFj5hRWvZKvqO7LZDlNWeJ7VTPA==", + "dev": true, + "dependencies": { + "@jest/console": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.2.2.tgz", + "integrity": "sha512-Cuc1znc1pl4v9REgmmLf0jBd3Y65UXJpioGYtMr/JNpQEIGEzkmHhy6W6DLbSsXeUA13TDzymPv0ZGZ9jH3eIw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.2.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.2.2.tgz", + "integrity": "sha512-aPe6rrletyuEIt2axxgdtxljmzH8O/nrov4byy6pDw9S8inIrTV+2PnjyP/oFHMSynzGxJ2s6OHowBNMXp/Jzg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.2.1", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.2.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "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/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "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, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "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, + "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/@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/@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==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "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/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/git": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + } + }, + "node_modules/@npmcli/git/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", + "dev": true + }, + "node_modules/@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + } + }, + "node_modules/@npmcli/run-script": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", + "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "23.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.2.tgz", + "integrity": "sha512-e9ThuiRf93YlVxc4qNIurvv+Hp9dnD+4PjOqQs5vAYfcZ3+AXSrcdzXnVjWxcGQOa6KGJFcRZyUI3ktWLavFjg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.26.4" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-commonjs/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==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", + "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.0", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-terser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.1.0.tgz", + "integrity": "sha512-N2KK+qUfHX2hBzVzM41UWGLrEmcjVC37spC8R3c9mt3oEDFKh3N2e12/lLp9aVSt86veR0TQiCNQXrm8C6aiUQ==", + "dev": true, + "dependencies": { + "terser": "^5.15.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.x || ^3.x" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-9.0.2.tgz", + "integrity": "sha512-/sS93vmHUMjzDUsl5scNQr1mUlNE1QjBBvOhmRwJCH8k2RRhDIm3c977B3wdu3t3Ap17W6dDeXP3hj1P1Un1bA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "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 + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "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, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "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, + "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, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "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, + "dependencies": { + "@types/node": "*" + } + }, + "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 + }, + "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, + "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, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.1.tgz", + "integrity": "sha512-nKixEdnGDqFOZkMTF74avFNr3yRqB1ZJ6sRZv5/28D5x2oLN14KApv7F9mfDT/vUic0L3tRCsh3XWpWjtJisUQ==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.22.tgz", + "integrity": "sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw==", + "dev": true + }, + "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 + }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "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 + }, + "node_modules/@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "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 + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "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/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "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, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "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, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "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, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "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/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, + "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": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "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 + }, + "node_modules/babel-jest": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.2.2.tgz", + "integrity": "sha512-kkq2QSDIuvpgfoac3WZ1OOcHsQQDU5xYk2Ql7tLdJ8BVAYbefEXal+NfS45Y5LVZA7cxC8KYcQMObpCt1J025w==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.2.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "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, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=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, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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, + "dependencies": { + "babel-plugin-jest-hoist": "^29.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "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/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "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/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/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/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/brotli-size": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", + "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", + "dev": true, + "dependencies": { + "duplexer": "0.1.1" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "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, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "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 + }, + "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/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "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/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "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/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, + "engines": { + "node": ">=10" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "dev": true + }, + "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 + }, + "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, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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 + }, + "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/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "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, + "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, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "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 + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "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/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "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/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff-sequences": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.2.0.tgz", + "integrity": "sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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/duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==", + "dev": true + }, + "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, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "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==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "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/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=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, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "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" + } + }, + "node_modules/expect": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.2.2.tgz", + "integrity": "sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.2.2", + "jest-get-type": "^29.2.0", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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 + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.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.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "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-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/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "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, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/filesize": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", + "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", + "dev": true, + "engines": { + "node": ">= 0.4.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": "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/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "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/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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, + "engines": { + "node": ">=8.0.0" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "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/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gzip-size/node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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-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-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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 + }, + "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==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "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, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "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, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "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": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "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/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "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-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-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-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "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==", + "dev": true, + "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, + "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==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "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-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "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, + "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, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=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, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.2.2.tgz", + "integrity": "sha512-r+0zCN9kUqoON6IjDdjbrsWobXM/09Nd45kIPRD8kloaRh1z5ZCMdVsgLXGxmlL7UpAJsvCYOQNO+NjvG/gqiQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.2.2", + "@jest/types": "^29.2.1", + "import-local": "^3.0.2", + "jest-cli": "^29.2.2" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "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, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.2.2.tgz", + "integrity": "sha512-upSdWxx+Mh4DV7oueuZndJ1NVdgtTsqM4YgywHEx05UMH5nxxA2Qu9T9T9XVuR021XxqSoaKvSmmpAbjwwwxMw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.2.2", + "@jest/expect": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.2.1", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-runtime": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "p-limit": "^3.1.0", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.2.2.tgz", + "integrity": "sha512-R45ygnnb2CQOfd8rTPFR+/fls0d+1zXS6JPYTBBrnLPrhr58SSuPTiA5Tplv8/PXpz4zXR/AYNxmwIj6J6nrvg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.2.2.tgz", + "integrity": "sha512-Q0JX54a5g1lP63keRfKR8EuC7n7wwny2HoTRDb8cx78IwQOiaYUVZAdjViY3WcTxpR02rPUpvNVmZ1fkIlZPcw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.2.2", + "@jest/types": "^29.2.1", + "babel-jest": "^29.2.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.2.2", + "jest-environment-node": "^29.2.2", + "jest-get-type": "^29.2.0", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-runner": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.2.1.tgz", + "integrity": "sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.2.0", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.2.1.tgz", + "integrity": "sha512-sGP86H/CpWHMyK3qGIGFCgP6mt+o5tu9qG4+tobl0LNdgny0aitLXs9/EBacLy3Bwqy+v4uXClqJgASJWcruYw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "jest-util": "^29.2.1", + "pretty-format": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.2.2.tgz", + "integrity": "sha512-B7qDxQjkIakQf+YyrqV5dICNs7tlCO55WJ4OMSXsqz1lpI/0PmeuXdx2F7eU8rnPbRkUR/fItSSUh0jvE2y/tw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.2.2", + "@jest/fake-timers": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-mock": "^29.2.2", + "jest-util": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.2.1.tgz", + "integrity": "sha512-wF460rAFmYc6ARcCFNw4MbGYQjYkvjovb9GBT+W10Um8q5nHq98jD6fHZMDMO3tA56S8XnmNkM8GcA8diSZfnA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.2.1", + "jest-worker": "^29.2.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.2.1.tgz", + "integrity": "sha512-1YvSqYoiurxKOJtySc+CGVmw/e1v4yNY27BjWTVzp0aTduQeA7pdieLiW05wTYG/twlKOp2xS/pWuikQEmklug==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz", + "integrity": "sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.2.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.2.1.tgz", + "integrity": "sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.2.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-mock": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.2.2.tgz", + "integrity": "sha512-1leySQxNAnivvbcx0sCB37itu8f4OX2S/+gxLAV4Z62shT4r4dTG9tACDywUAEZoLSr36aYUTsVp3WKwWt4PMQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-util": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "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, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.2.2.tgz", + "integrity": "sha512-3gaLpiC3kr14rJR3w7vWh0CBX2QAhfpfiQTwrFPvVrcHe5VUBtIXaR004aWE/X9B2CFrITOQAp5gxLONGrk6GA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.2.2.tgz", + "integrity": "sha512-wWOmgbkbIC2NmFsq8Lb+3EkHuW5oZfctffTGvwsA4JcJ1IRk8b2tg+hz44f0lngvRTeHvp3Kyix9ACgudHH9aQ==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.2.0", + "jest-snapshot": "^29.2.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.2.2.tgz", + "integrity": "sha512-1CpUxXDrbsfy9Hr9/1zCUUhT813kGGK//58HeIw/t8fa/DmkecEwZSWlb1N/xDKXg3uCFHQp1GCvlSClfImMxg==", + "dev": true, + "dependencies": { + "@jest/console": "^29.2.1", + "@jest/environment": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.2.0", + "jest-environment-node": "^29.2.2", + "jest-haste-map": "^29.2.1", + "jest-leak-detector": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-resolve": "^29.2.2", + "jest-runtime": "^29.2.2", + "jest-util": "^29.2.1", + "jest-watcher": "^29.2.2", + "jest-worker": "^29.2.1", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.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, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.2.2.tgz", + "integrity": "sha512-TpR1V6zRdLynckKDIQaY41od4o0xWL+KOPUCZvJK2bu5P1UXhjobt5nJ2ICNeIxgyj9NGkO0aWgDqYPVhDNKjA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.2.2", + "@jest/fake-timers": "^29.2.2", + "@jest/globals": "^29.2.2", + "@jest/source-map": "^29.2.0", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-mock": "^29.2.2", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.2.2.tgz", + "integrity": "sha512-GfKJrpZ5SMqhli3NJ+mOspDqtZfJBryGA8RIBxF+G+WbDoC7HCqKaeAss4Z/Sab6bAW11ffasx8/vGsj83jyjA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.2.2", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.2.2", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.2.1", + "jest-get-type": "^29.2.0", + "jest-haste-map": "^29.2.1", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "natural-compare": "^1.4.0", + "pretty-format": "^29.2.1", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/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/jest-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.2.2.tgz", + "integrity": "sha512-eJXATaKaSnOuxNfs8CLHgdABFgUrd0TtWS8QckiJ4L/QVDF4KVbZFBBOwCBZHOS0Rc5fOxqngXeGXE3nGQkpQA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.2.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "leven": "^3.1.0", + "pretty-format": "^29.2.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.2.2.tgz", + "integrity": "sha512-j2otfqh7mOvMgN2WlJ0n7gIx9XCMWntheYGlBK7+5g3b1Su13/UAK7pdKGyd4kDlrLwtH2QPvRv5oNIxWvsJ1w==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.2.1", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.2.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "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": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "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-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.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, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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": "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/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "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/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, + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "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, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "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 + }, + "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.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "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, + "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, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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/minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.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", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.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", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "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", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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 + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-install-checks/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-packlist": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", + "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "dev": true, + "dependencies": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + } + }, + "node_modules/npm-pick-manifest/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "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, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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": "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/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, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "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/pacote": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", + "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "dev": true, + "dependencies": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "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": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "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/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "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, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.2.1.tgz", + "integrity": "sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "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==", + "dev": true, + "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, + "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": [ + { + "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/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 + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/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, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/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, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "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-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, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "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/rollup": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.2.5.tgz", + "integrity": "sha512-/Ha7HhVVofduy+RKWOQJrxe4Qb3xyZo+chcpYiD8SoQa4AG7llhupUtyfKSSrdBM2mWJjhM8wZwmbY23NmlIYw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-base64/-/rollup-plugin-base64-1.0.1.tgz", + "integrity": "sha512-IbdX8fjuXO/Op3hYmRPjVo0VwcSenwsQDaDTFdoe+70B5ZGoLMtr96L2yhHXCfxv7HwZVvxZqLsuWj6VwzRt3g==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.1.0" + } + }, + "node_modules/rollup-plugin-base64/node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0" + } + }, + "node_modules/rollup-plugin-base64/node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/rollup-plugin-base64/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/rollup-plugin-base64/node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "peer": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/rollup-plugin-filesize": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.2.tgz", + "integrity": "sha512-m2fE9hFaKgWKisJzyWXctOFKlgMRelo/58HgeC0lXUK/qykxiqkr6bsrotlvo2bvrwPsjgT7scNdQSr6qtl37A==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.13.8", + "boxen": "^5.0.0", + "brotli-size": "4.0.0", + "colors": "1.4.0", + "filesize": "^6.1.0", + "gzip-size": "^6.0.0", + "pacote": "^11.2.7", + "terser": "^5.6.0" + }, + "engines": { + "node": ">=10.0.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": [ + { + "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-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "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/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "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/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 + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "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/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + }, + "engines": { + "node": ">= 10" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.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==", + "dev": true + }, + "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 + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.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, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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-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, + "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, + "engines": { + "node": ">=6" + } + }, + "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/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "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==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "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, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "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 + }, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "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==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "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, + "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, + "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/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "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==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "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, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/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": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "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, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "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/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "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, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "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" + } + } + }, + "dependencies": { + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@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, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.1.tgz", + "integrity": "sha512-EWZ4mE2diW3QALKvDMiXnbZpRvlj+nayZ112nK93SnhqOtpdsbVD4W+2tEoT3YNBAG9RBR0ISY758ZkOgsn6pQ==", + "dev": true + }, + "@babel/core": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.6.tgz", + "integrity": "sha512-D2Ue4KHpc6Ys2+AxpIx1BZ8+UegLLLE2p3KJEuJRKmokHOtl49jQ5ny1773KsGLZs8MQvBidAF6yWUJxRqtKtg==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.6", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-module-transforms": "^7.19.6", + "@babel/helpers": "^7.19.4", + "@babel/parser": "^7.19.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + } + }, + "@babel/generator": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.1.tgz", + "integrity": "sha512-u1dMdBUmA7Z0rBB97xh8pIhviK7oItYOkjbsCxTWMknyvbQRBwX7/gn4JXurRdirWMFh+ZtYARqkA6ydogVZpg==", + "dev": true, + "requires": { + "@babel/types": "^7.20.0", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@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, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.20.0", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + } + }, + "@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==", + "dev": true + }, + "@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==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.6.tgz", + "integrity": "sha512-fCmcfQo/KYr/VXXDIyd3CBGZ6AFhPFy1TfSEJ+PilGVlQT6jcbqtHAM4C1EciRqMza7/TpOUZliuSH+U6HAhJw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.19.4", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.19.1", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.6", + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dev": true, + "requires": { + "@babel/types": "^7.19.4" + } + }, + "@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==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@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==", + "dev": true + }, + "@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 + }, + "@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==", + "dev": true + }, + "@babel/helpers": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.1.tgz", + "integrity": "sha512-J77mUVaDTUJFZ5BpP6mMn6OIl3rEWymk2ZxDBQJUG3P+PbmyMcF3bYWvz0ma69Af1oobDqT/iAsvzhB58xhQUg==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.20.1", + "@babel/types": "^7.20.0" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^1.9.0" + } + }, + "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, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "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, + "requires": { + "color-name": "1.1.3" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.1.tgz", + "integrity": "sha512-hp0AYxaZJhxULfM1zyp7Wgr+pSUKBcP3M+PHnSzWGdXOzg/kHWIgiUWARvubhUKGOEw3xqY4x+lyZ9ytBVcELw==", + "dev": true + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@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, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/runtime": { + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.8.tgz", + "integrity": "sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.20.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.1.tgz", + "integrity": "sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.20.1", + "@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.1", + "@babel/types": "^7.20.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.0.tgz", + "integrity": "sha512-Jlgt3H0TajCW164wkTOTzHkZb075tMQMULzrLUoUeKmO7eFL96GgDxf7/Axhc5CAuKE3KFyVW1p6ysKsi2oXAg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@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 + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@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, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@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 + }, + "@jest/console": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.2.1.tgz", + "integrity": "sha512-MF8Adcw+WPLZGBiNxn76DOuczG3BhODTcMlDCA4+cFi41OkaY/lyI0XUUhi73F88Y+7IHoGmD80pN5CtxQUdSw==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.2.2.tgz", + "integrity": "sha512-susVl8o2KYLcZhhkvSB+b7xX575CX3TmSvxfeDjpRko7KmT89rHkXj6XkDkNpSeFMBzIENw5qIchO9HC9Sem+A==", + "dev": true, + "requires": { + "@jest/console": "^29.2.1", + "@jest/reporters": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.2.0", + "jest-config": "^29.2.2", + "jest-haste-map": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-resolve-dependencies": "^29.2.2", + "jest-runner": "^29.2.2", + "jest-runtime": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "jest-watcher": "^29.2.2", + "micromatch": "^4.0.4", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.2.2.tgz", + "integrity": "sha512-OWn+Vhu0I1yxuGBJEFFekMYc8aGBGrY4rt47SOh/IFaI+D7ZHCk7pKRiSoZ2/Ml7b0Ony3ydmEHRx/tEOC7H1A==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-mock": "^29.2.2" + } + }, + "@jest/expect": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.2.2.tgz", + "integrity": "sha512-zwblIZnrIVt8z/SiEeJ7Q9wKKuB+/GS4yZe9zw7gMqfGf4C5hBLGrVyxu1SzDbVSqyMSlprKl3WL1r80cBNkgg==", + "dev": true, + "requires": { + "expect": "^29.2.2", + "jest-snapshot": "^29.2.2" + } + }, + "@jest/expect-utils": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.2.2.tgz", + "integrity": "sha512-vwnVmrVhTmGgQzyvcpze08br91OL61t9O0lJMDyb6Y/D8EKQ9V7rGUb/p7PDt0GPzK0zFYqXWFo4EO2legXmkg==", + "dev": true, + "requires": { + "jest-get-type": "^29.2.0" + } + }, + "@jest/fake-timers": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.2.2.tgz", + "integrity": "sha512-nqaW3y2aSyZDl7zQ7t1XogsxeavNpH6kkdq+EpXncIDvAkjvFD7hmhcIs1nWloengEWUoWqkqSA6MSbf9w6DgA==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^29.2.1", + "jest-mock": "^29.2.2", + "jest-util": "^29.2.1" + } + }, + "@jest/globals": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.2.2.tgz", + "integrity": "sha512-/nt+5YMh65kYcfBhj38B3Hm0Trk4IsuMXNDGKE/swp36yydBWfz3OXkLqkSvoAtPW8IJMSJDFCbTM2oj5SNprw==", + "dev": true, + "requires": { + "@jest/environment": "^29.2.2", + "@jest/expect": "^29.2.2", + "@jest/types": "^29.2.1", + "jest-mock": "^29.2.2" + } + }, + "@jest/reporters": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.2.2.tgz", + "integrity": "sha512-AzjL2rl2zJC0njIzcooBvjA4sJjvdoq98sDuuNs4aNugtLPSQ+91nysGKRF0uY1to5k0MdGMdOBggUsPqvBcpA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.2.1", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "jest-worker": "^29.2.1", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@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, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@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, + "requires": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.2.1.tgz", + "integrity": "sha512-lS4+H+VkhbX6z64tZP7PAUwPqhwj3kbuEHcaLuaBuB+riyaX7oa1txe0tXgrFj5hRWvZKvqO7LZDlNWeJ7VTPA==", + "dev": true, + "requires": { + "@jest/console": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.2.2.tgz", + "integrity": "sha512-Cuc1znc1pl4v9REgmmLf0jBd3Y65UXJpioGYtMr/JNpQEIGEzkmHhy6W6DLbSsXeUA13TDzymPv0ZGZ9jH3eIw==", + "dev": true, + "requires": { + "@jest/test-result": "^29.2.1", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.2.2.tgz", + "integrity": "sha512-aPe6rrletyuEIt2axxgdtxljmzH8O/nrov4byy6pDw9S8inIrTV+2PnjyP/oFHMSynzGxJ2s6OHowBNMXp/Jzg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.2.1", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.2.1", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "@jest/types": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.2.1.tgz", + "integrity": "sha512-O/QNDQODLnINEPAI0cl9U6zUIDXEWXt6IC1o2N2QENuos7hlGUIthlKyV4p6ki3TvXFX071blj8HUhgLGquPjw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@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==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@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 + }, + "@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==", + "dev": true + }, + "@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, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@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, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@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 + }, + "@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==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@npmcli/git": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz", + "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^1.3.2", + "lru-cache": "^6.0.0", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^6.1.1", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz", + "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz", + "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz", + "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^1.0.2", + "@npmcli/promise-spawn": "^1.3.2", + "node-gyp": "^7.1.0", + "read-package-json-fast": "^2.0.1" + } + }, + "@rollup/plugin-commonjs": { + "version": "23.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-23.0.2.tgz", + "integrity": "sha512-e9ThuiRf93YlVxc4qNIurvv+Hp9dnD+4PjOqQs5vAYfcZ3+AXSrcdzXnVjWxcGQOa6KGJFcRZyUI3ktWLavFjg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.26.4" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@rollup/plugin-node-resolve": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.0.1.tgz", + "integrity": "sha512-ReY88T7JhJjeRVbfCyNj+NXAG3IIsVMsX9b5/9jC98dRP8/yxlZdz7mHZbHk5zHr24wZZICS5AcXsFZAXYUQEg==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.0", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-terser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.1.0.tgz", + "integrity": "sha512-N2KK+qUfHX2hBzVzM41UWGLrEmcjVC37spC8R3c9mt3oEDFKh3N2e12/lLp9aVSt86veR0TQiCNQXrm8C6aiUQ==", + "dev": true, + "requires": { + "terser": "^5.15.1" + } + }, + "@rollup/plugin-typescript": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-9.0.2.tgz", + "integrity": "sha512-/sS93vmHUMjzDUsl5scNQr1mUlNE1QjBBvOhmRwJCH8k2RRhDIm3c977B3wdu3t3Ap17W6dDeXP3hj1P1Un1bA==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + } + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + } + }, + "@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 + }, + "@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@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, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/babel__core": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@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, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@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, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.2.tgz", + "integrity": "sha512-FcFaxOr2V5KZCviw1TnutEMVUVsGt4D2hP1TAfXZAMKuHYW3xQhe3jTxNPWutgCJ3/X1c5yX8ZoGVEItxKbwBg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/estree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==", + "dev": true + }, + "@types/fs-extra": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", + "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@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, + "requires": { + "@types/node": "*" + } + }, + "@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 + }, + "@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, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@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, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.2.1.tgz", + "integrity": "sha512-nKixEdnGDqFOZkMTF74avFNr3yRqB1ZJ6sRZv5/28D5x2oLN14KApv7F9mfDT/vUic0L3tRCsh3XWpWjtJisUQ==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/node": { + "version": "17.0.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.22.tgz", + "integrity": "sha512-8FwbVoG4fy+ykY86XCAclKZDORttqE5/s7dyWZKLXTdv3vRy5HozBEinG5IqhvPXXzIZEcTVbuHlQEI6iuwcmw==", + "dev": true + }, + "@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 + }, + "@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, + "@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 + }, + "@types/yargs": { + "version": "17.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.13.tgz", + "integrity": "sha512-9sWaruZk2JGxIQU+IhI1fhPYRcQ0UuTNuKuCW9bR5fp7qi2Llf7WDzNa17Cy7TKnh3cdxDOiyTu6gaLS0eDatg==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@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 + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "dev": true + }, + "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, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "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, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "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, + "requires": { + "type-fest": "^0.21.3" + } + }, + "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 + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "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 + }, + "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, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "babel-jest": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.2.2.tgz", + "integrity": "sha512-kkq2QSDIuvpgfoac3WZ1OOcHsQQDU5xYk2Ql7tLdJ8BVAYbefEXal+NfS45Y5LVZA7cxC8KYcQMObpCt1J025w==", + "dev": true, + "requires": { + "@jest/transform": "^29.2.2", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.2.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "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, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "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, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "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, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "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, + "requires": { + "babel-plugin-jest-hoist": "^29.2.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "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 + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "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 + } + } + }, + "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, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brotli-size": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz", + "integrity": "sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA==", + "dev": true, + "requires": { + "duplexer": "0.1.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "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, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "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, + "requires": { + "node-int64": "^0.4.0" + } + }, + "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 + }, + "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 + }, + "builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=", + "dev": true + }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001429", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001429.tgz", + "integrity": "sha512-511ThLu1hF+5RRRt0zYCf2U2yRr9GPF6m5y90SBCWsvSoYoW7yAGlv/elyPaNfvGCkp6kj/KFZWU0BMA69Prsg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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 + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "ci-info": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.5.0.tgz", + "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", + "dev": true + }, + "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 + }, + "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 + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "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 + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "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, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "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 + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "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 + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "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 + }, + "diff-sequences": { + "version": "29.2.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.2.0.tgz", + "integrity": "sha512-413SY5JpYeSBZxmenGEmCVQ8mCgtFJF0w9PROdaS6z987XC2Pd2GOKqOITLtMftmyFZqgtCOb/QA7/Z3ZXfzIw==", + "dev": true + }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "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==", + "dev": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "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==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "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, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "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 + }, + "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 + }, + "estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.2.2.tgz", + "integrity": "sha512-hE09QerxZ5wXiOhqkXy5d2G9ar+EqOyifnCXCpMNu+vZ6DG9TJ6CO2c2kPDSLqERTTWrO7OZj8EkYHQqSd78Yw==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.2.2", + "jest-get-type": "^29.2.0", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "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 + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@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" + } + }, + "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 + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "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, + "requires": { + "bser": "2.1.1" + } + }, + "filesize": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-6.4.0.tgz", + "integrity": "sha512-mjFIpOHC4jbfcTfoh4rkWpI31mF7viw9ikj/JyLoKzqlwG/YsefKfvYlYhdYdg/9mtK2z1AzgN/0LvVQ3zdlSQ==", + "dev": true + }, + "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, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "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, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "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 + }, + "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 + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "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, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "gzip-size": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", + "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==", + "dev": true, + "requires": { + "duplexer": "^0.1.2" + }, + "dependencies": { + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + } + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "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 + }, + "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==", + "dev": true + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "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, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "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 + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "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, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "ignore-walk": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", + "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "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 + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "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 + }, + "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, + "requires": { + "builtin-modules": "^3.3.0" + } + }, + "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, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "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==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, + "is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=", + "dev": true + }, + "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 + }, + "is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true + }, + "is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "requires": { + "@types/estree": "*" + } + }, + "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 + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "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 + }, + "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, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "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, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "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, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.2.2.tgz", + "integrity": "sha512-r+0zCN9kUqoON6IjDdjbrsWobXM/09Nd45kIPRD8kloaRh1z5ZCMdVsgLXGxmlL7UpAJsvCYOQNO+NjvG/gqiQ==", + "dev": true, + "requires": { + "@jest/core": "^29.2.2", + "@jest/types": "^29.2.1", + "import-local": "^3.0.2", + "jest-cli": "^29.2.2" + } + }, + "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, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.2.2.tgz", + "integrity": "sha512-upSdWxx+Mh4DV7oueuZndJ1NVdgtTsqM4YgywHEx05UMH5nxxA2Qu9T9T9XVuR021XxqSoaKvSmmpAbjwwwxMw==", + "dev": true, + "requires": { + "@jest/environment": "^29.2.2", + "@jest/expect": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.2.1", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-runtime": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "p-limit": "^3.1.0", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.2.2.tgz", + "integrity": "sha512-R45ygnnb2CQOfd8rTPFR+/fls0d+1zXS6JPYTBBrnLPrhr58SSuPTiA5Tplv8/PXpz4zXR/AYNxmwIj6J6nrvg==", + "dev": true, + "requires": { + "@jest/core": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.2.2.tgz", + "integrity": "sha512-Q0JX54a5g1lP63keRfKR8EuC7n7wwny2HoTRDb8cx78IwQOiaYUVZAdjViY3WcTxpR02rPUpvNVmZ1fkIlZPcw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.2.2", + "@jest/types": "^29.2.1", + "babel-jest": "^29.2.2", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.2.2", + "jest-environment-node": "^29.2.2", + "jest-get-type": "^29.2.0", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-runner": "^29.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.2.1.tgz", + "integrity": "sha512-gfh/SMNlQmP3MOUgdzxPOd4XETDJifADpT937fN1iUGz+9DgOu2eUPHH25JDkLVcLwwqxv3GzVyK4VBUr9fjfA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.2.0", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + } + }, + "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, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.2.1.tgz", + "integrity": "sha512-sGP86H/CpWHMyK3qGIGFCgP6mt+o5tu9qG4+tobl0LNdgny0aitLXs9/EBacLy3Bwqy+v4uXClqJgASJWcruYw==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "jest-util": "^29.2.1", + "pretty-format": "^29.2.1" + } + }, + "jest-environment-node": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.2.2.tgz", + "integrity": "sha512-B7qDxQjkIakQf+YyrqV5dICNs7tlCO55WJ4OMSXsqz1lpI/0PmeuXdx2F7eU8rnPbRkUR/fItSSUh0jvE2y/tw==", + "dev": true, + "requires": { + "@jest/environment": "^29.2.2", + "@jest/fake-timers": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-mock": "^29.2.2", + "jest-util": "^29.2.1" + } + }, + "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 + }, + "jest-haste-map": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.2.1.tgz", + "integrity": "sha512-wF460rAFmYc6ARcCFNw4MbGYQjYkvjovb9GBT+W10Um8q5nHq98jD6fHZMDMO3tA56S8XnmNkM8GcA8diSZfnA==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.2.0", + "jest-util": "^29.2.1", + "jest-worker": "^29.2.1", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.2.1.tgz", + "integrity": "sha512-1YvSqYoiurxKOJtySc+CGVmw/e1v4yNY27BjWTVzp0aTduQeA7pdieLiW05wTYG/twlKOp2xS/pWuikQEmklug==", + "dev": true, + "requires": { + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + } + }, + "jest-matcher-utils": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.2.2.tgz", + "integrity": "sha512-4DkJ1sDPT+UX2MR7Y3od6KtvRi9Im1ZGLGgdLFLm4lPexbTaCgJW5NN3IOXlQHF7NSHY/VHhflQ+WoKtD/vyCw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.2.1", + "jest-get-type": "^29.2.0", + "pretty-format": "^29.2.1" + } + }, + "jest-message-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.2.1.tgz", + "integrity": "sha512-Dx5nEjw9V8C1/Yj10S/8ivA8F439VS8vTq1L7hEgwHFn9ovSKNpYW/kwNh7UglaEgXO42XxzKJB+2x0nSglFVw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.2.1", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.2.1", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.2.2.tgz", + "integrity": "sha512-1leySQxNAnivvbcx0sCB37itu8f4OX2S/+gxLAV4Z62shT4r4dTG9tACDywUAEZoLSr36aYUTsVp3WKwWt4PMQ==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "jest-util": "^29.2.1" + } + }, + "jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "requires": {} + }, + "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 + }, + "jest-resolve": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.2.2.tgz", + "integrity": "sha512-3gaLpiC3kr14rJR3w7vWh0CBX2QAhfpfiQTwrFPvVrcHe5VUBtIXaR004aWE/X9B2CFrITOQAp5gxLONGrk6GA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.2.1", + "jest-validate": "^29.2.2", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.2.2.tgz", + "integrity": "sha512-wWOmgbkbIC2NmFsq8Lb+3EkHuW5oZfctffTGvwsA4JcJ1IRk8b2tg+hz44f0lngvRTeHvp3Kyix9ACgudHH9aQ==", + "dev": true, + "requires": { + "jest-regex-util": "^29.2.0", + "jest-snapshot": "^29.2.2" + } + }, + "jest-runner": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.2.2.tgz", + "integrity": "sha512-1CpUxXDrbsfy9Hr9/1zCUUhT813kGGK//58HeIw/t8fa/DmkecEwZSWlb1N/xDKXg3uCFHQp1GCvlSClfImMxg==", + "dev": true, + "requires": { + "@jest/console": "^29.2.1", + "@jest/environment": "^29.2.2", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.2.0", + "jest-environment-node": "^29.2.2", + "jest-haste-map": "^29.2.1", + "jest-leak-detector": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-resolve": "^29.2.2", + "jest-runtime": "^29.2.2", + "jest-util": "^29.2.1", + "jest-watcher": "^29.2.2", + "jest-worker": "^29.2.1", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + } + } + }, + "jest-runtime": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.2.2.tgz", + "integrity": "sha512-TpR1V6zRdLynckKDIQaY41od4o0xWL+KOPUCZvJK2bu5P1UXhjobt5nJ2ICNeIxgyj9NGkO0aWgDqYPVhDNKjA==", + "dev": true, + "requires": { + "@jest/environment": "^29.2.2", + "@jest/fake-timers": "^29.2.2", + "@jest/globals": "^29.2.2", + "@jest/source-map": "^29.2.0", + "@jest/test-result": "^29.2.1", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.2.1", + "jest-message-util": "^29.2.1", + "jest-mock": "^29.2.2", + "jest-regex-util": "^29.2.0", + "jest-resolve": "^29.2.2", + "jest-snapshot": "^29.2.2", + "jest-util": "^29.2.1", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.2.2.tgz", + "integrity": "sha512-GfKJrpZ5SMqhli3NJ+mOspDqtZfJBryGA8RIBxF+G+WbDoC7HCqKaeAss4Z/Sab6bAW11ffasx8/vGsj83jyjA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.2.2", + "@jest/transform": "^29.2.2", + "@jest/types": "^29.2.1", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.2.2", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.2.1", + "jest-get-type": "^29.2.0", + "jest-haste-map": "^29.2.1", + "jest-matcher-utils": "^29.2.2", + "jest-message-util": "^29.2.1", + "jest-util": "^29.2.1", + "natural-compare": "^1.4.0", + "pretty-format": "^29.2.1", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "jest-util": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.2.1.tgz", + "integrity": "sha512-P5VWDj25r7kj7kl4pN2rG/RN2c1TLfYYYZYULnS/35nFDjBai+hBeo3MDrYZS7p6IoY3YHZnt2vq4L6mKnLk0g==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.2.2.tgz", + "integrity": "sha512-eJXATaKaSnOuxNfs8CLHgdABFgUrd0TtWS8QckiJ4L/QVDF4KVbZFBBOwCBZHOS0Rc5fOxqngXeGXE3nGQkpQA==", + "dev": true, + "requires": { + "@jest/types": "^29.2.1", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.2.0", + "leven": "^3.1.0", + "pretty-format": "^29.2.1" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "29.2.2", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.2.2.tgz", + "integrity": "sha512-j2otfqh7mOvMgN2WlJ0n7gIx9XCMWntheYGlBK7+5g3b1Su13/UAK7pdKGyd4kDlrLwtH2QPvRv5oNIxWvsJ1w==", + "dev": true, + "requires": { + "@jest/test-result": "^29.2.1", + "@jest/types": "^29.2.1", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.2.1", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.2.1.tgz", + "integrity": "sha512-ROHTZ+oj7sBrgtv46zZ84uWky71AoYi0vEV9CdEtc1FQunsoAGe5HbQmW76nI5QWdvECVPrSi1MCVUmizSavMg==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.2.1", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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 + }, + "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, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "dev": true + }, + "jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "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 + }, + "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 + }, + "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, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "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, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "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, + "requires": { + "semver": "^6.0.0" + } + }, + "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 + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "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 + }, + "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, + "requires": { + "mime-db": "1.52.0" + } + }, + "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 + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minipass": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "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 + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "node-gyp": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", + "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.3", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "request": "^2.88.2", + "rimraf": "^3.0.2", + "semver": "^7.3.2", + "tar": "^6.0.2", + "which": "^2.0.2" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "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 + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz", + "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==", + "dev": true, + "requires": { + "semver": "^7.1.1" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz", + "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "semver": "^7.3.4", + "validate-npm-package-name": "^3.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "npm-packlist": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz", + "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==", + "dev": true, + "requires": { + "glob": "^7.1.6", + "ignore-walk": "^3.0.3", + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-pick-manifest": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz", + "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==", + "dev": true, + "requires": { + "npm-install-checks": "^4.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^8.1.2", + "semver": "^7.3.4" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "npm-registry-fetch": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz", + "integrity": "sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA==", + "dev": true, + "requires": { + "make-fetch-happen": "^9.0.1", + "minipass": "^3.1.3", + "minipass-fetch": "^1.3.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.0.0", + "npm-package-arg": "^8.0.0" + } + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "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, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "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, + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "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, + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "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, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "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 + }, + "pacote": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz", + "integrity": "sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg==", + "dev": true, + "requires": { + "@npmcli/git": "^2.1.0", + "@npmcli/installed-package-contents": "^1.0.6", + "@npmcli/promise-spawn": "^1.2.0", + "@npmcli/run-script": "^1.8.2", + "cacache": "^15.0.5", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.3", + "mkdirp": "^1.0.3", + "npm-package-arg": "^8.0.1", + "npm-packlist": "^2.1.4", + "npm-pick-manifest": "^6.0.0", + "npm-registry-fetch": "^11.0.0", + "promise-retry": "^2.0.1", + "read-package-json-fast": "^2.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.1.0" + } + }, + "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, + "requires": { + "@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" + } + }, + "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 + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "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, + "requires": { + "find-up": "^4.0.0" + } + }, + "pretty-format": { + "version": "29.2.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.2.1.tgz", + "integrity": "sha512-Y41Sa4aLCtKAXvwuIpTvcFBkyeYp2gdFWzXGA+ZNES3VwURIB165XO/z7CjETwzCCS53MjW/rLMyyqEnTtaOfA==", + "dev": true, + "requires": { + "@jest/schemas": "^29.0.0", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "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 + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "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, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "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 + }, + "qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "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 + }, + "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 + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "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, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "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, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + } + } + }, + "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==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "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, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "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 + }, + "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 + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rollup": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.2.5.tgz", + "integrity": "sha512-/Ha7HhVVofduy+RKWOQJrxe4Qb3xyZo+chcpYiD8SoQa4AG7llhupUtyfKSSrdBM2mWJjhM8wZwmbY23NmlIYw==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + }, + "rollup-plugin-base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-base64/-/rollup-plugin-base64-1.0.1.tgz", + "integrity": "sha512-IbdX8fjuXO/Op3hYmRPjVo0VwcSenwsQDaDTFdoe+70B5ZGoLMtr96L2yhHXCfxv7HwZVvxZqLsuWj6VwzRt3g==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^3.1.0" + }, + "dependencies": { + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "peer": true, + "requires": { + "fsevents": "~2.3.2" + } + } + } + }, + "rollup-plugin-copy": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.4.0.tgz", + "integrity": "sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==", + "dev": true, + "requires": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + } + }, + "rollup-plugin-filesize": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.2.tgz", + "integrity": "sha512-m2fE9hFaKgWKisJzyWXctOFKlgMRelo/58HgeC0lXUK/qykxiqkr6bsrotlvo2bvrwPsjgT7scNdQSr6qtl37A==", + "dev": true, + "requires": { + "@babel/runtime": "^7.13.8", + "boxen": "^5.0.0", + "brotli-size": "4.0.0", + "colors": "1.4.0", + "filesize": "^6.1.0", + "gzip-size": "^6.0.0", + "pacote": "^11.2.7", + "terser": "^5.6.0" + } + }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "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 + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz", + "integrity": "sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.1", + "socks": "^2.6.1" + } + }, + "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 + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "stack-utils": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "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, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, + "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 + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "terser": { + "version": "5.15.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", + "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "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, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "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==", + "dev": true + }, + "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, + "requires": { + "is-number": "^7.0.0" + } + }, + "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==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.1", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "7.x", + "yargs-parser": "^21.0.1" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "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, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", + "dev": true, + "requires": { + "builtins": "^1.0.3" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + } + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "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, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "17.6.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.0.tgz", + "integrity": "sha512-8H/wTDqlSwoSnScvV2N/JHfLWOKuh5MVla9hqLjK3nsfyy6Y4kDSYSvkU5YCUEPOSnRXfIyx3Sq+B/IWudTo4g==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "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==", + "dev": true + }, + "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 + } + } +} diff --git a/typescript/rapier-compat/package.json b/typescript/rapier-compat/package.json new file mode 100644 index 000000000..f97e9cf4c --- /dev/null +++ b/typescript/rapier-compat/package.json @@ -0,0 +1,59 @@ +{ + "name": "build-rapier", + "description": "Build scripts for compatibility package with inlined webassembly as base64.", + "private": true, + "scripts": { + "build-rust-2d-non-deterministic": "./build-rust.sh -f non-deterministic -d 2", + "build-rust-2d-deterministic": "./build-rust.sh -f deterministic -d 2", + "build-rust-2d-simd": "./build-rust.sh -f simd -d 2", + "build-rust-2d-all": "npm run build-rust-2d-non-deterministic && npm run build-rust-2d-deterministic && npm run build-rust-2d-simd", + "build-rust-3d-non-deterministic": "./build-rust.sh -f non-deterministic -d 3", + "build-rust-3d-deterministic": "./build-rust.sh -f deterministic -d 3", + "build-rust-3d-simd": "./build-rust.sh -f simd -d 3", + "build-rust-3d-all": "npm run build-rust-3d-non-deterministic && npm run build-rust-3d-deterministic && npm run build-rust-3d-simd", + "build-rust-all": "npm run build-rust-2d-all && npm run build-rust-3d-all", + "build-genjs": "sh ./gen_src.sh", + "build-js": "rollup --config rollup.config.js --bundleConfigAsCjs", + "fix-raw-file": "sh ./fix_raw_file.sh", + "build": "npm run clean && npm run build-rust-all && npm run build-genjs && npm run build-js && npm run fix-raw-file", + "clean": "rimraf gen2d gen3d builds", + "test": "jest --detectOpenHandles", + "all": "npm run build" + }, + "dependencies": { + "base64-js": "^1.5.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^23.0.2", + "@rollup/plugin-node-resolve": "^15.0.1", + "@rollup/plugin-typescript": "^9.0.2", + "@rollup/plugin-terser": "0.1.0", + "@types/jest": "^29.2.1", + "jest": "^29.2.2", + "rimraf": "^3.0.2", + "rollup": "^3.2.5", + "rollup-plugin-base64": "^1.0.1", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-filesize": "^9.1.2", + "ts-jest": "^29.0.3", + "tslib": "^2.4.1", + "typescript": "^4.8.4" + }, + "jest": { + "roots": [ + "/tests" + ], + "preset": "ts-jest", + "collectCoverageFrom": [ + "builds/**/pkg/**/*.js" + ], + "transformIgnorePatterns": [ + "[/\\\\]node_modules[/\\\\].+\\.(js|ts)$", + "builds/.*/[/\\\\]pkg[/\\\\].+\\.(js|ts)$" + ], + "moduleFileExtensions": [ + "ts", + "js" + ] + } +} diff --git a/typescript/rapier-compat/rollup.config.js b/typescript/rapier-compat/rollup.config.js new file mode 100644 index 000000000..d127c6714 --- /dev/null +++ b/typescript/rapier-compat/rollup.config.js @@ -0,0 +1,85 @@ +import commonjs from "@rollup/plugin-commonjs"; +import {nodeResolve} from "@rollup/plugin-node-resolve"; +import typescript from "@rollup/plugin-typescript"; +import terser from "@rollup/plugin-terser"; +import path from "path"; +import {base64} from "rollup-plugin-base64"; +import copy from "rollup-plugin-copy"; +import filesize from "rollup-plugin-filesize"; + +const config = (dim, features_postfix) => ({ + input: `builds/${features_postfix}/gen${dim}/rapier.ts`, + output: [ + { + file: `builds/${features_postfix}/pkg/rapier.mjs`, + format: "es", + sourcemap: true, + exports: "named", + }, + { + file: `builds/${features_postfix}/pkg/rapier.cjs`, + format: "cjs", + sourcemap: true, + exports: "named", + }, + ], + plugins: [ + copy({ + targets: [ + { + src: `builds/${features_postfix}/wasm-build/package.json`, + dest: `builds/${features_postfix}/pkg/`, + transform(content) { + let config = JSON.parse(content.toString()); + config.name = `@dimforge/rapier${features_postfix}-compat`; + config.description += + " Compatibility package with inlined webassembly as base64."; + config.types = "rapier.d.ts"; + config.main = "rapier.cjs"; + config.module = "rapier.mjs"; + config.exports = { + ".": { + types: "./rapier.d.ts", + require: "./rapier.cjs", + import: "./rapier.mjs", + }, + }; + // delete config.module; + config.files = ["*"]; + return JSON.stringify(config, undefined, 2); + }, + }, + { + src: `../rapier${features_postfix}/LICENSE`, + dest: `builds/${features_postfix}/pkg`, + }, + { + src: `../rapier${features_postfix}/README.md`, + dest: `builds/${features_postfix}/pkg`, + }, + ], + }), + base64({include: "**/*.wasm"}), + terser(), + nodeResolve(), + commonjs(), + typescript({ + tsconfig: path.resolve( + __dirname, + `builds/${features_postfix}/tsconfig.pkg.json`, + ), + sourceMap: true, + inlineSources: true, + }), + filesize(), + ], +}); + +export default [ + config("2d", "2d"), + config("2d", "2d-deterministic"), + config("2d", "2d-simd"), + config("3d", "3d"), + config("3d", "3d-deterministic"), + config("3d", "3d-simd"), +]; diff --git a/typescript/rapier-compat/src2d/init.ts b/typescript/rapier-compat/src2d/init.ts new file mode 100644 index 000000000..668bfe130 --- /dev/null +++ b/typescript/rapier-compat/src2d/init.ts @@ -0,0 +1,12 @@ +// @ts-ignore +import wasmBase64 from "../pkg/rapier_wasm2d_bg.wasm"; +import wasmInit from "../pkg/rapier_wasm2d"; +import base64 from "base64-js"; + +/** + * Initializes RAPIER. + * Has to be called and awaited before using any library methods. + */ +export async function init() { + await wasmInit(base64.toByteArray(wasmBase64 as unknown as string).buffer); +} diff --git a/typescript/rapier-compat/src2d/raw.ts b/typescript/rapier-compat/src2d/raw.ts new file mode 100644 index 000000000..4eadaffad --- /dev/null +++ b/typescript/rapier-compat/src2d/raw.ts @@ -0,0 +1 @@ +export * from "../pkg/rapier_wasm2d"; diff --git a/typescript/rapier-compat/src3d/init.ts b/typescript/rapier-compat/src3d/init.ts new file mode 100644 index 000000000..15b14ada1 --- /dev/null +++ b/typescript/rapier-compat/src3d/init.ts @@ -0,0 +1,12 @@ +// @ts-ignore +import wasmBase64 from "../pkg/rapier_wasm3d_bg.wasm"; +import wasmInit from "../pkg/rapier_wasm3d"; +import base64 from "base64-js"; + +/** + * Initializes RAPIER. + * Has to be called and awaited before using any library methods. + */ +export async function init() { + await wasmInit(base64.toByteArray(wasmBase64 as unknown as string).buffer); +} diff --git a/typescript/rapier-compat/src3d/raw.ts b/typescript/rapier-compat/src3d/raw.ts new file mode 100644 index 000000000..b123ae6b3 --- /dev/null +++ b/typescript/rapier-compat/src3d/raw.ts @@ -0,0 +1 @@ +export * from "../pkg/rapier_wasm3d"; diff --git a/typescript/rapier-compat/tests/World2d.test.ts b/typescript/rapier-compat/tests/World2d.test.ts new file mode 100644 index 000000000..45a3bb72f --- /dev/null +++ b/typescript/rapier-compat/tests/World2d.test.ts @@ -0,0 +1,23 @@ +import {init, Vector2, World} from "../builds/2d-deterministic/pkg"; + +describe("2d/World", () => { + let world: World; + + beforeAll(init); + + afterAll(async () => { + await Promise.resolve(); + }); + + beforeEach(() => { + world = new World(new Vector2(0, 9.8)); + }); + + afterEach(() => { + world.free(); + }); + + test("constructor", () => { + expect(world.colliders.len()).toBe(0); + }); +}); diff --git a/typescript/rapier-compat/tests/World3d.test.ts b/typescript/rapier-compat/tests/World3d.test.ts new file mode 100644 index 000000000..e0ddd5467 --- /dev/null +++ b/typescript/rapier-compat/tests/World3d.test.ts @@ -0,0 +1,23 @@ +import {init, Vector3, World} from "../builds/3d-deterministic/pkg"; + +describe("3d/World", () => { + let world: World; + + beforeAll(init); + + afterAll(async () => { + await Promise.resolve(); + }); + + beforeEach(() => { + world = new World(new Vector3(0, 9.8, 0)); + }); + + afterEach(() => { + world.free(); + }); + + test("constructor", () => { + expect(world.colliders.len()).toBe(0); + }); +}); diff --git a/typescript/rapier-compat/tests/math2d.test.ts b/typescript/rapier-compat/tests/math2d.test.ts new file mode 100644 index 000000000..a75605650 --- /dev/null +++ b/typescript/rapier-compat/tests/math2d.test.ts @@ -0,0 +1,15 @@ +import {Vector2, VectorOps} from "../builds/2d-deterministic/pkg"; + +describe("2d/math", () => { + test("Vector2", () => { + const v = new Vector2(0, 1); + expect(v.x).toBe(0); + expect(v.y).toBe(1); + }); + + test("VectorOps", () => { + const v = VectorOps.new(0, 1); + expect(v.x).toBe(0); + expect(v.y).toBe(1); + }); +}); diff --git a/typescript/rapier-compat/tests/math3d.test.ts b/typescript/rapier-compat/tests/math3d.test.ts new file mode 100644 index 000000000..2ff194cc6 --- /dev/null +++ b/typescript/rapier-compat/tests/math3d.test.ts @@ -0,0 +1,17 @@ +import {Vector3, VectorOps} from "../builds/3d-deterministic/pkg"; + +describe("3d/math", () => { + test("Vector3", () => { + const v = new Vector3(0, 1, 2); + expect(v.x).toBe(0); + expect(v.y).toBe(1); + expect(v.z).toBe(2); + }); + + test("VectorOps", () => { + const v = VectorOps.new(0, 1, 2); + expect(v.x).toBe(0); + expect(v.y).toBe(1); + expect(v.z).toBe(2); + }); +}); diff --git a/typescript/rapier-compat/tsconfig.common.json b/typescript/rapier-compat/tsconfig.common.json new file mode 100644 index 000000000..37bd7d7f6 --- /dev/null +++ b/typescript/rapier-compat/tsconfig.common.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "ES6", + "target": "es6", + "noEmitOnError": true, + "noImplicitAny": true, + "noImplicitThis": true, + "strictFunctionTypes": true, + "lib": ["es6", "DOM"], + "moduleResolution": "node", + "esModuleInterop": true, + "sourceMap": true, + "declaration": true + } +} diff --git a/typescript/rapier-compat/tsconfig.json b/typescript/rapier-compat/tsconfig.json new file mode 100644 index 000000000..beeca9441 --- /dev/null +++ b/typescript/rapier-compat/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.common.json", + "compilerOptions": { + "lib": ["es6", "DOM"], + "esModuleInterop": true, + "types": ["jest"], + "outDir": "./dist" + }, + "include": ["./tests/**/*.test.ts"] +} diff --git a/typescript/rapier-compat/tsconfig.pkg2d.json b/typescript/rapier-compat/tsconfig.pkg2d.json new file mode 100644 index 000000000..77349ed25 --- /dev/null +++ b/typescript/rapier-compat/tsconfig.pkg2d.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.common.json", + "compilerOptions": { + "rootDir": "./gen2d", + "outDir": "./2d" + }, + "files": ["./gen2d/rapier.ts"] +} diff --git a/typescript/rapier-compat/tsconfig.pkg3d.json b/typescript/rapier-compat/tsconfig.pkg3d.json new file mode 100644 index 000000000..3d7323e88 --- /dev/null +++ b/typescript/rapier-compat/tsconfig.pkg3d.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.common.json", + "compilerOptions": { + "rootDir": "./gen3d", + "outDir": "." + }, + "files": ["./gen3d/rapier.ts"] +} diff --git a/typescript/src.ts/coarena.ts b/typescript/src.ts/coarena.ts new file mode 100644 index 000000000..9bf978a54 --- /dev/null +++ b/typescript/src.ts/coarena.ts @@ -0,0 +1,70 @@ +export class Coarena { + fconv: Float64Array; + uconv: Uint32Array; + data: Array; + size: number; + + public constructor() { + this.fconv = new Float64Array(1); + this.uconv = new Uint32Array(this.fconv.buffer); + this.data = new Array(); + this.size = 0; + } + + public set(handle: number, data: T) { + let i = this.index(handle); + while (this.data.length <= i) { + this.data.push(null); + } + + if (this.data[i] == null) this.size += 1; + this.data[i] = data; + } + + public len(): number { + return this.size; + } + + public delete(handle: number) { + let i = this.index(handle); + if (i < this.data.length) { + if (this.data[i] != null) this.size -= 1; + this.data[i] = null; + } + } + + public clear() { + this.data = new Array(); + } + + public get(handle: number): T | null { + let i = this.index(handle); + if (i < this.data.length) { + return this.data[i]; + } else { + return null; + } + } + + public forEach(f: (elt: T) => void) { + for (const elt of this.data) { + if (elt != null) f(elt); + } + } + + public getAll(): Array { + return this.data.filter((elt) => elt != null); + } + + private index(handle: number): number { + /// Extracts the index part of a handle (the lower 32 bits). + /// This is done by first injecting the handle into an Float64Array + /// which is itself injected into an Uint32Array (at construction time). + /// The 0-th value of the Uint32Array will become the `number` integer + /// representation of the lower 32 bits. + /// Also `this.uconv[1]` then contains the generation number as a `number`, + /// which we don’t really need. + this.fconv[0] = handle; + return this.uconv[0]; + } +} diff --git a/typescript/src.ts/control/character_controller.ts b/typescript/src.ts/control/character_controller.ts new file mode 100644 index 000000000..4c10f82c2 --- /dev/null +++ b/typescript/src.ts/control/character_controller.ts @@ -0,0 +1,395 @@ +import {RawKinematicCharacterController, RawCharacterCollision} from "../raw"; +import {Rotation, Vector, VectorOps, scratchBuffer} from "../math"; +import { + BroadPhase, + Collider, + ColliderSet, + InteractionGroups, + NarrowPhase, + Shape, +} from "../geometry"; +import {QueryFilterFlags, World} from "../pipeline"; +import {IntegrationParameters, RigidBody, RigidBodySet} from "../dynamics"; + +/** + * A collision between the character and an obstacle hit on its path. + */ +export class CharacterCollision { + /** The collider involved in the collision. Null if the collider no longer exists in the physics world. */ + public collider: Collider | null; + /** The translation delta applied to the character before this collision took place. */ + public translationDeltaApplied: Vector; + /** The translation delta the character would move after this collision if there is no other obstacles. */ + public translationDeltaRemaining: Vector; + /** The time-of-impact between the character and the obstacles. */ + public toi: number; + /** The world-space contact point on the collider when the collision happens. */ + public witness1: Vector; + /** The local-space contact point on the character when the collision happens. */ + public witness2: Vector; + /** The world-space outward contact normal on the collider when the collision happens. */ + public normal1: Vector; + /** The local-space outward contact normal on the character when the collision happens. */ + public normal2: Vector; +} + +/** + * A character controller for controlling kinematic bodies and parentless colliders by hitting + * and sliding against obstacles. + */ +export class KinematicCharacterController { + private raw: RawKinematicCharacterController; + private rawCharacterCollision: RawCharacterCollision; + + private params: IntegrationParameters; + private broadPhase: BroadPhase; + private narrowPhase: NarrowPhase; + private bodies: RigidBodySet; + private colliders: ColliderSet; + private _applyImpulsesToDynamicBodies: boolean; + private _characterMass: number | null; + + constructor( + offset: number, + params: IntegrationParameters, + broadPhase: BroadPhase, + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + ) { + this.params = params; + this.bodies = bodies; + this.colliders = colliders; + this.broadPhase = broadPhase; + this.narrowPhase = narrowPhase; + this.raw = new RawKinematicCharacterController(offset); + this.rawCharacterCollision = new RawCharacterCollision(); + this._applyImpulsesToDynamicBodies = false; + this._characterMass = null; + } + + /** @internal */ + public free() { + if (!!this.raw) { + this.raw.free(); + this.rawCharacterCollision.free(); + } + + this.raw = undefined; + this.rawCharacterCollision = undefined; + } + + /** + * The direction that goes "up". Used to determine where the floor is, and the floor’s angle. + */ + public up(): Vector { + return this.raw.up(); + } + + /** + * Sets the direction that goes "up". Used to determine where the floor is, and the floor’s angle. + */ + public setUp(vector: Vector) { + let rawVect = VectorOps.intoRaw(vector); + return this.raw.setUp(rawVect); + rawVect.free(); + } + + public applyImpulsesToDynamicBodies(): boolean { + return this._applyImpulsesToDynamicBodies; + } + + public setApplyImpulsesToDynamicBodies(enabled: boolean) { + this._applyImpulsesToDynamicBodies = enabled; + } + + /** + * Returns the custom value of the character mass, if it was set by `this.setCharacterMass`. + */ + public characterMass(): number | null { + return this._characterMass; + } + + /** + * Set the mass of the character to be used for impulse resolution if `self.applyImpulsesToDynamicBodies` + * is set to `true`. + * + * If no character mass is set explicitly (or if it is set to `null`) it is automatically assumed to be equal + * to the mass of the rigid-body the character collider is attached to; or equal to 0 if the character collider + * isn’t attached to any rigid-body. + * + * @param mass - The mass to set. + */ + public setCharacterMass(mass: number | null) { + this._characterMass = mass; + } + + /** + * A small gap to preserve between the character and its surroundings. + * + * This value should not be too large to avoid visual artifacts, but shouldn’t be too small + * (must not be zero) to improve numerical stability of the character controller. + */ + public offset(): number { + return this.raw.offset(); + } + + /** + * Sets a small gap to preserve between the character and its surroundings. + * + * This value should not be too large to avoid visual artifacts, but shouldn’t be too small + * (must not be zero) to improve numerical stability of the character controller. + */ + public setOffset(value: number) { + this.raw.setOffset(value); + } + + /// Increase this number if your character appears to get stuck when sliding against surfaces. + /// + /// This is a small distance applied to the movement toward the contact normals of shapes hit + /// by the character controller. This helps shape-casting not getting stuck in an always-penetrating + /// state during the sliding calculation. + /// + /// This value should remain fairly small since it can introduce artificial "bumps" when sliding + /// along a flat surface. + public normalNudgeFactor(): number { + return this.raw.normalNudgeFactor(); + } + + /// Increase this number if your character appears to get stuck when sliding against surfaces. + /// + /// This is a small distance applied to the movement toward the contact normals of shapes hit + /// by the character controller. This helps shape-casting not getting stuck in an always-penetrating + /// state during the sliding calculation. + /// + /// This value should remain fairly small since it can introduce artificial "bumps" when sliding + /// along a flat surface. + public setNormalNudgeFactor(value: number) { + this.raw.setNormalNudgeFactor(value); + } + + /** + * Is sliding against obstacles enabled? + */ + public slideEnabled(): boolean { + return this.raw.slideEnabled(); + } + + /** + * Enable or disable sliding against obstacles. + */ + public setSlideEnabled(enabled: boolean) { + this.raw.setSlideEnabled(enabled); + } + + /** + * The maximum step height a character can automatically step over. + */ + public autostepMaxHeight(): number | null { + return this.raw.autostepMaxHeight(); + } + + /** + * The minimum width of free space that must be available after stepping on a stair. + */ + public autostepMinWidth(): number | null { + return this.raw.autostepMinWidth(); + } + + /** + * Can the character automatically step over dynamic bodies too? + */ + public autostepIncludesDynamicBodies(): boolean | null { + return this.raw.autostepIncludesDynamicBodies(); + } + + /** + * Is automatically stepping over small objects enabled? + */ + public autostepEnabled(): boolean { + return this.raw.autostepEnabled(); + } + + /** + * Enabled automatically stepping over small objects. + * + * @param maxHeight - The maximum step height a character can automatically step over. + * @param minWidth - The minimum width of free space that must be available after stepping on a stair. + * @param includeDynamicBodies - Can the character automatically step over dynamic bodies too? + */ + public enableAutostep( + maxHeight: number, + minWidth: number, + includeDynamicBodies: boolean, + ) { + this.raw.enableAutostep(maxHeight, minWidth, includeDynamicBodies); + } + + /** + * Disable automatically stepping over small objects. + */ + public disableAutostep() { + return this.raw.disableAutostep(); + } + + /** + * The maximum angle (radians) between the floor’s normal and the `up` vector that the + * character is able to climb. + */ + public maxSlopeClimbAngle(): number { + return this.raw.maxSlopeClimbAngle(); + } + + /** + * Sets the maximum angle (radians) between the floor’s normal and the `up` vector that the + * character is able to climb. + */ + public setMaxSlopeClimbAngle(angle: number) { + this.raw.setMaxSlopeClimbAngle(angle); + } + + /** + * The minimum angle (radians) between the floor’s normal and the `up` vector before the + * character starts to slide down automatically. + */ + public minSlopeSlideAngle(): number { + return this.raw.minSlopeSlideAngle(); + } + + /** + * Sets the minimum angle (radians) between the floor’s normal and the `up` vector before the + * character starts to slide down automatically. + */ + public setMinSlopeSlideAngle(angle: number) { + this.raw.setMinSlopeSlideAngle(angle); + } + + /** + * If snap-to-ground is enabled, should the character be automatically snapped to the ground if + * the distance between the ground and its feet are smaller than the specified threshold? + */ + public snapToGroundDistance(): number | null { + return this.raw.snapToGroundDistance(); + } + + /** + * Enables automatically snapping the character to the ground if the distance between + * the ground and its feet are smaller than the specified threshold. + */ + public enableSnapToGround(distance: number) { + this.raw.enableSnapToGround(distance); + } + + /** + * Disables automatically snapping the character to the ground. + */ + public disableSnapToGround() { + this.raw.disableSnapToGround(); + } + + /** + * Is automatically snapping the character to the ground enabled? + */ + public snapToGroundEnabled(): boolean { + return this.raw.snapToGroundEnabled(); + } + + /** + * Computes the movement the given collider is able to execute after hitting and sliding on obstacles. + * + * @param collider - The collider to move. + * @param desiredTranslationDelta - The desired collider movement. + * @param filterFlags - Flags for excluding whole subsets of colliders from the obstacles taken into account. + * @param filterGroups - Groups for excluding colliders with incompatible collision groups from the obstacles + * taken into account. + * @param filterPredicate - Any collider for which this closure returns `false` will be excluded from the + * obstacles taken into account. + */ + public computeColliderMovement( + collider: Collider, + desiredTranslationDelta: Vector, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterPredicate?: (collider: Collider) => boolean, + ) { + let rawTranslationDelta = VectorOps.intoRaw(desiredTranslationDelta); + this.raw.computeColliderMovement( + this.params.dt, + this.broadPhase.raw, + this.narrowPhase.raw, + this.bodies.raw, + this.colliders.raw, + collider.handle, + rawTranslationDelta, + this._applyImpulsesToDynamicBodies, + this._characterMass, + filterFlags, + filterGroups, + this.colliders.castClosure(filterPredicate), + ); + rawTranslationDelta.free(); + } + + /** + * The movement computed by the last call to `this.computeColliderMovement`. + */ + public computedMovement(target?: Vector): Vector { + this.raw.computedMovement(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The result of ground detection computed by the last call to `this.computeColliderMovement`. + */ + public computedGrounded(): boolean { + return this.raw.computedGrounded(); + } + + /** + * The number of collisions against obstacles detected along the path of the last call + * to `this.computeColliderMovement`. + */ + public numComputedCollisions(): number { + return this.raw.numComputedCollisions(); + } + + /** + * Returns the collision against one of the obstacles detected along the path of the last + * call to `this.computeColliderMovement`. + * + * @param i - The i-th collision will be returned. + * @param out - If this argument is set, it will be filled with the collision information. + */ + public computedCollision( + i: number, + out?: CharacterCollision, + ): CharacterCollision | null { + if (!this.raw.computedCollision(i, this.rawCharacterCollision)) { + return null; + } else { + let c = this.rawCharacterCollision; + out = out ?? new CharacterCollision(); + c.translationDeltaApplied(scratchBuffer); + out.translationDeltaApplied = VectorOps.fromBuffer( + scratchBuffer, + out.translationDeltaApplied, + ); + c.translationDeltaRemaining(scratchBuffer); + out.translationDeltaRemaining = VectorOps.fromBuffer( + scratchBuffer, + out.translationDeltaRemaining, + ); + out.toi = c.toi(); + c.worldWitness1(scratchBuffer); + out.witness1 = VectorOps.fromBuffer(scratchBuffer, out.witness1); + c.worldWitness2(scratchBuffer); + out.witness2 = VectorOps.fromBuffer(scratchBuffer, out.witness2); + c.worldNormal1(scratchBuffer); + out.normal1 = VectorOps.fromBuffer(scratchBuffer, out.normal1); + c.worldNormal2(scratchBuffer); + out.normal2 = VectorOps.fromBuffer(scratchBuffer, out.normal2); + out.collider = this.colliders.get(c.handle()); + return out; + } + } +} diff --git a/typescript/src.ts/control/index.ts b/typescript/src.ts/control/index.ts new file mode 100644 index 000000000..43e495a56 --- /dev/null +++ b/typescript/src.ts/control/index.ts @@ -0,0 +1,6 @@ +export * from "./character_controller"; +export * from "./pid_controller"; + +// #if DIM3 +export * from "./ray_cast_vehicle_controller"; +// #endif diff --git a/typescript/src.ts/control/pid_controller.ts b/typescript/src.ts/control/pid_controller.ts new file mode 100644 index 000000000..a8f9bdac1 --- /dev/null +++ b/typescript/src.ts/control/pid_controller.ts @@ -0,0 +1,211 @@ +import {RawPidController} from "../raw"; +import {Rotation, RotationOps, scratchBuffer, Vector, VectorOps} from "../math"; +import {Collider, ColliderSet, InteractionGroups, Shape} from "../geometry"; +import {QueryFilterFlags, World} from "../pipeline"; +import {IntegrationParameters, RigidBody, RigidBodySet} from "../dynamics"; + +// TODO: unify with the JointAxesMask +/** + * An enum representing the possible joint axes controlled by a PidController. + * They can be ORed together, like: + * PidAxesMask.LinX || PidAxesMask.LinY + * to get a pid controller that only constraints the translational X and Y axes. + * + * Possible axes are: + * + * - `X`: X translation axis + * - `Y`: Y translation axis + * - `Z`: Z translation axis + * - `AngX`: X angular rotation axis (3D only) + * - `AngY`: Y angular rotation axis (3D only) + * - `AngZ`: Z angular rotation axis + */ +export enum PidAxesMask { + None = 0, + LinX = 1 << 0, + LinY = 1 << 1, + LinZ = 1 << 2, + // #if DIM3 + AngX = 1 << 3, + AngY = 1 << 4, + // #endif + AngZ = 1 << 5, + // #if DIM2 + AllLin = PidAxesMask.LinX | PidAxesMask.LinY, + AllAng = PidAxesMask.AngZ, + // #endif + // #if DIM3 + AllLin = PidAxesMask.LinX | PidAxesMask.LinY | PidAxesMask.LinZ, + AllAng = PidAxesMask.AngX | PidAxesMask.AngY | PidAxesMask.AngZ, + // #endif + All = PidAxesMask.AllLin | PidAxesMask.AllAng, +} + +/** + * A controller for controlling dynamic bodies using the + * Proportional-Integral-Derivative correction model. + */ +export class PidController { + private raw: RawPidController; + + private params: IntegrationParameters; + private bodies: RigidBodySet; + + constructor( + params: IntegrationParameters, + bodies: RigidBodySet, + kp: number, + ki: number, + kd: number, + axes: PidAxesMask, + ) { + this.params = params; + this.bodies = bodies; + this.raw = new RawPidController(kp, ki, kd, axes); + } + + /** @internal */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + + this.raw = undefined; + } + + public setKp(kp: number, axes: PidAxesMask) { + this.raw.set_kp(kp, axes); + } + + public setKi(ki: number, axes: PidAxesMask) { + this.raw.set_kp(ki, axes); + } + + public setKd(kd: number, axes: PidAxesMask) { + this.raw.set_kp(kd, axes); + } + + public setAxes(axes: PidAxesMask) { + this.raw.set_axes_mask(axes); + } + + public resetIntegrals() { + this.raw.reset_integrals(); + } + + public applyLinearCorrection( + body: RigidBody, + targetPosition: Vector, + targetLinvel: Vector, + ) { + let rawPos = VectorOps.intoRaw(targetPosition); + let rawVel = VectorOps.intoRaw(targetLinvel); + this.raw.apply_linear_correction( + this.params.dt, + this.bodies.raw, + body.handle, + rawPos, + rawVel, + ); + rawPos.free(); + rawVel.free(); + } + + // #if DIM2 + public applyAngularCorrection( + body: RigidBody, + targetRotation: number, + targetAngVel: number, + ) { + this.raw.apply_angular_correction( + this.params.dt, + this.bodies.raw, + body.handle, + targetRotation, + targetAngVel, + ); + } + // #endif + + // #if DIM3 + public applyAngularCorrection( + body: RigidBody, + targetRotation: Rotation, + targetAngVel: Vector, + ) { + let rawPos = RotationOps.intoRaw(targetRotation); + let rawVel = VectorOps.intoRaw(targetAngVel); + this.raw.apply_angular_correction( + this.params.dt, + this.bodies.raw, + body.handle, + rawPos, + rawVel, + ); + rawPos.free(); + rawVel.free(); + } + // #endif + + public linearCorrection( + body: RigidBody, + targetPosition: Vector, + targetLinvel: Vector, + target?: Vector, + ): Vector { + let rawPos = VectorOps.intoRaw(targetPosition); + let rawVel = VectorOps.intoRaw(targetLinvel); + this.raw.linear_correction( + this.params.dt, + this.bodies.raw, + body.handle, + rawPos, + rawVel, + scratchBuffer, + ); + rawPos.free(); + rawVel.free(); + + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM2 + public angularCorrection( + body: RigidBody, + targetRotation: number, + targetAngVel: number, + ): number { + return this.raw.angular_correction( + this.params.dt, + this.bodies.raw, + body.handle, + targetRotation, + targetAngVel, + ); + } + // #endif + + // #if DIM3 + public angularCorrection( + body: RigidBody, + targetRotation: Rotation, + targetAngVel: Vector, + target?: Vector, + ): Vector { + let rawPos = RotationOps.intoRaw(targetRotation); + let rawVel = VectorOps.intoRaw(targetAngVel); + this.raw.angular_correction( + this.params.dt, + this.bodies.raw, + body.handle, + rawPos, + rawVel, + scratchBuffer, + ); + rawPos.free(); + rawVel.free(); + + return VectorOps.fromBuffer(scratchBuffer, target); + } + // #endif +} diff --git a/typescript/src.ts/control/ray_cast_vehicle_controller.ts b/typescript/src.ts/control/ray_cast_vehicle_controller.ts new file mode 100644 index 000000000..55e4b52ff --- /dev/null +++ b/typescript/src.ts/control/ray_cast_vehicle_controller.ts @@ -0,0 +1,518 @@ +import {RawDynamicRayCastVehicleController} from "../raw"; +import {scratchBuffer, Vector, VectorOps} from "../math"; +import { + BroadPhase, + Collider, + ColliderSet, + InteractionGroups, + NarrowPhase, +} from "../geometry"; +import {QueryFilterFlags} from "../pipeline"; +import {RigidBody, RigidBodyHandle, RigidBodySet} from "../dynamics"; + +/** + * A character controller to simulate vehicles using ray-casting for the wheels. + */ +export class DynamicRayCastVehicleController { + private raw: RawDynamicRayCastVehicleController; + private broadPhase: BroadPhase; + private narrowPhase: NarrowPhase; + private bodies: RigidBodySet; + private colliders: ColliderSet; + private _chassis: RigidBody; + + constructor( + chassis: RigidBody, + broadPhase: BroadPhase, + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + ) { + this.raw = new RawDynamicRayCastVehicleController(chassis.handle); + this.broadPhase = broadPhase; + this.narrowPhase = narrowPhase; + this.bodies = bodies; + this.colliders = colliders; + this._chassis = chassis; + } + + /** @internal */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + + this.raw = undefined; + } + + /** + * Updates the vehicle’s velocity based on its suspension, engine force, and brake. + * + * This directly updates the velocity of its chassis rigid-body. + * + * @param dt - Time increment used to integrate forces. + * @param filterFlags - Flag to exclude categories of objects from the wheels’ ray-cast. + * @param filterGroups - Only colliders compatible with these groups will be hit by the wheels’ ray-casts. + * @param filterPredicate - Callback to filter out which collider will be hit by the wheels’ ray-casts. + */ + public updateVehicle( + dt: number, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterPredicate?: (collider: Collider) => boolean, + ) { + this.raw.update_vehicle( + dt, + this.broadPhase.raw, + this.narrowPhase.raw, + this.bodies.raw, + this.colliders.raw, + filterFlags, + filterGroups, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * The current forward speed of the vehicle. + */ + public currentVehicleSpeed(): number { + return this.raw.current_vehicle_speed(); + } + + /** + * The rigid-body used as the chassis. + */ + public chassis(): RigidBody { + return this._chassis; + } + + /** + * The chassis’ local _up_ direction (`0 = x, 1 = y, 2 = z`). + */ + get indexUpAxis(): number { + return this.raw.index_up_axis(); + } + + /** + * Sets the chassis’ local _up_ direction (`0 = x, 1 = y, 2 = z`). + */ + set indexUpAxis(axis: number) { + this.raw.set_index_up_axis(axis); + } + + /** + * The chassis’ local _forward_ direction (`0 = x, 1 = y, 2 = z`). + */ + get indexForwardAxis(): number { + return this.raw.index_forward_axis(); + } + + /** + * Sets the chassis’ local _forward_ direction (`0 = x, 1 = y, 2 = z`). + */ + set setIndexForwardAxis(axis: number) { + this.raw.set_index_forward_axis(axis); + } + + /** + * Adds a new wheel attached to this vehicle. + * @param chassisConnectionCs - The position of the wheel relative to the chassis. + * @param directionCs - The direction of the wheel’s suspension, relative to the chassis. The ray-casting will + * happen following this direction to detect the ground. + * @param axleCs - The wheel’s axle axis, relative to the chassis. + * @param suspensionRestLength - The rest length of the wheel’s suspension spring. + * @param radius - The wheel’s radius. + */ + public addWheel( + chassisConnectionCs: Vector, + directionCs: Vector, + axleCs: Vector, + suspensionRestLength: number, + radius: number, + ) { + let rawChassisConnectionCs = VectorOps.intoRaw(chassisConnectionCs); + let rawDirectionCs = VectorOps.intoRaw(directionCs); + let rawAxleCs = VectorOps.intoRaw(axleCs); + + this.raw.add_wheel( + rawChassisConnectionCs, + rawDirectionCs, + rawAxleCs, + suspensionRestLength, + radius, + ); + + rawChassisConnectionCs.free(); + rawDirectionCs.free(); + rawAxleCs.free(); + } + + /** + * The number of wheels attached to this vehicle. + */ + public numWheels(): number { + return this.raw.num_wheels(); + } + + /* + * + * Access to wheel properties. + * + */ + /* + * Getters + setters + */ + + /** + * The position of the i-th wheel, relative to the chassis. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelChassisConnectionPointCs( + i: number, + target?: Vector, + ): Vector | null { + const exists = this.raw.wheel_chassis_connection_point_cs( + i, + scratchBuffer, + ); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * Sets the position of the i-th wheel, relative to the chassis. + */ + public setWheelChassisConnectionPointCs(i: number, value: Vector) { + let rawValue = VectorOps.intoRaw(value); + this.raw.set_wheel_chassis_connection_point_cs(i, rawValue); + rawValue.free(); + } + + /** + * The rest length of the i-th wheel’s suspension spring. + */ + public wheelSuspensionRestLength(i: number): number | null { + return this.raw.wheel_suspension_rest_length(i); + } + + /** + * Sets the rest length of the i-th wheel’s suspension spring. + */ + public setWheelSuspensionRestLength(i: number, value: number) { + this.raw.set_wheel_suspension_rest_length(i, value); + } + + /** + * The maximum distance the i-th wheel suspension can travel before and after its resting length. + */ + public wheelMaxSuspensionTravel(i: number): number | null { + return this.raw.wheel_max_suspension_travel(i); + } + + /** + * Sets the maximum distance the i-th wheel suspension can travel before and after its resting length. + */ + public setWheelMaxSuspensionTravel(i: number, value: number) { + this.raw.set_wheel_max_suspension_travel(i, value); + } + + /** + * The i-th wheel’s radius. + */ + public wheelRadius(i: number): number | null { + return this.raw.wheel_radius(i); + } + + /** + * Sets the i-th wheel’s radius. + */ + public setWheelRadius(i: number, value: number) { + this.raw.set_wheel_radius(i, value); + } + + /** + * The i-th wheel’s suspension stiffness. + * + * Increase this value if the suspension appears to not push the vehicle strong enough. + */ + public wheelSuspensionStiffness(i: number): number | null { + return this.raw.wheel_suspension_stiffness(i); + } + + /** + * Sets the i-th wheel’s suspension stiffness. + * + * Increase this value if the suspension appears to not push the vehicle strong enough. + */ + public setWheelSuspensionStiffness(i: number, value: number) { + this.raw.set_wheel_suspension_stiffness(i, value); + } + + /** + * The i-th wheel’s suspension’s damping when it is being compressed. + */ + public wheelSuspensionCompression(i: number): number | null { + return this.raw.wheel_suspension_compression(i); + } + + /** + * The i-th wheel’s suspension’s damping when it is being compressed. + */ + public setWheelSuspensionCompression(i: number, value: number) { + this.raw.set_wheel_suspension_compression(i, value); + } + + /** + * The i-th wheel’s suspension’s damping when it is being released. + * + * Increase this value if the suspension appears to overshoot. + */ + public wheelSuspensionRelaxation(i: number): number | null { + return this.raw.wheel_suspension_relaxation(i); + } + + /** + * Sets the i-th wheel’s suspension’s damping when it is being released. + * + * Increase this value if the suspension appears to overshoot. + */ + public setWheelSuspensionRelaxation(i: number, value: number) { + this.raw.set_wheel_suspension_relaxation(i, value); + } + + /** + * The maximum force applied by the i-th wheel’s suspension. + */ + public wheelMaxSuspensionForce(i: number): number | null { + return this.raw.wheel_max_suspension_force(i); + } + + /** + * Sets the maximum force applied by the i-th wheel’s suspension. + */ + public setWheelMaxSuspensionForce(i: number, value: number) { + this.raw.set_wheel_max_suspension_force(i, value); + } + + /** + * The maximum amount of braking impulse applied on the i-th wheel to slow down the vehicle. + */ + public wheelBrake(i: number): number | null { + return this.raw.wheel_brake(i); + } + + /** + * Set the maximum amount of braking impulse applied on the i-th wheel to slow down the vehicle. + */ + public setWheelBrake(i: number, value: number) { + this.raw.set_wheel_brake(i, value); + } + + /** + * The steering angle (radians) for the i-th wheel. + */ + public wheelSteering(i: number): number | null { + return this.raw.wheel_steering(i); + } + + /** + * Sets the steering angle (radians) for the i-th wheel. + */ + public setWheelSteering(i: number, value: number) { + this.raw.set_wheel_steering(i, value); + } + + /** + * The forward force applied by the i-th wheel on the chassis. + */ + public wheelEngineForce(i: number): number | null { + return this.raw.wheel_engine_force(i); + } + + /** + * Sets the forward force applied by the i-th wheel on the chassis. + */ + public setWheelEngineForce(i: number, value: number) { + this.raw.set_wheel_engine_force(i, value); + } + + /** + * The direction of the i-th wheel’s suspension, relative to the chassis. + * + * The ray-casting will happen following this direction to detect the ground. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelDirectionCs(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_direction_cs(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * Sets the direction of the i-th wheel’s suspension, relative to the chassis. + * + * The ray-casting will happen following this direction to detect the ground. + */ + public setWheelDirectionCs(i: number, value: Vector) { + let rawValue = VectorOps.intoRaw(value); + this.raw.set_wheel_direction_cs(i, rawValue); + rawValue.free(); + } + + /** + * The i-th wheel’s axle axis, relative to the chassis. + * + * The axis index defined as 0 = X, 1 = Y, 2 = Z. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelAxleCs(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_axle_cs(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * Sets the i-th wheel’s axle axis, relative to the chassis. + * + * The axis index defined as 0 = X, 1 = Y, 2 = Z. + */ + public setWheelAxleCs(i: number, value: Vector) { + let rawValue = VectorOps.intoRaw(value); + this.raw.set_wheel_axle_cs(i, rawValue); + rawValue.free(); + } + + /** + * Parameter controlling how much traction the tire has. + * + * The larger the value, the more instantaneous braking will happen (with the risk of + * causing the vehicle to flip if it’s too strong). + */ + public wheelFrictionSlip(i: number): number | null { + return this.raw.wheel_friction_slip(i); + } + + /** + * Sets the parameter controlling how much traction the tire has. + * + * The larger the value, the more instantaneous braking will happen (with the risk of + * causing the vehicle to flip if it’s too strong). + */ + public setWheelFrictionSlip(i: number, value: number) { + this.raw.set_wheel_friction_slip(i, value); + } + + /** + * The multiplier of friction between a tire and the collider it’s on top of. + * + * The larger the value, the stronger side friction will be. + */ + public wheelSideFrictionStiffness(i: number): number | null { + return this.raw.wheel_side_friction_stiffness(i); + } + + /** + * The multiplier of friction between a tire and the collider it’s on top of. + * + * The larger the value, the stronger side friction will be. + */ + public setWheelSideFrictionStiffness(i: number, value: number) { + this.raw.set_wheel_side_friction_stiffness(i, value); + } + + /* + * Getters only. + */ + + /** + * The i-th wheel’s current rotation angle (radians) on its axle. + */ + public wheelRotation(i: number): number | null { + return this.raw.wheel_rotation(i); + } + + /** + * The forward impulses applied by the i-th wheel on the chassis. + */ + public wheelForwardImpulse(i: number): number | null { + return this.raw.wheel_forward_impulse(i); + } + + /** + * The side impulses applied by the i-th wheel on the chassis. + */ + public wheelSideImpulse(i: number): number | null { + return this.raw.wheel_side_impulse(i); + } + + /** + * The force applied by the i-th wheel suspension. + */ + public wheelSuspensionForce(i: number): number | null { + return this.raw.wheel_suspension_force(i); + } + + /** + * The (world-space) contact normal between the i-th wheel and the floor. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelContactNormal(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_contact_normal_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * The (world-space) point hit by the wheel’s ray-cast for the i-th wheel. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelContactPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_contact_point_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * The suspension length for the i-th wheel. + */ + public wheelSuspensionLength(i: number): number | null { + return this.raw.wheel_suspension_length(i); + } + + /** + * The (world-space) starting point of the ray-cast for the i-th wheel. + * + * @param {number} i + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public wheelHardPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.wheel_hard_point_ws(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * Is the i-th wheel in contact with the ground? + */ + public wheelIsInContact(i: number): boolean { + return this.raw.wheel_is_in_contact(i); + } + + /** + * The collider hit by the ray-cast for the i-th wheel. + */ + public wheelGroundObject(i: number): Collider | null { + return this.colliders.get(this.raw.wheel_ground_object(i)); + } +} diff --git a/typescript/src.ts/dynamics/ccd_solver.ts b/typescript/src.ts/dynamics/ccd_solver.ts new file mode 100644 index 000000000..7f7942224 --- /dev/null +++ b/typescript/src.ts/dynamics/ccd_solver.ts @@ -0,0 +1,25 @@ +import {RawCCDSolver} from "../raw"; + +/** + * The CCD solver responsible for resolving Continuous Collision Detection. + * + * To avoid leaking WASM resources, this MUST be freed manually with `ccdSolver.free()` + * once you are done using it. + */ +export class CCDSolver { + raw: RawCCDSolver; + + /** + * Release the WASM memory occupied by this narrow-phase. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawCCDSolver) { + this.raw = raw || new RawCCDSolver(); + } +} diff --git a/typescript/src.ts/dynamics/coefficient_combine_rule.ts b/typescript/src.ts/dynamics/coefficient_combine_rule.ts new file mode 100644 index 000000000..680b402a9 --- /dev/null +++ b/typescript/src.ts/dynamics/coefficient_combine_rule.ts @@ -0,0 +1,13 @@ +/** + * A rule applied to combine coefficients. + * + * Use this when configuring the `ColliderDesc` to specify + * how friction and restitution coefficient should be combined + * in a contact. + */ +export enum CoefficientCombineRule { + Average = 0, + Min = 1, + Multiply = 2, + Max = 3, +} diff --git a/typescript/src.ts/dynamics/impulse_joint.ts b/typescript/src.ts/dynamics/impulse_joint.ts new file mode 100644 index 000000000..68185efeb --- /dev/null +++ b/typescript/src.ts/dynamics/impulse_joint.ts @@ -0,0 +1,794 @@ +import {Rotation, Vector, VectorOps, RotationOps, scratchBuffer} from "../math"; +import { + RawGenericJoint, + RawImpulseJointSet, + RawRigidBodySet, + RawJointAxis, + RawJointType, + RawMotorModel, +} from "../raw"; +import {RigidBody, RigidBodyHandle} from "./rigid_body"; +import {RigidBodySet} from "./rigid_body_set"; +// #if DIM3 +import {Quaternion} from "../math"; +// #endif + +/** + * The integer identifier of a collider added to a `ColliderSet`. + */ +export type ImpulseJointHandle = number; + +/** + * An enum grouping all possible types of joints: + * + * - `Revolute`: A revolute joint that removes all degrees of freedom between the affected + * bodies except for the rotation along one axis. + * - `Fixed`: A fixed joint that removes all relative degrees of freedom between the affected bodies. + * - `Prismatic`: A prismatic joint that removes all degrees of freedom between the affected + * bodies except for the translation along one axis. + * - `Spherical`: (3D only) A spherical joint that removes all relative linear degrees of freedom between the affected bodies. + * - `Generic`: (3D only) A joint with customizable degrees of freedom, allowing any of the 6 axes to be locked. + */ +export enum JointType { + Revolute, + Fixed, + Prismatic, + Rope, + Spring, + // #if DIM3 + Spherical, + Generic, + // #endif +} + +export enum MotorModel { + AccelerationBased, + ForceBased, +} + +/** + * An enum representing the possible joint axes of a generic joint. + * They can be ORed together, like: + * JointAxesMask.LinX || JointAxesMask.LinY + * to get a joint that is only free in the X and Y translational (positional) axes. + * + * Possible free axes are: + * + * - `X`: X translation axis + * - `Y`: Y translation axis + * - `Z`: Z translation axis + * - `AngX`: X angular rotation axis + * - `AngY`: Y angular rotations axis + * - `AngZ`: Z angular rotation axis + */ +export enum JointAxesMask { + LinX = 1 << 0, + LinY = 1 << 1, + LinZ = 1 << 2, + AngX = 1 << 3, + AngY = 1 << 4, + AngZ = 1 << 5, +} + +export class ImpulseJoint { + protected rawSet: RawImpulseJointSet; // The ImpulseJoint won't need to free this. + protected bodySet: RigidBodySet; // The ImpulseJoint won’t need to free this. + handle: ImpulseJointHandle; + + constructor( + rawSet: RawImpulseJointSet, + bodySet: RigidBodySet, + handle: ImpulseJointHandle, + ) { + this.rawSet = rawSet; + this.bodySet = bodySet; + this.handle = handle; + } + + public static newTyped( + rawSet: RawImpulseJointSet, + bodySet: RigidBodySet, + handle: ImpulseJointHandle, + ): ImpulseJoint { + switch (rawSet.jointType(handle)) { + case RawJointType.Revolute: + return new RevoluteImpulseJoint(rawSet, bodySet, handle); + case RawJointType.Prismatic: + return new PrismaticImpulseJoint(rawSet, bodySet, handle); + case RawJointType.Fixed: + return new FixedImpulseJoint(rawSet, bodySet, handle); + case RawJointType.Spring: + return new SpringImpulseJoint(rawSet, bodySet, handle); + case RawJointType.Rope: + return new RopeImpulseJoint(rawSet, bodySet, handle); + // #if DIM3 + case RawJointType.Spherical: + return new SphericalImpulseJoint(rawSet, bodySet, handle); + case RawJointType.Generic: + return new GenericImpulseJoint(rawSet, bodySet, handle); + // #endif + default: + return new ImpulseJoint(rawSet, bodySet, handle); + } + } + + /** @internal */ + public finalizeDeserialization(bodySet: RigidBodySet) { + this.bodySet = bodySet; + } + + /** + * Checks if this joint is still valid (i.e. that it has + * not been deleted from the joint set yet). + */ + public isValid(): boolean { + return this.rawSet.contains(this.handle); + } + + /** + * The first rigid-body this joint it attached to. + */ + public body1(): RigidBody { + return this.bodySet.get(this.rawSet.jointBodyHandle1(this.handle)); + } + + /** + * The second rigid-body this joint is attached to. + */ + public body2(): RigidBody { + return this.bodySet.get(this.rawSet.jointBodyHandle2(this.handle)); + } + + /** + * The type of this joint given as a string. + */ + public type(): JointType { + return this.rawSet.jointType(this.handle) as number as JointType; + } + + // #if DIM3 + /** + * The rotation quaternion that aligns this joint's first local axis to the `x` axis. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public frameX1(target?: Rotation): Rotation { + this.rawSet.jointFrameX1(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + + // #endif + + // #if DIM3 + /** + * The rotation matrix that aligns this joint's second local axis to the `x` axis. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public frameX2(target?: Rotation): Rotation { + this.rawSet.jointFrameX2(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + + // #endif + + /** + * The position of the first anchor of this joint. + * + * The first anchor gives the position of the application point on the + * local frame of the first rigid-body it is attached to. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public anchor1(target?: Vector): Vector { + this.rawSet.jointAnchor1(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The position of the second anchor of this joint. + * + * The second anchor gives the position of the application point on the + * local frame of the second rigid-body it is attached to. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public anchor2(target?: Vector): Vector { + this.rawSet.jointAnchor2(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * Sets the position of the first anchor of this joint. + * + * The first anchor gives the position of the application point on the + * local frame of the first rigid-body it is attached to. + */ + public setAnchor1(newPos: Vector) { + const rawPoint = VectorOps.intoRaw(newPos); + this.rawSet.jointSetAnchor1(this.handle, rawPoint); + rawPoint.free(); + } + + /** + * Sets the position of the second anchor of this joint. + * + * The second anchor gives the position of the application point on the + * local frame of the second rigid-body it is attached to. + */ + public setAnchor2(newPos: Vector) { + const rawPoint = VectorOps.intoRaw(newPos); + this.rawSet.jointSetAnchor2(this.handle, rawPoint); + rawPoint.free(); + } + + // #if DIM3 + /** + * Sets the rotation quaternion that aligns this joint's first local axis to the `x` axis. + */ + public setFrameX1(rot: Rotation) { + const rawRot = RotationOps.intoRaw(rot); + this.rawSet.jointSetFrameX1(this.handle, rawRot); + rawRot.free(); + } + + /** + * Sets the rotation quaternion that aligns this joint's second local axis to the `x` axis. + */ + public setFrameX2(rot: Rotation) { + const rawRot = RotationOps.intoRaw(rot); + this.rawSet.jointSetFrameX2(this.handle, rawRot); + rawRot.free(); + } + + /** + * Sets the full local frame (anchor position and rotation) for the first rigid-body attachment. + */ + public setLocalFrame1(anchor: Vector, rot: Rotation) { + const rawAnchor = VectorOps.intoRaw(anchor); + const rawRot = RotationOps.intoRaw(rot); + this.rawSet.jointSetLocalFrame1(this.handle, rawAnchor, rawRot); + rawAnchor.free(); + rawRot.free(); + } + + /** + * Sets the full local frame (anchor position and rotation) for the second rigid-body attachment. + */ + public setLocalFrame2(anchor: Vector, rot: Rotation) { + const rawAnchor = VectorOps.intoRaw(anchor); + const rawRot = RotationOps.intoRaw(rot); + this.rawSet.jointSetLocalFrame2(this.handle, rawAnchor, rawRot); + rawAnchor.free(); + rawRot.free(); + } + // #endif + + /** + * Controls whether contacts are computed between colliders attached + * to the rigid-bodies linked by this joint. + */ + public setContactsEnabled(enabled: boolean) { + this.rawSet.jointSetContactsEnabled(this.handle, enabled); + } + + /** + * Indicates if contacts are enabled between colliders attached + * to the rigid-bodies linked by this joint. + */ + public contactsEnabled(): boolean { + return this.rawSet.jointContactsEnabled(this.handle); + } +} + +export class UnitImpulseJoint extends ImpulseJoint { + /** + * The axis left free by this joint. + */ + protected rawAxis?(): RawJointAxis; + + /** + * Are the limits enabled for this joint? + */ + public limitsEnabled(): boolean { + return this.rawSet.jointLimitsEnabled(this.handle, this.rawAxis()); + } + + /** + * The min limit of this joint. + */ + public limitsMin(): number { + return this.rawSet.jointLimitsMin(this.handle, this.rawAxis()); + } + + /** + * The max limit of this joint. + */ + public limitsMax(): number { + return this.rawSet.jointLimitsMax(this.handle, this.rawAxis()); + } + + /** + * Sets the limits of this joint. + * + * @param min - The minimum bound of this joint’s free coordinate. + * @param max - The maximum bound of this joint’s free coordinate. + */ + public setLimits(min: number, max: number) { + this.rawSet.jointSetLimits(this.handle, this.rawAxis(), min, max); + } + + public configureMotorModel(model: MotorModel) { + this.rawSet.jointConfigureMotorModel( + this.handle, + this.rawAxis(), + model as number as RawMotorModel, + ); + } + + public setMotorMaxForce(maxForce: number) { + this.rawSet.jointSetMotorMaxForce( + this.handle, + this.rawAxis(), + maxForce, + ); + } + + public configureMotorVelocity(targetVel: number, factor: number) { + this.rawSet.jointConfigureMotorVelocity( + this.handle, + this.rawAxis(), + targetVel, + factor, + ); + } + + public configureMotorPosition( + targetPos: number, + stiffness: number, + damping: number, + ) { + this.rawSet.jointConfigureMotorPosition( + this.handle, + this.rawAxis(), + targetPos, + stiffness, + damping, + ); + } + + public configureMotor( + targetPos: number, + targetVel: number, + stiffness: number, + damping: number, + ) { + this.rawSet.jointConfigureMotor( + this.handle, + this.rawAxis(), + targetPos, + targetVel, + stiffness, + damping, + ); + } +} + +export class FixedImpulseJoint extends ImpulseJoint {} + +export class RopeImpulseJoint extends ImpulseJoint {} + +export class SpringImpulseJoint extends ImpulseJoint {} + +export class PrismaticImpulseJoint extends UnitImpulseJoint { + public rawAxis(): RawJointAxis { + return RawJointAxis.LinX; + } +} + +export class RevoluteImpulseJoint extends UnitImpulseJoint { + public rawAxis(): RawJointAxis { + return RawJointAxis.AngX; + } +} + +// #if DIM3 +export class GenericImpulseJoint extends ImpulseJoint {} + +export class SphericalImpulseJoint extends ImpulseJoint { + /* Unsupported by this alpha release. + public configureMotorModel(model: MotorModel) { + this.rawSet.jointConfigureMotorModel(this.handle, model); + } + + public configureMotorVelocity(targetVel: Vector, factor: number) { + this.rawSet.jointConfigureBallMotorVelocity(this.handle, targetVel.x, targetVel.y, targetVel.z, factor); + } + + public configureMotorPosition(targetPos: Quaternion, stiffness: number, damping: number) { + this.rawSet.jointConfigureBallMotorPosition(this.handle, targetPos.w, targetPos.x, targetPos.y, targetPos.z, stiffness, damping); + } + + public configureMotor(targetPos: Quaternion, targetVel: Vector, stiffness: number, damping: number) { + this.rawSet.jointConfigureBallMotor(this.handle, + targetPos.w, targetPos.x, targetPos.y, targetPos.z, + targetVel.x, targetVel.y, targetVel.z, + stiffness, damping); + } + */ +} +// #endif + +export class JointData { + anchor1: Vector; + anchor2: Vector; + axis: Vector; + // #if DIM3 + axis1: Vector; + axis2: Vector; + // #endif + frame1: Rotation; + frame2: Rotation; + jointType: JointType; + limitsEnabled: boolean; + limits: Array; + axesMask: JointAxesMask; + stiffness: number; + damping: number; + length: number; + + private constructor() {} + + /** + * Creates a new joint descriptor that builds a Fixed joint. + * + * A fixed joint removes all the degrees of freedom between the affected bodies, ensuring their + * anchor and local frames coincide in world-space. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param frame1 - The reference orientation of the joint wrt. the first rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param frame2 - The reference orientation of the joint wrt. the second rigid-body. + */ + public static fixed( + anchor1: Vector, + frame1: Rotation, + anchor2: Vector, + frame2: Rotation, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.frame1 = frame1; + res.frame2 = frame2; + res.jointType = JointType.Fixed; + return res; + } + + public static spring( + rest_length: number, + stiffness: number, + damping: number, + anchor1: Vector, + anchor2: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.length = rest_length; + res.stiffness = stiffness; + res.damping = damping; + res.jointType = JointType.Spring; + return res; + } + + public static rope( + length: number, + anchor1: Vector, + anchor2: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.length = length; + res.jointType = JointType.Rope; + return res; + } + + // #if DIM2 + + /** + * Create a new joint descriptor that builds revolute joints. + * + * A revolute joint allows three relative rotational degrees of freedom + * by preventing any relative translation between the anchors of the + * two attached rigid-bodies. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + */ + public static revolute(anchor1: Vector, anchor2: Vector): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.jointType = JointType.Revolute; + return res; + } + + /** + * Creates a new joint descriptor that builds a Prismatic joint. + * + * A prismatic joint removes all the degrees of freedom between the + * affected bodies, except for the translation along one axis. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. + */ + public static prismatic( + anchor1: Vector, + anchor2: Vector, + axis: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis; + res.jointType = JointType.Prismatic; + return res; + } + + // #endif + + // #if DIM3 + /** + * Create a new joint descriptor that builds generic joints. + * + * A generic joint allows customizing its degrees of freedom + * by supplying a mask of the joint axes that should remain locked. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis - The X axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. + * @param axesMask - Mask representing the locked axes of the joint. You can use logical OR to select these from + * the JointAxesMask enum. For example, passing (JointAxesMask.AngX || JointAxesMask.AngY) will + * create a joint locked in the X and Y rotational axes. + */ + public static generic( + anchor1: Vector, + anchor2: Vector, + axis: Vector, + axesMask: JointAxesMask, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis; + res.axesMask = axesMask; + res.jointType = JointType.Generic; + return res; + } + + /** + * Create a new joint descriptor that builds spherical joints. + * + * A spherical joint allows three relative rotational degrees of freedom + * by preventing any relative translation between the anchors of the + * two attached rigid-bodies. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + */ + public static spherical(anchor1: Vector, anchor2: Vector): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.jointType = JointType.Spherical; + return res; + } + + /** + * Creates a new joint descriptor that builds a Prismatic joint. + * + * A prismatic joint removes all the degrees of freedom between the + * affected bodies, except for the translation along one axis. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. + */ + public static prismatic( + anchor1: Vector, + anchor2: Vector, + axis: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis; + res.jointType = JointType.Prismatic; + return res; + } + + /** + * Create a new joint descriptor that builds Revolute joints. + * + * A revolute joint removes all degrees of freedom between the affected + * bodies except for the rotation along one axis. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis - Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. + */ + public static revolute( + anchor1: Vector, + anchor2: Vector, + axis: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis; + res.jointType = JointType.Revolute; + return res; + } + + /** + * Create a new joint descriptor that builds Revolute joints with independent + * local axes for each attached rigid-body. + * + * This is useful when the same world-space hinge axis is represented by + * different local axes on the two bodies. + * + * @param anchor1 - Point where the joint is attached on the first rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param anchor2 - Point where the joint is attached on the second rigid-body affected by this joint. Expressed in the + * local-space of the rigid-body. + * @param axis1 - Axis of the joint, expressed in the local-space of the first rigid-body. + * @param axis2 - Axis of the joint, expressed in the local-space of the second rigid-body. + */ + public static revoluteWithAxes( + anchor1: Vector, + anchor2: Vector, + axis1: Vector, + axis2: Vector, + ): JointData { + let res = new JointData(); + res.anchor1 = anchor1; + res.anchor2 = anchor2; + res.axis = axis1; + res.axis1 = axis1; + res.axis2 = axis2; + res.jointType = JointType.Revolute; + return res; + } + // #endif + + public intoRaw(): RawGenericJoint { + let rawA1 = VectorOps.intoRaw(this.anchor1); + let rawA2 = VectorOps.intoRaw(this.anchor2); + let rawAx; + let result; + let limitsEnabled = false; + let limitsMin = 0.0; + let limitsMax = 0.0; + + switch (this.jointType) { + case JointType.Fixed: + let rawFra1 = RotationOps.intoRaw(this.frame1); + let rawFra2 = RotationOps.intoRaw(this.frame2); + result = RawGenericJoint.fixed(rawA1, rawFra1, rawA2, rawFra2); + rawFra1.free(); + rawFra2.free(); + break; + case JointType.Spring: + result = RawGenericJoint.spring( + this.length, + this.stiffness, + this.damping, + rawA1, + rawA2, + ); + break; + case JointType.Rope: + result = RawGenericJoint.rope(this.length, rawA1, rawA2); + break; + case JointType.Prismatic: + rawAx = VectorOps.intoRaw(this.axis); + + if (!!this.limitsEnabled) { + limitsEnabled = true; + limitsMin = this.limits[0]; + limitsMax = this.limits[1]; + } + + // #if DIM2 + result = RawGenericJoint.prismatic( + rawA1, + rawA2, + rawAx, + limitsEnabled, + limitsMin, + limitsMax, + ); + // #endif + + // #if DIM3 + result = RawGenericJoint.prismatic( + rawA1, + rawA2, + rawAx, + limitsEnabled, + limitsMin, + limitsMax, + ); + // #endif + + rawAx.free(); + break; + // #if DIM2 + case JointType.Revolute: + result = RawGenericJoint.revolute(rawA1, rawA2); + break; + // #endif + // #if DIM3 + case JointType.Generic: + rawAx = VectorOps.intoRaw(this.axis); + // implicit type cast: axesMask is a JointAxesMask bitflag enum, + // we're treating it as a u8 on the Rust side + let rawAxesMask = this.axesMask; + result = RawGenericJoint.generic( + rawA1, + rawA2, + rawAx, + rawAxesMask, + ); + break; + case JointType.Spherical: + result = RawGenericJoint.spherical(rawA1, rawA2); + break; + case JointType.Revolute: + if (!!this.axis1 && !!this.axis2) { + let rawAx1 = VectorOps.intoRaw(this.axis1); + let rawAx2 = VectorOps.intoRaw(this.axis2); + result = RawGenericJoint.revoluteWithAxes( + rawA1, + rawA2, + rawAx1, + rawAx2, + ); + rawAx1.free(); + rawAx2.free(); + } else { + rawAx = VectorOps.intoRaw(this.axis); + result = RawGenericJoint.revolute(rawA1, rawA2, rawAx); + rawAx.free(); + } + break; + // #endif + } + + rawA1.free(); + rawA2.free(); + + return result; + } +} diff --git a/typescript/src.ts/dynamics/impulse_joint_set.ts b/typescript/src.ts/dynamics/impulse_joint_set.ts new file mode 100644 index 000000000..2d382514b --- /dev/null +++ b/typescript/src.ts/dynamics/impulse_joint_set.ts @@ -0,0 +1,165 @@ +import {RawImpulseJointSet} from "../raw"; +import {Coarena} from "../coarena"; +import {RigidBodySet} from "./rigid_body_set"; +import { + RevoluteImpulseJoint, + FixedImpulseJoint, + ImpulseJoint, + ImpulseJointHandle, + JointData, + JointType, + PrismaticImpulseJoint, + // #if DIM3 + SphericalImpulseJoint, + // #endif +} from "./impulse_joint"; +import {IslandManager} from "./island_manager"; +import {RigidBodyHandle} from "./rigid_body"; +import {Collider, ColliderHandle} from "../geometry"; + +/** + * A set of joints. + * + * To avoid leaking WASM resources, this MUST be freed manually with `jointSet.free()` + * once you are done using it (and all the joints it created). + */ +export class ImpulseJointSet { + raw: RawImpulseJointSet; + private map: Coarena; + + /** + * Release the WASM memory occupied by this joint set. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + + if (!!this.map) { + this.map.clear(); + } + this.map = undefined; + } + + constructor(raw?: RawImpulseJointSet) { + this.raw = raw || new RawImpulseJointSet(); + this.map = new Coarena(); + // Initialize the map with the existing elements, if any. + if (raw) { + raw.forEachJointHandle((handle: ImpulseJointHandle) => { + this.map.set(handle, ImpulseJoint.newTyped(raw, null, handle)); + }); + } + } + + /** @internal */ + public finalizeDeserialization(bodies: RigidBodySet) { + this.map.forEach((joint) => joint.finalizeDeserialization(bodies)); + } + + /** + * Creates a new joint and return its integer handle. + * + * @param bodies - The set of rigid-bodies containing the bodies the joint is attached to. + * @param desc - The joint's parameters. + * @param parent1 - The handle of the first rigid-body this joint is attached to. + * @param parent2 - The handle of the second rigid-body this joint is attached to. + * @param wakeUp - Should the attached rigid-bodies be awakened? + */ + public createJoint( + bodies: RigidBodySet, + desc: JointData, + parent1: RigidBodyHandle, + parent2: RigidBodyHandle, + wakeUp: boolean, + ): ImpulseJoint { + const rawParams = desc.intoRaw(); + const handle = this.raw.createJoint( + rawParams, + parent1, + parent2, + wakeUp, + ); + rawParams.free(); + let joint = ImpulseJoint.newTyped(this.raw, bodies, handle); + this.map.set(handle, joint); + return joint; + } + + /** + * Remove a joint from this set. + * + * @param handle - The integer handle of the joint. + * @param wakeUp - If `true`, the rigid-bodies attached by the removed joint will be woken-up automatically. + */ + public remove(handle: ImpulseJointHandle, wakeUp: boolean) { + this.raw.remove(handle, wakeUp); + this.unmap(handle); + } + + /** + * Calls the given closure with the integer handle of each impulse joint attached to this rigid-body. + * + * @param f - The closure called with the integer handle of each impulse joint attached to the rigid-body. + */ + public forEachJointHandleAttachedToRigidBody( + handle: RigidBodyHandle, + f: (handle: ImpulseJointHandle) => void, + ) { + this.raw.forEachJointAttachedToRigidBody(handle, f); + } + + /** + * Internal function, do not call directly. + * @param handle + */ + public unmap(handle: ImpulseJointHandle) { + this.map.delete(handle); + } + + /** + * The number of joints on this set. + */ + public len(): number { + return this.map.len(); + } + + /** + * Does this set contain a joint with the given handle? + * + * @param handle - The joint handle to check. + */ + public contains(handle: ImpulseJointHandle): boolean { + return this.get(handle) != null; + } + + /** + * Gets the joint with the given handle. + * + * Returns `null` if no joint with the specified handle exists. + * + * @param handle - The integer handle of the joint to retrieve. + */ + public get(handle: ImpulseJointHandle): ImpulseJoint | null { + return this.map.get(handle); + } + + /** + * Applies the given closure to each joint contained by this set. + * + * @param f - The closure to apply. + */ + public forEach(f: (joint: ImpulseJoint) => void) { + this.map.forEach(f); + } + + /** + * Gets all joints in the list. + * + * @returns joint list. + */ + public getAll(): ImpulseJoint[] { + return this.map.getAll(); + } +} diff --git a/typescript/src.ts/dynamics/index.ts b/typescript/src.ts/dynamics/index.ts new file mode 100644 index 000000000..4141658e9 --- /dev/null +++ b/typescript/src.ts/dynamics/index.ts @@ -0,0 +1,10 @@ +export * from "./rigid_body"; +export * from "./rigid_body_set"; +export * from "./integration_parameters"; +export * from "./impulse_joint"; +export * from "./impulse_joint_set"; +export * from "./multibody_joint"; +export * from "./multibody_joint_set"; +export * from "./coefficient_combine_rule"; +export * from "./ccd_solver"; +export * from "./island_manager"; diff --git a/typescript/src.ts/dynamics/integration_parameters.ts b/typescript/src.ts/dynamics/integration_parameters.ts new file mode 100644 index 000000000..b7253e21a --- /dev/null +++ b/typescript/src.ts/dynamics/integration_parameters.ts @@ -0,0 +1,126 @@ +import {RawIntegrationParameters} from "../raw"; + +export class IntegrationParameters { + raw: RawIntegrationParameters; + + constructor(raw?: RawIntegrationParameters) { + this.raw = raw || new RawIntegrationParameters(); + } + + /** + * Free the WASM memory used by these integration parameters. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + /** + * The timestep length (default: `1.0 / 60.0`) + */ + get dt(): number { + return this.raw.dt; + } + + /** + * The Error Reduction Parameter in `[0, 1]` is the proportion of + * the positional error to be corrected at each time step (default: `0.2`). + */ + get contact_erp(): number { + return this.raw.contact_erp; + } + + get lengthUnit(): number { + return this.raw.lengthUnit; + } + + /** + * Normalized amount of penetration the engine won’t attempt to correct (default: `0.001m`). + * + * This threshold considered by the physics engine is this value multiplied by the `lengthUnit`. + */ + get normalizedAllowedLinearError(): number { + return this.raw.normalizedAllowedLinearError; + } + + /** + * The maximal normalized distance separating two objects that will generate predictive contacts (default: `0.002`). + * + * This threshold considered by the physics engine is this value multiplied by the `lengthUnit`. + */ + get normalizedPredictionDistance(): number { + return this.raw.normalizedPredictionDistance; + } + + /** + * The number of solver iterations run by the constraints solver for calculating forces (default: `4`). + */ + get numSolverIterations(): number { + return this.raw.numSolverIterations; + } + + /** + * Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`). + */ + get numInternalPgsIterations(): number { + return this.raw.numInternalPgsIterations; + } + + /** + * Minimum number of dynamic bodies in each active island (default: `128`). + */ + get minIslandSize(): number { + return this.raw.minIslandSize; + } + + /** + * Maximum number of substeps performed by the solver (default: `1`). + */ + get maxCcdSubsteps(): number { + return this.raw.maxCcdSubsteps; + } + + set dt(value: number) { + this.raw.dt = value; + } + + set contact_natural_frequency(value: number) { + this.raw.contact_natural_frequency = value; + } + + set lengthUnit(value: number) { + this.raw.lengthUnit = value; + } + + set normalizedAllowedLinearError(value: number) { + this.raw.normalizedAllowedLinearError = value; + } + + set normalizedPredictionDistance(value: number) { + this.raw.normalizedPredictionDistance = value; + } + + /** + * Sets the number of solver iterations run by the constraints solver for calculating forces (default: `4`). + */ + set numSolverIterations(value: number) { + this.raw.numSolverIterations = value; + } + + /** + * Sets the number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`). + */ + set numInternalPgsIterations(value: number) { + this.raw.numInternalPgsIterations = value; + } + + set minIslandSize(value: number) { + this.raw.minIslandSize = value; + } + + set maxCcdSubsteps(value: number) { + this.raw.maxCcdSubsteps = value; + } +} diff --git a/typescript/src.ts/dynamics/island_manager.ts b/typescript/src.ts/dynamics/island_manager.ts new file mode 100644 index 000000000..65ed21dcb --- /dev/null +++ b/typescript/src.ts/dynamics/island_manager.ts @@ -0,0 +1,37 @@ +import {RawIslandManager} from "../raw"; +import {RigidBodyHandle} from "./rigid_body"; + +/** + * The CCD solver responsible for resolving Continuous Collision Detection. + * + * To avoid leaking WASM resources, this MUST be freed manually with `ccdSolver.free()` + * once you are done using it. + */ +export class IslandManager { + raw: RawIslandManager; + + /** + * Release the WASM memory occupied by this narrow-phase. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawIslandManager) { + this.raw = raw || new RawIslandManager(); + } + + /** + * Applies the given closure to the handle of each active rigid-bodies contained by this set. + * + * A rigid-body is active if it is not sleeping, i.e., if it moved recently. + * + * @param f - The closure to apply. + */ + public forEachActiveRigidBodyHandle(f: (handle: RigidBodyHandle) => void) { + this.raw.forEachActiveRigidBodyHandle(f); + } +} diff --git a/typescript/src.ts/dynamics/multibody_joint.ts b/typescript/src.ts/dynamics/multibody_joint.ts new file mode 100644 index 000000000..5608aec7f --- /dev/null +++ b/typescript/src.ts/dynamics/multibody_joint.ts @@ -0,0 +1,222 @@ +import { + RawImpulseJointSet, + RawJointAxis, + RawJointType, + RawMultibodyJointSet, +} from "../raw"; +import { + FixedImpulseJoint, + ImpulseJointHandle, + JointType, + MotorModel, + PrismaticImpulseJoint, + RevoluteImpulseJoint, +} from "./impulse_joint"; + +// #if DIM3 +import {Quaternion} from "../math"; +import {SphericalImpulseJoint} from "./impulse_joint"; +// #endif + +/** + * The integer identifier of a collider added to a `ColliderSet`. + */ +export type MultibodyJointHandle = number; + +export class MultibodyJoint { + protected rawSet: RawMultibodyJointSet; // The MultibodyJoint won't need to free this. + handle: MultibodyJointHandle; + + constructor(rawSet: RawMultibodyJointSet, handle: MultibodyJointHandle) { + this.rawSet = rawSet; + this.handle = handle; + } + + public static newTyped( + rawSet: RawMultibodyJointSet, + handle: MultibodyJointHandle, + ): MultibodyJoint { + switch (rawSet.jointType(handle)) { + case RawJointType.Revolute: + return new RevoluteMultibodyJoint(rawSet, handle); + case RawJointType.Prismatic: + return new PrismaticMultibodyJoint(rawSet, handle); + case RawJointType.Fixed: + return new FixedMultibodyJoint(rawSet, handle); + // #if DIM3 + case RawJointType.Spherical: + return new SphericalMultibodyJoint(rawSet, handle); + // #endif + default: + return new MultibodyJoint(rawSet, handle); + } + } + + /** + * Checks if this joint is still valid (i.e. that it has + * not been deleted from the joint set yet). + */ + public isValid(): boolean { + return this.rawSet.contains(this.handle); + } + + // /** + // * The unique integer identifier of the first rigid-body this joint it attached to. + // */ + // public bodyHandle1(): RigidBodyHandle { + // return this.rawSet.jointBodyHandle1(this.handle); + // } + // + // /** + // * The unique integer identifier of the second rigid-body this joint is attached to. + // */ + // public bodyHandle2(): RigidBodyHandle { + // return this.rawSet.jointBodyHandle2(this.handle); + // } + // + // /** + // * The type of this joint given as a string. + // */ + // public type(): JointType { + // return this.rawSet.jointType(this.handle); + // } + // + // // #if DIM3 + // /** + // * The rotation quaternion that aligns this joint's first local axis to the `x` axis. + // */ + // public frameX1(): Rotation { + // return RotationOps.fromRaw(this.rawSet.jointFrameX1(this.handle)); + // } + // + // // #endif + // + // // #if DIM3 + // /** + // * The rotation matrix that aligns this joint's second local axis to the `x` axis. + // */ + // public frameX2(): Rotation { + // return RotationOps.fromRaw(this.rawSet.jointFrameX2(this.handle)); + // } + // + // // #endif + // + // /** + // * The position of the first anchor of this joint. + // * + // * The first anchor gives the position of the points application point on the + // * local frame of the first rigid-body it is attached to. + // */ + // public anchor1(): Vector { + // return VectorOps.fromRaw(this.rawSet.jointAnchor1(this.handle)); + // } + // + // /** + // * The position of the second anchor of this joint. + // * + // * The second anchor gives the position of the points application point on the + // * local frame of the second rigid-body it is attached to. + // */ + // public anchor2(): Vector { + // return VectorOps.fromRaw(this.rawSet.jointAnchor2(this.handle)); + // } + + /** + * Controls whether contacts are computed between colliders attached + * to the rigid-bodies linked by this joint. + */ + public setContactsEnabled(enabled: boolean) { + this.rawSet.jointSetContactsEnabled(this.handle, enabled); + } + + /** + * Indicates if contacts are enabled between colliders attached + * to the rigid-bodies linked by this joint. + */ + public contactsEnabled(): boolean { + return this.rawSet.jointContactsEnabled(this.handle); + } +} + +export class UnitMultibodyJoint extends MultibodyJoint { + /** + * The axis left free by this joint. + */ + protected rawAxis?(): RawJointAxis; + + // /** + // * Are the limits enabled for this joint? + // */ + // public limitsEnabled(): boolean { + // return this.rawSet.jointLimitsEnabled(this.handle, this.rawAxis()); + // } + // + // /** + // * The min limit of this joint. + // */ + // public limitsMin(): number { + // return this.rawSet.jointLimitsMin(this.handle, this.rawAxis()); + // } + // + // /** + // * The max limit of this joint. + // */ + // public limitsMax(): number { + // return this.rawSet.jointLimitsMax(this.handle, this.rawAxis()); + // } + // + // public configureMotorModel(model: MotorModel) { + // this.rawSet.jointConfigureMotorModel(this.handle, this.rawAxis(), model); + // } + // + // public configureMotorVelocity(targetVel: number, factor: number) { + // this.rawSet.jointConfigureMotorVelocity(this.handle, this.rawAxis(), targetVel, factor); + // } + // + // public configureMotorPosition(targetPos: number, stiffness: number, damping: number) { + // this.rawSet.jointConfigureMotorPosition(this.handle, this.rawAxis(), targetPos, stiffness, damping); + // } + // + // public configureMotor(targetPos: number, targetVel: number, stiffness: number, damping: number) { + // this.rawSet.jointConfigureMotor(this.handle, this.rawAxis(), targetPos, targetVel, stiffness, damping); + // } +} + +export class FixedMultibodyJoint extends MultibodyJoint {} + +export class PrismaticMultibodyJoint extends UnitMultibodyJoint { + public rawAxis(): RawJointAxis { + return RawJointAxis.LinX; + } +} + +export class RevoluteMultibodyJoint extends UnitMultibodyJoint { + public rawAxis(): RawJointAxis { + return RawJointAxis.AngX; + } +} + +// #if DIM3 +export class SphericalMultibodyJoint extends MultibodyJoint { + /* Unsupported by this alpha release. + public configureMotorModel(model: MotorModel) { + this.rawSet.jointConfigureMotorModel(this.handle, model); + } + + public configureMotorVelocity(targetVel: Vector, factor: number) { + this.rawSet.jointConfigureBallMotorVelocity(this.handle, targetVel.x, targetVel.y, targetVel.z, factor); + } + + public configureMotorPosition(targetPos: Quaternion, stiffness: number, damping: number) { + this.rawSet.jointConfigureBallMotorPosition(this.handle, targetPos.w, targetPos.x, targetPos.y, targetPos.z, stiffness, damping); + } + + public configureMotor(targetPos: Quaternion, targetVel: Vector, stiffness: number, damping: number) { + this.rawSet.jointConfigureBallMotor(this.handle, + targetPos.w, targetPos.x, targetPos.y, targetPos.z, + targetVel.x, targetVel.y, targetVel.z, + stiffness, damping); + } + */ +} +// #endif diff --git a/typescript/src.ts/dynamics/multibody_joint_set.ts b/typescript/src.ts/dynamics/multibody_joint_set.ts new file mode 100644 index 000000000..2fbb34030 --- /dev/null +++ b/typescript/src.ts/dynamics/multibody_joint_set.ts @@ -0,0 +1,157 @@ +import {RawMultibodyJointSet} from "../raw"; +import {Coarena} from "../coarena"; +import {RigidBodySet} from "./rigid_body_set"; +import { + MultibodyJoint, + MultibodyJointHandle, + RevoluteMultibodyJoint, + FixedMultibodyJoint, + PrismaticMultibodyJoint, + // #if DIM3 + SphericalMultibodyJoint, + // #endif +} from "./multibody_joint"; +import {ImpulseJointHandle, JointData, JointType} from "./impulse_joint"; +import {IslandManager} from "./island_manager"; +import {ColliderHandle} from "../geometry"; +import {RigidBodyHandle} from "./rigid_body"; + +/** + * A set of joints. + * + * To avoid leaking WASM resources, this MUST be freed manually with `jointSet.free()` + * once you are done using it (and all the joints it created). + */ +export class MultibodyJointSet { + raw: RawMultibodyJointSet; + private map: Coarena; + + /** + * Release the WASM memory occupied by this joint set. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + + if (!!this.map) { + this.map.clear(); + } + this.map = undefined; + } + + constructor(raw?: RawMultibodyJointSet) { + this.raw = raw || new RawMultibodyJointSet(); + this.map = new Coarena(); + // Initialize the map with the existing elements, if any. + if (raw) { + raw.forEachJointHandle((handle: MultibodyJointHandle) => { + this.map.set(handle, MultibodyJoint.newTyped(this.raw, handle)); + }); + } + } + + /** + * Creates a new joint and return its integer handle. + * + * @param desc - The joint's parameters. + * @param parent1 - The handle of the first rigid-body this joint is attached to. + * @param parent2 - The handle of the second rigid-body this joint is attached to. + * @param wakeUp - Should the attached rigid-bodies be awakened? + */ + public createJoint( + desc: JointData, + parent1: RigidBodyHandle, + parent2: RigidBodyHandle, + wakeUp: boolean, + ): MultibodyJoint { + const rawParams = desc.intoRaw(); + const handle = this.raw.createJoint( + rawParams, + parent1, + parent2, + wakeUp, + ); + rawParams.free(); + let joint = MultibodyJoint.newTyped(this.raw, handle); + this.map.set(handle, joint); + return joint; + } + + /** + * Remove a joint from this set. + * + * @param handle - The integer handle of the joint. + * @param wake_up - If `true`, the rigid-bodies attached by the removed joint will be woken-up automatically. + */ + public remove(handle: MultibodyJointHandle, wake_up: boolean) { + this.raw.remove(handle, wake_up); + this.map.delete(handle); + } + + /** + * Internal function, do not call directly. + * @param handle + */ + public unmap(handle: MultibodyJointHandle) { + this.map.delete(handle); + } + + /** + * The number of joints on this set. + */ + public len(): number { + return this.map.len(); + } + + /** + * Does this set contain a joint with the given handle? + * + * @param handle - The joint handle to check. + */ + public contains(handle: MultibodyJointHandle): boolean { + return this.get(handle) != null; + } + + /** + * Gets the joint with the given handle. + * + * Returns `null` if no joint with the specified handle exists. + * + * @param handle - The integer handle of the joint to retrieve. + */ + public get(handle: MultibodyJointHandle): MultibodyJoint | null { + return this.map.get(handle); + } + + /** + * Applies the given closure to each joint contained by this set. + * + * @param f - The closure to apply. + */ + public forEach(f: (joint: MultibodyJoint) => void) { + this.map.forEach(f); + } + + /** + * Calls the given closure with the integer handle of each multibody joint attached to this rigid-body. + * + * @param f - The closure called with the integer handle of each multibody joint attached to the rigid-body. + */ + public forEachJointHandleAttachedToRigidBody( + handle: RigidBodyHandle, + f: (handle: MultibodyJointHandle) => void, + ) { + this.raw.forEachJointAttachedToRigidBody(handle, f); + } + + /** + * Gets all joints in the list. + * + * @returns joint list. + */ + public getAll(): MultibodyJoint[] { + return this.map.getAll(); + } +} diff --git a/typescript/src.ts/dynamics/rigid_body.ts b/typescript/src.ts/dynamics/rigid_body.ts new file mode 100644 index 000000000..8363f3754 --- /dev/null +++ b/typescript/src.ts/dynamics/rigid_body.ts @@ -0,0 +1,1762 @@ +import {RawRigidBodySet, RawRigidBodyType} from "../raw"; +import {Rotation, RotationOps, Vector, VectorOps, scratchBuffer} from "../math"; +// #if DIM3 +import {SdpMatrix3, SdpMatrix3Ops} from "../math"; +// #endif +import {Collider, ColliderSet} from "../geometry"; + +/** + * The integer identifier of a collider added to a `ColliderSet`. + */ +export type RigidBodyHandle = number; + +/** + * The simulation status of a rigid-body. + */ +// TODO: rename this to RigidBodyType +export enum RigidBodyType { + /** + * A `RigidBodyType::Dynamic` body can be affected by all external forces. + */ + Dynamic = 0, + /** + * A `RigidBodyType::Fixed` body cannot be affected by external forces. + */ + Fixed, + /** + * A `RigidBodyType::KinematicPositionBased` body cannot be affected by any external forces but can be controlled + * by the user at the position level while keeping realistic one-way interaction with dynamic bodies. + * + * One-way interaction means that a kinematic body can push a dynamic body, but a kinematic body + * cannot be pushed by anything. In other words, the trajectory of a kinematic body can only be + * modified by the user and is independent from any contact or joint it is involved in. + */ + KinematicPositionBased, + /** + * A `RigidBodyType::KinematicVelocityBased` body cannot be affected by any external forces but can be controlled + * by the user at the velocity level while keeping realistic one-way interaction with dynamic bodies. + * + * One-way interaction means that a kinematic body can push a dynamic body, but a kinematic body + * cannot be pushed by anything. In other words, the trajectory of a kinematic body can only be + * modified by the user and is independent from any contact or joint it is involved in. + */ + KinematicVelocityBased, +} + +/** + * A rigid-body. + */ +export class RigidBody { + private rawSet: RawRigidBodySet; // The RigidBody won't need to free this. + private colliderSet: ColliderSet; + readonly handle: RigidBodyHandle; + + /** + * An arbitrary user-defined object associated with this rigid-body. + */ + public userData?: unknown; + + constructor( + rawSet: RawRigidBodySet, + colliderSet: ColliderSet, + handle: RigidBodyHandle, + ) { + this.rawSet = rawSet; + this.colliderSet = colliderSet; + this.handle = handle; + } + + /** @internal */ + public finalizeDeserialization(colliderSet: ColliderSet) { + this.colliderSet = colliderSet; + } + + /** + * Checks if this rigid-body is still valid (i.e. that it has + * not been deleted from the rigid-body set yet. + */ + public isValid(): boolean { + return this.rawSet.contains(this.handle); + } + + /** + * Locks or unlocks the ability of this rigid-body to translate. + * + * @param locked - If `true`, this rigid-body will no longer translate due to forces and impulses. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + */ + public lockTranslations(locked: boolean, wakeUp: boolean) { + return this.rawSet.rbLockTranslations(this.handle, locked, wakeUp); + } + + /** + * Locks or unlocks the ability of this rigid-body to rotate. + * + * @param locked - If `true`, this rigid-body will no longer rotate due to torques and impulses. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + */ + public lockRotations(locked: boolean, wakeUp: boolean) { + return this.rawSet.rbLockRotations(this.handle, locked, wakeUp); + } + + // #if DIM2 + /** + * Locks or unlocks the ability of this rigid-body to translation along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Y coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + */ + public setEnabledTranslations( + enableX: boolean, + enableY: boolean, + wakeUp: boolean, + ) { + return this.rawSet.rbSetEnabledTranslations( + this.handle, + enableX, + enableY, + wakeUp, + ); + } + + /** + * Locks or unlocks the ability of this rigid-body to translation along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Y coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + * @deprecated use `this.setEnabledTranslations` with the same arguments instead. + */ + public restrictTranslations( + enableX: boolean, + enableY: boolean, + wakeUp: boolean, + ) { + this.setEnabledTranslations(enableX, enableX, wakeUp); + } + + // #endif + // #if DIM3 + /** + * Locks or unlocks the ability of this rigid-body to translate along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer translate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer translate due to torques and impulses, along the Y coordinate axis. + * @param enableZ - If `false`, this rigid-body will no longer translate due to torques and impulses, along the Z coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + */ + public setEnabledTranslations( + enableX: boolean, + enableY: boolean, + enableZ: boolean, + wakeUp: boolean, + ) { + return this.rawSet.rbSetEnabledTranslations( + this.handle, + enableX, + enableY, + enableZ, + wakeUp, + ); + } + + /** + * Locks or unlocks the ability of this rigid-body to translate along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer translate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer translate due to torques and impulses, along the Y coordinate axis. + * @param enableZ - If `false`, this rigid-body will no longer translate due to torques and impulses, along the Z coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + * @deprecated use `this.setEnabledTranslations` with the same arguments instead. + */ + public restrictTranslations( + enableX: boolean, + enableY: boolean, + enableZ: boolean, + wakeUp: boolean, + ) { + this.setEnabledTranslations(enableX, enableY, enableZ, wakeUp); + } + + /** + * Locks or unlocks the ability of this rigid-body to rotate along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Y coordinate axis. + * @param enableZ - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Z coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + */ + public setEnabledRotations( + enableX: boolean, + enableY: boolean, + enableZ: boolean, + wakeUp: boolean, + ) { + return this.rawSet.rbSetEnabledRotations( + this.handle, + enableX, + enableY, + enableZ, + wakeUp, + ); + } + + /** + * Locks or unlocks the ability of this rigid-body to rotate along individual coordinate axes. + * + * @param enableX - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the X coordinate axis. + * @param enableY - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Y coordinate axis. + * @param enableZ - If `false`, this rigid-body will no longer rotate due to torques and impulses, along the Z coordinate axis. + * @param wakeUp - If `true`, this rigid-body will be automatically awaken if it is currently asleep. + * @deprecated use `this.setEnabledRotations` with the same arguments instead. + */ + public restrictRotations( + enableX: boolean, + enableY: boolean, + enableZ: boolean, + wakeUp: boolean, + ) { + this.setEnabledRotations(enableX, enableY, enableZ, wakeUp); + } + + // #endif + + /** + * The dominance group, in [-127, +127] this rigid-body is part of. + */ + public dominanceGroup(): number { + return this.rawSet.rbDominanceGroup(this.handle); + } + + /** + * Sets the dominance group of this rigid-body. + * + * @param group - The dominance group of this rigid-body. Must be a signed integer in the range [-127, +127]. + */ + public setDominanceGroup(group: number) { + this.rawSet.rbSetDominanceGroup(this.handle, group); + } + + /** + * The number of additional solver iterations that will be run for this + * rigid-body and everything that interacts with it directly or indirectly + * through contacts or joints. + */ + public additionalSolverIterations(): number { + return this.rawSet.rbAdditionalSolverIterations(this.handle); + } + + /** + * Sets the number of additional solver iterations that will be run for this + * rigid-body and everything that interacts with it directly or indirectly + * through contacts or joints. + * + * Compared to increasing the global `World.numSolverIteration`, setting this + * value lets you increase accuracy on only a subset of the scene, resulting in reduced + * performance loss. + * + * @param iters - The new number of additional solver iterations (default: 0). + */ + public setAdditionalSolverIterations(iters: number) { + this.rawSet.rbSetAdditionalSolverIterations(this.handle, iters); + } + + /** + * Enable or disable CCD (Continuous Collision Detection) for this rigid-body. + * + * @param enabled - If `true`, CCD will be enabled for this rigid-body. + */ + public enableCcd(enabled: boolean) { + this.rawSet.rbEnableCcd(this.handle, enabled); + } + + /** + * Sets the soft-CCD prediction distance for this rigid-body. + * + * See the documentation of `RigidBodyDesc.setSoftCcdPrediction` for + * additional details. + */ + public setSoftCcdPrediction(distance: number) { + this.rawSet.rbSetSoftCcdPrediction(this.handle, distance); + } + + /** + * Gets the soft-CCD prediction distance for this rigid-body. + * + * See the documentation of `RigidBodyDesc.setSoftCcdPrediction` for + * additional details. + */ + public softCcdPrediction(): number { + return this.rawSet.rbSoftCcdPrediction(this.handle); + } + + /** + * The world-space translation of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public translation(target?: Vector): Vector { + this.rawSet.rbTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM2 + /** + * The world-space orientation of this rigid-body. + */ + public rotation(): number { + return this.rawSet.rbRotation(this.handle); + } + // #endif + + // #if DIM3 + /** + * The world-space orientation of this rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotation(target?: Rotation): Rotation { + this.rawSet.rbRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + // #endif + + /** + * The world-space next translation of this rigid-body. + * + * If this rigid-body is kinematic this value is set by the `setNextKinematicTranslation` + * method and is used for estimating the kinematic body velocity at the next timestep. + * For non-kinematic bodies, this value is currently unspecified. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public nextTranslation(target?: Vector): Vector { + this.rawSet.rbNextTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM2 + /** + * The world-space next orientation of this rigid-body. + * + * If this rigid-body is kinematic this value is set by the `setNextKinematicRotation` + * method and is used for estimating the kinematic body velocity at the next timestep. + * For non-kinematic bodies, this value is currently unspecified. + */ + public nextRotation(): number { + return this.rawSet.rbNextRotation(this.handle); + } + // #endif + + // #if DIM3 + /** + * The world-space next orientation of this rigid-body. + * + * If this rigid-body is kinematic this value is set by the `setNextKinematicRotation` + * method and is used for estimating the kinematic body velocity at the next timestep. + * For non-kinematic bodies, this value is currently unspecified. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public nextRotation(target?: Rotation): Rotation { + this.rawSet.rbNextRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + // #endif + + /** + * Sets the translation of this rigid-body. + * + * @param tra - The world-space position of the rigid-body. + * @param wakeUp - Forces the rigid-body to wake-up so it is properly affected by forces if it + * wasn't moving before modifying its position. + */ + public setTranslation(tra: Vector, wakeUp: boolean) { + // #if DIM2 + this.rawSet.rbSetTranslation(this.handle, tra.x, tra.y, wakeUp); + // #endif + // #if DIM3 + this.rawSet.rbSetTranslation(this.handle, tra.x, tra.y, tra.z, wakeUp); + // #endif + } + + /** + * Sets the linear velocity of this rigid-body. + * + * @param vel - The linear velocity to set. + * @param wakeUp - Forces the rigid-body to wake-up if it was asleep. + */ + public setLinvel(vel: Vector, wakeUp: boolean) { + let rawVel = VectorOps.intoRaw(vel); + this.rawSet.rbSetLinvel(this.handle, rawVel, wakeUp); + rawVel.free(); + } + + /** + * The scale factor applied to the gravity affecting + * this rigid-body. + */ + public gravityScale(): number { + return this.rawSet.rbGravityScale(this.handle); + } + + /** + * Sets the scale factor applied to the gravity affecting + * this rigid-body. + * + * @param factor - The scale factor to set. A value of 0.0 means + * that this rigid-body will on longer be affected by gravity. + * @param wakeUp - Forces the rigid-body to wake-up if it was asleep. + */ + public setGravityScale(factor: number, wakeUp: boolean) { + this.rawSet.rbSetGravityScale(this.handle, factor, wakeUp); + } + + // #if DIM3 + /** + * Sets the rotation quaternion of this rigid-body. + * + * This does nothing if a zero quaternion is provided. + * + * @param rotation - The rotation to set. + * @param wakeUp - Forces the rigid-body to wake-up so it is properly affected by forces if it + * wasn't moving before modifying its position. + */ + public setRotation(rot: Rotation, wakeUp: boolean) { + this.rawSet.rbSetRotation( + this.handle, + rot.x, + rot.y, + rot.z, + rot.w, + wakeUp, + ); + } + + /** + * Sets the angular velocity for this rigid-body. + * + * @param vel - The angular velocity to set. + * @param wakeUp - Forces the rigid-body to wake-up if it was asleep. + */ + public setAngvel(vel: Vector, wakeUp: boolean) { + let rawVel = VectorOps.intoRaw(vel); + this.rawSet.rbSetAngvel(this.handle, rawVel, wakeUp); + rawVel.free(); + } + + // #endif + + // #if DIM2 + /** + * Sets the rotation angle of this rigid-body. + * + * @param angle - The rotation angle, in radians. + * @param wakeUp - Forces the rigid-body to wake-up so it is properly affected by forces if it + * wasn't moving before modifying its position. + */ + public setRotation(angle: number, wakeUp: boolean) { + this.rawSet.rbSetRotation(this.handle, angle, wakeUp); + } + + /** + * Sets the angular velocity for this rigid-body. + * + * @param vel - The angular velocity to set. + * @param wakeUp - Forces the rigid-body to wake-up if it was asleep. + */ + public setAngvel(vel: number, wakeUp: boolean) { + this.rawSet.rbSetAngvel(this.handle, vel, wakeUp); + } + + // #endif + + /** + * If this rigid body is kinematic, sets its future translation after the next timestep integration. + * + * This should be used instead of `rigidBody.setTranslation` to make the dynamic object + * interacting with this kinematic body behave as expected. Internally, Rapier will compute + * an artificial velocity for this rigid-body from its current position and its next kinematic + * position. This velocity will be used to compute forces on dynamic bodies interacting with + * this body. + * + * @param t - The kinematic translation to set. + */ + public setNextKinematicTranslation(t: Vector) { + // #if DIM2 + this.rawSet.rbSetNextKinematicTranslation(this.handle, t.x, t.y); + // #endif + // #if DIM3 + this.rawSet.rbSetNextKinematicTranslation(this.handle, t.x, t.y, t.z); + // #endif + } + + // #if DIM3 + /** + * If this rigid body is kinematic, sets its future rotation after the next timestep integration. + * + * This should be used instead of `rigidBody.setRotation` to make the dynamic object + * interacting with this kinematic body behave as expected. Internally, Rapier will compute + * an artificial velocity for this rigid-body from its current position and its next kinematic + * position. This velocity will be used to compute forces on dynamic bodies interacting with + * this body. + * + * @param rot - The kinematic rotation to set. + */ + public setNextKinematicRotation(rot: Rotation) { + this.rawSet.rbSetNextKinematicRotation( + this.handle, + rot.x, + rot.y, + rot.z, + rot.w, + ); + } + + // #endif + + // #if DIM2 + /** + * If this rigid body is kinematic, sets its future rotation after the next timestep integration. + * + * This should be used instead of `rigidBody.setRotation` to make the dynamic object + * interacting with this kinematic body behave as expected. Internally, Rapier will compute + * an artificial velocity for this rigid-body from its current position and its next kinematic + * position. This velocity will be used to compute forces on dynamic bodies interacting with + * this body. + * + * @param angle - The kinematic rotation angle, in radians. + */ + public setNextKinematicRotation(angle: number) { + this.rawSet.rbSetNextKinematicRotation(this.handle, angle); + } + + // #endif + + /** + * The linear velocity of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public linvel(target?: Vector): Vector { + this.rawSet.rbLinvel(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The velocity of the given world-space point on this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public velocityAtPoint(point: Vector, target?: Vector): Vector { + const rawPoint = VectorOps.intoRaw(point); + this.rawSet.rbVelocityAtPoint(this.handle, rawPoint, scratchBuffer); + rawPoint.free(); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM3 + /** + * The angular velocity of this rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public angvel(target?: Vector): Vector { + this.rawSet.rbAngvel(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + // #endif + + // #if DIM2 + /** + * The angular velocity of this rigid-body. + */ + public angvel(): number { + return this.rawSet.rbAngvel(this.handle); + } + // #endif + + /** + * The mass of this rigid-body. + */ + public mass(): number { + return this.rawSet.rbMass(this.handle); + } + + /** + * The inverse mass taking into account translation locking. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public effectiveInvMass(target?: Vector): Vector { + this.rawSet.rbEffectiveInvMass(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The inverse of the mass of a rigid-body. + * + * If this is zero, the rigid-body is assumed to have infinite mass. + */ + public invMass(): number { + return this.rawSet.rbInvMass(this.handle); + } + + /** + * The center of mass of a rigid-body expressed in its local-space. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localCom(target?: Vector): Vector { + this.rawSet.rbLocalCom(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The world-space center of mass of the rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public worldCom(target?: Vector): Vector { + this.rawSet.rbWorldCom(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM2 + /** + * The inverse of the principal angular inertia of the rigid-body. + * + * Components set to zero are assumed to be infinite along the corresponding principal axis. + */ + public invPrincipalInertia(): number { + return this.rawSet.rbInvPrincipalInertia(this.handle); + } + // #endif + + // #if DIM3 + /** + * The inverse of the principal angular inertia of the rigid-body. + * + * Components set to zero are assumed to be infinite along the corresponding principal axis. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public invPrincipalInertia(target?: Vector): Vector { + this.rawSet.rbInvPrincipalInertia(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + // #endif + + // #if DIM2 + /** + * The angular inertia along the principal inertia axes of the rigid-body. + */ + public principalInertia(): number { + return this.rawSet.rbPrincipalInertia(this.handle); + } + // #endif + + // #if DIM3 + /** + * The angular inertia along the principal inertia axes of the rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public principalInertia(target?: Vector): Vector { + this.rawSet.rbPrincipalInertia(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + // #endif + + // #if DIM3 + /** + * The principal vectors of the local angular inertia tensor of the rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public principalInertiaLocalFrame(target?: Rotation): Rotation { + this.rawSet.rbPrincipalInertiaLocalFrame(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + // #endif + + // #if DIM2 + /** + * The world-space inverse angular inertia tensor of the rigid-body, + * taking into account rotation locking. + */ + public effectiveWorldInvInertia(): number { + return this.rawSet.rbEffectiveWorldInvInertia(this.handle); + } + // #endif + + // #if DIM3 + /** + * The world-space inverse angular inertia tensor of the rigid-body, + * taking into account rotation locking. + * + * @param {SdpMatrix3?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public effectiveWorldInvInertia(target?: SdpMatrix3): SdpMatrix3 { + this.rawSet.rbEffectiveWorldInvInertia(this.handle, scratchBuffer); + return SdpMatrix3Ops.fromBuffer(scratchBuffer, target); + } + + // #endif + + // #if DIM2 + /** + * The effective world-space angular inertia (that takes the potential rotation locking into account) of + * this rigid-body. + */ + public effectiveAngularInertia(): number { + return this.rawSet.rbEffectiveAngularInertia(this.handle); + } + + // #endif + + // #if DIM3 + /** + * The effective world-space angular inertia (that takes the potential rotation locking into account) of + * this rigid-body. + * + * @param {SdpMatrix3?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public effectiveAngularInertia(target?: SdpMatrix3): SdpMatrix3 { + this.rawSet.rbEffectiveAngularInertia(this.handle, scratchBuffer); + return SdpMatrix3Ops.fromBuffer(scratchBuffer, target); + } + + // #endif + + /** + * Put this rigid body to sleep. + * + * A sleeping body no longer moves and is no longer simulated by the physics engine unless + * it is waken up. It can be woken manually with `this.wakeUp()` or automatically due to + * external forces like contacts. + */ + public sleep() { + this.rawSet.rbSleep(this.handle); + } + + /** + * Wakes this rigid-body up. + * + * A dynamic rigid-body that does not move during several consecutive frames will + * be put to sleep by the physics engine, i.e., it will stop being simulated in order + * to avoid useless computations. + * This methods forces a sleeping rigid-body to wake-up. This is useful, e.g., before modifying + * the position of a dynamic body so that it is properly simulated afterwards. + */ + public wakeUp() { + this.rawSet.rbWakeUp(this.handle); + } + + /** + * Is CCD enabled for this rigid-body? + */ + public isCcdEnabled(): boolean { + return this.rawSet.rbIsCcdEnabled(this.handle); + } + + /** + * The number of colliders attached to this rigid-body. + */ + public numColliders(): number { + return this.rawSet.rbNumColliders(this.handle); + } + + /** + * Retrieves the `i-th` collider attached to this rigid-body. + * + * @param i - The index of the collider to retrieve. Must be a number in `[0, this.numColliders()[`. + * This index is **not** the same as the unique identifier of the collider. + */ + public collider(i: number): Collider { + return this.colliderSet.get(this.rawSet.rbCollider(this.handle, i)); + } + + /** + * Sets whether this rigid-body is enabled or not. + * + * @param enabled - Set to `false` to disable this rigid-body and all its attached colliders. + */ + public setEnabled(enabled: boolean) { + this.rawSet.rbSetEnabled(this.handle, enabled); + } + + /** + * Is this rigid-body enabled? + */ + public isEnabled(): boolean { + return this.rawSet.rbIsEnabled(this.handle); + } + + /** + * The status of this rigid-body: static, dynamic, or kinematic. + */ + public bodyType(): RigidBodyType { + return this.rawSet.rbBodyType(this.handle) as number as RigidBodyType; + } + + /** + * Set a new status for this rigid-body: static, dynamic, or kinematic. + */ + public setBodyType(type: RigidBodyType, wakeUp: boolean) { + return this.rawSet.rbSetBodyType( + this.handle, + type as number as RawRigidBodyType, + wakeUp, + ); + } + + /** + * Is this rigid-body sleeping? + */ + public isSleeping(): boolean { + return this.rawSet.rbIsSleeping(this.handle); + } + + /** + * Is the velocity of this rigid-body not zero? + */ + public isMoving(): boolean { + return this.rawSet.rbIsMoving(this.handle); + } + + /** + * Is this rigid-body static? + */ + public isFixed(): boolean { + return this.rawSet.rbIsFixed(this.handle); + } + + /** + * Is this rigid-body kinematic? + */ + public isKinematic(): boolean { + return this.rawSet.rbIsKinematic(this.handle); + } + + /** + * Is this rigid-body dynamic? + */ + public isDynamic(): boolean { + return this.rawSet.rbIsDynamic(this.handle); + } + + /** + * The linear damping coefficient of this rigid-body. + */ + public linearDamping(): number { + return this.rawSet.rbLinearDamping(this.handle); + } + + /** + * The angular damping coefficient of this rigid-body. + */ + public angularDamping(): number { + return this.rawSet.rbAngularDamping(this.handle); + } + + /** + * Sets the linear damping factor applied to this rigid-body. + * + * @param factor - The damping factor to set. + */ + public setLinearDamping(factor: number) { + this.rawSet.rbSetLinearDamping(this.handle, factor); + } + + /** + * Recompute the mass-properties of this rigid-bodies based on its currently attached colliders. + */ + public recomputeMassPropertiesFromColliders() { + this.rawSet.rbRecomputeMassPropertiesFromColliders( + this.handle, + this.colliderSet.raw, + ); + } + + /** + * Sets the rigid-body's additional mass. + * + * The total angular inertia of the rigid-body will be scaled automatically based on this additional mass. If this + * scaling effect isn’t desired, use Self::additional_mass_properties instead of this method. + * + * This is only the "additional" mass because the total mass of the rigid-body is equal to the sum of this + * additional mass and the mass computed from the colliders (with non-zero densities) attached to this rigid-body. + * + * That total mass (which includes the attached colliders’ contributions) will be updated at the name physics step, + * or can be updated manually with `this.recomputeMassPropertiesFromColliders`. + * + * This will override any previous additional mass-properties set by `this.setAdditionalMass`, + * `this.setAdditionalMassProperties`, `RigidBodyDesc::setAdditionalMass`, or + * `RigidBodyDesc.setAdditionalMassfProperties` for this rigid-body. + * + * @param mass - The additional mass to set. + * @param wakeUp - If `true` then the rigid-body will be woken up if it was put to sleep because it did not move for a while. + */ + public setAdditionalMass(mass: number, wakeUp: boolean) { + this.rawSet.rbSetAdditionalMass(this.handle, mass, wakeUp); + } + + // #if DIM3 + /** + * Sets the rigid-body's additional mass-properties. + * + * This is only the "additional" mass-properties because the total mass-properties of the rigid-body is equal to the + * sum of this additional mass-properties and the mass computed from the colliders (with non-zero densities) attached + * to this rigid-body. + * + * That total mass-properties (which include the attached colliders’ contributions) will be updated at the name + * physics step, or can be updated manually with `this.recomputeMassPropertiesFromColliders`. + * + * This will override any previous mass-properties set by `this.setAdditionalMass`, + * `this.setAdditionalMassProperties`, `RigidBodyDesc.setAdditionalMass`, or `RigidBodyDesc.setAdditionalMassProperties` + * for this rigid-body. + * + * If `wake_up` is true then the rigid-body will be woken up if it was put to sleep because it did not move for a while. + */ + public setAdditionalMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: Vector, + angularInertiaLocalFrame: Rotation, + wakeUp: boolean, + ) { + let rawCom = VectorOps.intoRaw(centerOfMass); + let rawPrincipalInertia = VectorOps.intoRaw(principalAngularInertia); + let rawInertiaFrame = RotationOps.intoRaw(angularInertiaLocalFrame); + + this.rawSet.rbSetAdditionalMassProperties( + this.handle, + mass, + rawCom, + rawPrincipalInertia, + rawInertiaFrame, + wakeUp, + ); + + rawCom.free(); + rawPrincipalInertia.free(); + rawInertiaFrame.free(); + } + + // #endif + + // #if DIM2 + /** + * Sets the rigid-body's additional mass-properties. + * + * This is only the "additional" mass-properties because the total mass-properties of the rigid-body is equal to the + * sum of this additional mass-properties and the mass computed from the colliders (with non-zero densities) attached + * to this rigid-body. + * + * That total mass-properties (which include the attached colliders’ contributions) will be updated at the name + * physics step, or can be updated manually with `this.recomputeMassPropertiesFromColliders`. + * + * This will override any previous mass-properties set by `this.setAdditionalMass`, + * `this.setAdditionalMassProperties`, `RigidBodyDesc.setAdditionalMass`, or `RigidBodyDesc.setAdditionalMassProperties` + * for this rigid-body. + * + * If `wake_up` is true then the rigid-body will be woken up if it was put to sleep because it did not move for a while. + */ + public setAdditionalMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: number, + wakeUp: boolean, + ) { + let rawCom = VectorOps.intoRaw(centerOfMass); + this.rawSet.rbSetAdditionalMassProperties( + this.handle, + mass, + rawCom, + principalAngularInertia, + wakeUp, + ); + rawCom.free(); + } + + // #endif + + /** + * Sets the linear damping factor applied to this rigid-body. + * + * @param factor - The damping factor to set. + */ + public setAngularDamping(factor: number) { + this.rawSet.rbSetAngularDamping(this.handle, factor); + } + + /** + * Resets to zero the user forces (but not torques) applied to this rigid-body. + * + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public resetForces(wakeUp: boolean) { + this.rawSet.rbResetForces(this.handle, wakeUp); + } + + /** + * Resets to zero the user torques applied to this rigid-body. + * + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public resetTorques(wakeUp: boolean) { + this.rawSet.rbResetTorques(this.handle, wakeUp); + } + + /** + * Adds a force at the center-of-mass of this rigid-body. + * + * @param force - the world-space force to add to the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public addForce(force: Vector, wakeUp: boolean) { + const rawForce = VectorOps.intoRaw(force); + this.rawSet.rbAddForce(this.handle, rawForce, wakeUp); + rawForce.free(); + } + + /** + * Applies an impulse at the center-of-mass of this rigid-body. + * + * @param impulse - the world-space impulse to apply on the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public applyImpulse(impulse: Vector, wakeUp: boolean) { + const rawImpulse = VectorOps.intoRaw(impulse); + this.rawSet.rbApplyImpulse(this.handle, rawImpulse, wakeUp); + rawImpulse.free(); + } + + // #if DIM2 + /** + * Adds a torque at the center-of-mass of this rigid-body. + * + * @param torque - the torque to add to the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public addTorque(torque: number, wakeUp: boolean) { + this.rawSet.rbAddTorque(this.handle, torque, wakeUp); + } + + // #endif + + // #if DIM3 + /** + * Adds a torque at the center-of-mass of this rigid-body. + * + * @param torque - the world-space torque to add to the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public addTorque(torque: Vector, wakeUp: boolean) { + const rawTorque = VectorOps.intoRaw(torque); + this.rawSet.rbAddTorque(this.handle, rawTorque, wakeUp); + rawTorque.free(); + } + + // #endif + + // #if DIM2 + /** + * Applies an impulsive torque at the center-of-mass of this rigid-body. + * + * @param torqueImpulse - the torque impulse to apply on the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public applyTorqueImpulse(torqueImpulse: number, wakeUp: boolean) { + this.rawSet.rbApplyTorqueImpulse(this.handle, torqueImpulse, wakeUp); + } + + // #endif + + // #if DIM3 + /** + * Applies an impulsive torque at the center-of-mass of this rigid-body. + * + * @param torqueImpulse - the world-space torque impulse to apply on the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public applyTorqueImpulse(torqueImpulse: Vector, wakeUp: boolean) { + const rawTorqueImpulse = VectorOps.intoRaw(torqueImpulse); + this.rawSet.rbApplyTorqueImpulse(this.handle, rawTorqueImpulse, wakeUp); + rawTorqueImpulse.free(); + } + + // #endif + + /** + * Adds a force at the given world-space point of this rigid-body. + * + * @param force - the world-space force to add to the rigid-body. + * @param point - the world-space point where the impulse is to be applied on the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public addForceAtPoint(force: Vector, point: Vector, wakeUp: boolean) { + const rawForce = VectorOps.intoRaw(force); + const rawPoint = VectorOps.intoRaw(point); + this.rawSet.rbAddForceAtPoint(this.handle, rawForce, rawPoint, wakeUp); + rawForce.free(); + rawPoint.free(); + } + + /** + * Applies an impulse at the given world-space point of this rigid-body. + * + * @param impulse - the world-space impulse to apply on the rigid-body. + * @param point - the world-space point where the impulse is to be applied on the rigid-body. + * @param wakeUp - should the rigid-body be automatically woken-up? + */ + public applyImpulseAtPoint( + impulse: Vector, + point: Vector, + wakeUp: boolean, + ) { + const rawImpulse = VectorOps.intoRaw(impulse); + const rawPoint = VectorOps.intoRaw(point); + this.rawSet.rbApplyImpulseAtPoint( + this.handle, + rawImpulse, + rawPoint, + wakeUp, + ); + rawImpulse.free(); + rawPoint.free(); + } + + /** + * Retrieves the constant force(s) the user added to this rigid-body + * Returns zero if the rigid-body is not dynamic. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public userForce(target?: Vector): Vector { + this.rawSet.rbUserForce(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + // #if DIM2 + /** + * Retrieves the constant torque(s) the user added to this rigid-body + * Returns zero if the rigid-body is not dynamic. + */ + public userTorque(): number { + return this.rawSet.rbUserTorque(this.handle); + } + // #endif + + // #if DIM3 + /** + * Retrieves the constant torque(s) the user added to this rigid-body + * Returns zero if the rigid-body is not dynamic. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public userTorque(target?: Vector): Vector { + this.rawSet.rbUserTorque(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + // #endif +} + +export class RigidBodyDesc { + enabled: boolean; + translation: Vector; + rotation: Rotation; + gravityScale: number; + mass: number; + massOnly: boolean; + centerOfMass: Vector; + translationsEnabledX: boolean; + translationsEnabledY: boolean; + linvel: Vector; + // #if DIM2 + angvel: number; + principalAngularInertia: number; + rotationsEnabled: boolean; + // #endif + // #if DIM3 + angvel: Vector; + principalAngularInertia: Vector; + angularInertiaLocalFrame: Rotation; + translationsEnabledZ: boolean; + rotationsEnabledX: boolean; + rotationsEnabledY: boolean; + rotationsEnabledZ: boolean; + // #endif + linearDamping: number; + angularDamping: number; + status: RigidBodyType; + canSleep: boolean; + sleeping: boolean; + ccdEnabled: boolean; + softCcdPrediction: number; + dominanceGroup: number; + additionalSolverIterations: number; + userData?: unknown; + + constructor(status: RigidBodyType) { + this.enabled = true; + this.status = status; + this.translation = VectorOps.zeros(); + this.rotation = RotationOps.identity(); + this.gravityScale = 1.0; + this.linvel = VectorOps.zeros(); + this.mass = 0.0; + this.massOnly = false; + this.centerOfMass = VectorOps.zeros(); + this.translationsEnabledX = true; + this.translationsEnabledY = true; + // #if DIM2 + this.angvel = 0.0; + this.principalAngularInertia = 0.0; + this.rotationsEnabled = true; + // #endif + // #if DIM3 + this.angvel = VectorOps.zeros(); + this.principalAngularInertia = VectorOps.zeros(); + this.angularInertiaLocalFrame = RotationOps.identity(); + this.translationsEnabledZ = true; + this.rotationsEnabledX = true; + this.rotationsEnabledY = true; + this.rotationsEnabledZ = true; + // #endif + this.linearDamping = 0.0; + this.angularDamping = 0.0; + this.canSleep = true; + this.sleeping = false; + this.ccdEnabled = false; + this.softCcdPrediction = 0.0; + this.dominanceGroup = 0; + this.additionalSolverIterations = 0; + } + + /** + * A rigid-body descriptor used to build a dynamic rigid-body. + */ + public static dynamic(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.Dynamic); + } + + /** + * A rigid-body descriptor used to build a position-based kinematic rigid-body. + */ + public static kinematicPositionBased(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.KinematicPositionBased); + } + + /** + * A rigid-body descriptor used to build a velocity-based kinematic rigid-body. + */ + public static kinematicVelocityBased(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.KinematicVelocityBased); + } + + /** + * A rigid-body descriptor used to build a fixed rigid-body. + */ + public static fixed(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.Fixed); + } + + /** + * A rigid-body descriptor used to build a dynamic rigid-body. + * + * @deprecated The method has been renamed to `.dynamic()`. + */ + public static newDynamic(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.Dynamic); + } + + /** + * A rigid-body descriptor used to build a position-based kinematic rigid-body. + * + * @deprecated The method has been renamed to `.kinematicPositionBased()`. + */ + public static newKinematicPositionBased(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.KinematicPositionBased); + } + + /** + * A rigid-body descriptor used to build a velocity-based kinematic rigid-body. + * + * @deprecated The method has been renamed to `.kinematicVelocityBased()`. + */ + public static newKinematicVelocityBased(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.KinematicVelocityBased); + } + + /** + * A rigid-body descriptor used to build a fixed rigid-body. + * + * @deprecated The method has been renamed to `.fixed()`. + */ + public static newStatic(): RigidBodyDesc { + return new RigidBodyDesc(RigidBodyType.Fixed); + } + + public setDominanceGroup(group: number): RigidBodyDesc { + this.dominanceGroup = group; + return this; + } + + /** + * Sets the number of additional solver iterations that will be run for this + * rigid-body and everything that interacts with it directly or indirectly + * through contacts or joints. + * + * Compared to increasing the global `World.numSolverIteration`, setting this + * value lets you increase accuracy on only a subset of the scene, resulting in reduced + * performance loss. + * + * @param iters - The new number of additional solver iterations (default: 0). + */ + public setAdditionalSolverIterations(iters: number): RigidBodyDesc { + this.additionalSolverIterations = iters; + return this; + } + + /** + * Sets whether the created rigid-body will be enabled or disabled. + * @param enabled − If set to `false` the rigid-body will be disabled at creation. + */ + public setEnabled(enabled: boolean): RigidBodyDesc { + this.enabled = enabled; + return this; + } + + // #if DIM2 + /** + * Sets the initial translation of the rigid-body to create. + */ + public setTranslation(x: number, y: number): RigidBodyDesc { + if (typeof x != "number" || typeof y != "number") + throw TypeError("The translation components must be numbers."); + + this.translation = {x: x, y: y}; + return this; + } + + // #endif + + // #if DIM3 + /** + * Sets the initial translation of the rigid-body to create. + * + * @param tra - The translation to set. + */ + public setTranslation(x: number, y: number, z: number): RigidBodyDesc { + if ( + typeof x != "number" || + typeof y != "number" || + typeof z != "number" + ) + throw TypeError("The translation components must be numbers."); + + this.translation = {x: x, y: y, z: z}; + return this; + } + + // #endif + + /** + * Sets the initial rotation of the rigid-body to create. + * + * @param rot - The rotation to set. + */ + public setRotation(rot: Rotation): RigidBodyDesc { + // #if DIM2 + this.rotation = rot; + // #endif + // #if DIM3 + RotationOps.copy(this.rotation, rot); + // #endif + return this; + } + + /** + * Sets the scale factor applied to the gravity affecting + * the rigid-body being built. + * + * @param scale - The scale factor. Set this to `0.0` if the rigid-body + * needs to ignore gravity. + */ + public setGravityScale(scale: number): RigidBodyDesc { + this.gravityScale = scale; + return this; + } + + /** + * Sets the initial mass of the rigid-body being built, before adding colliders' contributions. + * + * @param mass − The initial mass of the rigid-body to create. + */ + public setAdditionalMass(mass: number): RigidBodyDesc { + this.mass = mass; + this.massOnly = true; + return this; + } + + // #if DIM2 + /** + * Sets the initial linear velocity of the rigid-body to create. + * + * @param x - The linear velocity to set along the `x` axis. + * @param y - The linear velocity to set along the `y` axis. + */ + public setLinvel(x: number, y: number): RigidBodyDesc { + if (typeof x != "number" || typeof y != "number") + throw TypeError("The linvel components must be numbers."); + + this.linvel = {x: x, y: y}; + return this; + } + + /** + * Sets the initial angular velocity of the rigid-body to create. + * + * @param vel - The angular velocity to set. + */ + public setAngvel(vel: number): RigidBodyDesc { + this.angvel = vel; + return this; + } + + /** + * Sets the mass properties of the rigid-body being built. + * + * Note that the final mass properties of the rigid-bodies depends + * on the initial mass-properties of the rigid-body (set by this method) + * to which is added the contributions of all the colliders with non-zero density + * attached to this rigid-body. + * + * Therefore, if you want your provided mass properties to be the final + * mass properties of your rigid-body, don't attach colliders to it, or + * only attach colliders with densities equal to zero. + * + * @param mass − The initial mass of the rigid-body to create. + * @param centerOfMass − The initial center-of-mass of the rigid-body to create. + * @param principalAngularInertia − The initial principal angular inertia of the rigid-body to create. + */ + public setAdditionalMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: number, + ): RigidBodyDesc { + this.mass = mass; + VectorOps.copy(this.centerOfMass, centerOfMass); + this.principalAngularInertia = principalAngularInertia; + this.massOnly = false; + return this; + } + + /** + * Allow translation of this rigid-body only along specific axes. + * @param translationsEnabledX - Are translations along the X axis enabled? + * @param translationsEnabledY - Are translations along the y axis enabled? + */ + public enabledTranslations( + translationsEnabledX: boolean, + translationsEnabledY: boolean, + ): RigidBodyDesc { + this.translationsEnabledX = translationsEnabledX; + this.translationsEnabledY = translationsEnabledY; + return this; + } + + /** + * Allow translation of this rigid-body only along specific axes. + * @param translationsEnabledX - Are translations along the X axis enabled? + * @param translationsEnabledY - Are translations along the y axis enabled? + * @deprecated use `this.enabledTranslations` with the same arguments instead. + */ + public restrictTranslations( + translationsEnabledX: boolean, + translationsEnabledY: boolean, + ): RigidBodyDesc { + return this.enabledTranslations( + translationsEnabledX, + translationsEnabledY, + ); + } + + /** + * Locks all translations that would have resulted from forces on + * the created rigid-body. + */ + public lockTranslations(): RigidBodyDesc { + return this.restrictTranslations(false, false); + } + + /** + * Locks all rotations that would have resulted from forces on + * the created rigid-body. + */ + public lockRotations(): RigidBodyDesc { + this.rotationsEnabled = false; + return this; + } + + // #endif + + // #if DIM3 + /** + * Sets the initial linear velocity of the rigid-body to create. + * + * @param x - The linear velocity to set along the `x` axis. + * @param y - The linear velocity to set along the `y` axis. + * @param z - The linear velocity to set along the `z` axis. + */ + public setLinvel(x: number, y: number, z: number): RigidBodyDesc { + if ( + typeof x != "number" || + typeof y != "number" || + typeof z != "number" + ) + throw TypeError("The linvel components must be numbers."); + + this.linvel = {x: x, y: y, z: z}; + return this; + } + + /** + * Sets the initial angular velocity of the rigid-body to create. + * + * @param vel - The angular velocity to set. + */ + public setAngvel(vel: Vector): RigidBodyDesc { + VectorOps.copy(this.angvel, vel); + return this; + } + + /** + * Sets the mass properties of the rigid-body being built. + * + * Note that the final mass properties of the rigid-bodies depends + * on the initial mass-properties of the rigid-body (set by this method) + * to which is added the contributions of all the colliders with non-zero density + * attached to this rigid-body. + * + * Therefore, if you want your provided mass properties to be the final + * mass properties of your rigid-body, don't attach colliders to it, or + * only attach colliders with densities equal to zero. + * + * @param mass − The initial mass of the rigid-body to create. + * @param centerOfMass − The initial center-of-mass of the rigid-body to create. + * @param principalAngularInertia − The initial principal angular inertia of the rigid-body to create. + * These are the eigenvalues of the angular inertia matrix. + * @param angularInertiaLocalFrame − The initial local angular inertia frame of the rigid-body to create. + * These are the eigenvectors of the angular inertia matrix. + */ + public setAdditionalMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: Vector, + angularInertiaLocalFrame: Rotation, + ): RigidBodyDesc { + this.mass = mass; + VectorOps.copy(this.centerOfMass, centerOfMass); + VectorOps.copy(this.principalAngularInertia, principalAngularInertia); + RotationOps.copy( + this.angularInertiaLocalFrame, + angularInertiaLocalFrame, + ); + this.massOnly = false; + return this; + } + + /** + * Allow translation of this rigid-body only along specific axes. + * @param translationsEnabledX - Are translations along the X axis enabled? + * @param translationsEnabledY - Are translations along the y axis enabled? + * @param translationsEnabledZ - Are translations along the Z axis enabled? + */ + public enabledTranslations( + translationsEnabledX: boolean, + translationsEnabledY: boolean, + translationsEnabledZ: boolean, + ): RigidBodyDesc { + this.translationsEnabledX = translationsEnabledX; + this.translationsEnabledY = translationsEnabledY; + this.translationsEnabledZ = translationsEnabledZ; + return this; + } + + /** + * Allow translation of this rigid-body only along specific axes. + * @param translationsEnabledX - Are translations along the X axis enabled? + * @param translationsEnabledY - Are translations along the y axis enabled? + * @param translationsEnabledZ - Are translations along the Z axis enabled? + * @deprecated use `this.enabledTranslations` with the same arguments instead. + */ + public restrictTranslations( + translationsEnabledX: boolean, + translationsEnabledY: boolean, + translationsEnabledZ: boolean, + ): RigidBodyDesc { + return this.enabledTranslations( + translationsEnabledX, + translationsEnabledY, + translationsEnabledZ, + ); + } + + /** + * Locks all translations that would have resulted from forces on + * the created rigid-body. + */ + public lockTranslations(): RigidBodyDesc { + return this.enabledTranslations(false, false, false); + } + + /** + * Allow rotation of this rigid-body only along specific axes. + * @param rotationsEnabledX - Are rotations along the X axis enabled? + * @param rotationsEnabledY - Are rotations along the y axis enabled? + * @param rotationsEnabledZ - Are rotations along the Z axis enabled? + */ + public enabledRotations( + rotationsEnabledX: boolean, + rotationsEnabledY: boolean, + rotationsEnabledZ: boolean, + ): RigidBodyDesc { + this.rotationsEnabledX = rotationsEnabledX; + this.rotationsEnabledY = rotationsEnabledY; + this.rotationsEnabledZ = rotationsEnabledZ; + return this; + } + + /** + * Allow rotation of this rigid-body only along specific axes. + * @param rotationsEnabledX - Are rotations along the X axis enabled? + * @param rotationsEnabledY - Are rotations along the y axis enabled? + * @param rotationsEnabledZ - Are rotations along the Z axis enabled? + * @deprecated use `this.enabledRotations` with the same arguments instead. + */ + public restrictRotations( + rotationsEnabledX: boolean, + rotationsEnabledY: boolean, + rotationsEnabledZ: boolean, + ): RigidBodyDesc { + return this.enabledRotations( + rotationsEnabledX, + rotationsEnabledY, + rotationsEnabledZ, + ); + } + + /** + * Locks all rotations that would have resulted from forces on + * the created rigid-body. + */ + public lockRotations(): RigidBodyDesc { + return this.restrictRotations(false, false, false); + } + + // #endif + + /** + * Sets the linear damping of the rigid-body to create. + * + * This will progressively slowdown the translational movement of the rigid-body. + * + * @param damping - The angular damping coefficient. Should be >= 0. The higher this + * value is, the stronger the translational slowdown will be. + */ + public setLinearDamping(damping: number): RigidBodyDesc { + this.linearDamping = damping; + return this; + } + + /** + * Sets the angular damping of the rigid-body to create. + * + * This will progressively slowdown the rotational movement of the rigid-body. + * + * @param damping - The angular damping coefficient. Should be >= 0. The higher this + * value is, the stronger the rotational slowdown will be. + */ + public setAngularDamping(damping: number): RigidBodyDesc { + this.angularDamping = damping; + return this; + } + + /** + * Sets whether or not the rigid-body to create can sleep. + * + * @param can - true if the rigid-body can sleep, false if it can't. + */ + public setCanSleep(can: boolean): RigidBodyDesc { + this.canSleep = can; + return this; + } + + /** + * Sets whether or not the rigid-body is to be created asleep. + * + * @param can - true if the rigid-body should be in sleep, default false. + */ + setSleeping(sleeping: boolean): RigidBodyDesc { + this.sleeping = sleeping; + return this; + } + + /** + * Sets whether Continuous Collision Detection (CCD) is enabled for this rigid-body. + * + * @param enabled - true if the rigid-body has CCD enabled. + */ + public setCcdEnabled(enabled: boolean): RigidBodyDesc { + this.ccdEnabled = enabled; + return this; + } + + /** + * Sets the maximum prediction distance Soft Continuous Collision-Detection. + * + * When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of + * slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how + * far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact + * performance badly by increasing the work needed from the broad-phase. + * + * It is a generally cheaper variant of regular CCD (that can be enabled with + * `RigidBodyDesc::setCcdEnabled` since it relies on predictive constraints instead of + * shape-cast and substeps. + */ + public setSoftCcdPrediction(distance: number): RigidBodyDesc { + this.softCcdPrediction = distance; + return this; + } + + /** + * Sets the user-defined object of this rigid-body. + * + * @param userData - The user-defined object to set. + */ + public setUserData(data?: unknown): RigidBodyDesc { + this.userData = data; + return this; + } +} diff --git a/typescript/src.ts/dynamics/rigid_body_set.ts b/typescript/src.ts/dynamics/rigid_body_set.ts new file mode 100644 index 000000000..4c2e47bd5 --- /dev/null +++ b/typescript/src.ts/dynamics/rigid_body_set.ts @@ -0,0 +1,238 @@ +import {RawRigidBodySet, RawRigidBodyType} from "../raw"; +import {Coarena} from "../coarena"; +import {VectorOps, RotationOps} from "../math"; +import { + RigidBody, + RigidBodyDesc, + RigidBodyHandle, + RigidBodyType, +} from "./rigid_body"; +import {ColliderSet} from "../geometry"; +import {ImpulseJointSet} from "./impulse_joint_set"; +import {MultibodyJointSet} from "./multibody_joint_set"; +import {IslandManager} from "./island_manager"; + +/** + * A set of rigid bodies that can be handled by a physics pipeline. + * + * To avoid leaking WASM resources, this MUST be freed manually with `rigidBodySet.free()` + * once you are done using it (and all the rigid-bodies it created). + */ +export class RigidBodySet { + raw: RawRigidBodySet; + private map: Coarena; + + /** + * Release the WASM memory occupied by this rigid-body set. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + + if (!!this.map) { + this.map.clear(); + } + this.map = undefined; + } + + constructor(raw?: RawRigidBodySet) { + this.raw = raw || new RawRigidBodySet(); + this.map = new Coarena(); + // deserialize + if (raw) { + raw.forEachRigidBodyHandle((handle: RigidBodyHandle) => { + this.map.set(handle, new RigidBody(raw, null, handle)); + }); + } + } + + /** + * Internal method, do not call this explicitly. + */ + public finalizeDeserialization(colliderSet: ColliderSet) { + this.map.forEach((rb) => rb.finalizeDeserialization(colliderSet)); + } + + /** + * Creates a new rigid-body and return its integer handle. + * + * @param desc - The description of the rigid-body to create. + */ + public createRigidBody( + colliderSet: ColliderSet, + desc: RigidBodyDesc, + ): RigidBody { + let rawTra = VectorOps.intoRaw(desc.translation); + let rawRot = RotationOps.intoRaw(desc.rotation); + let rawLv = VectorOps.intoRaw(desc.linvel); + let rawCom = VectorOps.intoRaw(desc.centerOfMass); + + // #if DIM3 + let rawAv = VectorOps.intoRaw(desc.angvel); + let rawPrincipalInertia = VectorOps.intoRaw( + desc.principalAngularInertia, + ); + let rawInertiaFrame = RotationOps.intoRaw( + desc.angularInertiaLocalFrame, + ); + // #endif + + let handle = this.raw.createRigidBody( + desc.enabled, + rawTra, + rawRot, + desc.gravityScale, + desc.mass, + desc.massOnly, + rawCom, + rawLv, + // #if DIM2 + desc.angvel, + desc.principalAngularInertia, + desc.translationsEnabledX, + desc.translationsEnabledY, + desc.rotationsEnabled, + // #endif + // #if DIM3 + rawAv, + rawPrincipalInertia, + rawInertiaFrame, + desc.translationsEnabledX, + desc.translationsEnabledY, + desc.translationsEnabledZ, + desc.rotationsEnabledX, + desc.rotationsEnabledY, + desc.rotationsEnabledZ, + // #endif + desc.linearDamping, + desc.angularDamping, + desc.status as number as RawRigidBodyType, + desc.canSleep, + desc.sleeping, + desc.softCcdPrediction, + desc.ccdEnabled, + desc.dominanceGroup, + desc.additionalSolverIterations, + ); + + rawTra.free(); + rawRot.free(); + rawLv.free(); + rawCom.free(); + + // #if DIM3 + rawAv.free(); + rawPrincipalInertia.free(); + rawInertiaFrame.free(); + // #endif + + const body = new RigidBody(this.raw, colliderSet, handle); + body.userData = desc.userData; + + this.map.set(handle, body); + + return body; + } + + /** + * Removes a rigid-body from this set. + * + * This will also remove all the colliders and joints attached to the rigid-body. + * + * @param handle - The integer handle of the rigid-body to remove. + * @param colliders - The set of colliders that may contain colliders attached to the removed rigid-body. + * @param impulseJoints - The set of impulse joints that may contain joints attached to the removed rigid-body. + * @param multibodyJoints - The set of multibody joints that may contain joints attached to the removed rigid-body. + */ + public remove( + handle: RigidBodyHandle, + islands: IslandManager, + colliders: ColliderSet, + impulseJoints: ImpulseJointSet, + multibodyJoints: MultibodyJointSet, + ) { + // Unmap the entities that will be removed automatically because of the rigid-body removals. + for (let i = 0; i < this.raw.rbNumColliders(handle); i += 1) { + colliders.unmap(this.raw.rbCollider(handle, i)); + } + + impulseJoints.forEachJointHandleAttachedToRigidBody(handle, (handle) => + impulseJoints.unmap(handle), + ); + multibodyJoints.forEachJointHandleAttachedToRigidBody( + handle, + (handle) => multibodyJoints.unmap(handle), + ); + + // Remove the rigid-body. + this.raw.remove( + handle, + islands.raw, + colliders.raw, + impulseJoints.raw, + multibodyJoints.raw, + ); + this.map.delete(handle); + } + + /** + * The number of rigid-bodies on this set. + */ + public len(): number { + return this.map.len(); + } + + /** + * Does this set contain a rigid-body with the given handle? + * + * @param handle - The rigid-body handle to check. + */ + public contains(handle: RigidBodyHandle): boolean { + return this.get(handle) != null; + } + + /** + * Gets the rigid-body with the given handle. + * + * @param handle - The handle of the rigid-body to retrieve. + */ + public get(handle: RigidBodyHandle): RigidBody | null { + return this.map.get(handle); + } + + /** + * Applies the given closure to each rigid-body contained by this set. + * + * @param f - The closure to apply. + */ + public forEach(f: (body: RigidBody) => void) { + this.map.forEach(f); + } + + /** + * Applies the given closure to each active rigid-bodies contained by this set. + * + * A rigid-body is active if it is not sleeping, i.e., if it moved recently. + * + * @param f - The closure to apply. + */ + public forEachActiveRigidBody( + islands: IslandManager, + f: (body: RigidBody) => void, + ) { + islands.forEachActiveRigidBodyHandle((handle) => { + f(this.get(handle)); + }); + } + + /** + * Gets all rigid-bodies in the list. + * + * @returns rigid-bodies list. + */ + public getAll(): RigidBody[] { + return this.map.getAll(); + } +} diff --git a/typescript/src.ts/exports.ts b/typescript/src.ts/exports.ts new file mode 100644 index 000000000..237bd5451 --- /dev/null +++ b/typescript/src.ts/exports.ts @@ -0,0 +1,27 @@ +import {version as vers, reserve_memory as reserve} from "./raw"; + +export function version(): string { + return vers(); +} + +/// Reserves additional memory in WASM land. +/// +/// This will grow the internal WASM memory buffer so that it can fit at least +/// the specified amount of extra bytes. This can help reduce future runtime +/// overhead due to dynamic internal memory growth once the limit of the +/// pre-allocated memory is reached. +/// +/// This feature is still experimental. Due to the nature of the internal +/// allocator, there can be situations where the allocator decides to perform +/// additional internal memory growth even though not all `extraBytesCount` +/// are occupied yet. +export function reserveMemory(extraBytesCount: number) { + reserve(extraBytesCount); +} + +export * from "./math"; +export * from "./dynamics"; +export * from "./geometry"; +export * from "./pipeline"; +export * from "./init"; +export * from "./control"; diff --git a/typescript/src.ts/geometry/broad_phase.ts b/typescript/src.ts/geometry/broad_phase.ts new file mode 100644 index 000000000..7101ec3f7 --- /dev/null +++ b/typescript/src.ts/geometry/broad_phase.ts @@ -0,0 +1,539 @@ +import {RawBroadPhase, RawRayColliderIntersection} from "../raw"; +import {RigidBodyHandle, RigidBodySet} from "../dynamics"; +import {ColliderSet} from "./collider_set"; +import {Ray, RayColliderHit, RayColliderIntersection} from "./ray"; +import {InteractionGroups} from "./interaction_groups"; +import {ColliderHandle} from "./collider"; +import {Rotation, RotationOps, Vector, VectorOps, scratchBuffer} from "../math"; +import {Shape} from "./shape"; +import {PointColliderProjection} from "./point"; +import {ColliderShapeCastHit} from "./toi"; +import {QueryFilterFlags} from "../pipeline"; +import {NarrowPhase} from "./narrow_phase"; + +/** + * The broad-phase used for coarse collision-detection. + * + * To avoid leaking WASM resources, this MUST be freed manually with `broadPhase.free()` + * once you are done using it. + */ +export class BroadPhase { + raw: RawBroadPhase; + + /** + * Release the WASM memory occupied by this broad-phase. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawBroadPhase) { + this.raw = raw || new RawBroadPhase(); + } + + /** + * Find the closest intersection between a ray and a set of collider. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + * @param filter - The callback to filter out which collider will be hit. + */ + public castRay( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + ray: Ray, + maxToi: number, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + ): RayColliderHit | null { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let result = RayColliderHit.fromRaw( + colliders, + this.raw.castRay( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawOrig, + rawDir, + maxToi, + solid, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ), + ); + + rawOrig.free(); + rawDir.free(); + + return result; + } + + /** + * Find the closest intersection between a ray and a set of collider. + * + * This also computes the normal at the hit point. + * @param colliders - The set of colliders taking part in this pipeline. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + */ + public castRayAndGetNormal( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + ray: Ray, + maxToi: number, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + target?: RayColliderIntersection, + ): RayColliderIntersection | null { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let result = RayColliderIntersection.fromBuffer( + colliders, + this.raw.castRayAndGetNormal( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawOrig, + rawDir, + maxToi, + solid, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ), + target, + ); + + rawOrig.free(); + rawDir.free(); + + return result; + } + + /** + * Cast a ray and collects all the intersections between a ray and the scene. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + * @param callback - The callback called once per hit (in no particular order) between a ray and a collider. + * If this callback returns `false`, then the cast will stop and no further hits will be detected/reported. + */ + public intersectionsWithRay( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + ray: Ray, + maxToi: number, + solid: boolean, + callback: (intersect: RayColliderIntersection) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + ) { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let rawCallback = (rawInter: RawRayColliderIntersection) => { + return callback( + RayColliderIntersection.fromBuffer(colliders, rawInter), + ); + }; + + this.raw.intersectionsWithRay( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawOrig, + rawDir, + maxToi, + solid, + rawCallback, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + rawOrig.free(); + rawDir.free(); + } + + /** + * Gets the handle of up to one collider intersecting the given shape. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param shapePos - The position of the shape used for the intersection test. + * @param shapeRot - The orientation of the shape used for the intersection test. + * @param shape - The shape used for the intersection test. + * @param groups - The bit groups and filter associated to the ray, in order to only + * hit the colliders with collision groups compatible with the ray's group. + */ + public intersectionWithShape( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + shapePos: Vector, + shapeRot: Rotation, + shape: Shape, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + ): ColliderHandle | null { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawShape = shape.intoRaw(); + let result = this.raw.intersectionWithShape( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPos, + rawRot, + rawShape, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + rawPos.free(); + rawRot.free(); + rawShape.free(); + + return result; + } + + /** + * Find the projection of a point on the closest collider. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param point - The point to project. + * @param solid - If this is set to `true` then the collider shapes are considered to + * be plain (if the point is located inside of a plain shape, its projection is the point + * itself). If it is set to `false` the collider shapes are considered to be hollow + * (if the point is located inside of an hollow shape, it is projected on the shape's + * boundary). + * @param groups - The bit groups and filter associated to the point to project, in order to only + * project on colliders with collision groups compatible with the ray's group. + */ + public projectPoint( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + point: Vector, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + target?: PointColliderProjection, + ): PointColliderProjection | null { + let rawPoint = VectorOps.intoRaw(point); + let result = PointColliderProjection.fromBuffer( + colliders, + this.raw.projectPoint( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPoint, + solid, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ), + target, + ); + + rawPoint.free(); + + return result; + } + + /** + * Find the projection of a point on the closest collider. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param point - The point to project. + * @param groups - The bit groups and filter associated to the point to project, in order to only + * project on colliders with collision groups compatible with the ray's group. + */ + public projectPointAndGetFeature( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + point: Vector, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + target?: PointColliderProjection, + ): PointColliderProjection | null { + let rawPoint = VectorOps.intoRaw(point); + let result = PointColliderProjection.fromBuffer( + colliders, + this.raw.projectPointAndGetFeature( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPoint, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ), + target, + ); + + rawPoint.free(); + + return result; + } + + /** + * Find all the colliders containing the given point. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param point - The point used for the containment test. + * @param groups - The bit groups and filter associated to the point to test, in order to only + * test on colliders with collision groups compatible with the ray's group. + * @param callback - A function called with the handles of each collider with a shape + * containing the `point`. + */ + public intersectionsWithPoint( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + point: Vector, + callback: (handle: ColliderHandle) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + ) { + let rawPoint = VectorOps.intoRaw(point); + + this.raw.intersectionsWithPoint( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPoint, + callback, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + rawPoint.free(); + } + + /** + * Casts a shape at a constant linear velocity and retrieve the first collider it hits. + * This is similar to ray-casting except that we are casting a whole shape instead of + * just a point (the ray origin). + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param shapePos - The initial position of the shape to cast. + * @param shapeRot - The initial rotation of the shape to cast. + * @param shapeVel - The constant velocity of the shape to cast (i.e. the cast direction). + * @param shape - The shape to cast. + * @param targetDistance − If the shape moves closer to this distance from a collider, a hit + * will be returned. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the distance traveled by the shape to `shapeVel.norm() * maxToi`. + * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if + * the shape is penetrating another shape at its starting point **and** its trajectory is such + * that it’s on a path to exit that penetration state. + * @param groups - The bit groups and filter associated to the shape to cast, in order to only + * test on colliders with collision groups compatible with this group. + * @param {ColliderShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public castShape( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + shapePos: Vector, + shapeRot: Rotation, + shapeVel: Vector, + shape: Shape, + targetDistance: number, + maxToi: number, + stopAtPenetration: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + target?: ColliderShapeCastHit, + ): ColliderShapeCastHit | null { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawVel = VectorOps.intoRaw(shapeVel); + let rawShape = shape.intoRaw(); + + const rawColliderShapeCastHit = this.raw.castShape( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPos, + rawRot, + rawVel, + rawShape, + targetDistance, + maxToi, + stopAtPenetration, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + let result = null; + if (rawColliderShapeCastHit) { + const colliderHandle: number = + rawColliderShapeCastHit.colliderHandle(); + rawColliderShapeCastHit.getComponents(scratchBuffer); + result = ColliderShapeCastHit.fromBuffer( + colliders.get(colliderHandle), + scratchBuffer, + target, + ); + rawColliderShapeCastHit.free(); + } + + rawPos.free(); + rawRot.free(); + rawVel.free(); + rawShape.free(); + + return result; + } + + /** + * Retrieve all the colliders intersecting the given shape. + * + * @param colliders - The set of colliders taking part in this pipeline. + * @param shapePos - The position of the shape to test. + * @param shapeRot - The orientation of the shape to test. + * @param shape - The shape to test. + * @param groups - The bit groups and filter associated to the shape to test, in order to only + * test on colliders with collision groups compatible with this group. + * @param callback - A function called with the handles of each collider intersecting the `shape`. + */ + public intersectionsWithShape( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + shapePos: Vector, + shapeRot: Rotation, + shape: Shape, + callback: (handle: ColliderHandle) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: ColliderHandle, + filterExcludeRigidBody?: RigidBodyHandle, + filterPredicate?: (collider: ColliderHandle) => boolean, + ) { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawShape = shape.intoRaw(); + + this.raw.intersectionsWithShape( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawPos, + rawRot, + rawShape, + callback, + filterFlags, + filterGroups, + filterExcludeCollider, + filterExcludeRigidBody, + filterPredicate, + ); + + rawPos.free(); + rawRot.free(); + rawShape.free(); + } + + /** + * Finds the handles of all the colliders with an AABB intersecting the given AABB. + * + * @param aabbCenter - The center of the AABB to test. + * @param aabbHalfExtents - The half-extents of the AABB to test. + * @param callback - The callback that will be called with the handles of all the colliders + * currently intersecting the given AABB. + */ + public collidersWithAabbIntersectingAabb( + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + aabbCenter: Vector, + aabbHalfExtents: Vector, + callback: (handle: ColliderHandle) => boolean, + ) { + let rawCenter = VectorOps.intoRaw(aabbCenter); + let rawHalfExtents = VectorOps.intoRaw(aabbHalfExtents); + this.raw.collidersWithAabbIntersectingAabb( + narrowPhase.raw, + bodies.raw, + colliders.raw, + rawCenter, + rawHalfExtents, + callback, + ); + rawCenter.free(); + rawHalfExtents.free(); + } +} diff --git a/typescript/src.ts/geometry/collider.ts b/typescript/src.ts/geometry/collider.ts new file mode 100644 index 000000000..1f1298fdf --- /dev/null +++ b/typescript/src.ts/geometry/collider.ts @@ -0,0 +1,2193 @@ +import {RawColliderSet, RawShape, RawVHACDParameters} from "../raw"; +import {Rotation, RotationOps, Vector, VectorOps, scratchBuffer} from "../math"; +import {CoefficientCombineRule, RigidBody, RigidBodySet} from "../dynamics"; +import {ActiveHooks, ActiveEvents} from "../pipeline"; +import {InteractionGroups} from "./interaction_groups"; +import { + Shape, + Cuboid, + Ball, + ShapeType, + Capsule, + Voxels, + TriMesh, + Polyline, + Heightfield, + Compound, + Segment, + Triangle, + RoundTriangle, + RoundCuboid, + HalfSpace, + TriMeshFlags, + // #if DIM2 + ConvexPolygon, + RoundConvexPolygon, + // #endif + // #if DIM3 + Cylinder, + RoundCylinder, + Cone, + RoundCone, + ConvexPolyhedron, + RoundConvexPolyhedron, + HeightFieldFlags, + // #endif +} from "./shape"; +import {Ray, RayIntersection} from "./ray"; +import {PointProjection} from "./point"; +import {ColliderShapeCastHit, ShapeCastHit} from "./toi"; +import {ShapeContact} from "./contact"; +import {ColliderSet} from "./collider_set"; + +/** + * Parameters for VHACD convex decomposition algorithm. + * + * All parameters are optional. When not specified, default values from the + * underlying Rapier/Parry library are used. + */ +export interface VHACDParameters { + /** + * Controls the bias toward clipping along symmetry planes. + * Range: [0.0, 1.0] + */ + alpha?: number; + + /** + * Controls the bias toward clipping along revolution planes. + * Range: [0.0, 1.0] + * Useful for objects with cylindrical or rotational features. + */ + beta?: number; + + /** + * Controls maximum allowed deviation from convexity. + * Range: [0.0, 1.0] + * Lower values create more convex parts for a tighter fit. + */ + concavity?: number; + + /** + * Controls the granularity of searching optimal clipping planes. + * Lower values test more planes (slower but more accurate). + */ + planeDownsampling?: number; + + /** + * Controls the precision of convex hull generation. + * Lower values use more voxels for hull computation. + */ + convexHullDownsampling?: number; + + /** + * Maximum number of convex parts to generate. + * Limits part count during decomposition. + */ + maxConvexHulls?: number; + + /** + * Voxel grid resolution for decomposition. + * Higher resolution captures more detail but is slower. + */ + resolution?: number; + + /** + * Whether to use approximate convex hulls for better performance. + * Faster method with minimal impact on quality. + */ + convexHullApproximation?: boolean; +} + +/** + * Flags affecting whether collision-detection happens between two colliders + * depending on the type of rigid-bodies they are attached to. + */ +export enum ActiveCollisionTypes { + /** + * Enable collision-detection between a collider attached to a dynamic body + * and another collider attached to a dynamic body. + */ + DYNAMIC_DYNAMIC = 0b0000_0000_0000_0001, + /** + * Enable collision-detection between a collider attached to a dynamic body + * and another collider attached to a kinematic body. + */ + DYNAMIC_KINEMATIC = 0b0000_0000_0000_1100, + /** + * Enable collision-detection between a collider attached to a dynamic body + * and another collider attached to a fixed body (or not attached to any body). + */ + DYNAMIC_FIXED = 0b0000_0000_0000_0010, + /** + * Enable collision-detection between a collider attached to a kinematic body + * and another collider attached to a kinematic body. + */ + KINEMATIC_KINEMATIC = 0b1100_1100_0000_0000, + + /** + * Enable collision-detection between a collider attached to a kinematic body + * and another collider attached to a fixed body (or not attached to any body). + */ + KINEMATIC_FIXED = 0b0010_0010_0000_0000, + + /** + * Enable collision-detection between a collider attached to a fixed body (or + * not attached to any body) and another collider attached to a fixed body (or + * not attached to any body). + */ + FIXED_FIXED = 0b0000_0000_0010_0000, + /** + * The default active collision types, enabling collisions between a dynamic body + * and another body of any type, but not enabling collisions between two non-dynamic bodies. + */ + DEFAULT = DYNAMIC_KINEMATIC | DYNAMIC_DYNAMIC | DYNAMIC_FIXED, + /** + * Enable collisions between any kind of rigid-bodies (including between two non-dynamic bodies). + */ + ALL = DYNAMIC_KINEMATIC | + DYNAMIC_DYNAMIC | + DYNAMIC_FIXED | + KINEMATIC_KINEMATIC | + KINEMATIC_FIXED | + KINEMATIC_KINEMATIC, +} + +/** + * The integer identifier of a collider added to a `ColliderSet`. + */ +export type ColliderHandle = number; + +/** + * A geometric entity that can be attached to a body so it can be affected + * by contacts and proximity queries. + */ +export class Collider { + private colliderSet: ColliderSet; // The Collider won't need to free this. + readonly handle: ColliderHandle; + private _shape: Shape; // TODO: deprecate/remove this since it isn’t a reliable way of getting the latest shape properties. + private _parent: RigidBody | null; + + constructor( + colliderSet: ColliderSet, + handle: ColliderHandle, + parent: RigidBody | null, + shape?: Shape, + ) { + this.colliderSet = colliderSet; + this.handle = handle; + this._parent = parent; + this._shape = shape; + } + + /** @internal */ + public finalizeDeserialization(bodies: RigidBodySet) { + if (this.handle != null) { + this._parent = bodies.get( + this.colliderSet.raw.coParent(this.handle), + ); + } + } + + private ensureShapeIsCached() { + if (!this._shape) + this._shape = Shape.fromRaw(this.colliderSet.raw, this.handle); + } + + /** + * The shape of this collider. + */ + public get shape(): Shape { + this.ensureShapeIsCached(); + return this._shape; + } + + /** + * Set the internal cached JS shape to null. + * + * This can be useful if you want to free some memory (assuming you are not + * holding any other references to the shape object), or in order to force + * the recalculation of the JS shape (the next time the `shape` getter is + * accessed) from the WASM source of truth. + */ + public clearShapeCache() { + this._shape = null; + } + + /** + * Checks if this collider is still valid (i.e. that it has + * not been deleted from the collider set yet). + */ + public isValid(): boolean { + return this.colliderSet.raw.contains(this.handle); + } + + /** + * The world-space translation of this collider. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public translation(target?: Vector): Vector { + this.colliderSet.raw.coTranslation(this.handle, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The translation of this collider relative to its parent rigid-body. + * + * Returns `null` if the collider doesn’t have a parent rigid-body. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public translationWrtParent(target?: Vector): Vector | null { + const hasParent = this.colliderSet.raw.coTranslationWrtParent( + this.handle, + scratchBuffer, + ); + return hasParent ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + // #if DIM2 + /** + * The world-space orientation of this collider. + */ + public rotation(): number { + return this.colliderSet.raw.coRotation(this.handle); + } + // #endif + + // #if DIM3 + /** + * The world-space orientation of this collider. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotation(target?: Rotation): Rotation { + this.colliderSet.raw.coRotation(this.handle, scratchBuffer); + return RotationOps.fromBuffer(scratchBuffer, target); + } + // #endif + + // #if DIM2 + /** + * The orientation of this collider relative to its parent rigid-body. + * + * Returns `null` if the collider doesn’t have a parent rigid-body. + */ + public rotationWrtParent(): Rotation | null { + const val = this.colliderSet.raw.coRotationWrtParent(this.handle); + return isNaN(val) ? null : val; + } + // #endif + + // #if DIM3 + /** + * The orientation of this collider relative to its parent rigid-body. + * + * Returns `null` if the collider doesn’t have a parent rigid-body. + * + * @param {Rotation?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public rotationWrtParent(target?: Rotation): Rotation | null { + const hasParent = this.colliderSet.raw.coRotationWrtParent( + this.handle, + scratchBuffer, + ); + return hasParent ? RotationOps.fromBuffer(scratchBuffer, target) : null; + } + // #endif + + /** + * Is this collider a sensor? + */ + public isSensor(): boolean { + return this.colliderSet.raw.coIsSensor(this.handle); + } + + /** + * Sets whether this collider is a sensor. + * @param isSensor - If `true`, the collider will be a sensor. + */ + public setSensor(isSensor: boolean) { + this.colliderSet.raw.coSetSensor(this.handle, isSensor); + } + + /** + * Sets the new shape of the collider. + * @param shape - The collider’s new shape. + */ + public setShape(shape: Shape) { + let rawShape = shape.intoRaw(); + this.colliderSet.raw.coSetShape(this.handle, rawShape); + rawShape.free(); + this._shape = shape; + } + + /** + * Sets whether this collider is enabled or not. + * + * @param enabled - Set to `false` to disable this collider (its parent rigid-body won’t be disabled automatically by this). + */ + public setEnabled(enabled: boolean) { + this.colliderSet.raw.coSetEnabled(this.handle, enabled); + } + + /** + * Is this collider enabled? + */ + public isEnabled(): boolean { + return this.colliderSet.raw.coIsEnabled(this.handle); + } + + /** + * Sets the restitution coefficient of the collider to be created. + * + * @param restitution - The restitution coefficient in `[0, 1]`. A value of 0 (the default) means no bouncing behavior + * while 1 means perfect bouncing (though energy may still be lost due to numerical errors of the + * constraints solver). + */ + public setRestitution(restitution: number) { + this.colliderSet.raw.coSetRestitution(this.handle, restitution); + } + + /** + * Sets the friction coefficient of the collider to be created. + * + * @param friction - The friction coefficient. Must be greater or equal to 0. This is generally smaller than 1. The + * higher the coefficient, the stronger friction forces will be for contacts with the collider + * being built. + */ + public setFriction(friction: number) { + this.colliderSet.raw.coSetFriction(this.handle, friction); + } + + /** + * Gets the rule used to combine the friction coefficients of two colliders + * colliders involved in a contact. + */ + public frictionCombineRule(): CoefficientCombineRule { + return this.colliderSet.raw.coFrictionCombineRule(this.handle); + } + + /** + * Sets the rule used to combine the friction coefficients of two colliders + * colliders involved in a contact. + * + * @param rule − The combine rule to apply. + */ + public setFrictionCombineRule(rule: CoefficientCombineRule) { + this.colliderSet.raw.coSetFrictionCombineRule(this.handle, rule); + } + + /** + * Gets the rule used to combine the restitution coefficients of two colliders + * colliders involved in a contact. + */ + public restitutionCombineRule(): CoefficientCombineRule { + return this.colliderSet.raw.coRestitutionCombineRule(this.handle); + } + + /** + * Sets the rule used to combine the restitution coefficients of two colliders + * colliders involved in a contact. + * + * @param rule − The combine rule to apply. + */ + public setRestitutionCombineRule(rule: CoefficientCombineRule) { + this.colliderSet.raw.coSetRestitutionCombineRule(this.handle, rule); + } + + /** + * Sets the collision groups used by this collider. + * + * Two colliders will interact iff. their collision groups are compatible. + * See the documentation of `InteractionGroups` for details on the used bit pattern. + * + * @param groups - The collision groups used for the collider being built. + */ + public setCollisionGroups(groups: InteractionGroups) { + this.colliderSet.raw.coSetCollisionGroups(this.handle, groups); + } + + /** + * Sets the solver groups used by this collider. + * + * Forces between two colliders in contact will be computed iff their solver + * groups are compatible. + * See the documentation of `InteractionGroups` for details on the used bit pattern. + * + * @param groups - The solver groups used for the collider being built. + */ + public setSolverGroups(groups: InteractionGroups) { + this.colliderSet.raw.coSetSolverGroups(this.handle, groups); + } + + /** + * Sets the contact skin for this collider. + * + * See the documentation of `ColliderDesc.setContactSkin` for additional details. + */ + public contactSkin(): number { + return this.colliderSet.raw.coContactSkin(this.handle); + } + + /** + * Sets the contact skin for this collider. + * + * See the documentation of `ColliderDesc.setContactSkin` for additional details. + * + * @param thickness - The contact skin thickness. + */ + public setContactSkin(thickness: number) { + return this.colliderSet.raw.coSetContactSkin(this.handle, thickness); + } + + /** + * Get the physics hooks active for this collider. + */ + public activeHooks(): ActiveHooks { + return this.colliderSet.raw.coActiveHooks(this.handle); + } + + /** + * Set the physics hooks active for this collider. + * + * Use this to enable custom filtering rules for contact/intersecstion pairs involving this collider. + * + * @param activeHooks - The hooks active for contact/intersection pairs involving this collider. + */ + public setActiveHooks(activeHooks: ActiveHooks) { + this.colliderSet.raw.coSetActiveHooks(this.handle, activeHooks); + } + + /** + * The events active for this collider. + */ + public activeEvents(): ActiveEvents { + return this.colliderSet.raw.coActiveEvents(this.handle); + } + + /** + * Set the events active for this collider. + * + * Use this to enable contact and/or intersection event reporting for this collider. + * + * @param activeEvents - The events active for contact/intersection pairs involving this collider. + */ + public setActiveEvents(activeEvents: ActiveEvents) { + this.colliderSet.raw.coSetActiveEvents(this.handle, activeEvents); + } + + /** + * Gets the collision types active for this collider. + */ + public activeCollisionTypes(): ActiveCollisionTypes { + return this.colliderSet.raw.coActiveCollisionTypes(this.handle); + } + + /** + * Sets the total force magnitude beyond which a contact force event can be emitted. + * + * @param threshold - The new force threshold. + */ + public setContactForceEventThreshold(threshold: number) { + return this.colliderSet.raw.coSetContactForceEventThreshold( + this.handle, + threshold, + ); + } + + /** + * The total force magnitude beyond which a contact force event can be emitted. + */ + public contactForceEventThreshold(): number { + return this.colliderSet.raw.coContactForceEventThreshold(this.handle); + } + + /** + * Set the collision types active for this collider. + * + * @param activeCollisionTypes - The hooks active for contact/intersection pairs involving this collider. + */ + public setActiveCollisionTypes(activeCollisionTypes: ActiveCollisionTypes) { + this.colliderSet.raw.coSetActiveCollisionTypes( + this.handle, + activeCollisionTypes, + ); + } + + /** + * Sets the uniform density of this collider. + * + * This will override any previous mass-properties set by `this.setDensity`, + * `this.setMass`, `this.setMassProperties`, `ColliderDesc.density`, + * `ColliderDesc.mass`, or `ColliderDesc.massProperties` for this collider. + * + * The mass and angular inertia of this collider will be computed automatically based on its + * shape. + */ + public setDensity(density: number) { + this.colliderSet.raw.coSetDensity(this.handle, density); + } + + /** + * Sets the mass of this collider. + * + * This will override any previous mass-properties set by `this.setDensity`, + * `this.setMass`, `this.setMassProperties`, `ColliderDesc.density`, + * `ColliderDesc.mass`, or `ColliderDesc.massProperties` for this collider. + * + * The angular inertia of this collider will be computed automatically based on its shape + * and this mass value. + */ + public setMass(mass: number) { + this.colliderSet.raw.coSetMass(this.handle, mass); + } + + // #if DIM3 + /** + * Sets the mass of this collider. + * + * This will override any previous mass-properties set by `this.setDensity`, + * `this.setMass`, `this.setMassProperties`, `ColliderDesc.density`, + * `ColliderDesc.mass`, or `ColliderDesc.massProperties` for this collider. + */ + public setMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: Vector, + angularInertiaLocalFrame: Rotation, + ) { + let rawCom = VectorOps.intoRaw(centerOfMass); + let rawPrincipalInertia = VectorOps.intoRaw(principalAngularInertia); + let rawInertiaFrame = RotationOps.intoRaw(angularInertiaLocalFrame); + + this.colliderSet.raw.coSetMassProperties( + this.handle, + mass, + rawCom, + rawPrincipalInertia, + rawInertiaFrame, + ); + + rawCom.free(); + rawPrincipalInertia.free(); + rawInertiaFrame.free(); + } + + // #endif + + // #if DIM2 + /** + * Sets the mass of this collider. + * + * This will override any previous mass-properties set by `this.setDensity`, + * `this.setMass`, `this.setMassProperties`, `ColliderDesc.density`, + * `ColliderDesc.mass`, or `ColliderDesc.massProperties` for this collider. + */ + public setMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: number, + ) { + let rawCom = VectorOps.intoRaw(centerOfMass); + this.colliderSet.raw.coSetMassProperties( + this.handle, + mass, + rawCom, + principalAngularInertia, + ); + rawCom.free(); + } + + // #endif + + /** + * Sets the translation of this collider. + * + * @param tra - The world-space position of the collider. + */ + public setTranslation(tra: Vector) { + // #if DIM2 + this.colliderSet.raw.coSetTranslation(this.handle, tra.x, tra.y); + // #endif + // #if DIM3 + this.colliderSet.raw.coSetTranslation(this.handle, tra.x, tra.y, tra.z); + // #endif + } + + /** + * Sets the translation of this collider relative to its parent rigid-body. + * + * Does nothing if this collider isn't attached to a rigid-body. + * + * @param tra - The new translation of the collider relative to its parent. + */ + public setTranslationWrtParent(tra: Vector) { + // #if DIM2 + this.colliderSet.raw.coSetTranslationWrtParent( + this.handle, + tra.x, + tra.y, + ); + // #endif + // #if DIM3 + this.colliderSet.raw.coSetTranslationWrtParent( + this.handle, + tra.x, + tra.y, + tra.z, + ); + // #endif + } + + // #if DIM3 + /** + * Sets the rotation quaternion of this collider. + * + * This does nothing if a zero quaternion is provided. + * + * @param rotation - The rotation to set. + */ + public setRotation(rot: Rotation) { + this.colliderSet.raw.coSetRotation( + this.handle, + rot.x, + rot.y, + rot.z, + rot.w, + ); + } + + /** + * Sets the rotation quaternion of this collider relative to its parent rigid-body. + * + * This does nothing if a zero quaternion is provided or if this collider isn't + * attached to a rigid-body. + * + * @param rotation - The rotation to set. + */ + public setRotationWrtParent(rot: Rotation) { + this.colliderSet.raw.coSetRotationWrtParent( + this.handle, + rot.x, + rot.y, + rot.z, + rot.w, + ); + } + + // #endif + // #if DIM2 + /** + * Sets the rotation angle of this collider. + * + * @param angle - The rotation angle, in radians. + */ + public setRotation(angle: number) { + this.colliderSet.raw.coSetRotation(this.handle, angle); + } + + /** + * Sets the rotation angle of this collider relative to its parent rigid-body. + * + * Does nothing if this collider isn't attached to a rigid-body. + * + * @param angle - The rotation angle, in radians. + */ + public setRotationWrtParent(angle: number) { + this.colliderSet.raw.coSetRotationWrtParent(this.handle, angle); + } + + // #endif + + /** + * The type of the shape of this collider. + */ + public shapeType(): ShapeType { + return this.colliderSet.raw.coShapeType( + this.handle, + ) as number as ShapeType; + } + + /** + * The half-extents of this collider if it is a cuboid shape. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public halfExtents(target?: Vector): Vector | null { + const isCuboid = this.colliderSet.raw.coHalfExtents( + this.handle, + scratchBuffer, + ); + return isCuboid ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * Sets the half-extents of this collider if it is a cuboid shape. + * + * @param newHalfExtents - desired half extents. + */ + public setHalfExtents(newHalfExtents: Vector) { + const rawPoint = VectorOps.intoRaw(newHalfExtents); + this.colliderSet.raw.coSetHalfExtents(this.handle, rawPoint); + } + + /** + * The radius of this collider if it is a ball, cylinder, capsule, or cone shape. + */ + public radius(): number { + return this.colliderSet.raw.coRadius(this.handle); + } + + /** + * Sets the radius of this collider if it is a ball, cylinder, capsule, or cone shape. + * + * @param newRadius - desired radius. + */ + public setRadius(newRadius: number): void { + this.colliderSet.raw.coSetRadius(this.handle, newRadius); + } + + /** + * The radius of the round edges of this collider if it is a round cylinder. + */ + public roundRadius(): number { + return this.colliderSet.raw.coRoundRadius(this.handle); + } + + /** + * Sets the radius of the round edges of this collider if it has round edges. + * + * @param newBorderRadius - desired round edge radius. + */ + public setRoundRadius(newBorderRadius: number) { + this.colliderSet.raw.coSetRoundRadius(this.handle, newBorderRadius); + } + + /** + * The half height of this collider if it is a cylinder, capsule, or cone shape. + */ + public halfHeight(): number { + return this.colliderSet.raw.coHalfHeight(this.handle); + } + + /** + * Sets the half height of this collider if it is a cylinder, capsule, or cone shape. + * + * @param newHalfheight - desired half height. + */ + public setHalfHeight(newHalfheight: number) { + this.colliderSet.raw.coSetHalfHeight(this.handle, newHalfheight); + } + + /** + * If this collider has a Voxels shape, this will mark the voxel at the + * given grid coordinates as filled or empty (depending on the `filled` + * argument). + * + * Each input value is assumed to be an integer. + * + * The operation is O(1), unless the provided coordinates are out of the + * bounds of the currently allocated internal grid in which case the grid + * will be grown automatically. + */ + public setVoxel( + ix: number, + iy: number, + // #if DIM3 + iz: number, + // #endif + filled: boolean, + ) { + this.colliderSet.raw.coSetVoxel( + this.handle, + ix, + iy, + // #if DIM3 + iz, + // #endif + filled, + ); + // We modified the shape, invalidate it to keep our cache + // up-to-date the next time the user requests the shape data. + // PERF: this isn’t ideal for performances as this adds a + // hidden, non-constant, cost. + this._shape = null; + } + + /** + * If this and `voxels2` are voxel colliders, and a voxel from `this` was + * modified with `setVoxel`, this will ensure that a + * moving object transitioning across the boundaries of these colliders + * won’t suffer from the "internal edges" artifact. + * + * The indices `ix, iy, iz` indicate the integer coordinates of the voxel in + * the local coordinate frame of `this`. + * + * If the voxels in `voxels2` live in a different coordinate space from `this`, + * then the `shift_*` argument indicate the distance, in voxel units, between + * the origin of `this` to the origin of `voxels2`. + * + * This method is intended to be called between `this` and all the other + * voxels colliders with a domain intersecting `this` or sharing a domain + * boundary. This is an incremental maintenance of the effect of + * `combineVoxelStates`. + */ + public propagateVoxelChange( + voxels2: Collider, + ix: number, + iy: number, + // #if DIM3 + iz: number, + // #endif + shift_x: number, + shift_y: number, + // #if DIM3 + shift_z: number, + // #endif + ) { + this.colliderSet.raw.coPropagateVoxelChange( + this.handle, + voxels2.handle, + ix, + iy, + // #if DIM3 + iz, + // #endif + shift_x, + shift_y, + // #if DIM3 + shift_z, + // #endif + ); + // We modified the shape, invalidate it to keep our cache + // up-to-date the next time the user requests the shape data. + // PERF: this isn’t ideal for performances as this adds a + // hidden, non-constant, cost. + this._shape = null; + } + + /** + * If this and `voxels2` are voxel colliders, this will ensure that a + * moving object transitioning across the boundaries of these colliders + * won’t suffer from the "internal edges" artifact. + * + * If the voxels in `voxels2` live in a different coordinate space from `this`, + * then the `shift_*` argument indicate the distance, in voxel units, between + * the origin of `this` to the origin of `voxels2`. + * + * This method is intended to be called once between all pairs of voxels + * colliders with intersecting domains or shared boundaries. + * + * If either voxels collider is then modified with `setVoxel`, the + * `propagateVoxelChange` method must be called to maintain the coupling + * between the voxels shapes after the modification. + */ + public combineVoxelStates( + voxels2: Collider, + shift_x: number, + shift_y: number, + // #if DIM3 + shift_z: number, + // #endif + ) { + this.colliderSet.raw.coCombineVoxelStates( + this.handle, + voxels2.handle, + shift_x, + shift_y, + // #if DIM3 + shift_z, + // #endif + ); + // We modified the shape, invalidate it to keep our cache + // up-to-date the next time the user requests the shape data. + // PERF: this isn’t ideal for performances as this adds a + // hidden, non-constant, cost. + this._shape = null; + } + + /** + * If this collider has a triangle mesh, polyline, convex polygon, or convex polyhedron shape, + * this returns the vertex buffer of said shape. + */ + public vertices(): Float32Array { + return this.colliderSet.raw.coVertices(this.handle); + } + + /** + * If this collider has a triangle mesh, polyline, or convex polyhedron shape, + * this returns the index buffer of said shape. + */ + public indices(): Uint32Array | undefined { + return this.colliderSet.raw.coIndices(this.handle); + } + + /** + * If this collider has a heightfield shape, this returns the heights buffer of + * the heightfield. + * In 3D, the returned height matrix is provided in column-major order. + */ + public heightfieldHeights(): Float32Array { + return this.colliderSet.raw.coHeightfieldHeights(this.handle); + } + + /** + * If this collider has a heightfield shape, this returns the scale + * applied to it. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public heightfieldScale(target?: Vector): Vector | null { + const isHeightfield = this.colliderSet.raw.coHeightfieldScale( + this.handle, + scratchBuffer, + ); + return isHeightfield + ? VectorOps.fromBuffer(scratchBuffer, target) + : null; + } + + // #if DIM3 + /** + * If this collider has a heightfield shape, this returns the number of + * rows of its height matrix. + */ + public heightfieldNRows(): number { + return this.colliderSet.raw.coHeightfieldNRows(this.handle); + } + + /** + * If this collider has a heightfield shape, this returns the number of + * columns of its height matrix. + */ + public heightfieldNCols(): number { + return this.colliderSet.raw.coHeightfieldNCols(this.handle); + } + + // #endif + + /** + * The rigid-body this collider is attached to. + */ + public parent(): RigidBody | null { + return this._parent; + } + + /** + * The friction coefficient of this collider. + */ + public friction(): number { + return this.colliderSet.raw.coFriction(this.handle); + } + + /** + * The restitution coefficient of this collider. + */ + public restitution(): number { + return this.colliderSet.raw.coRestitution(this.handle); + } + + /** + * The density of this collider. + */ + public density(): number { + return this.colliderSet.raw.coDensity(this.handle); + } + + /** + * The mass of this collider. + */ + public mass(): number { + return this.colliderSet.raw.coMass(this.handle); + } + + /** + * The volume of this collider. + */ + public volume(): number { + return this.colliderSet.raw.coVolume(this.handle); + } + + /** + * The collision groups of this collider. + */ + public collisionGroups(): InteractionGroups { + return this.colliderSet.raw.coCollisionGroups(this.handle); + } + + /** + * The solver groups of this collider. + */ + public solverGroups(): InteractionGroups { + return this.colliderSet.raw.coSolverGroups(this.handle); + } + + /** + * Tests if this collider contains a point. + * + * @param point - The point to test. + */ + public containsPoint(point: Vector): boolean { + let rawPoint = VectorOps.intoRaw(point); + let result = this.colliderSet.raw.coContainsPoint( + this.handle, + rawPoint, + ); + + rawPoint.free(); + + return result; + } + + /** + * Find the projection of a point on this collider. + * + * @param point - The point to project. + * @param solid - If this is set to `true` then the collider shapes are considered to + * be plain (if the point is located inside of a plain shape, its projection is the point + * itself). If it is set to `false` the collider shapes are considered to be hollow + * (if the point is located inside of an hollow shape, it is projected on the shape's + * boundary). + */ + public projectPoint( + point: Vector, + solid: boolean, + target?: PointProjection, + ): PointProjection | null { + let rawPoint = VectorOps.intoRaw(point); + let result = PointProjection.fromBuffer( + this.colliderSet.raw.coProjectPoint(this.handle, rawPoint, solid), + target, + ); + + rawPoint.free(); + + return result; + } + + /** + * Tests if this collider intersects the given ray. + * + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + */ + public intersectsRay(ray: Ray, maxToi: number): boolean { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let result = this.colliderSet.raw.coIntersectsRay( + this.handle, + rawOrig, + rawDir, + maxToi, + ); + + rawOrig.free(); + rawDir.free(); + + return result; + } + + /** + * Computes the smallest time between this and the given shape under translational movement are separated by a distance smaller or equal to distance. + * + * @param collider1Vel - The constant velocity of the current shape to cast (i.e. the cast direction). + * @param shape2 - The shape to cast against. + * @param shape2Pos - The position of the second shape. + * @param shape2Rot - The rotation of the second shape. + * @param shape2Vel - The constant velocity of the second shape. + * @param targetDistance − If the shape moves closer to this distance from a collider, a hit + * will be returned. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the distance traveled by the shape to `collider1Vel.norm() * maxToi`. + * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if + * the shape is penetrating another shape at its starting point **and** its trajectory is such + * that it’s on a path to exit that penetration state. + * @param {ShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public castShape( + collider1Vel: Vector, + shape2: Shape, + shape2Pos: Vector, + shape2Rot: Rotation, + shape2Vel: Vector, + targetDistance: number, + maxToi: number, + stopAtPenetration: boolean, + target?: ShapeCastHit, + ): ShapeCastHit | null { + let rawCollider1Vel = VectorOps.intoRaw(collider1Vel); + let rawShape2Pos = VectorOps.intoRaw(shape2Pos); + let rawShape2Rot = RotationOps.intoRaw(shape2Rot); + let rawShape2Vel = VectorOps.intoRaw(shape2Vel); + let rawShape2 = shape2.intoRaw(); + + const rawShapeCastHit = this.colliderSet.raw.coCastShape( + this.handle, + rawCollider1Vel, + rawShape2, + rawShape2Pos, + rawShape2Rot, + rawShape2Vel, + targetDistance, + maxToi, + stopAtPenetration, + ); + + let result = null; + if (rawShapeCastHit) { + rawShapeCastHit.getComponents(scratchBuffer); + result = ShapeCastHit.fromBuffer(null, scratchBuffer, target); + rawShapeCastHit.free(); + } + + rawCollider1Vel.free(); + rawShape2Pos.free(); + rawShape2Rot.free(); + rawShape2Vel.free(); + rawShape2.free(); + + return result; + } + + /** + * Computes the smallest time between this and the given collider under translational movement are separated by a distance smaller or equal to distance. + * + * @param collider1Vel - The constant velocity of the current collider to cast (i.e. the cast direction). + * @param collider2 - The collider to cast against. + * @param collider2Vel - The constant velocity of the second collider. + * @param targetDistance − If the shape moves closer to this distance from a collider, a hit + * will be returned. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the distance traveled by the shape to `shapeVel.norm() * maxToi`. + * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if + * the shape is penetrating another shape at its starting point **and** its trajectory is such + * that it’s on a path to exit that penetration state. + * @param {ColliderShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public castCollider( + collider1Vel: Vector, + collider2: Collider, + collider2Vel: Vector, + targetDistance: number, + maxToi: number, + stopAtPenetration: boolean, + target?: ColliderShapeCastHit, + ): ColliderShapeCastHit | null { + let rawCollider1Vel = VectorOps.intoRaw(collider1Vel); + let rawCollider2Vel = VectorOps.intoRaw(collider2Vel); + + const rawColliderShapeCastHit = this.colliderSet.raw.coCastCollider( + this.handle, + rawCollider1Vel, + collider2.handle, + rawCollider2Vel, + targetDistance, + maxToi, + stopAtPenetration, + ); + + let result = null; + if (rawColliderShapeCastHit) { + const colliderHandle: number = + rawColliderShapeCastHit.colliderHandle(); + rawColliderShapeCastHit.getComponents(scratchBuffer); + result = ColliderShapeCastHit.fromBuffer( + this.colliderSet.get(colliderHandle), + scratchBuffer, + target, + ); + rawColliderShapeCastHit.free(); + } + + rawCollider1Vel.free(); + rawCollider2Vel.free(); + + return result; + } + + public intersectsShape( + shape2: Shape, + shapePos2: Vector, + shapeRot2: Rotation, + ): boolean { + let rawPos2 = VectorOps.intoRaw(shapePos2); + let rawRot2 = RotationOps.intoRaw(shapeRot2); + let rawShape2 = shape2.intoRaw(); + + let result = this.colliderSet.raw.coIntersectsShape( + this.handle, + rawShape2, + rawPos2, + rawRot2, + ); + + rawPos2.free(); + rawRot2.free(); + rawShape2.free(); + + return result; + } + + /** + * Computes one pair of contact points between the shape owned by this collider and the given shape. + * + * @param shape2 - The second shape. + * @param shape2Pos - The initial position of the second shape. + * @param shape2Rot - The rotation of the second shape. + * @param prediction - The prediction value, if the shapes are separated by a distance greater than this value, test will fail. + * @returns `null` if the shapes are separated by a distance greater than prediction, otherwise contact details. The result is given in world-space. + */ + contactShape( + shape2: Shape, + shape2Pos: Vector, + shape2Rot: Rotation, + prediction: number, + target?: ShapeContact, + ): ShapeContact | null { + let rawPos2 = VectorOps.intoRaw(shape2Pos); + let rawRot2 = RotationOps.intoRaw(shape2Rot); + let rawShape2 = shape2.intoRaw(); + + let result = ShapeContact.fromBuffer( + this.colliderSet.raw.coContactShape( + this.handle, + rawShape2, + rawPos2, + rawRot2, + prediction, + ), + target, + ); + + rawPos2.free(); + rawRot2.free(); + rawShape2.free(); + + return result; + } + + /** + * Computes one pair of contact points between the collider and the given collider. + * + * @param collider2 - The second collider. + * @param prediction - The prediction value, if the shapes are separated by a distance greater than this value, test will fail. + * @returns `null` if the shapes are separated by a distance greater than prediction, otherwise contact details. The result is given in world-space. + */ + contactCollider( + collider2: Collider, + prediction: number, + target?: ShapeContact, + ): ShapeContact | null { + let result = ShapeContact.fromBuffer( + this.colliderSet.raw.coContactCollider( + this.handle, + collider2.handle, + prediction, + ), + target, + ); + + return result; + } + + /** + * Find the closest intersection between a ray and this collider. + * + * This also computes the normal at the hit point. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @returns The time-of-impact between this collider and the ray, or `-1` if there is no intersection. + */ + public castRay(ray: Ray, maxToi: number, solid: boolean): number { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let result = this.colliderSet.raw.coCastRay( + this.handle, + rawOrig, + rawDir, + maxToi, + solid, + ); + + rawOrig.free(); + rawDir.free(); + + return result; + } + + /** + * Find the closest intersection between a ray and this collider. + * + * This also computes the normal at the hit point. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + */ + public castRayAndGetNormal( + ray: Ray, + maxToi: number, + solid: boolean, + target?: RayIntersection, + ): RayIntersection | null { + let rawOrig = VectorOps.intoRaw(ray.origin); + let rawDir = VectorOps.intoRaw(ray.dir); + let result = RayIntersection.fromBuffer( + this.colliderSet.raw.coCastRayAndGetNormal( + this.handle, + rawOrig, + rawDir, + maxToi, + solid, + ), + target, + ); + + rawOrig.free(); + rawDir.free(); + + return result; + } +} + +export enum MassPropsMode { + Density, + Mass, + MassProps, +} + +export class ColliderDesc { + enabled: boolean; + shape: Shape; + massPropsMode: MassPropsMode; + mass: number; + centerOfMass: Vector; + // #if DIM2 + principalAngularInertia: number; + rotationsEnabled: boolean; + // #endif + // #if DIM3 + principalAngularInertia: Vector; + angularInertiaLocalFrame: Rotation; + // #endif + density: number; + friction: number; + restitution: number; + rotation: Rotation; + translation: Vector; + isSensor: boolean; + collisionGroups: InteractionGroups; + solverGroups: InteractionGroups; + frictionCombineRule: CoefficientCombineRule; + restitutionCombineRule: CoefficientCombineRule; + activeEvents: ActiveEvents; + activeHooks: ActiveHooks; + activeCollisionTypes: ActiveCollisionTypes; + contactForceEventThreshold: number; + contactSkin: number; + + /** + * Initializes a collider descriptor from the collision shape. + * + * @param shape - The shape of the collider being built. + */ + constructor(shape: Shape) { + this.enabled = true; + this.shape = shape; + this.massPropsMode = MassPropsMode.Density; + this.density = 1.0; + this.friction = 0.5; + this.restitution = 0.0; + this.rotation = RotationOps.identity(); + this.translation = VectorOps.zeros(); + this.isSensor = false; + this.collisionGroups = 0xffff_ffff; + this.solverGroups = 0xffff_ffff; + this.frictionCombineRule = CoefficientCombineRule.Average; + this.restitutionCombineRule = CoefficientCombineRule.Average; + this.activeCollisionTypes = ActiveCollisionTypes.DEFAULT; + this.activeEvents = ActiveEvents.NONE; + this.activeHooks = ActiveHooks.NONE; + this.mass = 0.0; + this.centerOfMass = VectorOps.zeros(); + this.contactForceEventThreshold = 0.0; + this.contactSkin = 0.0; + + // #if DIM2 + this.principalAngularInertia = 0.0; + this.rotationsEnabled = true; + // #endif + // #if DIM3 + this.principalAngularInertia = VectorOps.zeros(); + this.angularInertiaLocalFrame = RotationOps.identity(); + // #endif + } + + /** + * Create a new collider descriptor with a ball shape. + * + * @param radius - The radius of the ball. + */ + public static ball(radius: number): ColliderDesc { + const shape = new Ball(radius); + return new ColliderDesc(shape); + } + + /** + * Create a new collider descriptor with a capsule shape. + * + * @param halfHeight - The half-height of the capsule, along the `y` axis. + * @param radius - The radius of the capsule basis. + */ + public static capsule(halfHeight: number, radius: number): ColliderDesc { + const shape = new Capsule(halfHeight, radius); + return new ColliderDesc(shape); + } + + /** + * Creates a new segment shape. + * + * @param a - The first point of the segment. + * @param b - The second point of the segment. + */ + public static segment(a: Vector, b: Vector): ColliderDesc { + const shape = new Segment(a, b); + return new ColliderDesc(shape); + } + + /** + * Creates a new triangle shape. + * + * @param a - The first point of the triangle. + * @param b - The second point of the triangle. + * @param c - The third point of the triangle. + */ + public static triangle(a: Vector, b: Vector, c: Vector): ColliderDesc { + const shape = new Triangle(a, b, c); + return new ColliderDesc(shape); + } + + /** + * Creates a new triangle shape with round corners. + * + * @param a - The first point of the triangle. + * @param b - The second point of the triangle. + * @param c - The third point of the triangle. + * @param borderRadius - The radius of the borders of this triangle. In 3D, + * this is also equal to half the thickness of the triangle. + */ + public static roundTriangle( + a: Vector, + b: Vector, + c: Vector, + borderRadius: number, + ): ColliderDesc { + const shape = new RoundTriangle(a, b, c, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a polyline shape. + * + * @param vertices - The coordinates of the polyline's vertices. + * @param indices - The indices of the polyline's segments. If this is `undefined` or `null`, + * the vertices are assumed to describe a line strip. + */ + public static polyline( + vertices: Float32Array, + indices?: Uint32Array | null, + ): ColliderDesc { + const shape = new Polyline(vertices, indices); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a shape made of voxels. + * + * @param data - Defines the set of voxels. If this is a `Int32Array` then + * each voxel is defined from its (signed) grid coordinates, + * with 3 (resp 2) contiguous integers per voxel in 3D (resp 2D). + * If this is a `Float32Array`, each voxel will be such that + * they contain at least one point from this array (where each + * point is defined from 3 (resp 2) contiguous numbers per point + * in 3D (resp 2D). + * @param voxelSize - The size of each voxel. + */ + public static voxels( + voxels: Float32Array | Int32Array, + voxelSize: Vector, + ): ColliderDesc { + const shape = new Voxels(voxels, voxelSize); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a triangle mesh shape. + * + * @param vertices - The coordinates of the triangle mesh's vertices. + * @param indices - The indices of the triangle mesh's triangles. + */ + public static trimesh( + vertices: Float32Array, + indices: Uint32Array, + flags?: TriMeshFlags, + ): ColliderDesc { + const shape = new TriMesh(vertices, indices, flags); + return new ColliderDesc(shape); + } + + // #if DIM2 + /** + * Creates a new collider descriptor with a rectangular shape. + * + * @param hx - The half-width of the rectangle along its local `x` axis. + * @param hy - The half-width of the rectangle along its local `y` axis. + */ + public static cuboid(hx: number, hy: number): ColliderDesc { + const shape = new Cuboid(hx, hy); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a rectangular shape with round borders. + * + * @param hx - The half-width of the rectangle along its local `x` axis. + * @param hy - The half-width of the rectangle along its local `y` axis. + * @param borderRadius - The radius of the cuboid's borders. + */ + public static roundCuboid( + hx: number, + hy: number, + borderRadius: number, + ): ColliderDesc { + const shape = new RoundCuboid(hx, hy, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider description with a halfspace (infinite plane) shape. + * + * @param normal - The outward normal of the plane. + */ + public static halfspace(normal: Vector): ColliderDesc { + const shape = new HalfSpace(normal); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a heightfield shape. + * + * @param heights - The heights of the heightfield, along its local `y` axis. + * @param scale - The scale factor applied to the heightfield. + */ + public static heightfield( + heights: Float32Array, + scale: Vector, + ): ColliderDesc { + const shape = new Heightfield(heights, scale); + return new ColliderDesc(shape); + } + + /** + * Computes the convex-hull of the given points and use the resulting + * convex polygon as the shape for this new collider descriptor. + * + * @param points - The point that will be used to compute the convex-hull. + */ + public static convexHull(points: Float32Array): ColliderDesc | null { + const shape = new ConvexPolygon(points, false); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor that uses the given set of points assumed + * to form a convex polyline (no convex-hull computation will be done). + * + * @param vertices - The vertices of the convex polyline. + */ + public static convexPolyline(vertices: Float32Array): ColliderDesc | null { + const shape = new ConvexPolygon(vertices, true); + return new ColliderDesc(shape); + } + + /** + * Computes the convex-hull of the given points and use the resulting + * convex polygon as the shape for this new collider descriptor. A + * border is added to that convex polygon to give it round corners. + * + * @param points - The point that will be used to compute the convex-hull. + * @param borderRadius - The radius of the round border added to the convex polygon. + */ + public static roundConvexHull( + points: Float32Array, + borderRadius: number, + ): ColliderDesc | null { + const shape = new RoundConvexPolygon(points, borderRadius, false); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor that uses the given set of points assumed + * to form a round convex polyline (no convex-hull computation will be done). + * + * @param vertices - The vertices of the convex polyline. + * @param borderRadius - The radius of the round border added to the convex polyline. + */ + public static roundConvexPolyline( + vertices: Float32Array, + borderRadius: number, + ): ColliderDesc | null { + const shape = new RoundConvexPolygon(vertices, borderRadius, true); + return new ColliderDesc(shape); + } + + // #endif + + // #if DIM3 + /** + * Creates a new collider descriptor with a cuboid shape. + * + * @param hx - The half-width of the rectangle along its local `x` axis. + * @param hy - The half-width of the rectangle along its local `y` axis. + * @param hz - The half-width of the rectangle along its local `z` axis. + */ + public static cuboid(hx: number, hy: number, hz: number): ColliderDesc { + const shape = new Cuboid(hx, hy, hz); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a rectangular shape with round borders. + * + * @param hx - The half-width of the rectangle along its local `x` axis. + * @param hy - The half-width of the rectangle along its local `y` axis. + * @param hz - The half-width of the rectangle along its local `z` axis. + * @param borderRadius - The radius of the cuboid's borders. + */ + public static roundCuboid( + hx: number, + hy: number, + hz: number, + borderRadius: number, + ): ColliderDesc { + const shape = new RoundCuboid(hx, hy, hz, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a heightfield shape. + * + * @param nrows − The number of rows in the heights matrix. + * @param ncols - The number of columns in the heights matrix. + * @param heights - The heights of the heightfield along its local `y` axis, + * provided as a matrix stored in column-major order. + * @param scale - The scale factor applied to the heightfield. + */ + public static heightfield( + nrows: number, + ncols: number, + heights: Float32Array, + scale: Vector, + flags?: HeightFieldFlags, + ): ColliderDesc { + const shape = new Heightfield(nrows, ncols, heights, scale, flags); + return new ColliderDesc(shape); + } + + /** + * Create a new collider descriptor with a cylinder shape. + * + * @param halfHeight - The half-height of the cylinder, along the `y` axis. + * @param radius - The radius of the cylinder basis. + */ + public static cylinder(halfHeight: number, radius: number): ColliderDesc { + const shape = new Cylinder(halfHeight, radius); + return new ColliderDesc(shape); + } + + /** + * Create a new collider descriptor with a cylinder shape with rounded corners. + * + * @param halfHeight - The half-height of the cylinder, along the `y` axis. + * @param radius - The radius of the cylinder basis. + * @param borderRadius - The radius of the cylinder's rounded edges and vertices. + */ + public static roundCylinder( + halfHeight: number, + radius: number, + borderRadius: number, + ): ColliderDesc { + const shape = new RoundCylinder(halfHeight, radius, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Create a new collider descriptor with a cone shape. + * + * @param halfHeight - The half-height of the cone, along the `y` axis. + * @param radius - The radius of the cone basis. + */ + public static cone(halfHeight: number, radius: number): ColliderDesc { + const shape = new Cone(halfHeight, radius); + return new ColliderDesc(shape); + } + + /** + * Create a new collider descriptor with a cone shape with rounded corners. + * + * @param halfHeight - The half-height of the cone, along the `y` axis. + * @param radius - The radius of the cone basis. + * @param borderRadius - The radius of the cone's rounded edges and vertices. + */ + public static roundCone( + halfHeight: number, + radius: number, + borderRadius: number, + ): ColliderDesc { + const shape = new RoundCone(halfHeight, radius, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Computes the convex-hull of the given points and use the resulting + * convex polyhedron as the shape for this new collider descriptor. + * + * @param points - The point that will be used to compute the convex-hull. + */ + public static convexHull(points: Float32Array): ColliderDesc | null { + const shape = new ConvexPolyhedron(points, null); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor that uses the given set of points assumed + * to form a convex polyline (no convex-hull computation will be done). + * + * @param vertices - The vertices of the convex polyline. + */ + public static convexMesh( + vertices: Float32Array, + indices?: Uint32Array | null, + ): ColliderDesc | null { + const shape = new ConvexPolyhedron(vertices, indices); + return new ColliderDesc(shape); + } + + /** + * Computes the convex-hull of the given points and use the resulting + * convex polyhedron as the shape for this new collider descriptor. A + * border is added to that convex polyhedron to give it round corners. + * + * @param points - The point that will be used to compute the convex-hull. + * @param borderRadius - The radius of the round border added to the convex polyhedron. + */ + public static roundConvexHull( + points: Float32Array, + borderRadius: number, + ): ColliderDesc | null { + const shape = new RoundConvexPolyhedron(points, null, borderRadius); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor that uses the given set of points assumed + * to form a round convex polyline (no convex-hull computation will be done). + * + * @param vertices - The vertices of the convex polyline. + * @param borderRadius - The radius of the round border added to the convex polyline. + */ + public static roundConvexMesh( + vertices: Float32Array, + indices: Uint32Array | null, + borderRadius: number, + ): ColliderDesc | null { + const shape = new RoundConvexPolyhedron( + vertices, + indices, + borderRadius, + ); + return new ColliderDesc(shape); + } + + // #endif + + /** + * Creates a new collider descriptor with a compound shape. + * + * @param shapes - The array of shapes composing this compound. Must not be empty, and + * must not contain other compound shapes (nested compound shapes are + * not allowed). + * @param positions - The array of positions for each shape (relative to the compound's origin). + * @param rotations - The array of rotations for each shape (relative to the compound's orientation). + */ + public static compound( + shapes: Shape[], + positions: Vector[], + rotations: Rotation[], + ): ColliderDesc { + const shape = new Compound(shapes, positions, rotations); + return new ColliderDesc(shape); + } + + /** + * Creates a new collider descriptor with a compound shape automatically created + * from a convex decomposition of the given triangle mesh (in 3D) or polyline (in 2D). + * + * @param vertices - The coordinates of the mesh's vertices. + * @param indices - The indices of the mesh's triangles (in 3D) or segments (in 2D). + * @param params - Optional VHACD parameters to control the decomposition. + * @returns The collider descriptor, or `null` if the decomposition did not produce + * any convex part (e.g. if the input mesh is degenerate). + */ + public static convexDecomposition( + vertices: Float32Array, + indices: Uint32Array, + params?: VHACDParameters, + ): ColliderDesc | null { + let rawShape: RawShape; + + if (params) { + // Convert TypeScript params to Rust params + const rawParams = new RawVHACDParameters(); + if (params.alpha !== undefined) rawParams.alpha = params.alpha; + if (params.beta !== undefined) rawParams.beta = params.beta; + if (params.concavity !== undefined) + rawParams.concavity = params.concavity; + if (params.planeDownsampling !== undefined) + rawParams.plane_downsampling = params.planeDownsampling; + if (params.convexHullDownsampling !== undefined) + rawParams.convex_hull_downsampling = + params.convexHullDownsampling; + if (params.maxConvexHulls !== undefined) + rawParams.max_convex_hulls = params.maxConvexHulls; + if (params.resolution !== undefined) + rawParams.resolution = params.resolution; + if (params.convexHullApproximation !== undefined) + rawParams.convex_hull_approximation = + params.convexHullApproximation; + + rawShape = RawShape.convexDecompositionWithParams( + vertices, + indices, + rawParams, + ); + rawParams.free(); + } else { + rawShape = RawShape.convexDecomposition(vertices, indices); + } + + if (!rawShape) { + return null; + } + + const shape = Shape.fromRawShape(rawShape); + return new ColliderDesc(shape); + } + + // #if DIM2 + /** + * Sets the position of the collider to be created relative to the rigid-body it is attached to. + */ + public setTranslation(x: number, y: number): ColliderDesc { + if (typeof x != "number" || typeof y != "number") + throw TypeError("The translation components must be numbers."); + + this.translation = {x: x, y: y}; + return this; + } + + // #endif + + // #if DIM3 + /** + * Sets the position of the collider to be created relative to the rigid-body it is attached to. + */ + public setTranslation(x: number, y: number, z: number): ColliderDesc { + if ( + typeof x != "number" || + typeof y != "number" || + typeof z != "number" + ) + throw TypeError("The translation components must be numbers."); + + this.translation = {x: x, y: y, z: z}; + return this; + } + + // #endif + + /** + * Sets the rotation of the collider to be created relative to the rigid-body it is attached to. + * + * @param rot - The rotation of the collider to be created relative to the rigid-body it is attached to. + */ + public setRotation(rot: Rotation): ColliderDesc { + // #if DIM2 + this.rotation = rot; + // #endif + // #if DIM3 + RotationOps.copy(this.rotation, rot); + // #endif + return this; + } + + /** + * Sets whether or not the collider being created is a sensor. + * + * A sensor collider does not take part of the physics simulation, but generates + * proximity events. + * + * @param sensor - Set to `true` of the collider built is to be a sensor. + */ + public setSensor(sensor: boolean): ColliderDesc { + this.isSensor = sensor; + return this; + } + + /** + * Sets whether the created collider will be enabled or disabled. + * @param enabled − If set to `false` the collider will be disabled at creation. + */ + public setEnabled(enabled: boolean): ColliderDesc { + this.enabled = enabled; + return this; + } + + /** + * Sets the contact skin of the collider. + * + * The contact skin acts as if the collider was enlarged with a skin of width `skin_thickness` + * around it, keeping objects further apart when colliding. + * + * A non-zero contact skin can increase performance, and in some cases, stability. However + * it creates a small gap between colliding object (equal to the sum of their skin). If the + * skin is sufficiently small, this might not be visually significant or can be hidden by the + * rendering assets. + */ + public setContactSkin(thickness: number): ColliderDesc { + this.contactSkin = thickness; + return this; + } + + /** + * Sets the density of the collider being built. + * + * The mass and angular inertia tensor will be computed automatically based on this density and the collider’s shape. + * + * @param density - The density to set, must be greater or equal to 0. A density of 0 means that this collider + * will not affect the mass or angular inertia of the rigid-body it is attached to. + */ + public setDensity(density: number): ColliderDesc { + this.massPropsMode = MassPropsMode.Density; + this.density = density; + return this; + } + + /** + * Sets the mass of the collider being built. + * + * The angular inertia tensor will be computed automatically based on this mass and the collider’s shape. + * + * @param mass - The mass to set, must be greater or equal to 0. + */ + public setMass(mass: number): ColliderDesc { + this.massPropsMode = MassPropsMode.Mass; + this.mass = mass; + return this; + } + + // #if DIM2 + /** + * Sets the mass properties of the collider being built. + * + * This replaces the mass-properties automatically computed from the collider's density and shape. + * These mass-properties will be added to the mass-properties of the rigid-body this collider will be attached to. + * + * @param mass − The mass of the collider to create. + * @param centerOfMass − The center-of-mass of the collider to create. + * @param principalAngularInertia − The principal angular inertia of the collider to create. + */ + public setMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: number, + ): ColliderDesc { + this.massPropsMode = MassPropsMode.MassProps; + this.mass = mass; + VectorOps.copy(this.centerOfMass, centerOfMass); + this.principalAngularInertia = principalAngularInertia; + return this; + } + + // #endif + + // #if DIM3 + /** + * Sets the mass properties of the collider being built. + * + * This replaces the mass-properties automatically computed from the collider's density and shape. + * These mass-properties will be added to the mass-properties of the rigid-body this collider will be attached to. + * + * @param mass − The mass of the collider to create. + * @param centerOfMass − The center-of-mass of the collider to create. + * @param principalAngularInertia − The initial principal angular inertia of the collider to create. + * These are the eigenvalues of the angular inertia matrix. + * @param angularInertiaLocalFrame − The initial local angular inertia frame of the collider to create. + * These are the eigenvectors of the angular inertia matrix. + */ + public setMassProperties( + mass: number, + centerOfMass: Vector, + principalAngularInertia: Vector, + angularInertiaLocalFrame: Rotation, + ): ColliderDesc { + this.massPropsMode = MassPropsMode.MassProps; + this.mass = mass; + VectorOps.copy(this.centerOfMass, centerOfMass); + VectorOps.copy(this.principalAngularInertia, principalAngularInertia); + RotationOps.copy( + this.angularInertiaLocalFrame, + angularInertiaLocalFrame, + ); + return this; + } + + // #endif + + /** + * Sets the restitution coefficient of the collider to be created. + * + * @param restitution - The restitution coefficient in `[0, 1]`. A value of 0 (the default) means no bouncing behavior + * while 1 means perfect bouncing (though energy may still be lost due to numerical errors of the + * constraints solver). + */ + public setRestitution(restitution: number): ColliderDesc { + this.restitution = restitution; + return this; + } + + /** + * Sets the friction coefficient of the collider to be created. + * + * @param friction - The friction coefficient. Must be greater or equal to 0. This is generally smaller than 1. The + * higher the coefficient, the stronger friction forces will be for contacts with the collider + * being built. + */ + public setFriction(friction: number): ColliderDesc { + this.friction = friction; + return this; + } + + /** + * Sets the rule used to combine the friction coefficients of two colliders + * colliders involved in a contact. + * + * @param rule − The combine rule to apply. + */ + public setFrictionCombineRule(rule: CoefficientCombineRule): ColliderDesc { + this.frictionCombineRule = rule; + return this; + } + + /** + * Sets the rule used to combine the restitution coefficients of two colliders + * colliders involved in a contact. + * + * @param rule − The combine rule to apply. + */ + public setRestitutionCombineRule( + rule: CoefficientCombineRule, + ): ColliderDesc { + this.restitutionCombineRule = rule; + return this; + } + + /** + * Sets the collision groups used by this collider. + * + * Two colliders will interact iff. their collision groups are compatible. + * See the documentation of `InteractionGroups` for details on the used bit pattern. + * + * @param groups - The collision groups used for the collider being built. + */ + public setCollisionGroups(groups: InteractionGroups): ColliderDesc { + this.collisionGroups = groups; + return this; + } + + /** + * Sets the solver groups used by this collider. + * + * Forces between two colliders in contact will be computed iff their solver + * groups are compatible. + * See the documentation of `InteractionGroups` for details on the used bit pattern. + * + * @param groups - The solver groups used for the collider being built. + */ + public setSolverGroups(groups: InteractionGroups): ColliderDesc { + this.solverGroups = groups; + return this; + } + + /** + * Set the physics hooks active for this collider. + * + * Use this to enable custom filtering rules for contact/intersecstion pairs involving this collider. + * + * @param activeHooks - The hooks active for contact/intersection pairs involving this collider. + */ + public setActiveHooks(activeHooks: ActiveHooks): ColliderDesc { + this.activeHooks = activeHooks; + return this; + } + + /** + * Set the events active for this collider. + * + * Use this to enable contact and/or intersection event reporting for this collider. + * + * @param activeEvents - The events active for contact/intersection pairs involving this collider. + */ + public setActiveEvents(activeEvents: ActiveEvents): ColliderDesc { + this.activeEvents = activeEvents; + return this; + } + + /** + * Set the collision types active for this collider. + * + * @param activeCollisionTypes - The hooks active for contact/intersection pairs involving this collider. + */ + public setActiveCollisionTypes( + activeCollisionTypes: ActiveCollisionTypes, + ): ColliderDesc { + this.activeCollisionTypes = activeCollisionTypes; + return this; + } + + /** + * Sets the total force magnitude beyond which a contact force event can be emitted. + * + * @param threshold - The force threshold to set. + */ + public setContactForceEventThreshold(threshold: number): ColliderDesc { + this.contactForceEventThreshold = threshold; + return this; + } +} diff --git a/typescript/src.ts/geometry/collider_set.ts b/typescript/src.ts/geometry/collider_set.ts new file mode 100644 index 000000000..832b837a2 --- /dev/null +++ b/typescript/src.ts/geometry/collider_set.ts @@ -0,0 +1,213 @@ +import {RawColliderSet} from "../raw"; +import {Coarena} from "../coarena"; +import {RotationOps, VectorOps} from "../math"; +import {Collider, ColliderDesc, ColliderHandle} from "./collider"; +import {ImpulseJointHandle, IslandManager, RigidBodyHandle} from "../dynamics"; +import {RigidBodySet} from "../dynamics"; + +/** + * A set of rigid bodies that can be handled by a physics pipeline. + * + * To avoid leaking WASM resources, this MUST be freed manually with `colliderSet.free()` + * once you are done using it (and all the rigid-bodies it created). + */ +export class ColliderSet { + raw: RawColliderSet; + private map: Coarena; + + /** + * Release the WASM memory occupied by this collider set. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + + if (!!this.map) { + this.map.clear(); + } + this.map = undefined; + } + + constructor(raw?: RawColliderSet) { + this.raw = raw || new RawColliderSet(); + this.map = new Coarena(); + // Initialize the map with the existing elements, if any. + if (raw) { + raw.forEachColliderHandle((handle: ColliderHandle) => { + this.map.set(handle, new Collider(this, handle, null)); + }); + } + } + + /** @internal */ + public castClosure( + f?: (collider: Collider) => Res, + ): (handle: ColliderHandle) => Res | undefined { + return (handle) => { + if (!!f) { + return f(this.get(handle)); + } else { + return undefined; + } + }; + } + + /** @internal */ + public finalizeDeserialization(bodies: RigidBodySet) { + this.map.forEach((collider) => + collider.finalizeDeserialization(bodies), + ); + } + + /** + * Creates a new collider and return its integer handle. + * + * @param bodies - The set of bodies where the collider's parent can be found. + * @param desc - The collider's description. + * @param parentHandle - The integer handle of the rigid-body this collider is attached to. + */ + public createCollider( + bodies: RigidBodySet, + desc: ColliderDesc, + parentHandle: RigidBodyHandle, + ): Collider { + let hasParent = parentHandle != undefined && parentHandle != null; + + if (hasParent && isNaN(parentHandle)) + throw Error( + "Cannot create a collider with a parent rigid-body handle that is not a number.", + ); + + let rawShape = desc.shape.intoRaw(); + let rawTra = VectorOps.intoRaw(desc.translation); + let rawRot = RotationOps.intoRaw(desc.rotation); + let rawCom = VectorOps.intoRaw(desc.centerOfMass); + + // #if DIM3 + let rawPrincipalInertia = VectorOps.intoRaw( + desc.principalAngularInertia, + ); + let rawInertiaFrame = RotationOps.intoRaw( + desc.angularInertiaLocalFrame, + ); + // #endif + + let handle = this.raw.createCollider( + desc.enabled, + rawShape, + rawTra, + rawRot, + desc.massPropsMode, + desc.mass, + rawCom, + // #if DIM2 + desc.principalAngularInertia, + // #endif + // #if DIM3 + rawPrincipalInertia, + rawInertiaFrame, + // #endif + desc.density, + desc.friction, + desc.restitution, + desc.frictionCombineRule, + desc.restitutionCombineRule, + desc.isSensor, + desc.collisionGroups, + desc.solverGroups, + desc.activeCollisionTypes, + desc.activeHooks, + desc.activeEvents, + desc.contactForceEventThreshold, + desc.contactSkin, + hasParent, + hasParent ? parentHandle : 0, + bodies.raw, + ); + + rawShape.free(); + rawTra.free(); + rawRot.free(); + rawCom.free(); + + // #if DIM3 + rawPrincipalInertia.free(); + rawInertiaFrame.free(); + // #endif + + let parent = hasParent ? bodies.get(parentHandle) : null; + let collider = new Collider(this, handle, parent, desc.shape); + this.map.set(handle, collider); + return collider; + } + + /** + * Remove a collider from this set. + * + * @param handle - The integer handle of the collider to remove. + * @param bodies - The set of rigid-body containing the rigid-body the collider is attached to. + * @param wakeUp - If `true`, the rigid-body the removed collider is attached to will be woken-up automatically. + */ + public remove( + handle: ColliderHandle, + islands: IslandManager, + bodies: RigidBodySet, + wakeUp: boolean, + ) { + this.raw.remove(handle, islands.raw, bodies.raw, wakeUp); + this.unmap(handle); + } + + /** + * Internal function, do not call directly. + * @param handle + */ + public unmap(handle: ImpulseJointHandle) { + this.map.delete(handle); + } + + /** + * Gets the rigid-body with the given handle. + * + * @param handle - The handle of the rigid-body to retrieve. + */ + public get(handle: ColliderHandle): Collider | null { + return this.map.get(handle); + } + + /** + * The number of colliders on this set. + */ + public len(): number { + return this.map.len(); + } + + /** + * Does this set contain a collider with the given handle? + * + * @param handle - The collider handle to check. + */ + public contains(handle: ColliderHandle): boolean { + return this.get(handle) != null; + } + + /** + * Applies the given closure to each collider contained by this set. + * + * @param f - The closure to apply. + */ + public forEach(f: (collider: Collider) => void) { + this.map.forEach(f); + } + + /** + * Gets all colliders in the list. + * + * @returns collider list. + */ + public getAll(): Collider[] { + return this.map.getAll(); + } +} diff --git a/typescript/src.ts/geometry/contact.ts b/typescript/src.ts/geometry/contact.ts new file mode 100644 index 000000000..dc76b5576 --- /dev/null +++ b/typescript/src.ts/geometry/contact.ts @@ -0,0 +1,101 @@ +import {Vector, VectorOps, scratchBuffer} from "../math"; +import {RawShapeContact} from "../raw"; + +/** + * The contact info between two shapes. + */ +export class ShapeContact { + /** + * Distance between the two contact points. + * If this is negative, this contact represents a penetration. + */ + distance: number; + + /** + * Position of the contact on the first shape. + */ + point1: Vector; + + /** + * Position of the contact on the second shape. + */ + point2: Vector; + + /** + * Contact normal, pointing towards the exterior of the first shape. + */ + normal1: Vector; + + /** + * Contact normal, pointing towards the exterior of the second shape. + * If these contact data are expressed in world-space, this normal is equal to -normal1. + */ + normal2: Vector; + + constructor( + dist: number, + point1: Vector, + point2: Vector, + normal1: Vector, + normal2: Vector, + ) { + this.distance = dist; + this.point1 = point1; + this.point2 = point2; + this.normal1 = normal1; + this.normal2 = normal2; + } + + /** + * @param raw - The raw contact returned by the WASM query. It is freed by this method. + * @param target - If provided, this object is populated and returned instead of + * allocating a new one. + */ + public static fromBuffer( + raw: RawShapeContact, + target?: ShapeContact, + ): ShapeContact { + if (!raw) return null; + + raw.getComponents(scratchBuffer); + raw.free(); + + target ??= new ShapeContact( + 0, + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + ); + + target.distance = scratchBuffer[0]; + + // #if DIM2 + target.point1.x = scratchBuffer[1]; + target.point1.y = scratchBuffer[2]; + target.point2.x = scratchBuffer[3]; + target.point2.y = scratchBuffer[4]; + target.normal1.x = scratchBuffer[5]; + target.normal1.y = scratchBuffer[6]; + target.normal2.x = scratchBuffer[7]; + target.normal2.y = scratchBuffer[8]; + // #endif + + // #if DIM3 + target.point1.x = scratchBuffer[1]; + target.point1.y = scratchBuffer[2]; + target.point1.z = scratchBuffer[3]; + target.point2.x = scratchBuffer[4]; + target.point2.y = scratchBuffer[5]; + target.point2.z = scratchBuffer[6]; + target.normal1.x = scratchBuffer[7]; + target.normal1.y = scratchBuffer[8]; + target.normal1.z = scratchBuffer[9]; + target.normal2.x = scratchBuffer[10]; + target.normal2.y = scratchBuffer[11]; + target.normal2.z = scratchBuffer[12]; + // #endif + + return target; + } +} diff --git a/typescript/src.ts/geometry/feature.ts b/typescript/src.ts/geometry/feature.ts new file mode 100644 index 000000000..bec9560d3 --- /dev/null +++ b/typescript/src.ts/geometry/feature.ts @@ -0,0 +1,16 @@ +// #if DIM2 +export enum FeatureType { + Vertex, + Face, + Unknown, +} +// #endif + +// #if DIM3 +export enum FeatureType { + Vertex, + Edge, + Face, + Unknown, +} +// #endif diff --git a/typescript/src.ts/geometry/index.ts b/typescript/src.ts/geometry/index.ts new file mode 100644 index 000000000..1bd19e50b --- /dev/null +++ b/typescript/src.ts/geometry/index.ts @@ -0,0 +1,11 @@ +export * from "./broad_phase"; +export * from "./narrow_phase"; +export * from "./shape"; +export * from "./collider"; +export * from "./collider_set"; +export * from "./feature"; +export * from "./ray"; +export * from "./point"; +export * from "./toi"; +export * from "./interaction_groups"; +export * from "./contact"; diff --git a/typescript/src.ts/geometry/interaction_groups.ts b/typescript/src.ts/geometry/interaction_groups.ts new file mode 100644 index 000000000..4d73fd31c --- /dev/null +++ b/typescript/src.ts/geometry/interaction_groups.ts @@ -0,0 +1,18 @@ +/** + * Pairwise filtering using bit masks. + * + * This filtering method is based on two 16-bit values: + * - The interaction groups (the 16 left-most bits of `self.0`). + * - The interaction mask (the 16 right-most bits of `self.0`). + * + * An interaction is allowed between two filters `a` and `b` two conditions + * are met simultaneously: + * - The interaction groups of `a` has at least one bit set to `1` in common with the interaction mask of `b`. + * - The interaction groups of `b` has at least one bit set to `1` in common with the interaction mask of `a`. + * In other words, interactions are allowed between two filter iff. the following condition is met: + * + * ``` + * ((a >> 16) & b) != 0 && ((b >> 16) & a) != 0 + * ``` + */ +export type InteractionGroups = number; diff --git a/typescript/src.ts/geometry/narrow_phase.ts b/typescript/src.ts/geometry/narrow_phase.ts new file mode 100644 index 000000000..c5d4974cb --- /dev/null +++ b/typescript/src.ts/geometry/narrow_phase.ts @@ -0,0 +1,256 @@ +import {RawNarrowPhase, RawContactManifold} from "../raw"; +import {ColliderHandle} from "./collider"; +import {Vector, VectorOps, scratchBuffer} from "../math"; + +/** + * The narrow-phase used for precise collision-detection. + * + * To avoid leaking WASM resources, this MUST be freed manually with `narrowPhase.free()` + * once you are done using it. + */ +export class NarrowPhase { + raw: RawNarrowPhase; + tempManifold: TempContactManifold; + + /** + * Release the WASM memory occupied by this narrow-phase. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawNarrowPhase) { + this.raw = raw || new RawNarrowPhase(); + this.tempManifold = new TempContactManifold(null); + } + + /** + * Enumerates all the colliders potentially in contact with the given collider. + * + * @param collider1 - The second collider involved in the contact. + * @param f - Closure that will be called on each collider that is in contact with `collider1`. + */ + public contactPairsWith( + collider1: ColliderHandle, + f: (collider2: ColliderHandle) => void, + ) { + this.raw.contact_pairs_with(collider1, f); + } + + /** + * Enumerates all the colliders intersecting the given colliders, assuming one of them + * is a sensor. + */ + public intersectionPairsWith( + collider1: ColliderHandle, + f: (collider2: ColliderHandle) => void, + ) { + this.raw.intersection_pairs_with(collider1, f); + } + + /** + * Iterates through all the contact manifolds between the given pair of colliders. + * + * @param collider1 - The first collider involved in the contact. + * @param collider2 - The second collider involved in the contact. + * @param f - Closure that will be called on each contact manifold between the two colliders. If the second argument + * passed to this closure is `true`, then the contact manifold data is flipped, i.e., methods like `localNormal1` + * actually apply to the `collider2` and fields like `localNormal2` apply to the `collider1`. + */ + public contactPair( + collider1: ColliderHandle, + collider2: ColliderHandle, + f: (manifold: TempContactManifold, flipped: boolean) => void, + ) { + const rawPair = this.raw.contact_pair(collider1, collider2); + + if (!!rawPair) { + const flipped = rawPair.collider1() != collider1; + + let i; + for (i = 0; i < rawPair.numContactManifolds(); ++i) { + this.tempManifold.raw = rawPair.contactManifold(i); + if (!!this.tempManifold.raw) { + f(this.tempManifold, flipped); + } + + // SAFETY: The RawContactManifold stores a raw pointer that will be invalidated + // at the next timestep. So we must be sure to free the pair here + // to avoid unsoundness in the Rust code. + this.tempManifold.free(); + } + rawPair.free(); + } + } + + /** + * Returns `true` if `collider1` and `collider2` intersect and at least one of them is a sensor. + * @param collider1 − The first collider involved in the intersection. + * @param collider2 − The second collider involved in the intersection. + */ + public intersectionPair( + collider1: ColliderHandle, + collider2: ColliderHandle, + ): boolean { + return this.raw.intersection_pair(collider1, collider2); + } +} + +export class TempContactManifold { + raw: RawContactManifold; + + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw: RawContactManifold) { + this.raw = raw; + } + + /** + * The contact normal of the manifold, expressed in world-space. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public normal(target?: Vector): Vector { + this.raw.normal(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The contact normal of the manifold, expressed in the local-space of the first shape. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localNormal1(target?: Vector): Vector { + this.raw.local_n1(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The contact normal of the manifold, expressed in the local-space of the second shape. + * + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localNormal2(target?: Vector): Vector { + this.raw.local_n2(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + public subshape1(): number { + return this.raw.subshape1(); + } + + public subshape2(): number { + return this.raw.subshape2(); + } + + public numContacts(): number { + return this.raw.num_contacts(); + } + + /** + * The local-space contact point on the first shape, for the `i`-th contact. + * + * @param {number} i - The index of the contact to read. + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localContactPoint1(i: number, target?: Vector): Vector | null { + const exists = this.raw.contact_local_p1(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + /** + * The local-space contact point on the second shape, for the `i`-th contact. + * + * @param {number} i - The index of the contact to read. + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public localContactPoint2(i: number, target?: Vector): Vector | null { + const exists = this.raw.contact_local_p2(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + public contactDist(i: number): number { + return this.raw.contact_dist(i); + } + + public contactFid1(i: number): number { + return this.raw.contact_fid1(i); + } + + public contactFid2(i: number): number { + return this.raw.contact_fid2(i); + } + + public contactImpulse(i: number): number { + return this.raw.contact_impulse(i); + } + + // #if DIM2 + public contactTangentImpulse(i: number): number { + return this.raw.contact_tangent_impulse(i); + } + // #endif + + // #if DIM3 + public contactTangentImpulseX(i: number): number { + return this.raw.contact_tangent_impulse_x(i); + } + + public contactTangentImpulseY(i: number): number { + return this.raw.contact_tangent_impulse_y(i); + } + // #endif + + public numSolverContacts(): number { + return this.raw.num_solver_contacts(); + } + + /** + * The world-space position of the `i`-th solver contact point. + * + * @param {number} i - The index of the solver contact to read. + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public solverContactPoint(i: number, target?: Vector): Vector | null { + const exists = this.raw.solver_contact_point(i, scratchBuffer); + return exists ? VectorOps.fromBuffer(scratchBuffer, target) : null; + } + + public solverContactDist(i: number): number { + return this.raw.solver_contact_dist(i); + } + + public solverContactFriction(i: number): number { + return this.raw.solver_contact_friction(i); + } + + public solverContactRestitution(i: number): number { + return this.raw.solver_contact_restitution(i); + } + + /** + * The tangent (surface) velocity of the `i`-th solver contact point. + * + * @param {number} i - The index of the solver contact to read. + * @param {Vector?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + */ + public solverContactTangentVelocity(i: number, target?: Vector): Vector { + this.raw.solver_contact_tangent_velocity(i, scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } +} diff --git a/typescript/src.ts/geometry/point.ts b/typescript/src.ts/geometry/point.ts new file mode 100644 index 000000000..ec1335c13 --- /dev/null +++ b/typescript/src.ts/geometry/point.ts @@ -0,0 +1,117 @@ +import {Collider, ColliderHandle} from "./collider"; +import {Vector, VectorOps, scratchBuffer} from "../math"; +import { + RawFeatureType, + RawPointColliderProjection, + RawPointProjection, +} from "../raw"; +import {FeatureType} from "./feature"; +import {ColliderSet} from "./collider_set"; + +/** + * The projection of a point on a collider. + */ +export class PointProjection { + /** + * The projection of the point on the collider. + */ + point: Vector; + /** + * Is the point inside of the collider? + */ + isInside: boolean; + + constructor(point: Vector, isInside: boolean) { + this.point = point; + this.isInside = isInside; + } + + /** + * @param raw - The raw projection returned by the WASM query. It is freed by this method. + * @param target - If provided, this object is populated and returned instead of + * allocating a new one. + */ + public static fromBuffer( + raw: RawPointProjection, + target?: PointProjection, + ): PointProjection { + if (!raw) return null; + + raw.point(scratchBuffer); + + target ??= new PointProjection(VectorOps.zeros(), false); + target.point = VectorOps.fromBuffer(scratchBuffer, target.point); + target.isInside = raw.isInside(); + + raw.free(); + return target; + } +} + +/** + * The projection of a point on a collider (includes the collider handle). + */ +export class PointColliderProjection { + /** + * The collider hit by the ray. + */ + collider: Collider; + /** + * The projection of the point on the collider. + */ + point: Vector; + /** + * Is the point inside of the collider? + */ + isInside: boolean; + + /** + * The type of the geometric feature the point was projected on. + */ + featureType = FeatureType.Unknown; + + /** + * The id of the geometric feature the point was projected on. + */ + featureId: number | undefined = undefined; + + constructor( + collider: Collider, + point: Vector, + isInside: boolean, + featureType?: FeatureType, + featureId?: number, + ) { + this.collider = collider; + this.point = point; + this.isInside = isInside; + if (featureId !== undefined) this.featureId = featureId; + if (featureType !== undefined) this.featureType = featureType; + } + + /** + * @param colliderSet - The set the projected-on collider belongs to. + * @param raw - The raw projection returned by the WASM query. It is freed by this method. + * @param target - If provided, this object is populated and returned instead of + * allocating a new one. + */ + public static fromBuffer( + colliderSet: ColliderSet, + raw: RawPointColliderProjection, + target?: PointColliderProjection, + ): PointColliderProjection { + if (!raw) return null; + + raw.point(scratchBuffer); + + target ??= new PointColliderProjection(null, VectorOps.zeros(), false); + target.collider = colliderSet.get(raw.colliderHandle()); + target.point = VectorOps.fromBuffer(scratchBuffer, target.point); + target.isInside = raw.isInside(); + target.featureType = raw.featureType() as number as FeatureType; + target.featureId = raw.featureId(); + + raw.free(); + return target; + } +} diff --git a/typescript/src.ts/geometry/ray.ts b/typescript/src.ts/geometry/ray.ts new file mode 100644 index 000000000..cd0356099 --- /dev/null +++ b/typescript/src.ts/geometry/ray.ts @@ -0,0 +1,211 @@ +import {Vector, VectorOps, scratchBuffer} from "../math"; +import { + RawFeatureType, + RawRayColliderIntersection, + RawRayColliderHit, + RawRayIntersection, +} from "../raw"; +import {Collider} from "./collider"; +import {FeatureType} from "./feature"; +import {ColliderSet} from "./collider_set"; + +/** + * A ray. This is a directed half-line. + */ +export class Ray { + /** + * The starting point of the ray. + */ + public origin: Vector; + /** + * The direction of propagation of the ray. + */ + public dir: Vector; + + /** + * Builds a ray from its origin and direction. + * + * @param origin - The ray's starting point. + * @param dir - The ray's direction of propagation. + */ + constructor(origin: Vector, dir: Vector) { + this.origin = origin; + this.dir = dir; + } + + public pointAt(t: number): Vector { + return { + x: this.origin.x + this.dir.x * t, + y: this.origin.y + this.dir.y * t, + // #if DIM3 + z: this.origin.z + this.dir.z * t, + // #endif + }; + } +} + +/** + * The intersection between a ray and a collider. + */ +export class RayIntersection { + /** + * The time-of-impact of the ray with the collider. + * + * The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`. + */ + timeOfImpact: number; + /** + * The normal of the collider at the hit point. + */ + normal: Vector; + + /** + * The type of the geometric feature the point was projected on. + */ + featureType = FeatureType.Unknown; + + /** + * The id of the geometric feature the point was projected on. + */ + featureId: number | undefined = undefined; + + constructor( + timeOfImpact: number, + normal: Vector, + featureType?: FeatureType, + featureId?: number, + ) { + this.timeOfImpact = timeOfImpact; + this.normal = normal; + if (featureId !== undefined) this.featureId = featureId; + if (featureType !== undefined) this.featureType = featureType; + } + + /** + * @param raw - The raw intersection returned by the WASM query. It is freed by this method. + * @param target - If provided, this object is populated and returned instead of + * allocating a new one. + */ + public static fromBuffer( + raw: RawRayIntersection, + target?: RayIntersection, + ): RayIntersection { + if (!raw) return null; + + raw.normal(scratchBuffer); + + target ??= new RayIntersection(0, VectorOps.zeros()); + target.timeOfImpact = raw.time_of_impact(); + target.normal = VectorOps.fromBuffer(scratchBuffer, target.normal); + target.featureType = raw.featureType() as number as FeatureType; + target.featureId = raw.featureId(); + + raw.free(); + return target; + } +} + +/** + * The intersection between a ray and a collider (includes the collider handle). + */ +export class RayColliderIntersection { + /** + * The collider hit by the ray. + */ + collider: Collider; + /** + * The time-of-impact of the ray with the collider. + * + * The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`. + */ + timeOfImpact: number; + /** + * The normal of the collider at the hit point. + */ + normal: Vector; + + /** + * The type of the geometric feature the point was projected on. + */ + featureType = FeatureType.Unknown; + + /** + * The id of the geometric feature the point was projected on. + */ + featureId: number | undefined = undefined; + + constructor( + collider: Collider, + timeOfImpact: number, + normal: Vector, + featureType?: FeatureType, + featureId?: number, + ) { + this.collider = collider; + this.timeOfImpact = timeOfImpact; + this.normal = normal; + if (featureId !== undefined) this.featureId = featureId; + if (featureType !== undefined) this.featureType = featureType; + } + + /** + * @param colliderSet - The set the hit collider belongs to. + * @param raw - The raw intersection returned by the WASM query. It is freed by this method. + * @param target - If provided, this object is populated and returned instead of + * allocating a new one. + */ + public static fromBuffer( + colliderSet: ColliderSet, + raw: RawRayColliderIntersection, + target?: RayColliderIntersection, + ): RayColliderIntersection { + if (!raw) return null; + + raw.normal(scratchBuffer); + + target ??= new RayColliderIntersection(null, 0, VectorOps.zeros()); + target.collider = colliderSet.get(raw.colliderHandle()); + target.timeOfImpact = raw.time_of_impact(); + target.normal = VectorOps.fromBuffer(scratchBuffer, target.normal); + target.featureType = raw.featureType() as number as FeatureType; + target.featureId = raw.featureId(); + + raw.free(); + return target; + } +} + +/** + * The time of impact between a ray and a collider. + */ +export class RayColliderHit { + /** + * The handle of the collider hit by the ray. + */ + collider: Collider; + /** + * The time-of-impact of the ray with the collider. + * + * The hit point is obtained from the ray's origin and direction: `origin + dir * timeOfImpact`. + */ + timeOfImpact: number; + + constructor(collider: Collider, timeOfImpact: number) { + this.collider = collider; + this.timeOfImpact = timeOfImpact; + } + + public static fromRaw( + colliderSet: ColliderSet, + raw: RawRayColliderHit, + ): RayColliderHit { + if (!raw) return null; + + const result = new RayColliderHit( + colliderSet.get(raw.colliderHandle()), + raw.timeOfImpact(), + ); + raw.free(); + return result; + } +} diff --git a/typescript/src.ts/geometry/shape.ts b/typescript/src.ts/geometry/shape.ts new file mode 100644 index 000000000..e74c8e54d --- /dev/null +++ b/typescript/src.ts/geometry/shape.ts @@ -0,0 +1,1932 @@ +import {Vector, VectorOps, Rotation, RotationOps, scratchBuffer} from "../math"; +import {RawColliderSet, RawShape, RawShapeType} from "../raw"; +import {ShapeContact} from "./contact"; +import {PointProjection} from "./point"; +import {Ray, RayIntersection} from "./ray"; +import {ShapeCastHit} from "./toi"; +import {ColliderHandle} from "./collider"; + +export abstract class Shape { + public abstract intoRaw(): RawShape; + + /** + * The concrete type of this shape. + */ + public abstract get type(): ShapeType; + + /** + * instant mode without cache + */ + public static fromRaw( + rawSet: RawColliderSet, + handle: ColliderHandle, + ): Shape { + const rawType = rawSet.coShapeType(handle); + + if (rawType === RawShapeType.Compound) { + return Compound.fromRawShape(rawSet.coShape(handle)); + } + + let borderRadius: number; + let vs: Float32Array; + let indices: Uint32Array; + let halfHeight: number; + let radius: number; + let normal: Vector; + + switch (rawType) { + case RawShapeType.Ball: + return new Ball(rawSet.coRadius(handle)); + case RawShapeType.Cuboid: + rawSet.coHalfExtents(handle, scratchBuffer); + + // #if DIM2 + return new Cuboid(scratchBuffer[0], scratchBuffer[1]); + // #endif + + // #if DIM3 + return new Cuboid( + scratchBuffer[0], + scratchBuffer[1], + scratchBuffer[2], + ); + // #endif + + case RawShapeType.RoundCuboid: + borderRadius = rawSet.coRoundRadius(handle); + rawSet.coHalfExtents(handle, scratchBuffer); + + // #if DIM2 + return new RoundCuboid( + scratchBuffer[0], + scratchBuffer[1], + borderRadius, + ); + // #endif + + // #if DIM3 + return new RoundCuboid( + scratchBuffer[0], + scratchBuffer[1], + scratchBuffer[2], + borderRadius, + ); + // #endif + + case RawShapeType.Capsule: + halfHeight = rawSet.coHalfHeight(handle); + radius = rawSet.coRadius(handle); + return new Capsule(halfHeight, radius); + case RawShapeType.Segment: + vs = rawSet.coVertices(handle); + + // #if DIM2 + return new Segment( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + ); + // #endif + + // #if DIM3 + return new Segment( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + ); + // #endif + + case RawShapeType.Polyline: + vs = rawSet.coVertices(handle); + indices = rawSet.coIndices(handle); + return new Polyline(vs, indices); + case RawShapeType.Triangle: + vs = rawSet.coVertices(handle); + + // #if DIM2 + return new Triangle( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + VectorOps.new(vs[4], vs[5]), + ); + // #endif + + // #if DIM3 + return new Triangle( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + VectorOps.new(vs[6], vs[7], vs[8]), + ); + // #endif + + case RawShapeType.RoundTriangle: + vs = rawSet.coVertices(handle); + borderRadius = rawSet.coRoundRadius(handle); + + // #if DIM2 + return new RoundTriangle( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + VectorOps.new(vs[4], vs[5]), + borderRadius, + ); + // #endif + + // #if DIM3 + return new RoundTriangle( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + VectorOps.new(vs[6], vs[7], vs[8]), + borderRadius, + ); + // #endif + + case RawShapeType.HalfSpace: + rawSet.coHalfspaceNormal(handle, scratchBuffer); + normal = VectorOps.fromBuffer(scratchBuffer); + return new HalfSpace(normal); + + case RawShapeType.Voxels: + const vox_data = rawSet.coVoxelData(handle); + const vox_size = rawSet.coVoxelSize(handle); + return new Voxels(vox_data, vox_size); + + case RawShapeType.TriMesh: + vs = rawSet.coVertices(handle); + indices = rawSet.coIndices(handle); + const tri_flags = rawSet.coTriMeshFlags(handle); + return new TriMesh(vs, indices, tri_flags); + + case RawShapeType.HeightField: + const heights = rawSet.coHeightfieldHeights(handle); + rawSet.coHeightfieldScale(handle, scratchBuffer); + + // #if DIM2 + const scale = { + x: scratchBuffer[0], + y: scratchBuffer[1], + }; + return new Heightfield(heights, scale); + // #endif + + // #if DIM3 + const scale = { + x: scratchBuffer[0], + y: scratchBuffer[1], + z: scratchBuffer[2], + }; + const nrows = rawSet.coHeightfieldNRows(handle); + const ncols = rawSet.coHeightfieldNCols(handle); + const hf_flags = rawSet.coHeightFieldFlags(handle); + return new Heightfield(nrows, ncols, heights, scale, hf_flags); + // #endif + + // #if DIM2 + case RawShapeType.ConvexPolygon: + vs = rawSet.coVertices(handle); + return new ConvexPolygon(vs, false); + case RawShapeType.RoundConvexPolygon: + vs = rawSet.coVertices(handle); + borderRadius = rawSet.coRoundRadius(handle); + return new RoundConvexPolygon(vs, borderRadius, false); + // #endif + + // #if DIM3 + case RawShapeType.ConvexPolyhedron: + vs = rawSet.coVertices(handle); + indices = rawSet.coIndices(handle); + return new ConvexPolyhedron(vs, indices); + case RawShapeType.RoundConvexPolyhedron: + vs = rawSet.coVertices(handle); + indices = rawSet.coIndices(handle); + borderRadius = rawSet.coRoundRadius(handle); + return new RoundConvexPolyhedron(vs, indices, borderRadius); + case RawShapeType.Cylinder: + halfHeight = rawSet.coHalfHeight(handle); + radius = rawSet.coRadius(handle); + return new Cylinder(halfHeight, radius); + case RawShapeType.RoundCylinder: + halfHeight = rawSet.coHalfHeight(handle); + radius = rawSet.coRadius(handle); + borderRadius = rawSet.coRoundRadius(handle); + return new RoundCylinder(halfHeight, radius, borderRadius); + case RawShapeType.Cone: + halfHeight = rawSet.coHalfHeight(handle); + radius = rawSet.coRadius(handle); + return new Cone(halfHeight, radius); + case RawShapeType.RoundCone: + halfHeight = rawSet.coHalfHeight(handle); + radius = rawSet.coRadius(handle); + borderRadius = rawSet.coRoundRadius(handle); + return new RoundCone(halfHeight, radius, borderRadius); + // #endif + + default: + throw new Error("unknown shape type: " + rawType); + } + } + + public static fromRawShape(rawShape: RawShape): Shape { + if (!rawShape) return null; + + let extents: Vector; + let borderRadius: number; + let vs: Float32Array; + let indices: Uint32Array; + let halfHeight: number; + let radius: number; + let normal: Vector; + const rawType = rawShape.shapeType(); + + try { + switch (rawType) { + case RawShapeType.Ball: + return new Ball(rawShape.radius()); + case RawShapeType.Cuboid: + extents = VectorOps.fromRaw(rawShape.halfExtents()); + // #if DIM2 + return new Cuboid(extents.x, extents.y); + // #endif + + // #if DIM3 + return new Cuboid(extents.x, extents.y, extents.z); + // #endif + + case RawShapeType.RoundCuboid: + extents = VectorOps.fromRaw(rawShape.halfExtents()); + borderRadius = rawShape.roundRadius(); + + // #if DIM2 + return new RoundCuboid(extents.x, extents.y, borderRadius); + // #endif + + // #if DIM3 + return new RoundCuboid( + extents.x, + extents.y, + extents.z, + borderRadius, + ); + // #endif + + case RawShapeType.Capsule: + halfHeight = rawShape.halfHeight(); + radius = rawShape.radius(); + return new Capsule(halfHeight, radius); + case RawShapeType.Segment: + vs = rawShape.vertices(); + + // #if DIM2 + return new Segment( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + ); + // #endif + + // #if DIM3 + return new Segment( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + ); + // #endif + + case RawShapeType.Polyline: + vs = rawShape.vertices(); + indices = rawShape.indices(); + return new Polyline(vs, indices); + case RawShapeType.Triangle: + vs = rawShape.vertices(); + + // #if DIM2 + return new Triangle( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + VectorOps.new(vs[4], vs[5]), + ); + // #endif + + // #if DIM3 + return new Triangle( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + VectorOps.new(vs[6], vs[7], vs[8]), + ); + // #endif + + case RawShapeType.RoundTriangle: + vs = rawShape.vertices(); + borderRadius = rawShape.roundRadius(); + + // #if DIM2 + return new RoundTriangle( + VectorOps.new(vs[0], vs[1]), + VectorOps.new(vs[2], vs[3]), + VectorOps.new(vs[4], vs[5]), + borderRadius, + ); + // #endif + + // #if DIM3 + return new RoundTriangle( + VectorOps.new(vs[0], vs[1], vs[2]), + VectorOps.new(vs[3], vs[4], vs[5]), + VectorOps.new(vs[6], vs[7], vs[8]), + borderRadius, + ); + // #endif + + case RawShapeType.HalfSpace: + normal = VectorOps.fromRaw(rawShape.halfspaceNormal()); + return new HalfSpace(normal); + + case RawShapeType.Voxels: + const vox_data = rawShape.voxelData(); + const vox_size = VectorOps.fromRaw(rawShape.voxelSize()); + return new Voxels(vox_data, vox_size); + + case RawShapeType.TriMesh: + vs = rawShape.vertices(); + indices = rawShape.indices(); + const tri_flags = rawShape.triMeshFlags(); + return new TriMesh(vs, indices, tri_flags); + + case RawShapeType.HeightField: + const scale = VectorOps.fromRaw( + rawShape.heightfieldScale(), + ); + const heights = rawShape.heightfieldHeights(); + + // #if DIM2 + return new Heightfield(heights, scale); + // #endif + + // #if DIM3 + const nrows = rawShape.heightfieldNRows(); + const ncols = rawShape.heightfieldNCols(); + const hf_flags = rawShape.heightFieldFlags(); + return new Heightfield( + nrows, + ncols, + heights, + scale, + hf_flags, + ); + // #endif + + // #if DIM2 + case RawShapeType.ConvexPolygon: + vs = rawShape.vertices(); + return new ConvexPolygon(vs, false); + case RawShapeType.RoundConvexPolygon: + vs = rawShape.vertices(); + borderRadius = rawShape.roundRadius(); + return new RoundConvexPolygon(vs, borderRadius, false); + // #endif + + // #if DIM3 + case RawShapeType.ConvexPolyhedron: { + const mesh = rawShape.convexMeshData(); + if (!mesh) { + throw new Error( + "Failed to compute the convex hull of a convex polyhedron shape.", + ); + } + vs = mesh.vertices; + indices = mesh.indices; + mesh.free(); + return new ConvexPolyhedron(vs, indices); + } + case RawShapeType.RoundConvexPolyhedron: { + const mesh = rawShape.convexMeshData(); + if (!mesh) { + throw new Error( + "Failed to compute the convex hull of a convex polyhedron shape.", + ); + } + vs = mesh.vertices; + indices = mesh.indices; + mesh.free(); + borderRadius = rawShape.roundRadius(); + return new RoundConvexPolyhedron(vs, indices, borderRadius); + } + case RawShapeType.Cylinder: + halfHeight = rawShape.halfHeight(); + radius = rawShape.radius(); + return new Cylinder(halfHeight, radius); + case RawShapeType.RoundCylinder: + halfHeight = rawShape.halfHeight(); + radius = rawShape.radius(); + borderRadius = rawShape.roundRadius(); + return new RoundCylinder(halfHeight, radius, borderRadius); + case RawShapeType.Cone: + halfHeight = rawShape.halfHeight(); + radius = rawShape.radius(); + return new Cone(halfHeight, radius); + case RawShapeType.RoundCone: + halfHeight = rawShape.halfHeight(); + radius = rawShape.radius(); + borderRadius = rawShape.roundRadius(); + return new RoundCone(halfHeight, radius, borderRadius); + // #endif + + case RawShapeType.Compound: + return Compound.fromRawShape(rawShape); + default: + throw new Error("unknown shape type: " + rawType); + } + } finally { + if (rawType !== RawShapeType.Compound) { + rawShape.free(); + } + } + } + + /** + * Computes the time of impact between two moving shapes. + * @param shapePos1 - The initial position of this shape. + * @param shapeRot1 - The rotation of this shape. + * @param shapeVel1 - The velocity of this shape. + * @param shape2 - The second moving shape. + * @param shapePos2 - The initial position of the second shape. + * @param shapeRot2 - The rotation of the second shape. + * @param shapeVel2 - The velocity of the second shape. + * @param targetDistance − If the shape moves closer to this distance from a collider, a hit + * will be returned. + * @param maxToi - The maximum time when the impact can happen. + * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if + * the shape is penetrating another shape at its starting point **and** its trajectory is such + * that it’s on a path to exit that penetration state. + * @param {ShapeCastHit?} target - The object to be populated. If provided, + * the function returns this object instead of creating a new one. + * @returns If the two moving shapes collider at some point along their trajectories, this returns the + * time at which the two shape collider as well as the contact information during the impact. Returns + * `null` if the two shapes never collide along their paths. + */ + public castShape( + shapePos1: Vector, + shapeRot1: Rotation, + shapeVel1: Vector, + shape2: Shape, + shapePos2: Vector, + shapeRot2: Rotation, + shapeVel2: Vector, + targetDistance: number, + maxToi: number, + stopAtPenetration: boolean, + target?: ShapeCastHit, + ): ShapeCastHit | null { + let rawPos1 = VectorOps.intoRaw(shapePos1); + let rawRot1 = RotationOps.intoRaw(shapeRot1); + let rawVel1 = VectorOps.intoRaw(shapeVel1); + let rawPos2 = VectorOps.intoRaw(shapePos2); + let rawRot2 = RotationOps.intoRaw(shapeRot2); + let rawVel2 = VectorOps.intoRaw(shapeVel2); + + let rawShape1 = this.intoRaw(); + let rawShape2 = shape2.intoRaw(); + + const rawShapeCastHit = rawShape1.castShape( + rawPos1, + rawRot1, + rawVel1, + rawShape2, + rawPos2, + rawRot2, + rawVel2, + targetDistance, + maxToi, + stopAtPenetration, + ); + + let result = null; + if (rawShapeCastHit) { + rawShapeCastHit.getComponents(scratchBuffer); + result = ShapeCastHit.fromBuffer(null, scratchBuffer, target); + rawShapeCastHit.free(); + } + + rawPos1.free(); + rawRot1.free(); + rawVel1.free(); + rawPos2.free(); + rawRot2.free(); + rawVel2.free(); + + rawShape1.free(); + rawShape2.free(); + + return result; + } + + /** + * Tests if this shape intersects another shape. + * + * @param shapePos1 - The position of this shape. + * @param shapeRot1 - The rotation of this shape. + * @param shape2 - The second shape to test. + * @param shapePos2 - The position of the second shape. + * @param shapeRot2 - The rotation of the second shape. + * @returns `true` if the two shapes intersect, `false` if they don’t. + */ + public intersectsShape( + shapePos1: Vector, + shapeRot1: Rotation, + shape2: Shape, + shapePos2: Vector, + shapeRot2: Rotation, + ): boolean { + let rawPos1 = VectorOps.intoRaw(shapePos1); + let rawRot1 = RotationOps.intoRaw(shapeRot1); + let rawPos2 = VectorOps.intoRaw(shapePos2); + let rawRot2 = RotationOps.intoRaw(shapeRot2); + + let rawShape1 = this.intoRaw(); + let rawShape2 = shape2.intoRaw(); + + let result = rawShape1.intersectsShape( + rawPos1, + rawRot1, + rawShape2, + rawPos2, + rawRot2, + ); + + rawPos1.free(); + rawRot1.free(); + rawPos2.free(); + rawRot2.free(); + + rawShape1.free(); + rawShape2.free(); + + return result; + } + + /** + * Computes one pair of contact points between two shapes. + * + * @param shapePos1 - The initial position of this sahpe. + * @param shapeRot1 - The rotation of this shape. + * @param shape2 - The second shape. + * @param shapePos2 - The initial position of the second shape. + * @param shapeRot2 - The rotation of the second shape. + * @param prediction - The prediction value, if the shapes are separated by a distance greater than this value, test will fail. + * @returns `null` if the shapes are separated by a distance greater than prediction, otherwise contact details. The result is given in world-space. + */ + contactShape( + shapePos1: Vector, + shapeRot1: Rotation, + shape2: Shape, + shapePos2: Vector, + shapeRot2: Rotation, + prediction: number, + target?: ShapeContact, + ): ShapeContact | null { + let rawPos1 = VectorOps.intoRaw(shapePos1); + let rawRot1 = RotationOps.intoRaw(shapeRot1); + let rawPos2 = VectorOps.intoRaw(shapePos2); + let rawRot2 = RotationOps.intoRaw(shapeRot2); + + let rawShape1 = this.intoRaw(); + let rawShape2 = shape2.intoRaw(); + + let result = ShapeContact.fromBuffer( + rawShape1.contactShape( + rawPos1, + rawRot1, + rawShape2, + rawPos2, + rawRot2, + prediction, + ), + target, + ); + + rawPos1.free(); + rawRot1.free(); + rawPos2.free(); + rawRot2.free(); + + rawShape1.free(); + rawShape2.free(); + + return result; + } + + containsPoint( + shapePos: Vector, + shapeRot: Rotation, + point: Vector, + ): boolean { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawPoint = VectorOps.intoRaw(point); + let rawShape = this.intoRaw(); + + let result = rawShape.containsPoint(rawPos, rawRot, rawPoint); + + rawPos.free(); + rawRot.free(); + rawPoint.free(); + rawShape.free(); + + return result; + } + + projectPoint( + shapePos: Vector, + shapeRot: Rotation, + point: Vector, + solid: boolean, + target?: PointProjection, + ): PointProjection { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawPoint = VectorOps.intoRaw(point); + let rawShape = this.intoRaw(); + + let result = PointProjection.fromBuffer( + rawShape.projectPoint(rawPos, rawRot, rawPoint, solid), + target, + ); + + rawPos.free(); + rawRot.free(); + rawPoint.free(); + rawShape.free(); + + return result; + } + + intersectsRay( + ray: Ray, + shapePos: Vector, + shapeRot: Rotation, + maxToi: number, + ): boolean { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawRayOrig = VectorOps.intoRaw(ray.origin); + let rawRayDir = VectorOps.intoRaw(ray.dir); + let rawShape = this.intoRaw(); + + let result = rawShape.intersectsRay( + rawPos, + rawRot, + rawRayOrig, + rawRayDir, + maxToi, + ); + + rawPos.free(); + rawRot.free(); + rawRayOrig.free(); + rawRayDir.free(); + rawShape.free(); + + return result; + } + + castRay( + ray: Ray, + shapePos: Vector, + shapeRot: Rotation, + maxToi: number, + solid: boolean, + ): number { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawRayOrig = VectorOps.intoRaw(ray.origin); + let rawRayDir = VectorOps.intoRaw(ray.dir); + let rawShape = this.intoRaw(); + + let result = rawShape.castRay( + rawPos, + rawRot, + rawRayOrig, + rawRayDir, + maxToi, + solid, + ); + + rawPos.free(); + rawRot.free(); + rawRayOrig.free(); + rawRayDir.free(); + rawShape.free(); + + return result; + } + + castRayAndGetNormal( + ray: Ray, + shapePos: Vector, + shapeRot: Rotation, + maxToi: number, + solid: boolean, + target?: RayIntersection, + ): RayIntersection { + let rawPos = VectorOps.intoRaw(shapePos); + let rawRot = RotationOps.intoRaw(shapeRot); + let rawRayOrig = VectorOps.intoRaw(ray.origin); + let rawRayDir = VectorOps.intoRaw(ray.dir); + let rawShape = this.intoRaw(); + + let result = RayIntersection.fromBuffer( + rawShape.castRayAndGetNormal( + rawPos, + rawRot, + rawRayOrig, + rawRayDir, + maxToi, + solid, + ), + target, + ); + + rawPos.free(); + rawRot.free(); + rawRayOrig.free(); + rawRayDir.free(); + rawShape.free(); + + return result; + } +} + +// #if DIM2 +/** + * An enumeration representing the type of a shape. + */ +export enum ShapeType { + Ball = 0, + Cuboid = 1, + Capsule = 2, + Segment = 3, + Polyline = 4, + Triangle = 5, + TriMesh = 6, + HeightField = 7, + Compound = 8, + ConvexPolygon = 9, + RoundCuboid = 10, + RoundTriangle = 11, + RoundConvexPolygon = 12, + HalfSpace = 13, + Voxels = 14, +} + +// #endif + +// #if DIM3 + +/** + * An enumeration representing the type of a shape. + */ +export enum ShapeType { + Ball = 0, + Cuboid = 1, + Capsule = 2, + Segment = 3, + Polyline = 4, + Triangle = 5, + TriMesh = 6, + HeightField = 7, + Compound = 8, + ConvexPolyhedron = 9, + Cylinder = 10, + Cone = 11, + RoundCuboid = 12, + RoundTriangle = 13, + RoundCylinder = 14, + RoundCone = 15, + RoundConvexPolyhedron = 16, + HalfSpace = 17, + Voxels = 18, +} + +// NOTE: this **must** match the bits in the HeightFieldFlags on the rust side. +/** + * Flags controlling the behavior of some operations involving heightfields. + */ +export enum HeightFieldFlags { + /** + * If set, a special treatment will be applied to contact manifold calculation to eliminate + * or fix contacts normals that could lead to incorrect bumps in physics simulation (especially + * on flat surfaces). + * + * This is achieved by taking into account adjacent triangle normals when computing contact + * points for a given triangle. + */ + FIX_INTERNAL_EDGES = 0b0000_0001, +} + +// #endif + +// NOTE: this **must** match the TriMeshFlags on the rust side. +/** + * Flags controlling the behavior of the triangle mesh creation and of some + * operations involving triangle meshes. + */ +export enum TriMeshFlags { + // NOTE: these two flags are not really useful in JS. + // + // /** + // * If set, the half-edge topology of the trimesh will be computed if possible. + // */ + // HALF_EDGE_TOPOLOGY = 0b0000_0001, + // /** If set, the half-edge topology and connected components of the trimesh will be computed if possible. + // * + // * Because of the way it is currently implemented, connected components can only be computed on + // * a mesh where the half-edge topology computation succeeds. It will no longer be the case in the + // * future once we decouple the computations. + // */ + // CONNECTED_COMPONENTS = 0b0000_0010, + /** + * If set, any triangle that results in a failing half-hedge topology computation will be deleted. + */ + DELETE_BAD_TOPOLOGY_TRIANGLES = 0b0000_0100, + /** + * If set, the trimesh will be assumed to be oriented (with outward normals). + * + * The pseudo-normals of its vertices and edges will be computed. + */ + ORIENTED = 0b0000_1000, + /** + * If set, the duplicate vertices of the trimesh will be merged. + * + * Two vertices with the exact same coordinates will share the same entry on the + * vertex buffer and the index buffer is adjusted accordingly. + */ + MERGE_DUPLICATE_VERTICES = 0b0001_0000, + /** + * If set, the triangles sharing two vertices with identical index values will be removed. + * + * Because of the way it is currently implemented, this methods implies that duplicate + * vertices will be merged. It will no longer be the case in the future once we decouple + * the computations. + */ + DELETE_DEGENERATE_TRIANGLES = 0b0010_0000, + /** + * If set, two triangles sharing three vertices with identical index values (in any order) + * will be removed. + * + * Because of the way it is currently implemented, this methods implies that duplicate + * vertices will be merged. It will no longer be the case in the future once we decouple + * the computations. + */ + DELETE_DUPLICATE_TRIANGLES = 0b0100_0000, + /** + * If set, a special treatment will be applied to contact manifold calculation to eliminate + * or fix contacts normals that could lead to incorrect bumps in physics simulation + * (especially on flat surfaces). + * + * This is achieved by taking into account adjacent triangle normals when computing contact + * points for a given triangle. + * + * /!\ NOT SUPPORTED IN THE 2D VERSION OF RAPIER. + */ + FIX_INTERNAL_EDGES = 0b1000_0000 | TriMeshFlags.MERGE_DUPLICATE_VERTICES, +} + +/** + * A shape that is a sphere in 3D and a circle in 2D. + */ +export class Ball extends Shape { + readonly type = ShapeType.Ball; + + /** + * The balls radius. + */ + radius: number; + + /** + * Creates a new ball with the given radius. + * @param radius - The balls radius. + */ + constructor(radius: number) { + super(); + this.radius = radius; + } + + public intoRaw(): RawShape { + return RawShape.ball(this.radius); + } +} + +export class HalfSpace extends Shape { + readonly type = ShapeType.HalfSpace; + + /** + * The outward normal of the half-space. + */ + normal: Vector; + + /** + * Creates a new halfspace delimited by an infinite plane. + * + * @param normal - The outward normal of the plane. + */ + constructor(normal: Vector) { + super(); + this.normal = normal; + } + + public intoRaw(): RawShape { + let n = VectorOps.intoRaw(this.normal); + let result = RawShape.halfspace(n); + n.free(); + return result; + } +} + +/** + * A shape that is a box in 3D and a rectangle in 2D. + */ +export class Cuboid extends Shape { + readonly type = ShapeType.Cuboid; + + /** + * The half extent of the cuboid along each coordinate axis. + */ + halfExtents: Vector; + + // #if DIM2 + /** + * Creates a new 2D rectangle. + * @param hx - The half width of the rectangle. + * @param hy - The helf height of the rectangle. + */ + constructor(hx: number, hy: number) { + super(); + this.halfExtents = VectorOps.new(hx, hy); + } + + // #endif + + // #if DIM3 + /** + * Creates a new 3D cuboid. + * @param hx - The half width of the cuboid. + * @param hy - The half height of the cuboid. + * @param hz - The half depth of the cuboid. + */ + constructor(hx: number, hy: number, hz: number) { + super(); + this.halfExtents = VectorOps.new(hx, hy, hz); + } + + // #endif + + public intoRaw(): RawShape { + // #if DIM2 + return RawShape.cuboid(this.halfExtents.x, this.halfExtents.y); + // #endif + + // #if DIM3 + return RawShape.cuboid( + this.halfExtents.x, + this.halfExtents.y, + this.halfExtents.z, + ); + // #endif + } +} + +/** + * A shape that is a box in 3D and a rectangle in 2D, with round corners. + */ +export class RoundCuboid extends Shape { + readonly type = ShapeType.RoundCuboid; + + /** + * The half extent of the cuboid along each coordinate axis. + */ + halfExtents: Vector; + + /** + * The radius of the cuboid's round border. + */ + borderRadius: number; + + // #if DIM2 + /** + * Creates a new 2D rectangle. + * @param hx - The half width of the rectangle. + * @param hy - The helf height of the rectangle. + * @param borderRadius - The radius of the borders of this cuboid. This will + * effectively increase the half-extents of the cuboid by this radius. + */ + constructor(hx: number, hy: number, borderRadius: number) { + super(); + this.halfExtents = VectorOps.new(hx, hy); + this.borderRadius = borderRadius; + } + + // #endif + + // #if DIM3 + /** + * Creates a new 3D cuboid. + * @param hx - The half width of the cuboid. + * @param hy - The half height of the cuboid. + * @param hz - The half depth of the cuboid. + * @param borderRadius - The radius of the borders of this cuboid. This will + * effectively increase the half-extents of the cuboid by this radius. + */ + constructor(hx: number, hy: number, hz: number, borderRadius: number) { + super(); + this.halfExtents = VectorOps.new(hx, hy, hz); + this.borderRadius = borderRadius; + } + + // #endif + + public intoRaw(): RawShape { + // #if DIM2 + return RawShape.roundCuboid( + this.halfExtents.x, + this.halfExtents.y, + this.borderRadius, + ); + // #endif + + // #if DIM3 + return RawShape.roundCuboid( + this.halfExtents.x, + this.halfExtents.y, + this.halfExtents.z, + this.borderRadius, + ); + // #endif + } +} + +/** + * A shape that is a capsule. + */ +export class Capsule extends Shape { + readonly type = ShapeType.Capsule; + + /** + * The radius of the capsule's basis. + */ + radius: number; + + /** + * The capsule's half height, along the `y` axis. + */ + halfHeight: number; + + /** + * Creates a new capsule with the given radius and half-height. + * @param halfHeight - The balls half-height along the `y` axis. + * @param radius - The balls radius. + */ + constructor(halfHeight: number, radius: number) { + super(); + this.halfHeight = halfHeight; + this.radius = radius; + } + + public intoRaw(): RawShape { + return RawShape.capsule(this.halfHeight, this.radius); + } +} + +/** + * A shape that is a segment. + */ +export class Segment extends Shape { + readonly type = ShapeType.Segment; + + /** + * The first point of the segment. + */ + a: Vector; + + /** + * The second point of the segment. + */ + b: Vector; + + /** + * Creates a new segment shape. + * @param a - The first point of the segment. + * @param b - The second point of the segment. + */ + constructor(a: Vector, b: Vector) { + super(); + this.a = a; + this.b = b; + } + + public intoRaw(): RawShape { + let ra = VectorOps.intoRaw(this.a); + let rb = VectorOps.intoRaw(this.b); + let result = RawShape.segment(ra, rb); + ra.free(); + rb.free(); + return result; + } +} + +/** + * A shape that is a segment. + */ +export class Triangle extends Shape { + readonly type = ShapeType.Triangle; + + /** + * The first point of the triangle. + */ + a: Vector; + + /** + * The second point of the triangle. + */ + b: Vector; + + /** + * The second point of the triangle. + */ + c: Vector; + + /** + * Creates a new triangle shape. + * + * @param a - The first point of the triangle. + * @param b - The second point of the triangle. + * @param c - The third point of the triangle. + */ + constructor(a: Vector, b: Vector, c: Vector) { + super(); + this.a = a; + this.b = b; + this.c = c; + } + + public intoRaw(): RawShape { + let ra = VectorOps.intoRaw(this.a); + let rb = VectorOps.intoRaw(this.b); + let rc = VectorOps.intoRaw(this.c); + let result = RawShape.triangle(ra, rb, rc); + ra.free(); + rb.free(); + rc.free(); + return result; + } +} + +/** + * A shape that is a triangle with round borders and a non-zero thickness. + */ +export class RoundTriangle extends Shape { + readonly type = ShapeType.RoundTriangle; + + /** + * The first point of the triangle. + */ + a: Vector; + + /** + * The second point of the triangle. + */ + b: Vector; + + /** + * The second point of the triangle. + */ + c: Vector; + + /** + * The radius of the triangles's rounded edges and vertices. + * In 3D, this is also equal to half the thickness of the round triangle. + */ + borderRadius: number; + + /** + * Creates a new triangle shape with round corners. + * + * @param a - The first point of the triangle. + * @param b - The second point of the triangle. + * @param c - The third point of the triangle. + * @param borderRadius - The radius of the borders of this triangle. In 3D, + * this is also equal to half the thickness of the triangle. + */ + constructor(a: Vector, b: Vector, c: Vector, borderRadius: number) { + super(); + this.a = a; + this.b = b; + this.c = c; + this.borderRadius = borderRadius; + } + + public intoRaw(): RawShape { + let ra = VectorOps.intoRaw(this.a); + let rb = VectorOps.intoRaw(this.b); + let rc = VectorOps.intoRaw(this.c); + let result = RawShape.roundTriangle(ra, rb, rc, this.borderRadius); + ra.free(); + rb.free(); + rc.free(); + return result; + } +} + +/** + * A shape that is a triangle mesh. + */ +export class Polyline extends Shape { + readonly type = ShapeType.Polyline; + + /** + * The vertices of the polyline. + */ + vertices: Float32Array; + + /** + * The indices of the segments. + */ + indices: Uint32Array; + + /** + * Creates a new polyline shape. + * + * @param vertices - The coordinates of the polyline's vertices. + * @param indices - The indices of the polyline's segments. If this is `null` or not provided, then + * the vertices are assumed to form a line strip. + */ + constructor(vertices: Float32Array, indices?: Uint32Array) { + super(); + this.vertices = vertices; + this.indices = indices ?? new Uint32Array(0); + } + + public intoRaw(): RawShape { + return RawShape.polyline(this.vertices, this.indices); + } +} + +/** + * A shape made of voxels. + */ +export class Voxels extends Shape { + readonly type = ShapeType.Voxels; + + /** + * The points or grid coordinates used to initialize the voxels. + */ + data: Float32Array | Int32Array; + + /** + * The dimensions of each voxel. + */ + voxelSize: Vector; + + /** + * Creates a new shape made of voxels. + * + * @param data - Defines the set of voxels. If this is a `Int32Array` then + * each voxel is defined from its (signed) grid coordinates, + * with 3 (resp 2) contiguous integers per voxel in 3D (resp 2D). + * If this is a `Float32Array`, each voxel will be such that + * they contain at least one point from this array (where each + * point is defined from 3 (resp 2) contiguous numbers per point + * in 3D (resp 2D). + * @param voxelSize - The size of each voxel. + */ + constructor(data: Float32Array | Int32Array, voxelSize: Vector) { + super(); + this.data = data; + this.voxelSize = voxelSize; + } + + public intoRaw(): RawShape { + let voxelSize = VectorOps.intoRaw(this.voxelSize); + + let result; + if (this.data instanceof Int32Array) { + result = RawShape.voxels(voxelSize, this.data); + } else { + result = RawShape.voxelsFromPoints(voxelSize, this.data); + } + + voxelSize.free(); + return result; + } +} + +/** + * A compound shape, consisting of multiple sub-shapes with relative positions. + */ +export class Compound extends Shape { + readonly type = ShapeType.Compound; + + /** + * The shapes composing this compound shape. + */ + shapes: Shape[]; + + /** + * The positions of each sub-shape relative to the compound's origin. + */ + positions: Vector[]; + + /** + * The rotations of each sub-shape relative to the compound's orientation. + */ + rotations: Rotation[]; + + /** + * Creates a new compound shape. + * + * @param shapes - The array of shapes composing this compound. Must not be empty, + * and must not contain other compound shapes (nested compound shapes + * are not allowed). + * @param positions - The array of positions for each shape. + * @param rotations - The array of rotations for each shape. + */ + constructor(shapes: Shape[], positions: Vector[], rotations: Rotation[]) { + super(); + + if ( + shapes.length !== positions.length || + shapes.length !== rotations.length + ) { + throw new Error( + "shapes, positions, and rotations arrays must have the same length", + ); + } + + if (shapes.length === 0) { + throw new Error("a compound shape must contain at least one shape"); + } + + if (shapes.some((shape) => shape.type === ShapeType.Compound)) { + throw new Error("nested compound shapes are not allowed"); + } + + this.shapes = shapes; + this.positions = positions; + this.rotations = rotations; + } + + /** + * Reconstructs a compound shape from its raw representation. + * + * This takes ownership of `rawShape` and always frees it before returning. + */ + public static fromRawShape(rawShape: RawShape): Compound { + try { + const numShapes = rawShape.compoundLen(); + if (numShapes == null) { + throw new Error("Expected a raw compound shape."); + } + + const shapes = new Array(numShapes); + const positions = new Array(numShapes); + const rotations = new Array(numShapes); + + for (let i = 0; i < numShapes; i++) { + shapes[i] = Shape.fromRawShape(rawShape.compoundShape(i)); + positions[i] = VectorOps.fromRaw( + rawShape.compoundTranslation(i), + ); + rotations[i] = RotationOps.fromRaw( + rawShape.compoundRotation(i), + ); + } + + return new Compound(shapes, positions, rotations); + } finally { + rawShape.free(); + } + } + + public intoRaw(): RawShape { + const rawShapes = this.shapes.map((s) => s.intoRaw()); + + // #if DIM2 + const positions = new Float32Array(this.positions.length * 2); + this.positions.forEach((pos, i) => { + positions[i * 2] = pos.x; + positions[i * 2 + 1] = pos.y; + }); + + const rotations = new Float32Array(this.rotations.length); + this.rotations.forEach((rot, i) => { + rotations[i] = rot; + }); + // #endif + + // #if DIM3 + const positions = new Float32Array(this.positions.length * 3); + this.positions.forEach((pos, i) => { + positions[i * 3] = pos.x; + positions[i * 3 + 1] = pos.y; + positions[i * 3 + 2] = pos.z; + }); + + const rotations = new Float32Array(this.rotations.length * 4); + this.rotations.forEach((rot, i) => { + rotations[i * 4] = rot.x; + rotations[i * 4 + 1] = rot.y; + rotations[i * 4 + 2] = rot.z; + rotations[i * 4 + 3] = rot.w; + }); + // #endif + + return RawShape.compound(rawShapes, positions, rotations); + } +} + +/** + * A shape that is a triangle mesh. + */ +export class TriMesh extends Shape { + readonly type = ShapeType.TriMesh; + + /** + * The vertices of the triangle mesh. + */ + vertices: Float32Array; + + /** + * The indices of the triangles. + */ + indices: Uint32Array; + + /** + * The triangle mesh flags. + */ + flags: TriMeshFlags; + + /** + * Creates a new triangle mesh shape. + * + * @param vertices - The coordinates of the triangle mesh's vertices. + * @param indices - The indices of the triangle mesh's triangles. + */ + constructor( + vertices: Float32Array, + indices: Uint32Array, + flags?: TriMeshFlags, + ) { + super(); + this.vertices = vertices; + this.indices = indices; + this.flags = flags; + } + + public intoRaw(): RawShape { + return RawShape.trimesh(this.vertices, this.indices, this.flags); + } +} + +// #if DIM2 +/** + * A shape that is a convex polygon. + */ +export class ConvexPolygon extends Shape { + readonly type = ShapeType.ConvexPolygon; + + /** + * The vertices of the convex polygon. + */ + vertices: Float32Array; + + /** + * Do we want to assume the vertices already form a convex hull? + */ + skipConvexHullComputation: boolean; + + /** + * Creates a new convex polygon shape. + * + * @param vertices - The coordinates of the convex polygon's vertices. + * @param skipConvexHullComputation - If set to `true`, the input points will + * be assumed to form a convex polyline and no convex-hull computation will + * be done automatically. + */ + constructor(vertices: Float32Array, skipConvexHullComputation: boolean) { + super(); + this.vertices = vertices; + this.skipConvexHullComputation = !!skipConvexHullComputation; + } + + public intoRaw(): RawShape { + if (this.skipConvexHullComputation) { + return RawShape.convexPolyline(this.vertices); + } else { + return RawShape.convexHull(this.vertices); + } + } +} + +/** + * A shape that is a convex polygon. + */ +export class RoundConvexPolygon extends Shape { + readonly type = ShapeType.RoundConvexPolygon; + + /** + * The vertices of the convex polygon. + */ + vertices: Float32Array; + + /** + * Do we want to assume the vertices already form a convex hull? + */ + skipConvexHullComputation: boolean; + + /** + * The radius of the convex polygon's rounded edges and vertices. + */ + borderRadius: number; + + /** + * Creates a new convex polygon shape. + * + * @param vertices - The coordinates of the convex polygon's vertices. + * @param borderRadius - The radius of the borders of this convex polygon. + * @param skipConvexHullComputation - If set to `true`, the input points will + * be assumed to form a convex polyline and no convex-hull computation will + * be done automatically. + */ + constructor( + vertices: Float32Array, + borderRadius: number, + skipConvexHullComputation: boolean, + ) { + super(); + this.vertices = vertices; + this.borderRadius = borderRadius; + this.skipConvexHullComputation = !!skipConvexHullComputation; + } + + public intoRaw(): RawShape { + if (this.skipConvexHullComputation) { + return RawShape.roundConvexPolyline( + this.vertices, + this.borderRadius, + ); + } else { + return RawShape.roundConvexHull(this.vertices, this.borderRadius); + } + } +} + +/** + * A shape that is a heightfield. + */ +export class Heightfield extends Shape { + readonly type = ShapeType.HeightField; + + /** + * The heights of the heightfield, along its local `y` axis. + */ + heights: Float32Array; + + /** + * The heightfield's length along its local `x` axis. + */ + scale: Vector; + + /** + * Creates a new heightfield shape. + * + * @param heights - The heights of the heightfield, along its local `y` axis. + * @param scale - The scale factor applied to the heightfield. + */ + constructor(heights: Float32Array, scale: Vector) { + super(); + this.heights = heights; + this.scale = scale; + } + + public intoRaw(): RawShape { + let rawScale = VectorOps.intoRaw(this.scale); + let rawShape = RawShape.heightfield(this.heights, rawScale); + rawScale.free(); + return rawShape; + } +} + +// #endif + +// #if DIM3 +/** + * A shape that is a convex polygon. + */ +export class ConvexPolyhedron extends Shape { + readonly type = ShapeType.ConvexPolyhedron; + + /** + * The vertices of the convex polygon. + */ + vertices: Float32Array; + + /** + * The indices of the convex polygon. + */ + indices?: Uint32Array | null; + + /** + * Creates a new convex polygon shape. + * + * @param vertices - The coordinates of the convex polygon's vertices. + * @param indices - The index buffer of this convex mesh. If this is `null` + * or `undefined`, the convex-hull of the input vertices will be computed + * automatically. Otherwise, it will be assumed that the mesh you provide + * is already convex. + */ + constructor(vertices: Float32Array, indices?: Uint32Array | null) { + super(); + this.vertices = vertices; + this.indices = indices; + } + + public intoRaw(): RawShape { + if (!!this.indices) { + return RawShape.convexMesh(this.vertices, this.indices); + } else { + return RawShape.convexHull(this.vertices); + } + } +} + +/** + * A shape that is a convex polygon. + */ +export class RoundConvexPolyhedron extends Shape { + readonly type = ShapeType.RoundConvexPolyhedron; + + /** + * The vertices of the convex polygon. + */ + vertices: Float32Array; + + /** + * The indices of the convex polygon. + */ + indices?: Uint32Array; + + /** + * The radius of the convex polyhedron's rounded edges and vertices. + */ + borderRadius: number; + + /** + * Creates a new convex polygon shape. + * + * @param vertices - The coordinates of the convex polygon's vertices. + * @param indices - The index buffer of this convex mesh. If this is `null` + * or `undefined`, the convex-hull of the input vertices will be computed + * automatically. Otherwise, it will be assumed that the mesh you provide + * is already convex. + * @param borderRadius - The radius of the borders of this convex polyhedron. + */ + constructor( + vertices: Float32Array, + indices: Uint32Array | null | undefined, + borderRadius: number, + ) { + super(); + this.vertices = vertices; + this.indices = indices; + this.borderRadius = borderRadius; + } + + public intoRaw(): RawShape { + if (!!this.indices) { + return RawShape.roundConvexMesh( + this.vertices, + this.indices, + this.borderRadius, + ); + } else { + return RawShape.roundConvexHull(this.vertices, this.borderRadius); + } + } +} + +/** + * A shape that is a heightfield. + */ +export class Heightfield extends Shape { + readonly type = ShapeType.HeightField; + + /** + * The number of rows in the heights matrix. + */ + nrows: number; + + /** + * The number of columns in the heights matrix. + */ + ncols: number; + + /** + * The heights of the heightfield along its local `y` axis, + * provided as a matrix stored in column-major order. + */ + heights: Float32Array; + + /** + * The dimensions of the heightfield's local `x,z` plane. + */ + scale: Vector; + + /** + * Flags applied to the heightfield. + */ + flags: HeightFieldFlags; + + /** + * Creates a new heightfield shape. + * + * @param nrows − The number of rows in the heights matrix. + * @param ncols - The number of columns in the heights matrix. + * @param heights - The heights of the heightfield along its local `y` axis, + * provided as a matrix stored in column-major order. + * @param scale - The dimensions of the heightfield's local `x,z` plane. + */ + constructor( + nrows: number, + ncols: number, + heights: Float32Array, + scale: Vector, + flags?: HeightFieldFlags, + ) { + super(); + this.nrows = nrows; + this.ncols = ncols; + this.heights = heights; + this.scale = scale; + this.flags = flags; + } + + public intoRaw(): RawShape { + let rawScale = VectorOps.intoRaw(this.scale); + let rawShape = RawShape.heightfield( + this.nrows, + this.ncols, + this.heights, + rawScale, + this.flags, + ); + rawScale.free(); + return rawShape; + } +} + +/** + * A shape that is a 3D cylinder. + */ +export class Cylinder extends Shape { + readonly type = ShapeType.Cylinder; + + /** + * The radius of the cylinder's basis. + */ + radius: number; + + /** + * The cylinder's half height, along the `y` axis. + */ + halfHeight: number; + + /** + * Creates a new cylinder with the given radius and half-height. + * @param halfHeight - The balls half-height along the `y` axis. + * @param radius - The balls radius. + */ + constructor(halfHeight: number, radius: number) { + super(); + this.halfHeight = halfHeight; + this.radius = radius; + } + + public intoRaw(): RawShape { + return RawShape.cylinder(this.halfHeight, this.radius); + } +} + +/** + * A shape that is a 3D cylinder with round corners. + */ +export class RoundCylinder extends Shape { + readonly type = ShapeType.RoundCylinder; + + /** + * The radius of the cylinder's basis. + */ + radius: number; + + /** + * The cylinder's half height, along the `y` axis. + */ + halfHeight: number; + + /** + * The radius of the cylinder's rounded edges and vertices. + */ + borderRadius: number; + + /** + * Creates a new cylinder with the given radius and half-height. + * @param halfHeight - The balls half-height along the `y` axis. + * @param radius - The balls radius. + * @param borderRadius - The radius of the borders of this cylinder. + */ + constructor(halfHeight: number, radius: number, borderRadius: number) { + super(); + this.borderRadius = borderRadius; + this.halfHeight = halfHeight; + this.radius = radius; + } + + public intoRaw(): RawShape { + return RawShape.roundCylinder( + this.halfHeight, + this.radius, + this.borderRadius, + ); + } +} + +/** + * A shape that is a 3D cone. + */ +export class Cone extends Shape { + readonly type = ShapeType.Cone; + + /** + * The radius of the cone's basis. + */ + radius: number; + + /** + * The cone's half height, along the `y` axis. + */ + halfHeight: number; + + /** + * Creates a new cone with the given radius and half-height. + * @param halfHeight - The balls half-height along the `y` axis. + * @param radius - The balls radius. + */ + constructor(halfHeight: number, radius: number) { + super(); + this.halfHeight = halfHeight; + this.radius = radius; + } + + public intoRaw(): RawShape { + return RawShape.cone(this.halfHeight, this.radius); + } +} + +/** + * A shape that is a 3D cone with round corners. + */ +export class RoundCone extends Shape { + readonly type = ShapeType.RoundCone; + + /** + * The radius of the cone's basis. + */ + radius: number; + + /** + * The cone's half height, along the `y` axis. + */ + halfHeight: number; + + /** + * The radius of the cylinder's rounded edges and vertices. + */ + borderRadius: number; + + /** + * Creates a new cone with the given radius and half-height. + * @param halfHeight - The balls half-height along the `y` axis. + * @param radius - The balls radius. + * @param borderRadius - The radius of the borders of this cone. + */ + constructor(halfHeight: number, radius: number, borderRadius: number) { + super(); + this.halfHeight = halfHeight; + this.radius = radius; + this.borderRadius = borderRadius; + } + + public intoRaw(): RawShape { + return RawShape.roundCone( + this.halfHeight, + this.radius, + this.borderRadius, + ); + } +} + +// #endif diff --git a/typescript/src.ts/geometry/toi.ts b/typescript/src.ts/geometry/toi.ts new file mode 100644 index 000000000..013c4be38 --- /dev/null +++ b/typescript/src.ts/geometry/toi.ts @@ -0,0 +1,163 @@ +import {Collider} from "./collider"; +import {Vector, VectorOps} from "../math"; + +/** + * The intersection between a ray and a collider. + */ +export class ShapeCastHit { + /** + * The time of impact of the two shapes. + */ + time_of_impact: number; + /** + * The local-space contact point on the first shape, at + * the time of impact. + */ + witness1: Vector; + /** + * The local-space contact point on the second shape, at + * the time of impact. + */ + witness2: Vector; + /** + * The local-space normal on the first shape, at + * the time of impact. + */ + normal1: Vector; + /** + * The local-space normal on the second shape, at + * the time of impact. + */ + normal2: Vector; + + constructor( + time_of_impact: number, + witness1: Vector, + witness2: Vector, + normal1: Vector, + normal2: Vector, + ) { + this.time_of_impact = time_of_impact; + this.witness1 = witness1; + this.witness2 = witness2; + this.normal1 = normal1; + this.normal2 = normal2; + } + + public static fromBuffer( + collider: Collider, + buffer: Float32Array, + target?: ShapeCastHit, + ): ShapeCastHit { + if (!buffer) return null; + + target ??= new ShapeCastHit( + 0, + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + ); + + target.time_of_impact = buffer[0]; + + // #if DIM2 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness2.x = buffer[3]; + target.witness2.y = buffer[4]; + target.normal1.x = buffer[5]; + target.normal1.y = buffer[6]; + target.normal2.x = buffer[7]; + target.normal2.y = buffer[8]; + // #endif + + // #if DIM3 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness1.z = buffer[3]; + target.witness2.x = buffer[4]; + target.witness2.y = buffer[5]; + target.witness2.z = buffer[6]; + target.normal1.x = buffer[7]; + target.normal1.y = buffer[8]; + target.normal1.z = buffer[9]; + target.normal2.x = buffer[10]; + target.normal2.y = buffer[11]; + target.normal2.z = buffer[12]; + // #endif + + return target; + } +} + +/** + * The intersection between a ray and a collider. + */ +export class ColliderShapeCastHit extends ShapeCastHit { + /** + * The handle of the collider hit by the ray. + */ + collider: Collider; + + constructor( + collider: Collider, + time_of_impact: number, + witness1: Vector, + witness2: Vector, + normal1: Vector, + normal2: Vector, + ) { + super(time_of_impact, witness1, witness2, normal1, normal2); + this.collider = collider; + } + + public static fromBuffer( + collider: Collider, + buffer: Float32Array, + target?: ColliderShapeCastHit, + ): ColliderShapeCastHit { + if (!buffer) return null; + + target ??= new ColliderShapeCastHit( + null, + 0, + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + VectorOps.zeros(), + ); + + target.collider = collider; + + target.time_of_impact = buffer[0]; + + // #if DIM2 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness2.x = buffer[3]; + target.witness2.y = buffer[4]; + target.normal1.x = buffer[5]; + target.normal1.y = buffer[6]; + target.normal2.x = buffer[7]; + target.normal2.y = buffer[8]; + // #endif + + // #if DIM3 + target.witness1.x = buffer[1]; + target.witness1.y = buffer[2]; + target.witness1.z = buffer[3]; + target.witness2.x = buffer[4]; + target.witness2.y = buffer[5]; + target.witness2.z = buffer[6]; + target.normal1.x = buffer[7]; + target.normal1.y = buffer[8]; + target.normal1.z = buffer[9]; + target.normal2.x = buffer[10]; + target.normal2.y = buffer[11]; + target.normal2.z = buffer[12]; + // #endif + + return target; + } +} diff --git a/typescript/src.ts/init.ts b/typescript/src.ts/init.ts new file mode 100644 index 000000000..e9e66aad7 --- /dev/null +++ b/typescript/src.ts/init.ts @@ -0,0 +1,2 @@ +// Placeholder for the `init` function used in rapier-compat. +export {}; diff --git a/typescript/src.ts/math.ts b/typescript/src.ts/math.ts new file mode 100644 index 000000000..86eb9e5a6 --- /dev/null +++ b/typescript/src.ts/math.ts @@ -0,0 +1,315 @@ +import {RawVector, RawRotation} from "./raw"; +// #if DIM3 +import {RawSdpMatrix3} from "./raw"; +// #endif + +// scratchBuffer should be as big as the biggest index Rust tries to set on it. +export const scratchBuffer = new Float32Array(16); + +// #if DIM2 +export interface Vector { + x: number; + y: number; +} + +/** + * A 2D vector. + */ +export class Vector2 implements Vector { + x: number; + y: number; + + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } +} + +export class VectorOps { + public static new(x: number, y: number): Vector { + return new Vector2(x, y); + } + + public static zeros(): Vector { + return VectorOps.new(0.0, 0.0); + } + + public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { + if (!buffer) return null; + + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + return target; + } + + // FIXME: type ram: RawVector? + public static fromRaw(raw: RawVector): Vector { + if (!raw) return null; + + let res = VectorOps.new(raw.x, raw.y); + raw.free(); + return res; + } + + public static intoRaw(v: Vector): RawVector { + return new RawVector(v.x, v.y); + } + + public static copy(out: Vector, input: Vector) { + out.x = input.x; + out.y = input.y; + } +} + +/** + * A rotation angle in radians. + */ +export type Rotation = number; + +export class RotationOps { + public static identity(): number { + return 0.0; + } + + public static fromRaw(raw: RawRotation): Rotation { + if (!raw) return null; + + let res = raw.angle; + raw.free(); + return res; + } + + public static intoRaw(angle: Rotation): RawRotation { + return RawRotation.fromAngle(angle); + } +} + +// #endif + +// #if DIM3 +export interface Vector { + x: number; + y: number; + z: number; +} + +/** + * A 3D vector. + */ +export class Vector3 implements Vector { + x: number; + y: number; + z: number; + + constructor(x: number, y: number, z: number) { + this.x = x; + this.y = y; + this.z = z; + } +} + +export class VectorOps { + public static new(x: number, y: number, z: number): Vector { + return new Vector3(x, y, z); + } + + public static intoRaw(v: Vector): RawVector { + return new RawVector(v.x, v.y, v.z); + } + + public static zeros(): Vector { + return VectorOps.new(0.0, 0.0, 0.0); + } + + public static fromBuffer(buffer: Float32Array, target?: Vector): Vector { + if (!buffer) return null; + + target ??= VectorOps.zeros(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + return target; + } + + // FIXME: type ram: RawVector? + public static fromRaw(raw: RawVector): Vector { + if (!raw) return null; + + let res = VectorOps.new(raw.x, raw.y, raw.z); + raw.free(); + return res; + } + + public static copy(out: Vector, input: Vector) { + out.x = input.x; + out.y = input.y; + out.z = input.z; + } +} + +export interface Rotation { + x: number; + y: number; + z: number; + w: number; +} + +/** + * A quaternion. + */ +export class Quaternion implements Rotation { + x: number; + y: number; + z: number; + w: number; + + constructor(x: number, y: number, z: number, w: number) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } +} + +export class RotationOps { + public static identity(): Rotation { + return new Quaternion(0.0, 0.0, 0.0, 1.0); + } + + public static fromBuffer( + buffer: Float32Array, + target?: Rotation, + ): Rotation { + if (!buffer) return null; + + target ??= RotationOps.identity(); + target.x = buffer[0]; + target.y = buffer[1]; + target.z = buffer[2]; + target.w = buffer[3]; + return target; + } + + public static fromRaw(raw: RawRotation): Rotation { + if (!raw) return null; + + let res = new Quaternion(raw.x, raw.y, raw.z, raw.w); + raw.free(); + return res; + } + + public static intoRaw(rot: Rotation): RawRotation { + return new RawRotation(rot.x, rot.y, rot.z, rot.w); + } + + public static copy(out: Rotation, input: Rotation) { + out.x = input.x; + out.y = input.y; + out.z = input.z; + out.w = input.w; + } +} + +/** + * A 3D symmetric-positive-definite matrix. + */ +export class SdpMatrix3 { + /** + * Row major list of the upper-triangular part of the symmetric matrix. + */ + elements: Float32Array; + + /** + * Matrix element at row 1, column 1. + */ + public get m11(): number { + return this.elements[0]; + } + + /** + * Matrix element at row 1, column 2. + */ + public get m12(): number { + return this.elements[1]; + } + + /** + * Matrix element at row 2, column 1. + */ + public get m21(): number { + return this.m12; + } + + /** + * Matrix element at row 1, column 3. + */ + public get m13(): number { + return this.elements[2]; + } + + /** + * Matrix element at row 3, column 1. + */ + public get m31(): number { + return this.m13; + } + + /** + * Matrix element at row 2, column 2. + */ + public get m22(): number { + return this.elements[3]; + } + + /** + * Matrix element at row 2, column 3. + */ + public get m23(): number { + return this.elements[4]; + } + + /** + * Matrix element at row 3, column 2. + */ + public get m32(): number { + return this.m23; + } + + /** + * Matrix element at row 3, column 3. + */ + public get m33(): number { + return this.elements[5]; + } + + constructor(elements: Float32Array) { + this.elements = elements; + } +} + +export class SdpMatrix3Ops { + public static fromBuffer( + buffer: Float32Array, + target?: SdpMatrix3, + ): SdpMatrix3 { + if (!buffer) return null; + + target ??= new SdpMatrix3(buffer); + target.elements[0] = buffer[0]; + target.elements[1] = buffer[1]; + target.elements[2] = buffer[2]; + target.elements[3] = buffer[3]; + target.elements[4] = buffer[4]; + target.elements[5] = buffer[5]; + return target; + } + + public static fromRaw(raw: RawSdpMatrix3): SdpMatrix3 { + const sdpMatrix3 = new SdpMatrix3(raw.elements()); + raw.free(); + return sdpMatrix3; + } +} + +// #endif diff --git a/typescript/src.ts/pipeline/debug_render_pipeline.ts b/typescript/src.ts/pipeline/debug_render_pipeline.ts new file mode 100644 index 000000000..a377ef5e4 --- /dev/null +++ b/typescript/src.ts/pipeline/debug_render_pipeline.ts @@ -0,0 +1,85 @@ +import {RawDebugRenderPipeline} from "../raw"; +import {Vector, VectorOps} from "../math"; +import { + IntegrationParameters, + IslandManager, + ImpulseJointSet, + MultibodyJointSet, + RigidBodySet, +} from "../dynamics"; +import {BroadPhase, Collider, ColliderSet, NarrowPhase} from "../geometry"; +import {QueryFilterFlags} from "./query_pipeline"; + +/** + * The vertex and color buffers for debug-rendering the physics scene. + */ +export class DebugRenderBuffers { + /** + * The lines to render. This is a flat array containing all the lines + * to render. Each line is described as two consecutive point. Each + * point is described as two (in 2D) or three (in 3D) consecutive + * floats. For example, in 2D, the array: `[1, 2, 3, 4, 5, 6, 7, 8]` + * describes the two segments `[[1, 2], [3, 4]]` and `[[5, 6], [7, 8]]`. + */ + public vertices: Float32Array; + /** + * The color buffer. There is one color per vertex, and each color + * has four consecutive components (in RGBA format). + */ + public colors: Float32Array; + + constructor(vertices: Float32Array, colors: Float32Array) { + this.vertices = vertices; + this.colors = colors; + } +} + +/** + * A pipeline for rendering the physics scene. + * + * To avoid leaking WASM resources, this MUST be freed manually with `debugRenderPipeline.free()` + * once you are done using it (and all the rigid-bodies it created). + */ +export class DebugRenderPipeline { + raw: RawDebugRenderPipeline; + public vertices: Float32Array; + public colors: Float32Array; + + /** + * Release the WASM memory occupied by this serialization pipeline. + */ + free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + this.vertices = undefined; + this.colors = undefined; + } + + constructor(raw?: RawDebugRenderPipeline) { + this.raw = raw || new RawDebugRenderPipeline(); + } + + public render( + bodies: RigidBodySet, + colliders: ColliderSet, + impulse_joints: ImpulseJointSet, + multibody_joints: MultibodyJointSet, + narrow_phase: NarrowPhase, + filterFlags?: QueryFilterFlags, + filterPredicate?: (collider: Collider) => boolean, + ) { + this.raw.render( + bodies.raw, + colliders.raw, + impulse_joints.raw, + multibody_joints.raw, + narrow_phase.raw, + filterFlags, + colliders.castClosure(filterPredicate), + ); + this.vertices = this.raw.vertices(); + this.colors = this.raw.colors(); + } +} diff --git a/typescript/src.ts/pipeline/event_queue.ts b/typescript/src.ts/pipeline/event_queue.ts new file mode 100644 index 000000000..1269b7a8f --- /dev/null +++ b/typescript/src.ts/pipeline/event_queue.ts @@ -0,0 +1,160 @@ +import {RawContactForceEvent, RawEventQueue} from "../raw"; +import {RigidBodyHandle} from "../dynamics"; +import {Collider, ColliderHandle} from "../geometry"; +import {Vector, VectorOps, scratchBuffer} from "../math"; + +/** + * Flags indicating what events are enabled for colliders. + */ +export enum ActiveEvents { + NONE = 0, + /** + * Enable collision events. + */ + COLLISION_EVENTS = 0b0001, + /** + * Enable contact force events. + */ + CONTACT_FORCE_EVENTS = 0b0010, +} + +/** + * Event occurring when the sum of the magnitudes of the + * contact forces between two colliders exceed a threshold. + * + * This object should **not** be stored anywhere. Its properties can only be + * read from within the closure given to `EventHandler.drainContactForceEvents`. + */ +export class TempContactForceEvent { + raw: RawContactForceEvent; + + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + /** + * The first collider involved in the contact. + */ + public collider1(): ColliderHandle { + return this.raw.collider1(); + } + + /** + * The second collider involved in the contact. + */ + public collider2(): ColliderHandle { + return this.raw.collider2(); + } + + /** + * The sum of all the forces between the two colliders. + */ + public totalForce(target?: Vector): Vector { + this.raw.total_force(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The sum of the magnitudes of each force between the two colliders. + * + * Note that this is **not** the same as the magnitude of `self.total_force`. + * Here we are summing the magnitude of all the forces, instead of taking + * the magnitude of their sum. + */ + public totalForceMagnitude(): number { + return this.raw.total_force_magnitude(); + } + + /** + * The world-space (unit) direction of the force with strongest magnitude. + */ + public maxForceDirection(target?: Vector): Vector { + this.raw.max_force_direction(scratchBuffer); + return VectorOps.fromBuffer(scratchBuffer, target); + } + + /** + * The magnitude of the largest force at a contact point of this contact pair. + */ + public maxForceMagnitude(): number { + return this.raw.max_force_magnitude(); + } +} + +/** + * A structure responsible for collecting events generated + * by the physics engine. + * + * To avoid leaking WASM resources, this MUST be freed manually with `eventQueue.free()` + * once you are done using it. + */ +export class EventQueue { + raw: RawEventQueue; + + /** + * Creates a new event collector. + * + * @param autoDrain -setting this to `true` is strongly recommended. If true, the collector will + * be automatically drained before each `world.step(collector)`. If false, the collector will + * keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of + * RAM if no drain is performed. + */ + constructor(autoDrain: boolean, raw?: RawEventQueue) { + this.raw = raw || new RawEventQueue(autoDrain); + } + + /** + * Release the WASM memory occupied by this event-queue. + */ + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + /** + * Applies the given javascript closure on each collision event of this collector, then clear + * the internal collision event buffer. + * + * @param f - JavaScript closure applied to each collision event. The + * closure must take three arguments: two integers representing the handles of the colliders + * involved in the collision, and a boolean indicating if the collision started (true) or stopped + * (false). + */ + public drainCollisionEvents( + f: ( + handle1: ColliderHandle, + handle2: ColliderHandle, + started: boolean, + ) => void, + ) { + this.raw.drainCollisionEvents(f); + } + + /** + * Applies the given javascript closure on each contact force event of this collector, then clear + * the internal collision event buffer. + * + * @param f - JavaScript closure applied to each collision event. The + * closure must take one `TempContactForceEvent` argument. + */ + public drainContactForceEvents(f: (event: TempContactForceEvent) => void) { + let event = new TempContactForceEvent(); + this.raw.drainContactForceEvents((raw: RawContactForceEvent) => { + event.raw = raw; + f(event); + event.free(); + }); + } + + /** + * Removes all events contained by this collector + */ + public clear() { + this.raw.clear(); + } +} diff --git a/typescript/src.ts/pipeline/index.ts b/typescript/src.ts/pipeline/index.ts new file mode 100644 index 000000000..092c1a596 --- /dev/null +++ b/typescript/src.ts/pipeline/index.ts @@ -0,0 +1,7 @@ +export * from "./world"; +export * from "./physics_pipeline"; +export * from "./serialization_pipeline"; +export * from "./event_queue"; +export * from "./physics_hooks"; +export * from "./debug_render_pipeline"; +export * from "./query_pipeline"; diff --git a/typescript/src.ts/pipeline/physics_hooks.ts b/typescript/src.ts/pipeline/physics_hooks.ts new file mode 100644 index 000000000..20e12ad98 --- /dev/null +++ b/typescript/src.ts/pipeline/physics_hooks.ts @@ -0,0 +1,54 @@ +import {RigidBodyHandle} from "../dynamics"; +import {ColliderHandle} from "../geometry"; + +export enum ActiveHooks { + NONE = 0, + FILTER_CONTACT_PAIRS = 0b0001, + FILTER_INTERSECTION_PAIRS = 0b0010, + // MODIFY_SOLVER_CONTACTS = 0b0100, /* Not supported yet in JS. */ +} + +export enum SolverFlags { + EMPTY = 0b000, + COMPUTE_IMPULSE = 0b001, +} + +export interface PhysicsHooks { + /** + * Function that determines if contacts computation should happen between two colliders, and how the + * constraints solver should behave for these contacts. + * + * This will only be executed and taken into account if at least one of the involved colliders contains the + * `ActiveHooks.FILTER_CONTACT_PAIR` flag in its active hooks. + * + * @param collider1 − Handle of the first collider involved in the potential contact. + * @param collider2 − Handle of the second collider involved in the potential contact. + * @param body1 − Handle of the first body involved in the potential contact. + * @param body2 − Handle of the second body involved in the potential contact. + */ + filterContactPair( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle, + ): SolverFlags | null; + + /** + * Function that determines if intersection computation should happen between two colliders (where at least + * one is a sensor). + * + * This will only be executed and taken into account if `one of the involved colliders contains the + * `ActiveHooks.FILTER_INTERSECTION_PAIR` flag in its active hooks. + * + * @param collider1 − Handle of the first collider involved in the potential contact. + * @param collider2 − Handle of the second collider involved in the potential contact. + * @param body1 − Handle of the first body involved in the potential contact. + * @param body2 − Handle of the second body involved in the potential contact. + */ + filterIntersectionPair( + collider1: ColliderHandle, + collider2: ColliderHandle, + body1: RigidBodyHandle, + body2: RigidBodyHandle, + ): boolean; +} diff --git a/typescript/src.ts/pipeline/physics_pipeline.ts b/typescript/src.ts/pipeline/physics_pipeline.ts new file mode 100644 index 000000000..a3319205c --- /dev/null +++ b/typescript/src.ts/pipeline/physics_pipeline.ts @@ -0,0 +1,85 @@ +import {RawPhysicsPipeline} from "../raw"; +import {Vector, VectorOps} from "../math"; +import { + IntegrationParameters, + ImpulseJointSet, + MultibodyJointSet, + RigidBodyHandle, + RigidBodySet, + CCDSolver, + IslandManager, +} from "../dynamics"; +import { + BroadPhase, + ColliderHandle, + ColliderSet, + NarrowPhase, +} from "../geometry"; +import {EventQueue} from "./event_queue"; +import {PhysicsHooks} from "./physics_hooks"; + +export class PhysicsPipeline { + raw: RawPhysicsPipeline; + + public free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawPhysicsPipeline) { + this.raw = raw || new RawPhysicsPipeline(); + } + + public step( + gravity: Vector, + integrationParameters: IntegrationParameters, + islands: IslandManager, + broadPhase: BroadPhase, + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + impulseJoints: ImpulseJointSet, + multibodyJoints: MultibodyJointSet, + ccdSolver: CCDSolver, + eventQueue?: EventQueue, + hooks?: PhysicsHooks, + ) { + let rawG = VectorOps.intoRaw(gravity); + + if (!!eventQueue) { + this.raw.stepWithEvents( + rawG, + integrationParameters.raw, + islands.raw, + broadPhase.raw, + narrowPhase.raw, + bodies.raw, + colliders.raw, + impulseJoints.raw, + multibodyJoints.raw, + ccdSolver.raw, + eventQueue.raw, + hooks, + !!hooks ? hooks.filterContactPair : null, + !!hooks ? hooks.filterIntersectionPair : null, + ); + } else { + this.raw.step( + rawG, + integrationParameters.raw, + islands.raw, + broadPhase.raw, + narrowPhase.raw, + bodies.raw, + colliders.raw, + impulseJoints.raw, + multibodyJoints.raw, + ccdSolver.raw, + ); + } + + rawG.free(); + } +} diff --git a/typescript/src.ts/pipeline/query_pipeline.ts b/typescript/src.ts/pipeline/query_pipeline.ts new file mode 100644 index 000000000..5610ff31f --- /dev/null +++ b/typescript/src.ts/pipeline/query_pipeline.ts @@ -0,0 +1,57 @@ +import {RawRayColliderIntersection} from "../raw"; +import { + ColliderHandle, + ColliderSet, + InteractionGroups, + PointColliderProjection, + Ray, + RayColliderIntersection, + RayColliderHit, + Shape, + ColliderShapeCastHit, +} from "../geometry"; +import {IslandManager, RigidBodyHandle, RigidBodySet} from "../dynamics"; +import {Rotation, RotationOps, Vector, VectorOps} from "../math"; + +// NOTE: must match the bits in the QueryFilterFlags on the Rust side. +/** + * Flags for excluding whole sets of colliders from a scene query. + */ +export enum QueryFilterFlags { + /** + * Exclude from the query any collider attached to a fixed rigid-body and colliders with no rigid-body attached. + */ + EXCLUDE_FIXED = 0b0000_0001, + /** + * Exclude from the query any collider attached to a dynamic rigid-body. + */ + EXCLUDE_KINEMATIC = 0b0000_0010, + /** + * Exclude from the query any collider attached to a kinematic rigid-body. + */ + EXCLUDE_DYNAMIC = 0b0000_0100, + /** + * Exclude from the query any collider that is a sensor. + */ + EXCLUDE_SENSORS = 0b0000_1000, + /** + * Exclude from the query any collider that is not a sensor. + */ + EXCLUDE_SOLIDS = 0b0001_0000, + /** + * Excludes all colliders not attached to a dynamic rigid-body. + */ + ONLY_DYNAMIC = QueryFilterFlags.EXCLUDE_FIXED | + QueryFilterFlags.EXCLUDE_KINEMATIC, + /** + * Excludes all colliders not attached to a kinematic rigid-body. + */ + ONLY_KINEMATIC = QueryFilterFlags.EXCLUDE_DYNAMIC | + QueryFilterFlags.EXCLUDE_FIXED, + /** + * Exclude all colliders attached to a non-fixed rigid-body + * (this will not exclude colliders not attached to any rigid-body). + */ + ONLY_FIXED = QueryFilterFlags.EXCLUDE_DYNAMIC | + QueryFilterFlags.EXCLUDE_KINEMATIC, +} diff --git a/typescript/src.ts/pipeline/serialization_pipeline.ts b/typescript/src.ts/pipeline/serialization_pipeline.ts new file mode 100644 index 000000000..87fde398c --- /dev/null +++ b/typescript/src.ts/pipeline/serialization_pipeline.ts @@ -0,0 +1,84 @@ +import {RawSerializationPipeline} from "../raw"; +import {Vector, VectorOps} from "../math"; +import { + IntegrationParameters, + IslandManager, + ImpulseJointSet, + MultibodyJointSet, + RigidBodySet, +} from "../dynamics"; +import {BroadPhase, ColliderSet, NarrowPhase} from "../geometry"; +import {World} from "./world"; + +/** + * A pipeline for serializing the physics scene. + * + * To avoid leaking WASM resources, this MUST be freed manually with `serializationPipeline.free()` + * once you are done using it (and all the rigid-bodies it created). + */ +export class SerializationPipeline { + raw: RawSerializationPipeline; + + /** + * Release the WASM memory occupied by this serialization pipeline. + */ + free() { + if (!!this.raw) { + this.raw.free(); + } + this.raw = undefined; + } + + constructor(raw?: RawSerializationPipeline) { + this.raw = raw || new RawSerializationPipeline(); + } + + /** + * Serialize a complete physics state into a single byte array. + * @param gravity - The current gravity affecting the simulation. + * @param integrationParameters - The integration parameters of the simulation. + * @param broadPhase - The broad-phase of the simulation. + * @param narrowPhase - The narrow-phase of the simulation. + * @param bodies - The rigid-bodies taking part into the simulation. + * @param colliders - The colliders taking part into the simulation. + * @param impulseJoints - The impulse joints taking part into the simulation. + * @param multibodyJoints - The multibody joints taking part into the simulation. + */ + public serializeAll( + gravity: Vector, + integrationParameters: IntegrationParameters, + islands: IslandManager, + broadPhase: BroadPhase, + narrowPhase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + impulseJoints: ImpulseJointSet, + multibodyJoints: MultibodyJointSet, + ): Uint8Array { + let rawGra = VectorOps.intoRaw(gravity); + + const res = this.raw.serializeAll( + rawGra, + integrationParameters.raw, + islands.raw, + broadPhase.raw, + narrowPhase.raw, + bodies.raw, + colliders.raw, + impulseJoints.raw, + multibodyJoints.raw, + ); + rawGra.free(); + + return res; + } + + /** + * Deserialize the complete physics state from a single byte array. + * + * @param data - The byte array to deserialize. + */ + public deserializeAll(data: Uint8Array): World { + return World.fromRaw(this.raw.deserializeAll(data)); + } +} diff --git a/typescript/src.ts/pipeline/world.ts b/typescript/src.ts/pipeline/world.ts new file mode 100644 index 000000000..9ee856161 --- /dev/null +++ b/typescript/src.ts/pipeline/world.ts @@ -0,0 +1,1312 @@ +import { + RawBroadPhase, + RawCCDSolver, + RawColliderSet, + RawDeserializedWorld, + RawIntegrationParameters, + RawIslandManager, + RawImpulseJointSet, + RawMultibodyJointSet, + RawNarrowPhase, + RawPhysicsPipeline, + RawRigidBodySet, + RawSerializationPipeline, + RawDebugRenderPipeline, +} from "../raw"; + +import { + BroadPhase, + Collider, + ColliderDesc, + ColliderHandle, + ColliderSet, + InteractionGroups, + NarrowPhase, + PointColliderProjection, + Ray, + RayColliderIntersection, + RayColliderHit, + Shape, + ColliderShapeCastHit, + TempContactManifold, +} from "../geometry"; +import { + CCDSolver, + IntegrationParameters, + IslandManager, + ImpulseJoint, + ImpulseJointHandle, + MultibodyJoint, + MultibodyJointHandle, + JointData, + ImpulseJointSet, + MultibodyJointSet, + RigidBody, + RigidBodyDesc, + RigidBodyHandle, + RigidBodySet, +} from "../dynamics"; +import {Rotation, Vector, VectorOps} from "../math"; +import {PhysicsPipeline} from "./physics_pipeline"; +import {QueryFilterFlags} from "./query_pipeline"; +import {SerializationPipeline} from "./serialization_pipeline"; +import {EventQueue} from "./event_queue"; +import {PhysicsHooks} from "./physics_hooks"; +import {DebugRenderBuffers, DebugRenderPipeline} from "./debug_render_pipeline"; +import { + KinematicCharacterController, + PidAxesMask, + PidController, +} from "../control"; +import {Coarena} from "../coarena"; + +// #if DIM3 +import {DynamicRayCastVehicleController} from "../control"; + +// #endif + +/** + * The physics world. + * + * This contains all the data-structures necessary for creating and simulating + * bodies with contacts, joints, and external forces. + */ +export class World { + public gravity: Vector; + integrationParameters: IntegrationParameters; + islands: IslandManager; + broadPhase: BroadPhase; + narrowPhase: NarrowPhase; + bodies: RigidBodySet; + colliders: ColliderSet; + impulseJoints: ImpulseJointSet; + multibodyJoints: MultibodyJointSet; + ccdSolver: CCDSolver; + physicsPipeline: PhysicsPipeline; + serializationPipeline: SerializationPipeline; + debugRenderPipeline: DebugRenderPipeline; + characterControllers: Set; + pidControllers: Set; + + // #if DIM3 + vehicleControllers: Set; + + // #endif + + /** + * Release the WASM memory occupied by this physics world. + * + * All the fields of this physics world will be freed as well, + * so there is no need to call their `.free()` methods individually. + */ + public free() { + this.integrationParameters.free(); + this.islands.free(); + this.broadPhase.free(); + this.narrowPhase.free(); + this.bodies.free(); + this.colliders.free(); + this.impulseJoints.free(); + this.multibodyJoints.free(); + this.ccdSolver.free(); + this.physicsPipeline.free(); + this.serializationPipeline.free(); + this.debugRenderPipeline.free(); + this.characterControllers.forEach((controller) => controller.free()); + this.pidControllers.forEach((controller) => controller.free()); + + // #if DIM3 + this.vehicleControllers.forEach((controller) => controller.free()); + // #endif + + this.integrationParameters = undefined; + this.islands = undefined; + this.broadPhase = undefined; + this.narrowPhase = undefined; + this.bodies = undefined; + this.colliders = undefined; + this.ccdSolver = undefined; + this.impulseJoints = undefined; + this.multibodyJoints = undefined; + this.physicsPipeline = undefined; + this.serializationPipeline = undefined; + this.debugRenderPipeline = undefined; + this.characterControllers = undefined; + this.pidControllers = undefined; + + // #if DIM3 + this.vehicleControllers = undefined; + // #endif + } + + constructor( + gravity: Vector, + rawIntegrationParameters?: RawIntegrationParameters, + rawIslands?: RawIslandManager, + rawBroadPhase?: RawBroadPhase, + rawNarrowPhase?: RawNarrowPhase, + rawBodies?: RawRigidBodySet, + rawColliders?: RawColliderSet, + rawImpulseJoints?: RawImpulseJointSet, + rawMultibodyJoints?: RawMultibodyJointSet, + rawCCDSolver?: RawCCDSolver, + rawPhysicsPipeline?: RawPhysicsPipeline, + rawSerializationPipeline?: RawSerializationPipeline, + rawDebugRenderPipeline?: RawDebugRenderPipeline, + ) { + this.gravity = gravity; + this.integrationParameters = new IntegrationParameters( + rawIntegrationParameters, + ); + this.islands = new IslandManager(rawIslands); + this.broadPhase = new BroadPhase(rawBroadPhase); + this.narrowPhase = new NarrowPhase(rawNarrowPhase); + this.bodies = new RigidBodySet(rawBodies); + this.colliders = new ColliderSet(rawColliders); + this.impulseJoints = new ImpulseJointSet(rawImpulseJoints); + this.multibodyJoints = new MultibodyJointSet(rawMultibodyJoints); + this.ccdSolver = new CCDSolver(rawCCDSolver); + this.physicsPipeline = new PhysicsPipeline(rawPhysicsPipeline); + this.serializationPipeline = new SerializationPipeline( + rawSerializationPipeline, + ); + this.debugRenderPipeline = new DebugRenderPipeline( + rawDebugRenderPipeline, + ); + this.characterControllers = new Set(); + this.pidControllers = new Set(); + + // #if DIM3 + this.vehicleControllers = new Set(); + // #endif + + this.impulseJoints.finalizeDeserialization(this.bodies); + this.bodies.finalizeDeserialization(this.colliders); + this.colliders.finalizeDeserialization(this.bodies); + } + + public static fromRaw(raw: RawDeserializedWorld): World { + if (!raw) return null; + + return new World( + VectorOps.fromRaw(raw.takeGravity()), + raw.takeIntegrationParameters(), + raw.takeIslandManager(), + raw.takeBroadPhase(), + raw.takeNarrowPhase(), + raw.takeBodies(), + raw.takeColliders(), + raw.takeImpulseJoints(), + raw.takeMultibodyJoints(), + ); + } + + /** + * Takes a snapshot of this world. + * + * Use `World.restoreSnapshot` to create a new physics world with a state identical to + * the state when `.takeSnapshot()` is called. + */ + public takeSnapshot(): Uint8Array { + return this.serializationPipeline.serializeAll( + this.gravity, + this.integrationParameters, + this.islands, + this.broadPhase, + this.narrowPhase, + this.bodies, + this.colliders, + this.impulseJoints, + this.multibodyJoints, + ); + } + + /** + * Creates a new physics world from a snapshot. + * + * This new physics world will be an identical copy of the snapshoted physics world. + */ + public static restoreSnapshot(data: Uint8Array): World { + let deser = new SerializationPipeline(); + return deser.deserializeAll(data); + } + + /** + * Computes all the lines (and their colors) needed to render the scene. + * + * @param filterFlags - Flags for excluding whole subsets of colliders from rendering. + * @param filterPredicate - Any collider for which this closure returns `false` will be excluded from the + * debug rendering. + */ + public debugRender( + filterFlags?: QueryFilterFlags, + filterPredicate?: (collider: Collider) => boolean, + ): DebugRenderBuffers { + this.debugRenderPipeline.render( + this.bodies, + this.colliders, + this.impulseJoints, + this.multibodyJoints, + this.narrowPhase, + filterFlags, + filterPredicate, + ); + return new DebugRenderBuffers( + this.debugRenderPipeline.vertices, + this.debugRenderPipeline.colors, + ); + } + + /** + * Advance the simulation by one time step. + * + * All events generated by the physics engine are ignored. + * + * @param EventQueue - (optional) structure responsible for collecting + * events generated by the physics engine. + */ + public step(eventQueue?: EventQueue, hooks?: PhysicsHooks) { + this.physicsPipeline.step( + this.gravity, + this.integrationParameters, + this.islands, + this.broadPhase, + this.narrowPhase, + this.bodies, + this.colliders, + this.impulseJoints, + this.multibodyJoints, + this.ccdSolver, + eventQueue, + hooks, + ); + } + + /** + * Update colliders positions after rigid-bodies moved. + * + * When a rigid-body moves, the positions of the colliders attached to it need to be updated. This update is + * generally automatically done at the beginning and the end of each simulation step with World.step. + * If the positions need to be updated without running a simulation step this method can be called manually. + */ + public propagateModifiedBodyPositionsToColliders() { + this.bodies.raw.propagateModifiedBodyPositionsToColliders( + this.colliders.raw, + ); + } + + // TODO: This needs to trigger a broad-phase update but without emitting collision events? + // /** + // * Ensure subsequent scene queries take into account the collider positions set before this method is called. + // * + // * This does not step the physics simulation forward. + // */ + // public updateSceneQueries() { + // this.propagateModifiedBodyPositionsToColliders(); + // this.queryPipeline.update(this.colliders); + // } + + /** + * The current simulation timestep. + */ + get timestep(): number { + return this.integrationParameters.dt; + } + + /** + * Sets the new simulation timestep. + * + * The simulation timestep governs by how much the physics state of the world will + * be integrated. A simulation timestep should: + * - be as small as possible. Typical values evolve around 0.016 (assuming the chosen unit is milliseconds, + * corresponds to the time between two frames of a game running at 60FPS). + * - not vary too much during the course of the simulation. A timestep with large variations may + * cause instabilities in the simulation. + * + * @param dt - The timestep length, in seconds. + */ + set timestep(dt: number) { + this.integrationParameters.dt = dt; + } + + /** + * The approximate size of most dynamic objects in the scene. + * + * See the documentation of the `World.lengthUnit` setter for further details. + */ + get lengthUnit(): number { + return this.integrationParameters.lengthUnit; + } + + /** + * The approximate size of most dynamic objects in the scene. + * + * This value is used internally to estimate some length-based tolerance. In particular, the + * values `IntegrationParameters.allowedLinearError`, + * `IntegrationParameters.maxPenetrationCorrection`, + * `IntegrationParameters.predictionDistance`, `RigidBodyActivation.linearThreshold` + * are scaled by this value implicitly. + * + * This value can be understood as the number of units-per-meter in your physical world compared + * to a human-sized world in meter. For example, in a 2d game, if your typical object size is 100 + * pixels, set the `[`Self::length_unit`]` parameter to 100.0. The physics engine will interpret + * it as if 100 pixels is equivalent to 1 meter in its various internal threshold. + * (default `1.0`). + */ + set lengthUnit(unitsPerMeter: number) { + this.integrationParameters.lengthUnit = unitsPerMeter; + } + + /** + * The number of solver iterations run by the constraints solver for calculating forces (default: `4`). + */ + get numSolverIterations(): number { + return this.integrationParameters.numSolverIterations; + } + + /** + * Sets the number of solver iterations run by the constraints solver for calculating forces (default: `4`). + * + * The greater this value is, the most rigid and realistic the physics simulation will be. + * However a greater number of iterations is more computationally intensive. + * + * @param niter - The new number of solver iterations. + */ + set numSolverIterations(niter: number) { + this.integrationParameters.numSolverIterations = niter; + } + + /** + * Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`). + */ + get numInternalPgsIterations(): number { + return this.integrationParameters.numInternalPgsIterations; + } + + /** + * Sets the Number of internal Project Gauss Seidel (PGS) iterations run at each solver iteration (default: `1`). + * + * Increasing this parameter will improve stability of the simulation. It will have a lesser effect than + * increasing `numSolverIterations` but is also less computationally expensive. + * + * @param niter - The new number of internal PGS iterations. + */ + set numInternalPgsIterations(niter: number) { + this.integrationParameters.numInternalPgsIterations = niter; + } + + /** + * The number of substeps continuous collision-detection can run (default: `1`). + */ + get maxCcdSubsteps(): number { + return this.integrationParameters.maxCcdSubsteps; + } + + /** + * Sets the number of substeps continuous collision-detection can run (default: `1`). + * + * CCD operates using a "motion clamping" mechanism where all fast-moving object trajectories will + * be truncated to their first impact on their path. The number of CCD substeps beyond 1 indicate how + * many times that trajectory will be updated and continued after a hit. This can results in smoother + * paths, but at a significant computational cost. + * + * @param niter - The new maximum number of CCD substeps. Setting to `0` disables CCD entirely. + */ + set maxCcdSubsteps(substeps: number) { + this.integrationParameters.maxCcdSubsteps = substeps; + } + + /** + * Creates a new rigid-body from the given rigid-body descriptor. + * + * @param body - The description of the rigid-body to create. + */ + public createRigidBody(body: RigidBodyDesc): RigidBody { + return this.bodies.createRigidBody(this.colliders, body); + } + + /** + * Creates a new character controller. + * + * @param offset - The artificial gap added between the character’s chape and its environment. + */ + public createCharacterController( + offset: number, + ): KinematicCharacterController { + let controller = new KinematicCharacterController( + offset, + this.integrationParameters, + this.broadPhase, + this.narrowPhase, + this.bodies, + this.colliders, + ); + this.characterControllers.add(controller); + return controller; + } + + /** + * Removes a character controller from this world. + * + * @param controller - The character controller to remove. + */ + public removeCharacterController(controller: KinematicCharacterController) { + this.characterControllers.delete(controller); + controller.free(); + } + + /** + * Creates a new PID (Proportional-Integral-Derivative) controller. + * + * @param kp - The Proportional gain applied to the instantaneous linear position errors. + * This is usually set to a multiple of the inverse of simulation step time + * (e.g. `60` if the delta-time is `1.0 / 60.0`). + * @param ki - The linear gain applied to the Integral part of the PID controller. + * @param kd - The Derivative gain applied to the instantaneous linear velocity errors. + * This is usually set to a value in `[0.0, 1.0]` where `0.0` implies no damping + * (no correction of velocity errors) and `1.0` implies complete damping (velocity errors + * are corrected in a single simulation step). + * @param axes - The axes affected by this controller. + * Only coordinate axes with a bit flags set to `true` will be taken into + * account when calculating the errors and corrections. + */ + public createPidController( + kp: number, + ki: number, + kd: number, + axes: PidAxesMask, + ): PidController { + let controller = new PidController( + this.integrationParameters, + this.bodies, + kp, + ki, + kd, + axes, + ); + this.pidControllers.add(controller); + return controller; + } + + /** + * Removes a PID controller from this world. + * + * @param controller - The PID controller to remove. + */ + public removePidController(controller: PidController) { + this.pidControllers.delete(controller); + controller.free(); + } + + // #if DIM3 + /** + * Creates a new vehicle controller. + * + * @param chassis - The rigid-body used as the chassis of the vehicle controller. When the vehicle + * controller is updated, it will change directly the rigid-body’s velocity. This + * rigid-body must be a dynamic or kinematic-velocity-based rigid-body. + */ + public createVehicleController( + chassis: RigidBody, + ): DynamicRayCastVehicleController { + let controller = new DynamicRayCastVehicleController( + chassis, + this.broadPhase, + this.narrowPhase, + this.bodies, + this.colliders, + ); + this.vehicleControllers.add(controller); + return controller; + } + + /** + * Removes a vehicle controller from this world. + * + * @param controller - The vehicle controller to remove. + */ + public removeVehicleController( + controller: DynamicRayCastVehicleController, + ) { + this.vehicleControllers.delete(controller); + controller.free(); + } + + // #endif + + /** + * Creates a new collider. + * + * @param desc - The description of the collider. + * @param parent - The rigid-body this collider is attached to. + */ + public createCollider(desc: ColliderDesc, parent?: RigidBody): Collider { + let parentHandle = parent ? parent.handle : undefined; + return this.colliders.createCollider(this.bodies, desc, parentHandle); + } + + /** + * Creates a new impulse joint from the given joint descriptor. + * + * @param params - The description of the joint to create. + * @param parent1 - The first rigid-body attached to this joint. + * @param parent2 - The second rigid-body attached to this joint. + * @param wakeUp - Should the attached rigid-bodies be awakened? + */ + public createImpulseJoint( + params: JointData, + parent1: RigidBody, + parent2: RigidBody, + wakeUp: boolean, + ): ImpulseJoint { + return this.impulseJoints.createJoint( + this.bodies, + params, + parent1.handle, + parent2.handle, + wakeUp, + ); + } + + /** + * Creates a new multibody joint from the given joint descriptor. + * + * @param params - The description of the joint to create. + * @param parent1 - The first rigid-body attached to this joint. + * @param parent2 - The second rigid-body attached to this joint. + * @param wakeUp - Should the attached rigid-bodies be awakened? + */ + public createMultibodyJoint( + params: JointData, + parent1: RigidBody, + parent2: RigidBody, + wakeUp: boolean, + ): MultibodyJoint { + return this.multibodyJoints.createJoint( + params, + parent1.handle, + parent2.handle, + wakeUp, + ); + } + + /** + * Retrieves a rigid-body from its handle. + * + * @param handle - The integer handle of the rigid-body to retrieve. + */ + public getRigidBody(handle: RigidBodyHandle): RigidBody { + return this.bodies.get(handle); + } + + /** + * Retrieves a collider from its handle. + * + * @param handle - The integer handle of the collider to retrieve. + */ + public getCollider(handle: ColliderHandle): Collider { + return this.colliders.get(handle); + } + + /** + * Retrieves an impulse joint from its handle. + * + * @param handle - The integer handle of the impulse joint to retrieve. + */ + public getImpulseJoint(handle: ImpulseJointHandle): ImpulseJoint { + return this.impulseJoints.get(handle); + } + + /** + * Retrieves an multibody joint from its handle. + * + * @param handle - The integer handle of the multibody joint to retrieve. + */ + public getMultibodyJoint(handle: MultibodyJointHandle): MultibodyJoint { + return this.multibodyJoints.get(handle); + } + + /** + * Removes the given rigid-body from this physics world. + * + * This will remove this rigid-body as well as all its attached colliders and joints. + * Every other bodies touching or attached by joints to this rigid-body will be woken-up. + * + * @param body - The rigid-body to remove. + */ + public removeRigidBody(body: RigidBody) { + if (this.bodies) { + this.bodies.remove( + body.handle, + this.islands, + this.colliders, + this.impulseJoints, + this.multibodyJoints, + ); + } + } + + /** + * Removes the given collider from this physics world. + * + * @param collider - The collider to remove. + * @param wakeUp - If set to `true`, the rigid-body this collider is attached to will be awaken. + */ + public removeCollider(collider: Collider, wakeUp: boolean) { + if (this.colliders) { + this.colliders.remove( + collider.handle, + this.islands, + this.bodies, + wakeUp, + ); + } + } + + /** + * Removes the given impulse joint from this physics world. + * + * @param joint - The impulse joint to remove. + * @param wakeUp - If set to `true`, the rigid-bodies attached by this joint will be awaken. + */ + public removeImpulseJoint(joint: ImpulseJoint, wakeUp: boolean) { + if (this.impulseJoints) { + this.impulseJoints.remove(joint.handle, wakeUp); + } + } + + /** + * Removes the given multibody joint from this physics world. + * + * @param joint - The multibody joint to remove. + * @param wakeUp - If set to `true`, the rigid-bodies attached by this joint will be awaken. + */ + public removeMultibodyJoint(joint: MultibodyJoint, wakeUp: boolean) { + if (this.impulseJoints) { + this.multibodyJoints.remove(joint.handle, wakeUp); + } + } + + /** + * Applies the given closure to each collider managed by this physics world. + * + * @param f(collider) - The function to apply to each collider managed by this physics world. Called as `f(collider)`. + */ + public forEachCollider(f: (collider: Collider) => void) { + this.colliders.forEach(f); + } + + /** + * Applies the given closure to each rigid-body managed by this physics world. + * + * @param f(body) - The function to apply to each rigid-body managed by this physics world. Called as `f(collider)`. + */ + public forEachRigidBody(f: (body: RigidBody) => void) { + this.bodies.forEach(f); + } + + /** + * Applies the given closure to each active rigid-body managed by this physics world. + * + * After a short time of inactivity, a rigid-body is automatically deactivated ("asleep") by + * the physics engine in order to save computational power. A sleeping rigid-body never moves + * unless it is moved manually by the user. + * + * @param f - The function to apply to each active rigid-body managed by this physics world. Called as `f(collider)`. + */ + public forEachActiveRigidBody(f: (body: RigidBody) => void) { + this.bodies.forEachActiveRigidBody(this.islands, f); + } + + /** + * Find the closest intersection between a ray and the physics world. + * + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + * @param filter - The callback to filter out which collider will be hit. + */ + public castRay( + ray: Ray, + maxToi: number, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): RayColliderHit | null { + return this.broadPhase.castRay( + this.narrowPhase, + this.bodies, + this.colliders, + ray, + maxToi, + solid, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Find the closest intersection between a ray and the physics world. + * + * This also computes the normal at the hit point. + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + */ + public castRayAndGetNormal( + ray: Ray, + maxToi: number, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): RayColliderIntersection | null { + return this.broadPhase.castRayAndGetNormal( + this.narrowPhase, + this.bodies, + this.colliders, + ray, + maxToi, + solid, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Cast a ray and collects all the intersections between a ray and the scene. + * + * @param ray - The ray to cast. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the length of the ray to `ray.dir.norm() * maxToi`. + * @param solid - If `false` then the ray will attempt to hit the boundary of a shape, even if its + * origin already lies inside of a shape. In other terms, `true` implies that all shapes are plain, + * whereas `false` implies that all shapes are hollow for this ray-cast. + * @param groups - Used to filter the colliders that can or cannot be hit by the ray. + * @param callback - The callback called once per hit (in no particular order) between a ray and a collider. + * If this callback returns `false`, then the cast will stop and no further hits will be detected/reported. + */ + public intersectionsWithRay( + ray: Ray, + maxToi: number, + solid: boolean, + callback: (intersect: RayColliderIntersection) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ) { + this.broadPhase.intersectionsWithRay( + this.narrowPhase, + this.bodies, + this.colliders, + ray, + maxToi, + solid, + callback, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Gets the handle of up to one collider intersecting the given shape. + * + * @param shapePos - The position of the shape used for the intersection test. + * @param shapeRot - The orientation of the shape used for the intersection test. + * @param shape - The shape used for the intersection test. + * @param groups - The bit groups and filter associated to the ray, in order to only + * hit the colliders with collision groups compatible with the ray's group. + */ + public intersectionWithShape( + shapePos: Vector, + shapeRot: Rotation, + shape: Shape, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): Collider | null { + let handle = this.broadPhase.intersectionWithShape( + this.narrowPhase, + this.bodies, + this.colliders, + shapePos, + shapeRot, + shape, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + return handle != null ? this.colliders.get(handle) : null; + } + + /** + * Find the projection of a point on the closest collider. + * + * @param point - The point to project. + * @param solid - If this is set to `true` then the collider shapes are considered to + * be plain (if the point is located inside of a plain shape, its projection is the point + * itself). If it is set to `false` the collider shapes are considered to be hollow + * (if the point is located inside of an hollow shape, it is projected on the shape's + * boundary). + * @param groups - The bit groups and filter associated to the point to project, in order to only + * project on colliders with collision groups compatible with the ray's group. + */ + public projectPoint( + point: Vector, + solid: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): PointColliderProjection | null { + return this.broadPhase.projectPoint( + this.narrowPhase, + this.bodies, + this.colliders, + point, + solid, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Find the projection of a point on the closest collider. + * + * @param point - The point to project. + * @param groups - The bit groups and filter associated to the point to project, in order to only + * project on colliders with collision groups compatible with the ray's group. + */ + public projectPointAndGetFeature( + point: Vector, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): PointColliderProjection | null { + return this.broadPhase.projectPointAndGetFeature( + this.narrowPhase, + this.bodies, + this.colliders, + point, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Find all the colliders containing the given point. + * + * @param point - The point used for the containment test. + * @param groups - The bit groups and filter associated to the point to test, in order to only + * test on colliders with collision groups compatible with the ray's group. + * @param callback - A function called with the handles of each collider with a shape + * containing the `point`. + */ + public intersectionsWithPoint( + point: Vector, + callback: (handle: Collider) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ) { + this.broadPhase.intersectionsWithPoint( + this.narrowPhase, + this.bodies, + this.colliders, + point, + this.colliders.castClosure(callback), + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Casts a shape at a constant linear velocity and retrieve the first collider it hits. + * This is similar to ray-casting except that we are casting a whole shape instead of + * just a point (the ray origin). + * + * @param shapePos - The initial position of the shape to cast. + * @param shapeRot - The initial rotation of the shape to cast. + * @param shapeVel - The constant velocity of the shape to cast (i.e. the cast direction). + * @param shape - The shape to cast. + * @param targetDistance − If the shape moves closer to this distance from a collider, a hit + * will be returned. + * @param maxToi - The maximum time-of-impact that can be reported by this cast. This effectively + * limits the distance traveled by the shape to `shapeVel.norm() * maxToi`. + * @param stopAtPenetration - If set to `false`, the linear shape-cast won’t immediately stop if + * the shape is penetrating another shape at its starting point **and** its trajectory is such + * that it’s on a path to exit that penetration state. + * @param groups - The bit groups and filter associated to the shape to cast, in order to only + * test on colliders with collision groups compatible with this group. + */ + public castShape( + shapePos: Vector, + shapeRot: Rotation, + shapeVel: Vector, + shape: Shape, + targetDistance: number, + maxToi: number, + stopAtPenetration: boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ): ColliderShapeCastHit | null { + return this.broadPhase.castShape( + this.narrowPhase, + this.bodies, + this.colliders, + shapePos, + shapeRot, + shapeVel, + shape, + targetDistance, + maxToi, + stopAtPenetration, + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Retrieve all the colliders intersecting the given shape. + * + * @param shapePos - The position of the shape to test. + * @param shapeRot - The orientation of the shape to test. + * @param shape - The shape to test. + * @param groups - The bit groups and filter associated to the shape to test, in order to only + * test on colliders with collision groups compatible with this group. + * @param callback - A function called with the handles of each collider intersecting the `shape`. + */ + public intersectionsWithShape( + shapePos: Vector, + shapeRot: Rotation, + shape: Shape, + callback: (collider: Collider) => boolean, + filterFlags?: QueryFilterFlags, + filterGroups?: InteractionGroups, + filterExcludeCollider?: Collider, + filterExcludeRigidBody?: RigidBody, + filterPredicate?: (collider: Collider) => boolean, + ) { + this.broadPhase.intersectionsWithShape( + this.narrowPhase, + this.bodies, + this.colliders, + shapePos, + shapeRot, + shape, + this.colliders.castClosure(callback), + filterFlags, + filterGroups, + filterExcludeCollider ? filterExcludeCollider.handle : null, + filterExcludeRigidBody ? filterExcludeRigidBody.handle : null, + this.colliders.castClosure(filterPredicate), + ); + } + + /** + * Finds the handles of all the colliders with an AABB intersecting the given AABB. + * + * @param aabbCenter - The center of the AABB to test. + * @param aabbHalfExtents - The half-extents of the AABB to test. + * @param callback - The callback that will be called with the handles of all the colliders + * currently intersecting the given AABB. + */ + public collidersWithAabbIntersectingAabb( + aabbCenter: Vector, + aabbHalfExtents: Vector, + callback: (handle: Collider) => boolean, + ) { + this.broadPhase.collidersWithAabbIntersectingAabb( + this.narrowPhase, + this.bodies, + this.colliders, + aabbCenter, + aabbHalfExtents, + this.colliders.castClosure(callback), + ); + } + + /** + * Enumerates all the colliders potentially in contact with the given collider. + * + * @param collider1 - The second collider involved in the contact. + * @param f - Closure that will be called on each collider that is in contact with `collider1`. + */ + public contactPairsWith( + collider1: Collider, + f: (collider2: Collider) => void, + ) { + this.narrowPhase.contactPairsWith( + collider1.handle, + this.colliders.castClosure(f), + ); + } + + /** + * Enumerates all the colliders intersecting the given colliders, assuming one of them + * is a sensor. + */ + public intersectionPairsWith( + collider1: Collider, + f: (collider2: Collider) => void, + ) { + this.narrowPhase.intersectionPairsWith( + collider1.handle, + this.colliders.castClosure(f), + ); + } + + /** + * Iterates through all the contact manifolds between the given pair of colliders. + * + * @param collider1 - The first collider involved in the contact. + * @param collider2 - The second collider involved in the contact. + * @param f - Closure that will be called on each contact manifold between the two colliders. If the second argument + * passed to this closure is `true`, then the contact manifold data is flipped, i.e., methods like `localNormal1` + * actually apply to the `collider2` and fields like `localNormal2` apply to the `collider1`. + */ + public contactPair( + collider1: Collider, + collider2: Collider, + f: (manifold: TempContactManifold, flipped: boolean) => void, + ) { + this.narrowPhase.contactPair(collider1.handle, collider2.handle, f); + } + + /** + * Returns `true` if `collider1` and `collider2` intersect and at least one of them is a sensor. + * @param collider1 − The first collider involved in the intersection. + * @param collider2 − The second collider involved in the intersection. + */ + public intersectionPair(collider1: Collider, collider2: Collider): boolean { + return this.narrowPhase.intersectionPair( + collider1.handle, + collider2.handle, + ); + } + + /** + * Sets whether internal performance profiling is enabled (default: false). + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + set profilerEnabled(enabled: boolean) { + this.physicsPipeline.raw.set_profiler_enabled(enabled); + } + + /** + * Indicates if the internal performance profiling is enabled. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + get profilerEnabled(): boolean { + return this.physicsPipeline.raw.is_profiler_enabled(); + } + + /** + * The time spent in milliseconds by the last step to run the entire simulation step. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingStep(): number { + return this.physicsPipeline.raw.timing_step(); + } + + /** + * The time spent in milliseconds by the last step to run the collision-detection + * (broad-phase + narrow-phase). + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCollisionDetection(): number { + return this.physicsPipeline.raw.timing_collision_detection(); + } + + /** + * The time spent in milliseconds by the last step to run the broad-phase. + * + * This timing is included in `timingCollisionDetection`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingBroadPhase(): number { + return this.physicsPipeline.raw.timing_broad_phase(); + } + + /** + * The time spent in milliseconds by the last step to run the narrow-phase. + * + * This timing is included in `timingCollisionDetection`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingNarrowPhase(): number { + return this.physicsPipeline.raw.timing_narrow_phase(); + } + + /** + * The time spent in milliseconds by the last step to run the constraint solver. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingSolver(): number { + return this.physicsPipeline.raw.timing_solver(); + } + + /** + * The time spent in milliseconds by the last step to run the constraint + * initialization. + * + * This timing is included in `timingSolver`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingVelocityAssembly(): number { + return this.physicsPipeline.raw.timing_velocity_assembly(); + } + + /** + * The time spent in milliseconds by the last step to run the constraint + * resolution. + * + * This timing is included in `timingSolver`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingVelocityResolution(): number { + return this.physicsPipeline.raw.timing_velocity_resolution(); + } + + /** + * The time spent in milliseconds by the last step to run the rigid-body + * velocity update. + * + * This timing is included in `timingSolver`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingVelocityUpdate(): number { + return this.physicsPipeline.raw.timing_velocity_update(); + } + + /** + * The time spent in milliseconds by writing rigid-body velocities + * calculated by the solver back into the rigid-bodies. + * + * This timing is included in `timingSolver`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingVelocityWriteback(): number { + return this.physicsPipeline.raw.timing_velocity_writeback(); + } + + /** + * The total time spent in CCD detection and resolution. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCcd(): number { + return this.physicsPipeline.raw.timing_ccd(); + } + + /** + * The total time spent searching for the continuous hits during CCD. + * + * This timing is included in `timingCcd`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCcdToiComputation(): number { + return this.physicsPipeline.raw.timing_ccd_toi_computation(); + } + + /** + * The total time spent in the broad-phase during CCD. + * + * This timing is included in `timingCcd`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCcdBroadPhase(): number { + return this.physicsPipeline.raw.timing_ccd_broad_phase(); + } + + /** + * The total time spent in the narrow-phase during CCD. + * + * This timing is included in `timingCcd`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCcdNarrowPhase(): number { + return this.physicsPipeline.raw.timing_ccd_narrow_phase(); + } + + /** + * The total time spent in the constraints resolution during CCD. + * + * This timing is included in `timingCcd`. + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingCcdSolver(): number { + return this.physicsPipeline.raw.timing_ccd_solver(); + } + + /** + * The total time spent in the islands calculation during CCD. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingIslandConstruction(): number { + return this.physicsPipeline.raw.timing_island_construction(); + } + + /** + * The total time spent propagating detected user changes. + * + * Only works if the internal profiler is enabled with `World.profilerEnabled = true`. + */ + public timingUserChanges(): number { + return this.physicsPipeline.raw.timing_user_changes(); + } +} diff --git a/typescript/src.ts/rapier.ts b/typescript/src.ts/rapier.ts new file mode 100644 index 000000000..dbf4d053a --- /dev/null +++ b/typescript/src.ts/rapier.ts @@ -0,0 +1,3 @@ +import * as RAPIER from "./exports"; +export * from "./exports"; +export default RAPIER; diff --git a/typescript/src.ts/raw.ts b/typescript/src.ts/raw.ts new file mode 100644 index 000000000..51f837b78 --- /dev/null +++ b/typescript/src.ts/raw.ts @@ -0,0 +1 @@ +export * from "../rapier3d/pkg/rapier_wasm3d"; diff --git a/typescript/src/control/character_controller.rs b/typescript/src/control/character_controller.rs new file mode 100644 index 000000000..8456624ea --- /dev/null +++ b/typescript/src/control/character_controller.rs @@ -0,0 +1,366 @@ +use crate::dynamics::RawRigidBodySet; +use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase}; +use crate::math::RawVector; +use crate::utils::{self, FlatHandle}; +use rapier::control::{ + CharacterAutostep, CharacterCollision, CharacterLength, EffectiveCharacterMovement, + KinematicCharacterController, +}; +use rapier::geometry::{ColliderHandle, ShapeCastHit}; +use rapier::math::{Pose, Real, Vector}; +use rapier::parry::query::ShapeCastStatus; +use rapier::pipeline::{QueryFilter, QueryFilterFlags}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawKinematicCharacterController { + controller: KinematicCharacterController, + result: EffectiveCharacterMovement, + events: Vec, +} + +fn length_value(length: CharacterLength) -> Real { + match length { + CharacterLength::Absolute(val) => val, + CharacterLength::Relative(val) => val, + } +} +#[wasm_bindgen] +impl RawKinematicCharacterController { + #[wasm_bindgen(constructor)] + pub fn new(offset: Real) -> Self { + let controller = KinematicCharacterController { + offset: CharacterLength::Absolute(offset), + autostep: None, + snap_to_ground: None, + ..KinematicCharacterController::default() + }; + + Self { + controller, + result: EffectiveCharacterMovement { + translation: Vector::ZERO, + grounded: false, + is_sliding_down_slope: false, + }, + events: vec![], + } + } + + pub fn up(&self) -> RawVector { + self.controller.up.into() + } + + pub fn setUp(&mut self, vector: &RawVector) { + self.controller.up = vector.0.normalize(); + } + + pub fn normalNudgeFactor(&self) -> Real { + self.controller.normal_nudge_factor + } + + pub fn setNormalNudgeFactor(&mut self, value: Real) { + self.controller.normal_nudge_factor = value; + } + + pub fn offset(&self) -> Real { + length_value(self.controller.offset) + } + + pub fn setOffset(&mut self, value: Real) { + self.controller.offset = CharacterLength::Absolute(value); + } + + pub fn slideEnabled(&self) -> bool { + self.controller.slide + } + + pub fn setSlideEnabled(&mut self, enabled: bool) { + self.controller.slide = enabled + } + + pub fn autostepMaxHeight(&self) -> Option { + self.controller.autostep.map(|e| length_value(e.max_height)) + } + + pub fn autostepMinWidth(&self) -> Option { + self.controller.autostep.map(|e| length_value(e.min_width)) + } + + pub fn autostepIncludesDynamicBodies(&self) -> Option { + self.controller.autostep.map(|e| e.include_dynamic_bodies) + } + + pub fn autostepEnabled(&self) -> bool { + self.controller.autostep.is_some() + } + + pub fn enableAutostep(&mut self, maxHeight: Real, minWidth: Real, includeDynamicBodies: bool) { + self.controller.autostep = Some(CharacterAutostep { + min_width: CharacterLength::Absolute(minWidth), + max_height: CharacterLength::Absolute(maxHeight), + include_dynamic_bodies: includeDynamicBodies, + }) + } + + pub fn disableAutostep(&mut self) { + self.controller.autostep = None; + } + + pub fn maxSlopeClimbAngle(&self) -> Real { + self.controller.max_slope_climb_angle + } + + pub fn setMaxSlopeClimbAngle(&mut self, angle: Real) { + self.controller.max_slope_climb_angle = angle; + } + + pub fn minSlopeSlideAngle(&self) -> Real { + self.controller.min_slope_slide_angle + } + + pub fn setMinSlopeSlideAngle(&mut self, angle: Real) { + self.controller.min_slope_slide_angle = angle + } + + pub fn snapToGroundDistance(&self) -> Option { + self.controller.snap_to_ground.map(length_value) + } + + pub fn enableSnapToGround(&mut self, distance: Real) { + self.controller.snap_to_ground = Some(CharacterLength::Absolute(distance)); + } + + pub fn disableSnapToGround(&mut self) { + self.controller.snap_to_ground = None; + } + + pub fn snapToGroundEnabled(&self) -> bool { + self.controller.snap_to_ground.is_some() + } + + pub fn computeColliderMovement( + &mut self, + dt: Real, + broad_phase: &RawBroadPhase, + narrow_phase: &RawNarrowPhase, + bodies: &mut RawRigidBodySet, + colliders: &mut RawColliderSet, + collider_handle: FlatHandle, + desired_translation_delta: &RawVector, + apply_impulses_to_dynamic_bodies: bool, + character_mass: Option, + filter_flags: u32, + filter_groups: Option, + filter_predicate: &js_sys::Function, + ) { + let handle = crate::utils::collider_handle(collider_handle); + if let Some(collider) = colliders.0.get(handle) { + let collider_pose = *collider.position(); + let collider_shape = collider.shared_shape().clone(); + let collider_parent = collider.parent(); + + crate::utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: Some(handle), + exclude_rigid_body: collider_parent, + predicate, + }; + + let character_mass = character_mass + .or_else(|| { + collider_parent + .and_then(|h| bodies.0.get(h)) + .map(|b| b.mass()) + }) + .unwrap_or(0.0); + + let mut query_pipeline = broad_phase.0.as_query_pipeline_mut( + narrow_phase.0.query_dispatcher(), + &mut bodies.0, + &mut colliders.0, + query_filter, + ); + + self.events.clear(); + let events = &mut self.events; + self.result = self.controller.move_shape( + dt, + &query_pipeline.as_ref(), + &*collider_shape, + &collider_pose, + desired_translation_delta.0, + |event| events.push(event), + ); + + if apply_impulses_to_dynamic_bodies { + self.controller.solve_character_collision_impulses( + dt, + &mut query_pipeline, + &*collider_shape, + character_mass, + self.events.iter(), + ); + } + }); + } else { + self.result.translation = Vector::ZERO; + } + } + + #[cfg(feature = "dim2")] + pub fn computedMovement(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.result.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn computedMovement(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.result.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn computedGrounded(&self) -> bool { + self.result.grounded + } + + pub fn numComputedCollisions(&self) -> usize { + self.events.len() + } + + pub fn computedCollision(&self, i: usize, collision: &mut RawCharacterCollision) -> bool { + if let Some(coll) = self.events.get(i) { + collision.0 = *coll; + } + + i < self.events.len() + } +} + +#[wasm_bindgen] +pub struct RawCharacterCollision(CharacterCollision); + +#[wasm_bindgen] +impl RawCharacterCollision { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self(CharacterCollision { + handle: ColliderHandle::invalid(), + character_pos: Pose::identity(), + translation_applied: Vector::ZERO, + translation_remaining: Vector::ZERO, + hit: ShapeCastHit { + time_of_impact: 0.0, + witness1: Vector::ZERO, + witness2: Vector::ZERO, + normal1: Vector::Y, + normal2: Vector::Y, + status: ShapeCastStatus::Failed, + }, + }) + } + + pub fn handle(&self) -> FlatHandle { + utils::flat_handle(self.0.handle.0) + } + + #[cfg(feature = "dim2")] + pub fn translationDeltaApplied(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.translation_applied; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn translationDeltaApplied(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.translation_applied; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + #[cfg(feature = "dim2")] + pub fn translationDeltaRemaining(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.translation_remaining; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn translationDeltaRemaining(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.translation_remaining; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn toi(&self) -> Real { + self.0.hit.time_of_impact + } + + #[cfg(feature = "dim2")] + pub fn worldWitness1(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.hit.witness1; // Already in world-space. + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn worldWitness1(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.hit.witness1; // Already in world-space. + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + #[cfg(feature = "dim2")] + pub fn worldWitness2(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.character_pos.transform_point(self.0.hit.witness2); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn worldWitness2(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.character_pos.transform_point(self.0.hit.witness2); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + #[cfg(feature = "dim2")] + pub fn worldNormal1(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.hit.normal1; // Already in world-space. + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn worldNormal1(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.hit.normal1; // Already in world-space. + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + #[cfg(feature = "dim2")] + pub fn worldNormal2(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.character_pos.transform_vector(self.0.hit.normal2); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + #[cfg(feature = "dim3")] + pub fn worldNormal2(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.character_pos.transform_vector(self.0.hit.normal2); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } +} diff --git a/typescript/src/control/mod.rs b/typescript/src/control/mod.rs new file mode 100644 index 000000000..74352c2ba --- /dev/null +++ b/typescript/src/control/mod.rs @@ -0,0 +1,11 @@ +pub use self::character_controller::RawKinematicCharacterController; +pub use self::pid_controller::RawPidController; + +#[cfg(feature = "dim3")] +pub use self::ray_cast_vehicle_controller::RawDynamicRayCastVehicleController; + +mod character_controller; +mod pid_controller; + +#[cfg(feature = "dim3")] +mod ray_cast_vehicle_controller; diff --git a/typescript/src/control/pid_controller.rs b/typescript/src/control/pid_controller.rs new file mode 100644 index 000000000..a29eb684f --- /dev/null +++ b/typescript/src/control/pid_controller.rs @@ -0,0 +1,286 @@ +use crate::dynamics::RawRigidBodySet; +use crate::math::RawVector; +use crate::utils::{self, FlatHandle}; +use rapier::control::PidController; +use rapier::dynamics::AxesMask; +use rapier::math::Vector; +use wasm_bindgen::prelude::*; + +#[cfg(feature = "dim3")] +use crate::math::RawRotation; +#[cfg(feature = "dim2")] +use rapier::math::Rotation; + +#[wasm_bindgen] +pub struct RawPidController { + controller: PidController, +} + +#[wasm_bindgen] +impl RawPidController { + #[wasm_bindgen(constructor)] + pub fn new(kp: f32, ki: f32, kd: f32, axes_mask: u8) -> Self { + let controller = PidController::new( + kp, + ki, + kd, + AxesMask::from_bits(axes_mask).unwrap_or(AxesMask::all()), + ); + Self { controller } + } + + pub fn set_kp(&mut self, kp: f32, axes: u8) { + let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all()); + if axes.contains(AxesMask::LIN_X) { + self.controller.pd.lin_kp.x = kp; + } + if axes.contains(AxesMask::LIN_Y) { + self.controller.pd.lin_kp.y = kp; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::LIN_Z) { + self.controller.pd.lin_kp.z = kp; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_X) { + self.controller.pd.ang_kp.x = kp; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_Y) { + self.controller.pd.ang_kp.y = kp; + } + if axes.contains(AxesMask::ANG_Z) { + #[cfg(feature = "dim2")] + { + self.controller.pd.ang_kp = kp; + } + #[cfg(feature = "dim3")] + { + self.controller.pd.ang_kp.z = kp; + } + } + } + + pub fn set_ki(&mut self, ki: f32, axes: u8) { + let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all()); + if axes.contains(AxesMask::LIN_X) { + self.controller.lin_ki.x = ki; + } + if axes.contains(AxesMask::LIN_Y) { + self.controller.lin_ki.y = ki; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::LIN_Z) { + self.controller.lin_ki.z = ki; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_X) { + self.controller.ang_ki.x = ki; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_Y) { + self.controller.ang_ki.y = ki; + } + if axes.contains(AxesMask::ANG_Z) { + #[cfg(feature = "dim2")] + { + self.controller.ang_ki = ki; + } + #[cfg(feature = "dim3")] + { + self.controller.ang_ki.z = ki; + } + } + } + + pub fn set_kd(&mut self, kd: f32, axes: u8) { + let axes = AxesMask::from_bits(axes).unwrap_or(AxesMask::all()); + if axes.contains(AxesMask::LIN_X) { + self.controller.pd.lin_kd.x = kd; + } + if axes.contains(AxesMask::LIN_Y) { + self.controller.pd.lin_kd.x = kd; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::LIN_Z) { + self.controller.pd.lin_kd.x = kd; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_X) { + self.controller.pd.ang_kd.x = kd; + } + #[cfg(feature = "dim3")] + if axes.contains(AxesMask::ANG_Y) { + self.controller.pd.ang_kd.y = kd; + } + if axes.contains(AxesMask::ANG_Z) { + #[cfg(feature = "dim2")] + { + self.controller.pd.ang_kd = kd; + } + #[cfg(feature = "dim3")] + { + self.controller.pd.ang_kd.z = kd; + } + } + } + + pub fn set_axes_mask(&mut self, axes_mask: u8) { + if let Some(mask) = AxesMask::from_bits(axes_mask) { + self.controller.pd.axes = mask; + } + } + + pub fn reset_integrals(&mut self) { + self.controller.reset_integrals(); + } + + pub fn apply_linear_correction( + &mut self, + dt: f32, + bodies: &mut RawRigidBodySet, + rb_handle: FlatHandle, + target_translation: &RawVector, + target_linvel: &RawVector, + ) { + let rb_handle = utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get_mut(rb_handle) else { + return; + }; + + let correction = self.controller.linear_rigid_body_correction( + dt, + rb, + target_translation.0.into(), + target_linvel.0, + ); + rb.set_linvel(rb.linvel() + correction, true); + } + + #[cfg(feature = "dim2")] + pub fn apply_angular_correction( + &mut self, + dt: f32, + bodies: &mut RawRigidBodySet, + rb_handle: FlatHandle, + target_rotation: f32, + target_angvel: f32, + ) { + let rb_handle = crate::utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get_mut(rb_handle) else { + return; + }; + + let correction = self.controller.angular_rigid_body_correction( + dt, + rb, + Rotation::new(target_rotation), + target_angvel, + ); + rb.set_angvel(rb.angvel() + correction, true); + } + + #[cfg(feature = "dim3")] + pub fn apply_angular_correction( + &mut self, + dt: f32, + bodies: &mut RawRigidBodySet, + rb_handle: FlatHandle, + target_rotation: &RawRotation, + target_angvel: &RawVector, + ) { + let rb_handle = crate::utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get_mut(rb_handle) else { + return; + }; + + let correction = self.controller.angular_rigid_body_correction( + dt, + rb, + target_rotation.0, + target_angvel.0, + ); + rb.set_angvel(rb.angvel() + correction, true); + } + + pub fn linear_correction( + &mut self, + dt: f32, + bodies: &RawRigidBodySet, + rb_handle: FlatHandle, + target_translation: &RawVector, + target_linvel: &RawVector, + scratch_buffer: &js_sys::Float32Array, + ) { + let rb_handle = crate::utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get(rb_handle) else { + scratch_buffer.set_index(0, 0.0); + scratch_buffer.set_index(1, 0.0); + #[cfg(feature = "dim3")] + scratch_buffer.set_index(2, 0.0); + return; + }; + + let u: Vector = self.controller.linear_rigid_body_correction( + dt, + rb, + target_translation.0.into(), + target_linvel.0, + ); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + #[cfg(feature = "dim3")] + scratch_buffer.set_index(2, u.z); + } + + #[cfg(feature = "dim2")] + pub fn angular_correction( + &mut self, + dt: f32, + bodies: &RawRigidBodySet, + rb_handle: FlatHandle, + target_rotation: f32, + target_angvel: f32, + ) -> f32 { + let rb_handle = crate::utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get(rb_handle) else { + return 0.0; + }; + + self.controller.angular_rigid_body_correction( + dt, + rb, + Rotation::new(target_rotation), + target_angvel, + ) + } + + #[cfg(feature = "dim3")] + pub fn angular_correction( + &mut self, + dt: f32, + bodies: &RawRigidBodySet, + rb_handle: FlatHandle, + target_rotation: &RawRotation, + target_angvel: &RawVector, + scratch_buffer: &js_sys::Float32Array, + ) { + let rb_handle = crate::utils::body_handle(rb_handle); + let Some(rb) = bodies.0.get(rb_handle) else { + scratch_buffer.set_index(0, 0.0); + scratch_buffer.set_index(1, 0.0); + scratch_buffer.set_index(2, 0.0); + return; + }; + + let u: Vector = self.controller.angular_rigid_body_correction( + dt, + rb, + target_rotation.0, + target_angvel.0, + ); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } +} diff --git a/typescript/src/control/ray_cast_vehicle_controller.rs b/typescript/src/control/ray_cast_vehicle_controller.rs new file mode 100644 index 000000000..445037ceb --- /dev/null +++ b/typescript/src/control/ray_cast_vehicle_controller.rs @@ -0,0 +1,434 @@ +use crate::dynamics::RawRigidBodySet; +use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase}; +use crate::math::RawVector; +use crate::utils::{self, FlatHandle}; +use rapier::control::{DynamicRayCastVehicleController, WheelTuning}; +use rapier::math::Real; +use rapier::pipeline::{QueryFilter, QueryFilterFlags}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawDynamicRayCastVehicleController { + controller: DynamicRayCastVehicleController, +} + +#[wasm_bindgen] +impl RawDynamicRayCastVehicleController { + #[wasm_bindgen(constructor)] + pub fn new(chassis: FlatHandle) -> Self { + Self { + controller: DynamicRayCastVehicleController::new(utils::body_handle(chassis)), + } + } + + pub fn current_vehicle_speed(&self) -> Real { + self.controller.current_vehicle_speed + } + + pub fn chassis(&self) -> FlatHandle { + utils::flat_handle(self.controller.chassis.0) + } + + pub fn index_up_axis(&self) -> usize { + self.controller.index_up_axis + } + pub fn set_index_up_axis(&mut self, axis: usize) { + self.controller.index_up_axis = axis; + } + + pub fn index_forward_axis(&self) -> usize { + self.controller.index_forward_axis + } + pub fn set_index_forward_axis(&mut self, axis: usize) { + self.controller.index_forward_axis = axis; + } + + pub fn add_wheel( + &mut self, + chassis_connection_cs: &RawVector, + direction_cs: &RawVector, + axle_cs: &RawVector, + suspension_rest_length: Real, + radius: Real, + ) { + self.controller.add_wheel( + chassis_connection_cs.0.into(), + direction_cs.0, + axle_cs.0, + suspension_rest_length, + radius, + &WheelTuning::default(), + ); + } + + pub fn num_wheels(&self) -> usize { + self.controller.wheels().len() + } + + pub fn update_vehicle( + &mut self, + dt: Real, + broad_phase: &RawBroadPhase, + narrow_phase: &RawNarrowPhase, + bodies: &mut RawRigidBodySet, + colliders: &mut RawColliderSet, + filter_flags: u32, + filter_groups: Option, + filter_predicate: &js_sys::Function, + ) { + crate::utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + predicate, + exclude_rigid_body: Some(self.controller.chassis), + exclude_collider: None, + }; + + let query_pipeline = broad_phase.0.as_query_pipeline_mut( + narrow_phase.0.query_dispatcher(), + &mut bodies.0, + &mut colliders.0, + query_filter, + ); + + self.controller.update_vehicle(dt, query_pipeline); + }); + } + + /* + * + * Access to wheel properties. + * + */ + /* + * Getters + setters + */ + #[cfg(feature = "dim2")] + pub fn wheel_chassis_connection_point_cs( + &self, + i: usize, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.chassis_connection_point_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_chassis_connection_point_cs( + &self, + i: usize, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.chassis_connection_point_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + pub fn set_wheel_chassis_connection_point_cs(&mut self, i: usize, value: &RawVector) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.chassis_connection_point_cs = value.0.into(); + } + } + + pub fn wheel_suspension_rest_length(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.suspension_rest_length) + } + pub fn set_wheel_suspension_rest_length(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.suspension_rest_length = value; + } + } + + pub fn wheel_max_suspension_travel(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.max_suspension_travel) + } + pub fn set_wheel_max_suspension_travel(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.max_suspension_travel = value; + } + } + + pub fn wheel_radius(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.radius) + } + pub fn set_wheel_radius(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.radius = value; + } + } + + pub fn wheel_suspension_stiffness(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.suspension_stiffness) + } + pub fn set_wheel_suspension_stiffness(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.suspension_stiffness = value; + } + } + + pub fn wheel_suspension_compression(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.damping_compression) + } + pub fn set_wheel_suspension_compression(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.damping_compression = value; + } + } + + pub fn wheel_suspension_relaxation(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.damping_relaxation) + } + pub fn set_wheel_suspension_relaxation(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.damping_relaxation = value; + } + } + + pub fn wheel_max_suspension_force(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.max_suspension_force) + } + pub fn set_wheel_max_suspension_force(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.max_suspension_force = value; + } + } + + pub fn wheel_brake(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.brake) + } + pub fn set_wheel_brake(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.brake = value; + } + } + + pub fn wheel_steering(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.steering) + } + pub fn set_wheel_steering(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.steering = value; + } + } + + pub fn wheel_engine_force(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.engine_force) + } + pub fn set_wheel_engine_force(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.engine_force = value; + } + } + + #[cfg(feature = "dim2")] + pub fn wheel_direction_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.direction_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_direction_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.direction_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + pub fn set_wheel_direction_cs(&mut self, i: usize, value: &RawVector) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.direction_cs = value.0; + } + } + + #[cfg(feature = "dim2")] + pub fn wheel_axle_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.axle_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_axle_cs(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.axle_cs; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + pub fn set_wheel_axle_cs(&mut self, i: usize, value: &RawVector) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.axle_cs = value.0; + } + } + + pub fn wheel_friction_slip(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.friction_slip) + } + pub fn set_wheel_friction_slip(&mut self, i: usize, value: Real) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.friction_slip = value; + } + } + + pub fn wheel_side_friction_stiffness(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.side_friction_stiffness) + } + + pub fn set_wheel_side_friction_stiffness(&mut self, i: usize, stiffness: f32) { + if let Some(wheel) = self.controller.wheels_mut().get_mut(i) { + wheel.side_friction_stiffness = stiffness; + } + } + + /* + * Getters only. + */ + pub fn wheel_rotation(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.rotation) + } + + pub fn wheel_forward_impulse(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.forward_impulse) + } + + pub fn wheel_side_impulse(&self, i: usize) -> Option { + self.controller.wheels().get(i).map(|w| w.side_impulse) + } + + pub fn wheel_suspension_force(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.wheel_suspension_force) + } + + #[cfg(feature = "dim2")] + pub fn wheel_contact_normal_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_normal_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_contact_normal_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_normal_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + #[cfg(feature = "dim2")] + pub fn wheel_contact_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_contact_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().contact_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + pub fn wheel_suspension_length(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .map(|w| w.raycast_info().suspension_length) + } + + #[cfg(feature = "dim2")] + pub fn wheel_hard_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().hard_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + + #[cfg(feature = "dim3")] + pub fn wheel_hard_point_ws(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + self.controller.wheels().get(i).map_or(false, |w| { + let u = w.raycast_info().hard_point_ws; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + + pub fn wheel_is_in_contact(&self, i: usize) -> bool { + self.controller + .wheels() + .get(i) + .map(|w| w.raycast_info().is_in_contact) + .unwrap_or(false) + } + + pub fn wheel_ground_object(&self, i: usize) -> Option { + self.controller + .wheels() + .get(i) + .and_then(|w| w.raycast_info().ground_object) + .map(|h| utils::flat_handle(h.0)) + } +} diff --git a/typescript/src/dynamics/ccd_solver.rs b/typescript/src/dynamics/ccd_solver.rs new file mode 100644 index 000000000..4c8b54f8c --- /dev/null +++ b/typescript/src/dynamics/ccd_solver.rs @@ -0,0 +1,13 @@ +use rapier::dynamics::CCDSolver; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawCCDSolver(pub(crate) CCDSolver); + +#[wasm_bindgen] +impl RawCCDSolver { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawCCDSolver(CCDSolver::new()) + } +} diff --git a/typescript/src/dynamics/impulse_joint.rs b/typescript/src/dynamics/impulse_joint.rs new file mode 100644 index 000000000..e8b24510e --- /dev/null +++ b/typescript/src/dynamics/impulse_joint.rs @@ -0,0 +1,314 @@ +use crate::dynamics::{RawImpulseJointSet, RawJointAxis, RawJointType, RawMotorModel}; +use crate::math::{RawRotation, RawVector}; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::JointAxis; +use rapier::math::Pose; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +impl RawImpulseJointSet { + /// The type of this joint. + pub fn jointType(&self, handle: FlatHandle) -> RawJointType { + self.map(handle, |j| j.data.locked_axes.into()) + } + + /// The unique integer identifier of the first rigid-body this joint it attached to. + pub fn jointBodyHandle1(&self, handle: FlatHandle) -> FlatHandle { + self.map(handle, |j| utils::flat_handle(j.body1().0)) + } + + /// The unique integer identifier of the second rigid-body this joint is attached to. + pub fn jointBodyHandle2(&self, handle: FlatHandle) -> FlatHandle { + self.map(handle, |j| utils::flat_handle(j.body2().0)) + } + + /// The angular part of the joint’s local frame relative to the first rigid-body it is attached to. + #[cfg(feature = "dim3")] + pub fn jointFrameX1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// The angular part of the joint’s local frame relative to the second rigid-body it is attached to. + #[cfg(feature = "dim3")] + pub fn jointFrameX2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// The position of the first anchor of this joint. + /// + /// The first anchor gives the position of the points application point on the + /// local frame of the first rigid-body it is attached to. + #[cfg(feature = "dim2")] + pub fn jointAnchor1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + #[cfg(feature = "dim3")] + pub fn jointAnchor1(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame1.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + #[cfg(feature = "dim2")] + pub fn jointAnchor2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + #[cfg(feature = "dim3")] + pub fn jointAnchor2(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |j| { + let u = j.data.local_frame2.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// Sets the position of the first local anchor + pub fn jointSetAnchor1(&mut self, handle: FlatHandle, newPos: &RawVector) { + self.map_mut(handle, |j| { + j.data.set_local_anchor1(newPos.0.into()); + }); + } + + /// Sets the position of the second local anchor + pub fn jointSetAnchor2(&mut self, handle: FlatHandle, newPos: &RawVector) { + self.map_mut(handle, |j| { + j.data.set_local_anchor2(newPos.0.into()); + }) + } + + /// Sets the angular part of the joint's local frame relative to the first rigid-body. + pub fn jointSetFrameX1(&mut self, handle: FlatHandle, newRot: &RawRotation) { + self.map_mut(handle, |j| { + j.data.local_frame1.rotation = newRot.0; + }); + } + + /// Sets the angular part of the joint's local frame relative to the second rigid-body. + pub fn jointSetFrameX2(&mut self, handle: FlatHandle, newRot: &RawRotation) { + self.map_mut(handle, |j| { + j.data.local_frame2.rotation = newRot.0; + }); + } + + /// Sets the full local frame (anchor + rotation) for the first rigid-body attachment. + pub fn jointSetLocalFrame1( + &mut self, + handle: FlatHandle, + anchor: &RawVector, + rot: &RawRotation, + ) { + self.map_mut(handle, |j| { + j.data + .set_local_frame1(Pose::from_parts(anchor.0, rot.0)); + }); + } + + /// Sets the full local frame (anchor + rotation) for the second rigid-body attachment. + pub fn jointSetLocalFrame2( + &mut self, + handle: FlatHandle, + anchor: &RawVector, + rot: &RawRotation, + ) { + self.map_mut(handle, |j| { + j.data + .set_local_frame2(Pose::from_parts(anchor.0, rot.0)); + }); + } + + /// Are contacts between the rigid-bodies attached by this joint enabled? + pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool { + self.map(handle, |j| j.data.contacts_enabled) + } + + /// Sets whether contacts are enabled between the rigid-bodies attached by this joint. + pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) { + self.map_mut(handle, |j| { + j.data.contacts_enabled = enabled; + }); + } + + /// Are the limits for this joint enabled? + pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool { + self.map(handle, |j| { + j.data.limit_axes.contains(JointAxis::from(axis).into()) + }) + } + + /// Return the lower limit along the given joint axis. + pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 { + self.map(handle, |j| j.data.limits[axis as usize].min) + } + + /// If this is a prismatic joint, returns its upper limit. + pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 { + self.map(handle, |j| j.data.limits[axis as usize].max) + } + + /// Enables and sets the joint limits + pub fn jointSetLimits(&mut self, handle: FlatHandle, axis: RawJointAxis, min: f32, max: f32) { + self.map_mut(handle, |j| { + j.data.set_limits(axis.into(), [min, max]); + }); + } + + pub fn jointConfigureMotorModel( + &mut self, + handle: FlatHandle, + axis: RawJointAxis, + model: RawMotorModel, + ) { + self.map_mut(handle, |j| { + j.data.motors[axis as usize].model = model.into() + }) + } + + pub fn jointSetMotorMaxForce(&mut self, handle: FlatHandle, axis: RawJointAxis, maxForce: f32) { + self.map_mut(handle, |j| { + j.data.set_motor_max_force(axis.into(), maxForce); + }) + } + + /* + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotorVelocity( + &mut self, + handle: FlatHandle, + vx: f32, + vy: f32, + vz: f32, + factor: f32, + ) { + let targetVel = Vector3::new(vx, vy, vz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor), + _ => {} + }) + } + + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotorPosition( + &mut self, + handle: FlatHandle, + qw: f32, + qx: f32, + qy: f32, + qz: f32, + stiffness: f32, + damping: f32, + ) { + let quat = Quaternion::new(qw, qx, qy, qz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => { + if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) { + j.configure_motor_position(unit_quat, stiffness, damping) + } + } + _ => {} + }) + } + + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotor( + &mut self, + handle: FlatHandle, + qw: f32, + qx: f32, + qy: f32, + qz: f32, + vx: f32, + vy: f32, + vz: f32, + stiffness: f32, + damping: f32, + ) { + let quat = Quaternion::new(qw, qx, qy, qz); + let vel = Vector3::new(vx, vy, vz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => { + if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) { + j.configure_motor(unit_quat, vel, stiffness, damping) + } + } + _ => {} + }) + } + */ + + pub fn jointConfigureMotorVelocity( + &mut self, + handle: FlatHandle, + axis: RawJointAxis, + targetVel: f32, + factor: f32, + ) { + self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor) + } + + pub fn jointConfigureMotorPosition( + &mut self, + handle: FlatHandle, + axis: RawJointAxis, + targetPos: f32, + stiffness: f32, + damping: f32, + ) { + self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping) + } + + pub fn jointConfigureMotor( + &mut self, + handle: FlatHandle, + axis: RawJointAxis, + targetPos: f32, + targetVel: f32, + stiffness: f32, + damping: f32, + ) { + self.map_mut(handle, |j| { + j.data + .set_motor(axis.into(), targetPos, targetVel, stiffness, damping); + }) + } +} diff --git a/typescript/src/dynamics/impulse_joint_set.rs b/typescript/src/dynamics/impulse_joint_set.rs new file mode 100644 index 000000000..b7ba1bf08 --- /dev/null +++ b/typescript/src/dynamics/impulse_joint_set.rs @@ -0,0 +1,92 @@ +use crate::dynamics::RawGenericJoint; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::{ImpulseJoint, ImpulseJointSet}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawImpulseJointSet(pub(crate) ImpulseJointSet); + +impl RawImpulseJointSet { + pub(crate) fn map(&self, handle: FlatHandle, f: impl FnOnce(&ImpulseJoint) -> T) -> T { + let body = self.0.get(utils::impulse_joint_handle(handle)).expect( + "Invalid ImpulseJoint reference. It may have been removed from the physics World.", + ); + f(body) + } + + pub(crate) fn map_mut( + &mut self, + handle: FlatHandle, + f: impl FnOnce(&mut ImpulseJoint) -> T, + ) -> T { + let body = self + .0 + .get_mut(utils::impulse_joint_handle(handle), true) + .expect( + "Invalid ImpulseJoint reference. It may have been removed from the physics World.", + ); + f(body) + } +} + +#[wasm_bindgen] +impl RawImpulseJointSet { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawImpulseJointSet(ImpulseJointSet::new()) + } + + pub fn createJoint( + &mut self, + params: &RawGenericJoint, + parent1: FlatHandle, + parent2: FlatHandle, + wake_up: bool, + ) -> FlatHandle { + utils::flat_handle( + self.0 + .insert( + utils::body_handle(parent1), + utils::body_handle(parent2), + params.0.clone(), + wake_up, + ) + .0, + ) + } + + pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) { + let handle = utils::impulse_joint_handle(handle); + self.0.remove(handle, wakeUp); + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn contains(&self, handle: FlatHandle) -> bool { + self.0.get(utils::impulse_joint_handle(handle)).is_some() + } + + /// Applies the given JavaScript function to the integer handle of each joint managed by this physics world. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`. + pub fn forEachJointHandle(&self, f: &js_sys::Function) { + let this = JsValue::null(); + for (handle, _) in self.0.iter() { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } + + /// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`. + pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) { + let this = JsValue::null(); + for (_, _, handle, _) in self.0.attached_joints(utils::body_handle(body)) { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } +} diff --git a/typescript/src/dynamics/integration_parameters.rs b/typescript/src/dynamics/integration_parameters.rs new file mode 100644 index 000000000..6aac0b517 --- /dev/null +++ b/typescript/src/dynamics/integration_parameters.rs @@ -0,0 +1,101 @@ +use rapier::dynamics::IntegrationParameters; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawIntegrationParameters(pub(crate) IntegrationParameters); + +#[wasm_bindgen] +impl RawIntegrationParameters { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawIntegrationParameters(IntegrationParameters::default()) + } + + #[wasm_bindgen(getter)] + pub fn dt(&self) -> f32 { + self.0.dt + } + + #[wasm_bindgen(getter)] + pub fn contact_erp(&self) -> f32 { + self.0.contact_softness.erp(self.0.dt) + } + + #[wasm_bindgen(getter)] + pub fn normalizedAllowedLinearError(&self) -> f32 { + self.0.normalized_allowed_linear_error + } + + #[wasm_bindgen(getter)] + pub fn normalizedPredictionDistance(&self) -> f32 { + self.0.normalized_prediction_distance + } + + #[wasm_bindgen(getter)] + pub fn numSolverIterations(&self) -> usize { + self.0.num_solver_iterations + } + + #[wasm_bindgen(getter)] + pub fn numInternalPgsIterations(&self) -> usize { + self.0.num_internal_pgs_iterations + } + + #[wasm_bindgen(getter)] + pub fn minIslandSize(&self) -> usize { + self.0.min_island_size + } + + #[wasm_bindgen(getter)] + pub fn maxCcdSubsteps(&self) -> usize { + self.0.max_ccd_substeps + } + + #[wasm_bindgen(getter)] + pub fn lengthUnit(&self) -> f32 { + self.0.length_unit + } + + #[wasm_bindgen(setter)] + pub fn set_dt(&mut self, value: f32) { + self.0.dt = value; + } + + #[wasm_bindgen(setter)] + pub fn set_contact_natural_frequency(&mut self, value: f32) { + self.0.contact_softness.natural_frequency = value + } + + #[wasm_bindgen(setter)] + pub fn set_normalizedAllowedLinearError(&mut self, value: f32) { + self.0.normalized_allowed_linear_error = value + } + + #[wasm_bindgen(setter)] + pub fn set_normalizedPredictionDistance(&mut self, value: f32) { + self.0.normalized_prediction_distance = value + } + + #[wasm_bindgen(setter)] + pub fn set_numSolverIterations(&mut self, value: usize) { + self.0.num_solver_iterations = value; + } + #[wasm_bindgen(setter)] + pub fn set_numInternalPgsIterations(&mut self, value: usize) { + self.0.num_internal_pgs_iterations = value; + } + #[wasm_bindgen(setter)] + pub fn set_minIslandSize(&mut self, value: usize) { + self.0.min_island_size = value + } + + #[wasm_bindgen(setter)] + pub fn set_maxCcdSubsteps(&mut self, value: usize) { + self.0.max_ccd_substeps = value + } + + #[wasm_bindgen(setter)] + pub fn set_lengthUnit(&mut self, value: f32) { + self.0.length_unit = value + } +} diff --git a/typescript/src/dynamics/island_manager.rs b/typescript/src/dynamics/island_manager.rs new file mode 100644 index 000000000..7b4cfae61 --- /dev/null +++ b/typescript/src/dynamics/island_manager.rs @@ -0,0 +1,31 @@ +use crate::utils; +use rapier::dynamics::IslandManager; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawIslandManager(pub(crate) IslandManager); + +#[wasm_bindgen] +impl RawIslandManager { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawIslandManager(IslandManager::new()) + } + + /// Applies the given JavaScript function to the integer handle of each active rigid-body + /// managed by this island manager. + /// + /// After a short time of inactivity, a rigid-body is automatically deactivated ("asleep") by + /// the physics engine in order to save computational power. A sleeping rigid-body never moves + /// unless it is moved manually by the user. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each active rigid-body managed by this + /// set. Called as `f(collider)`. + pub fn forEachActiveRigidBodyHandle(&self, f: &js_sys::Function) { + let this = JsValue::null(); + for handle in self.0.active_bodies() { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } +} diff --git a/typescript/src/dynamics/joint.rs b/typescript/src/dynamics/joint.rs new file mode 100644 index 000000000..d6199db66 --- /dev/null +++ b/typescript/src/dynamics/joint.rs @@ -0,0 +1,337 @@ +use crate::math::{RawRotation, RawVector}; +use rapier::dynamics::{ + FixedJointBuilder, GenericJoint, JointAxesMask, JointAxis, MotorModel, PrismaticJointBuilder, + RevoluteJointBuilder, RopeJointBuilder, SpringJointBuilder, +}; +#[cfg(feature = "dim3")] +use rapier::dynamics::{GenericJointBuilder, SphericalJointBuilder}; +use rapier::math::Pose; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[cfg(feature = "dim2")] +pub enum RawJointType { + Revolute, + Fixed, + Prismatic, + Rope, + Spring, + Generic, +} + +#[wasm_bindgen] +#[cfg(feature = "dim3")] +pub enum RawJointType { + Revolute, + Fixed, + Prismatic, + Rope, + Spring, + Spherical, + Generic, +} + +/// The type of this joint. +#[cfg(feature = "dim2")] +impl From for RawJointType { + fn from(ty: JointAxesMask) -> RawJointType { + let rev_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y; + let pri_axes = JointAxesMask::LIN_Y | JointAxesMask::ANG_X; + let fix_axes = JointAxesMask::LIN_X | JointAxesMask::LIN_Y | JointAxesMask::ANG_X; + + if ty == rev_axes { + RawJointType::Revolute + } else if ty == pri_axes { + RawJointType::Prismatic + } else if ty == fix_axes { + RawJointType::Fixed + } else { + RawJointType::Generic + } + } +} + +/// The type of this joint. +#[cfg(feature = "dim3")] +impl From for RawJointType { + fn from(ty: JointAxesMask) -> RawJointType { + let rev_axes = JointAxesMask::LIN_X + | JointAxesMask::LIN_Y + | JointAxesMask::LIN_Z + | JointAxesMask::ANG_Y + | JointAxesMask::ANG_Z; + let pri_axes = JointAxesMask::LIN_Y + | JointAxesMask::LIN_Z + | JointAxesMask::ANG_X + | JointAxesMask::ANG_Y + | JointAxesMask::ANG_Z; + let sph_axes = JointAxesMask::ANG_X | JointAxesMask::ANG_Y | JointAxesMask::ANG_Z; + let fix_axes = JointAxesMask::LIN_X + | JointAxesMask::LIN_Y + | JointAxesMask::LIN_Z + | JointAxesMask::ANG_X + | JointAxesMask::ANG_Y + | JointAxesMask::ANG_Z; + + if ty == rev_axes { + RawJointType::Revolute + } else if ty == pri_axes { + RawJointType::Prismatic + } else if ty == sph_axes { + RawJointType::Spherical + } else if ty == fix_axes { + RawJointType::Fixed + } else { + RawJointType::Generic + } + } +} + +#[wasm_bindgen] +pub enum RawMotorModel { + AccelerationBased, + ForceBased, +} + +impl From for MotorModel { + fn from(model: RawMotorModel) -> MotorModel { + match model { + RawMotorModel::AccelerationBased => MotorModel::AccelerationBased, + RawMotorModel::ForceBased => MotorModel::ForceBased, + } + } +} + +#[cfg(feature = "dim2")] +#[wasm_bindgen] +#[derive(Copy, Clone)] +pub enum RawJointAxis { + LinX, + LinY, + AngX, +} + +#[cfg(feature = "dim3")] +#[wasm_bindgen] +#[derive(Copy, Clone)] +pub enum RawJointAxis { + LinX, + LinY, + LinZ, + AngX, + AngY, + AngZ, +} + +impl From for JointAxis { + fn from(axis: RawJointAxis) -> JointAxis { + match axis { + RawJointAxis::LinX => JointAxis::LinX, + RawJointAxis::LinY => JointAxis::LinY, + #[cfg(feature = "dim3")] + RawJointAxis::LinZ => JointAxis::LinZ, + RawJointAxis::AngX => JointAxis::AngX, + #[cfg(feature = "dim3")] + RawJointAxis::AngY => JointAxis::AngY, + #[cfg(feature = "dim3")] + RawJointAxis::AngZ => JointAxis::AngZ, + } + } +} + +#[wasm_bindgen] +pub struct RawGenericJoint(pub(crate) GenericJoint); + +#[wasm_bindgen] +impl RawGenericJoint { + /// Creates a new joint descriptor that builds generic joints. + /// + /// Generic joints allow arbitrary axes of freedom to be selected + /// for the joint from the available 6 degrees of freedom. + #[cfg(feature = "dim3")] + pub fn generic( + anchor1: &RawVector, + anchor2: &RawVector, + axis: &RawVector, + lockedAxes: u8, + ) -> Option { + let axesMask: JointAxesMask = JointAxesMask::from_bits(lockedAxes)?; + let axis = axis.0.try_normalize()?; + let joint: GenericJoint = GenericJointBuilder::new(axesMask) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .local_axis1(axis) + .local_axis2(axis) + .into(); + Some(Self(joint)) + } + + pub fn spring( + rest_length: f32, + stiffness: f32, + damping: f32, + anchor1: &RawVector, + anchor2: &RawVector, + ) -> Self { + Self( + SpringJointBuilder::new(rest_length, stiffness, damping) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .into(), + ) + } + + pub fn rope(length: f32, anchor1: &RawVector, anchor2: &RawVector) -> Self { + Self( + RopeJointBuilder::new(length) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .into(), + ) + } + + /// Create a new joint descriptor that builds spherical joints. + /// + /// A spherical joints allows three relative rotational degrees of freedom + /// by preventing any relative translation between the anchors of the + /// two attached rigid-bodies. + #[cfg(feature = "dim3")] + pub fn spherical(anchor1: &RawVector, anchor2: &RawVector) -> Self { + Self( + SphericalJointBuilder::new() + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .into(), + ) + } + + /// Creates a new joint descriptor that builds a Prismatic joint. + /// + /// A prismatic joint removes all the degrees of freedom between the + /// affected bodies, except for the translation along one axis. + /// + /// Returns `None` if any of the provided axes cannot be normalized. + #[cfg(feature = "dim2")] + pub fn prismatic( + anchor1: &RawVector, + anchor2: &RawVector, + axis: &RawVector, + limitsEnabled: bool, + limitsMin: f32, + limitsMax: f32, + ) -> Option { + let axis = axis.0.try_normalize()?; + let mut joint = PrismaticJointBuilder::new(axis) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()); + + if limitsEnabled { + joint = joint.limits([limitsMin, limitsMax]); + } + + Some(Self(joint.into())) + } + + /// Creates a new joint descriptor that builds a Prismatic joint. + /// + /// A prismatic joint removes all the degrees of freedom between the + /// affected bodies, except for the translation along one axis. + /// + /// Returns `None` if any of the provided axes cannot be normalized. + #[cfg(feature = "dim3")] + pub fn prismatic( + anchor1: &RawVector, + anchor2: &RawVector, + axis: &RawVector, + limitsEnabled: bool, + limitsMin: f32, + limitsMax: f32, + ) -> Option { + let axis = axis.0.try_normalize()?; + let mut joint = PrismaticJointBuilder::new(axis) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()); + + if limitsEnabled { + joint = joint.limits([limitsMin, limitsMax]); + } + + Some(Self(joint.into())) + } + + /// Creates a new joint descriptor that builds a Fixed joint. + /// + /// A fixed joint removes all the degrees of freedom between the affected bodies. + pub fn fixed( + anchor1: &RawVector, + axes1: &RawRotation, + anchor2: &RawVector, + axes2: &RawRotation, + ) -> RawGenericJoint { + let pos1 = Pose::from_parts(anchor1.0, axes1.0); + let pos2 = Pose::from_parts(anchor2.0, axes2.0); + Self( + FixedJointBuilder::new() + .local_frame1(pos1) + .local_frame2(pos2) + .into(), + ) + } + + /// Create a new joint descriptor that builds Revolute joints. + /// + /// A revolute joint removes all degrees of freedom between the affected + /// bodies except for the rotation. + #[cfg(feature = "dim2")] + pub fn revolute(anchor1: &RawVector, anchor2: &RawVector) -> Option { + Some(Self( + RevoluteJointBuilder::new() + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .into(), + )) + } + + /// Create a new joint descriptor that builds Revolute joints. + /// + /// A revolute joint removes all degrees of freedom between the affected + /// bodies except for the rotation along one axis. + #[cfg(feature = "dim3")] + pub fn revolute( + anchor1: &RawVector, + anchor2: &RawVector, + axis: &RawVector, + ) -> Option { + let axis = axis.0.try_normalize()?; + Some(Self( + RevoluteJointBuilder::new(axis) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .into(), + )) + } + + /// Create a new joint descriptor that builds Revolute joints with + /// independent local axes for each attached rigid-body. + /// + /// This is equivalent to a revolute generic joint with all linear axes + /// locked and only angular X free, but it preserves the local hinge axis + /// on each body instead of assuming they are identical. + #[cfg(feature = "dim3")] + pub fn revoluteWithAxes( + anchor1: &RawVector, + anchor2: &RawVector, + axis1: &RawVector, + axis2: &RawVector, + ) -> Option { + let axis1 = axis1.0.try_normalize()?; + let axis2 = axis2.0.try_normalize()?; + let joint: GenericJoint = GenericJointBuilder::new(JointAxesMask::LOCKED_REVOLUTE_AXES) + .local_anchor1(anchor1.0.into()) + .local_anchor2(anchor2.0.into()) + .local_axis1(axis1) + .local_axis2(axis2) + .into(); + Some(Self(joint)) + } +} diff --git a/typescript/src/dynamics/mod.rs b/typescript/src/dynamics/mod.rs new file mode 100644 index 000000000..36cc7eaa6 --- /dev/null +++ b/typescript/src/dynamics/mod.rs @@ -0,0 +1,20 @@ +//! Structures related to dynamics: bodies, joints, etc. + +pub use self::ccd_solver::*; +pub use self::impulse_joint_set::*; +pub use self::integration_parameters::*; +pub use self::island_manager::*; +pub use self::joint::*; +pub use self::multibody_joint_set::*; +pub use self::rigid_body_set::*; + +mod ccd_solver; +mod impulse_joint; +mod impulse_joint_set; +mod integration_parameters; +mod island_manager; +mod joint; +mod multibody_joint; +mod multibody_joint_set; +mod rigid_body; +mod rigid_body_set; diff --git a/typescript/src/dynamics/multibody_joint.rs b/typescript/src/dynamics/multibody_joint.rs new file mode 100644 index 000000000..9a95f0d53 --- /dev/null +++ b/typescript/src/dynamics/multibody_joint.rs @@ -0,0 +1,196 @@ +use crate::dynamics::{RawJointAxis, RawJointType, RawMultibodyJointSet}; +use crate::math::{RawRotation, RawVector}; +use crate::utils::FlatHandle; +use rapier::dynamics::JointAxis; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +impl RawMultibodyJointSet { + /// The type of this joint. + pub fn jointType(&self, handle: FlatHandle) -> RawJointType { + self.map(handle, |j| j.data.locked_axes.into()) + } + + // /// The unique integer identifier of the first rigid-body this joint it attached to. + // pub fn jointBodyHandle1(&self, handle: FlatHandle) -> u32 { + // self.map(handle, |j| j.body1.into_raw_parts().0) + // } + // + // /// The unique integer identifier of the second rigid-body this joint is attached to. + // pub fn jointBodyHandle2(&self, handle: FlatHandle) -> u32 { + // self.map(handle, |j| j.body2.into_raw_parts().0) + // } + + /// The angular part of the joint’s local frame relative to the first rigid-body it is attached to. + pub fn jointFrameX1(&self, handle: FlatHandle) -> RawRotation { + self.map(handle, |j| j.data.local_frame1.rotation.into()) + } + + /// The angular part of the joint’s local frame relative to the second rigid-body it is attached to. + pub fn jointFrameX2(&self, handle: FlatHandle) -> RawRotation { + self.map(handle, |j| j.data.local_frame2.rotation.into()) + } + + /// The position of the first anchor of this joint. + /// + /// The first anchor gives the position of the points application point on the + /// local frame of the first rigid-body it is attached to. + pub fn jointAnchor1(&self, handle: FlatHandle) -> RawVector { + self.map(handle, |j| j.data.local_frame1.translation.into()) + } + + /// The position of the second anchor of this joint. + /// + /// The second anchor gives the position of the points application point on the + /// local frame of the second rigid-body it is attached to. + pub fn jointAnchor2(&self, handle: FlatHandle) -> RawVector { + self.map(handle, |j| j.data.local_frame2.translation.into()) + } + + /// Are contacts between the rigid-bodies attached by this joint enabled? + pub fn jointContactsEnabled(&self, handle: FlatHandle) -> bool { + self.map(handle, |j| j.data.contacts_enabled) + } + + /// Sets whether contacts are enabled between the rigid-bodies attached by this joint. + pub fn jointSetContactsEnabled(&mut self, handle: FlatHandle, enabled: bool) { + self.map_mut(handle, |j| { + j.data.contacts_enabled = enabled; + }); + } + + /// Are the limits for this joint enabled? + pub fn jointLimitsEnabled(&self, handle: FlatHandle, axis: RawJointAxis) -> bool { + self.map(handle, |j| { + j.data.limit_axes.contains(JointAxis::from(axis).into()) + }) + } + + /// Return the lower limit along the given joint axis. + pub fn jointLimitsMin(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 { + self.map(handle, |j| j.data.limits[axis as usize].min) + } + + /// If this is a prismatic joint, returns its upper limit. + pub fn jointLimitsMax(&self, handle: FlatHandle, axis: RawJointAxis) -> f32 { + self.map(handle, |j| j.data.limits[axis as usize].max) + } + + // pub fn jointConfigureMotorModel( + // &mut self, + // handle: FlatHandle, + // axis: RawJointAxis, + // model: RawMotorModel, + // ) { + // self.map_mut(handle, |j| { + // j.data.motors[axis as usize].model = model.into() + // }) + // } + + /* + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotorVelocity( + &mut self, + handle: FlatHandle, + vx: f32, + vy: f32, + vz: f32, + factor: f32, + ) { + let targetVel = Vector3::new(vx, vy, vz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => j.configure_motor_velocity(targetVel, factor), + _ => {} + }) + } + + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotorPosition( + &mut self, + handle: FlatHandle, + qw: f32, + qx: f32, + qy: f32, + qz: f32, + stiffness: f32, + damping: f32, + ) { + let quat = Quaternion::new(qw, qx, qy, qz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => { + if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) { + j.configure_motor_position(unit_quat, stiffness, damping) + } + } + _ => {} + }) + } + + #[cfg(feature = "dim3")] + pub fn jointConfigureBallMotor( + &mut self, + handle: FlatHandle, + qw: f32, + qx: f32, + qy: f32, + qz: f32, + vx: f32, + vy: f32, + vz: f32, + stiffness: f32, + damping: f32, + ) { + let quat = Quaternion::new(qw, qx, qy, qz); + let vel = Vector3::new(vx, vy, vz); + + self.map_mut(handle, |j| match &mut j.params { + JointData::SphericalJoint(j) => { + if let Some(unit_quat) = UnitQuaternion::try_new(quat, 1.0e-5) { + j.configure_motor(unit_quat, vel, stiffness, damping) + } + } + _ => {} + }) + } + */ + + // pub fn jointConfigureMotorVelocity( + // &mut self, + // handle: FlatHandle, + // axis: RawJointAxis, + // targetVel: f32, + // factor: f32, + // ) { + // self.jointConfigureMotor(handle, axis, 0.0, targetVel, 0.0, factor) + // } + // + // pub fn jointConfigureMotorPosition( + // &mut self, + // handle: FlatHandle, + // axis: RawJointAxis, + // targetPos: f32, + // stiffness: f32, + // damping: f32, + // ) { + // self.jointConfigureMotor(handle, axis, targetPos, 0.0, stiffness, damping) + // } + + // pub fn jointConfigureMotor( + // &mut self, + // handle: FlatHandle, + // axis: RawJointAxis, + // targetPos: f32, + // targetVel: f32, + // stiffness: f32, + // damping: f32, + // ) { + // self.map_mut(handle, |j| { + // j.data.motors[axis as usize].target_pos = targetPos; + // j.data.motors[axis as usize].target_vel = targetVel; + // j.data.motors[axis as usize].stiffness = stiffness; + // j.data.motors[axis as usize].damping = damping; + // }) + // } +} diff --git a/typescript/src/dynamics/multibody_joint_set.rs b/typescript/src/dynamics/multibody_joint_set.rs new file mode 100644 index 000000000..c7f4839e0 --- /dev/null +++ b/typescript/src/dynamics/multibody_joint_set.rs @@ -0,0 +1,85 @@ +use crate::dynamics::RawGenericJoint; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::{MultibodyJoint, MultibodyJointSet}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawMultibodyJointSet(pub(crate) MultibodyJointSet); + +impl RawMultibodyJointSet { + pub(crate) fn map(&self, handle: FlatHandle, f: impl FnOnce(&MultibodyJoint) -> T) -> T { + let (body, link_id) = self + .0 + .get(utils::multibody_joint_handle(handle)) + .expect("Invalid Joint reference. It may have been removed from the physics World."); + f(body.link(link_id).unwrap().joint()) + } + + pub(crate) fn map_mut( + &mut self, + handle: FlatHandle, + f: impl FnOnce(&mut MultibodyJoint) -> T, + ) -> T { + let (body, link_id) = self + .0 + .get_mut(utils::multibody_joint_handle(handle)) + .expect("Invalid Joint reference. It may have been removed from the physics World."); + f(&mut body.link_mut(link_id).unwrap().joint) + } +} + +#[wasm_bindgen] +impl RawMultibodyJointSet { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawMultibodyJointSet(MultibodyJointSet::new()) + } + + pub fn createJoint( + &mut self, + params: &RawGenericJoint, + parent1: FlatHandle, + parent2: FlatHandle, + wakeUp: bool, + ) -> FlatHandle { + // TODO: avoid the unwrap? + let parent1 = utils::body_handle(parent1); + let parent2 = utils::body_handle(parent2); + + self.0 + .insert(parent1, parent2, params.0.clone(), wakeUp) + .map(|h| utils::flat_handle(h.0)) + .unwrap_or(FlatHandle::MAX) + } + + pub fn remove(&mut self, handle: FlatHandle, wakeUp: bool) { + let handle = utils::multibody_joint_handle(handle); + self.0.remove(handle, wakeUp); + } + + pub fn contains(&self, handle: FlatHandle) -> bool { + self.0.get(utils::multibody_joint_handle(handle)).is_some() + } + + /// Applies the given JavaScript function to the integer handle of each joint managed by this physics world. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each joint managed by this set. Called as `f(collider)`. + pub fn forEachJointHandle(&self, f: &js_sys::Function) { + let this = JsValue::null(); + for (handle, _, _, _) in self.0.iter() { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } + + /// Applies the given JavaScript function to the integer handle of each joint attached to the given rigid-body. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each joint attached to the rigid-body. Called as `f(collider)`. + pub fn forEachJointAttachedToRigidBody(&self, body: FlatHandle, f: &js_sys::Function) { + let this = JsValue::null(); + for (_, _, handle) in self.0.attached_joints(utils::body_handle(body)) { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } +} diff --git a/typescript/src/dynamics/rigid_body.rs b/typescript/src/dynamics/rigid_body.rs new file mode 100644 index 000000000..0b12e1964 --- /dev/null +++ b/typescript/src/dynamics/rigid_body.rs @@ -0,0 +1,1036 @@ +use crate::dynamics::{RawRigidBodySet, RawRigidBodyType}; +use crate::geometry::RawColliderSet; +#[cfg(feature = "dim3")] +use crate::math::RawRotation; +use crate::math::RawVector; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::MassProperties; +use rapier::math::{Rotation, Vector}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +impl RawRigidBodySet { + /// The world-space translation of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The world-space translation of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The world-space orientation of this rigid-body. + #[cfg(feature = "dim2")] + pub fn rbRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.position().rotation.angle()) + } + + /// The world-space orientation of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbRotation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.position().rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// Put the given rigid-body to sleep. + pub fn rbSleep(&mut self, handle: FlatHandle) { + self.map_mut(handle, |rb| rb.sleep()); + } + + /// Is this rigid-body sleeping? + pub fn rbIsSleeping(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_sleeping()) + } + + /// Is the velocity of this rigid-body not zero? + pub fn rbIsMoving(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_moving()) + } + + /// The world-space predicted translation of this rigid-body. + /// + /// If this rigid-body is kinematic this value is set by the `setNextKinematicTranslation` + /// method and is used for estimating the kinematic body velocity at the next timestep. + /// For non-kinematic bodies, this value is currently unspecified. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbNextTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.next_position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The world-space predicted translation of this rigid-body. + /// + /// If this rigid-body is kinematic this value is set by the `setNextKinematicTranslation` + /// method and is used for estimating the kinematic body velocity at the next timestep. + /// For non-kinematic bodies, this value is currently unspecified. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbNextTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.next_position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The world-space predicted orientation of this rigid-body. + /// + /// If this rigid-body is kinematic this value is set by the `setNextKinematicRotation` + /// method and is used for estimating the kinematic body velocity at the next timestep. + /// For non-kinematic bodies, this value is currently unspecified. + #[cfg(feature = "dim2")] + pub fn rbNextRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.next_position().rotation.angle()) + } + + /// The world-space predicted orientation of this rigid-body. + /// + /// If this rigid-body is kinematic this value is set by the `setNextKinematicRotation` + /// method and is used for estimating the kinematic body velocity at the next timestep. + /// For non-kinematic bodies, this value is currently unspecified. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbNextRotation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.next_position().rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// Sets the translation of this rigid-body. + /// + /// # Parameters + /// - `x`: the world-space position of the rigid-body along the `x` axis. + /// - `y`: the world-space position of the rigid-body along the `y` axis. + /// - `z`: the world-space position of the rigid-body along the `z` axis. + /// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim3")] + pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_translation(Vector::new(x, y, z), wakeUp); + }) + } + + /// Sets the translation of this rigid-body. + /// + /// # Parameters + /// - `x`: the world-space position of the rigid-body along the `x` axis. + /// - `y`: the world-space position of the rigid-body along the `y` axis. + /// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim2")] + pub fn rbSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_translation(Vector::new(x, y), wakeUp); + }) + } + + /// Sets the rotation quaternion of this rigid-body. + /// + /// This does nothing if a zero quaternion is provided. + /// + /// # Parameters + /// - `x`: the first vector component of the quaternion. + /// - `y`: the second vector component of the quaternion. + /// - `z`: the third vector component of the quaternion. + /// - `w`: the scalar component of the quaternion. + /// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim3")] + pub fn rbSetRotation( + &mut self, + handle: FlatHandle, + x: f32, + y: f32, + z: f32, + w: f32, + wakeUp: bool, + ) { + let q = Rotation::from_xyzw(x, y, z, w); + if q.length_squared() > 0.0 { + let q = q.normalize(); + self.map_mut(handle, |rb| rb.set_rotation(q, wakeUp)) + } + } + + /// Sets the rotation angle of this rigid-body. + /// + /// # Parameters + /// - `angle`: the rotation angle, in radians. + /// - `wakeUp`: forces the rigid-body to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim2")] + pub fn rbSetRotation(&mut self, handle: FlatHandle, angle: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_rotation(Rotation::new(angle), wakeUp) + }) + } + + /// Sets the linear velocity of this rigid-body. + pub fn rbSetLinvel(&mut self, handle: FlatHandle, linvel: &RawVector, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_linvel(linvel.0, wakeUp); + }); + } + + /// Sets the angular velocity of this rigid-body. + #[cfg(feature = "dim2")] + pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_angvel(angvel, wakeUp); + }); + } + + /// Sets the angular velocity of this rigid-body. + #[cfg(feature = "dim3")] + pub fn rbSetAngvel(&mut self, handle: FlatHandle, angvel: &RawVector, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.set_angvel(angvel.0, wakeUp); + }); + } + + /// If this rigid body is kinematic, sets its future translation after the next timestep integration. + /// + /// This should be used instead of `rigidBody.setTranslation` to make the dynamic object + /// interacting with this kinematic body behave as expected. Internally, Rapier will compute + /// an artificial velocity for this rigid-body from its current position and its next kinematic + /// position. This velocity will be used to compute forces on dynamic bodies interacting with + /// this body. + /// + /// # Parameters + /// - `x`: the world-space position of the rigid-body along the `x` axis. + /// - `y`: the world-space position of the rigid-body along the `y` axis. + /// - `z`: the world-space position of the rigid-body along the `z` axis. + #[cfg(feature = "dim3")] + pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) { + self.map_mut(handle, |rb| { + rb.set_next_kinematic_translation(Vector::new(x, y, z)); + }) + } + + /// If this rigid body is kinematic, sets its future translation after the next timestep integration. + /// + /// This should be used instead of `rigidBody.setTranslation` to make the dynamic object + /// interacting with this kinematic body behave as expected. Internally, Rapier will compute + /// an artificial velocity for this rigid-body from its current position and its next kinematic + /// position. This velocity will be used to compute forces on dynamic bodies interacting with + /// this body. + /// + /// # Parameters + /// - `x`: the world-space position of the rigid-body along the `x` axis. + /// - `y`: the world-space position of the rigid-body along the `y` axis. + #[cfg(feature = "dim2")] + pub fn rbSetNextKinematicTranslation(&mut self, handle: FlatHandle, x: f32, y: f32) { + self.map_mut(handle, |rb| { + rb.set_next_kinematic_translation(Vector::new(x, y)); + }) + } + + /// If this rigid body is kinematic, sets its future rotation after the next timestep integration. + /// + /// This should be used instead of `rigidBody.setRotation` to make the dynamic object + /// interacting with this kinematic body behave as expected. Internally, Rapier will compute + /// an artificial velocity for this rigid-body from its current position and its next kinematic + /// position. This velocity will be used to compute forces on dynamic bodies interacting with + /// this body. + /// + /// # Parameters + /// - `x`: the first vector component of the quaternion. + /// - `y`: the second vector component of the quaternion. + /// - `z`: the third vector component of the quaternion. + /// - `w`: the scalar component of the quaternion. + #[cfg(feature = "dim3")] + pub fn rbSetNextKinematicRotation( + &mut self, + handle: FlatHandle, + x: f32, + y: f32, + z: f32, + w: f32, + ) { + let q = Rotation::from_xyzw(x, y, z, w); + if q.length_squared() > 0.0 { + let q = q.normalize(); + self.map_mut(handle, |rb| { + rb.set_next_kinematic_rotation(q); + }) + } + } + + /// If this rigid body is kinematic, sets its future rotation after the next timestep integration. + /// + /// This should be used instead of `rigidBody.setRotation` to make the dynamic object + /// interacting with this kinematic body behave as expected. Internally, Rapier will compute + /// an artificial velocity for this rigid-body from its current position and its next kinematic + /// position. This velocity will be used to compute forces on dynamic bodies interacting with + /// this body. + /// + /// # Parameters + /// - `angle`: the rotation angle, in radians. + #[cfg(feature = "dim2")] + pub fn rbSetNextKinematicRotation(&mut self, handle: FlatHandle, angle: f32) { + self.map_mut(handle, |rb| { + rb.set_next_kinematic_rotation(Rotation::new(angle)); + }) + } + + pub fn rbRecomputeMassPropertiesFromColliders( + &mut self, + handle: FlatHandle, + colliders: &RawColliderSet, + ) { + self.map_mut(handle, |rb| { + rb.recompute_mass_properties_from_colliders(&colliders.0) + }) + } + + pub fn rbSetAdditionalMass(&mut self, handle: FlatHandle, mass: f32, wake_up: bool) { + self.map_mut(handle, |rb| { + rb.set_additional_mass(mass, wake_up); + }) + } + + #[cfg(feature = "dim3")] + pub fn rbSetAdditionalMassProperties( + &mut self, + handle: FlatHandle, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: &RawVector, + angularInertiaFrame: &RawRotation, + wake_up: bool, + ) { + self.map_mut(handle, |rb| { + let mprops = MassProperties::with_principal_inertia_frame( + centerOfMass.0.into(), + mass, + principalAngularInertia.0, + angularInertiaFrame.0, + ); + rb.set_additional_mass_properties(mprops, wake_up) + }) + } + + #[cfg(feature = "dim2")] + pub fn rbSetAdditionalMassProperties( + &mut self, + handle: FlatHandle, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: f32, + wake_up: bool, + ) { + self.map_mut(handle, |rb| { + let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia); + rb.set_additional_mass_properties(props, wake_up) + }) + } + + /// The linear velocity of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbLinvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.linvel(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The linear velocity of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbLinvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.linvel(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The angular velocity of this rigid-body. + #[cfg(feature = "dim2")] + pub fn rbAngvel(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.angvel()) + } + + /// The angular velocity of this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbAngvel(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.angvel(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The velocity of the given world-space point on this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbVelocityAtPoint( + &self, + handle: FlatHandle, + point: &RawVector, + scratch_buffer: &js_sys::Float32Array, + ) { + self.map(handle, |rb| { + let u = rb.velocity_at_point(point.0); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The velocity of the given world-space point on this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbVelocityAtPoint( + &self, + handle: FlatHandle, + point: &RawVector, + scratch_buffer: &js_sys::Float32Array, + ) { + self.map(handle, |rb| { + let u = rb.velocity_at_point(point.0); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + pub fn rbLockTranslations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) { + self.map_mut(handle, |rb| rb.lock_translations(locked, wake_up)) + } + + #[cfg(feature = "dim2")] + pub fn rbSetEnabledTranslations( + &mut self, + handle: FlatHandle, + allow_x: bool, + allow_y: bool, + wake_up: bool, + ) { + self.map_mut(handle, |rb| { + rb.set_enabled_translations(allow_x, allow_y, wake_up) + }) + } + + #[cfg(feature = "dim3")] + pub fn rbSetEnabledTranslations( + &mut self, + handle: FlatHandle, + allow_x: bool, + allow_y: bool, + allow_z: bool, + wake_up: bool, + ) { + self.map_mut(handle, |rb| { + rb.set_enabled_translations(allow_x, allow_y, allow_z, wake_up) + }) + } + + pub fn rbLockRotations(&mut self, handle: FlatHandle, locked: bool, wake_up: bool) { + self.map_mut(handle, |rb| rb.lock_rotations(locked, wake_up)) + } + + #[cfg(feature = "dim3")] + pub fn rbSetEnabledRotations( + &mut self, + handle: FlatHandle, + allow_x: bool, + allow_y: bool, + allow_z: bool, + wake_up: bool, + ) { + self.map_mut(handle, |rb| { + rb.set_enabled_rotations(allow_x, allow_y, allow_z, wake_up) + }) + } + + pub fn rbDominanceGroup(&self, handle: FlatHandle) -> i8 { + self.map(handle, |rb| rb.dominance_group()) + } + + pub fn rbSetDominanceGroup(&mut self, handle: FlatHandle, group: i8) { + self.map_mut(handle, |rb| rb.set_dominance_group(group)) + } + + pub fn rbEnableCcd(&mut self, handle: FlatHandle, enabled: bool) { + self.map_mut(handle, |rb| rb.enable_ccd(enabled)) + } + + pub fn rbSetSoftCcdPrediction(&mut self, handle: FlatHandle, prediction: f32) { + self.map_mut(handle, |rb| rb.set_soft_ccd_prediction(prediction)) + } + + /// The mass of this rigid-body. + pub fn rbMass(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.mass()) + } + + /// The inverse of the mass of a rigid-body. + /// + /// If this is zero, the rigid-body is assumed to have infinite mass. + pub fn rbInvMass(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.mass_properties().local_mprops.inv_mass) + } + + /// The inverse mass taking into account translation locking. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().effective_inv_mass; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The inverse mass taking into account translation locking. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbEffectiveInvMass(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().effective_inv_mass; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The center of mass of a rigid-body expressed in its local-space. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbLocalCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.local_com; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The center of mass of a rigid-body expressed in its local-space. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbLocalCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.local_com; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The world-space center of mass of the rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbWorldCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().world_com; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// The world-space center of mass of the rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbWorldCom(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().world_com; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The inverse of the principal angular inertia of the rigid-body. + /// + /// Components set to zero are assumed to be infinite along the corresponding principal axis. + #[cfg(feature = "dim2")] + pub fn rbInvPrincipalInertia(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| { + rb.mass_properties().local_mprops.inv_principal_inertia + }) + } + + /// The inverse of the principal angular inertia of the rigid-body. + /// + /// Components set to zero are assumed to be infinite along the corresponding principal axis. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbInvPrincipalInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.inv_principal_inertia; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The principal vectors of the local angular inertia tensor of the rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbPrincipalInertiaLocalFrame( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) { + self.map(handle, |rb| { + let u = rb + .mass_properties() + .local_mprops + .principal_inertia_local_frame; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// The angular inertia along the principal inertia axes of the rigid-body. + #[cfg(feature = "dim2")] + pub fn rbPrincipalInertia(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| { + rb.mass_properties().local_mprops.principal_inertia() + }) + } + + /// The angular inertia along the principal inertia axes of the rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbPrincipalInertia(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.mass_properties().local_mprops.principal_inertia(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The world-space inverse angular inertia tensor of the rigid-body, + /// taking into account rotation locking. + #[cfg(feature = "dim2")] + pub fn rbEffectiveWorldInvInertia(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| { + rb.mass_properties().effective_world_inv_inertia + }) + } + + /// The world-space inverse angular inertia tensor of the rigid-body, + /// taking into account rotation locking. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbEffectiveWorldInvInertia( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) { + self.map(handle, |rb| { + let u = rb.mass_properties().effective_world_inv_inertia; + scratch_buffer.set_index(0, u.m11); + scratch_buffer.set_index(1, u.m12); + scratch_buffer.set_index(2, u.m13); + scratch_buffer.set_index(3, u.m22); + scratch_buffer.set_index(4, u.m23); + scratch_buffer.set_index(5, u.m33); + }); + } + + /// The effective world-space angular inertia (that takes the potential rotation locking into account) of + /// this rigid-body. + #[cfg(feature = "dim2")] + pub fn rbEffectiveAngularInertia(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| { + rb.mass_properties().effective_angular_inertia() + }) + } + + /// The effective world-space angular inertia (that takes the potential rotation locking into account) of + /// this rigid-body. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbEffectiveAngularInertia( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) { + self.map(handle, |rb| { + let u = rb.mass_properties().effective_angular_inertia(); + scratch_buffer.set_index(0, u.m11); + scratch_buffer.set_index(1, u.m12); + scratch_buffer.set_index(2, u.m13); + scratch_buffer.set_index(3, u.m22); + scratch_buffer.set_index(4, u.m23); + scratch_buffer.set_index(5, u.m33); + }); + } + + /// Wakes this rigid-body up. + /// + /// A dynamic rigid-body that does not move during several consecutive frames will + /// be put to sleep by the physics engine, i.e., it will stop being simulated in order + /// to avoid useless computations. + /// This method forces a sleeping rigid-body to wake-up. This is useful, e.g., before modifying + /// the position of a dynamic body so that it is properly simulated afterwards. + pub fn rbWakeUp(&mut self, handle: FlatHandle) { + self.map_mut(handle, |rb| rb.wake_up(true)) + } + + /// Is Continuous Collision Detection enabled for this rigid-body? + pub fn rbIsCcdEnabled(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_ccd_enabled()) + } + pub fn rbSoftCcdPrediction(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.soft_ccd_prediction()) + } + + /// The number of colliders attached to this rigid-body. + pub fn rbNumColliders(&self, handle: FlatHandle) -> usize { + self.map(handle, |rb| rb.colliders().len()) + } + + /// Retrieves the `i-th` collider attached to this rigid-body. + /// + /// # Parameters + /// - `at`: The index of the collider to retrieve. Must be a number in `[0, this.numColliders()[`. + /// This index is **not** the same as the unique identifier of the collider. + pub fn rbCollider(&self, handle: FlatHandle, at: usize) -> FlatHandle { + self.map(handle, |rb| utils::flat_handle(rb.colliders()[at].0)) + } + + /// The status of this rigid-body: fixed, dynamic, or kinematic. + pub fn rbBodyType(&self, handle: FlatHandle) -> RawRigidBodyType { + self.map(handle, |rb| rb.body_type().into()) + } + + /// Set a new status for this rigid-body: fixed, dynamic, or kinematic. + pub fn rbSetBodyType(&mut self, handle: FlatHandle, status: RawRigidBodyType, wake_up: bool) { + self.map_mut(handle, |rb| rb.set_body_type(status.into(), wake_up)); + } + + /// Is this rigid-body fixed? + pub fn rbIsFixed(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_fixed()) + } + + /// Is this rigid-body kinematic? + pub fn rbIsKinematic(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_kinematic()) + } + + /// Is this rigid-body dynamic? + pub fn rbIsDynamic(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_dynamic()) + } + + /// The linear damping coefficient of this rigid-body. + pub fn rbLinearDamping(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.linear_damping()) + } + + /// The angular damping coefficient of this rigid-body. + pub fn rbAngularDamping(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.angular_damping()) + } + + pub fn rbSetLinearDamping(&mut self, handle: FlatHandle, factor: f32) { + self.map_mut(handle, |rb| rb.set_linear_damping(factor)); + } + + pub fn rbSetAngularDamping(&mut self, handle: FlatHandle, factor: f32) { + self.map_mut(handle, |rb| rb.set_angular_damping(factor)); + } + + pub fn rbSetEnabled(&mut self, handle: FlatHandle, enabled: bool) { + self.map_mut(handle, |rb| rb.set_enabled(enabled)) + } + + pub fn rbIsEnabled(&self, handle: FlatHandle) -> bool { + self.map(handle, |rb| rb.is_enabled()) + } + + pub fn rbGravityScale(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.gravity_scale()) + } + + pub fn rbSetGravityScale(&mut self, handle: FlatHandle, factor: f32, wakeUp: bool) { + self.map_mut(handle, |rb| rb.set_gravity_scale(factor, wakeUp)); + } + + /// Resets to zero all user-added forces added to this rigid-body. + pub fn rbResetForces(&mut self, handle: FlatHandle, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.reset_forces(wakeUp); + }) + } + + /// Resets to zero all user-added torques added to this rigid-body. + pub fn rbResetTorques(&mut self, handle: FlatHandle, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.reset_torques(wakeUp); + }) + } + + /// Adds a force at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `force`: the world-space force to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + pub fn rbAddForce(&mut self, handle: FlatHandle, force: &RawVector, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.add_force(force.0, wakeUp); + }) + } + + /// Applies an impulse at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `impulse`: the world-space impulse to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + pub fn rbApplyImpulse(&mut self, handle: FlatHandle, impulse: &RawVector, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.apply_impulse(impulse.0, wakeUp); + }) + } + + /// Adds a torque at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `torque`: the torque to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + #[cfg(feature = "dim2")] + pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.add_torque(torque, wakeUp); + }) + } + + /// Adds a torque at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `torque`: the world-space torque to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + #[cfg(feature = "dim3")] + pub fn rbAddTorque(&mut self, handle: FlatHandle, torque: &RawVector, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.add_torque(torque.0, wakeUp); + }) + } + + /// Applies an impulsive torque at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `torque impulse`: the torque impulse to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + #[cfg(feature = "dim2")] + pub fn rbApplyTorqueImpulse(&mut self, handle: FlatHandle, torque_impulse: f32, wakeUp: bool) { + self.map_mut(handle, |rb| { + rb.apply_torque_impulse(torque_impulse, wakeUp); + }) + } + + /// Applies an impulsive torque at the center-of-mass of this rigid-body. + /// + /// # Parameters + /// - `torque impulse`: the world-space torque impulse to apply on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + #[cfg(feature = "dim3")] + pub fn rbApplyTorqueImpulse( + &mut self, + handle: FlatHandle, + torque_impulse: &RawVector, + wakeUp: bool, + ) { + self.map_mut(handle, |rb| { + rb.apply_torque_impulse(torque_impulse.0, wakeUp); + }) + } + + /// Adds a force at the given world-space point of this rigid-body. + /// + /// # Parameters + /// - `force`: the world-space force to apply on the rigid-body. + /// - `point`: the world-space point where the impulse is to be applied on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + pub fn rbAddForceAtPoint( + &mut self, + handle: FlatHandle, + force: &RawVector, + point: &RawVector, + wakeUp: bool, + ) { + self.map_mut(handle, |rb| { + rb.add_force_at_point(force.0, point.0.into(), wakeUp); + }) + } + + /// Applies an impulse at the given world-space point of this rigid-body. + /// + /// # Parameters + /// - `impulse`: the world-space impulse to apply on the rigid-body. + /// - `point`: the world-space point where the impulse is to be applied on the rigid-body. + /// - `wakeUp`: should the rigid-body be automatically woken-up? + pub fn rbApplyImpulseAtPoint( + &mut self, + handle: FlatHandle, + impulse: &RawVector, + point: &RawVector, + wakeUp: bool, + ) { + self.map_mut(handle, |rb| { + rb.apply_impulse_at_point(impulse.0, point.0.into(), wakeUp); + }) + } + + pub fn rbAdditionalSolverIterations(&self, handle: FlatHandle) -> usize { + self.map(handle, |rb| rb.additional_solver_iterations()) + } + + pub fn rbSetAdditionalSolverIterations(&mut self, handle: FlatHandle, iters: usize) { + self.map_mut(handle, |rb| { + rb.set_additional_solver_iterations(iters as usize); + }) + } + + /// An arbitrary user-defined 32-bit integer + pub fn rbUserData(&self, handle: FlatHandle) -> u32 { + self.map(handle, |rb| rb.user_data as u32) + } + + /// Sets the user-defined 32-bit integer of this rigid-body. + /// + /// # Parameters + /// - `data`: an arbitrary user-defined 32-bit integer. + pub fn rbSetUserData(&mut self, handle: FlatHandle, data: u32) { + self.map_mut(handle, |rb| { + rb.user_data = data as u128; + }) + } + + /// Retrieves the constant force(s) the user added to this rigid-body. + /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn rbUserForce(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.user_force(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + + /// Retrieves the constant force(s) the user added to this rigid-body. + /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbUserForce(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.user_force(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// Retrieves the constant torque(s) the user added to this rigid-body. + /// Returns zero if the rigid-body is not dynamic. + #[cfg(feature = "dim2")] + pub fn rbUserTorque(&self, handle: FlatHandle) -> f32 { + self.map(handle, |rb| rb.user_torque()) + } + + /// Retrieves the constant torque(s) the user added to this rigid-body. + /// Returns zero if the rigid-body is not dynamic. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn rbUserTorque(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |rb| { + let u = rb.user_torque(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } +} diff --git a/typescript/src/dynamics/rigid_body_set.rs b/typescript/src/dynamics/rigid_body_set.rs new file mode 100644 index 000000000..d8027c72c --- /dev/null +++ b/typescript/src/dynamics/rigid_body_set.rs @@ -0,0 +1,238 @@ +use crate::dynamics::{RawImpulseJointSet, RawIslandManager, RawMultibodyJointSet}; +use crate::geometry::RawColliderSet; +use crate::math::{RawRotation, RawVector}; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::{MassProperties, RigidBody, RigidBodyBuilder, RigidBodySet, RigidBodyType}; +use rapier::math::Pose; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub enum RawRigidBodyType { + Dynamic, + Fixed, + KinematicPositionBased, + KinematicVelocityBased, +} + +impl Into for RawRigidBodyType { + fn into(self) -> RigidBodyType { + match self { + RawRigidBodyType::Dynamic => RigidBodyType::Dynamic, + RawRigidBodyType::Fixed => RigidBodyType::Fixed, + RawRigidBodyType::KinematicPositionBased => RigidBodyType::KinematicPositionBased, + RawRigidBodyType::KinematicVelocityBased => RigidBodyType::KinematicVelocityBased, + } + } +} + +impl Into for RigidBodyType { + fn into(self) -> RawRigidBodyType { + match self { + RigidBodyType::Dynamic => RawRigidBodyType::Dynamic, + RigidBodyType::Fixed => RawRigidBodyType::Fixed, + RigidBodyType::KinematicPositionBased => RawRigidBodyType::KinematicPositionBased, + RigidBodyType::KinematicVelocityBased => RawRigidBodyType::KinematicVelocityBased, + } + } +} + +#[wasm_bindgen] +pub struct RawRigidBodySet(pub(crate) RigidBodySet); + +impl RawRigidBodySet { + pub(crate) fn map(&self, handle: FlatHandle, f: impl FnOnce(&RigidBody) -> T) -> T { + let body = self.0.get(utils::body_handle(handle)).expect( + "Invalid RigidBody reference. It may have been removed from the physics World.", + ); + f(body) + } + + pub(crate) fn map_mut( + &mut self, + handle: FlatHandle, + f: impl FnOnce(&mut RigidBody) -> T, + ) -> T { + let body = self.0.get_mut(utils::body_handle(handle)).expect( + "Invalid RigidBody reference. It may have been removed from the physics World.", + ); + f(body) + } +} + +#[wasm_bindgen] +impl RawRigidBodySet { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawRigidBodySet(RigidBodySet::new()) + } + + #[cfg(feature = "dim3")] + pub fn createRigidBody( + &mut self, + enabled: bool, + translation: &RawVector, + rotation: &RawRotation, + gravityScale: f32, + mass: f32, + massOnly: bool, + centerOfMass: &RawVector, + linvel: &RawVector, + angvel: &RawVector, + principalAngularInertia: &RawVector, + angularInertiaFrame: &RawRotation, + translationEnabledX: bool, + translationEnabledY: bool, + translationEnabledZ: bool, + rotationEnabledX: bool, + rotationEnabledY: bool, + rotationEnabledZ: bool, + linearDamping: f32, + angularDamping: f32, + rb_type: RawRigidBodyType, + canSleep: bool, + sleeping: bool, + softCcdPrediction: f32, + ccdEnabled: bool, + dominanceGroup: i8, + additional_solver_iterations: usize, + ) -> FlatHandle { + let pos = Pose::from_parts(translation.0, rotation.0); + + let mut rigid_body = RigidBodyBuilder::new(rb_type.into()) + .enabled(enabled) + .pose(pos) + .gravity_scale(gravityScale) + .enabled_translations( + translationEnabledX, + translationEnabledY, + translationEnabledZ, + ) + .enabled_rotations(rotationEnabledX, rotationEnabledY, rotationEnabledZ) + .linvel(linvel.0) + .angvel(angvel.0) + .linear_damping(linearDamping) + .angular_damping(angularDamping) + .can_sleep(canSleep) + .sleeping(sleeping) + .ccd_enabled(ccdEnabled) + .dominance_group(dominanceGroup) + .additional_solver_iterations(additional_solver_iterations) + .soft_ccd_prediction(softCcdPrediction); + + rigid_body = if massOnly { + rigid_body.additional_mass(mass) + } else { + let props = MassProperties::with_principal_inertia_frame( + centerOfMass.0.into(), + mass, + principalAngularInertia.0, + angularInertiaFrame.0, + ); + rigid_body.additional_mass_properties(props) + }; + + utils::flat_handle(self.0.insert(rigid_body.build()).0) + } + + #[cfg(feature = "dim2")] + pub fn createRigidBody( + &mut self, + enabled: bool, + translation: &RawVector, + rotation: &RawRotation, + gravityScale: f32, + mass: f32, + massOnly: bool, + centerOfMass: &RawVector, + linvel: &RawVector, + angvel: f32, + principalAngularInertia: f32, + translationEnabledX: bool, + translationEnabledY: bool, + rotationsEnabled: bool, + linearDamping: f32, + angularDamping: f32, + rb_type: RawRigidBodyType, + canSleep: bool, + sleeping: bool, + softCcdPrediction: f32, + ccdEnabled: bool, + dominanceGroup: i8, + additional_solver_iterations: usize, + ) -> FlatHandle { + let pos = Pose::from_parts(translation.0, rotation.0); + let mut rigid_body = RigidBodyBuilder::new(rb_type.into()) + .enabled(enabled) + .pose(pos) + .gravity_scale(gravityScale) + .enabled_translations(translationEnabledX, translationEnabledY) + .linvel(linvel.0) + .angvel(angvel) + .linear_damping(linearDamping) + .angular_damping(angularDamping) + .can_sleep(canSleep) + .sleeping(sleeping) + .ccd_enabled(ccdEnabled) + .dominance_group(dominanceGroup) + .additional_solver_iterations(additional_solver_iterations) + .soft_ccd_prediction(softCcdPrediction); + + rigid_body = if massOnly { + rigid_body.additional_mass(mass) + } else { + let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia); + rigid_body.additional_mass_properties(props) + }; + + if !rotationsEnabled { + rigid_body = rigid_body.lock_rotations(); + } + + utils::flat_handle(self.0.insert(rigid_body.build()).0) + } + + pub fn remove( + &mut self, + handle: FlatHandle, + islands: &mut RawIslandManager, + colliders: &mut RawColliderSet, + joints: &mut RawImpulseJointSet, + articulations: &mut RawMultibodyJointSet, + ) { + let handle = utils::body_handle(handle); + self.0.remove( + handle, + &mut islands.0, + &mut colliders.0, + &mut joints.0, + &mut articulations.0, + true, + ); + } + + /// The number of rigid-bodies on this set. + pub fn len(&self) -> usize { + self.0.len() + } + + /// Checks if a rigid-body with the given integer handle exists. + pub fn contains(&self, handle: FlatHandle) -> bool { + self.0.get(utils::body_handle(handle)).is_some() + } + + /// Applies the given JavaScript function to the integer handle of each rigid-body managed by this set. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each rigid-body managed by this set. Called as `f(collider)`. + pub fn forEachRigidBodyHandle(&self, f: &js_sys::Function) { + let this = JsValue::null(); + for (handle, _) in self.0.iter() { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } + + pub fn propagateModifiedBodyPositionsToColliders(&mut self, colliders: &mut RawColliderSet) { + self.0 + .propagate_modified_body_positions_to_colliders(&mut colliders.0); + } +} diff --git a/typescript/src/geometry/broad_phase.rs b/typescript/src/geometry/broad_phase.rs new file mode 100644 index 000000000..f85a7762e --- /dev/null +++ b/typescript/src/geometry/broad_phase.rs @@ -0,0 +1,462 @@ +use crate::dynamics::RawRigidBodySet; +use crate::geometry::{ + RawColliderSet, RawColliderShapeCastHit, RawNarrowPhase, RawPointColliderProjection, + RawRayColliderHit, RawRayColliderIntersection, RawShape, +}; +use crate::math::{RawRotation, RawVector}; +use crate::utils::{self, FlatHandle}; +use rapier::geometry::DefaultBroadPhase; +use rapier::geometry::{Aabb, ColliderHandle, Ray}; +use rapier::math::Pose; +use rapier::parry::query::ShapeCastOptions; +use rapier::pipeline::{QueryFilter, QueryFilterFlags}; +use rapier::prelude::FeatureId; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawBroadPhase(pub(crate) DefaultBroadPhase); + +#[wasm_bindgen] +impl RawBroadPhase { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawBroadPhase(DefaultBroadPhase::new()) + } + + pub fn castRay( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + let (handle, timeOfImpact) = utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let ray = Ray::new(rayOrig.0, rayDir.0); + query_pipeline.cast_ray(&ray, maxToi, solid) + })?; + + Some(RawRayColliderHit { + handle, + timeOfImpact, + }) + } + + pub fn castRayAndGetNormal( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + let (handle, inter) = utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let ray = Ray::new(rayOrig.0, rayDir.0); + query_pipeline.cast_ray_and_get_normal(&ray, maxToi, solid) + })?; + + Some(RawRayColliderIntersection { handle, inter }) + } + + // The callback is of type (RawRayColliderIntersection) => bool + pub fn intersectionsWithRay( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + callback: &js_sys::Function, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let ray = Ray::new(rayOrig.0, rayDir.0); + let rcallback = |handle, inter| { + let result = RawRayColliderIntersection { handle, inter }; + match callback.call1(&JsValue::null(), &JsValue::from(result)) { + Err(_) => true, + Ok(val) => val.as_bool().unwrap_or(true), + } + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + for (handle, _, inter) in query_pipeline.intersect_ray(ray, maxToi, solid) { + if !rcallback(handle, inter) { + break; + } + } + }); + } + + pub fn intersectionWithShape( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + shapePos: &RawVector, + shapeRot: &RawRotation, + shape: &RawShape, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + // TODO: take a callback as argument so we can yield all the intersecting shapes? + for (handle, _) in query_pipeline.intersect_shape(pos, &*shape.0) { + // Return the first intersection we find. + return Some(utils::flat_handle(handle.0)); + } + + None + }) + } + + pub fn projectPoint( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + point: &RawVector, + solid: bool, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + query_pipeline + .project_point(point.0, f32::MAX, solid) + .map(|(handle, proj)| RawPointColliderProjection { + handle, + proj, + feature: FeatureId::Unknown, + }) + }) + } + + pub fn projectPointAndGetFeature( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + point: &RawVector, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + query_pipeline + .project_point_and_get_feature(point.0, f32::MAX) + .map(|(handle, proj, feature)| RawPointColliderProjection { + handle, + proj, + feature, + }) + }) + } + + // The callback is of type (u32) => bool + pub fn intersectionsWithPoint( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + point: &RawVector, + callback: &js_sys::Function, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let rcallback = |handle: ColliderHandle| match callback.call1( + &JsValue::null(), + &JsValue::from(utils::flat_handle(handle.0)), + ) { + Err(_) => true, + Ok(val) => val.as_bool().unwrap_or(true), + }; + + for (handle, _) in query_pipeline.intersect_point(point.0) { + if !rcallback(handle) { + break; + } + } + }); + } + + pub fn castShape( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + shapePos: &RawVector, + shapeRot: &RawRotation, + shapeVel: &RawVector, + shape: &RawShape, + target_distance: f32, + maxToi: f32, + stop_at_penetration: bool, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) -> Option { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + query_pipeline + .cast_shape( + &pos, + shapeVel.0, + &*shape.0, + ShapeCastOptions { + max_time_of_impact: maxToi, + stop_at_penetration, + compute_impact_geometry_on_penetration: true, + target_distance, + }, + ) + .map(|(handle, hit)| RawColliderShapeCastHit { handle, hit }) + }) + } + + // The callback has type (u32) => boolean + pub fn intersectionsWithShape( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + shapePos: &RawVector, + shapeRot: &RawRotation, + shape: &RawShape, + callback: &js_sys::Function, + filter_flags: u32, + filter_groups: Option, + filter_exclude_collider: Option, + filter_exclude_rigid_body: Option, + filter_predicate: &js_sys::Function, + ) { + utils::with_filter(filter_predicate, |predicate| { + let query_filter = QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: filter_groups.map(crate::geometry::unpack_interaction_groups), + exclude_collider: filter_exclude_collider.map(crate::utils::collider_handle), + exclude_rigid_body: filter_exclude_rigid_body.map(crate::utils::body_handle), + predicate, + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + query_filter, + ); + + let rcallback = |handle: ColliderHandle| match callback.call1( + &JsValue::null(), + &JsValue::from(utils::flat_handle(handle.0)), + ) { + Err(_) => true, + Ok(val) => val.as_bool().unwrap_or(true), + }; + + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + for (handle, _) in query_pipeline.intersect_shape(pos, &*shape.0) { + if !rcallback(handle) { + break; + } + } + }) + } + + pub fn collidersWithAabbIntersectingAabb( + &self, + narrow_phase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + aabbCenter: &RawVector, + aabbHalfExtents: &RawVector, + callback: &js_sys::Function, + ) { + let rcallback = |handle: &ColliderHandle| match callback.call1( + &JsValue::null(), + &JsValue::from(utils::flat_handle(handle.0)), + ) { + Err(_) => true, + Ok(val) => val.as_bool().unwrap_or(true), + }; + + let query_pipeline = self.0.as_query_pipeline( + narrow_phase.0.query_dispatcher(), + &bodies.0, + &colliders.0, + Default::default(), + ); + + let center = aabbCenter.0; + let aabb = Aabb::new(center - aabbHalfExtents.0, center + aabbHalfExtents.0); + + for (handle, _) in query_pipeline.intersect_aabb_conservative(aabb) { + if !rcallback(&handle) { + break; + } + } + } +} diff --git a/typescript/src/geometry/collider.rs b/typescript/src/geometry/collider.rs new file mode 100644 index 000000000..fa68c7d88 --- /dev/null +++ b/typescript/src/geometry/collider.rs @@ -0,0 +1,1231 @@ +#[cfg(feature = "dim3")] +use crate::geometry::shape::normalized_convex_polyhedron_mesh; +use crate::geometry::shape::SharedShapeUtility; +use crate::geometry::{ + RawColliderSet, RawColliderShapeCastHit, RawPointProjection, RawRayIntersection, RawShape, + RawShapeCastHit, RawShapeContact, RawShapeType, +}; +use crate::math::{RawRotation, RawVector}; +use crate::utils::{self, FlatHandle}; +use rapier::dynamics::MassProperties; +use rapier::geometry::{ActiveCollisionTypes, ShapeType}; +use rapier::math::{IVector, Pose, Real, Rotation, Vector}; +use rapier::parry::query; +use rapier::parry::query::ShapeCastOptions; +use rapier::pipeline::{ActiveEvents, ActiveHooks}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +impl RawColliderSet { + /// The world-space translation of this collider. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + }); + } + /// The world-space translation of this collider. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coTranslation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + }); + } + + /// The world-space orientation of this collider. + #[cfg(feature = "dim2")] + pub fn coRotation(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.position().rotation.angle()) + } + + /// The world-space orientation of this collider. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coRotation(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) { + self.map(handle, |co| { + let u = co.position().rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + }); + } + + /// The translation of this collider relative to its parent rigid-body. + /// + /// Returns `false` if it doesn’t have a parent. + #[cfg(feature = "dim2")] + pub fn coTranslationWrtParent( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| { + co.position_wrt_parent().map_or(false, |pose| { + let u = pose.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + }) + } + + /// The translation of this collider relative to its parent rigid-body. + /// + /// Returns `false` if it doesn’t have a parent. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coTranslationWrtParent( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| { + co.position_wrt_parent().map_or(false, |pose| { + let u = pose.translation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + }) + } + + /// The orientation of this collider relative to its parent rigid-body. + /// + /// Returns `NAN` if it doesn’t have a parent. + #[cfg(feature = "dim2")] + pub fn coRotationWrtParent(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| { + co.position_wrt_parent() + .map_or(f32::NAN, |pose| pose.rotation.angle()) + }) + } + + /// The orientation of this collider relative to its parent rigid-body. + /// + /// Returns `false` if it doesn’t have a parent. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coRotationWrtParent( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| { + co.position_wrt_parent().map_or(false, |pose| { + let u = pose.rotation; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + scratch_buffer.set_index(3, u.w); + true + }) + }) + } + + /// Sets the translation of this collider. + /// + /// # Parameters + /// - `x`: the world-space position of the collider along the `x` axis. + /// - `y`: the world-space position of the collider along the `y` axis. + /// - `z`: the world-space position of the collider along the `z` axis. + /// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim3")] + pub fn coSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) { + self.map_mut(handle, |co| { + co.set_translation(Vector::new(x, y, z)); + }) + } + + /// Sets the translation of this collider. + /// + /// # Parameters + /// - `x`: the world-space position of the collider along the `x` axis. + /// - `y`: the world-space position of the collider along the `y` axis. + /// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim2")] + pub fn coSetTranslation(&mut self, handle: FlatHandle, x: f32, y: f32) { + self.map_mut(handle, |co| { + co.set_translation(Vector::new(x, y)); + }) + } + + #[cfg(feature = "dim3")] + pub fn coSetTranslationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32) { + self.map_mut(handle, |co| { + co.set_translation_wrt_parent(Vector::new(x, y, z)); + }) + } + + #[cfg(feature = "dim2")] + pub fn coSetTranslationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32) { + self.map_mut(handle, |co| { + co.set_translation_wrt_parent(Vector::new(x, y)); + }) + } + + /// Sets the rotation quaternion of this collider. + /// + /// This does nothing if a zero quaternion is provided. + /// + /// # Parameters + /// - `x`: the first vector component of the quaternion. + /// - `y`: the second vector component of the quaternion. + /// - `z`: the third vector component of the quaternion. + /// - `w`: the scalar component of the quaternion. + /// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim3")] + pub fn coSetRotation(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, w: f32) { + let q = Rotation::from_xyzw(x, y, z, w); + if q.length_squared() != 0.0 { + let q = q.normalize(); + self.map_mut(handle, |co| co.set_rotation(q)) + } + } + + /// Sets the rotation angle of this collider. + /// + /// # Parameters + /// - `angle`: the rotation angle, in radians. + /// - `wakeUp`: forces the collider to wake-up so it is properly affected by forces if it + /// wasn't moving before modifying its position. + #[cfg(feature = "dim2")] + pub fn coSetRotation(&mut self, handle: FlatHandle, angle: f32) { + self.map_mut(handle, |co| co.set_rotation(Rotation::new(angle))) + } + + #[cfg(feature = "dim3")] + pub fn coSetRotationWrtParent(&mut self, handle: FlatHandle, x: f32, y: f32, z: f32, w: f32) { + let q = Rotation::from_xyzw(x, y, z, w); + if q.length_squared() != 0.0 { + let q = q.normalize(); + self.map_mut(handle, |co| co.set_rotation_wrt_parent(q.to_scaled_axis())) + } + } + + #[cfg(feature = "dim2")] + pub fn coSetRotationWrtParent(&mut self, handle: FlatHandle, angle: f32) { + self.map_mut(handle, |co| co.set_rotation_wrt_parent(angle)) + } + + /// Is this collider a sensor? + pub fn coIsSensor(&self, handle: FlatHandle) -> bool { + self.map(handle, |co| co.is_sensor()) + } + + /// The type of the shape of this collider. + pub fn coShapeType(&self, handle: FlatHandle) -> RawShapeType { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::Ball => RawShapeType::Ball, + ShapeType::Cuboid => RawShapeType::Cuboid, + ShapeType::Capsule => RawShapeType::Capsule, + ShapeType::Segment => RawShapeType::Segment, + ShapeType::Polyline => RawShapeType::Polyline, + ShapeType::Triangle => RawShapeType::Triangle, + ShapeType::TriMesh => RawShapeType::TriMesh, + ShapeType::HeightField => RawShapeType::HeightField, + ShapeType::Compound => RawShapeType::Compound, + ShapeType::HalfSpace => RawShapeType::HalfSpace, + ShapeType::Voxels => RawShapeType::Voxels, + #[cfg(feature = "dim3")] + ShapeType::ConvexPolyhedron => RawShapeType::ConvexPolyhedron, + #[cfg(feature = "dim2")] + ShapeType::ConvexPolygon => RawShapeType::ConvexPolygon, + #[cfg(feature = "dim3")] + ShapeType::Cylinder => RawShapeType::Cylinder, + #[cfg(feature = "dim3")] + ShapeType::Cone => RawShapeType::Cone, + ShapeType::RoundCuboid => RawShapeType::RoundCuboid, + ShapeType::RoundTriangle => RawShapeType::RoundTriangle, + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => RawShapeType::RoundCylinder, + #[cfg(feature = "dim3")] + ShapeType::RoundCone => RawShapeType::RoundCone, + #[cfg(feature = "dim3")] + ShapeType::RoundConvexPolyhedron => RawShapeType::RoundConvexPolyhedron, + #[cfg(feature = "dim2")] + ShapeType::RoundConvexPolygon => RawShapeType::RoundConvexPolygon, + ShapeType::Custom => panic!("Not yet implemented."), + }) + } + + pub fn coShape(&self, handle: FlatHandle) -> RawShape { + self.map(handle, |co| RawShape(co.shared_shape().clone())) + } + + /// The outward normal of this collider if it has a half-space shape. + /// + /// Returns `false` if it doesn’t have a half-space shape. + #[cfg(feature = "dim2")] + pub fn coHalfspaceNormal( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| { + co.shape().as_halfspace().map_or(false, |h| { + let u = h.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + }) + } + + /// The outward normal of this collider if it has a half-space shape. + /// + /// Returns `false` if it doesn’t have a half-space shape. + #[cfg(feature = "dim3")] + pub fn coHalfspaceNormal( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| { + co.shape().as_halfspace().map_or(false, |h| { + let u = h.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + }) + } + + /// The half-extents of this collider if it has a cuboid shape. + /// + /// Returns `false` if it doesn’t have a cuboid shape. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coHalfExtents(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| { + co.shape().as_cuboid().map_or_else( + || { + co.shape().as_round_cuboid().map_or(false, |c| { + let u = c.inner_shape.half_extents; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + }, + |c| { + let u = c.half_extents; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }, + ) + }) + } + + /// The half-extents of this collider if it has a cuboid shape. + /// + /// Returns `false` if it doesn’t have a cuboid shape. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coHalfExtents(&self, handle: FlatHandle, scratch_buffer: &js_sys::Float32Array) -> bool { + self.map(handle, |co| { + co.shape().as_cuboid().map_or_else( + || { + co.shape().as_round_cuboid().map_or(false, |c| { + let u = c.inner_shape.half_extents; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + }, + |c| { + let u = c.half_extents; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }, + ) + }) + } + + /// Set the half-extents of this collider if it has a cuboid shape. + pub fn coSetHalfExtents(&mut self, handle: FlatHandle, newHalfExtents: &RawVector) { + self.map_mut(handle, |co| match co.shape().shape_type() { + ShapeType::Cuboid => co + .shape_mut() + .as_cuboid_mut() + .map(|b| b.half_extents = newHalfExtents.0.into()), + ShapeType::RoundCuboid => co + .shape_mut() + .as_round_cuboid_mut() + .map(|b| b.inner_shape.half_extents = newHalfExtents.0.into()), + _ => None, + }); + } + + /// The radius of this collider if it is a ball, capsule, cylinder, or cone shape. + pub fn coRadius(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::Ball => co.shape().as_ball().map(|b| b.radius), + ShapeType::Capsule => co.shape().as_capsule().map(|b| b.radius), + #[cfg(feature = "dim3")] + ShapeType::Cylinder => co.shape().as_cylinder().map(|b| b.radius), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => { + co.shape().as_round_cylinder().map(|b| b.inner_shape.radius) + } + #[cfg(feature = "dim3")] + ShapeType::Cone => co.shape().as_cone().map(|b| b.radius), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co.shape().as_round_cone().map(|b| b.inner_shape.radius), + _ => None, + }) + } + + /// Set the radius of this collider if it is a ball, capsule, cylinder, or cone shape. + pub fn coSetRadius(&mut self, handle: FlatHandle, newRadius: Real) { + self.map_mut(handle, |co| match co.shape().shape_type() { + ShapeType::Ball => co.shape_mut().as_ball_mut().map(|b| b.radius = newRadius), + ShapeType::Capsule => co + .shape_mut() + .as_capsule_mut() + .map(|b| b.radius = newRadius), + #[cfg(feature = "dim3")] + ShapeType::Cylinder => co + .shape_mut() + .as_cylinder_mut() + .map(|b| b.radius = newRadius), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => co + .shape_mut() + .as_round_cylinder_mut() + .map(|b| b.inner_shape.radius = newRadius), + #[cfg(feature = "dim3")] + ShapeType::Cone => co.shape_mut().as_cone_mut().map(|b| b.radius = newRadius), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co + .shape_mut() + .as_round_cone_mut() + .map(|b| b.inner_shape.radius = newRadius), + _ => None, + }); + } + + /// The half height of this collider if it is a capsule, cylinder, or cone shape. + pub fn coHalfHeight(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::Capsule => co.shape().as_capsule().map(|b| b.half_height()), + #[cfg(feature = "dim3")] + ShapeType::Cylinder => co.shape().as_cylinder().map(|b| b.half_height), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => co + .shape() + .as_round_cylinder() + .map(|b| b.inner_shape.half_height), + #[cfg(feature = "dim3")] + ShapeType::Cone => co.shape().as_cone().map(|b| b.half_height), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co + .shape() + .as_round_cone() + .map(|b| b.inner_shape.half_height), + _ => None, + }) + } + + /// Set the half height of this collider if it is a capsule, cylinder, or cone shape. + pub fn coSetHalfHeight(&mut self, handle: FlatHandle, newHalfheight: Real) { + self.map_mut(handle, |co| match co.shape().shape_type() { + ShapeType::Capsule => { + let point = Vector::Y * newHalfheight; + co.shape_mut().as_capsule_mut().map(|b| { + b.segment.a = -point; + b.segment.b = point; + }) + } + #[cfg(feature = "dim3")] + ShapeType::Cylinder => co + .shape_mut() + .as_cylinder_mut() + .map(|b| b.half_height = newHalfheight), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => co + .shape_mut() + .as_round_cylinder_mut() + .map(|b| b.inner_shape.half_height = newHalfheight), + #[cfg(feature = "dim3")] + ShapeType::Cone => co + .shape_mut() + .as_cone_mut() + .map(|b| b.half_height = newHalfheight), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co + .shape_mut() + .as_round_cone_mut() + .map(|b| b.inner_shape.half_height = newHalfheight), + _ => None, + }); + } + + /// The radius of the round edges of this collider. + pub fn coRoundRadius(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::RoundCuboid => co.shape().as_round_cuboid().map(|b| b.border_radius), + ShapeType::RoundTriangle => co.shape().as_round_triangle().map(|b| b.border_radius), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => co.shape().as_round_cylinder().map(|b| b.border_radius), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co.shape().as_round_cone().map(|b| b.border_radius), + #[cfg(feature = "dim3")] + ShapeType::RoundConvexPolyhedron => co + .shape() + .as_round_convex_polyhedron() + .map(|b| b.border_radius), + #[cfg(feature = "dim2")] + ShapeType::RoundConvexPolygon => co + .shape() + .as_round_convex_polygon() + .map(|b| b.border_radius), + _ => None, + }) + } + + /// Set the radius of the round edges of this collider. + pub fn coSetRoundRadius(&mut self, handle: FlatHandle, newBorderRadius: Real) { + self.map_mut(handle, |co| match co.shape().shape_type() { + ShapeType::RoundCuboid => co + .shape_mut() + .as_round_cuboid_mut() + .map(|b| b.border_radius = newBorderRadius), + ShapeType::RoundTriangle => co + .shape_mut() + .as_round_triangle_mut() + .map(|b| b.border_radius = newBorderRadius), + #[cfg(feature = "dim3")] + ShapeType::RoundCylinder => co + .shape_mut() + .as_round_cylinder_mut() + .map(|b| b.border_radius = newBorderRadius), + #[cfg(feature = "dim3")] + ShapeType::RoundCone => co + .shape_mut() + .as_round_cone_mut() + .map(|b| b.border_radius = newBorderRadius), + #[cfg(feature = "dim3")] + ShapeType::RoundConvexPolyhedron => co + .shape_mut() + .as_round_convex_polyhedron_mut() + .map(|b| b.border_radius = newBorderRadius), + #[cfg(feature = "dim2")] + ShapeType::RoundConvexPolygon => co + .shape_mut() + .as_round_convex_polygon_mut() + .map(|b| b.border_radius = newBorderRadius), + _ => None, + }); + } + + pub fn coVoxelData(&self, handle: FlatHandle) -> Option> { + self.map(handle, |co| { + let vox = co.shape().as_voxels()?; + let coords = vox + .voxels() + .filter_map(|vox| (!vox.state.is_empty()).then_some(vox.grid_coords)) + .flat_map(|ids| ids.to_array()) + .collect(); + Some(coords) + }) + } + + pub fn coVoxelSize(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| { + let vox = co.shape().as_voxels()?; + Some(RawVector(vox.voxel_size())) + }) + } + + #[cfg(feature = "dim2")] + pub fn coSetVoxel(&mut self, handle: FlatHandle, ix: i32, iy: i32, filled: bool) { + self.map_mut(handle, |co| { + if let Some(vox) = co.shape_mut().as_voxels_mut() { + vox.set_voxel(IVector::new(ix, iy), filled); + } + }) + } + + #[cfg(feature = "dim3")] + pub fn coSetVoxel(&mut self, handle: FlatHandle, ix: i32, iy: i32, iz: i32, filled: bool) { + self.map_mut(handle, |co| { + if let Some(vox) = co.shape_mut().as_voxels_mut() { + vox.set_voxel(IVector::new(ix, iy, iz), filled); + } + }) + } + + #[cfg(feature = "dim2")] + pub fn coPropagateVoxelChange( + &mut self, + handle1: FlatHandle, + handle2: FlatHandle, + ix: i32, + iy: i32, + shift_x: i32, + shift_y: i32, + ) { + self.map_pair_mut(handle1, handle2, |co1, co2| { + if let (Some(co1), Some(co2)) = (co1, co2) { + if let (Some(vox1), Some(vox2)) = ( + co1.shape_mut().as_voxels_mut(), + co2.shape_mut().as_voxels_mut(), + ) { + vox1.propagate_voxel_change( + vox2, + IVector::new(ix, iy), + IVector::new(shift_x, shift_y), + ); + } + } + }) + } + + #[cfg(feature = "dim3")] + pub fn coPropagateVoxelChange( + &mut self, + handle1: FlatHandle, + handle2: FlatHandle, + ix: i32, + iy: i32, + iz: i32, + shift_x: i32, + shift_y: i32, + shift_z: i32, + ) { + self.map_pair_mut(handle1, handle2, |co1, co2| { + if let (Some(co1), Some(co2)) = (co1, co2) { + if let (Some(vox1), Some(vox2)) = ( + co1.shape_mut().as_voxels_mut(), + co2.shape_mut().as_voxels_mut(), + ) { + vox1.propagate_voxel_change( + vox2, + IVector::new(ix, iy, iz), + IVector::new(shift_x, shift_y, shift_z), + ); + } + } + }) + } + + #[cfg(feature = "dim2")] + pub fn coCombineVoxelStates( + &mut self, + handle1: FlatHandle, + handle2: FlatHandle, + shift_x: i32, + shift_y: i32, + ) { + self.map_pair_mut(handle1, handle2, |co1, co2| { + if let (Some(co1), Some(co2)) = (co1, co2) { + if let (Some(vox1), Some(vox2)) = ( + co1.shape_mut().as_voxels_mut(), + co2.shape_mut().as_voxels_mut(), + ) { + vox1.combine_voxel_states(vox2, IVector::new(shift_x, shift_y)); + } + } + }) + } + + #[cfg(feature = "dim3")] + pub fn coCombineVoxelStates( + &mut self, + handle1: FlatHandle, + handle2: FlatHandle, + shift_x: i32, + shift_y: i32, + shift_z: i32, + ) { + self.map_pair_mut(handle1, handle2, |co1, co2| { + if let (Some(co1), Some(co2)) = (co1, co2) { + if let (Some(vox1), Some(vox2)) = ( + co1.shape_mut().as_voxels_mut(), + co2.shape_mut().as_voxels_mut(), + ) { + vox1.combine_voxel_states(vox2, IVector::new(shift_x, shift_y, shift_z)); + } + } + }) + } + + /// The vertices of this triangle mesh, polyline, convex polyhedron, segment, triangle or convex polyhedron, if it is one. + /// + /// For convex polyhedra, this returns the vertices of a convex hull recomputed with + /// `try_convex_hull`, so they may differ in count and order from the points the shape + /// was built from. This guarantees the result can be used to reconstruct the shape. + pub fn coVertices(&self, handle: FlatHandle) -> Option> { + let flatten = + |vertices: &[Vector]| vertices.iter().flat_map(|p| p.to_array()).collect(); + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::TriMesh => co.shape().as_trimesh().map(|t| flatten(t.vertices())), + #[cfg(feature = "dim2")] + ShapeType::Polyline => co.shape().as_polyline().map(|p| flatten(p.vertices())), + #[cfg(feature = "dim3")] + ShapeType::ConvexPolyhedron => co + .shape() + .as_convex_polyhedron() + .and_then(normalized_convex_polyhedron_mesh) + .map(|(points, _)| flatten(&points)), + #[cfg(feature = "dim3")] + ShapeType::RoundConvexPolyhedron => co + .shape() + .as_round_convex_polyhedron() + .and_then(|p| normalized_convex_polyhedron_mesh(&p.inner_shape)) + .map(|(points, _)| flatten(&points)), + #[cfg(feature = "dim2")] + ShapeType::ConvexPolygon => co.shape().as_convex_polygon().map(|p| flatten(p.points())), + #[cfg(feature = "dim2")] + ShapeType::RoundConvexPolygon => co + .shape() + .as_round_convex_polygon() + .map(|p| flatten(p.inner_shape.points())), + ShapeType::Segment => co.shape().as_segment().map(|s| flatten(&[s.a, s.b])), + ShapeType::RoundTriangle => co + .shape() + .as_round_triangle() + .map(|t| flatten(&[t.inner_shape.a, t.inner_shape.b, t.inner_shape.c])), + ShapeType::Triangle => co.shape().as_triangle().map(|t| flatten(&[t.a, t.b, t.c])), + _ => None, + }) + } + + /// The indices of this triangle mesh, polyline, or convex polyhedron, if it is one. + /// + /// For convex polyhedra, the indices refer to the convex hull recomputed with + /// `try_convex_hull` (matching `coVertices`), not to the original input mesh. + pub fn coIndices(&self, handle: FlatHandle) -> Option> { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::TriMesh => co + .shape() + .as_trimesh() + .map(|t| t.indices().iter().flat_map(|p| p.iter()).copied().collect()), + ShapeType::Polyline => co + .shape() + .as_polyline() + .map(|p| p.indices().iter().flat_map(|p| p.iter()).copied().collect()), + #[cfg(feature = "dim3")] + ShapeType::ConvexPolyhedron => co + .shape() + .as_convex_polyhedron() + .and_then(normalized_convex_polyhedron_mesh) + .map(|(_, indices)| indices), + #[cfg(feature = "dim3")] + ShapeType::RoundConvexPolyhedron => co + .shape() + .as_round_convex_polyhedron() + .and_then(|p| normalized_convex_polyhedron_mesh(&p.inner_shape)) + .map(|(_, indices)| indices), + _ => None, + }) + } + + pub fn coTriMeshFlags(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| { + co.shape().as_trimesh().map(|tri| tri.flags().bits() as u32) + }) + } + + #[cfg(feature = "dim3")] + pub fn coHeightFieldFlags(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| { + co.shape() + .as_heightfield() + .map(|hf| hf.flags().bits() as u32) + }) + } + + /// The height of this heightfield if it is one. + pub fn coHeightfieldHeights(&self, handle: FlatHandle) -> Option> { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map(|h| { + #[cfg(feature = "dim2")] + { + h.heights().as_slice().to_vec() + } + #[cfg(feature = "dim3")] + { + h.heights().data().to_vec() + } + }), + _ => None, + }) + } + + /// The scaling factor applied to this heightfield if it is one. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim2")] + pub fn coHeightfieldScale( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map_or(false, |h| { + let u = h.scale(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }), + _ => false, + }) + } + + /// The scaling factor applied to this heightfield if it is one. + /// + /// # Parameters + /// - `scratch_buffer`: The array to be populated. + #[cfg(feature = "dim3")] + pub fn coHeightfieldScale( + &self, + handle: FlatHandle, + scratch_buffer: &js_sys::Float32Array, + ) -> bool { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map_or(false, |h| { + let u = h.scale(); + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }), + _ => false, + }) + } + + /// The number of rows on this heightfield's height matrix, if it is one. + #[cfg(feature = "dim3")] + pub fn coHeightfieldNRows(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map(|h| h.nrows()), + _ => None, + }) + } + + /// The number of columns on this heightfield's height matrix, if it is one. + #[cfg(feature = "dim3")] + pub fn coHeightfieldNCols(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| match co.shape().shape_type() { + ShapeType::HeightField => co.shape().as_heightfield().map(|h| h.ncols()), + _ => None, + }) + } + + /// The unique integer identifier of the collider this collider is attached to. + pub fn coParent(&self, handle: FlatHandle) -> Option { + self.map(handle, |co| co.parent().map(|p| utils::flat_handle(p.0))) + } + + pub fn coSetEnabled(&mut self, handle: FlatHandle, enabled: bool) { + self.map_mut(handle, |co| co.set_enabled(enabled)) + } + + pub fn coIsEnabled(&self, handle: FlatHandle) -> bool { + self.map(handle, |co| co.is_enabled()) + } + + pub fn coSetContactSkin(&mut self, handle: FlatHandle, contact_skin: f32) { + self.map_mut(handle, |co| co.set_contact_skin(contact_skin)) + } + + pub fn coContactSkin(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.contact_skin()) + } + + /// The friction coefficient of this collider. + pub fn coFriction(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.material().friction) + } + /// The restitution coefficient of this collider. + pub fn coRestitution(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.material().restitution) + } + + /// The density of this collider. + pub fn coDensity(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.density()) + } + + /// The mass of this collider. + pub fn coMass(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.mass()) + } + + /// The volume of this collider. + pub fn coVolume(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.volume()) + } + + /// The collision groups of this collider. + pub fn coCollisionGroups(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| { + super::pack_interaction_groups(co.collision_groups()) + }) + } + + /// The solver groups of this collider. + pub fn coSolverGroups(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| { + super::pack_interaction_groups(co.solver_groups()) + }) + } + + /// The physics hooks enabled for this collider. + pub fn coActiveHooks(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| co.active_hooks().bits()) + } + + /// The collision types enabled for this collider. + pub fn coActiveCollisionTypes(&self, handle: FlatHandle) -> u16 { + self.map(handle, |co| co.active_collision_types().bits()) + } + + /// The events enabled for this collider. + pub fn coActiveEvents(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| co.active_events().bits()) + } + + /// The total force magnitude beyond which a contact force event can be emitted. + pub fn coContactForceEventThreshold(&self, handle: FlatHandle) -> f32 { + self.map(handle, |co| co.contact_force_event_threshold()) + } + + pub fn coContainsPoint(&self, handle: FlatHandle, point: &RawVector) -> bool { + self.map(handle, |co| { + co.shared_shape() + .containsPoint(co.position(), &point.0.into()) + }) + } + + pub fn coCastShape( + &self, + handle: FlatHandle, + colliderVel: &RawVector, + shape2: &RawShape, + shape2Pos: &RawVector, + shape2Rot: &RawRotation, + shape2Vel: &RawVector, + target_distance: f32, + maxToi: f32, + stop_at_penetration: bool, + ) -> Option { + let pos2 = Pose::from_parts(shape2Pos.0.into(), shape2Rot.0); + + self.map(handle, |co| { + let pos1 = co.position(); + co.shared_shape().castShape( + pos1, + &colliderVel.0.into(), + &*shape2.0, + &pos2, + &shape2Vel.0.into(), + target_distance, + maxToi, + stop_at_penetration, + ) + }) + } + + pub fn coCastCollider( + &self, + handle: FlatHandle, + collider1Vel: &RawVector, + collider2handle: FlatHandle, + collider2Vel: &RawVector, + target_distance: f32, + max_toi: f32, + stop_at_penetration: bool, + ) -> Option { + let handle2 = utils::collider_handle(collider2handle); + let co2 = self + .0 + .get(handle2) + .expect("Invalid Collider reference. It may have been removed from the physics World."); + + self.map(handle, |co| { + query::cast_shapes( + co.position(), + collider1Vel.0, + co.shape(), + co2.position(), + collider2Vel.0, + co2.shape(), + ShapeCastOptions { + max_time_of_impact: max_toi, + stop_at_penetration, + target_distance, + compute_impact_geometry_on_penetration: true, + }, + ) + .unwrap_or(None) + .map_or(None, |hit| { + Some(RawColliderShapeCastHit { + handle: handle2, + hit, + }) + }) + }) + } + + pub fn coIntersectsShape( + &self, + handle: FlatHandle, + shape2: &RawShape, + shapePos2: &RawVector, + shapeRot2: &RawRotation, + ) -> bool { + let pos2 = Pose::from_parts(shapePos2.0.into(), shapeRot2.0); + + self.map(handle, |co| { + co.shared_shape() + .intersectsShape(co.position(), &*shape2.0, &pos2) + }) + } + + pub fn coContactShape( + &self, + handle: FlatHandle, + shape2: &RawShape, + shapePos2: &RawVector, + shapeRot2: &RawRotation, + prediction: f32, + ) -> Option { + let pos2 = Pose::from_parts(shapePos2.0.into(), shapeRot2.0); + + self.map(handle, |co| { + co.shared_shape() + .contactShape(co.position(), &*shape2.0, &pos2, prediction) + }) + } + + pub fn coContactCollider( + &self, + handle: FlatHandle, + collider2handle: FlatHandle, + prediction: f32, + ) -> Option { + let co2 = self + .0 + .get(utils::collider_handle(collider2handle)) + .expect("Invalid Collider reference. It may have been removed from the physics World."); + + self.map(handle, |co| { + query::contact( + co.position(), + co.shape(), + &co2.position(), + co2.shape(), + prediction, + ) + .ok() + .flatten() + .map(|contact| RawShapeContact { contact }) + }) + } + + pub fn coProjectPoint( + &self, + handle: FlatHandle, + point: &RawVector, + solid: bool, + ) -> RawPointProjection { + self.map(handle, |co| { + co.shared_shape() + .projectPoint(co.position(), &point.0.into(), solid) + }) + } + + pub fn coIntersectsRay( + &self, + handle: FlatHandle, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + ) -> bool { + self.map(handle, |co| { + co.shared_shape().intersectsRay( + co.position(), + rayOrig.0.into(), + rayDir.0.into(), + maxToi, + ) + }) + } + + pub fn coCastRay( + &self, + handle: FlatHandle, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + ) -> f32 { + self.map(handle, |co| { + co.shared_shape().castRay( + co.position(), + rayOrig.0.into(), + rayDir.0.into(), + maxToi, + solid, + ) + }) + } + + pub fn coCastRayAndGetNormal( + &self, + handle: FlatHandle, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + ) -> Option { + self.map(handle, |co| { + co.shared_shape().castRayAndGetNormal( + co.position(), + rayOrig.0.into(), + rayDir.0.into(), + maxToi, + solid, + ) + }) + } + + pub fn coSetSensor(&mut self, handle: FlatHandle, is_sensor: bool) { + self.map_mut(handle, |co| co.set_sensor(is_sensor)) + } + + pub fn coSetRestitution(&mut self, handle: FlatHandle, restitution: f32) { + self.map_mut(handle, |co| co.set_restitution(restitution)) + } + + pub fn coSetFriction(&mut self, handle: FlatHandle, friction: f32) { + self.map_mut(handle, |co| co.set_friction(friction)) + } + + pub fn coFrictionCombineRule(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| co.friction_combine_rule() as u32) + } + + pub fn coSetFrictionCombineRule(&mut self, handle: FlatHandle, rule: u32) { + let rule = super::combine_rule_from_u32(rule); + self.map_mut(handle, |co| co.set_friction_combine_rule(rule)) + } + + pub fn coRestitutionCombineRule(&self, handle: FlatHandle) -> u32 { + self.map(handle, |co| co.restitution_combine_rule() as u32) + } + + pub fn coSetRestitutionCombineRule(&mut self, handle: FlatHandle, rule: u32) { + let rule = super::combine_rule_from_u32(rule); + self.map_mut(handle, |co| co.set_restitution_combine_rule(rule)) + } + + pub fn coSetCollisionGroups(&mut self, handle: FlatHandle, groups: u32) { + let groups = super::unpack_interaction_groups(groups); + self.map_mut(handle, |co| co.set_collision_groups(groups)) + } + + pub fn coSetSolverGroups(&mut self, handle: FlatHandle, groups: u32) { + let groups = super::unpack_interaction_groups(groups); + self.map_mut(handle, |co| co.set_solver_groups(groups)) + } + + pub fn coSetActiveHooks(&mut self, handle: FlatHandle, hooks: u32) { + let hooks = ActiveHooks::from_bits(hooks).unwrap_or(ActiveHooks::empty()); + self.map_mut(handle, |co| co.set_active_hooks(hooks)); + } + + pub fn coSetActiveEvents(&mut self, handle: FlatHandle, events: u32) { + let events = ActiveEvents::from_bits(events).unwrap_or(ActiveEvents::empty()); + self.map_mut(handle, |co| co.set_active_events(events)) + } + + pub fn coSetActiveCollisionTypes(&mut self, handle: FlatHandle, types: u16) { + let types = ActiveCollisionTypes::from_bits(types).unwrap_or(ActiveCollisionTypes::empty()); + self.map_mut(handle, |co| co.set_active_collision_types(types)); + } + + pub fn coSetShape(&mut self, handle: FlatHandle, shape: &RawShape) { + self.map_mut(handle, |co| co.set_shape(shape.0.clone())); + } + + pub fn coSetContactForceEventThreshold(&mut self, handle: FlatHandle, threshold: f32) { + self.map_mut(handle, |co| co.set_contact_force_event_threshold(threshold)) + } + + pub fn coSetDensity(&mut self, handle: FlatHandle, density: f32) { + self.map_mut(handle, |co| co.set_density(density)) + } + + pub fn coSetMass(&mut self, handle: FlatHandle, mass: f32) { + self.map_mut(handle, |co| co.set_mass(mass)) + } + + #[cfg(feature = "dim3")] + pub fn coSetMassProperties( + &mut self, + handle: FlatHandle, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: &RawVector, + angularInertiaFrame: &RawRotation, + ) { + self.map_mut(handle, |co| { + let mprops = MassProperties::with_principal_inertia_frame( + centerOfMass.0.into(), + mass, + principalAngularInertia.0, + angularInertiaFrame.0, + ); + + co.set_mass_properties(mprops) + }) + } + + #[cfg(feature = "dim2")] + pub fn coSetMassProperties( + &mut self, + handle: FlatHandle, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: f32, + ) { + self.map_mut(handle, |co| { + let props = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia); + co.set_mass_properties(props) + }) + } +} diff --git a/typescript/src/geometry/collider_set.rs b/typescript/src/geometry/collider_set.rs new file mode 100644 index 000000000..14e715263 --- /dev/null +++ b/typescript/src/geometry/collider_set.rs @@ -0,0 +1,293 @@ +use crate::dynamics::{RawIslandManager, RawRigidBodySet}; +use crate::geometry::RawShape; +use crate::math::{RawRotation, RawVector}; +use crate::utils::{self, FlatHandle}; +use rapier::prelude::*; +use wasm_bindgen::prelude::*; + +// NOTE: this MUST match the same enum on the TS side. +enum MassPropsMode { + Density = 0, + Mass, + MassProps, +} + +#[wasm_bindgen] +pub struct RawColliderSet(pub(crate) ColliderSet); + +impl RawColliderSet { + pub(crate) fn map(&self, handle: FlatHandle, f: impl FnOnce(&Collider) -> T) -> T { + let collider = self + .0 + .get(utils::collider_handle(handle)) + .expect("Invalid Collider reference. It may have been removed from the physics World."); + f(collider) + } + + pub(crate) fn map_mut( + &mut self, + handle: FlatHandle, + f: impl FnOnce(&mut Collider) -> T, + ) -> T { + let collider = self + .0 + .get_mut(utils::collider_handle(handle)) + .expect("Invalid Collider reference. It may have been removed from the physics World."); + f(collider) + } + + pub(crate) fn map_pair_mut( + &mut self, + handle1: FlatHandle, + handle2: FlatHandle, + f: impl FnOnce(Option<&mut Collider>, Option<&mut Collider>) -> T, + ) -> T { + let (collider1, collider2) = self.0.get_pair_mut( + utils::collider_handle(handle1), + utils::collider_handle(handle2), + ); + f(collider1, collider2) + } +} + +impl RawColliderSet { + // This is a workaround because wasm-bindgen doesn't support the `cfg(feature = ...)` + // for the method arguments. + pub fn do_create_collider( + &mut self, + enabled: bool, + shape: &RawShape, + translation: &RawVector, + rotation: &RawRotation, + massPropsMode: u32, + mass: f32, + centerOfMass: &RawVector, + #[cfg(feature = "dim2")] principalAngularInertia: f32, + #[cfg(feature = "dim3")] principalAngularInertia: &RawVector, + #[cfg(feature = "dim3")] angularInertiaFrame: &RawRotation, + density: f32, + friction: f32, + restitution: f32, + frictionCombineRule: u32, + restitutionCombineRule: u32, + isSensor: bool, + collisionGroups: u32, + solverGroups: u32, + activeCollisionTypes: u16, + activeHooks: u32, + activeEvents: u32, + contactForceEventThreshold: f32, + contactSkin: f32, + hasParent: bool, + parent: FlatHandle, + bodies: &mut RawRigidBodySet, + ) -> Option { + let pos = Pose::from_parts(translation.0.into(), rotation.0); + let mut builder = ColliderBuilder::new(shape.0.clone()) + .enabled(enabled) + .position(pos) + .friction(friction) + .restitution(restitution) + .collision_groups(super::unpack_interaction_groups(collisionGroups)) + .solver_groups(super::unpack_interaction_groups(solverGroups)) + .active_hooks(ActiveHooks::from_bits(activeHooks).unwrap_or(ActiveHooks::empty())) + .active_events(ActiveEvents::from_bits(activeEvents).unwrap_or(ActiveEvents::empty())) + .active_collision_types( + ActiveCollisionTypes::from_bits(activeCollisionTypes) + .unwrap_or(ActiveCollisionTypes::empty()), + ) + .sensor(isSensor) + .friction_combine_rule(super::combine_rule_from_u32(frictionCombineRule)) + .restitution_combine_rule(super::combine_rule_from_u32(restitutionCombineRule)) + .contact_force_event_threshold(contactForceEventThreshold) + .contact_skin(contactSkin); + + if massPropsMode == MassPropsMode::MassProps as u32 { + #[cfg(feature = "dim2")] + let mprops = MassProperties::new(centerOfMass.0.into(), mass, principalAngularInertia); + #[cfg(feature = "dim3")] + let mprops = MassProperties::with_principal_inertia_frame( + centerOfMass.0.into(), + mass, + principalAngularInertia.0, + angularInertiaFrame.0, + ); + builder = builder.mass_properties(mprops); + } else if massPropsMode == MassPropsMode::Density as u32 { + builder = builder.density(density); + } else { + assert_eq!(massPropsMode, MassPropsMode::Mass as u32); + builder = builder.mass(mass); + }; + + let collider = builder.build(); + + if hasParent { + Some(utils::flat_handle( + self.0 + .insert_with_parent(collider, utils::body_handle(parent), &mut bodies.0) + .0, + )) + } else { + Some(utils::flat_handle(self.0.insert(collider).0)) + } + } +} + +#[wasm_bindgen] +impl RawColliderSet { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawColliderSet(ColliderSet::new()) + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn contains(&self, handle: FlatHandle) -> bool { + self.0.get(utils::collider_handle(handle)).is_some() + } + + #[cfg(feature = "dim2")] + pub fn createCollider( + &mut self, + enabled: bool, + shape: &RawShape, + translation: &RawVector, + rotation: &RawRotation, + massPropsMode: u32, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: f32, + density: f32, + friction: f32, + restitution: f32, + frictionCombineRule: u32, + restitutionCombineRule: u32, + isSensor: bool, + collisionGroups: u32, + solverGroups: u32, + activeCollisionTypes: u16, + activeHooks: u32, + activeEvents: u32, + contactForceEventThreshold: f32, + contactSkin: f32, + hasParent: bool, + parent: FlatHandle, + bodies: &mut RawRigidBodySet, + ) -> Option { + self.do_create_collider( + enabled, + shape, + translation, + rotation, + massPropsMode, + mass, + centerOfMass, + principalAngularInertia, + density, + friction, + restitution, + frictionCombineRule, + restitutionCombineRule, + isSensor, + collisionGroups, + solverGroups, + activeCollisionTypes, + activeHooks, + activeEvents, + contactForceEventThreshold, + contactSkin, + hasParent, + parent, + bodies, + ) + } + + #[cfg(feature = "dim3")] + pub fn createCollider( + &mut self, + enabled: bool, + shape: &RawShape, + translation: &RawVector, + rotation: &RawRotation, + massPropsMode: u32, + mass: f32, + centerOfMass: &RawVector, + principalAngularInertia: &RawVector, + angularInertiaFrame: &RawRotation, + density: f32, + friction: f32, + restitution: f32, + frictionCombineRule: u32, + restitutionCombineRule: u32, + isSensor: bool, + collisionGroups: u32, + solverGroups: u32, + activeCollisionTypes: u16, + activeHooks: u32, + activeEvents: u32, + contactForceEventThreshold: f32, + contactSkin: f32, + hasParent: bool, + parent: FlatHandle, + bodies: &mut RawRigidBodySet, + ) -> Option { + self.do_create_collider( + enabled, + shape, + translation, + rotation, + massPropsMode, + mass, + centerOfMass, + principalAngularInertia, + angularInertiaFrame, + density, + friction, + restitution, + frictionCombineRule, + restitutionCombineRule, + isSensor, + collisionGroups, + solverGroups, + activeCollisionTypes, + activeHooks, + activeEvents, + contactForceEventThreshold, + contactSkin, + hasParent, + parent, + bodies, + ) + } + + /// Removes a collider from this set and wake-up the rigid-body it is attached to. + pub fn remove( + &mut self, + handle: FlatHandle, + islands: &mut RawIslandManager, + bodies: &mut RawRigidBodySet, + wakeUp: bool, + ) { + let handle = utils::collider_handle(handle); + self.0.remove(handle, &mut islands.0, &mut bodies.0, wakeUp); + } + + /// Checks if a collider with the given integer handle exists. + pub fn isHandleValid(&self, handle: FlatHandle) -> bool { + self.0.get(utils::collider_handle(handle)).is_some() + } + + /// Applies the given JavaScript function to the integer handle of each collider managed by this collider set. + /// + /// # Parameters + /// - `f(handle)`: the function to apply to the integer handle of each collider managed by this collider set. Called as `f(handle)`. + pub fn forEachColliderHandle(&self, f: &js_sys::Function) { + let this = JsValue::null(); + for (handle, _) in self.0.iter() { + let _ = f.call1(&this, &JsValue::from(utils::flat_handle(handle.0))); + } + } +} diff --git a/typescript/src/geometry/contact.rs b/typescript/src/geometry/contact.rs new file mode 100644 index 000000000..5acd09a5b --- /dev/null +++ b/typescript/src/geometry/contact.rs @@ -0,0 +1,54 @@ +use rapier::parry::query; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawShapeContact { + pub(crate) contact: query::Contact, +} + +#[wasm_bindgen] +impl RawShapeContact { + /// Writes the contact components into the given scratch buffer. + /// + /// Layout: `[distance, point1, point2, normal1, normal2]`. + #[cfg(feature = "dim2")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.contact.dist); + let p1 = self.contact.point1; + scratch_buffer.set_index(1, p1.x); + scratch_buffer.set_index(2, p1.y); + let p2 = self.contact.point2; + scratch_buffer.set_index(3, p2.x); + scratch_buffer.set_index(4, p2.y); + let n1 = self.contact.normal1; + scratch_buffer.set_index(5, n1.x); + scratch_buffer.set_index(6, n1.y); + let n2 = self.contact.normal2; + scratch_buffer.set_index(7, n2.x); + scratch_buffer.set_index(8, n2.y); + } + + /// Writes the contact components into the given scratch buffer. + /// + /// Layout: `[distance, point1, point2, normal1, normal2]`. + #[cfg(feature = "dim3")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.contact.dist); + let p1 = self.contact.point1; + scratch_buffer.set_index(1, p1.x); + scratch_buffer.set_index(2, p1.y); + scratch_buffer.set_index(3, p1.z); + let p2 = self.contact.point2; + scratch_buffer.set_index(4, p2.x); + scratch_buffer.set_index(5, p2.y); + scratch_buffer.set_index(6, p2.z); + let n1 = self.contact.normal1; + scratch_buffer.set_index(7, n1.x); + scratch_buffer.set_index(8, n1.y); + scratch_buffer.set_index(9, n1.z); + let n2 = self.contact.normal2; + scratch_buffer.set_index(10, n2.x); + scratch_buffer.set_index(11, n2.y); + scratch_buffer.set_index(12, n2.z); + } +} diff --git a/typescript/src/geometry/feature.rs b/typescript/src/geometry/feature.rs new file mode 100644 index 000000000..96e8f5114 --- /dev/null +++ b/typescript/src/geometry/feature.rs @@ -0,0 +1,47 @@ +use rapier::prelude::FeatureId; +use wasm_bindgen::prelude::wasm_bindgen; + +#[cfg(feature = "dim2")] +#[wasm_bindgen] +#[derive(Copy, Clone)] +pub enum RawFeatureType { + Vertex, + Face, + Unknown, +} + +#[cfg(feature = "dim3")] +#[wasm_bindgen] +#[derive(Copy, Clone)] +pub enum RawFeatureType { + Vertex, + Edge, + Face, + Unknown, +} + +pub trait IntoTypeValue { + fn into_type(self) -> RawFeatureType; + fn into_value(self) -> Option; +} + +impl IntoTypeValue for FeatureId { + fn into_type(self) -> RawFeatureType { + match self { + FeatureId::Vertex(_) => RawFeatureType::Vertex, + #[cfg(feature = "dim3")] + FeatureId::Edge(_) => RawFeatureType::Edge, + FeatureId::Face(_) => RawFeatureType::Face, + _ => RawFeatureType::Unknown, + } + } + + fn into_value(self) -> Option { + match self { + FeatureId::Vertex(id) | FeatureId::Face(id) => Some(id), + #[cfg(feature = "dim3")] + FeatureId::Edge(id) => Some(id), + _ => None, + } + } +} diff --git a/typescript/src/geometry/mod.rs b/typescript/src/geometry/mod.rs new file mode 100644 index 000000000..4f398d921 --- /dev/null +++ b/typescript/src/geometry/mod.rs @@ -0,0 +1,50 @@ +//! Structures related to geometry: colliders, shapes, etc. + +pub use self::broad_phase::*; +pub use self::collider_set::*; +pub use self::contact::*; +pub use self::feature::*; +pub use self::narrow_phase::*; +pub use self::point::*; +pub use self::ray::*; +pub use self::shape::*; +pub use self::toi::*; + +mod broad_phase; +mod collider; +mod collider_set; +mod contact; +mod feature; +mod narrow_phase; +mod point; +mod ray; +mod shape; +mod toi; + +use rapier::dynamics::CoefficientCombineRule; +use rapier::geometry::{InteractionGroups, InteractionTestMode}; +use rapier::prelude::Group; + +pub const fn unpack_interaction_groups(memberships_filter: u32) -> InteractionGroups { + InteractionGroups::new( + Group::from_bits_retain((memberships_filter >> 16) as u32), + Group::from_bits_retain((memberships_filter & 0x0000_ffff) as u32), + InteractionTestMode::And, + ) +} + +pub const fn pack_interaction_groups(groups: InteractionGroups) -> u32 { + (groups.memberships.bits() << 16) | groups.filter.bits() +} + +pub const fn combine_rule_from_u32(rule: u32) -> CoefficientCombineRule { + if rule == CoefficientCombineRule::Average as u32 { + CoefficientCombineRule::Average + } else if rule == CoefficientCombineRule::Min as u32 { + CoefficientCombineRule::Min + } else if rule == CoefficientCombineRule::Multiply as u32 { + CoefficientCombineRule::Multiply + } else { + CoefficientCombineRule::Max + } +} diff --git a/typescript/src/geometry/narrow_phase.rs b/typescript/src/geometry/narrow_phase.rs new file mode 100644 index 000000000..874f950b4 --- /dev/null +++ b/typescript/src/geometry/narrow_phase.rs @@ -0,0 +1,334 @@ +use crate::utils::{self, FlatHandle}; +use rapier::geometry::{ContactManifold, ContactPair, NarrowPhase}; +use rapier::math::Real; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawNarrowPhase(pub(crate) NarrowPhase); + +#[wasm_bindgen] +impl RawNarrowPhase { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawNarrowPhase(NarrowPhase::new()) + } + + pub fn contact_pairs_with(&self, handle1: FlatHandle, f: js_sys::Function) { + let this = JsValue::null(); + let handle1 = utils::collider_handle(handle1); + for pair in self.0.contact_pairs_with(handle1) { + let handle2 = if pair.collider1 == handle1 { + utils::flat_handle(pair.collider2.0) + } else { + utils::flat_handle(pair.collider1.0) + }; + + let _ = f.call1(&this, &JsValue::from(handle2)); + } + } + + pub fn contact_pair(&self, handle1: FlatHandle, handle2: FlatHandle) -> Option { + let handle1 = utils::collider_handle(handle1); + let handle2 = utils::collider_handle(handle2); + self.0 + .contact_pair(handle1, handle2) + .map(|p| RawContactPair(p as *const ContactPair)) + } + + pub fn intersection_pairs_with(&self, handle1: FlatHandle, f: js_sys::Function) { + let this = JsValue::null(); + let handle1 = utils::collider_handle(handle1); + for (h1, h2, inter) in self.0.intersection_pairs_with(handle1) { + if inter { + let handle2 = if h1 == handle1 { + utils::flat_handle(h2.0) + } else { + utils::flat_handle(h1.0) + }; + + let _ = f.call1(&this, &JsValue::from(handle2)); + } + } + } + + pub fn intersection_pair(&self, handle1: FlatHandle, handle2: FlatHandle) -> bool { + let handle1 = utils::collider_handle(handle1); + let handle2 = utils::collider_handle(handle2); + self.0.intersection_pair(handle1, handle2) == Some(true) + } +} + +#[wasm_bindgen] +pub struct RawContactPair(*const ContactPair); +#[wasm_bindgen] +pub struct RawContactManifold(*const ContactManifold); + +// SAFETY: the use of a raw pointer is very unsafe. +// We need this because wasm-bindgen doesn't support +// lifetimes. So for the moment, we have to make sure +// that our TypeScript wrapper properly free the pair +// before the user has a chance to invalidate this pointer. +#[wasm_bindgen] +impl RawContactPair { + pub fn collider1(&self) -> FlatHandle { + unsafe { utils::flat_handle((*self.0).collider1.0) } + } + + pub fn collider2(&self) -> FlatHandle { + unsafe { utils::flat_handle((*self.0).collider2.0) } + } + + pub fn numContactManifolds(&self) -> usize { + unsafe { (*self.0).manifolds.len() } + } + pub fn contactManifold(&self, i: usize) -> Option { + unsafe { + (&(*self.0).manifolds) + .get(i) + .map(|m| RawContactManifold(m as *const ContactManifold)) + } + } +} + +#[wasm_bindgen] +impl RawContactManifold { + #[cfg(feature = "dim2")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).data.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).data.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + } + + // pub fn user_data(&self) -> u32 { + // unsafe { (*self.0).data.user_data } + // } + + #[cfg(feature = "dim2")] + pub fn local_n1(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn local_n1(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + } + + #[cfg(feature = "dim2")] + pub fn local_n2(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn local_n2(&self, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (*self.0).local_n2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + } + + pub fn subshape1(&self) -> u32 { + unsafe { (*self.0).subshape1 } + } + + pub fn subshape2(&self) -> u32 { + unsafe { (*self.0).subshape2 } + } + + pub fn num_contacts(&self) -> usize { + unsafe { (*self.0).points.len() } + } + + #[cfg(feature = "dim2")] + pub fn contact_local_p1(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_local_p1(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p1; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + } + + #[cfg(feature = "dim2")] + pub fn contact_local_p2(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_local_p2(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).points).get(i).map_or(false, |c| { + let u = c.local_p2; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + } + + pub fn contact_dist(&self, i: usize) -> Real { + unsafe { (&(*self.0).points).get(i).map(|c| c.dist).unwrap_or(0.0) } + } + + pub fn contact_fid1(&self, i: usize) -> u32 { + unsafe { (&(*self.0).points).get(i).map(|c| c.fid1.0).unwrap_or(0) } + } + + pub fn contact_fid2(&self, i: usize) -> u32 { + unsafe { (&(*self.0).points).get(i).map(|c| c.fid2.0).unwrap_or(0) } + } + + pub fn contact_impulse(&self, i: usize) -> Real { + unsafe { + (&(*self.0).points) + .get(i) + .map(|c| c.data.impulse) + .unwrap_or(0.0) + } + } + + #[cfg(feature = "dim2")] + pub fn contact_tangent_impulse(&self, i: usize) -> Real { + unsafe { + (&(*self.0).points) + .get(i) + .map(|c| c.data.tangent_impulse.x) + .unwrap_or(0.0) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_tangent_impulse_x(&self, i: usize) -> Real { + unsafe { + (&(*self.0).points) + .get(i) + .map(|c| c.data.tangent_impulse.x) + .unwrap_or(0.0) + } + } + + #[cfg(feature = "dim3")] + pub fn contact_tangent_impulse_y(&self, i: usize) -> Real { + unsafe { + (&(*self.0).points) + .get(i) + .map(|c| c.data.tangent_impulse.y) + .unwrap_or(0.0) + } + } + + pub fn num_solver_contacts(&self) -> usize { + unsafe { (*self.0).data.solver_contacts.len() } + } + + #[cfg(feature = "dim2")] + pub fn solver_contact_point(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).data).solver_contacts.get(i).map_or(false, |c| { + let u = c.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + true + }) + } + } + + #[cfg(feature = "dim3")] + pub fn solver_contact_point(&self, i: usize, scratch_buffer: &js_sys::Float32Array) -> bool { + unsafe { + (&(*self.0).data).solver_contacts.get(i).map_or(false, |c| { + let u = c.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + true + }) + } + } + + pub fn solver_contact_dist(&self, i: usize) -> Real { + unsafe { + (&(*self.0).data) + .solver_contacts + .get(i) + .map(|c| c.dist) + .unwrap_or(0.0) + } + } + + pub fn solver_contact_friction(&self, i: usize) -> Real { + unsafe { (&(*self.0).data).solver_contacts[i].friction } + } + + pub fn solver_contact_restitution(&self, i: usize) -> Real { + unsafe { (&(*self.0).data).solver_contacts[i].restitution } + } + + #[cfg(feature = "dim2")] + pub fn solver_contact_tangent_velocity(&self, i: usize, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (&(*self.0).data).solver_contacts[i].tangent_velocity; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + } + + #[cfg(feature = "dim3")] + pub fn solver_contact_tangent_velocity(&self, i: usize, scratch_buffer: &js_sys::Float32Array) { + unsafe { + let u = (&(*self.0).data).solver_contacts[i].tangent_velocity; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + } +} diff --git a/typescript/src/geometry/point.rs b/typescript/src/geometry/point.rs new file mode 100644 index 000000000..a9c6ed823 --- /dev/null +++ b/typescript/src/geometry/point.rs @@ -0,0 +1,78 @@ +use crate::geometry::feature::IntoTypeValue; +use crate::geometry::RawFeatureType; +use crate::utils::{self, FlatHandle}; +use rapier::{ + geometry::{ColliderHandle, PointProjection}, + prelude::FeatureId, +}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawPointProjection(pub(crate) PointProjection); + +#[wasm_bindgen] +impl RawPointProjection { + /// Writes the projected point components into the given scratch buffer. + #[cfg(feature = "dim2")] + pub fn point(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + /// Writes the projected point components into the given scratch buffer. + #[cfg(feature = "dim3")] + pub fn point(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn isInside(&self) -> bool { + self.0.is_inside + } +} + +#[wasm_bindgen] +pub struct RawPointColliderProjection { + pub(crate) handle: ColliderHandle, + pub(crate) proj: PointProjection, + pub(crate) feature: FeatureId, +} + +#[wasm_bindgen] +impl RawPointColliderProjection { + pub fn colliderHandle(&self) -> FlatHandle { + utils::flat_handle(self.handle.0) + } + + /// Writes the projected point components into the given scratch buffer. + #[cfg(feature = "dim2")] + pub fn point(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.proj.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + /// Writes the projected point components into the given scratch buffer. + #[cfg(feature = "dim3")] + pub fn point(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.proj.point; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn isInside(&self) -> bool { + self.proj.is_inside + } + + pub fn featureType(&self) -> RawFeatureType { + self.feature.into_type() + } + + pub fn featureId(&self) -> Option { + self.feature.into_value() + } +} diff --git a/typescript/src/geometry/ray.rs b/typescript/src/geometry/ray.rs new file mode 100644 index 000000000..a99723cc0 --- /dev/null +++ b/typescript/src/geometry/ray.rs @@ -0,0 +1,99 @@ +use crate::geometry::feature::IntoTypeValue; +use crate::geometry::RawFeatureType; +use crate::utils::{self, FlatHandle}; +use rapier::geometry::{ColliderHandle, RayIntersection}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawRayIntersection(pub(crate) RayIntersection); + +#[wasm_bindgen] +impl RawRayIntersection { + /// Writes the hit normal components into the given scratch buffer. + #[cfg(feature = "dim2")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + /// Writes the hit normal components into the given scratch buffer. + #[cfg(feature = "dim3")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn time_of_impact(&self) -> f32 { + self.0.time_of_impact + } + + pub fn featureType(&self) -> RawFeatureType { + self.0.feature.into_type() + } + + pub fn featureId(&self) -> Option { + self.0.feature.into_value() + } +} + +#[wasm_bindgen] +pub struct RawRayColliderIntersection { + pub(crate) handle: ColliderHandle, + pub(crate) inter: RayIntersection, +} + +#[wasm_bindgen] +impl RawRayColliderIntersection { + pub fn colliderHandle(&self) -> FlatHandle { + utils::flat_handle(self.handle.0) + } + + /// Writes the hit normal components into the given scratch buffer. + #[cfg(feature = "dim2")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.inter.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + } + + /// Writes the hit normal components into the given scratch buffer. + #[cfg(feature = "dim3")] + pub fn normal(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.inter.normal; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + scratch_buffer.set_index(2, u.z); + } + + pub fn time_of_impact(&self) -> f32 { + self.inter.time_of_impact + } + + pub fn featureType(&self) -> RawFeatureType { + self.inter.feature.into_type() + } + + pub fn featureId(&self) -> Option { + self.inter.feature.into_value() + } +} + +#[wasm_bindgen] +pub struct RawRayColliderHit { + pub(crate) handle: ColliderHandle, + pub(crate) timeOfImpact: f32, +} + +#[wasm_bindgen] +impl RawRayColliderHit { + pub fn colliderHandle(&self) -> FlatHandle { + utils::flat_handle(self.handle.0) + } + + pub fn timeOfImpact(&self) -> f32 { + self.timeOfImpact + } +} diff --git a/typescript/src/geometry/shape.rs b/typescript/src/geometry/shape.rs new file mode 100644 index 000000000..c6463feca --- /dev/null +++ b/typescript/src/geometry/shape.rs @@ -0,0 +1,1331 @@ +use crate::geometry::{RawPointProjection, RawRayIntersection, RawShapeCastHit, RawShapeContact}; +use crate::math::{RawRotation, RawVector}; +use rapier::geometry::{Shape, SharedShape, TriMeshFlags}; +use rapier::math::{IVector, Pose, Rotation, Vector, DIM}; +#[cfg(feature = "dim3")] +use rapier::parry::utils::Array2; +use rapier::parry::query; +use rapier::parry::query::{Ray, ShapeCastOptions}; +use rapier::parry::transformation::vhacd::{VHACDParameters, VHACD}; +use wasm_bindgen::prelude::*; + +pub trait SharedShapeUtility { + fn castShape( + &self, + shapePos1: &Pose, + shapeVel1: &Vector, + shape2: &dyn Shape, + shapePos2: &Pose, + shapeVel2: &Vector, + target_distance: f32, + maxToi: f32, + stop_at_penetration: bool, + ) -> Option; + + fn intersectsShape( + &self, + shapePos1: &Pose, + shape2: &dyn Shape, + shapePos2: &Pose, + ) -> bool; + + fn contactShape( + &self, + shapePos1: &Pose, + shape2: &dyn Shape, + shapePos2: &Pose, + prediction: f32, + ) -> Option; + + fn containsPoint(&self, shapePos: &Pose, point: &Vector) -> bool; + + fn projectPoint( + &self, + shapePos: &Pose, + point: &Vector, + solid: bool, + ) -> RawPointProjection; + + fn intersectsRay( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + ) -> bool; + + fn castRay( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + solid: bool, + ) -> f32; + + fn castRayAndGetNormal( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + solid: bool, + ) -> Option; +} + +#[cfg(feature = "dim3")] +pub(crate) fn normalized_convex_polyhedron_mesh( + polyhedron: &rapier::parry::shape::ConvexPolyhedron, +) -> Option<(Vec, Vec)> { + let (points, indices) = + rapier::parry::transformation::try_convex_hull(polyhedron.points()).ok()?; + let flat_indices = indices + .iter() + .flat_map(|triangle| triangle.iter()) + .copied() + .collect(); + Some((points, flat_indices)) +} + +// for RawShape & Collider +impl SharedShapeUtility for SharedShape { + fn castShape( + &self, + shapePos1: &Pose, + shapeVel1: &Vector, + shape2: &dyn Shape, + shapePos2: &Pose, + shapeVel2: &Vector, + target_distance: f32, + maxToi: f32, + stop_at_penetration: bool, + ) -> Option { + query::cast_shapes( + shapePos1, + *shapeVel1, + &*self.0, + shapePos2, + *shapeVel2, + shape2, + ShapeCastOptions { + max_time_of_impact: maxToi, + target_distance, + stop_at_penetration, + compute_impact_geometry_on_penetration: true, + }, + ) + .ok() + .flatten() + .map(|hit| RawShapeCastHit { hit }) + } + + fn intersectsShape( + &self, + shapePos1: &Pose, + shape2: &dyn Shape, + shapePos2: &Pose, + ) -> bool { + query::intersection_test(shapePos1, &*self.0, shapePos2, shape2).unwrap_or(false) + } + + fn contactShape( + &self, + shapePos1: &Pose, + shape2: &dyn Shape, + shapePos2: &Pose, + prediction: f32, + ) -> Option { + query::contact(shapePos1, &*self.0, shapePos2, shape2, prediction) + .ok() + .flatten() + .map(|contact| RawShapeContact { contact }) + } + + fn containsPoint(&self, shapePos: &Pose, point: &Vector) -> bool { + self.as_ref().contains_point(shapePos, *point) + } + + fn projectPoint( + &self, + shapePos: &Pose, + point: &Vector, + solid: bool, + ) -> RawPointProjection { + RawPointProjection(self.as_ref().project_point(shapePos, *point, solid)) + } + + fn intersectsRay( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + ) -> bool { + self.as_ref() + .intersects_ray(shapePos, &Ray::new(rayOrig, rayDir), maxToi) + } + + fn castRay( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + solid: bool, + ) -> f32 { + self.as_ref() + .cast_ray(shapePos, &Ray::new(rayOrig, rayDir), maxToi, solid) + .unwrap_or(-1.0) // Negative value = no hit. + } + + fn castRayAndGetNormal( + &self, + shapePos: &Pose, + rayOrig: Vector, + rayDir: Vector, + maxToi: f32, + solid: bool, + ) -> Option { + self.as_ref() + .cast_ray_and_get_normal(shapePos, &Ray::new(rayOrig, rayDir), maxToi, solid) + .map(|inter| RawRayIntersection(inter)) + } +} + +#[wasm_bindgen] +#[cfg(feature = "dim2")] +pub enum RawShapeType { + Ball = 0, + Cuboid = 1, + Capsule = 2, + Segment = 3, + Polyline = 4, + Triangle = 5, + TriMesh = 6, + HeightField = 7, + Compound = 8, + ConvexPolygon = 9, + RoundCuboid = 10, + RoundTriangle = 11, + RoundConvexPolygon = 12, + HalfSpace = 13, + Voxels = 14, +} + +#[wasm_bindgen] +#[cfg(feature = "dim3")] +pub enum RawShapeType { + Ball = 0, + Cuboid = 1, + Capsule = 2, + Segment = 3, + Polyline = 4, + Triangle = 5, + TriMesh = 6, + HeightField = 7, + Compound = 8, + ConvexPolyhedron = 9, + Cylinder = 10, + Cone = 11, + RoundCuboid = 12, + RoundTriangle = 13, + RoundCylinder = 14, + RoundCone = 15, + RoundConvexPolyhedron = 16, + HalfSpace = 17, + Voxels = 18, +} + +/// Parameters for VHACD convex decomposition algorithm +#[wasm_bindgen] +pub struct RawVHACDParameters(pub(crate) VHACDParameters); + +#[wasm_bindgen] +impl RawVHACDParameters { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawVHACDParameters(VHACDParameters::default()) + } + + #[wasm_bindgen(getter)] + pub fn alpha(&self) -> f32 { + self.0.alpha + } + #[wasm_bindgen(setter)] + pub fn set_alpha(&mut self, val: f32) { + self.0.alpha = val.clamp(0.0, 1.0); + } + + #[wasm_bindgen(getter)] + pub fn beta(&self) -> f32 { + self.0.beta + } + #[wasm_bindgen(setter)] + pub fn set_beta(&mut self, val: f32) { + self.0.beta = val.clamp(0.0, 1.0); + } + + #[wasm_bindgen(getter)] + pub fn concavity(&self) -> f32 { + self.0.concavity + } + #[wasm_bindgen(setter)] + pub fn set_concavity(&mut self, val: f32) { + self.0.concavity = val.clamp(0.0, 1.0); + } + + #[wasm_bindgen(getter)] + pub fn plane_downsampling(&self) -> u32 { + self.0.plane_downsampling + } + #[wasm_bindgen(setter)] + pub fn set_plane_downsampling(&mut self, val: u32) { + self.0.plane_downsampling = val; + } + + #[wasm_bindgen(getter)] + pub fn convex_hull_downsampling(&self) -> u32 { + self.0.convex_hull_downsampling + } + #[wasm_bindgen(setter)] + pub fn set_convex_hull_downsampling(&mut self, val: u32) { + self.0.convex_hull_downsampling = val; + } + + #[wasm_bindgen(getter)] + pub fn max_convex_hulls(&self) -> u32 { + self.0.max_convex_hulls + } + #[wasm_bindgen(setter)] + pub fn set_max_convex_hulls(&mut self, val: u32) { + self.0.max_convex_hulls = val; + } + + #[wasm_bindgen(getter)] + pub fn resolution(&self) -> u32 { + self.0.resolution + } + #[wasm_bindgen(setter)] + pub fn set_resolution(&mut self, val: u32) { + self.0.resolution = val; + } + + #[wasm_bindgen(getter)] + pub fn convex_hull_approximation(&self) -> bool { + self.0.convex_hull_approximation + } + #[wasm_bindgen(setter)] + pub fn set_convex_hull_approximation(&mut self, val: bool) { + self.0.convex_hull_approximation = val; + } +} + +/// The vertex/index buffers of a convex polyhedron’s convex hull. +#[cfg(feature = "dim3")] +#[wasm_bindgen(getter_with_clone)] +pub struct RawConvexMeshData { + pub vertices: Vec, + pub indices: Vec, +} + +#[wasm_bindgen] +pub struct RawShape(pub(crate) SharedShape); + +#[wasm_bindgen] +impl RawShape { + pub fn shapeType(&self) -> RawShapeType { + match self.0.shape_type() { + rapier::geometry::ShapeType::Ball => RawShapeType::Ball, + rapier::geometry::ShapeType::Cuboid => RawShapeType::Cuboid, + rapier::geometry::ShapeType::Capsule => RawShapeType::Capsule, + rapier::geometry::ShapeType::Segment => RawShapeType::Segment, + rapier::geometry::ShapeType::Polyline => RawShapeType::Polyline, + rapier::geometry::ShapeType::Triangle => RawShapeType::Triangle, + rapier::geometry::ShapeType::TriMesh => RawShapeType::TriMesh, + rapier::geometry::ShapeType::HeightField => RawShapeType::HeightField, + rapier::geometry::ShapeType::Compound => RawShapeType::Compound, + rapier::geometry::ShapeType::HalfSpace => RawShapeType::HalfSpace, + rapier::geometry::ShapeType::Voxels => RawShapeType::Voxels, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::ConvexPolyhedron => RawShapeType::ConvexPolyhedron, + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::ConvexPolygon => RawShapeType::ConvexPolygon, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cylinder => RawShapeType::Cylinder, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cone => RawShapeType::Cone, + rapier::geometry::ShapeType::RoundCuboid => RawShapeType::RoundCuboid, + rapier::geometry::ShapeType::RoundTriangle => RawShapeType::RoundTriangle, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCylinder => RawShapeType::RoundCylinder, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCone => RawShapeType::RoundCone, + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundConvexPolyhedron => { + RawShapeType::RoundConvexPolyhedron + } + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::RoundConvexPolygon => RawShapeType::RoundConvexPolygon, + rapier::geometry::ShapeType::Custom => panic!("Not yet implemented."), + } + } + + pub fn halfspaceNormal(&self) -> Option { + self.0 + .as_halfspace() + .map(|halfspace| halfspace.normal.into()) + } + + pub fn halfExtents(&self) -> Option { + self.0 + .as_cuboid() + .map(|cuboid| cuboid.half_extents.into()) + .or_else(|| { + self.0 + .as_round_cuboid() + .map(|cuboid| cuboid.inner_shape.half_extents.into()) + }) + } + + pub fn radius(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::Ball => self.0.as_ball().map(|ball| ball.radius), + rapier::geometry::ShapeType::Capsule => { + self.0.as_capsule().map(|capsule| capsule.radius) + } + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cylinder => { + self.0.as_cylinder().map(|cylinder| cylinder.radius) + } + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCylinder => self + .0 + .as_round_cylinder() + .map(|cylinder| cylinder.inner_shape.radius), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cone => self.0.as_cone().map(|cone| cone.radius), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCone => { + self.0.as_round_cone().map(|cone| cone.inner_shape.radius) + } + _ => None, + } + } + + pub fn halfHeight(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::Capsule => { + self.0.as_capsule().map(|capsule| capsule.half_height()) + } + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cylinder => { + self.0.as_cylinder().map(|cylinder| cylinder.half_height) + } + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCylinder => self + .0 + .as_round_cylinder() + .map(|cylinder| cylinder.inner_shape.half_height), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::Cone => self.0.as_cone().map(|cone| cone.half_height), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCone => self + .0 + .as_round_cone() + .map(|cone| cone.inner_shape.half_height), + _ => None, + } + } + + pub fn roundRadius(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::RoundCuboid => { + self.0.as_round_cuboid().map(|cuboid| cuboid.border_radius) + } + rapier::geometry::ShapeType::RoundTriangle => self + .0 + .as_round_triangle() + .map(|triangle| triangle.border_radius), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCylinder => self + .0 + .as_round_cylinder() + .map(|cylinder| cylinder.border_radius), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundCone => { + self.0.as_round_cone().map(|cone| cone.border_radius) + } + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundConvexPolyhedron => self + .0 + .as_round_convex_polyhedron() + .map(|polyhedron| polyhedron.border_radius), + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::RoundConvexPolygon => self + .0 + .as_round_convex_polygon() + .map(|polygon| polygon.border_radius), + _ => None, + } + } + + pub fn voxelData(&self) -> Option> { + let voxels = self.0.as_voxels()?; + Some( + voxels + .voxels() + .filter_map(|vox| (!vox.state.is_empty()).then_some(vox.grid_coords)) + .flat_map(|ids| ids.to_array()) + .collect(), + ) + } + + pub fn voxelSize(&self) -> Option { + self.0 + .as_voxels() + .map(|voxels| RawVector(voxels.voxel_size())) + } + + /// The vertices of this shape, if it is vertex-based. + /// + /// For convex polyhedra, this returns the vertices of a convex hull recomputed with + /// `try_convex_hull` (so they may differ in count and order from the points the shape + /// was built from), ensuring the result can be fed back to `RawShape::convexMesh`. + /// If both `vertices` and `indices` are needed, prefer `convexMeshData` which computes + /// the convex hull only once. + pub fn vertices(&self) -> Option> { + let flatten = |vertices: &[Vector]| { + vertices + .iter() + .flat_map(|point| point.to_array()) + .collect() + }; + + match self.0.shape_type() { + rapier::geometry::ShapeType::TriMesh => { + self.0.as_trimesh().map(|mesh| flatten(mesh.vertices())) + } + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::Polyline => self + .0 + .as_polyline() + .map(|polyline| flatten(polyline.vertices())), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::ConvexPolyhedron => self + .0 + .as_convex_polyhedron() + .and_then(normalized_convex_polyhedron_mesh) + .map(|(points, _)| flatten(&points)), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundConvexPolyhedron => self + .0 + .as_round_convex_polyhedron() + .and_then(|polyhedron| normalized_convex_polyhedron_mesh(&polyhedron.inner_shape)) + .map(|(points, _)| flatten(&points)), + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::ConvexPolygon => self + .0 + .as_convex_polygon() + .map(|polygon| flatten(polygon.points())), + #[cfg(feature = "dim2")] + rapier::geometry::ShapeType::RoundConvexPolygon => self + .0 + .as_round_convex_polygon() + .map(|polygon| flatten(polygon.inner_shape.points())), + rapier::geometry::ShapeType::Segment => self + .0 + .as_segment() + .map(|segment| flatten(&[segment.a, segment.b])), + rapier::geometry::ShapeType::RoundTriangle => { + self.0.as_round_triangle().map(|triangle| { + flatten(&[ + triangle.inner_shape.a, + triangle.inner_shape.b, + triangle.inner_shape.c, + ]) + }) + } + rapier::geometry::ShapeType::Triangle => self + .0 + .as_triangle() + .map(|triangle| flatten(&[triangle.a, triangle.b, triangle.c])), + _ => None, + } + } + + pub fn indices(&self) -> Option> { + match self.0.shape_type() { + rapier::geometry::ShapeType::TriMesh => self.0.as_trimesh().map(|mesh| { + mesh.indices() + .iter() + .flat_map(|triangle| triangle.iter()) + .copied() + .collect() + }), + rapier::geometry::ShapeType::Polyline => self.0.as_polyline().map(|polyline| { + polyline + .indices() + .iter() + .flat_map(|segment| segment.iter()) + .copied() + .collect() + }), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::ConvexPolyhedron => self + .0 + .as_convex_polyhedron() + .and_then(normalized_convex_polyhedron_mesh) + .map(|(_, indices)| indices), + #[cfg(feature = "dim3")] + rapier::geometry::ShapeType::RoundConvexPolyhedron => self + .0 + .as_round_convex_polyhedron() + .and_then(|polyhedron| normalized_convex_polyhedron_mesh(&polyhedron.inner_shape)) + .map(|(_, indices)| indices), + _ => None, + } + } + + /// The vertices and indices of the convex hull of this convex polyhedron, recomputed + /// with `try_convex_hull` so that the result can always be fed back to + /// `RawShape::convexMesh`. + /// + /// This computes the convex hull only once, unlike calling both `vertices()` and + /// `indices()`. + #[cfg(feature = "dim3")] + pub fn convexMeshData(&self) -> Option { + let polyhedron = match self.0.shape_type() { + rapier::geometry::ShapeType::ConvexPolyhedron => self.0.as_convex_polyhedron(), + rapier::geometry::ShapeType::RoundConvexPolyhedron => self + .0 + .as_round_convex_polyhedron() + .map(|polyhedron| &polyhedron.inner_shape), + _ => None, + }?; + let (points, indices) = normalized_convex_polyhedron_mesh(polyhedron)?; + Some(RawConvexMeshData { + vertices: points + .iter() + .flat_map(|point| point.to_array()) + .collect(), + indices, + }) + } + + pub fn triMeshFlags(&self) -> Option { + self.0 + .as_trimesh() + .map(|trimesh| trimesh.flags().bits() as u32) + } + + #[cfg(feature = "dim3")] + pub fn heightFieldFlags(&self) -> Option { + self.0 + .as_heightfield() + .map(|heightfield| heightfield.flags().bits() as u32) + } + + pub fn heightfieldHeights(&self) -> Option> { + match self.0.shape_type() { + rapier::geometry::ShapeType::HeightField => self.0.as_heightfield().map(|heightfield| { + #[cfg(feature = "dim2")] + { + heightfield.heights().as_slice().to_vec() + } + #[cfg(feature = "dim3")] + { + heightfield.heights().data().to_vec() + } + }), + _ => None, + } + } + + pub fn heightfieldScale(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::HeightField => self + .0 + .as_heightfield() + .map(|heightfield| RawVector(heightfield.scale())), + _ => None, + } + } + + #[cfg(feature = "dim3")] + pub fn heightfieldNRows(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::HeightField => self + .0 + .as_heightfield() + .map(|heightfield| heightfield.nrows()), + _ => None, + } + } + + #[cfg(feature = "dim3")] + pub fn heightfieldNCols(&self) -> Option { + match self.0.shape_type() { + rapier::geometry::ShapeType::HeightField => self + .0 + .as_heightfield() + .map(|heightfield| heightfield.ncols()), + _ => None, + } + } + + pub fn compoundLen(&self) -> Option { + self.0.as_compound().map(|compound| compound.shapes().len()) + } + + pub fn compoundShape(&self, index: usize) -> Option { + self.0 + .as_compound() + .and_then(|compound| compound.shapes().get(index)) + .map(|(_, shape)| RawShape(shape.clone())) + } + + pub fn compoundTranslation(&self, index: usize) -> Option { + self.0 + .as_compound() + .and_then(|compound| compound.shapes().get(index)) + .map(|(position, _)| position.translation.into()) + } + + pub fn compoundRotation(&self, index: usize) -> Option { + self.0 + .as_compound() + .and_then(|compound| compound.shapes().get(index)) + .map(|(position, _)| position.rotation.into()) + } + + #[cfg(feature = "dim2")] + pub fn cuboid(hx: f32, hy: f32) -> Self { + Self(SharedShape::cuboid(hx, hy)) + } + + #[cfg(feature = "dim3")] + pub fn cuboid(hx: f32, hy: f32, hz: f32) -> Self { + Self(SharedShape::cuboid(hx, hy, hz)) + } + + #[cfg(feature = "dim2")] + pub fn roundCuboid(hx: f32, hy: f32, borderRadius: f32) -> Self { + Self(SharedShape::round_cuboid(hx, hy, borderRadius)) + } + + #[cfg(feature = "dim3")] + pub fn roundCuboid(hx: f32, hy: f32, hz: f32, borderRadius: f32) -> Self { + Self(SharedShape::round_cuboid(hx, hy, hz, borderRadius)) + } + + pub fn ball(radius: f32) -> Self { + Self(SharedShape::ball(radius)) + } + + pub fn halfspace(normal: &RawVector) -> Self { + Self(SharedShape::halfspace(normal.0.normalize())) + } + + pub fn capsule(halfHeight: f32, radius: f32) -> Self { + let p2 = Vector::Y * halfHeight; + let p1 = -p2; + Self(SharedShape::capsule(p1, p2, radius)) + } + + #[cfg(feature = "dim3")] + pub fn cylinder(halfHeight: f32, radius: f32) -> Self { + Self(SharedShape::cylinder(halfHeight, radius)) + } + + #[cfg(feature = "dim3")] + pub fn roundCylinder(halfHeight: f32, radius: f32, borderRadius: f32) -> Self { + Self(SharedShape::round_cylinder( + halfHeight, + radius, + borderRadius, + )) + } + + #[cfg(feature = "dim3")] + pub fn cone(halfHeight: f32, radius: f32) -> Self { + Self(SharedShape::cone(halfHeight, radius)) + } + + #[cfg(feature = "dim3")] + pub fn roundCone(halfHeight: f32, radius: f32, borderRadius: f32) -> Self { + Self(SharedShape::round_cone(halfHeight, radius, borderRadius)) + } + + pub fn voxels(voxel_size: &RawVector, grid_coords: Vec) -> Self { + let grid_coords: Vec<_> = grid_coords + .chunks_exact(DIM) + .map(IVector::from_slice) + .collect(); + Self(SharedShape::voxels(voxel_size.0, &grid_coords)) + } + + pub fn voxelsFromPoints(voxel_size: &RawVector, points: Vec) -> Self { + let points: Vec<_> = points.chunks_exact(DIM).map(Vector::from_slice).collect(); + Self(SharedShape::voxels_from_points(voxel_size.0, &points)) + } + + pub fn polyline(vertices: Vec, indices: Vec) -> Self { + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + let indices: Vec<_> = indices.chunks(2).map(|v| [v[0], v[1]]).collect(); + if indices.is_empty() { + Self(SharedShape::polyline(vertices, None)) + } else { + Self(SharedShape::polyline(vertices, Some(indices))) + } + } + + pub fn trimesh(vertices: Vec, indices: Vec, flags: u32) -> Option { + let flags = TriMeshFlags::from_bits(flags as u16).unwrap_or_default(); + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + let indices = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect(); + SharedShape::trimesh_with_flags(vertices, indices, flags) + .ok() + .map(Self) + } + + #[cfg(feature = "dim2")] + pub fn heightfield(heights: Vec, scale: &RawVector) -> Self { + Self(SharedShape::heightfield(heights, scale.0)) + } + + #[cfg(feature = "dim3")] + pub fn heightfield( + nrows: u32, + ncols: u32, + heights: Vec, + scale: &RawVector, + flags: u32, + ) -> Self { + let flags = + rapier::parry::shape::HeightFieldFlags::from_bits(flags as u8).unwrap_or_default(); + let heights = Array2::new(nrows as usize + 1, ncols as usize + 1, heights); + Self(SharedShape::heightfield_with_flags(heights, scale.0, flags)) + } + + pub fn segment(p1: &RawVector, p2: &RawVector) -> Self { + Self(SharedShape::segment(p1.0.into(), p2.0.into())) + } + + pub fn triangle(p1: &RawVector, p2: &RawVector, p3: &RawVector) -> Self { + Self(SharedShape::triangle(p1.0.into(), p2.0.into(), p3.0.into())) + } + + pub fn roundTriangle( + p1: &RawVector, + p2: &RawVector, + p3: &RawVector, + borderRadius: f32, + ) -> Self { + Self(SharedShape::round_triangle( + p1.0.into(), + p2.0.into(), + p3.0.into(), + borderRadius, + )) + } + + pub fn convexHull(points: Vec) -> Option { + let points: Vec<_> = points.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + SharedShape::convex_hull(&points).map(|s| Self(s)) + } + + pub fn roundConvexHull(points: Vec, borderRadius: f32) -> Option { + let points: Vec<_> = points.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + SharedShape::round_convex_hull(&points, borderRadius).map(|s| Self(s)) + } + + #[cfg(feature = "dim2")] + pub fn convexPolyline(vertices: Vec) -> Option { + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + SharedShape::convex_polyline(vertices).map(|s| Self(s)) + } + + #[cfg(feature = "dim2")] + pub fn roundConvexPolyline(vertices: Vec, borderRadius: f32) -> Option { + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + SharedShape::round_convex_polyline(vertices, borderRadius).map(|s| Self(s)) + } + + #[cfg(feature = "dim3")] + pub fn convexMesh(vertices: Vec, indices: Vec) -> Option { + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + let indices: Vec<_> = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect(); + SharedShape::convex_mesh(vertices, &indices).map(|s| Self(s)) + } + + #[cfg(feature = "dim3")] + pub fn roundConvexMesh( + vertices: Vec, + indices: Vec, + borderRadius: f32, + ) -> Option { + let vertices = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + let indices: Vec<_> = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect(); + SharedShape::round_convex_mesh(vertices, &indices, borderRadius).map(|s| Self(s)) + } + + pub fn compound(shapes: Vec, positions: Vec, rotations: Vec) -> RawShape { + let mut compound_parts = Vec::new(); + let num_shapes = shapes.len(); + + assert_eq!( + positions.len(), + num_shapes * DIM, + "The compound positions array must contain DIM entries per shape." + ); + #[cfg(feature = "dim2")] + assert_eq!( + rotations.len(), + num_shapes, + "The compound rotations array must contain one angle per shape." + ); + #[cfg(feature = "dim3")] + assert_eq!( + rotations.len(), + num_shapes * 4, + "The compound rotations array must contain one quaternion (4 entries) per shape." + ); + + for i in 0..num_shapes { + let pos_offset = i * DIM; + + #[cfg(feature = "dim2")] + let translation = Vector::new(positions[pos_offset], positions[pos_offset + 1]); + + #[cfg(feature = "dim3")] + let translation = Vector::new( + positions[pos_offset], + positions[pos_offset + 1], + positions[pos_offset + 2], + ); + + #[cfg(feature = "dim2")] + let rotation = Rotation::new(rotations[i]); + + #[cfg(feature = "dim3")] + let rotation = { + let rot_offset = i * 4; + Rotation::from_xyzw( + rotations[rot_offset], // x + rotations[rot_offset + 1], // y + rotations[rot_offset + 2], // z + rotations[rot_offset + 3], // w + ) + }; + + let pose = Pose::from_parts(translation, rotation); + compound_parts.push((pose, shapes[i].0.clone())); + } + + Self(SharedShape::compound(compound_parts)) + } + + pub fn convexDecomposition(vertices: Vec, indices: Vec) -> Option { + Self::convexDecompositionWithParams(vertices, indices, &RawVHACDParameters::new()) + } + + pub fn convexDecompositionWithParams( + vertices: Vec, + indices: Vec, + params: &RawVHACDParameters, + ) -> Option { + let vertices: Vec<_> = vertices.chunks(DIM).map(|v| Vector::from_slice(v)).collect(); + #[cfg(feature = "dim2")] + let indices: Vec<_> = indices.chunks(2).map(|v| [v[0], v[1]]).collect(); + #[cfg(feature = "dim3")] + let indices: Vec<_> = indices.chunks(3).map(|v| [v[0], v[1], v[2]]).collect(); + + // Same as `SharedShape::convex_decomposition_with_params`, except that a + // decomposition yielding no convex part returns `None` instead of panicking + // when building the empty compound. + let decomp = VHACD::decompose(¶ms.0, &vertices, &indices, true); + let mut parts = vec![]; + + #[cfg(feature = "dim2")] + for hull_vertices in decomp.compute_exact_convex_hulls(&vertices, &indices) { + if let Some(convex) = SharedShape::convex_polyline(hull_vertices) { + parts.push((Pose::identity(), convex)); + } + } + + #[cfg(feature = "dim3")] + for (hull_vertices, hull_indices) in decomp.compute_exact_convex_hulls(&vertices, &indices) + { + if let Some(convex) = SharedShape::convex_mesh(hull_vertices, &hull_indices) { + parts.push((Pose::identity(), convex)); + } + } + + if parts.is_empty() { + return None; + } + + Some(Self(SharedShape::compound(parts))) + } + + pub fn castShape( + &self, + shapePos1: &RawVector, + shapeRot1: &RawRotation, + shapeVel1: &RawVector, + shape2: &RawShape, + shapePos2: &RawVector, + shapeRot2: &RawRotation, + shapeVel2: &RawVector, + target_distance: f32, + maxToi: f32, + stop_at_penetration: bool, + ) -> Option { + let pos1 = Pose::from_parts(shapePos1.0.into(), shapeRot1.0); + let pos2 = Pose::from_parts(shapePos2.0.into(), shapeRot2.0); + + self.0.castShape( + &pos1, + &shapeVel1.0, + &*shape2.0, + &pos2, + &shapeVel2.0, + target_distance, + maxToi, + stop_at_penetration, + ) + } + + pub fn intersectsShape( + &self, + shapePos1: &RawVector, + shapeRot1: &RawRotation, + shape2: &RawShape, + shapePos2: &RawVector, + shapeRot2: &RawRotation, + ) -> bool { + let pos1 = Pose::from_parts(shapePos1.0.into(), shapeRot1.0); + let pos2 = Pose::from_parts(shapePos2.0.into(), shapeRot2.0); + + self.0.intersectsShape(&pos1, &*shape2.0, &pos2) + } + + pub fn contactShape( + &self, + shapePos1: &RawVector, + shapeRot1: &RawRotation, + shape2: &RawShape, + shapePos2: &RawVector, + shapeRot2: &RawRotation, + prediction: f32, + ) -> Option { + let pos1 = Pose::from_parts(shapePos1.0.into(), shapeRot1.0); + let pos2 = Pose::from_parts(shapePos2.0.into(), shapeRot2.0); + + self.0.contactShape(&pos1, &*shape2.0, &pos2, prediction) + } + + pub fn containsPoint( + &self, + shapePos: &RawVector, + shapeRot: &RawRotation, + point: &RawVector, + ) -> bool { + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + self.0.containsPoint(&pos, &point.0.into()) + } + + pub fn projectPoint( + &self, + shapePos: &RawVector, + shapeRot: &RawRotation, + point: &RawVector, + solid: bool, + ) -> RawPointProjection { + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + self.0.projectPoint(&pos, &point.0.into(), solid) + } + + pub fn intersectsRay( + &self, + shapePos: &RawVector, + shapeRot: &RawRotation, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + ) -> bool { + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + self.0 + .intersectsRay(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi) + } + + pub fn castRay( + &self, + shapePos: &RawVector, + shapeRot: &RawRotation, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + ) -> f32 { + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + self.0 + .castRay(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi, solid) + } + + pub fn castRayAndGetNormal( + &self, + shapePos: &RawVector, + shapeRot: &RawRotation, + rayOrig: &RawVector, + rayDir: &RawVector, + maxToi: f32, + solid: bool, + ) -> Option { + let pos = Pose::from_parts(shapePos.0.into(), shapeRot.0); + + self.0 + .castRayAndGetNormal(&pos, rayOrig.0.into(), rayDir.0.into(), maxToi, solid) + } +} + +#[cfg(all(test, feature = "dim3"))] +mod tests { + use super::RawShape; + + #[test] + fn convex_decomposition_of_degenerate_mesh_returns_none() { + // A single zero-area triangle can’t produce any convex part. + let vertices = vec![0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 0.0, 0.0]; + let indices = vec![0, 1, 2]; + assert!(RawShape::convexDecomposition(vertices, indices).is_none()); + } + + #[test] + fn raw_convex_mesh_accessors_round_trip_with_collinear_boundary_vertex() { + let vertices = vec![ + 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.5, + ]; + let indices = vec![ + [0, 2, 1], + [0, 3, 2], + [4, 5, 6], + [4, 6, 7], + [0, 1, 5], + [0, 5, 8], + [8, 5, 4], + [0, 8, 7], + [8, 4, 7], + [0, 7, 3], + [1, 2, 6], + [1, 6, 5], + [2, 3, 7], + [2, 7, 6], + ]; + let flat_indices: Vec = indices + .iter() + .flat_map(|triangle| triangle.iter()) + .copied() + .collect(); + + let raw_shape = RawShape::convexMesh(vertices, flat_indices).unwrap(); + let roundtrip_vertices = raw_shape.vertices().unwrap(); + let roundtrip_indices = raw_shape.indices().unwrap(); + + assert!(RawShape::convexMesh(roundtrip_vertices, roundtrip_indices).is_some()); + } + + #[test] + fn captured_invalid_convex_mesh_export_is_not_reconstructable() { + let vertices = vec![ + -3.2503600120544434, + 19.476539611816406, + -2.0955400466918945, + -3.3597400188446045, + 19.960920333862305, + -2.0330400466918945, + -3.1253600120544434, + 20.30466079711914, + -2.126800060272217, + -2.3614742755889893, + 20.145801544189453, + -1.71620512008667, + -3.3284800052642822, + 20.007780075073242, + -1.8768000602722168, + -2.3614742755889893, + 20.138565063476562, + -1.8094041347503662, + -3.1878600120544434, + 19.476539611816406, + -1.8924200534820557, + -2.3614742755889893, + 20.05278968811035, + -1.4539750814437866, + -2.3614742755889893, + 20.1295166015625, + -1.4817370176315308, + -3.0941200256347656, + 20.382780075073242, + -1.8768000602722168, + -2.3614742755889893, + 19.238826751708984, + -1.366246223449707, + -2.3614742755889893, + 19.214706420898438, + -1.3726158142089844, + -2.3614742755889893, + 19.113746643066406, + -1.4277477264404297, + -2.3614742755889893, + 19.131973266601562, + -1.6892800331115723, + -2.3614742755889893, + 19.141845703125, + -1.792968511581421, + -2.526392936706543, + 20.19354248046875, + -1.9115056991577148, + -2.448280096054077, + 19.144739151000977, + -1.7378942966461182, + -2.448280096054077, + 19.153003692626953, + -1.824700117111206, + -2.7034800052642822, + 19.195280075073242, + -2.0174200534820557, + -2.448280096054077, + 19.155406951904297, + -1.8499374389648438, + -2.406599998474121, + 20.17966079711914, + -1.5018000602722168, + -2.4691200256347656, + 20.085920333862305, + -1.4705400466918945, + -2.688455820083618, + 19.69875144958496, + -2.0099079608917236, + -2.6722400188446045, + 20.24216079711914, + -2.001800060272217, + -2.7034800052642822, + 19.185195922851562, + -1.9115058183670044, + -2.6722400188446045, + 20.320280075073242, + -1.6580400466918945, + -2.7034800052642822, + 19.164039611816406, + -1.6892800331115723, + ]; + let indices = vec![ + 1, 4, 9, 1, 0, 4, 6, 4, 0, 6, 10, 4, 2, 1, 9, 2, 0, 1, 26, 6, 0, 26, 12, 6, 11, 6, 12, + 11, 10, 6, 21, 20, 25, 21, 25, 9, 21, 9, 4, 21, 4, 10, 8, 20, 21, 8, 21, 7, 26, 0, 18, + 13, 12, 26, 13, 26, 18, 13, 18, 14, 3, 5, 25, 3, 25, 20, 3, 20, 8, 7, 21, 10, 7, 10, + 11, 7, 11, 12, 7, 12, 13, 7, 13, 14, 7, 14, 5, 7, 5, 3, 7, 3, 8, 18, 0, 2, 18, 23, 5, + 25, 5, 23, 23, 15, 5, 23, 22, 18, 23, 18, 2, 23, 2, 9, 23, 9, 25, 18, 5, 14, + ]; + + assert!(RawShape::convexMesh(vertices, indices).is_none()); + } + + #[test] + fn raw_convex_hull_accessors_round_trip_with_redundant_points() { + let vertices = vec![ + -3.2503600120544434, + 19.476539611816406, + -2.0955400466918945, + -3.3597400188446045, + 19.960920333862305, + -2.0330400466918945, + -3.1253600120544434, + 20.30466079711914, + -2.126800060272217, + -2.3614742755889893, + 20.145801544189453, + -1.71620512008667, + -3.3284800052642822, + 20.007780075073242, + -1.8768000602722168, + -2.3614742755889893, + 20.138565063476562, + -1.8094041347503662, + -3.1878600120544434, + 19.476539611816406, + -1.8924200534820557, + -2.3614742755889893, + 20.05278968811035, + -1.4539750814437866, + -2.3614742755889893, + 20.1295166015625, + -1.4817370176315308, + -3.0941200256347656, + 20.382780075073242, + -1.8768000602722168, + -2.3614742755889893, + 19.238826751708984, + -1.366246223449707, + -2.3614742755889893, + 19.214706420898438, + -1.3726158142089844, + -2.3614742755889893, + 19.113746643066406, + -1.4277477264404297, + -2.3614742755889893, + 19.131973266601562, + -1.6892800331115723, + -2.3614742755889893, + 19.141845703125, + -1.792968511581421, + -2.526392936706543, + 20.19354248046875, + -1.9115056991577148, + -2.448280096054077, + 19.144739151000977, + -1.7378942966461182, + -2.448280096054077, + 19.153003692626953, + -1.824700117111206, + -2.7034800052642822, + 19.195280075073242, + -2.0174200534820557, + -2.448280096054077, + 19.155406951904297, + -1.8499374389648438, + -2.406599998474121, + 20.17966079711914, + -1.5018000602722168, + -2.4691200256347656, + 20.085920333862305, + -1.4705400466918945, + -2.688455820083618, + 19.69875144958496, + -2.0099079608917236, + -2.6722400188446045, + 20.24216079711914, + -2.001800060272217, + -2.7034800052642822, + 19.185195922851562, + -1.9115058183670044, + -2.6722400188446045, + 20.320280075073242, + -1.6580400466918945, + -2.7034800052642822, + 19.164039611816406, + -1.6892800331115723, + ]; + + let raw_shape = RawShape::convexHull(vertices).unwrap(); + let roundtrip_vertices = raw_shape.vertices().unwrap(); + let roundtrip_indices = raw_shape.indices().unwrap(); + + assert!(RawShape::convexMesh(roundtrip_vertices, roundtrip_indices).is_some()); + } +} diff --git a/typescript/src/geometry/toi.rs b/typescript/src/geometry/toi.rs new file mode 100644 index 000000000..4ee1ac5a5 --- /dev/null +++ b/typescript/src/geometry/toi.rs @@ -0,0 +1,97 @@ +use crate::utils::{self, FlatHandle}; +use rapier::geometry::{ColliderHandle, ShapeCastHit}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawShapeCastHit { + pub(crate) hit: ShapeCastHit, +} + +#[wasm_bindgen] +impl RawShapeCastHit { + #[cfg(feature = "dim2")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1; + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + u = self.hit.witness2; + scratch_buffer.set_index(3, u.x); + scratch_buffer.set_index(4, u.y); + u = self.hit.normal1; + scratch_buffer.set_index(5, u.x); + scratch_buffer.set_index(6, u.y); + u = self.hit.normal2; + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + } + #[cfg(feature = "dim3")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1; + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + scratch_buffer.set_index(3, u.z); + u = self.hit.witness2; + scratch_buffer.set_index(4, u.x); + scratch_buffer.set_index(5, u.y); + scratch_buffer.set_index(6, u.z); + u = self.hit.normal1; + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + scratch_buffer.set_index(9, u.z); + u = self.hit.normal2; + scratch_buffer.set_index(10, u.x); + scratch_buffer.set_index(11, u.y); + scratch_buffer.set_index(12, u.z); + } +} + +#[wasm_bindgen] +pub struct RawColliderShapeCastHit { + pub(crate) handle: ColliderHandle, + pub(crate) hit: ShapeCastHit, +} + +#[wasm_bindgen] +impl RawColliderShapeCastHit { + pub fn colliderHandle(&self) -> FlatHandle { + utils::flat_handle(self.handle.0) + } + #[cfg(feature = "dim2")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1; + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + u = self.hit.witness2; + scratch_buffer.set_index(3, u.x); + scratch_buffer.set_index(4, u.y); + u = self.hit.normal1; + scratch_buffer.set_index(5, u.x); + scratch_buffer.set_index(6, u.y); + u = self.hit.normal2; + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + } + #[cfg(feature = "dim3")] + pub fn getComponents(&self, scratch_buffer: &js_sys::Float32Array) { + scratch_buffer.set_index(0, self.hit.time_of_impact); + let mut u = self.hit.witness1; + scratch_buffer.set_index(1, u.x); + scratch_buffer.set_index(2, u.y); + scratch_buffer.set_index(3, u.z); + u = self.hit.witness2; + scratch_buffer.set_index(4, u.x); + scratch_buffer.set_index(5, u.y); + scratch_buffer.set_index(6, u.z); + u = self.hit.normal1; + scratch_buffer.set_index(7, u.x); + scratch_buffer.set_index(8, u.y); + scratch_buffer.set_index(9, u.z); + u = self.hit.normal2; + scratch_buffer.set_index(10, u.x); + scratch_buffer.set_index(11, u.y); + scratch_buffer.set_index(12, u.z); + } +} diff --git a/typescript/src/lib.rs b/typescript/src/lib.rs new file mode 100644 index 000000000..132809dc6 --- /dev/null +++ b/typescript/src/lib.rs @@ -0,0 +1,32 @@ +//! # Rapier +//! Fast and deterministic WASM physics engine. + +#![allow(non_snake_case)] // JS uses camelCase, so we will follow its convention for the generated bindings. + // #![deny(missing_docs)] + +extern crate nalgebra as na; +#[cfg(feature = "dim2")] +extern crate rapier2d as rapier; +#[cfg(feature = "dim3")] +extern crate rapier3d as rapier; +#[macro_use] +extern crate serde; + +#[wasm_bindgen::prelude::wasm_bindgen] +pub fn version() -> String { + env!("CARGO_PKG_VERSION").to_string() +} + +#[wasm_bindgen::prelude::wasm_bindgen] +pub fn reserve_memory(extra_bytes_count: u32) { + let mut unused: Vec = vec![]; + unused.reserve(extra_bytes_count as usize); + std::hint::black_box(&unused); +} + +pub mod control; +pub mod dynamics; +pub mod geometry; +pub mod math; +pub mod pipeline; +pub mod utils; diff --git a/typescript/src/math.rs b/typescript/src/math.rs new file mode 100644 index 000000000..2581e4af9 --- /dev/null +++ b/typescript/src/math.rs @@ -0,0 +1,251 @@ +//! Linear algebra primitives. + +#[cfg(feature = "dim3")] +use js_sys::Float32Array; +#[cfg(feature = "dim3")] +use rapier::math::Real; +use rapier::math::{Rotation, Vector}; +#[cfg(feature = "dim3")] +use rapier::parry::utils::SdpMatrix3; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[repr(transparent)] +#[derive(Copy, Clone)] +/// A rotation quaternion. +pub struct RawRotation(pub(crate) Rotation); + +impl From for RawRotation { + fn from(v: Rotation) -> Self { + RawRotation(v) + } +} + +#[wasm_bindgen] +#[cfg(feature = "dim2")] +/// A unit complex number describing the orientation of a Rapier entity. +impl RawRotation { + /// The identity rotation. + pub fn identity() -> Self { + Self(Rotation::identity()) + } + + /// The rotation with thegiven angle. + pub fn fromAngle(angle: f32) -> Self { + Self(Rotation::new(angle)) + } + + /// The imaginary part of this complex number. + #[wasm_bindgen(getter)] + pub fn im(&self) -> f32 { + self.0.im + } + + /// The real part of this complex number. + #[wasm_bindgen(getter)] + pub fn re(&self) -> f32 { + self.0.re + } + + /// The rotation angle in radians. + #[wasm_bindgen(getter)] + pub fn angle(&self) -> f32 { + self.0.angle() + } +} + +#[wasm_bindgen] +#[cfg(feature = "dim3")] +/// A unit quaternion describing the orientation of a Rapier entity. +impl RawRotation { + #[wasm_bindgen(constructor)] + pub fn new(x: f32, y: f32, z: f32, w: f32) -> Self { + RawRotation(Rotation::from_xyzw(x, y, z, w)) + } + + /// The identity quaternion. + pub fn identity() -> Self { + Self(Rotation::IDENTITY) + } + + /// The `x` component of this quaternion. + #[wasm_bindgen(getter)] + pub fn x(&self) -> f32 { + self.0.x + } + + /// The `y` component of this quaternion. + #[wasm_bindgen(getter)] + pub fn y(&self) -> f32 { + self.0.y + } + + /// The `z` component of this quaternion. + #[wasm_bindgen(getter)] + pub fn z(&self) -> f32 { + self.0.z + } + + /// The `w` component of this quaternion. + #[wasm_bindgen(getter)] + pub fn w(&self) -> f32 { + self.0.w + } +} + +#[wasm_bindgen] +#[repr(transparent)] +#[derive(Copy, Clone)] +/// A vector. +pub struct RawVector(pub(crate) Vector); + +impl From for RawVector { + fn from(v: Vector) -> Self { + RawVector(v) + } +} + +#[wasm_bindgen] +impl RawVector { + /// Creates a new vector filled with zeros. + pub fn zero() -> Self { + Self(Vector::ZERO) + } + + /// Creates a new 2D vector from its two components. + /// + /// # Parameters + /// - `x`: the `x` component of this 2D vector. + /// - `y`: the `y` component of this 2D vector. + #[cfg(feature = "dim2")] + #[wasm_bindgen(constructor)] + pub fn new(x: f32, y: f32) -> Self { + Self(Vector::new(x, y)) + } + + /// Creates a new 3D vector from its two components. + /// + /// # Parameters + /// - `x`: the `x` component of this 3D vector. + /// - `y`: the `y` component of this 3D vector. + /// - `z`: the `z` component of this 3D vector. + #[cfg(feature = "dim3")] + #[wasm_bindgen(constructor)] + pub fn new(x: f32, y: f32, z: f32) -> Self { + Self(Vector::new(x, y, z)) + } + + /// The `x` component of this vector. + #[wasm_bindgen(getter)] + pub fn x(&self) -> f32 { + self.0.x + } + + /// Sets the `x` component of this vector. + #[wasm_bindgen(setter)] + pub fn set_x(&mut self, x: f32) { + self.0.x = x + } + + /// The `y` component of this vector. + #[wasm_bindgen(getter)] + pub fn y(&self) -> f32 { + self.0.y + } + + /// Sets the `y` component of this vector. + #[wasm_bindgen(setter)] + pub fn set_y(&mut self, y: f32) { + self.0.y = y + } + + /// The `z` component of this vector. + #[cfg(feature = "dim3")] + #[wasm_bindgen(getter)] + pub fn z(&self) -> f32 { + self.0.z + } + + /// Sets the `z` component of this vector. + #[cfg(feature = "dim3")] + #[wasm_bindgen(setter)] + pub fn set_z(&mut self, z: f32) { + self.0.z = z + } + + /// Create a new 2D vector from this vector with its components rearranged as `{x, y}`. + #[cfg(feature = "dim2")] + pub fn xy(&self) -> Self { + Self(Vector::new(self.0.x, self.0.y)) + } + + /// Create a new 2D vector from this vector with its components rearranged as `{y, x}`. + #[cfg(feature = "dim2")] + pub fn yx(&self) -> Self { + Self(Vector::new(self.0.y, self.0.x)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{x, y, z}`. + /// + /// This will effectively return a copy of `this`. This method exist for completeness with the + /// other swizzling functions. + #[cfg(feature = "dim3")] + pub fn xyz(&self) -> Self { + Self(Vector::new(self.0.x, self.0.y, self.0.z)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{y, x, z}`. + #[cfg(feature = "dim3")] + pub fn yxz(&self) -> Self { + Self(Vector::new(self.0.y, self.0.x, self.0.z)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{z, x, y}`. + #[cfg(feature = "dim3")] + pub fn zxy(&self) -> Self { + Self(Vector::new(self.0.z, self.0.x, self.0.y)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{x, z, y}`. + #[cfg(feature = "dim3")] + pub fn xzy(&self) -> Self { + Self(Vector::new(self.0.x, self.0.z, self.0.y)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{y, z, x}`. + #[cfg(feature = "dim3")] + pub fn yzx(&self) -> Self { + Self(Vector::new(self.0.y, self.0.z, self.0.x)) + } + + /// Create a new 3D vector from this vector with its components rearranged as `{z, y, x}`. + #[cfg(feature = "dim3")] + pub fn zyx(&self) -> Self { + Self(Vector::new(self.0.z, self.0.y, self.0.x)) + } +} + +#[wasm_bindgen] +#[repr(transparent)] +#[derive(Copy, Clone)] +#[cfg(feature = "dim3")] +pub struct RawSdpMatrix3(pub(crate) SdpMatrix3); + +#[cfg(feature = "dim3")] +impl From> for RawSdpMatrix3 { + fn from(v: SdpMatrix3) -> Self { + RawSdpMatrix3(v) + } +} + +#[wasm_bindgen] +#[cfg(feature = "dim3")] +impl RawSdpMatrix3 { + /// Row major list of the upper-triangular part of the symmetric matrix. + pub fn elements(&self) -> Float32Array { + let m = self.0; + let output = Float32Array::new_with_length(6); + output.copy_from(&[m.m11, m.m12, m.m13, m.m22, m.m23, m.m33]); + output + } +} diff --git a/typescript/src/pipeline/debug_render_pipeline.rs b/typescript/src/pipeline/debug_render_pipeline.rs new file mode 100644 index 000000000..f39fff106 --- /dev/null +++ b/typescript/src/pipeline/debug_render_pipeline.rs @@ -0,0 +1,152 @@ +use crate::dynamics::{RawImpulseJointSet, RawMultibodyJointSet, RawRigidBodySet}; +use crate::geometry::{RawColliderSet, RawNarrowPhase}; +use js_sys::Float32Array; +use palette::convert::IntoColorUnclamped; +use palette::rgb::Rgba; +use palette::Hsla; +use rapier::dynamics::{RigidBody, RigidBodySet}; +use rapier::geometry::ColliderSet; +use rapier::math::Vector; +use rapier::pipeline::{DebugRenderBackend, DebugRenderObject, DebugRenderPipeline}; +use rapier::prelude::{QueryFilter, QueryFilterFlags}; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawDebugRenderPipeline { + pub(crate) raw: DebugRenderPipeline, + vertices: Vec, + colors: Vec, +} + +#[wasm_bindgen] +impl RawDebugRenderPipeline { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawDebugRenderPipeline { + raw: DebugRenderPipeline::default(), + vertices: vec![], + colors: vec![], + } + } + + pub fn vertices(&self) -> Float32Array { + let output = Float32Array::new_with_length(self.vertices.len() as u32); + output.copy_from(&self.vertices); + output + } + + pub fn colors(&self) -> Float32Array { + let output = Float32Array::new_with_length(self.colors.len() as u32); + output.copy_from(&self.colors); + output + } + + pub fn render( + &mut self, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + impulse_joints: &RawImpulseJointSet, + multibody_joints: &RawMultibodyJointSet, + narrow_phase: &RawNarrowPhase, + filter_flags: u32, + filter_predicate: &js_sys::Function, + ) { + self.vertices.clear(); + self.colors.clear(); + + crate::utils::with_filter(filter_predicate, |predicate| { + let mut backend = CopyToBuffersBackend { + filter: QueryFilter { + flags: QueryFilterFlags::from_bits(filter_flags) + .unwrap_or(QueryFilterFlags::empty()), + groups: None, + exclude_collider: None, + exclude_rigid_body: None, + predicate, + }, + bodies: &bodies.0, + colliders: &colliders.0, + vertices: &mut self.vertices, + colors: &mut self.colors, + }; + + self.raw.render( + &mut backend, + &bodies.0, + &colliders.0, + &impulse_joints.0, + &multibody_joints.0, + &narrow_phase.0, + ) + }) + } +} + +struct CopyToBuffersBackend<'a> { + filter: QueryFilter<'a>, + bodies: &'a RigidBodySet, + colliders: &'a ColliderSet, + vertices: &'a mut Vec, + colors: &'a mut Vec, +} + +impl<'a> DebugRenderBackend for CopyToBuffersBackend<'a> { + fn filter_object(&self, object: DebugRenderObject) -> bool { + let test_rigid_body = |rb: &RigidBody| { + rb.colliders().iter().all(|handle| { + let Some(co) = self.colliders.get(*handle) else { + return false; + }; + self.filter.test(self.bodies, *handle, co) + }) + }; + + match object { + DebugRenderObject::Collider(handle, co) + | DebugRenderObject::ColliderAabb(handle, co, _) => { + self.filter.test(self.bodies, handle, co) + } + DebugRenderObject::ContactPair(pair, co1, co2) => { + self.filter.test(self.bodies, pair.collider1, co1) + && self.filter.test(self.bodies, pair.collider2, co2) + } + DebugRenderObject::ImpulseJoint(_, joint) => { + let Some(rb1) = self.bodies.get(joint.body1()) else { + return false; + }; + let Some(rb2) = self.bodies.get(joint.body2()) else { + return false; + }; + test_rigid_body(rb1) && test_rigid_body(rb2) + } + DebugRenderObject::MultibodyJoint(_, _, link) => { + let Some(rb) = self.bodies.get(link.rigid_body_handle()) else { + return false; + }; + test_rigid_body(rb) + } + DebugRenderObject::RigidBody(_, rb) => test_rigid_body(rb), + } + } + + /// Draws a colored line. + /// + /// Note that this method can be called multiple time for the same `object`. + fn draw_line( + &mut self, + _object: DebugRenderObject, + a: Vector, + b: Vector, + color: [f32; 4], + ) { + self.vertices.extend_from_slice(&a.to_array()); + self.vertices.extend_from_slice(&b.to_array()); + + // Convert to RGB which will be easier to handle in JS. + let hsl = Hsla::new(color[0], color[1], color[2], color[3]); + let rgb: Rgba = hsl.into_color_unclamped(); + self.colors.extend_from_slice(&[ + rgb.red, rgb.green, rgb.blue, rgb.alpha, rgb.red, rgb.green, rgb.blue, rgb.alpha, + ]); + } +} diff --git a/typescript/src/pipeline/event_queue.rs b/typescript/src/pipeline/event_queue.rs new file mode 100644 index 000000000..af61b6273 --- /dev/null +++ b/typescript/src/pipeline/event_queue.rs @@ -0,0 +1,147 @@ +use crate::utils; +use crate::utils::FlatHandle; +use rapier::geometry::{CollisionEvent, ContactForceEvent}; +use rapier::pipeline::ChannelEventCollector; +use std::sync::mpsc::Receiver; +use wasm_bindgen::prelude::*; + +/// A structure responsible for collecting events generated +/// by the physics engine. +#[wasm_bindgen] +pub struct RawEventQueue { + pub(crate) collector: ChannelEventCollector, + collision_events: Receiver, + contact_force_events: Receiver, + pub(crate) auto_drain: bool, +} + +#[wasm_bindgen] +pub struct RawContactForceEvent(ContactForceEvent); + +#[wasm_bindgen] +impl RawContactForceEvent { + /// The first collider involved in the contact. + pub fn collider1(&self) -> FlatHandle { + crate::utils::flat_handle(self.0.collider1.0) + } + + /// The second collider involved in the contact. + pub fn collider2(&self) -> FlatHandle { + crate::utils::flat_handle(self.0.collider2.0) + } + + /// The sum of all the forces between the two colliders. + pub fn total_force(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.total_force; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + #[cfg(feature = "dim3")] + scratch_buffer.set_index(2, u.z); + } + + /// The sum of the magnitudes of each force between the two colliders. + /// + /// Note that this is **not** the same as the magnitude of `self.total_force`. + /// Here we are summing the magnitude of all the forces, instead of taking + /// the magnitude of their sum. + pub fn total_force_magnitude(&self) -> f32 { + self.0.total_force_magnitude + } + + /// The world-space (unit) direction of the force with strongest magnitude. + pub fn max_force_direction(&self, scratch_buffer: &js_sys::Float32Array) { + let u = self.0.max_force_direction; + scratch_buffer.set_index(0, u.x); + scratch_buffer.set_index(1, u.y); + #[cfg(feature = "dim3")] + scratch_buffer.set_index(2, u.z); + } + + /// The magnitude of the largest force at a contact point of this contact pair. + pub fn max_force_magnitude(&self) -> f32 { + self.0.max_force_magnitude + } +} + +// #[wasm_bindgen] +// /// The proximity state of a sensor collider and another collider. +// pub enum RawIntersection { +// /// The sensor is intersecting the other collider. +// Intersecting = 0, +// /// The sensor is within tolerance margin of the other collider. +// WithinMargin = 1, +// /// The sensor is disjoint from the other collider. +// Disjoint = 2, +// } + +#[wasm_bindgen] +impl RawEventQueue { + /// Creates a new event collector. + /// + /// # Parameters + /// - `autoDrain`: setting this to `true` is strongly recommended. If true, the collector will + /// be automatically drained before each `world.step(collector)`. If false, the collector will + /// keep all events in memory unless it is manually drained/cleared; this may lead to unbounded use of + /// RAM if no drain is performed. + #[wasm_bindgen(constructor)] + pub fn new(autoDrain: bool) -> Self { + let collision_channel = std::sync::mpsc::channel(); + let contact_force_channel = std::sync::mpsc::channel(); + let collector = ChannelEventCollector::new(collision_channel.0, contact_force_channel.0); + + Self { + collector, + collision_events: collision_channel.1, + contact_force_events: contact_force_channel.1, + auto_drain: autoDrain, + } + } + + /// Applies the given javascript closure on each collision event of this collector, then clear + /// the internal collision event buffer. + /// + /// # Parameters + /// - `f(handle1, handle2, started)`: JavaScript closure applied to each collision event. The + /// closure should take three arguments: two integers representing the handles of the colliders + /// involved in the collision, and a boolean indicating if the collision started (true) or stopped + /// (false). + pub fn drainCollisionEvents(&mut self, f: &js_sys::Function) { + let this = JsValue::null(); + while let Ok(event) = self.collision_events.try_recv() { + match event { + CollisionEvent::Started(co1, co2, _) => { + let h1 = utils::flat_handle(co1.0); + let h2 = utils::flat_handle(co2.0); + let _ = f.call3( + &this, + &JsValue::from(h1), + &JsValue::from(h2), + &JsValue::from_bool(true), + ); + } + CollisionEvent::Stopped(co1, co2, _) => { + let h1 = utils::flat_handle(co1.0); + let h2 = utils::flat_handle(co2.0); + let _ = f.call3( + &this, + &JsValue::from(h1), + &JsValue::from(h2), + &JsValue::from_bool(false), + ); + } + } + } + } + + pub fn drainContactForceEvents(&mut self, f: &js_sys::Function) { + let this = JsValue::null(); + while let Ok(event) = self.contact_force_events.try_recv() { + let _ = f.call1(&this, &JsValue::from(RawContactForceEvent(event))); + } + } + + /// Removes all events contained by this collector. + pub fn clear(&self) { + while let Ok(_) = self.collision_events.try_recv() {} + } +} diff --git a/typescript/src/pipeline/mod.rs b/typescript/src/pipeline/mod.rs new file mode 100644 index 000000000..23e19bfb0 --- /dev/null +++ b/typescript/src/pipeline/mod.rs @@ -0,0 +1,11 @@ +pub use self::debug_render_pipeline::*; +pub use self::event_queue::*; +pub use self::physics_hooks::*; +pub use self::physics_pipeline::*; +pub use self::serialization_pipeline::*; + +mod debug_render_pipeline; +mod event_queue; +mod physics_hooks; +mod physics_pipeline; +mod serialization_pipeline; diff --git a/typescript/src/pipeline/physics_hooks.rs b/typescript/src/pipeline/physics_hooks.rs new file mode 100644 index 000000000..2bbc80340 --- /dev/null +++ b/typescript/src/pipeline/physics_hooks.rs @@ -0,0 +1,217 @@ +use crate::utils; +use rapier::geometry::SolverFlags; +use rapier::pipeline::{ContactModificationContext, PairFilterContext, PhysicsHooks}; +use wasm_bindgen::prelude::*; + +pub struct RawPhysicsHooks { + pub this: js_sys::Object, + pub filter_contact_pair: js_sys::Function, + pub filter_intersection_pair: js_sys::Function, + // pub modify_solver_contacts: &'a js_sys::Function, +} + +// HACK: the RawPhysicsHooks is no longer Send+Sync because the JS objects are +// no longer Send+Sync since https://github.com/rustwasm/wasm-bindgen/pull/955 +// As far as this is confined to the bindings this should be fine since we +// never use threading in wasm. +unsafe impl Send for RawPhysicsHooks {} +unsafe impl Sync for RawPhysicsHooks {} + +#[wasm_bindgen] +extern "C" { + // Use `js_namespace` here to bind `console.log(..)` instead of just + // `log(..)` + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +impl PhysicsHooks for RawPhysicsHooks { + fn filter_contact_pair(&self, ctxt: &PairFilterContext) -> Option { + let rb1 = ctxt + .rigid_body1 + .map(|rb| JsValue::from(utils::flat_handle(rb.0))) + .unwrap_or(JsValue::NULL); + let rb2 = ctxt + .rigid_body2 + .map(|rb| JsValue::from(utils::flat_handle(rb.0))) + .unwrap_or(JsValue::NULL); + + let result = self + .filter_contact_pair + .bind2( + &self.this, + &JsValue::from(utils::flat_handle(ctxt.collider1.0)), + &JsValue::from(utils::flat_handle(ctxt.collider2.0)), + ) + .call2(&self.this, &rb1, &rb2) + .ok()?; + let flags = result.as_f64()?; + // TODO: not sure exactly why we have to do `flags as u32` instead + // of `flags.to_bits() as u32`. + SolverFlags::from_bits(flags as u32) + } + + fn filter_intersection_pair(&self, ctxt: &PairFilterContext) -> bool { + let rb1 = ctxt + .rigid_body1 + .map(|rb| JsValue::from(utils::flat_handle(rb.0))) + .unwrap_or(JsValue::NULL); + let rb2 = ctxt + .rigid_body2 + .map(|rb| JsValue::from(utils::flat_handle(rb.0))) + .unwrap_or(JsValue::NULL); + + self.filter_intersection_pair + .bind2( + &self.this, + &JsValue::from(utils::flat_handle(ctxt.collider1.0)), + &JsValue::from(utils::flat_handle(ctxt.collider2.0)), + ) + .call2(&self.this, &rb1, &rb2) + .ok() + .and_then(|res| res.as_bool()) + .unwrap_or(false) + } + + fn modify_solver_contacts(&self, _ctxt: &mut ContactModificationContext) {} +} + +/* NOTE: the following is an attempt to make contact modification work. + * +#[wasm_bindgen] +#[derive(Copy, Clone, Debug)] +pub struct RawContactManifold(*const ContactManifold); +pub struct RawSolverContact(*const SolverContact); + +#[wasm_bindgen] +pub struct RawContactModificationContext { + pub collider1: u32, + pub collider2: u32, + pub rigid_body1: Option, + pub rigid_body2: Option, + pub manifold: *const ContactManifold, + pub solver_contacts: *mut Vec, + normal: *mut Vector, + user_data: *mut u32, +} + +#[wasm_bindgen] +impl RawContactModificationContext { + pub fn collider1(&self) -> u32 { + self.collider1 + } + + pub fn collider2(&self) -> u32 { + self.collider2 + } + + #[wasm_bindgen(getter)] + pub fn normal(&self) -> RawVector { + unsafe { RawVector(*self.normal) } + } + + #[wasm_bindgen(setter)] + pub fn set_normal(&mut self, normal: RawVector) { + unsafe { + *self.normal = normal.0; + } + } + + #[wasm_bindgen(getter)] + pub fn user_data(&self) -> u32 { + unsafe { *self.user_data } + } + + #[wasm_bindgen(setter)] + pub fn set_user_data(&mut self, user_data: u32) { + unsafe { + *self.user_data = user_data; + } + } + + pub fn num_solver_contacts(&self) -> usize { + unsafe { (*self.solver_contacts).len() } + } + + pub fn clear_solver_contacts(&mut self) { + unsafe { (*self.solver_contacts).clear() } + } + + pub fn remove_solver_contact(&mut self, i: usize) { + unsafe { + if i < self.num_solver_contacts() { + (*self.solver_contacts).swap_remove(i); + } + } + } + + pub fn solver_contact_point(&self, i: usize) -> Option { + unsafe { + (*self.solver_contacts) + .get(i) + .map(|c| c.point.coords.into()) + } + } + + pub fn set_solver_contact_point(&mut self, i: usize, pt: &RawVector) { + unsafe { + if let Some(c) = (*self.solver_contacts).get_mut(i) { + c.point = pt.0.into() + } + } + } + + pub fn solver_contact_dist(&self, i: usize) -> Real { + unsafe { + (*self.solver_contacts) + .get(i) + .map(|c| c.dist) + .unwrap_or(0.0) + } + } + + pub fn set_solver_contact_dist(&mut self, i: usize, dist: Real) { + unsafe { + if let Some(c) = (*self.solver_contacts).get_mut(i) { + c.dist = dist + } + } + } + + pub fn solver_contact_friction(&self, i: usize) -> Real { + unsafe { (*self.solver_contacts)[i].friction } + } + + pub fn set_solver_contact_friction(&mut self, i: usize, friction: Real) { + unsafe { + if let Some(c) = (*self.solver_contacts).get_mut(i) { + c.friction = friction + } + } + } + + pub fn solver_contact_restitution(&self, i: usize) -> Real { + unsafe { (*self.solver_contacts)[i].restitution } + } + + pub fn set_solver_contact_restitution(&mut self, i: usize, restitution: Real) { + unsafe { + if let Some(c) = (*self.solver_contacts).get_mut(i) { + c.restitution = restitution + } + } + } + + pub fn solver_contact_tangent_velocity(&self, i: usize) -> RawVector { + unsafe { (*self.solver_contacts)[i].tangent_velocity.into() } + } + + pub fn set_solver_contact_tangent_velocity(&mut self, i: usize, vel: &RawVector) { + unsafe { + if let Some(c) = (*self.solver_contacts).get_mut(i) { + c.tangent_velocity = vel.0.into() + } + } + } +} +*/ diff --git a/typescript/src/pipeline/physics_pipeline.rs b/typescript/src/pipeline/physics_pipeline.rs new file mode 100644 index 000000000..e844ed995 --- /dev/null +++ b/typescript/src/pipeline/physics_pipeline.rs @@ -0,0 +1,170 @@ +use crate::dynamics::{ + RawCCDSolver, RawImpulseJointSet, RawIntegrationParameters, RawIslandManager, + RawMultibodyJointSet, RawRigidBodySet, +}; +use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase}; +use crate::math::RawVector; +use crate::pipeline::{RawEventQueue, RawPhysicsHooks}; +use crate::rapier::pipeline::PhysicsPipeline; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +pub struct RawPhysicsPipeline(pub(crate) PhysicsPipeline); + +#[wasm_bindgen] +impl RawPhysicsPipeline { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + let mut pipeline = PhysicsPipeline::new(); + pipeline.counters.disable(); // Disable perf counters by default. + RawPhysicsPipeline(pipeline) + } + + pub fn set_profiler_enabled(&mut self, enabled: bool) { + if enabled { + self.0.counters.enable(); + } else { + self.0.counters.disable(); + } + } + + pub fn is_profiler_enabled(&self) -> bool { + self.0.counters.enabled() + } + + pub fn timing_step(&self) -> f64 { + self.0.counters.step_time_ms() + } + + pub fn timing_collision_detection(&self) -> f64 { + self.0.counters.collision_detection_time_ms() + } + + pub fn timing_broad_phase(&self) -> f64 { + self.0.counters.broad_phase_time_ms() + } + + pub fn timing_narrow_phase(&self) -> f64 { + self.0.counters.narrow_phase_time_ms() + } + + pub fn timing_solver(&self) -> f64 { + self.0.counters.solver_time_ms() + } + + pub fn timing_velocity_assembly(&self) -> f64 { + self.0.counters.solver.velocity_assembly_time.time_ms() + } + + pub fn timing_velocity_resolution(&self) -> f64 { + self.0.counters.velocity_resolution_time_ms() + } + + pub fn timing_velocity_update(&self) -> f64 { + self.0.counters.velocity_update_time_ms() + } + + pub fn timing_velocity_writeback(&self) -> f64 { + self.0.counters.solver.velocity_writeback_time.time_ms() + } + + pub fn timing_ccd(&self) -> f64 { + self.0.counters.ccd_time_ms() + } + + pub fn timing_ccd_toi_computation(&self) -> f64 { + self.0.counters.ccd.toi_computation_time.time_ms() + } + + pub fn timing_ccd_broad_phase(&self) -> f64 { + self.0.counters.ccd.broad_phase_time.time_ms() + } + + pub fn timing_ccd_narrow_phase(&self) -> f64 { + self.0.counters.ccd.narrow_phase_time.time_ms() + } + + pub fn timing_ccd_solver(&self) -> f64 { + self.0.counters.ccd.solver_time.time_ms() + } + + pub fn timing_island_construction(&self) -> f64 { + self.0.counters.island_construction_time_ms() + } + + pub fn timing_user_changes(&self) -> f64 { + self.0.counters.stages.user_changes.time_ms() + } + + pub fn step( + &mut self, + gravity: &RawVector, + integrationParameters: &RawIntegrationParameters, + islands: &mut RawIslandManager, + broadPhase: &mut RawBroadPhase, + narrowPhase: &mut RawNarrowPhase, + bodies: &mut RawRigidBodySet, + colliders: &mut RawColliderSet, + joints: &mut RawImpulseJointSet, + articulations: &mut RawMultibodyJointSet, + ccd_solver: &mut RawCCDSolver, + ) { + self.0.step( + gravity.0, + &integrationParameters.0, + &mut islands.0, + &mut broadPhase.0, + &mut narrowPhase.0, + &mut bodies.0, + &mut colliders.0, + &mut joints.0, + &mut articulations.0, + &mut ccd_solver.0, + &(), + &(), + ); + } + + pub fn stepWithEvents( + &mut self, + gravity: &RawVector, + integrationParameters: &RawIntegrationParameters, + islands: &mut RawIslandManager, + broadPhase: &mut RawBroadPhase, + narrowPhase: &mut RawNarrowPhase, + bodies: &mut RawRigidBodySet, + colliders: &mut RawColliderSet, + joints: &mut RawImpulseJointSet, + articulations: &mut RawMultibodyJointSet, + ccd_solver: &mut RawCCDSolver, + eventQueue: &mut RawEventQueue, + hookObject: js_sys::Object, + hookFilterContactPair: js_sys::Function, + hookFilterIntersectionPair: js_sys::Function, + ) { + if eventQueue.auto_drain { + eventQueue.clear(); + } + + let hooks = RawPhysicsHooks { + this: hookObject, + filter_contact_pair: hookFilterContactPair, + filter_intersection_pair: hookFilterIntersectionPair, + }; + + self.0.step( + gravity.0, + &integrationParameters.0, + &mut islands.0, + &mut broadPhase.0, + &mut narrowPhase.0, + &mut bodies.0, + &mut colliders.0, + &mut joints.0, + &mut articulations.0, + &mut ccd_solver.0, + &hooks, + &eventQueue.collector, + ); + } +} diff --git a/typescript/src/pipeline/serialization_pipeline.rs b/typescript/src/pipeline/serialization_pipeline.rs new file mode 100644 index 000000000..8d2e841ad --- /dev/null +++ b/typescript/src/pipeline/serialization_pipeline.rs @@ -0,0 +1,145 @@ +use crate::dynamics::{ + RawImpulseJointSet, RawIntegrationParameters, RawIslandManager, RawMultibodyJointSet, + RawRigidBodySet, +}; +use crate::geometry::{RawBroadPhase, RawColliderSet, RawNarrowPhase}; +use crate::math::RawVector; +use js_sys::Uint8Array; +use rapier::dynamics::{ + ImpulseJointSet, IntegrationParameters, IslandManager, MultibodyJointSet, RigidBodySet, +}; +use rapier::geometry::{ColliderSet, DefaultBroadPhase, NarrowPhase}; +use rapier::math::Vector; +use wasm_bindgen::prelude::*; + +#[derive(Serialize)] +struct SerializableWorld<'a> { + gravity: &'a Vector, + integration_parameters: &'a IntegrationParameters, + islands: &'a IslandManager, + broad_phase: &'a DefaultBroadPhase, + narrow_phase: &'a NarrowPhase, + bodies: &'a RigidBodySet, + colliders: &'a ColliderSet, + impulse_joints: &'a ImpulseJointSet, + multibody_joints: &'a MultibodyJointSet, +} + +#[derive(Deserialize)] +struct DeserializableWorld { + gravity: Vector, + integration_parameters: IntegrationParameters, + islands: IslandManager, + broad_phase: DefaultBroadPhase, + narrow_phase: NarrowPhase, + bodies: RigidBodySet, + colliders: ColliderSet, + impulse_joints: ImpulseJointSet, + multibody_joints: MultibodyJointSet, +} + +#[wasm_bindgen] +pub struct RawDeserializedWorld { + gravity: Option, + integrationParameters: Option, + islands: Option, + broadPhase: Option, + narrowPhase: Option, + bodies: Option, + colliders: Option, + impulse_joints: Option, + multibody_joints: Option, +} + +#[wasm_bindgen] +impl RawDeserializedWorld { + pub fn takeGravity(&mut self) -> Option { + self.gravity.take() + } + + pub fn takeIntegrationParameters(&mut self) -> Option { + self.integrationParameters.take() + } + + pub fn takeIslandManager(&mut self) -> Option { + self.islands.take() + } + + pub fn takeBroadPhase(&mut self) -> Option { + self.broadPhase.take() + } + + pub fn takeNarrowPhase(&mut self) -> Option { + self.narrowPhase.take() + } + + pub fn takeBodies(&mut self) -> Option { + self.bodies.take() + } + + pub fn takeColliders(&mut self) -> Option { + self.colliders.take() + } + + pub fn takeImpulseJoints(&mut self) -> Option { + self.impulse_joints.take() + } + + pub fn takeMultibodyJoints(&mut self) -> Option { + self.multibody_joints.take() + } +} + +#[wasm_bindgen] +pub struct RawSerializationPipeline; + +#[wasm_bindgen] +impl RawSerializationPipeline { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + RawSerializationPipeline + } + + pub fn serializeAll( + &self, + gravity: &RawVector, + integrationParameters: &RawIntegrationParameters, + islands: &RawIslandManager, + broadPhase: &RawBroadPhase, + narrowPhase: &RawNarrowPhase, + bodies: &RawRigidBodySet, + colliders: &RawColliderSet, + impulse_joints: &RawImpulseJointSet, + multibody_joints: &RawMultibodyJointSet, + ) -> Option { + let to_serialize = SerializableWorld { + gravity: &gravity.0, + integration_parameters: &integrationParameters.0, + islands: &islands.0, + broad_phase: &broadPhase.0, + narrow_phase: &narrowPhase.0, + bodies: &bodies.0, + colliders: &colliders.0, + impulse_joints: &impulse_joints.0, + multibody_joints: &multibody_joints.0, + }; + let snap = bincode::serialize(&to_serialize).ok()?; + Some(Uint8Array::from(&snap[..])) + } + + pub fn deserializeAll(&self, data: Uint8Array) -> Option { + let data = data.to_vec(); + let d: DeserializableWorld = bincode::deserialize(&data[..]).ok()?; + Some(RawDeserializedWorld { + gravity: Some(RawVector(d.gravity)), + integrationParameters: Some(RawIntegrationParameters(d.integration_parameters)), + islands: Some(RawIslandManager(d.islands)), + broadPhase: Some(RawBroadPhase(d.broad_phase)), + narrowPhase: Some(RawNarrowPhase(d.narrow_phase)), + bodies: Some(RawRigidBodySet(d.bodies)), + colliders: Some(RawColliderSet(d.colliders)), + impulse_joints: Some(RawImpulseJointSet(d.impulse_joints)), + multibody_joints: Some(RawMultibodyJointSet(d.multibody_joints)), + }) + } +} diff --git a/typescript/src/utils.rs b/typescript/src/utils.rs new file mode 100644 index 000000000..1b46e7cc8 --- /dev/null +++ b/typescript/src/utils.rs @@ -0,0 +1,79 @@ +use rapier::data::Index; +use rapier::dynamics::{ImpulseJointHandle, MultibodyJointHandle, RigidBodyHandle}; +use rapier::geometry::{Collider, ColliderHandle}; +use wasm_bindgen::JsValue; + +pub type FlatHandle = f64; + +#[inline(always)] +pub fn collider_handle(id: FlatHandle) -> ColliderHandle { + ColliderHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32) +} + +#[inline(always)] +pub fn body_handle(id: FlatHandle) -> RigidBodyHandle { + RigidBodyHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32) +} + +#[inline(always)] +pub fn impulse_joint_handle(id: FlatHandle) -> ImpulseJointHandle { + ImpulseJointHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32) +} + +#[inline(always)] +pub fn multibody_joint_handle(id: FlatHandle) -> MultibodyJointHandle { + MultibodyJointHandle::from_raw_parts(id.to_bits() as u32, (id.to_bits() >> 32) as u32) +} + +#[inline(always)] +pub fn flat_handle(id: Index) -> FlatHandle { + let (i, g) = id.into_raw_parts(); + FlatHandle::from_bits(i as u64 | ((g as u64) << 32)) +} + +// pub type FlatHandle = u32; +// +// #[inline(always)] +// pub fn collider_handle(id: FlatHandle) -> ColliderHandle { +// ColliderHandle::from_raw_parts(id as u32, (id >> 16) as u32) +// } +// +// #[inline(always)] +// pub fn body_handle(id: FlatHandle) -> RigidBodyHandle { +// RigidBodyHandle::from_raw_parts(id as u32, (id >> 16) as u32) +// } +// +// #[inline(always)] +// pub fn impulse_joint_handle(id: FlatHandle) -> ImpulseJointHandle { +// ImpulseJointHandle::from_raw_parts(id as u32, (id >> 16) as u32) +// } +// +// #[inline(always)] +// pub fn multibody_joint_handle(id: FlatHandle) -> MultibodyJointHandle { +// MultibodyJointHandle::from_raw_parts(id as u32, (id >> 16) as u32) +// } +// +// #[inline(always)] +// pub fn flat_handle(id: Index) -> FlatHandle { +// let (i, g) = id.into_raw_parts(); +// i as u32 | ((g as u32) << 16) +// } + +#[inline(always)] +pub fn with_filter( + filter: &js_sys::Function, + f: impl FnOnce(Option<&dyn Fn(ColliderHandle, &Collider) -> bool>) -> T, +) -> T { + if filter.is_function() { + let filtercb = move |handle: ColliderHandle, _: &Collider| match filter + .call1(&JsValue::null(), &JsValue::from(flat_handle(handle.0))) + { + Err(_) => true, + Ok(val) => val.as_bool().unwrap_or(true), + }; + + f(Some(&filtercb)) + } else { + f(None) + } +} diff --git a/typescript/testbed2d/.npmignore b/typescript/testbed2d/.npmignore new file mode 100644 index 000000000..488f91257 --- /dev/null +++ b/typescript/testbed2d/.npmignore @@ -0,0 +1,3 @@ +webpack.config2d.js +src +*.tgz \ No newline at end of file diff --git a/typescript/testbed2d/package-lock.json b/typescript/testbed2d/package-lock.json new file mode 100644 index 000000000..4777a9ac5 --- /dev/null +++ b/typescript/testbed2d/package-lock.json @@ -0,0 +1,7435 @@ +{ + "name": "rapier-testbed2d", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "rapier-testbed2d", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@dimforge/rapier2d": "file:../builds/rapier2d", + "hash-wasm": "^4.12.0", + "lil-gui": "^0.17.0", + "pixi-viewport": "^4.37.0", + "pixi.js": "^6.3.2", + "seedrandom": "^3.0.5", + "stats.js": "^0.17.0" + }, + "devDependencies": { + "@types/seedrandom": "^3.0.2", + "@types/stats.js": "^0.17.0", + "copy-webpack-plugin": "^11.0.0", + "rimraf": "^3.0.2", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" + } + }, + "../builds/rapier2d": { + "name": "@dimforge/rapier2d", + "dependencies": { + "wasm-pack": "^0.12.1" + }, + "devDependencies": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13" + } + }, + "../rapier2d": { + "name": "@dimforge/rapier2d", + "extraneous": true, + "dependencies": { + "wasm-pack": "^0.12.1" + }, + "devDependencies": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13" + } + }, + "node_modules/@dimforge/rapier2d": { + "resolved": "../builds/rapier2d", + "link": true + }, + "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, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "dev": true, + "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, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "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/@pixi/accessibility": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-6.5.8.tgz", + "integrity": "sha512-3q1YaZeZKOoblgbxTQg2L0RAp9jtNtGcl/7kce+XelqxwIMS3p8411nwo90YO53XCqc/eQW2SoZ+hSXqcL0qOw==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/app": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/app/-/app-6.5.8.tgz", + "integrity": "sha512-pDPkamtYDaPhscNxack+bHNqazCwrqw6cAotKyoz1mvLXeGhxqTntOcfgGLZR2fNbnY8EBmdduLvH7n2jI/LTg==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/compressed-textures": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-6.5.8.tgz", + "integrity": "sha512-nW74kcvdEoe4a2U7Ekx4egqdH1tYKC2kCOZxKWYcUARqz26tS0ddwSRyIs05In6EChmXHXGy/MtShdueMH38TA==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/loaders": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/constants": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-6.5.8.tgz", + "integrity": "sha512-yYRCebBPqajm1kn5f8QQTTvl7oDRDk1nppfO+JpqbrFXg0W7oqIMurec3KeG9RdZW5foOiXDoz1Gw+VtolYIEw==" + }, + "node_modules/@pixi/core": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/core/-/core-6.5.8.tgz", + "integrity": "sha512-Gconik7/PpFPMpCpOddXVIPx5C2StWKw7lQ4YX19yQ+cRRmecCea2cV0xTBtpEjjx0ilX7nBfIEuZ4zIlMmlbA==", + "dependencies": { + "@types/offscreencanvas": "^2019.6.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/pixijs" + }, + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/extensions": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/runner": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/ticker": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/display": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/display/-/display-6.5.8.tgz", + "integrity": "sha512-2K8YOG8s0iF8x/k2Q0RTFmoMJ9biI6PXEh76nH3EqUFdpyrIIgrG5aOMnCkVDvOxlgVRrKG8Q3JBHlSievTmuw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/extensions": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/extensions/-/extensions-6.5.8.tgz", + "integrity": "sha512-6vEV801Vn/EkU/qjFiZ76OZWPq5KsBR2r+P5gfKv4YLnaDc3A+0IpUOJ7sLBAJqmr0iw68g6xV6MnuqVjNGjFg==" + }, + "node_modules/@pixi/extract": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-6.5.8.tgz", + "integrity": "sha512-qbuuD/iBA4J+TCBgrbMe8oDUFbCriyy9LTKEtQp+pghKD5MEMvJ3nO6Osumxqiqta2kYU6WldFLTldKyHEiQ7Q==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/filter-alpha": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-6.5.8.tgz", + "integrity": "sha512-W4IkFTLTP84H+DS9XIdBGunAEpaXLrasDc4CQBeyp4c4hBlGlzriUZp30vkmqm7GPmFhzPe7aiJtNYgUpxKQBQ==", + "peerDependencies": { + "@pixi/core": "6.5.8" + } + }, + "node_modules/@pixi/filter-blur": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-6.5.8.tgz", + "integrity": "sha512-1UOfVthFBnavzTBkR6R+1tWhOOymtWvcpuJILhxf3mryLj9eqYbQubAG0gV8Da6Ibsgk+v73ORnOJyWR3POFvw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/settings": "6.5.8" + } + }, + "node_modules/@pixi/filter-color-matrix": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-6.5.8.tgz", + "integrity": "sha512-iix+a/KEi6HAwZwkUH3nkIzyLu0ln3HBuHEFLUUhug7xrQgQgGrTQZ32iWlfpJD/BZuKphIGfzlxMFfvyQmkVw==", + "peerDependencies": { + "@pixi/core": "6.5.8" + } + }, + "node_modules/@pixi/filter-displacement": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-6.5.8.tgz", + "integrity": "sha512-qLRka5cQbeH6667A+ViYoemsXGGe2tOBt92vM91+slMt9OBGtR0ymlpGU7VxBggWUlu5PE10zYed/xw78uSpig==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/math": "6.5.8" + } + }, + "node_modules/@pixi/filter-fxaa": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-6.5.8.tgz", + "integrity": "sha512-TxsBH2z2RMj0mqr13VPi18/EJ/Kn38J2u65HonJmhbvTaoK9HWMExTvl38Xjg0k7TlepwhoayxMhQ1uCw9xudQ==", + "peerDependencies": { + "@pixi/core": "6.5.8" + } + }, + "node_modules/@pixi/filter-noise": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-6.5.8.tgz", + "integrity": "sha512-BZHKuzV5Mdn+EpC52lFYpd6jUcrL+YQHdq0v0yJfVtpW2ripseQxMGxxXr6Yxp2P4F3g2aY2JrfX2VztosmGLA==", + "peerDependencies": { + "@pixi/core": "6.5.8" + } + }, + "node_modules/@pixi/graphics": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-6.5.8.tgz", + "integrity": "sha512-DUuUXHO4t5fg+n+srMkHX38QEH3WtS1IMXtovBGFJkkopG0Z0xjxSp5XvsPPw1J//4fzkHZI5OBrlN613p9+sg==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/interaction": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-6.5.8.tgz", + "integrity": "sha512-uP247r0f47vo9WSpEnsUfeD1izxVGpjtg4iAyGT/02ezWse2vD1aEL8AbxFa65TL0IXOKsHEQudCVL+wjnbSKQ==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/ticker": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/loaders": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-6.5.8.tgz", + "integrity": "sha512-mj11UPKsqWaTEPMpCnFugr6heKkQeNFuVSddSwE8crg19l46zcMhk3ucpQX15RDpAdDJjtl3OraevQCHHbNENw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/math": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/math/-/math-6.5.8.tgz", + "integrity": "sha512-9493KEH5ITnjOZvQZbaU22lD0kcg/XhNh+309KYfwFX787zA1BN/7is06oHEgHBDb2NemqioYi6sw1WnECgQig==" + }, + "node_modules/@pixi/mesh": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-6.5.8.tgz", + "integrity": "sha512-iZZGkh8QBhnfMEgpJsuwemFZZVatodckCgj7N8t1hyHEf0aOWEA6wp5N0Osa3mhltokl7BGnZZLxaR8NtjaiEQ==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/mesh-extras": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-6.5.8.tgz", + "integrity": "sha512-eU2I53yZUFxKbTYZvyRfUcdina3WOl87fyqYwAoaHosU9VgbFl16YADKTGV+NflNp6RCTwU/UIPZ1T19W/iysw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/mesh": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/mixin-cache-as-bitmap": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-6.5.8.tgz", + "integrity": "sha512-5TTv4w8v7guI6z3gKz5ppUCbNMRw+8RRNru/aq65qUl6kcUaJiYwQdBFJ/vJwpI9ePEScWrCuLVEc8QtX6xjNw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/mixin-get-child-by-name": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-6.5.8.tgz", + "integrity": "sha512-b15HTdHpW4ErDBpf7wm1vvWHrTv5kQzElXrwAPBCnLgvronfSL9mL7npOUkZOybUorCoEBq/7oNVjkimsQc5gw==", + "peerDependencies": { + "@pixi/display": "6.5.8" + } + }, + "node_modules/@pixi/mixin-get-global-position": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-6.5.8.tgz", + "integrity": "sha512-Y5epEW5mRrgpDOHvfc92t0PaBgboBKXR4n/AzOOFt0h9GRNTmVKYBpUQPp/HO+r1Bxq+XbaGm1CyfkjUUxnORA==", + "peerDependencies": { + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8" + } + }, + "node_modules/@pixi/particle-container": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/particle-container/-/particle-container-6.5.8.tgz", + "integrity": "sha512-wc4j84PssPWmZLpOJTLLC7MftCULzkQMAfVlwOERhNTZ+6E1LIKw91wDWZe9LQ/20iarzQwQXo0a4uNlJlhnVQ==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/polyfill": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-6.5.8.tgz", + "integrity": "sha512-z2klHelxTZExMyO4oiLdxJMGzzXnToEIDn7Dwfy3FY+98LbxSa2dVFCgzDsYeiiS8fSMsni2Ru7aZT/DFsRDcA==", + "dependencies": { + "object-assign": "^4.1.1", + "promise-polyfill": "^8.2.0" + } + }, + "node_modules/@pixi/prepare": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-6.5.8.tgz", + "integrity": "sha512-anrAcjX3r9ZzK/L6Fw7GhE1pCkjhSfBsxUTlVhuRKJPFC+A3BNpZCwy3GzyvHP4ocl8wvUMzuz5BB5l0AoBCFw==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/graphics": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/text": "6.5.8", + "@pixi/ticker": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/runner": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-6.5.8.tgz", + "integrity": "sha512-/9KVgQjTKiBa1qHdNmhP9I+AHgC/Eu9QiKcc+oakLCJtpYi79lx+nDFrpLUamIi2c7lP0hDWVe0XqlQeYmSwag==" + }, + "node_modules/@pixi/settings": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-6.5.8.tgz", + "integrity": "sha512-gmnwHkg9+tlQRuFNOdimzl73Dup2fdEo/VYaF7spT+8womE4KWAvARCBMqY/10aAx1iYeYuo5av/RfqrePB5Hg==", + "peerDependencies": { + "@pixi/constants": "6.5.8" + } + }, + "node_modules/@pixi/sprite": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-6.5.8.tgz", + "integrity": "sha512-ywvbrNgjK+K93X9cvHtDCnsBtU7B9JD/3wg+1G6v1Ktrr2E1gwVIQK1NANBrjzt6cYGphz5EqGAW68d0rMBliw==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/sprite-animated": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-6.5.8.tgz", + "integrity": "sha512-woPT2cF1BaC0PDWdDrqJ0+DYcyIeXzZLq6bVx2YYia3+jJao1Zjmz1ns5e7YMUTEG7DoVFfhO6CC81YimsMG5w==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/ticker": "6.5.8" + } + }, + "node_modules/@pixi/sprite-tiling": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-6.5.8.tgz", + "integrity": "sha512-PG3tiWI6uUest/d7HAz4/3I8NjpYyeMUL2WDy86nMXCJ6bLdTs/s9Nq3DLckaUsyIMTGsVbj/BXjE8LP1WDTog==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/spritesheet": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-6.5.8.tgz", + "integrity": "sha512-WiJd4fKpSitD3A+/u5q8IPoHXMFT8++bsluhuJvDwzo//s0PHb9qExlF2xos7zUmekmydEFMkDnrl4+lWn2cyg==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/loaders": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/text": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/text/-/text-6.5.8.tgz", + "integrity": "sha512-7AZPj5+vWcUjK0QzQ3ehiEwEqywiWR8NhDmnnN5nRNHR9u5IOOnqCQtBTdDffYPN0uMgCi8MzUPwTJhGuyOeww==", + "peerDependencies": { + "@pixi/core": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/text-bitmap": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-6.5.8.tgz", + "integrity": "sha512-6VxejDc0gOu5HFN06m6i94xBZHdZ728iao8q+hEOjavGR5i2Pv3xseuke1qY0iN4q6Z+wTkcmoK5BfEVi2ujdQ==", + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/loaders": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/mesh": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/text": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "node_modules/@pixi/ticker": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-6.5.8.tgz", + "integrity": "sha512-7VKq5hfnRDSv6a16pATqZAmpQfEu4G171iUTloy3QZfbnPw0s3JervZSih1yJJD84GXEF4VzYB26pJ/x3arGjQ==", + "peerDependencies": { + "@pixi/extensions": "6.5.8", + "@pixi/settings": "6.5.8" + } + }, + "node_modules/@pixi/utils": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-6.5.8.tgz", + "integrity": "sha512-zLnvmVQBWPDnwkfvrSpBBF2XpWSMt+kQAsX562eqjuME63ic9M6fK4u/IaA8csdlG2wtcjBvSYWrpWmPq0bWag==", + "dependencies": { + "@types/earcut": "^2.1.0", + "earcut": "^2.2.4", + "eventemitter3": "^3.1.0", + "url": "^0.11.0" + }, + "peerDependencies": { + "@pixi/constants": "6.5.8", + "@pixi/settings": "6.5.8" + } + }, + "node_modules/@pixi/utils/node_modules/eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/earcut": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.1.tgz", + "integrity": "sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==" + }, + "node_modules/@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "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 + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "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/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "17.0.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", + "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==", + "dev": true + }, + "node_modules/@types/offscreencanvas": { + "version": "2019.7.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", + "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/seedrandom": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.2.tgz", + "integrity": "sha512-YPLqEOo0/X8JU3rdiq+RgUKtQhQtrppE766y7vMTu8dGML7TVtZNiiiaC/hhU9Zqw9UYopXxhuWWENclMVBwKQ==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "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, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "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 + }, + "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 + }, + "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 + }, + "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, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "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 + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "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, + "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, + "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 + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "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, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "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 + }, + "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 + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "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, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/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, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "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/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bonjour-service": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.12.tgz", + "integrity": "sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.4" + } + }, + "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/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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 + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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/caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "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/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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/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, + "engines": { + "node": ">=6.0" + } + }, + "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, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "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 + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/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/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/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, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "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": "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/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": 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/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", + "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.143", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.143.tgz", + "integrity": "sha512-2hIgvu0+pDfXIqmVmV5X6iwMjQ2KxDsWKwM+oI1fABEOy/Dqmll0QJRmIQ3rm+XaoUa/qKrmy5h7LSTFQ6Ldzg==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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/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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "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, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "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.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "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/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.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/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.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, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "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/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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 + }, + "node_modules/globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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 + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "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-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-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/hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", + "license": "MIT" + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "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, + "engines": { + "node": ">=10.17.0" + } + }, + "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, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">= 4" + } + }, + "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, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-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-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "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/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "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, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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": "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 + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lil-gui": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz", + "integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==" + }, + "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, + "engines": { + "node": ">=6.11.5" + } + }, + "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/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/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.4.tgz", + "integrity": "sha512-W4gHNUE++1oSJVn8Y68jPXi+mkx3fXR5ITE/Ubz6EQ3xRpCN5k2CQ4AUR8094Z7211F876TyoBACGsIveqgiGA==", + "dev": true, + "dependencies": { + "fs-monkey": "1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "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 + }, + "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/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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, + "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, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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==", + "dev": true + }, + "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/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "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/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "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/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/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/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "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/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "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/pixi-viewport": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/pixi-viewport/-/pixi-viewport-4.37.0.tgz", + "integrity": "sha512-bF22o1WbWeQ3TTHnxh5MYPzjXiKAG2ezAV6rm1oaEbA66hZAAU6lCs7BgwmEBiZKgHNGko1bIJQUSe7cXWJVCw==", + "peerDependencies": { + "@pixi/display": "^6.5.7", + "@pixi/interaction": "^6.5.7", + "@pixi/math": "^6.5.7", + "@pixi/ticker": "^6.5.7" + } + }, + "node_modules/pixi.js": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-6.5.8.tgz", + "integrity": "sha512-TAovIMCvKiWlonyAEbStOSq2+GZliRgs+Pqlavffa/D0Rmvmb78bytWRxgonGx1qkg7G8W7eIbF55tFP4a5Krw==", + "dependencies": { + "@pixi/accessibility": "6.5.8", + "@pixi/app": "6.5.8", + "@pixi/compressed-textures": "6.5.8", + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/extensions": "6.5.8", + "@pixi/extract": "6.5.8", + "@pixi/filter-alpha": "6.5.8", + "@pixi/filter-blur": "6.5.8", + "@pixi/filter-color-matrix": "6.5.8", + "@pixi/filter-displacement": "6.5.8", + "@pixi/filter-fxaa": "6.5.8", + "@pixi/filter-noise": "6.5.8", + "@pixi/graphics": "6.5.8", + "@pixi/interaction": "6.5.8", + "@pixi/loaders": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/mesh": "6.5.8", + "@pixi/mesh-extras": "6.5.8", + "@pixi/mixin-cache-as-bitmap": "6.5.8", + "@pixi/mixin-get-child-by-name": "6.5.8", + "@pixi/mixin-get-global-position": "6.5.8", + "@pixi/particle-container": "6.5.8", + "@pixi/polyfill": "6.5.8", + "@pixi/prepare": "6.5.8", + "@pixi/runner": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/sprite-animated": "6.5.8", + "@pixi/sprite-tiling": "6.5.8", + "@pixi/spritesheet": "6.5.8", + "@pixi/text": "6.5.8", + "@pixi/text-bitmap": "6.5.8", + "@pixi/ticker": "6.5.8", + "@pixi/utils": "6.5.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/pixijs" + } + }, + "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, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "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/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "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/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.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, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "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-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, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "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==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "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-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": 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, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "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, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "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, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=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, + "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/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 + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "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, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/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/spdy-transport/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/spdy/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/spdy/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/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha1-scPcRtlEmLV4t/05hbgaznExzH0=" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "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, + "engines": { + "node": ">=6" + } + }, + "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/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.0.tgz", + "integrity": "sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "dependencies": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "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, + "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/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, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "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 + }, + "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, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "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/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "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, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "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, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "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": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "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, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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, + "engines": { + "node": ">=10.13.0" + } + }, + "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, + "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/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, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "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 + }, + "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, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.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/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/ws": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz", + "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": 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 + } + }, + "dependencies": { + "@dimforge/rapier2d": { + "version": "file:../builds/rapier2d", + "requires": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13", + "wasm-pack": "^0.12.1" + } + }, + "@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 + }, + "@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", + "dev": true + }, + "@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, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@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, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@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 + }, + "@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, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@pixi/accessibility": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-6.5.8.tgz", + "integrity": "sha512-3q1YaZeZKOoblgbxTQg2L0RAp9jtNtGcl/7kce+XelqxwIMS3p8411nwo90YO53XCqc/eQW2SoZ+hSXqcL0qOw==", + "requires": {} + }, + "@pixi/app": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/app/-/app-6.5.8.tgz", + "integrity": "sha512-pDPkamtYDaPhscNxack+bHNqazCwrqw6cAotKyoz1mvLXeGhxqTntOcfgGLZR2fNbnY8EBmdduLvH7n2jI/LTg==", + "requires": {} + }, + "@pixi/compressed-textures": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-6.5.8.tgz", + "integrity": "sha512-nW74kcvdEoe4a2U7Ekx4egqdH1tYKC2kCOZxKWYcUARqz26tS0ddwSRyIs05In6EChmXHXGy/MtShdueMH38TA==", + "requires": {} + }, + "@pixi/constants": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-6.5.8.tgz", + "integrity": "sha512-yYRCebBPqajm1kn5f8QQTTvl7oDRDk1nppfO+JpqbrFXg0W7oqIMurec3KeG9RdZW5foOiXDoz1Gw+VtolYIEw==" + }, + "@pixi/core": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/core/-/core-6.5.8.tgz", + "integrity": "sha512-Gconik7/PpFPMpCpOddXVIPx5C2StWKw7lQ4YX19yQ+cRRmecCea2cV0xTBtpEjjx0ilX7nBfIEuZ4zIlMmlbA==", + "requires": { + "@types/offscreencanvas": "^2019.6.4" + } + }, + "@pixi/display": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/display/-/display-6.5.8.tgz", + "integrity": "sha512-2K8YOG8s0iF8x/k2Q0RTFmoMJ9biI6PXEh76nH3EqUFdpyrIIgrG5aOMnCkVDvOxlgVRrKG8Q3JBHlSievTmuw==", + "requires": {} + }, + "@pixi/extensions": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/extensions/-/extensions-6.5.8.tgz", + "integrity": "sha512-6vEV801Vn/EkU/qjFiZ76OZWPq5KsBR2r+P5gfKv4YLnaDc3A+0IpUOJ7sLBAJqmr0iw68g6xV6MnuqVjNGjFg==" + }, + "@pixi/extract": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-6.5.8.tgz", + "integrity": "sha512-qbuuD/iBA4J+TCBgrbMe8oDUFbCriyy9LTKEtQp+pghKD5MEMvJ3nO6Osumxqiqta2kYU6WldFLTldKyHEiQ7Q==", + "requires": {} + }, + "@pixi/filter-alpha": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-6.5.8.tgz", + "integrity": "sha512-W4IkFTLTP84H+DS9XIdBGunAEpaXLrasDc4CQBeyp4c4hBlGlzriUZp30vkmqm7GPmFhzPe7aiJtNYgUpxKQBQ==", + "requires": {} + }, + "@pixi/filter-blur": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-6.5.8.tgz", + "integrity": "sha512-1UOfVthFBnavzTBkR6R+1tWhOOymtWvcpuJILhxf3mryLj9eqYbQubAG0gV8Da6Ibsgk+v73ORnOJyWR3POFvw==", + "requires": {} + }, + "@pixi/filter-color-matrix": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-6.5.8.tgz", + "integrity": "sha512-iix+a/KEi6HAwZwkUH3nkIzyLu0ln3HBuHEFLUUhug7xrQgQgGrTQZ32iWlfpJD/BZuKphIGfzlxMFfvyQmkVw==", + "requires": {} + }, + "@pixi/filter-displacement": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-6.5.8.tgz", + "integrity": "sha512-qLRka5cQbeH6667A+ViYoemsXGGe2tOBt92vM91+slMt9OBGtR0ymlpGU7VxBggWUlu5PE10zYed/xw78uSpig==", + "requires": {} + }, + "@pixi/filter-fxaa": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-6.5.8.tgz", + "integrity": "sha512-TxsBH2z2RMj0mqr13VPi18/EJ/Kn38J2u65HonJmhbvTaoK9HWMExTvl38Xjg0k7TlepwhoayxMhQ1uCw9xudQ==", + "requires": {} + }, + "@pixi/filter-noise": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-6.5.8.tgz", + "integrity": "sha512-BZHKuzV5Mdn+EpC52lFYpd6jUcrL+YQHdq0v0yJfVtpW2ripseQxMGxxXr6Yxp2P4F3g2aY2JrfX2VztosmGLA==", + "requires": {} + }, + "@pixi/graphics": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-6.5.8.tgz", + "integrity": "sha512-DUuUXHO4t5fg+n+srMkHX38QEH3WtS1IMXtovBGFJkkopG0Z0xjxSp5XvsPPw1J//4fzkHZI5OBrlN613p9+sg==", + "requires": {} + }, + "@pixi/interaction": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-6.5.8.tgz", + "integrity": "sha512-uP247r0f47vo9WSpEnsUfeD1izxVGpjtg4iAyGT/02ezWse2vD1aEL8AbxFa65TL0IXOKsHEQudCVL+wjnbSKQ==", + "requires": {} + }, + "@pixi/loaders": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-6.5.8.tgz", + "integrity": "sha512-mj11UPKsqWaTEPMpCnFugr6heKkQeNFuVSddSwE8crg19l46zcMhk3ucpQX15RDpAdDJjtl3OraevQCHHbNENw==", + "requires": {} + }, + "@pixi/math": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/math/-/math-6.5.8.tgz", + "integrity": "sha512-9493KEH5ITnjOZvQZbaU22lD0kcg/XhNh+309KYfwFX787zA1BN/7is06oHEgHBDb2NemqioYi6sw1WnECgQig==" + }, + "@pixi/mesh": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-6.5.8.tgz", + "integrity": "sha512-iZZGkh8QBhnfMEgpJsuwemFZZVatodckCgj7N8t1hyHEf0aOWEA6wp5N0Osa3mhltokl7BGnZZLxaR8NtjaiEQ==", + "requires": {} + }, + "@pixi/mesh-extras": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-6.5.8.tgz", + "integrity": "sha512-eU2I53yZUFxKbTYZvyRfUcdina3WOl87fyqYwAoaHosU9VgbFl16YADKTGV+NflNp6RCTwU/UIPZ1T19W/iysw==", + "requires": {} + }, + "@pixi/mixin-cache-as-bitmap": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-6.5.8.tgz", + "integrity": "sha512-5TTv4w8v7guI6z3gKz5ppUCbNMRw+8RRNru/aq65qUl6kcUaJiYwQdBFJ/vJwpI9ePEScWrCuLVEc8QtX6xjNw==", + "requires": {} + }, + "@pixi/mixin-get-child-by-name": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-6.5.8.tgz", + "integrity": "sha512-b15HTdHpW4ErDBpf7wm1vvWHrTv5kQzElXrwAPBCnLgvronfSL9mL7npOUkZOybUorCoEBq/7oNVjkimsQc5gw==", + "requires": {} + }, + "@pixi/mixin-get-global-position": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-6.5.8.tgz", + "integrity": "sha512-Y5epEW5mRrgpDOHvfc92t0PaBgboBKXR4n/AzOOFt0h9GRNTmVKYBpUQPp/HO+r1Bxq+XbaGm1CyfkjUUxnORA==", + "requires": {} + }, + "@pixi/particle-container": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/particle-container/-/particle-container-6.5.8.tgz", + "integrity": "sha512-wc4j84PssPWmZLpOJTLLC7MftCULzkQMAfVlwOERhNTZ+6E1LIKw91wDWZe9LQ/20iarzQwQXo0a4uNlJlhnVQ==", + "requires": {} + }, + "@pixi/polyfill": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-6.5.8.tgz", + "integrity": "sha512-z2klHelxTZExMyO4oiLdxJMGzzXnToEIDn7Dwfy3FY+98LbxSa2dVFCgzDsYeiiS8fSMsni2Ru7aZT/DFsRDcA==", + "requires": { + "object-assign": "^4.1.1", + "promise-polyfill": "^8.2.0" + } + }, + "@pixi/prepare": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-6.5.8.tgz", + "integrity": "sha512-anrAcjX3r9ZzK/L6Fw7GhE1pCkjhSfBsxUTlVhuRKJPFC+A3BNpZCwy3GzyvHP4ocl8wvUMzuz5BB5l0AoBCFw==", + "requires": {} + }, + "@pixi/runner": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-6.5.8.tgz", + "integrity": "sha512-/9KVgQjTKiBa1qHdNmhP9I+AHgC/Eu9QiKcc+oakLCJtpYi79lx+nDFrpLUamIi2c7lP0hDWVe0XqlQeYmSwag==" + }, + "@pixi/settings": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-6.5.8.tgz", + "integrity": "sha512-gmnwHkg9+tlQRuFNOdimzl73Dup2fdEo/VYaF7spT+8womE4KWAvARCBMqY/10aAx1iYeYuo5av/RfqrePB5Hg==", + "requires": {} + }, + "@pixi/sprite": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-6.5.8.tgz", + "integrity": "sha512-ywvbrNgjK+K93X9cvHtDCnsBtU7B9JD/3wg+1G6v1Ktrr2E1gwVIQK1NANBrjzt6cYGphz5EqGAW68d0rMBliw==", + "requires": {} + }, + "@pixi/sprite-animated": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-6.5.8.tgz", + "integrity": "sha512-woPT2cF1BaC0PDWdDrqJ0+DYcyIeXzZLq6bVx2YYia3+jJao1Zjmz1ns5e7YMUTEG7DoVFfhO6CC81YimsMG5w==", + "requires": {} + }, + "@pixi/sprite-tiling": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-6.5.8.tgz", + "integrity": "sha512-PG3tiWI6uUest/d7HAz4/3I8NjpYyeMUL2WDy86nMXCJ6bLdTs/s9Nq3DLckaUsyIMTGsVbj/BXjE8LP1WDTog==", + "requires": {} + }, + "@pixi/spritesheet": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-6.5.8.tgz", + "integrity": "sha512-WiJd4fKpSitD3A+/u5q8IPoHXMFT8++bsluhuJvDwzo//s0PHb9qExlF2xos7zUmekmydEFMkDnrl4+lWn2cyg==", + "requires": {} + }, + "@pixi/text": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/text/-/text-6.5.8.tgz", + "integrity": "sha512-7AZPj5+vWcUjK0QzQ3ehiEwEqywiWR8NhDmnnN5nRNHR9u5IOOnqCQtBTdDffYPN0uMgCi8MzUPwTJhGuyOeww==", + "requires": {} + }, + "@pixi/text-bitmap": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-6.5.8.tgz", + "integrity": "sha512-6VxejDc0gOu5HFN06m6i94xBZHdZ728iao8q+hEOjavGR5i2Pv3xseuke1qY0iN4q6Z+wTkcmoK5BfEVi2ujdQ==", + "requires": {} + }, + "@pixi/ticker": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-6.5.8.tgz", + "integrity": "sha512-7VKq5hfnRDSv6a16pATqZAmpQfEu4G171iUTloy3QZfbnPw0s3JervZSih1yJJD84GXEF4VzYB26pJ/x3arGjQ==", + "requires": {} + }, + "@pixi/utils": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-6.5.8.tgz", + "integrity": "sha512-zLnvmVQBWPDnwkfvrSpBBF2XpWSMt+kQAsX562eqjuME63ic9M6fK4u/IaA8csdlG2wtcjBvSYWrpWmPq0bWag==", + "requires": { + "@types/earcut": "^2.1.0", + "earcut": "^2.2.4", + "eventemitter3": "^3.1.0", + "url": "^0.11.0" + }, + "dependencies": { + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + } + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/earcut": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.1.tgz", + "integrity": "sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==" + }, + "@types/eslint": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@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 + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@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 + }, + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "dev": true + }, + "@types/node": { + "version": "17.0.38", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.38.tgz", + "integrity": "sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g==", + "dev": true + }, + "@types/offscreencanvas": { + "version": "2019.7.0", + "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz", + "integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/seedrandom": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.2.tgz", + "integrity": "sha512-YPLqEOo0/X8JU3rdiq+RgUKtQhQtrppE766y7vMTu8dGML7TVtZNiiiaC/hhU9Zqw9UYopXxhuWWENclMVBwKQ==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "dev": true, + "requires": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-9w+a7bR8PeB0dCT/HBULU2fMqf6BAzvKbxFboYhmDtDkKPiyXYbjoe2auwsXlEFI7CFNMF1dCv3dFH5Poy9R1w==", + "dev": true + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@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, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@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 + }, + "@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 + }, + "@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 + }, + "@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, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@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 + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" + } + }, + "@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, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@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, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@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 + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" + } + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" + } + }, + "@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, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "requires": {} + }, + "@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "requires": { + "envinfo": "^7.7.3" + } + }, + "@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "requires": {} + }, + "@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 + }, + "@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 + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "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, + "requires": {} + }, + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "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, + "requires": { + "ajv": "^8.0.0" + } + }, + "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, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "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 + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "body-parser": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.12.tgz", + "integrity": "sha512-pMmguXYCu63Ug37DluMKEHdxc+aaIf/ay4YbF8Gxtba+9d3u+rmEWy61VK3Z3hp8Rskok3BunHYnG0dUHAsblw==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.4" + } + }, + "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, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + } + }, + "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 + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "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 + }, + "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, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "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 + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "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, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "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 + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "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, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.3.1.tgz", + "integrity": "sha512-spBwIj0TK0Ey3666GwIdWVfUpLyubpU53BTCu8iPn4r4oXd9O14Hjg3EHw3ts2oed77/SeckunUYCyRlSngqHw==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "earcut": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", + "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.143", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.143.tgz", + "integrity": "sha512-2hIgvu0+pDfXIqmVmV5X6iwMjQ2KxDsWKwM+oI1fABEOy/Dqmll0QJRmIQ3rm+XaoUa/qKrmy5h7LSTFQ6Ldzg==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true + }, + "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 + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "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, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "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, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "express": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.0", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.10.3", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + } + } + }, + "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 + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "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, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "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 + }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "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, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "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, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "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 + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "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 + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "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" + } + }, + "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, + "requires": { + "is-glob": "^4.0.3" + } + }, + "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 + }, + "globby": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.1.tgz", + "integrity": "sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "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 + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "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 + }, + "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 + }, + "hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==" + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "http-parser-js": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "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 + }, + "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, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "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, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true + }, + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "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 + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "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, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "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 + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "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, + "requires": { + "isobject": "^3.0.1" + } + }, + "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 + }, + "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, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "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, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "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, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "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 + }, + "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 + }, + "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 + }, + "lil-gui": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz", + "integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==" + }, + "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 + }, + "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, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.4.tgz", + "integrity": "sha512-W4gHNUE++1oSJVn8Y68jPXi+mkx3fXR5ITE/Ubz6EQ3xRpCN5k2CQ4AUR8094Z7211F876TyoBACGsIveqgiGA==", + "dev": true, + "requires": { + "fs-monkey": "1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "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 + }, + "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, + "requires": { + "mime-db": "1.52.0" + } + }, + "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 + }, + "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==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "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-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "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, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "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 + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "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, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "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, + "requires": { + "p-try": "^2.0.0" + } + }, + "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, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + } + }, + "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 + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "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 + }, + "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 + }, + "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 + }, + "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 + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "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 + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pixi-viewport": { + "version": "4.37.0", + "resolved": "https://registry.npmjs.org/pixi-viewport/-/pixi-viewport-4.37.0.tgz", + "integrity": "sha512-bF22o1WbWeQ3TTHnxh5MYPzjXiKAG2ezAV6rm1oaEbA66hZAAU6lCs7BgwmEBiZKgHNGko1bIJQUSe7cXWJVCw==", + "requires": {} + }, + "pixi.js": { + "version": "6.5.8", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-6.5.8.tgz", + "integrity": "sha512-TAovIMCvKiWlonyAEbStOSq2+GZliRgs+Pqlavffa/D0Rmvmb78bytWRxgonGx1qkg7G8W7eIbF55tFP4a5Krw==", + "requires": { + "@pixi/accessibility": "6.5.8", + "@pixi/app": "6.5.8", + "@pixi/compressed-textures": "6.5.8", + "@pixi/constants": "6.5.8", + "@pixi/core": "6.5.8", + "@pixi/display": "6.5.8", + "@pixi/extensions": "6.5.8", + "@pixi/extract": "6.5.8", + "@pixi/filter-alpha": "6.5.8", + "@pixi/filter-blur": "6.5.8", + "@pixi/filter-color-matrix": "6.5.8", + "@pixi/filter-displacement": "6.5.8", + "@pixi/filter-fxaa": "6.5.8", + "@pixi/filter-noise": "6.5.8", + "@pixi/graphics": "6.5.8", + "@pixi/interaction": "6.5.8", + "@pixi/loaders": "6.5.8", + "@pixi/math": "6.5.8", + "@pixi/mesh": "6.5.8", + "@pixi/mesh-extras": "6.5.8", + "@pixi/mixin-cache-as-bitmap": "6.5.8", + "@pixi/mixin-get-child-by-name": "6.5.8", + "@pixi/mixin-get-global-position": "6.5.8", + "@pixi/particle-container": "6.5.8", + "@pixi/polyfill": "6.5.8", + "@pixi/prepare": "6.5.8", + "@pixi/runner": "6.5.8", + "@pixi/settings": "6.5.8", + "@pixi/sprite": "6.5.8", + "@pixi/sprite-animated": "6.5.8", + "@pixi/sprite-tiling": "6.5.8", + "@pixi/spritesheet": "6.5.8", + "@pixi/text": "6.5.8", + "@pixi/text-bitmap": "6.5.8", + "@pixi/ticker": "6.5.8", + "@pixi/utils": "6.5.8" + } + }, + "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, + "requires": { + "find-up": "^4.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-polyfill": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.3.tgz", + "integrity": "sha512-Og0+jCRQetV84U8wVjMNccfGCnMQ9mGs9Hv78QFe+pSDD3gWTpz0y+1QCuxy5d/vBFuZ3iwP2eycAkvqIMPmWg==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "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 + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + }, + "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 + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + } + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "requires": { + "resolve": "^1.9.0" + } + }, + "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 + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "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, + "requires": { + "resolve-from": "^5.0.0" + } + }, + "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 + }, + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "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, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "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 + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "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, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==" + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "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, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "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, + "requires": { + "kind-of": "^6.0.2" + } + }, + "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, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "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 + }, + "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, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "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 + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "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 + }, + "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, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "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 + } + } + }, + "stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha1-scPcRtlEmLV4t/05hbgaznExzH0=" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + }, + "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, + "requires": { + "safe-buffer": "~5.2.0" + } + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } + }, + "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 + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "terser": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.0.tgz", + "integrity": "sha512-JC6qfIEkPBd9j1SMO3Pfn+A6w2kQV54tv+ABQLgZr7dA3k/DL/OBoYSWxzVpZev3J+bUHXfr55L8Mox7AaNo6g==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "requires": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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, + "requires": {} + }, + "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 + }, + "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, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "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, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "ts-loader": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.4.1.tgz", + "integrity": "sha512-384TYAqGs70rn9F0VBnh6BPTfhga7yFNdC5gXbQpDrBj9/KsT4iRkGqKXhziofHOlE2j6YEaiTYVGKKvPhGWvw==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "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 + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ==", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "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 + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "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, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "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, + "requires": {} + }, + "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 + }, + "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, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "requires": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } + } + }, + "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, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + } + }, + "webpack-dev-server": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", + "dev": true, + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + } + }, + "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, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "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 + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "ws": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.7.0.tgz", + "integrity": "sha512-c2gsP0PRwcLFzUiA8Mkr37/MI7ilIlHQxaEAtd0uNMbVMoy8puJyafRlm0bV9MbGSabUPeLrRRaqIBcFcA2Pqg==", + "dev": true, + "requires": {} + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } +} diff --git a/typescript/testbed2d/package.json b/typescript/testbed2d/package.json new file mode 100644 index 000000000..9152daa0e --- /dev/null +++ b/typescript/testbed2d/package.json @@ -0,0 +1,32 @@ +{ + "author": "sebcrozet ", + "name": "rapier-testbed2d", + "version": "0.1.0", + "description": "JavaScript testbed for rapier.", + "license": "Apache-2.0", + "main": "dist/rapier-testbed2d.js", + "scripts": { + "build": "rimraf dist pkg && webpack", + "start": "rimraf dist pkg && webpack serve --open --node-env development" + }, + "dependencies": { + "@dimforge/rapier2d": "file:../builds/rapier2d", + "hash-wasm": "^4.12.0", + "lil-gui": "^0.17.0", + "pixi-viewport": "^4.37.0", + "pixi.js": "^6.3.2", + "seedrandom": "^3.0.5", + "stats.js": "^0.17.0" + }, + "devDependencies": { + "@types/seedrandom": "^3.0.2", + "@types/stats.js": "^0.17.0", + "copy-webpack-plugin": "^11.0.0", + "rimraf": "^3.0.2", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" + } +} diff --git a/typescript/testbed2d/publish.sh b/typescript/testbed2d/publish.sh new file mode 100755 index 000000000..087c63bec --- /dev/null +++ b/typescript/testbed2d/publish.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +npm run build +rsync -av dist/ crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/demos2d +# rsync -av dist/Box2D_v2.3.1_min.wasm.wasm crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/Box2D_v2.3.1_min.wasm.wasm diff --git a/typescript/testbed2d/src/Graphics.ts b/typescript/testbed2d/src/Graphics.ts new file mode 100644 index 000000000..4f9448f8d --- /dev/null +++ b/typescript/testbed2d/src/Graphics.ts @@ -0,0 +1,269 @@ +import * as PIXI from "pixi.js"; +import {Viewport} from "pixi-viewport"; +import type * as RAPIER from "@dimforge/rapier2d"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +const BOX_INSTANCE_INDEX = 0; +const BALL_INSTANCE_INDEX = 1; + +var kk = 0; + +export class Graphics { + coll2gfx: Map; + colorIndex: number; + colorPalette: Array; + renderer: PIXI.Renderer; + scene: PIXI.Container; + viewport: Viewport; + instanceGroups: Array>; + lines: PIXI.Graphics; + + constructor() { + // High pixel Ratio make the rendering extremely slow, so we cap it. + // const pixelRatio = window.devicePixelRatio ? Math.min(window.devicePixelRatio, 1.5) : 1; + + this.coll2gfx = new Map(); + this.colorIndex = 0; + this.colorPalette = [0xf3d9b1, 0x98c1d9, 0x053c5e, 0x1f7a8c]; + this.renderer = new PIXI.Renderer({ + backgroundColor: 0x292929, + antialias: true, + // resolution: pixelRatio, + width: window.innerWidth, + height: window.innerHeight, + }); + + this.scene = new PIXI.Container(); + document.body.appendChild(this.renderer.view); + + this.viewport = new Viewport({ + screenWidth: window.innerWidth, + screenHeight: window.innerHeight, + worldWidth: 1000, + worldHeight: 1000, + interaction: this.renderer.plugins.interaction, + }); + + this.scene.addChild(this.viewport); + this.viewport.drag().pinch().wheel().decelerate(); + + let me = this; + + function onWindowResize() { + me.renderer.resize(window.innerWidth, window.innerHeight); + } + + function onContextMenu(event: UIEvent) { + event.preventDefault(); + } + + document.oncontextmenu = onContextMenu; + document.body.oncontextmenu = onContextMenu; + + window.addEventListener("resize", onWindowResize, false); + + this.initInstances(); + } + + initInstances() { + this.instanceGroups = []; + this.instanceGroups.push( + this.colorPalette.map((color) => { + let graphics = new PIXI.Graphics(); + graphics.beginFill(color); + graphics.drawRect(-1.0, 1.0, 2.0, -2.0); + graphics.endFill(); + return graphics; + }), + ); + + this.instanceGroups.push( + this.colorPalette.map((color) => { + let graphics = new PIXI.Graphics(); + graphics.beginFill(color); + graphics.drawCircle(0.0, 0.0, 1.0); + graphics.endFill(); + return graphics; + }), + ); + } + + render(world: RAPIER.World, debugRender: Boolean) { + kk += 1; + + if (!this.lines) { + this.lines = new PIXI.Graphics(); + this.viewport.addChild(this.lines); + } + + if (debugRender) { + let buffers = world.debugRender(); + let vtx = buffers.vertices; + let cls = buffers.colors; + + this.lines.clear(); + + for (let i = 0; i < vtx.length / 4; i += 1) { + let color = PIXI.utils.rgb2hex([ + cls[i * 8], + cls[i * 8 + 1], + cls[i * 8 + 2], + ]); + this.lines.lineStyle(1.0, color, cls[i * 8 + 3], 0.5, true); + this.lines.moveTo(vtx[i * 4], -vtx[i * 4 + 1]); + this.lines.lineTo(vtx[i * 4 + 2], -vtx[i * 4 + 3]); + } + } else { + this.lines.clear(); + } + + this.updatePositions(world); + this.renderer.render(this.scene); + } + + lookAt(pos: {zoom: number; target: {x: number; y: number}}) { + this.viewport.setZoom(pos.zoom); + this.viewport.moveCenter(pos.target.x, pos.target.y); + } + + updatePositions(world: RAPIER.World) { + world.forEachCollider((elt) => { + let gfx = this.coll2gfx.get(elt.handle); + let translation = elt.translation(); + let rotation = elt.rotation(); + + if (!!gfx) { + gfx.position.x = translation.x; + gfx.position.y = -translation.y; + gfx.rotation = -rotation; + } + }); + } + + reset() { + this.coll2gfx.forEach((gfx) => { + this.viewport.removeChild(gfx); + gfx.destroy(); + }); + this.coll2gfx = new Map(); + this.colorIndex = 0; + } + + addCollider( + RAPIER: RAPIER_API, + world: RAPIER.World, + collider: RAPIER.Collider, + ) { + let i; + let parent = collider.parent(); + let instance; + let graphics; + let vertices; + let instanceId = parent.isFixed() ? 0 : this.colorIndex + 1; + + switch (collider.shapeType()) { + case RAPIER.ShapeType.Cuboid: + let hext = collider.halfExtents(); + instance = this.instanceGroups[BOX_INSTANCE_INDEX][instanceId]; + graphics = instance.clone(); + graphics.scale.x = hext.x; + graphics.scale.y = hext.y; + this.viewport.addChild(graphics); + break; + case RAPIER.ShapeType.Ball: + let rad = collider.radius(); + instance = this.instanceGroups[BALL_INSTANCE_INDEX][instanceId]; + graphics = instance.clone(); + graphics.scale.x = rad; + graphics.scale.y = rad; + this.viewport.addChild(graphics); + break; + case RAPIER.ShapeType.Polyline: + vertices = Array.from(collider.vertices()); + graphics = new PIXI.Graphics(); + graphics + .lineStyle(0.2, this.colorPalette[instanceId]) + .moveTo(vertices[0], -vertices[1]); + + for (i = 2; i < vertices.length; i += 2) { + graphics.lineTo(vertices[i], -vertices[i + 1]); + } + + this.viewport.addChild(graphics); + break; + case RAPIER.ShapeType.HeightField: + let heights = Array.from(collider.heightfieldHeights()); + let scale = collider.heightfieldScale(); + let step = scale.x / (heights.length - 1); + + graphics = new PIXI.Graphics(); + graphics + .lineStyle(0.2, this.colorPalette[instanceId]) + .moveTo(-scale.x / 2.0, -heights[0] * scale.y); + + for (i = 1; i < heights.length; i += 1) { + graphics.lineTo( + -scale.x / 2.0 + i * step, + -heights[i] * scale.y, + ); + } + + this.viewport.addChild(graphics); + break; + case RAPIER.ShapeType.ConvexPolygon: + vertices = Array.from(collider.vertices()); + graphics = new PIXI.Graphics(); + graphics.beginFill(this.colorPalette[instanceId], 1.0); + graphics.moveTo(vertices[0], -vertices[1]); + + for (i = 2; i < vertices.length; i += 2) { + graphics.lineTo(vertices[i], -vertices[i + 1]); + } + + this.viewport.addChild(graphics); + break; + case RAPIER.ShapeType.Voxels: + graphics = new PIXI.Graphics(); + graphics.beginFill(this.colorPalette[instanceId], 1.0); + collider.clearShapeCache(); + let shape = collider.shape as RAPIER.Voxels; + let gridCoords = shape.data; + let sz = shape.voxelSize; + + for (i = 0; i < gridCoords.length; i += 2) { + let minx = gridCoords[i] * sz.x; + let miny = gridCoords[i + 1] * sz.y; + let maxx = minx + sz.x; + let maxy = miny + sz.y; + + graphics.moveTo(minx, -miny); + graphics.lineTo(maxx, -miny); + graphics.lineTo(maxx, -maxy); + graphics.lineTo(minx, -maxy); + } + + this.viewport.addChild(graphics); + break; + default: + console.log("Unknown shape to render: ", collider.shapeType()); + return; + } + + let t = collider.translation(); + let r = collider.rotation(); + // dummy.position.set(t.x, t.y, t.z); + // dummy.quaternion.set(r.x, r.y, r.z, r.w); + // dummy.scale.set(instanceDesc.scale.x, instanceDesc.scale.y, instanceDesc.scale.z); + // dummy.updateMatrix(); + // instance.setMatrixAt(instanceDesc.elementId, dummy.matrix); + // instance.instanceMatrix.needsUpdate = true; + graphics.position.x = t.x; + graphics.position.y = -t.y; + graphics.rotation = r; + + this.coll2gfx.set(collider.handle, graphics); + this.colorIndex = + (this.colorIndex + 1) % (this.colorPalette.length - 1); + } +} diff --git a/typescript/testbed2d/src/Gui.ts b/typescript/testbed2d/src/Gui.ts new file mode 100644 index 000000000..a410607e3 --- /dev/null +++ b/typescript/testbed2d/src/Gui.ts @@ -0,0 +1,113 @@ +import GUI from "lil-gui"; +import * as Stats from "stats.js"; +import type {Testbed} from "./Testbed"; + +export interface DebugInfos { + token: number; + stepId: number; + worldHash: string; + worldHashTime: number; + snapshotTime: number; +} + +export class Gui { + stats: Stats; + rapierVersion: string; + maxTimePanelValue: number; + stepTimePanel: Stats.Panel; + gui: GUI; + debugText: HTMLDivElement; + + constructor(testbed: Testbed, simulationParameters: Testbed["parameters"]) { + // Timings + this.stats = new Stats(); + this.rapierVersion = testbed.RAPIER.version(); + this.maxTimePanelValue = 16.0; + this.stepTimePanel = this.stats.addPanel( + new Stats.Panel("ms (step)", "#ff8", "#221"), + ); + this.stats.showPanel(this.stats.dom.children.length - 1); + document.body.appendChild(this.stats.dom); + + var backends = simulationParameters.backends; + var demos = Array.from(simulationParameters.builders.keys()); + var me = this; + + // For configuring simulation parameters. + this.gui = new GUI({ + title: "Rapier JS demos", + }); + var currDemo = this.gui + .add(simulationParameters, "demo", demos) + .onChange((demo: string) => { + testbed.switchToDemo(demo); + }); + this.gui + .add(simulationParameters, "numSolverIters", 0, 20) + .step(1) + .listen(); + this.gui + .add(simulationParameters, "debugInfos") + .listen() + .onChange((value: boolean) => { + me.debugText.style.visibility = value ? "visible" : "hidden"; + }); + this.gui.add(simulationParameters, "debugRender").listen(); + this.gui.add(simulationParameters, "running").listen(); + this.gui.add(simulationParameters, "step"); + simulationParameters.step = () => { + simulationParameters.stepping = true; + }; + this.gui.add(simulationParameters, "takeSnapshot"); + simulationParameters.takeSnapshot = () => { + testbed.takeSnapshot(); + }; + this.gui.add(simulationParameters, "restoreSnapshot"); + simulationParameters.restoreSnapshot = () => { + testbed.restoreSnapshot(); + }; + this.gui.add(simulationParameters, "restart"); + simulationParameters.restart = () => { + testbed.switchToDemo(currDemo.getValue()); + }; + + /* + * Block of text for debug infos. + */ + this.debugText = document.createElement("div"); + this.debugText.style.position = "absolute"; + this.debugText.innerHTML = ""; + this.debugText.style.top = 50 + "px"; + this.debugText.style.visibility = "visible"; + this.debugText.style.color = "#fff"; + document.body.appendChild(this.debugText); + } + + setDebugInfos(infos: DebugInfos) { + let text = "Version " + this.rapierVersion; + text += "
[Step " + infos.stepId + "]"; + + if (infos.worldHash) { + text += + "
World hash (xxHash128): " + infos.worldHash.toString(); + text += + "
World hash time (xxHash128): " + + infos.worldHashTime + + "ms"; + text += "
Snapshot time: " + infos.snapshotTime + "ms"; + } + this.debugText.innerHTML = text; + } + + setTiming(timing: number) { + if (!!timing) { + this.maxTimePanelValue = Math.max(this.maxTimePanelValue, timing); + this.stepTimePanel.update(timing, this.maxTimePanelValue); + } + } + + resetTiming() { + this.maxTimePanelValue = 1.0; + this.stepTimePanel.update(0.0, 16.0); + } +} diff --git a/typescript/testbed2d/src/Testbed.ts b/typescript/testbed2d/src/Testbed.ts new file mode 100644 index 000000000..61279ab2a --- /dev/null +++ b/typescript/testbed2d/src/Testbed.ts @@ -0,0 +1,189 @@ +import {Graphics} from "./Graphics"; +import {Gui} from "./Gui"; +import type {DebugInfos} from "./Gui"; +import {xxhash128} from "hash-wasm"; +import type * as RAPIER from "@dimforge/rapier2d"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +type Builders = Map void>; + +class SimulationParameters { + backend: string; + prevBackend: string; + demo: string; + numSolverIters: number; + running: boolean; + stepping: boolean; + debugRender: boolean; + step: () => void; + restart: () => void; + takeSnapshot: () => void; + restoreSnapshot: () => void; + backends: Array; + builders: Builders; + debugInfos: boolean; + + constructor(backends: Array, builders: Builders) { + this.backend = "rapier"; + this.prevBackend = "rapier"; + this.demo = "collision groups"; + this.numSolverIters = 4; + this.running = true; + this.stepping = false; + this.debugRender = false; + this.step = function () {}; + this.restart = function () {}; + this.takeSnapshot = function () {}; + this.restoreSnapshot = function () {}; + this.backends = backends; + this.builders = builders; + this.debugInfos = false; + } +} + +export class Testbed { + RAPIER: RAPIER_API; + gui: Gui; + graphics: Graphics; + inhibitLookAt: boolean; + parameters: SimulationParameters; + demoToken: number; + mouse: {x: number; y: number}; + events: RAPIER.EventQueue; + world: RAPIER.World; + preTimestepAction?: (gfx: Graphics) => void; + stepId: number; + prevDemo: string; + lastMessageTime: number; + snap: Uint8Array; + snapStepId: number; + + constructor(RAPIER: RAPIER_API, builders: Builders) { + let backends = ["rapier"]; + this.RAPIER = RAPIER; + let parameters = new SimulationParameters(backends, builders); + this.gui = new Gui(this, parameters); + this.graphics = new Graphics(); + this.inhibitLookAt = false; + this.parameters = parameters; + this.demoToken = 0; + this.mouse = {x: 0, y: 0}; + this.events = new RAPIER.EventQueue(true); + this.switchToDemo(builders.keys().next().value); + + window.addEventListener("mousemove", (event) => { + this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + this.mouse.y = 1 - (event.clientY / window.innerHeight) * 2; + }); + } + + setpreTimestepAction(action: (gfx: Graphics) => void) { + this.preTimestepAction = action; + } + + setWorld(world: RAPIER.World) { + document.onkeyup = null; + document.onkeydown = null; + this.preTimestepAction = null; + this.world = world; + this.world.numSolverIterations = this.parameters.numSolverIters; + this.demoToken += 1; + this.stepId = 0; + this.gui.resetTiming(); + + world.forEachCollider((coll) => { + this.graphics.addCollider(this.RAPIER, world, coll); + }); + + this.lastMessageTime = new Date().getTime(); + } + + lookAt(pos: Parameters[0]) { + if (!this.inhibitLookAt) { + this.graphics.lookAt(pos); + } + + this.inhibitLookAt = false; + } + + switchToDemo(demo: string) { + if (demo == this.prevDemo) { + this.inhibitLookAt = true; + } + + this.prevDemo = demo; + this.graphics.reset(); + this.stepId = 0; + + this.parameters.prevBackend = this.parameters.backend; + this.parameters.builders.get(demo)(this.RAPIER, this); + } + + switchToBackend(backend: string) { + this.switchToDemo(this.parameters.demo); + } + + takeSnapshot() { + this.snap = this.world.takeSnapshot(); + this.snapStepId = this.stepId; + } + + restoreSnapshot() { + if (!!this.snap) { + this.world.free(); + this.world = this.RAPIER.World.restoreSnapshot(this.snap); + this.stepId = this.snapStepId; + } + } + + run() { + if (this.parameters.running || this.parameters.stepping) { + this.world.numSolverIterations = this.parameters.numSolverIters; + + if (!!this.preTimestepAction) { + this.preTimestepAction(this.graphics); + } + + let t0 = new Date().getTime(); + this.world.step(this.events); + this.gui.setTiming(new Date().getTime() - t0); + this.stepId += 1; + + if (!!this.parameters.debugInfos) { + let t0 = performance.now(); + let snapshot = this.world.takeSnapshot(); + let t1 = performance.now(); + let snapshotTime = t1 - t0; + + let debugInfos: DebugInfos = { + token: this.demoToken, + stepId: this.stepId, + worldHash: "", + worldHashTime: 0, + snapshotTime: 0, + }; + t0 = performance.now(); + xxhash128(snapshot).then((hash) => { + debugInfos.worldHash = hash; + t1 = performance.now(); + let worldHashTime = t1 - t0; + debugInfos.worldHashTime = worldHashTime; + debugInfos.snapshotTime = snapshotTime; + this.gui.setDebugInfos(debugInfos); + }); + } + } + + if (this.parameters.stepping) { + this.parameters.running = false; + this.parameters.stepping = false; + } + + this.gui.stats.begin(); + this.graphics.render(this.world, this.parameters.debugRender); + this.gui.stats.end(); + + requestAnimationFrame(() => this.run()); + } +} diff --git a/typescript/testbed2d/src/demos/characterController.ts b/typescript/testbed2d/src/demos/characterController.ts new file mode 100644 index 000000000..7877db12e --- /dev/null +++ b/typescript/testbed2d/src/demos/characterController.ts @@ -0,0 +1,89 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let rad = 0.5; + let num = 5; + let i, j, k; + let shift = rad * 2.5; + let center = num * rad; + let height = 5.0; + + for (i = 0; i < num; ++i) { + for (k = i; k < num; ++k) { + let x = (i * shift) / 2.0 + (k - i) * shift - center; + let y = (i * shift) / 2.0 + height; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad / 2.0); + world.createCollider(colliderDesc, body); + } + } + + // Character. + let characterDesc = + RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation( + -10.0, + 4.0, + ); + let character = world.createRigidBody(characterDesc); + let characterColliderDesc = RAPIER.ColliderDesc.cuboid(0.6, 1.2); + let characterCollider = world.createCollider( + characterColliderDesc, + character, + ); + + let characterController = world.createCharacterController(0.1); + characterController.enableAutostep(0.7, 0.3, true); + characterController.enableSnapToGround(0.7); + + let speed = 0.2; + let movementDirection = {x: 0.0, y: -speed}; + + let updateCharacter = () => { + characterController.computeColliderMovement( + characterCollider, + movementDirection, + ); + + let movement = characterController.computedMovement(); + let newPos = character.translation(); + newPos.x += movement.x; + newPos.y += movement.y; + character.setNextKinematicTranslation(newPos); + console.log("here"); + }; + + testbed.setWorld(world); + testbed.setpreTimestepAction(updateCharacter); + + document.onkeydown = function (event: KeyboardEvent) { + if (event.key == "ArrowLeft") movementDirection.x = -speed; + if (event.key == "ArrowRight") movementDirection.x = speed; + if (event.key == " ") movementDirection.y = speed; + }; + + document.onkeyup = function (event: KeyboardEvent) { + if (event.key == "ArrowLeft") movementDirection.x = 0.0; + if (event.key == "ArrowRight") movementDirection.x = 0.0; + if (event.key == " ") movementDirection.y = -speed; // Gravity + }; + + testbed.lookAt({ + target: {x: 0.0, y: -1.0}, + zoom: 50.0, + }); +} diff --git a/typescript/testbed2d/src/demos/collisionGroups.ts b/typescript/testbed2d/src/demos/collisionGroups.ts new file mode 100644 index 000000000..511636181 --- /dev/null +++ b/typescript/testbed2d/src/demos/collisionGroups.ts @@ -0,0 +1,79 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + /* + * Ground + */ + let ground_size = 5.0; + let ground_height = 0.1; + + let groundBodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + 0.0, + -ground_height, + ); + let groundBody = world.createRigidBody(groundBodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(ground_size, ground_height); + world.createCollider(colliderDesc, groundBody); + + /* + * Setup groups + */ + let group1 = 0x00010001; + let group2 = 0x00020002; + + /* + * A green floor that will collide with the first group only. + */ + colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1) + .setTranslation(0.0, 1.0) + .setCollisionGroups(group1); + world.createCollider(colliderDesc, groundBody); + + /* + * A blue floor that will collide with the second group only. + */ + colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1) + .setTranslation(0.0, 2.0) + .setCollisionGroups(group2); + world.createCollider(colliderDesc, groundBody); + + /* + * Create the cubes + */ + let num = 8; + let rad = 0.1; + + let shift = rad * 2.0; + let centerx = shift * (num / 2); + let centery = 2.5; + let i, j; + + for (j = 0; j < 4; ++j) { + for (i = 0; i < num; ++i) { + let x = i * shift - centerx; + let y = j * shift + centery; + + // Alternate between the green and blue groups. + let group = i % 2 == 0 ? group1 : group2; + + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + ).setCollisionGroups(group); + world.createCollider(colliderDesc, body); + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: 0.0, y: -1.0}, + zoom: 100.0, + }); +} diff --git a/typescript/testbed2d/src/demos/convexPolygons.ts b/typescript/testbed2d/src/demos/convexPolygons.ts new file mode 100644 index 000000000..6edad202f --- /dev/null +++ b/typescript/testbed2d/src/demos/convexPolygons.ts @@ -0,0 +1,68 @@ +import seedrandom from "seedrandom"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + /* + * Ground + */ + // Create Ground. + let groundSize = 30.0; + let grounds = [ + {x: 0.0, y: 0.0, hx: groundSize, hy: 1.2}, + {x: -groundSize, y: groundSize, hx: 1.2, hy: groundSize}, + {x: groundSize, y: groundSize, hx: 1.2, hy: groundSize}, + ]; + + grounds.forEach((ground) => { + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + ground.x, + ground.y, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(ground.hx, ground.hy); + world.createCollider(colliderDesc, body); + }); + + /* + * Create the convex polygons + */ + let num = 14; + let scale = 4.0; + + let shift = scale; + let centerx = (shift * num) / 2.0; + let centery = shift / 2.0; + + let i, j, k; + let rng = seedrandom("convexPolygon"); + + for (i = 0; i < num; ++i) { + for (j = 0; j < num * 2; ++j) { + let x = i * shift - centerx; + let y = j * shift * 2.0 + centery + 2.0; + + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + + let points = []; + for (k = 0; k < 10; ++k) { + points.push(rng() * scale, rng() * scale); + } + let colliderDesc = RAPIER.ColliderDesc.convexHull( + new Float32Array(points), + ); + world.createCollider(colliderDesc, body); + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: -10.0, y: -30.0}, + zoom: 7.0, + }); +} diff --git a/typescript/testbed2d/src/demos/cubes.ts b/typescript/testbed2d/src/demos/cubes.ts new file mode 100644 index 000000000..5214b485d --- /dev/null +++ b/typescript/testbed2d/src/demos/cubes.ts @@ -0,0 +1,56 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + // Create Ground. + let groundSize = 40.0; + let grounds = [ + {x: 0.0, y: 0.0, hx: groundSize, hy: 0.1}, + {x: -groundSize, y: groundSize, hx: 0.1, hy: groundSize}, + {x: groundSize, y: groundSize, hx: 0.1, hy: groundSize}, + ]; + + grounds.forEach((ground) => { + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + ground.x, + ground.y, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(ground.hx, ground.hy); + world.createCollider(colliderDesc, body); + }); + + // Dynamic cubes. + let num = 20; + let numy = 50; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centerx = shift * (num / 2); + let centery = shift / 2.0; + + let i, j; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + let x = i * shift - centerx; + let y = j * shift + centery + 3.0; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad); + world.createCollider(colliderDesc, body); + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: -10.0, y: -30.0}, + zoom: 7.0, + }); +} diff --git a/typescript/testbed2d/src/demos/heightfield.ts b/typescript/testbed2d/src/demos/heightfield.ts new file mode 100644 index 000000000..d055499b1 --- /dev/null +++ b/typescript/testbed2d/src/demos/heightfield.ts @@ -0,0 +1,65 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + let i, j; + + /* + * Ground + */ + let ground_size = {x: 50.0, y: 1.0}; + let nsubdivs = 100; + let heights = []; + + heights.push(40.0); + for (i = 1; i < nsubdivs; ++i) { + heights.push(Math.cos((i * ground_size.x) / nsubdivs) * 2.0); + } + heights.push(40.0); + + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.heightfield( + new Float32Array(heights), + ground_size, + ); + world.createCollider(colliderDesc, body); + + /* + * Create the cubes + */ + let num = 15; + let rad = 0.5; + + let shift = rad * 2.0; + let centerx = shift * (num / 2); + let centery = shift / 2.0; + + for (i = 0; i < num; ++i) { + for (j = 0; j < num * 5; ++j) { + let x = i * shift - centerx; + let y = j * shift + centery + 3.0; + + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + + if (j % 2 == 0) { + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad); + world.createCollider(colliderDesc, body); + } else { + let colliderDesc = RAPIER.ColliderDesc.ball(rad); + world.createCollider(colliderDesc, body); + } + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: -10.0, y: -15.0}, + zoom: 10.0, + }); +} diff --git a/typescript/testbed2d/src/demos/keva.ts b/typescript/testbed2d/src/demos/keva.ts new file mode 100644 index 000000000..6ca57c0cf --- /dev/null +++ b/typescript/testbed2d/src/demos/keva.ts @@ -0,0 +1,92 @@ +import type * as RAPIER from "@dimforge/rapier2d"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +function buildBlock( + RAPIER: RAPIER_API, + world: RAPIER.World, + halfExtents: RAPIER.Vector, + shift: RAPIER.Vector, + numx: number, + numy: number, + numz: number, +) { + let halfExtents_yx = {x: halfExtents.y, y: halfExtents.x}; + let dimensions = [halfExtents, halfExtents_yx]; + let spacing = (halfExtents.y * numx - halfExtents.x) / (numz - 1.0); + + let i; + let j; + let y = 0.0; + + for (i = 0; i <= numy; ++i) { + let dim = dimensions[i % 2]; + [numx, numz] = [numz, numx]; + + for (j = 0; j < numx; ++j) { + let x = i % 2 == 0 ? spacing * j * 2.0 : dim.x * j * 2.0; + + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x + dim.x + shift.x, + y + dim.y + shift.y, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(dim.x, dim.y); + world.createCollider(colliderDesc, body); + } + + y += dim.y * 2.0; + } +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + // Create Ground. + let groundSize = 150.0; + let groundHeight = 0.1; + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + 0.0, + -groundHeight, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(groundSize, groundHeight); + world.createCollider(colliderDesc, body); + + // Keva tower. + let halfExtents = new RAPIER.Vector2(0.5, 2.0); + let blockHeight = 0.0; + // These should only be set to odd values otherwise + // the blocks won't align in the nicest way. + let numyArr = [0, 3, 5, 5, 7, 9]; + let numBlocksBuilt = 0; + let i; + + for (i = 5; i >= 1; --i) { + let numx = i * 15; + let numy = numyArr[i]; + let numz = numx * 2 + 1; + let blockWidth = numx * halfExtents.y * 2.0; + buildBlock( + RAPIER, + world, + halfExtents, + new RAPIER.Vector2(-blockWidth / 2.0, blockHeight), + numx, + numy, + numz, + ); + blockHeight += (numy + 1) * (halfExtents.x + halfExtents.y); + numBlocksBuilt += numx * numy; + } + + testbed.setWorld(world); + + testbed.lookAt({ + target: {x: -10.0, y: -5.0}, + zoom: 4.0, + }); +} diff --git a/typescript/testbed2d/src/demos/lockedRotations.ts b/typescript/testbed2d/src/demos/lockedRotations.ts new file mode 100644 index 000000000..8600f95f1 --- /dev/null +++ b/typescript/testbed2d/src/demos/lockedRotations.ts @@ -0,0 +1,51 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + /* + * The ground + */ + let ground_size = 1.8; + let ground_height = 1.0; + + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + 0.0, + -ground_height, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(ground_size, ground_height); + world.createCollider(colliderDesc, body); + + /* + * A rectangle that only rotates along the `x` axis. + */ + bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(0.0, 3.0) + .lockTranslations(); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.cuboid(2.0, 0.6); + world.createCollider(colliderDesc, body); + + /* + * A cuboid that cannot rotate. + */ + bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(0.4, 5.0) + .lockRotations(); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.cuboid(0.4, 0.6); + world.createCollider(colliderDesc, body); + + /* + * Setup the testbed. + */ + testbed.setWorld(world); + testbed.lookAt({ + target: {x: 0.0, y: -2.0}, + zoom: 50.0, + }); +} diff --git a/typescript/testbed2d/src/demos/pidController.ts b/typescript/testbed2d/src/demos/pidController.ts new file mode 100644 index 000000000..fac2a7c45 --- /dev/null +++ b/typescript/testbed2d/src/demos/pidController.ts @@ -0,0 +1,100 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let rad = 0.5; + let num = 5; + let i, j, k; + let shift = rad * 2.5; + let center = num * rad; + let height = 5.0; + + for (i = 0; i < num; ++i) { + for (k = i; k < num; ++k) { + let x = (i * shift) / 2.0 + (k - i) * shift - center; + let y = (i * shift) / 2.0 + height; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad / 2.0); + world.createCollider(colliderDesc, body); + } + } + + // Character. + let characterDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(-10.0, 4.0) + .setGravityScale(10.0) + .setSoftCcdPrediction(10.0); + let character = world.createRigidBody(characterDesc); + let characterColliderDesc = RAPIER.ColliderDesc.cuboid(0.6, 1.2); + world.createCollider(characterColliderDesc, character); + + let pidController = world.createPidController( + 60.0, + 0.0, + 1.0, + RAPIER.PidAxesMask.AllAng, + ); + let speed = 0.2; + let movementDirection = {x: 0.0, y: 0.0}; + let targetVelocity = {x: 0.0, y: 0.0}; + let targetRotation = 0.0; + + let updateCharacter = () => { + if (movementDirection.x == 0.0 && movementDirection.y == 0.0) { + // Only adjust the rotation, but let translation. + pidController.setAxes(RAPIER.PidAxesMask.AllAng); + } else if (movementDirection.y == 0.0) { + // Don’t control the linear Y axis so the player can fall down due to gravity. + pidController.setAxes( + RAPIER.PidAxesMask.AllAng | RAPIER.PidAxesMask.LinX, + ); + } else { + pidController.setAxes(RAPIER.PidAxesMask.All); + } + + let targetPoint = character.translation(); + targetPoint.x += movementDirection.x; + targetPoint.y += movementDirection.y; + + pidController.applyLinearCorrection( + character, + targetPoint, + targetVelocity, + ); + pidController.applyAngularCorrection(character, 0.0, 0.0); + }; + + testbed.setWorld(world); + testbed.setpreTimestepAction(updateCharacter); + + document.onkeydown = function (event: KeyboardEvent) { + if (event.key == "ArrowLeft") movementDirection.x = -speed; + if (event.key == "ArrowRight") movementDirection.x = speed; + if (event.key == " ") movementDirection.y = speed; + }; + + document.onkeyup = function (event: KeyboardEvent) { + if (event.key == "ArrowLeft") movementDirection.x = 0.0; + if (event.key == "ArrowRight") movementDirection.x = 0.0; + if (event.key == " ") movementDirection.y = 0.0; + }; + + testbed.lookAt({ + target: {x: 0.0, y: -1.0}, + zoom: 50.0, + }); +} diff --git a/typescript/testbed2d/src/demos/polyline.ts b/typescript/testbed2d/src/demos/polyline.ts new file mode 100644 index 000000000..47d825401 --- /dev/null +++ b/typescript/testbed2d/src/demos/polyline.ts @@ -0,0 +1,64 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + let i, j; + + /* + * Ground + */ + let nsubdivs = 100; + let points = []; + let groundSize = 30.0; + let stepSize = groundSize / nsubdivs; + + points.push(-groundSize / 2.0, 25.0); + for (i = 1; i < nsubdivs; ++i) { + let x = -groundSize / 2.0 + i * stepSize; + let y = Math.cos(i * stepSize) * 2.0; + points.push(x, y); + } + points.push(groundSize / 2.0, 25.0); + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.polyline(new Float32Array(points)); + world.createCollider(colliderDesc, body); + + /* + * Create the cubes + */ + let num = 10; + let rad = 0.5; + + let shift = rad * 2.0; + let centerx = shift * (num / 2); + let centery = shift / 2.0; + + for (i = 0; i < num; ++i) { + for (j = 0; j < num * 5; ++j) { + let x = i * shift - centerx; + let y = j * shift + centery + 3.0; + + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + + if (j % 2 == 0) { + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad); + world.createCollider(colliderDesc, body); + } else { + let colliderDesc = RAPIER.ColliderDesc.ball(rad); + world.createCollider(colliderDesc, body); + } + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: -10.0, y: -15.0}, + zoom: 10.0, + }); +} diff --git a/typescript/testbed2d/src/demos/revoluteJoints.ts b/typescript/testbed2d/src/demos/revoluteJoints.ts new file mode 100644 index 000000000..2d7923fd5 --- /dev/null +++ b/typescript/testbed2d/src/demos/revoluteJoints.ts @@ -0,0 +1,59 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + let bodies = []; + + let rad = 0.4; + let numi = 30; // Num vertical nodes. + let numk = 30; // Num horizontal nodes. + let shift = 1.0; + let i, k; + + for (k = 0; k < numk; ++k) { + for (i = 0; i < numi; ++i) { + let status = + k >= numk / 2 - 3 && k <= numk / 2 + 3 && i == 0 + ? RAPIER.RigidBodyType.Fixed + : RAPIER.RigidBodyType.Dynamic; + + let bodyDesc = new RAPIER.RigidBodyDesc(status).setTranslation( + k * shift, + -i * shift, + ); + let child = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.ball(rad); + world.createCollider(colliderDesc, child); + + // Vertical joint. + if (i > 0) { + let parent = bodies[bodies.length - 1]; + let anchor1 = new RAPIER.Vector2(0.0, 0.0); + let anchor2 = new RAPIER.Vector2(0.0, shift); + let JointData = RAPIER.JointData.revolute(anchor1, anchor2); + world.createImpulseJoint(JointData, parent, child, true); + } + + // Horizontal joint. + if (k > 0) { + let parentIndex = bodies.length - numi; + let parent = bodies[parentIndex]; + let anchor1 = new RAPIER.Vector2(0.0, 0.0); + let anchor2 = new RAPIER.Vector2(-shift, 0.0); + let JointData = RAPIER.JointData.revolute(anchor1, anchor2); + world.createImpulseJoint(JointData, parent, child, true); + } + + bodies.push(child); + } + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: 30.0, y: 30.0}, + zoom: 10.0, + }); +} diff --git a/typescript/testbed2d/src/demos/voxels.ts b/typescript/testbed2d/src/demos/voxels.ts new file mode 100644 index 000000000..6a6fc3668 --- /dev/null +++ b/typescript/testbed2d/src/demos/voxels.ts @@ -0,0 +1,90 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier2d"); + +function generateVoxels(n: number) { + let points = []; + + let i; + for (i = 0; i <= n; ++i) { + let y = Math.max(-0.8, Math.min(Math.sin((i / n) * 10.0), 0.8)) * 8.0; + points.push(i - n / 2.0, y); + } + return { + points: new Float32Array(points), + voxelSize: {x: 1.0, y: 1.2}, + }; +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector2(0.0, -9.81); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let voxels = generateVoxels(100); + let colliderDesc = RAPIER.ColliderDesc.voxels( + voxels.points, + voxels.voxelSize, + ); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let num = 10; + let numy = 4; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centery = shift / 2.0; + + let offset = -num * (rad * 2.0 + rad) * 0.5; + let i, j; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + let x = i * shift + offset; + let y = j * shift + centery + 10.0; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y); + let body = world.createRigidBody(bodyDesc); + let colliderDesc; + + switch (j % 3) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad / 2.0, + ); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + ).setTranslation(rad, 0.0); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + ).setTranslation(-rad, 0.0); + break; + } + + world.createCollider(colliderDesc, body); + } + + offset -= 0.05 * rad * (num - 1.0); + } + + testbed.setWorld(world); + testbed.lookAt({ + target: {x: 0.0, y: 0.0}, + zoom: 20.0, + }); +} diff --git a/typescript/testbed2d/src/index.ts b/typescript/testbed2d/src/index.ts new file mode 100644 index 000000000..24bd18f43 --- /dev/null +++ b/typescript/testbed2d/src/index.ts @@ -0,0 +1,30 @@ +import {Testbed} from "./Testbed"; +import * as CollisionGroups from "./demos/collisionGroups"; +import * as Cubes from "./demos/cubes"; +import * as Keva from "./demos/keva"; +import * as Heightfield from "./demos/heightfield"; +import * as Polyline from "./demos/polyline"; +import * as RevoluteJoints from "./demos/revoluteJoints"; +import * as LockedRotations from "./demos/lockedRotations"; +import * as ConvexPolygons from "./demos/convexPolygons"; +import * as CharacterController from "./demos/characterController"; +import * as PidController from "./demos/pidController"; +import * as Voxels from "./demos/voxels"; + +import("@dimforge/rapier2d").then((RAPIER) => { + let builders = new Map([ + ["collision groups", CollisionGroups.initWorld], + ["character controller", CharacterController.initWorld], + ["convex polygons", ConvexPolygons.initWorld], + ["cubes", Cubes.initWorld], + ["heightfield", Heightfield.initWorld], + ["joints: revolute", RevoluteJoints.initWorld], + ["keva tower", Keva.initWorld], + ["locked rotations", LockedRotations.initWorld], + ["pid controller", PidController.initWorld], + ["polyline", Polyline.initWorld], + ["voxels", Voxels.initWorld], + ]); + let testbed = new Testbed(RAPIER, builders); + testbed.run(); +}); diff --git a/typescript/testbed2d/static/.htaccess b/typescript/testbed2d/static/.htaccess new file mode 100644 index 000000000..9bdb356b9 --- /dev/null +++ b/typescript/testbed2d/static/.htaccess @@ -0,0 +1,3 @@ +RewriteEngine On +RewriteCond %{SERVER_PORT} 80 +RewriteRule ^(.*)$ https://www.rapier.rs/$1 [R,L] diff --git a/typescript/testbed2d/static/index.html b/typescript/testbed2d/static/index.html new file mode 100644 index 000000000..6df5b069c --- /dev/null +++ b/typescript/testbed2d/static/index.html @@ -0,0 +1,18 @@ + + + + + Rapier2D JS bindings demo + + + + + + diff --git a/typescript/testbed2d/tsconfig.json b/typescript/testbed2d/tsconfig.json new file mode 100644 index 000000000..5d07ecd80 --- /dev/null +++ b/typescript/testbed2d/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "noImplicitAny": true, + "module": "es2022", + "target": "es2022", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + } +} diff --git a/typescript/testbed2d/webpack.config.js b/typescript/testbed2d/webpack.config.js new file mode 100644 index 000000000..0e5c98393 --- /dev/null +++ b/typescript/testbed2d/webpack.config.js @@ -0,0 +1,55 @@ +const webpack = require("webpack"); +const path = require("path"); +const CopyPlugin = require("copy-webpack-plugin"); + +const isDev = process.env.NODE_ENV === "development"; +const dist = path.resolve(__dirname, "dist"); + +/** + * @type {import('webpack-dev-server').Configuration} + */ +const devServer = { + static: { + directory: dist, + }, + allowedHosts: "all", + compress: true, +}; + +/** + * @type {import('webpack').Configuration} + */ +const webpackConfig = { + mode: isDev ? "development" : "production", + entry: "./src/index.ts", + devtool: "inline-source-map", + output: { + path: dist, + filename: "index.js", + }, + resolve: { + extensions: [".ts", ".js"], + }, + devServer, + performance: false, + experiments: { + asyncWebAssembly: true, + syncWebAssembly: true, + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [{from: "static", to: dist}], + }), + ], +}; + +module.exports = webpackConfig; diff --git a/typescript/testbed3d/.npmignore b/typescript/testbed3d/.npmignore new file mode 100644 index 000000000..488f91257 --- /dev/null +++ b/typescript/testbed3d/.npmignore @@ -0,0 +1,3 @@ +webpack.config2d.js +src +*.tgz \ No newline at end of file diff --git a/typescript/testbed3d/package-lock.json b/typescript/testbed3d/package-lock.json new file mode 100644 index 000000000..95727a7e4 --- /dev/null +++ b/typescript/testbed3d/package-lock.json @@ -0,0 +1,4373 @@ +{ + "name": "rapier-testbed3d", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "rapier-testbed3d", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@dimforge/rapier3d": "file:../builds/rapier3d", + "hash-wasm": "^4.12.0", + "lil-gui": "^0.17.0", + "seedrandom": "^3.0.5", + "stats.js": "^0.17.0", + "three": "^0.146.0" + }, + "devDependencies": { + "@types/seedrandom": "^3.0.2", + "@types/stats.js": "^0.17.0", + "@types/three": "^0.144.0", + "copy-webpack-plugin": "^11.0.0", + "rimraf": "^3.0.2", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" + } + }, + "../builds/rapier3d": { + "name": "@dimforge/rapier3d", + "dependencies": { + "wasm-pack": "^0.12.1" + }, + "devDependencies": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13" + } + }, + "../rapier3d": { + "name": "@dimforge/rapier3d", + "extraneous": true, + "dependencies": { + "typescript": "^5.7.2", + "wasm-pack": "^0.12.1" + }, + "devDependencies": { + "rimraf": "^3.0.2", + "typedoc": "^0.25.13" + } + }, + "node_modules/@dimforge/rapier3d": { + "resolved": "../builds/rapier3d", + "link": true + }, + "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/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "dev": true, + "license": "MIT" + }, + "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" + }, + "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, + "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" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz", + "integrity": "sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/express/node_modules/@types/express-serve-static-core": { + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz", + "integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/http-proxy": { + "version": "1.17.15", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz", + "integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.17", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.17.tgz", + "integrity": "sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/seedrandom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-3.0.8.tgz", + "integrity": "sha512-TY1eezMU2zH2ozQoAFAQFOPpvP15g+ZgSfTZt31AUUH/Rxtnz3H+A/Sv1Snw2/amp//omibc+AEkTaA8KUeOLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/stats.js": { + "version": "0.17.3", + "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz", + "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/three": { + "version": "0.144.0", + "resolved": "https://registry.npmjs.org/@types/three/-/three-0.144.0.tgz", + "integrity": "sha512-psvEs6q5rLN50jUYZ3D4pZMfxTbdt3A243blt0my7/NcL6chaCZpHe2csbCtx0SOD9fI/XnF3wnVUAYZGqCSYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/webxr": "*" + } + }, + "node_modules/@types/webxr": { + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.20.tgz", + "integrity": "sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "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, + "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, + "license": "Apache-2.0" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "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" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "license": "Apache-2.0", + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "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==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bonjour-service": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.3.0.tgz", + "integrity": "sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "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" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "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, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001686", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001686.tgz", + "integrity": "sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0" + } + }, + "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", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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" + }, + "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, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.0.2", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true, + "license": "MIT" + }, + "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", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "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, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT" + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.68", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.68.tgz", + "integrity": "sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.14.0.tgz", + "integrity": "sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "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" + }, + "engines": { + "node": ">=8.0.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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "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, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true, + "license": "MIT" + }, + "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": "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", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/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, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "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, + "license": "ISC", + "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, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.3.tgz", + "integrity": "sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", + "integrity": "sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==", + "dev": true, + "license": "Unlicense" + }, + "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, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "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, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "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, + "license": "BSD-2-Clause" + }, + "node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true, + "license": "MIT" + }, + "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/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.1.0.tgz", + "integrity": "sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-wasm": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz", + "integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ], + "license": "MIT" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "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/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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-local": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "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, + "license": "ISC" + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", + "integrity": "sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "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, + "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/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", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "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, + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "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/launch-editor": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", + "integrity": "sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lil-gui": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/lil-gui/-/lil-gui-0.17.0.tgz", + "integrity": "sha512-MVBHmgY+uEbmJNApAaPbtvNh1RCAeMnKym82SBjtp5rODTYKWtM+MXHCifLe2H2Ti1HuBGBtK/5SyG4ShQ3pUQ==", + "license": "MIT" + }, + "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/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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "license": "Unlicense", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "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" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "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" + }, + "engines": { + "node": ">=4" + } + }, + "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" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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/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==", + "dev": true, + "license": "ISC" + }, + "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" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "license": "MIT", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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, + "license": "MIT" + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "license": "(BSD-3-Clause OR GPL-2.0)", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "dev": true, + "license": "MIT" + }, + "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==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "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" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "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/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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, + "license": "MIT" + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "dev": true, + "license": "MIT" + }, + "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/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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" + } + ], + "license": "MIT" + }, + "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" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "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/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.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-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" + }, + "engines": { + "node": ">=8" + } + }, + "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/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "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" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "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, + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/seedrandom": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", + "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", + "license": "MIT" + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true, + "license": "MIT" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "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" + }, + "engines": { + "node": ">=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" + }, + "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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "ISC" + }, + "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" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 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" + } + }, + "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/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy-transport/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/spdy/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/spdy/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stats.js": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stats.js/-/stats.js-0.17.0.tgz", + "integrity": "sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/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/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" + }, + "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, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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" + } + }, + "node_modules/terser": { + "version": "5.36.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.36.0.tgz", + "integrity": "sha512-IYV9eNMuFAV4THUspIRXkLakHnV6XO7FEdtKjf/mDyrnqUg9LnlOn6/RwRvM9SZjR4GUq8Nk8zj67FzVARr74w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "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", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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/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, + "license": "MIT" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/three": { + "version": "0.146.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.146.0.tgz", + "integrity": "sha512-1lvNfLezN6OJ9NaFAhfX4sm5e9YCzHtaRgZ1+B4C+Hv6TibRMsuBAM5/wVKzxjpYIlMymvgsHEFrrigEfXnb2A==", + "license": "MIT" + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "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, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "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/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "5.97.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.97.0.tgz", + "integrity": "sha512-CWT8v7ShSfj7tGs4TLRtaOLmOCPWhoKEvp+eA7FVx8Xrjb3XfT0aXdxDItnRZmE8sHcH+a8ayDrJCOjXKxVFfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dev": true, + "license": "MIT", + "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": { + "version": "4.15.2", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz", + "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.4", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "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/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", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "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/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, + "license": "MIT" + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.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, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true, + "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==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/typescript/testbed3d/package.json b/typescript/testbed3d/package.json new file mode 100644 index 000000000..516ee2757 --- /dev/null +++ b/typescript/testbed3d/package.json @@ -0,0 +1,32 @@ +{ + "author": "sebcrozet ", + "name": "rapier-testbed3d", + "version": "0.1.0", + "description": "JavaScript testbed for rapier.", + "license": "Apache-2.0", + "main": "dist/rapier-testbed3d.js", + "scripts": { + "build": "rimraf dist pkg && webpack", + "start": "rimraf dist pkg && webpack serve --open --node-env development" + }, + "dependencies": { + "@dimforge/rapier3d": "file:../builds/rapier3d", + "hash-wasm": "^4.12.0", + "lil-gui": "^0.17.0", + "seedrandom": "^3.0.5", + "stats.js": "^0.17.0", + "three": "^0.146.0" + }, + "devDependencies": { + "@types/seedrandom": "^3.0.2", + "@types/stats.js": "^0.17.0", + "@types/three": "^0.144.0", + "copy-webpack-plugin": "^11.0.0", + "rimraf": "^3.0.2", + "ts-loader": "^9.4.1", + "typescript": "^4.8.4", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" + } +} diff --git a/typescript/testbed3d/publish.sh b/typescript/testbed3d/publish.sh new file mode 100755 index 000000000..e8bc248f1 --- /dev/null +++ b/typescript/testbed3d/publish.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +npm run build +rsync -av --delete-after dist/ crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/demos3d +# rsync -av dist/ammo.wasm.wasm crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/ammo.wasm.wasm +# rsync -av dist/physx.release.wasm crozet@ssh.cluster003.hosting.ovh.net:/home/crozet/rapier/physx.release.wasm diff --git a/typescript/testbed3d/src/Graphics.ts b/typescript/testbed3d/src/Graphics.ts new file mode 100644 index 000000000..f52d6c965 --- /dev/null +++ b/typescript/testbed3d/src/Graphics.ts @@ -0,0 +1,576 @@ +import * as THREE from "three"; +import {OrbitControls} from "three/examples/jsm/controls/OrbitControls"; +import RAPIER from "@dimforge/rapier3d"; + +const BOX_INSTANCE_INDEX = 0; +const BALL_INSTANCE_INDEX = 1; +const CYLINDER_INSTANCE_INDEX = 2; +const CONE_INSTANCE_INDEX = 3; + +var dummy = new THREE.Object3D(); +var kk = 0; + +interface InstanceDesc { + groupId: number; + instanceId: number; + elementId: number; + highlighted: boolean; + scale?: THREE.Vector3; +} + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +// NOTE: this is a very naive voxels -> mesh conversion. Proper +// conversions should use something like greedy meshing instead. +function genVoxelsGeometry(collider: RAPIER.Collider) { + // Clear the cached shape so it gets recomputed from the source of truth, + // and so we’ll be sure that the data contain grid coordinates even if the + // voxels were initialized with floating points. + collider.clearShapeCache(); + let shape = collider.shape as RAPIER.Voxels; + let gridCoords = shape.data; + let sz = shape.voxelSize; + let vertices = []; + let indices = []; + + let i: number; + for (i = 0; i < gridCoords.length; i += 3) { + let minx = gridCoords[i] * sz.x; + let miny = gridCoords[i + 1] * sz.y; + let minz = gridCoords[i + 2] * sz.z; + let maxx = minx + sz.x; + let maxy = miny + sz.y; + let maxz = minz + sz.z; + + let k: number = vertices.length / 3; + vertices.push(minx, miny, maxz); + vertices.push(minx, miny, minz); + vertices.push(maxx, miny, minz); + vertices.push(maxx, miny, maxz); + vertices.push(minx, maxy, maxz); + vertices.push(minx, maxy, minz); + vertices.push(maxx, maxy, minz); + vertices.push(maxx, maxy, maxz); + + indices.push(k + 4, k + 5, k + 0); + indices.push(k + 5, k + 1, k + 0); + indices.push(k + 5, k + 6, k + 1); + indices.push(k + 6, k + 2, k + 1); + indices.push(k + 6, k + 7, k + 3); + indices.push(k + 2, k + 6, k + 3); + indices.push(k + 7, k + 4, k + 0); + indices.push(k + 3, k + 7, k + 0); + indices.push(k + 0, k + 1, k + 2); + indices.push(k + 3, k + 0, k + 2); + indices.push(k + 7, k + 6, k + 5); + indices.push(k + 4, k + 7, k + 5); + } + + return { + vertices: new Float32Array(vertices), + indices: new Uint32Array(indices), + }; +} + +function genHeightfieldGeometry(collider: RAPIER.Collider) { + let heights = collider.heightfieldHeights(); + let nrows = collider.heightfieldNRows(); + let ncols = collider.heightfieldNCols(); + let scale = collider.heightfieldScale(); + + let vertices = []; + let indices = []; + let eltWX = 1.0 / nrows; + let eltWY = 1.0 / ncols; + + let i: number; + let j: number; + for (j = 0; j <= ncols; ++j) { + for (i = 0; i <= nrows; ++i) { + let x = (j * eltWX - 0.5) * scale.x; + let y = heights[j * (nrows + 1) + i] * scale.y; + let z = (i * eltWY - 0.5) * scale.z; + + vertices.push(x, y, z); + } + } + + for (j = 0; j < ncols; ++j) { + for (i = 0; i < nrows; ++i) { + let i1 = (i + 0) * (ncols + 1) + (j + 0); + let i2 = (i + 0) * (ncols + 1) + (j + 1); + let i3 = (i + 1) * (ncols + 1) + (j + 0); + let i4 = (i + 1) * (ncols + 1) + (j + 1); + + indices.push(i1, i3, i2); + indices.push(i3, i4, i2); + } + } + + return { + vertices: new Float32Array(vertices), + indices: new Uint32Array(indices), + }; +} + +export class Graphics { + raycaster: THREE.Raycaster; + highlightedCollider: null | number; + coll2instance: Map; + coll2mesh: Map; + rb2colls: Map>; + colorIndex: number; + colorPalette: Array; + scene: THREE.Scene; + camera: THREE.PerspectiveCamera; + renderer: THREE.WebGLRenderer; + light: THREE.PointLight; + lines: THREE.LineSegments; + controls: OrbitControls; + instanceGroups: Array>; + + constructor() { + this.raycaster = new THREE.Raycaster(); + this.highlightedCollider = null; + this.coll2instance = new Map(); + this.coll2mesh = new Map(); + this.rb2colls = new Map(); + this.colorIndex = 0; + this.colorPalette = [0xf3d9b1, 0x98c1d9, 0x053c5e, 0x1f7a8c, 0xff0000]; + this.scene = new THREE.Scene(); + this.camera = new THREE.PerspectiveCamera( + 45, + window.innerWidth / window.innerHeight, + 0.1, + 10000, + ); + this.renderer = new THREE.WebGLRenderer({antialias: true}); + this.renderer.setSize(window.innerWidth, window.innerHeight); + this.renderer.setClearColor(0x292929, 1); + // High pixel Ratio make the rendering extremely slow, so we cap it. + const pixelRatio = window.devicePixelRatio + ? Math.min(window.devicePixelRatio, 1.5) + : 1; + this.renderer.setPixelRatio(pixelRatio); + document.body.appendChild(this.renderer.domElement); + + let ambientLight = new THREE.AmbientLight(0x606060); + this.scene.add(ambientLight); + this.light = new THREE.PointLight(0xffffff, 1, 1000); + this.scene.add(this.light); + + // For the debug-renderer. + { + let material = new THREE.LineBasicMaterial({ + color: 0xffffff, + vertexColors: true, + }); + let geometry = new THREE.BufferGeometry(); + this.lines = new THREE.LineSegments(geometry, material); + this.scene.add(this.lines); + } + let me = this; + + function onWindowResize() { + if (!!me.camera) { + me.camera.aspect = window.innerWidth / window.innerHeight; + me.camera.updateProjectionMatrix(); + me.renderer.setSize(window.innerWidth, window.innerHeight); + } + } + + window.addEventListener("resize", onWindowResize, false); + + this.controls = new OrbitControls( + this.camera, + this.renderer.domElement, + ); + this.controls.enableDamping = true; + this.controls.dampingFactor = 0.2; + this.controls.maxPolarAngle = Math.PI / 2; + this.initInstances(); + } + + initInstances() { + this.instanceGroups = []; + this.instanceGroups.push( + this.colorPalette.map((color) => { + let box = new THREE.BoxGeometry(2.0, 2.0, 2.0); + let mat = new THREE.MeshPhongMaterial({ + color: color, + flatShading: true, + }); + return new THREE.InstancedMesh(box, mat, 1000); + }), + ); + + this.instanceGroups.push( + this.colorPalette.map((color) => { + let ball = new THREE.SphereGeometry(1.0); + let mat = new THREE.MeshPhongMaterial({ + color: color, + flatShading: true, + }); + return new THREE.InstancedMesh(ball, mat, 1000); + }), + ); + + this.instanceGroups.push( + this.colorPalette.map((color) => { + let cylinder = new THREE.CylinderGeometry(1.0, 1.0); + let mat = new THREE.MeshPhongMaterial({ + color: color, + flatShading: true, + }); + return new THREE.InstancedMesh(cylinder, mat, 100); + }), + ); + + this.instanceGroups.push( + this.colorPalette.map((color) => { + let cone = new THREE.ConeGeometry(1.0, 1.0); + let mat = new THREE.MeshPhongMaterial({ + color: color, + flatShading: true, + }); + return new THREE.InstancedMesh(cone, mat, 100); + }), + ); + + this.instanceGroups.forEach((groups) => { + groups.forEach((instance) => { + instance.userData.elementId2coll = new Map(); + instance.count = 0; + instance.instanceMatrix.setUsage(THREE.DynamicDrawUsage); + this.scene.add(instance); + }); + }); + } + + render(world: RAPIER.World, debugRender: boolean) { + kk += 1; + this.controls.update(); + // if (kk % 100 == 0) { + // console.log(this.camera.position); + // console.log(this.controls.target); + // } + + this.light.position.set( + this.camera.position.x, + this.camera.position.y, + this.camera.position.z, + ); + + if (debugRender) { + let buffers = world.debugRender(); + this.lines.visible = true; + this.lines.geometry.setAttribute( + "position", + new THREE.BufferAttribute(buffers.vertices, 3), + ); + this.lines.geometry.setAttribute( + "color", + new THREE.BufferAttribute(buffers.colors, 4), + ); + } else { + this.lines.visible = false; + } + + this.updatePositions(world); + this.renderer.render(this.scene, this.camera); + } + + rayAtMousePosition(pos: {x: number; y: number}) { + this.raycaster.setFromCamera(pos, this.camera); + return this.raycaster.ray; + } + + lookAt(pos: { + target: {x: number; y: number; z: number}; + eye: {x: number; y: number; z: number}; + }) { + this.camera.position.set(pos.eye.x, pos.eye.y, pos.eye.z); + this.controls.target.set(pos.target.x, pos.target.y, pos.target.z); + this.controls.update(); + } + + highlightInstanceId() { + return this.colorPalette.length - 1; + } + + highlightCollider(handle: number) { + if (handle == this.highlightedCollider) + // Avoid flickering when moving the mouse on a single collider. + return; + + if (this.highlightedCollider != null) { + let desc = this.coll2instance.get(this.highlightedCollider); + + if (!!desc) { + desc.highlighted = false; + this.instanceGroups[desc.groupId][ + this.highlightInstanceId() + ].count = 0; + } + } + if (handle != null) { + let desc = this.coll2instance.get(handle); + + if (!!desc) { + if (desc.instanceId != 0) + // Don't highlight static/kinematic bodies. + desc.highlighted = true; + } + } + this.highlightedCollider = handle; + } + + updatePositions(world: RAPIER.World) { + world.forEachCollider((elt) => { + let gfx = this.coll2instance.get(elt.handle); + let translation = elt.translation(); + let rotation = elt.rotation(); + + if (!!gfx) { + let instance = this.instanceGroups[gfx.groupId][gfx.instanceId]; + dummy.scale.set(gfx.scale.x, gfx.scale.y, gfx.scale.z); + dummy.position.set(translation.x, translation.y, translation.z); + dummy.quaternion.set( + rotation.x, + rotation.y, + rotation.z, + rotation.w, + ); + dummy.updateMatrix(); + instance.setMatrixAt(gfx.elementId, dummy.matrix); + + let highlightInstance = + this.instanceGroups[gfx.groupId][ + this.highlightInstanceId() + ]; + if (gfx.highlighted) { + highlightInstance.count = 1; + highlightInstance.setMatrixAt(0, dummy.matrix); + } + + instance.instanceMatrix.needsUpdate = true; + highlightInstance.instanceMatrix.needsUpdate = true; + } + + let mesh = this.coll2mesh.get(elt.handle); + + if (!!mesh) { + mesh.position.set(translation.x, translation.y, translation.z); + mesh.quaternion.set( + rotation.x, + rotation.y, + rotation.z, + rotation.w, + ); + mesh.updateMatrix(); + } + }); + } + + reset() { + this.instanceGroups.forEach((groups) => { + groups.forEach((instance) => { + instance.userData.elementId2coll = new Map(); + instance.count = 0; + }); + }); + + this.coll2mesh.forEach((mesh) => { + this.scene.remove(mesh); + }); + + this.coll2instance = new Map(); + this.rb2colls = new Map(); + this.colorIndex = 0; + } + + // applyModifications(RAPIER: RAPIER_API, world: RAPIER.World, modifications) { + // if (!!modifications) { + // modifications.addCollider.forEach(coll => { + // let collider = world.getCollider(coll.handle); + // this.addCollider(RAPIER, world, collider); + // }); + // modifications.removeRigidBody.forEach(body => { + // if (!!this.rb2colls.get(body.handle)) { + // this.rb2colls.get(body.handle).forEach(coll => this.removeCollider(coll)); + // this.rb2colls.delete(body.handle); + // } + // }); + // } + // } + + removeRigidBody(body: RAPIER.RigidBody) { + if (!!this.rb2colls.get(body.handle)) { + this.rb2colls + .get(body.handle) + .forEach((coll) => this.removeCollider(coll)); + this.rb2colls.delete(body.handle); + } + } + + removeCollider(collider: RAPIER.Collider) { + let gfx = this.coll2instance.get(collider.handle); + let instance = this.instanceGroups[gfx.groupId][gfx.instanceId]; + + if (instance.count > 1) { + let coll2 = instance.userData.elementId2coll.get( + instance.count - 1, + ); + instance.userData.elementId2coll.delete(instance.count - 1); + instance.userData.elementId2coll.set(gfx.elementId, coll2); + + let gfx2 = this.coll2instance.get(coll2.handle); + gfx2.elementId = gfx.elementId; + } + + instance.count -= 1; + this.coll2instance.delete(collider.handle); + } + + addCollider( + RAPIER: RAPIER_API, + world: RAPIER.World, + collider: RAPIER.Collider, + ) { + this.colorIndex = + (this.colorIndex + 1) % (this.colorPalette.length - 2); + let parent = collider.parent(); + if (!this.rb2colls.get(parent.handle)) { + this.rb2colls.set(parent.handle, [collider]); + } else { + this.rb2colls.get(parent.handle).push(collider); + } + + let instance; + let instanceDesc: InstanceDesc = { + groupId: 0, + instanceId: parent.isFixed() ? 0 : this.colorIndex + 1, + elementId: 0, + highlighted: false, + }; + + switch (collider.shapeType()) { + case RAPIER.ShapeType.Cuboid: + let hext = collider.halfExtents(); + instance = + this.instanceGroups[BOX_INSTANCE_INDEX][ + instanceDesc.instanceId + ]; + instanceDesc.groupId = BOX_INSTANCE_INDEX; + instanceDesc.scale = new THREE.Vector3(hext.x, hext.y, hext.z); + break; + case RAPIER.ShapeType.Ball: + let rad = collider.radius(); + instance = + this.instanceGroups[BALL_INSTANCE_INDEX][ + instanceDesc.instanceId + ]; + instanceDesc.groupId = BALL_INSTANCE_INDEX; + instanceDesc.scale = new THREE.Vector3(rad, rad, rad); + break; + case RAPIER.ShapeType.Cylinder: + case RAPIER.ShapeType.RoundCylinder: + let cyl_rad = collider.radius(); + let cyl_height = collider.halfHeight() * 2.0; + instance = + this.instanceGroups[CYLINDER_INSTANCE_INDEX][ + instanceDesc.instanceId + ]; + instanceDesc.groupId = CYLINDER_INSTANCE_INDEX; + instanceDesc.scale = new THREE.Vector3( + cyl_rad, + cyl_height, + cyl_rad, + ); + break; + case RAPIER.ShapeType.Cone: + let cone_rad = collider.radius(); + let cone_height = collider.halfHeight() * 2.0; + instance = + this.instanceGroups[CONE_INSTANCE_INDEX][ + instanceDesc.instanceId + ]; + instanceDesc.groupId = CONE_INSTANCE_INDEX; + instanceDesc.scale = new THREE.Vector3( + cone_rad, + cone_height, + cone_rad, + ); + break; + case RAPIER.ShapeType.TriMesh: + case RAPIER.ShapeType.HeightField: + case RAPIER.ShapeType.ConvexPolyhedron: + case RAPIER.ShapeType.RoundConvexPolyhedron: + case RAPIER.ShapeType.Voxels: + let geometry = new THREE.BufferGeometry(); + let vertices; + let indices; + + if (collider.shapeType() == RAPIER.ShapeType.HeightField) { + let g = genHeightfieldGeometry(collider); + vertices = g.vertices; + indices = g.indices; + } else if (collider.shapeType() == RAPIER.ShapeType.Voxels) { + let g = genVoxelsGeometry(collider); + vertices = g.vertices; + indices = g.indices; + } else { + vertices = collider.vertices(); + indices = collider.indices(); + } + + geometry.setIndex(Array.from(indices)); + geometry.setAttribute( + "position", + new THREE.BufferAttribute(vertices, 3), + ); + let color = parent.isFixed() ? 0 : this.colorIndex + 1; + + let material = new THREE.MeshPhongMaterial({ + color: this.colorPalette[color], + side: THREE.DoubleSide, + flatShading: true, + }); + + let mesh = new THREE.Mesh(geometry, material); + this.scene.add(mesh); + this.coll2mesh.set(collider.handle, mesh); + return; + default: + console.log("Unknown shape to render."); + return; + } + + if (!!instance) { + instanceDesc.elementId = instance.count; + instance.userData.elementId2coll.set(instance.count, collider); + instance.count += 1; + } + + let highlightInstance = + this.instanceGroups[instanceDesc.groupId][ + this.highlightInstanceId() + ]; + highlightInstance.count = 0; + + let t = collider.translation(); + let r = collider.rotation(); + dummy.position.set(t.x, t.y, t.z); + dummy.quaternion.set(r.x, r.y, r.z, r.w); + dummy.scale.set( + instanceDesc.scale.x, + instanceDesc.scale.y, + instanceDesc.scale.z, + ); + dummy.updateMatrix(); + instance.setMatrixAt(instanceDesc.elementId, dummy.matrix); + instance.instanceMatrix.needsUpdate = true; + + this.coll2instance.set(collider.handle, instanceDesc); + } +} diff --git a/typescript/testbed3d/src/Gui.ts b/typescript/testbed3d/src/Gui.ts new file mode 100644 index 000000000..e89b2f47c --- /dev/null +++ b/typescript/testbed3d/src/Gui.ts @@ -0,0 +1,167 @@ +import GUI from "lil-gui"; +import * as Stats from "stats.js"; +import type {Testbed} from "./Testbed"; + +export interface DebugInfos { + token: number; + stepId: number; + worldHash: string; + worldHashTime: number; + snapshotTime: number; + + timingStep: number; + timingCollisionDetection: number; + timingBroadPhase: number; + timingNarrowPhase: number; + timingSolver: number; + timingVelocityAssembly: number; + timingVelocityResolution: number; + timingVelocityUpdate: number; + timingVelocityWriteback: number; + timingCcd: number; + timingCcdToiComputation: number; + timingCcdBroadPhase: number; + timingCcdNarrowPhase: number; + timingCcdSolver: number; + timingIslandConstruction: number; + timingUserChanges: number; +} + +export class Gui { + stats: Stats; + rapierVersion: string; + maxTimePanelValue: number; + stepTimePanel: Stats.Panel; + gui: GUI; + debugText: HTMLDivElement; + + constructor(testbed: Testbed, simulationParameters: Testbed["parameters"]) { + // Timings + this.stats = new Stats(); + this.rapierVersion = testbed.RAPIER.version(); + this.maxTimePanelValue = 16.0; + this.stepTimePanel = this.stats.addPanel( + new Stats.Panel("ms (step)", "#ff8", "#221"), + ); + this.stats.showPanel(this.stats.dom.children.length - 1); + document.body.appendChild(this.stats.dom); + + var backends = simulationParameters.backends; + var demos = Array.from(simulationParameters.builders.keys()); + var me = this; + + // For configuring simulation parameters. + this.gui = new GUI({ + title: "Rapier JS demos", + }); + var currDemo = this.gui + .add(simulationParameters, "demo", demos) + .onChange((demo: string) => { + testbed.switchToDemo(demo); + }); + this.gui + .add(simulationParameters, "numSolverIters", 0, 20) + .step(1) + .listen(); + this.gui + .add(simulationParameters, "debugInfos") + .listen() + .onChange((value: boolean) => { + me.debugText.style.visibility = value ? "visible" : "hidden"; + }); + this.gui.add(simulationParameters, "debugRender").listen(); + this.gui.add(simulationParameters, "running").listen(); + this.gui.add(simulationParameters, "step"); + simulationParameters.step = () => { + simulationParameters.stepping = true; + }; + this.gui.add(simulationParameters, "takeSnapshot"); + simulationParameters.takeSnapshot = () => { + testbed.takeSnapshot(); + }; + this.gui.add(simulationParameters, "restoreSnapshot"); + simulationParameters.restoreSnapshot = () => { + testbed.restoreSnapshot(); + }; + this.gui.add(simulationParameters, "restart"); + simulationParameters.restart = () => { + testbed.switchToDemo(currDemo.getValue()); + }; + + /* + * Block of text for debug infos. + */ + this.debugText = document.createElement("div"); + this.debugText.style.position = "absolute"; + this.debugText.innerHTML = ""; + this.debugText.style.top = 50 + "px"; + this.debugText.style.visibility = "visible"; + this.debugText.style.color = "#fff"; + document.body.appendChild(this.debugText); + } + + setDebugInfos(infos: DebugInfos) { + let text = "Version " + this.rapierVersion; + text += "
[Step " + infos.stepId + "]"; + + if (infos.worldHash) { + text += + "
World hash (xxHash128): " + infos.worldHash.toString(); + text += + "
World hash time (xxHash128): " + + infos.worldHashTime + + "ms"; + text += "
Snapshot time: " + infos.snapshotTime + "ms"; + } + + text += "
timingStep: " + infos.timingStep + "ms"; + text += + "
timingCollisionDetection: " + + infos.timingCollisionDetection + + "ms"; + text += "
timingBroadPhase: " + infos.timingBroadPhase + "ms"; + text += "
timingNarrowPhase: " + infos.timingNarrowPhase + "ms"; + text += "
timingSolver: " + infos.timingSolver + "ms"; + text += + "
timingVelocityAssembly: " + + infos.timingVelocityAssembly + + "ms"; + text += + "
timingVelocityResolution: " + + infos.timingVelocityResolution + + "ms"; + text += + "
timingVelocityUpdate: " + infos.timingVelocityUpdate + "ms"; + text += + "
timingVelocityWriteback: " + + infos.timingVelocityWriteback + + "ms"; + text += "
timingCcd: " + infos.timingCcd + "ms"; + text += + "
timingCcdToiComputation: " + + infos.timingCcdToiComputation + + "ms"; + text += "
timingCcdBroadPhase: " + infos.timingCcdBroadPhase + "ms"; + text += + "
timingCcdNarrowPhase: " + infos.timingCcdNarrowPhase + "ms"; + text += "
timingCcdSolver: " + infos.timingCcdSolver + "ms"; + text += + "
timingIslandConstruction: " + + infos.timingIslandConstruction + + "ms"; + text += "
timingUserChanges: " + infos.timingUserChanges + "ms"; + this.debugText.innerHTML = text; + } + + setTiming(timing: number) { + if (!!timing) { + this.maxTimePanelValue = Math.max(this.maxTimePanelValue, timing); + this.stepTimePanel.update(timing, this.maxTimePanelValue); + } + } + + resetTiming() { + this.maxTimePanelValue = 1.0; + this.stepTimePanel.update(0.0, 16.0); + } +} diff --git a/typescript/testbed3d/src/Testbed.ts b/typescript/testbed3d/src/Testbed.ts new file mode 100644 index 000000000..5d3afd886 --- /dev/null +++ b/typescript/testbed3d/src/Testbed.ts @@ -0,0 +1,211 @@ +import {Graphics} from "./Graphics"; +import {Gui} from "./Gui"; +import type {DebugInfos} from "./Gui"; +import {xxhash128} from "hash-wasm"; +import type * as RAPIER from "@dimforge/rapier3d"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +type Builders = Map void>; + +class SimulationParameters { + backend: string; + prevBackend: string; + demo: string; + numSolverIters: number; + running: boolean; + stepping: boolean; + debugInfos: boolean; + debugRender: boolean; + step: () => void; + restart: () => void; + takeSnapshot: () => void; + restoreSnapshot: () => void; + backends: Array; + builders: Builders; + + constructor(backends: Array, builders: Builders) { + this.backend = "rapier"; + this.prevBackend = "rapier"; + this.demo = "collision groups"; + this.numSolverIters = 4; + this.running = true; + this.stepping = false; + this.debugRender = false; + this.step = () => {}; + this.restart = () => {}; + this.takeSnapshot = () => {}; + this.restoreSnapshot = () => {}; + this.backends = backends; + this.builders = builders; + this.debugInfos = false; + } +} + +export class Testbed { + RAPIER: RAPIER_API; + gui: Gui; + graphics: Graphics; + inhibitLookAt: boolean; + parameters: SimulationParameters; + demoToken: number; + mouse: {x: number; y: number}; + events: RAPIER.EventQueue; + world: RAPIER.World; + preTimestepAction?: (gfx: Graphics) => void; + stepId: number; + prevDemo: string; + lastMessageTime: number; + snap: Uint8Array; + snapStepId: number; + + constructor(RAPIER: RAPIER_API, builders: Builders) { + let backends = ["rapier"]; + this.RAPIER = RAPIER; + let parameters = new SimulationParameters(backends, builders); + this.gui = new Gui(this, parameters); + this.graphics = new Graphics(); + this.inhibitLookAt = false; + this.parameters = parameters; + this.demoToken = 0; + this.mouse = {x: 0, y: 0}; + this.events = new RAPIER.EventQueue(true); + + this.switchToDemo(builders.keys().next().value); + + window.addEventListener("mousemove", (event) => { + this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1; + this.mouse.y = 1 - (event.clientY / window.innerHeight) * 2; + }); + } + + setpreTimestepAction(action: (gfx: Graphics) => void) { + this.preTimestepAction = action; + } + + setWorld(world: RAPIER.World) { + document.onkeydown = null; // Reset key events. + document.onkeyup = null; // Reset key events. + + this.preTimestepAction = null; + this.world = world; + this.world.numSolverIterations = this.parameters.numSolverIters; + this.demoToken += 1; + this.stepId = 0; + this.gui.resetTiming(); + + world.forEachCollider((coll) => { + this.graphics.addCollider(this.RAPIER, world, coll); + }); + + this.lastMessageTime = new Date().getTime(); + } + + lookAt(pos: Parameters[0]) { + if (!this.inhibitLookAt) { + this.graphics.lookAt(pos); + } + + this.inhibitLookAt = false; + } + + switchToDemo(demo: string) { + if (demo == this.prevDemo) { + this.inhibitLookAt = true; + } + + this.prevDemo = demo; + this.graphics.reset(); + + this.parameters.prevBackend = this.parameters.backend; + this.parameters.builders.get(demo)(this.RAPIER, this); + } + + switchToBackend(backend: string) { + this.switchToDemo(this.parameters.demo); + } + + takeSnapshot() { + this.snap = this.world.takeSnapshot(); + this.snapStepId = this.stepId; + } + + restoreSnapshot() { + if (!!this.snap) { + this.world.free(); + this.world = this.RAPIER.World.restoreSnapshot(this.snap); + this.stepId = this.snapStepId; + } + } + + run() { + if (this.parameters.running || this.parameters.stepping) { + this.world.numSolverIterations = this.parameters.numSolverIters; + + if (!!this.preTimestepAction) { + this.preTimestepAction(this.graphics); + } + + let t0 = new Date().getTime(); + this.world.step(this.events); + this.gui.setTiming(new Date().getTime() - t0); + this.stepId += 1; + + if (!!this.parameters.debugInfos) { + let t0 = performance.now(); + let snapshot = this.world.takeSnapshot(); + let t1 = performance.now(); + let snapshotTime = t1 - t0; + + let debugInfos: DebugInfos = { + token: this.demoToken, + stepId: this.stepId, + worldHash: "", + worldHashTime: 0, + snapshotTime: 0, + timingStep: this.world.timingStep(), + timingCollisionDetection: + this.world.timingCollisionDetection(), + timingBroadPhase: this.world.timingBroadPhase(), + timingNarrowPhase: this.world.timingNarrowPhase(), + timingSolver: this.world.timingSolver(), + timingVelocityAssembly: this.world.timingVelocityAssembly(), + timingVelocityResolution: + this.world.timingVelocityResolution(), + timingVelocityUpdate: this.world.timingVelocityUpdate(), + timingVelocityWriteback: + this.world.timingVelocityWriteback(), + timingCcd: this.world.timingCcd(), + timingCcdToiComputation: + this.world.timingCcdToiComputation(), + timingCcdBroadPhase: this.world.timingCcdBroadPhase(), + timingCcdNarrowPhase: this.world.timingCcdNarrowPhase(), + timingCcdSolver: this.world.timingCcdSolver(), + timingIslandConstruction: + this.world.timingIslandConstruction(), + timingUserChanges: this.world.timingUserChanges(), + }; + t0 = performance.now(); + xxhash128(snapshot).then((hash) => { + debugInfos.worldHash = hash; + t1 = performance.now(); + let worldHashTime = t1 - t0; + debugInfos.worldHashTime = worldHashTime; + debugInfos.snapshotTime = snapshotTime; + this.gui.setDebugInfos(debugInfos); + }); + } + } + + if (this.parameters.stepping) { + this.parameters.running = false; + this.parameters.stepping = false; + } + + this.gui.stats.begin(); + this.graphics.render(this.world, this.parameters.debugRender); + this.gui.stats.end(); + + requestAnimationFrame(() => this.run()); + } +} diff --git a/typescript/testbed3d/src/demos/ccd.ts b/typescript/testbed3d/src/demos/ccd.ts new file mode 100644 index 000000000..823c9013b --- /dev/null +++ b/typescript/testbed3d/src/demos/ccd.ts @@ -0,0 +1,75 @@ +import type RAPIER from "@dimforge/rapier3d"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function createWall( + RAPIER: RAPIER_API, + testbed: Testbed, + world: RAPIER.World, + offset: {x: number; y: number; z: number}, + stackHeight: number, +) { + let i, j; + + let shiftY = 1.0; + let shiftZ = 2.0; + + for (i = 0; i < stackHeight; ++i) { + for (j = i; j < stackHeight; ++j) { + let x = offset.x; + let y = i * shiftY + offset.y; + let z = + (i * shiftZ) / 2.0 + (j - i) * shiftZ + offset.z - stackHeight; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(0.5, 0.5, 1.0); + world.createCollider(colliderDesc, body); + } + } +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let groundHeight = 0.1; + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(30.0, 0.1, 30.0); + world.createCollider(colliderDesc, body); + + let numX = 5; + let numZ = 8; + let shiftY = groundHeight + 0.5; + + let i; + for (i = 0; i < numX; ++i) { + let x = i * 6.0; + createWall(RAPIER, testbed, world, {x: x, y: shiftY, z: 0.0}, numZ); + } + + // A very fast rigid-body with CCD enabled. + // Create dynamic cube. + bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(-20.0, shiftY + 2.0, 0.0) + .setLinvel(1000.0, 0.0, 0.0) + .setCcdEnabled(true); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.ball(1.0).setDensity(10.0); + world.createCollider(colliderDesc, body); + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: -31.96000000000001, y: 19.730000000000008, z: -27.86}, + target: {x: -0.0505, y: -0.4126, z: -0.0229}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/characterController.ts b/typescript/testbed3d/src/demos/characterController.ts new file mode 100644 index 000000000..2406ebccb --- /dev/null +++ b/typescript/testbed3d/src/demos/characterController.ts @@ -0,0 +1,106 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1, 15.0); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let rad = 0.5; + let num = 5; + let i, j, k; + let shift = rad * 2.5; + let center = num * rad; + let height = 5.0; + + for (i = 0; i < num; ++i) { + for (j = i; j < num; ++j) { + for (k = i; k < num; ++k) { + let x = (i * shift) / 2.0 + (k - i) * shift - center; + let y = (i * shift) / 2.0 + height; + let z = (i * shift) / 2.0 + (j - i) * shift - center; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad / 2.0, + rad, + ); + world.createCollider(colliderDesc, body); + } + } + } + + // Character. + let characterDesc = + RAPIER.RigidBodyDesc.kinematicPositionBased().setTranslation( + -10.0, + 4.0, + -10.0, + ); + let character = world.createRigidBody(characterDesc); + let characterColliderDesc = RAPIER.ColliderDesc.cylinder(1.2, 0.6); + let characterCollider = world.createCollider( + characterColliderDesc, + character, + ); + + let characterController = world.createCharacterController(0.1); + characterController.enableAutostep(0.7, 0.3, true); + characterController.enableSnapToGround(0.7); + + let speed = 0.2; + let movementDirection = {x: 0.0, y: -speed, z: 0.0}; + + let updateCharacter = () => { + characterController.computeColliderMovement( + characterCollider, + movementDirection, + ); + + let movement = characterController.computedMovement(); + let newPos = character.translation(); + newPos.x += movement.x; + newPos.y += movement.y; + newPos.z += movement.z; + character.setNextKinematicTranslation(newPos); + }; + + testbed.setWorld(world); + testbed.setpreTimestepAction(updateCharacter); + + document.onkeydown = function (event: KeyboardEvent) { + if (event.key == "ArrowUp") movementDirection.x = speed; + if (event.key == "ArrowDown") movementDirection.x = -speed; + if (event.key == "ArrowLeft") movementDirection.z = -speed; + if (event.key == "ArrowRight") movementDirection.z = speed; + if (event.key == " ") movementDirection.y = speed; + }; + + document.onkeyup = function (event: KeyboardEvent) { + if (event.key == "ArrowUp") movementDirection.x = 0.0; + if (event.key == "ArrowDown") movementDirection.x = 0.0; + if (event.key == "ArrowLeft") movementDirection.z = 0.0; + if (event.key == "ArrowRight") movementDirection.z = 0.0; + if (event.key == " ") movementDirection.y = -speed; // Gravity + }; + + let cameraPosition = { + eye: {x: -40.0, y: 19.730000000000008, z: 0.0}, + target: {x: 0.0, y: -0.4126, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/collisionGroups.ts b/typescript/testbed3d/src/demos/collisionGroups.ts new file mode 100644 index 000000000..49c9ddb78 --- /dev/null +++ b/typescript/testbed3d/src/demos/collisionGroups.ts @@ -0,0 +1,73 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(5.0, 0.1, 5.0); + world.createCollider(colliderDesc, groundBody); + + // Setup groups. + let group1 = 0x00010001; + let group2 = 0x00020002; + + // Add one floor that collides with the first group only. + colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1, 1.0) + .setTranslation(0.0, 1.0, 0.0) + .setCollisionGroups(group1); + world.createCollider(colliderDesc, groundBody); + + // Add one floor that collides with the second group only. + colliderDesc = RAPIER.ColliderDesc.cuboid(1.0, 0.1, 1.0) + .setTranslation(0.0, 2.0, 0.0) + .setCollisionGroups(group2); + world.createCollider(colliderDesc, groundBody); + + // Dynamic cubes. + let num = 8; + let rad = 0.1; + + let shift = rad * 2.0; + let centerx = shift * (num / 2); + let centery = 2.5; + let centerz = shift * (num / 2); + let i, j, k; + + for (j = 0; j < 4; j++) { + for (i = 0; i < num; i++) { + for (k = 0; k < num; k++) { + let x = i * shift - centerx; + let y = j * shift + centery; + let z = k * shift - centerz; + + // Alternate between the green and blue groups. + let group = k % 2 == 0 ? group1 : group2; + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + rad, + ).setCollisionGroups(group); + world.createCollider(colliderDesc, body); + } + } + } + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: 10.0, y: 5.0, z: 10.0}, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/compoundShapes.ts b/typescript/testbed3d/src/demos/compoundShapes.ts new file mode 100644 index 000000000..2039dc00b --- /dev/null +++ b/typescript/testbed3d/src/demos/compoundShapes.ts @@ -0,0 +1,188 @@ +import type {Testbed} from "../Testbed"; +import type {ColliderDesc} from "@dimforge/rapier3d"; +import seedrandom from "seedrandom"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function createLShape(RAPIER: RAPIER_API): ColliderDesc { + const shape1 = new RAPIER.Cuboid(2.0, 0.5, 0.5); + const shape2 = new RAPIER.Cuboid(0.5, 1.5, 0.5); + + const shapes = [shape1, shape2]; + const positions = [ + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Vector3(-1.5, -1.5, 0.0), + ]; + const rotations = [ + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ]; + + return RAPIER.ColliderDesc.compound(shapes, positions, rotations); +} + +function createTShape(RAPIER: RAPIER_API): ColliderDesc { + const shape1 = new RAPIER.Cuboid(2.0, 0.5, 0.5); + const shape2 = new RAPIER.Cuboid(0.5, 1.5, 0.5); + + const shapes = [shape1, shape2]; + const positions = [ + new RAPIER.Vector3(0.0, 1.0, 0.0), + new RAPIER.Vector3(0.0, -1.0, 0.0), + ]; + const rotations = [ + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ]; + + return RAPIER.ColliderDesc.compound(shapes, positions, rotations); +} + +function createPlusShape(RAPIER: RAPIER_API): ColliderDesc { + const shape1 = new RAPIER.Cuboid(2.0, 0.5, 0.5); + const shape2 = new RAPIER.Cuboid(0.5, 2.0, 0.5); + + const shapes = [shape1, shape2]; + const positions = [ + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Vector3(0.0, 0.0, 0.0), + ]; + const rotations = [ + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ]; + + return RAPIER.ColliderDesc.compound(shapes, positions, rotations); +} + +function createStairsShape(RAPIER: RAPIER_API): ColliderDesc { + const step = new RAPIER.Cuboid(0.8, 0.4, 0.5); + + const shapes = [step, step, step]; + // Bottom, middle, top steps respectively. + const positions = [ + new RAPIER.Vector3(-1.2, -0.8, 0.0), + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Vector3(1.2, 0.8, 0.0), + ]; + const rotations = [ + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ]; + + return RAPIER.ColliderDesc.compound(shapes, positions, rotations); +} + +function createDumbbellShape(RAPIER: RAPIER_API): ColliderDesc { + const shape1 = new RAPIER.Ball(0.8); // left weight + const shape2 = new RAPIER.Cuboid(1.5, 0.2, 0.2); // bar + const shape3 = new RAPIER.Ball(0.8); // right weight + + const shapes = [shape1, shape2, shape3]; + const positions = [ + new RAPIER.Vector3(-2.0, 0.0, 0.0), + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Vector3(2.0, 0.0, 0.0), + ]; + const rotations = [ + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ]; + + return RAPIER.ColliderDesc.compound(shapes, positions, rotations); +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + testbed.parameters.debugRender = true; + + // Create Ground - a large platform + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.5, 15.0); + world.createCollider(colliderDesc, groundBody); + + for (let i = 0; i < 3; i++) { + const x = (i - 1) * 8; + const bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + x, + 1.0, + 0.0, + ); + const body = world.createRigidBody(bodyDesc); + const colliderDesc = RAPIER.ColliderDesc.cylinder(2.0, 0.5); + world.createCollider(colliderDesc, body); + } + + const rng = seedrandom("compoundShapes"); + + const shapeCreators = [ + createLShape, + createTShape, + createPlusShape, + createStairsShape, + createDumbbellShape, + ]; + + const gridSize = 4; + const spacing = 6.0; + const startHeight = 15.0; + + for (let i = 0; i < gridSize; i++) { + for (let j = 0; j < gridSize; j++) { + const x = (i - gridSize / 2) * spacing; + const z = (j - gridSize / 2) * spacing; + const y = startHeight + i * 3.0; + + const shapeCreator = + shapeCreators[Math.floor(rng() * shapeCreators.length)]; + + const bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + const body = world.createRigidBody(bodyDesc); + const colliderDesc = shapeCreator(RAPIER); + world.createCollider(colliderDesc, body); + body.setAngvel( + new RAPIER.Vector3( + (rng() - 0.5) * 3, + (rng() - 0.5) * 3, + (rng() - 0.5) * 3, + ), + true, + ); + body.setLinvel( + new RAPIER.Vector3((rng() - 0.5) * 2, -1.0, (rng() - 0.5) * 2), + true, + ); + } + } + + for (let i = 0; i < 3; i++) { + const side = i % 2 === 0 ? -12 : 12; + const bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + side, + 20.0 + i * 4, + 0.0, + ); + const body = world.createRigidBody(bodyDesc); + const colliderDesc = createDumbbellShape(RAPIER); + world.createCollider(colliderDesc, body); + body.setLinvel(new RAPIER.Vector3(side * -1.5, 0.0, 0.0), true); + body.setAngvel(new RAPIER.Vector3(0.0, (rng() - 0.5) * 4, 0.0), true); + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: {x: 30.0, y: 25.0, z: 30.0}, + target: {x: 0.0, y: 10.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/convexDecomposition.ts b/typescript/testbed3d/src/demos/convexDecomposition.ts new file mode 100644 index 000000000..9d6277083 --- /dev/null +++ b/typescript/testbed3d/src/demos/convexDecomposition.ts @@ -0,0 +1,158 @@ +import type {Testbed} from "../Testbed"; +import { + Vector3, + Object3D, + Mesh, + BufferGeometry, + BufferAttribute, + MeshPhongMaterial, + Color, +} from "three"; +import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"; +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + testbed.parameters.debugRender = true; + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(10.0, 0.1, 10.0); + world.createCollider(colliderDesc, groundBody); + + let loader = new GLTFLoader(); + + const positions = [ + {x: -4, y: 15, z: 0}, + {x: 0, y: 18, z: 0}, + {x: 4, y: 21, z: 0}, + ]; + + const colors = [ + [0xff6b6b, 0x4ecdc4, 0x45b7d1, 0xf9ca24, 0xee5a6f], + [0x6c5ce7, 0xa29bfe, 0xfd79a8, 0xfdcb6e, 0xe17055], + [0x00b894, 0x00cec9, 0x0984e3, 0x6c5ce7, 0xfd79a8], + ]; + + positions.forEach((pos, index) => { + loader.load("./suzanne_blender_monkey.glb", (gltf) => { + const scale = 2.0; + gltf.scene.position.set(pos.x, pos.y, pos.z); + gltf.scene.scale.set(scale, scale, scale); + gltf.scene.updateMatrixWorld(true); + + const v = new Vector3(); + const meshVertices: number[] = []; + const meshIndices: number[] = []; + + gltf.scene.traverse((child: Object3D) => { + if ((child as Mesh).isMesh && (child as Mesh).geometry) { + const mesh = child as Mesh; + const geometry = mesh.geometry as BufferGeometry; + const positionAttribute = geometry.getAttribute( + "position", + ) as BufferAttribute; + const indexArray = geometry.index?.array; + + if (!indexArray) return; + + const baseIndex = meshVertices.length / 3; + + for (let i = 0, l = positionAttribute.count; i < l; i++) { + v.fromBufferAttribute(positionAttribute, i); + v.applyMatrix4(mesh.matrixWorld); + meshVertices.push(v.x, v.y, v.z); + } + + for (let i = 0; i < indexArray.length; i++) { + meshIndices.push(indexArray[i] + baseIndex); + } + } + }); + + const colliderDesc = RAPIER.ColliderDesc.convexDecomposition( + new Float32Array(meshVertices), + new Uint32Array(meshIndices), + ); + + if (colliderDesc) { + const rigidBodyDesc = RAPIER.RigidBodyDesc.dynamic(); + const rigidBody = world.createRigidBody(rigidBodyDesc); + world.createCollider(colliderDesc, rigidBody); + rigidBody.setAngvel( + new RAPIER.Vector3( + (Math.random() - 0.5) * 2, + (Math.random() - 0.5) * 2, + (Math.random() - 0.5) * 2, + ), + true, + ); + + gltf.scene.traverse((child: Object3D) => { + if ((child as Mesh).isMesh) { + const mesh = child as Mesh; + const geometry = mesh.geometry as BufferGeometry; + const vertexColors = new Float32Array( + geometry.attributes.position.count * 3, + ); + const colorPalette = colors[index]; + + for ( + let i = 0; + i < geometry.attributes.position.count; + i++ + ) { + const color = new Color( + colorPalette[ + Math.floor( + (i / + geometry.attributes.position + .count) * + colorPalette.length, + ) + ], + ); + vertexColors[i * 3] = color.r; + vertexColors[i * 3 + 1] = color.g; + vertexColors[i * 3 + 2] = color.b; + } + + geometry.setAttribute( + "color", + new BufferAttribute(vertexColors, 3), + ); + mesh.material = new MeshPhongMaterial({ + vertexColors: true, + flatShading: false, + }); + } + }); + + testbed.graphics.scene.add(gltf.scene); + } + }); + }); + + for (let i = 0; i < 10; i++) { + const x = (Math.random() - 0.5) * 8; + const y = 3 + Math.random() * 5; + const z = (Math.random() - 0.5) * 8; + const size = 0.3 + Math.random() * 0.4; + + const bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation(x, y, z); + const body = world.createRigidBody(bodyDesc); + const colliderDesc = RAPIER.ColliderDesc.cuboid(size, size, size); + world.createCollider(colliderDesc, body); + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: {x: 15.0, y: 10.0, z: 15.0}, + target: {x: 0.0, y: 5.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/convexPolyhedron.ts b/typescript/testbed3d/src/demos/convexPolyhedron.ts new file mode 100644 index 000000000..0ec4b9031 --- /dev/null +++ b/typescript/testbed3d/src/demos/convexPolyhedron.ts @@ -0,0 +1,111 @@ +import type {Testbed} from "../Testbed"; +import seedrandom from "seedrandom"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function generateTriMesh(nsubdivs: number, wx: number, wy: number, wz: number) { + let vertices = []; + let indices = []; + + let elementWidth = 1.0 / nsubdivs; + let rng = seedrandom("trimesh"); + + let i, j; + for (i = 0; i <= nsubdivs; ++i) { + for (j = 0; j <= nsubdivs; ++j) { + let x = (j * elementWidth - 0.5) * wx; + let y = rng() * wy; + let z = (i * elementWidth - 0.5) * wz; + + vertices.push(x, y, z); + } + } + + for (i = 0; i < nsubdivs; ++i) { + for (j = 0; j < nsubdivs; ++j) { + let i1 = (i + 0) * (nsubdivs + 1) + (j + 0); + let i2 = (i + 0) * (nsubdivs + 1) + (j + 1); + let i3 = (i + 1) * (nsubdivs + 1) + (j + 0); + let i4 = (i + 1) * (nsubdivs + 1) + (j + 1); + + indices.push(i1, i3, i2); + indices.push(i3, i4, i2); + } + } + + return { + vertices: new Float32Array(vertices), + indices: new Uint32Array(indices), + }; +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let trimesh = generateTriMesh(20, 40.0, 4.0, 40.0); + let colliderDesc = RAPIER.ColliderDesc.trimesh( + trimesh.vertices, + trimesh.indices, + ); + world.createCollider(colliderDesc, body); + + /* + * Create the polyhedra + */ + let num = 5; + let scale = 2.0; + let border_rad = 0.1; + + let shift = border_rad * 2.0 + scale; + let centerx = shift * (num / 2); + let centery = shift / 2.0; + let centerz = shift * (num / 2); + + let rng = seedrandom("convexPolyhedron"); + let i, j, k, l; + + for (j = 0; j < 15; ++j) { + for (i = 0; i < num; ++i) { + for (k = 0; k < num; ++k) { + let x = i * shift - centerx; + let y = j * shift + centery + 3.0; + let z = k * shift - centerz; + + let vertices = []; + for (l = 0; l < 10; ++l) { + vertices.push(rng() * scale, rng() * scale, rng() * scale); + } + let v = new Float32Array(vertices); + + // Build the rigid body. + bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.roundConvexHull( + v, + border_rad, + ); + world.createCollider(colliderDesc, body); + } + } + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/damping.ts b/typescript/testbed3d/src/demos/damping.ts new file mode 100644 index 000000000..c6295f667 --- /dev/null +++ b/typescript/testbed3d/src/demos/damping.ts @@ -0,0 +1,42 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, 0.0, 0.0); + let world = new RAPIER.World(gravity); + + /* + * Create the cubes + */ + let num = 10; + let rad = 0.2; + + let subdiv = 1.0 / num; + + let i; + for (i = 0; i < num; ++i) { + let x = Math.sin(i * subdiv * Math.PI * 2.0); + let y = Math.cos(i * subdiv * Math.PI * 2.0); + + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(x, y, 0.0) + .setLinvel(x * 10.0, y * 10.0, 0.0) + .setAngvel(new RAPIER.Vector3(0.0, 0.0, 100.0)) + .setLinearDamping((i + 1) * subdiv * 10.0) + .setAngularDamping((num - i) * subdiv * 10.0); + let body = world.createRigidBody(bodyDesc); + + // Build the collider. + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, body); + } + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: 0, y: 2.0, z: 20}, + target: {x: 0, y: 2.0, z: 0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/fountain.ts b/typescript/testbed3d/src/demos/fountain.ts new file mode 100644 index 000000000..00d8dced6 --- /dev/null +++ b/typescript/testbed3d/src/demos/fountain.ts @@ -0,0 +1,78 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + let removableBodies = new Array(); + + // Create Ground. + let groundBodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(groundBodyDesc); + let groundColliderDesc = RAPIER.ColliderDesc.cuboid(40.0, 0.1, 40.0); + world.createCollider(groundColliderDesc, groundBody); + + // Dynamic cubes. + let rad = 1.0; + let j = 0; + let spawn_interval = 5; + + let spawnBodies = (graphics: Testbed["graphics"]) => { + j += 1; + if (j % spawn_interval != 0) { + return; + } + + let bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setLinvel(0.0, 15.0, 0.0) + .setTranslation(0.0, 10.0, 0.0); + let colliderDesc; + + switch ((j / spawn_interval) % 4) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.roundCylinder( + rad, + rad, + rad / 10.0, + ); + break; + case 3: + colliderDesc = RAPIER.ColliderDesc.cone(rad, rad); + break; + } + + let body = world.createRigidBody(bodyDesc); + let collider = world.createCollider(colliderDesc, body); + graphics.addCollider(RAPIER, world, collider); + + removableBodies.push(body); + + // We reached the max number, delete the oldest rigid-body. + if (removableBodies.length > 400) { + let rb = removableBodies[0]; + world.removeRigidBody(rb); + graphics.removeRigidBody(rb); + removableBodies.shift(); + } + }; + + testbed.setWorld(world); + testbed.setpreTimestepAction(spawnBodies); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 10.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/glbToTrimesh.ts b/typescript/testbed3d/src/demos/glbToTrimesh.ts new file mode 100644 index 000000000..fa65a7cd7 --- /dev/null +++ b/typescript/testbed3d/src/demos/glbToTrimesh.ts @@ -0,0 +1,68 @@ +import type {Testbed} from "../Testbed"; +import {Vector3, Object3D, Mesh, BufferGeometry, BufferAttribute} from "three"; +import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"; +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + testbed.parameters.debugRender = true; + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(5.0, 0.1, 5.0); + world.createCollider(colliderDesc, groundBody); + + // Adding the 3d model + + let loader = new GLTFLoader(); + + loader.load("./suzanne_blender_monkey.glb", (gltf) => { + gltf.scene.position.set(0, 1.2, 0); + gltf.scene.scale.set(3, 3, 3); + testbed.graphics.scene.add(gltf.scene); + gltf.scene.updateMatrixWorld(true); // ensure world matrix is up to date + gltf.scene.traverse((child: Object3D) => { + if ((child as Mesh).isMesh && (child as Mesh).geometry) { + const mesh = child as Mesh; + const geometry = mesh.geometry as BufferGeometry; + + const vertices: number[] = []; + const indices = new Uint32Array(geometry.index!.array); // assume index is non-null + const positionAttribute = geometry.getAttribute( + "position", + ) as BufferAttribute; + + mesh.updateWorldMatrix(true, true); + + const v = new Vector3(); + + for (let i = 0, l = positionAttribute.count; i < l; i++) { + v.fromBufferAttribute(positionAttribute, i); + v.applyMatrix4(mesh.matrixWorld); + vertices.push(v.x, v.y, v.z); + } + + const verticesArray = new Float32Array(vertices); + + const rigidBodyDesc = RAPIER.RigidBodyDesc.fixed(); + const rigidBody = world.createRigidBody(rigidBodyDesc); + + const colliderDesc = RAPIER.ColliderDesc.trimesh( + verticesArray, + indices, + ); + world.createCollider(colliderDesc, rigidBody); + } + }); + }); + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: 10.0, y: 5.0, z: 10.0}, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/glbtoConvexHull.ts b/typescript/testbed3d/src/demos/glbtoConvexHull.ts new file mode 100644 index 000000000..a4d2619e7 --- /dev/null +++ b/typescript/testbed3d/src/demos/glbtoConvexHull.ts @@ -0,0 +1,68 @@ +import type {Testbed} from "../Testbed"; +import { + Vector3, + Object3D, + Mesh, + BufferGeometry, + BufferAttribute, + TriangleStripDrawMode, +} from "three"; +import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"; +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let groundBody = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(5.0, 0.1, 5.0); + world.createCollider(colliderDesc, groundBody); + + // Adding the 3d model + + let loader = new GLTFLoader(); + + loader.load("./suzanne_blender_monkey.glb", (gltf) => { + gltf.scene.position.set(0, 1.2, 0); + gltf.scene.scale.set(3, 3, 3); + testbed.graphics.scene.add(gltf.scene); + testbed.parameters.debugRender = true; + gltf.scene.updateMatrixWorld(true); // ensure world matrix is up to date + + const v = new Vector3(); + const positions: number[] = []; + + gltf.scene.traverse((child: Object3D) => { + if ((child as Mesh).isMesh && (child as Mesh).geometry) { + const mesh = child as Mesh; + const geometry = mesh.geometry as BufferGeometry; + const positionAttribute = geometry.getAttribute( + "position", + ) as BufferAttribute; + + for (let i = 0, l = positionAttribute.count; i < l; i++) { + v.fromBufferAttribute(positionAttribute, i); + v.applyMatrix4(mesh.matrixWorld); + positions.push(v.x, v.y, v.z); + } + } + }); + + const rigidBodyDesc = RAPIER.RigidBodyDesc.fixed(); + const rigidBody = world.createRigidBody(rigidBodyDesc); + + const colliderDesc = RAPIER.ColliderDesc.convexHull( + new Float32Array(positions), + ); + world.createCollider(colliderDesc, rigidBody); + }); + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: 10.0, y: 5.0, z: 10.0}, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/heightfield.ts b/typescript/testbed3d/src/demos/heightfield.ts new file mode 100644 index 000000000..5a2feece9 --- /dev/null +++ b/typescript/testbed3d/src/demos/heightfield.ts @@ -0,0 +1,126 @@ +import seedrandom from "seedrandom"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function generateHeightfield(nsubdivs: number) { + let heights = []; + + let rng = seedrandom("heightfield"); + + let i, j; + for (i = 0; i <= nsubdivs; ++i) { + for (j = 0; j <= nsubdivs; ++j) { + heights.push(rng()); + } + } + + return new Float32Array(heights); +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let nsubdivs = 20; + let scale = new RAPIER.Vector3(70.0, 4.0, 70.0); + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let heights = generateHeightfield(nsubdivs); + let colliderDesc = RAPIER.ColliderDesc.heightfield( + nsubdivs, + nsubdivs, + heights, + scale, + ); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let num = 4; + let numy = 10; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centery = shift / 2.0; + + let offset = -num * (rad * 2.0 + rad) * 0.5; + let i, j, k; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + for (k = 0; k < num; ++k) { + let x = i * shift + offset; + let y = j * shift + centery + 3.0; + let z = k * shift + offset; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc; + + switch (j % 5) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + rad, + ); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.roundCylinder( + rad, + rad, + rad / 10.0, + ); + break; + case 3: + colliderDesc = RAPIER.ColliderDesc.cone(rad, rad); + break; + case 4: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad / 2.0, + rad / 2.0, + ); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(rad, 0.0, 0.0); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(-rad, 0.0, 0.0); + break; + } + + world.createCollider(colliderDesc, body); + } + } + + offset -= 0.05 * rad * (num - 1.0); + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/joints.ts b/typescript/testbed3d/src/demos/joints.ts new file mode 100644 index 000000000..56546d7fa --- /dev/null +++ b/typescript/testbed3d/src/demos/joints.ts @@ -0,0 +1,292 @@ +import type RAPIER from "@dimforge/rapier3d"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function createPrismaticJoints( + RAPIER: RAPIER_API, + world: RAPIER.World, + origin: RAPIER.Vector, + num: number, +) { + let rad = 0.4; + let shift = 1.0; + + let groundDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + origin.x, + origin.y, + origin.z, + ); + let currParent = world.createRigidBody(groundDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, currParent); + + let i; + let z; + + for (i = 0; i < num; ++i) { + z = origin.z + (i + 1) * shift; + let rigidBodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + origin.x, + origin.y, + z, + ); + let currChild = world.createRigidBody(rigidBodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, currChild); + + let axis; + + if (i % 2 == 0) { + axis = new RAPIER.Vector3(1.0, 1.0, 0.0); + } else { + axis = new RAPIER.Vector3(-1.0, 1.0, 0.0); + } + + z = new RAPIER.Vector3(0.0, 0.0, 1.0); + let prism = RAPIER.JointData.prismatic( + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Vector3(0.0, 0.0, -shift), + axis, + ); + prism.limitsEnabled = true; + prism.limits = [-2.0, 2.0]; + world.createImpulseJoint(prism, currParent, currChild, true); + + currParent = currChild; + } +} + +function createRevoluteJoints( + RAPIER: RAPIER_API, + world: RAPIER.World, + origin: RAPIER.Vector3, + num: number, +) { + let rad = 0.4; + let shift = 2.0; + + let groundDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + origin.x, + origin.y, + 0.0, + ); + let currParent = world.createRigidBody(groundDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, currParent); + + let i, k; + let z; + + for (i = 0; i < num; ++i) { + // Create four bodies. + z = origin.z + i * shift * 2.0 + shift; + + let positions = [ + new RAPIER.Vector3(origin.x, origin.y, z), + new RAPIER.Vector3(origin.x + shift, origin.y, z), + new RAPIER.Vector3(origin.x + shift, origin.y, z + shift), + new RAPIER.Vector3(origin.x, origin.y, z + shift), + ]; + + let parents = [currParent, currParent, currParent, currParent]; + + for (k = 0; k < 4; ++k) { + let rigidBodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + positions[k].x, + positions[k].y, + positions[k].z, + ); + let rigidBody = world.createRigidBody(rigidBodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, rigidBody); + + parents[k] = rigidBody; + } + + // Setup four joints. + let o = new RAPIER.Vector3(0.0, 0.0, 0.0); + let x = new RAPIER.Vector3(1.0, 0.0, 0.0); + z = new RAPIER.Vector3(0.0, 0.0, 1.0); + + let revs = [ + RAPIER.JointData.revolute( + o, + new RAPIER.Vector3(0.0, 0.0, -shift), + z, + ), + RAPIER.JointData.revolute( + o, + new RAPIER.Vector3(-shift, 0.0, 0.0), + x, + ), + RAPIER.JointData.revolute( + o, + new RAPIER.Vector3(0.0, 0.0, -shift), + z, + ), + RAPIER.JointData.revolute( + o, + new RAPIER.Vector3(shift, 0.0, 0.0), + x, + ), + ]; + + world.createImpulseJoint(revs[0], currParent, parents[0], true); + world.createImpulseJoint(revs[1], parents[0], parents[1], true); + world.createImpulseJoint(revs[2], parents[1], parents[2], true); + world.createImpulseJoint(revs[3], parents[2], parents[3], true); + + currParent = parents[3]; + } +} + +function createFixedJoints( + RAPIER: RAPIER_API, + world: RAPIER.World, + origin: RAPIER.Vector3, + num: number, +) { + let rad = 0.4; + let shift = 1.0; + let i, k; + let parents = []; + + for (k = 0; k < num; ++k) { + for (i = 0; i < num; ++i) { + let fk = k; + let fi = i; + + // NOTE: the num - 2 test is to avoid two consecutive + // fixed bodies. Because physx will crash if we add + // a joint between these. + let bodyType; + + if (i == 0 && ((k % 4 == 0 && k != num - 2) || k == num - 1)) { + bodyType = RAPIER.RigidBodyType.Fixed; + } else { + bodyType = RAPIER.RigidBodyType.Dynamic; + } + + let rigidBody = new RAPIER.RigidBodyDesc(bodyType).setTranslation( + origin.x + fk * shift, + origin.y, + origin.z + fi * shift, + ); + let child = world.createRigidBody(rigidBody); + let colliderDesc = RAPIER.ColliderDesc.ball(rad); + world.createCollider(colliderDesc, child); + + // Vertical joint. + if (i > 0) { + let parent = parents[parents.length - 1]; + let params = RAPIER.JointData.fixed( + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Vector3(0.0, 0.0, -shift), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ); + + world.createImpulseJoint(params, parent, child, true); + } + + // Horizontal joint. + if (k > 0) { + let parent_index = parents.length - num; + let parent = parents[parent_index]; + let params = RAPIER.JointData.fixed( + new RAPIER.Vector3(0.0, 0.0, 0.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + new RAPIER.Vector3(-shift, 0.0, 0.0), + new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0), + ); + + world.createImpulseJoint(params, parent, child, true); + } + + parents.push(child); + } + } +} + +function createBallJoints( + RAPIER: RAPIER_API, + world: RAPIER.World, + num: number, +) { + let rad = 0.4; + let shift = 1.0; + let i, k; + let parents = []; + + for (k = 0; k < num; ++k) { + for (i = 0; i < num; ++i) { + let fk = k; + let fi = i; + + let bodyType; + + if (i == 0 && (k % 4 == 0 || k == num - 1)) { + bodyType = RAPIER.RigidBodyType.Fixed; + } else { + bodyType = RAPIER.RigidBodyType.Dynamic; + } + + let bodyDesc = new RAPIER.RigidBodyDesc(bodyType).setTranslation( + fk * shift, + 0.0, + fi * shift, + ); + let child = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.ball(rad); + world.createCollider(colliderDesc, child); + + // Vertical joint. + let o = new RAPIER.Vector3(0.0, 0.0, 0.0); + + if (i > 0) { + let parent = parents[parents.length - 1]; + let params = RAPIER.JointData.spherical( + o, + new RAPIER.Vector3(0.0, 0.0, -shift), + ); + world.createImpulseJoint(params, parent, child, true); + } + + // Horizontal joint. + if (k > 0) { + let parent_index = parents.length - num; + let parent = parents[parent_index]; + let params = RAPIER.JointData.spherical( + o, + new RAPIER.Vector3(-shift, 0.0, 0.0), + ); + world.createImpulseJoint(params, parent, child, true); + } + + parents.push(child); + } + } +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + createPrismaticJoints( + RAPIER, + world, + new RAPIER.Vector3(20.0, 10.0, 0.0), + 5, + ); + createFixedJoints(RAPIER, world, new RAPIER.Vector3(0.0, 10.0, 0.0), 5); + createRevoluteJoints(RAPIER, world, new RAPIER.Vector3(20.0, 0.0, 0.0), 3); + createBallJoints(RAPIER, world, 15); + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: 15.0, y: 5.0, z: 42.0}, + target: {x: 13.0, y: 1.0, z: 1.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/keva.ts b/typescript/testbed3d/src/demos/keva.ts new file mode 100644 index 000000000..d4e27cb0d --- /dev/null +++ b/typescript/testbed3d/src/demos/keva.ts @@ -0,0 +1,139 @@ +import type RAPIER from "@dimforge/rapier3d"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function buildBlock( + RAPIER: RAPIER_API, + world: RAPIER.World, + halfExtents: RAPIER.Vector, + shift: RAPIER.Vector, + numx: number, + numy: number, + numz: number, +) { + let half_extents_zyx = { + x: halfExtents.z, + y: halfExtents.y, + z: halfExtents.x, + }; + let dimensions = [halfExtents, half_extents_zyx]; + let blockWidth = 2.0 * halfExtents.z * numx; + let blockHeight = 2.0 * halfExtents.y * numy; + let spacing = (halfExtents.z * numx - halfExtents.x) / (numz - 1.0); + + let i; + let j; + let k; + + for (i = 0; i < numy; ++i) { + [numx, numz] = [numz, numx]; + let dim = dimensions[i % 2]; + let y = dim.y * i * 2.0; + + for (j = 0; j < numx; ++j) { + let x = i % 2 == 0 ? spacing * j * 2.0 : dim.x * j * 2.0; + + for (k = 0; k < numz; ++k) { + let z = i % 2 == 0 ? dim.z * k * 2.0 : spacing * k * 2.0; + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x + dim.x + shift.x, + y + dim.y + shift.y, + z + dim.z + shift.z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + dim.x, + dim.y, + dim.z, + ); + world.createCollider(colliderDesc, body); + } + } + } + + // Close the top. + let dim = {x: halfExtents.z, y: halfExtents.x, z: halfExtents.y}; + + for (i = 0; i < blockWidth / (dim.x * 2.0); ++i) { + for (j = 0; j < blockWidth / (dim.z * 2.0); ++j) { + // Build the rigid body. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + i * dim.x * 2.0 + dim.x + shift.x, + dim.y + shift.y + blockHeight, + j * dim.z * 2.0 + dim.z + shift.z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(dim.x, dim.y, dim.z); + world.createCollider(colliderDesc, body); + } + } +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let groundSize = 50.0; + let groundHeight = 0.1; + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + 0.0, + -groundHeight, + 0.0, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + groundSize, + groundHeight, + groundSize, + ); + world.createCollider(colliderDesc, body); + + // Keva tower. + let halfExtents = new RAPIER.Vector3(0.1, 0.5, 2.0); + let blockHeight = 0.0; + // These should only be set to odd values otherwise + // the blocks won't align in the nicest way. + let numyArr = [0, 3, 5, 5, 7, 9]; + let numBlocksBuilt = 0; + let i; + + for (i = 5; i >= 1; --i) { + let numx = i; + let numy = numyArr[i]; + let numz = numx * 3 + 1; + let blockWidth = numx * halfExtents.z * 2.0; + buildBlock( + RAPIER, + world, + halfExtents, + new RAPIER.Vector3( + -blockWidth / 2.0, + blockHeight, + -blockWidth / 2.0, + ), + numx, + numy, + numz, + ); + blockHeight += numy * halfExtents.y * 2.0 + halfExtents.x * 2.0; + numBlocksBuilt += numx * numy * numz; + } + + testbed.setWorld(world); + let cameraPosition = { + eye: { + x: -70.38553832116718, + y: 17.893810295517365, + z: 29.34767842147597, + }, + target: { + x: 0.5890869353464383, + y: 3.132044603021203, + z: -0.2899937806661885, + }, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/lockedRotations.ts b/typescript/testbed3d/src/demos/lockedRotations.ts new file mode 100644 index 000000000..e3b4c538a --- /dev/null +++ b/typescript/testbed3d/src/demos/lockedRotations.ts @@ -0,0 +1,58 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + /* + * The ground + */ + let ground_size = 1.7; + let ground_height = 0.1; + + let bodyDesc = RAPIER.RigidBodyDesc.fixed().setTranslation( + 0.0, + -ground_height, + 0.0, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + ground_size, + ground_height, + ground_size, + ); + world.createCollider(colliderDesc, body); + + /* + * A rectangle that only rotates along the `x` axis. + */ + bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(0.0, 3.0, 0.0) + .lockTranslations() + .enabledRotations(true, false, false); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.cuboid(0.2, 0.6, 2.0); + world.createCollider(colliderDesc, body); + + /* + * A cylinder that cannot rotate. + */ + bodyDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(0.2, 5.0, 0.4) + .lockRotations(); + body = world.createRigidBody(bodyDesc); + colliderDesc = RAPIER.ColliderDesc.cylinder(0.6, 0.4); + world.createCollider(colliderDesc, body); + + /* + * Setup the testbed. + */ + testbed.setWorld(world); + let cameraPosition = { + eye: {x: -10.0, y: 3.0, z: 0.0}, + target: {x: 0.0, y: 3.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/pidController.ts b/typescript/testbed3d/src/demos/pidController.ts new file mode 100644 index 000000000..ea3e1286e --- /dev/null +++ b/typescript/testbed3d/src/demos/pidController.ts @@ -0,0 +1,127 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(15.0, 0.1, 15.0); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let rad = 0.5; + let num = 5; + let i, j, k; + let shift = rad * 2.5; + let center = num * rad; + let height = 5.0; + + for (i = 0; i < num; ++i) { + for (j = i; j < num; ++j) { + for (k = i; k < num; ++k) { + let x = (i * shift) / 2.0 + (k - i) * shift - center; + let y = (i * shift) / 2.0 + height; + let z = (i * shift) / 2.0 + (j - i) * shift - center; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad / 2.0, + rad, + ); + world.createCollider(colliderDesc, body); + } + } + } + + // Character. + let characterDesc = RAPIER.RigidBodyDesc.dynamic() + .setTranslation(-10.0, 4.0, -10.0) + .setGravityScale(10.0) + .setSoftCcdPrediction(10.0); + let character = world.createRigidBody(characterDesc); + let characterColliderDesc = RAPIER.ColliderDesc.cylinder(1.2, 0.6); + world.createCollider(characterColliderDesc, character); + + let pidController = world.createPidController( + 60.0, + 0.0, + 1.0, + RAPIER.PidAxesMask.AllAng, + ); + let speed = 0.2; + let movementDirection = {x: 0.0, y: 0.0, z: 0.0}; + let targetVelocity = {x: 0.0, y: 0.0, z: 0.0}; + let targetRotation = new RAPIER.Quaternion(0.0, 0.0, 0.0, 1.0); + + let updateCharacter = () => { + if ( + movementDirection.x == 0.0 && + movementDirection.y == 0.0 && + movementDirection.z == 0.0 + ) { + // Only adjust the rotation, but let translation. + pidController.setAxes(RAPIER.PidAxesMask.AllAng); + } else if (movementDirection.y == 0.0) { + // Don’t control the linear Y axis so the player can fall down due to gravity. + pidController.setAxes( + RAPIER.PidAxesMask.AllAng | + RAPIER.PidAxesMask.LinX | + RAPIER.PidAxesMask.LinZ, + ); + } else { + pidController.setAxes(RAPIER.PidAxesMask.All); + } + + let targetPoint = character.translation(); + targetPoint.x += movementDirection.x; + targetPoint.y += movementDirection.y; + targetPoint.z += movementDirection.z; + + pidController.applyLinearCorrection( + character, + targetPoint, + targetVelocity, + ); + pidController.applyAngularCorrection( + character, + targetRotation, + targetVelocity, + ); + }; + + testbed.setWorld(world); + testbed.setpreTimestepAction(updateCharacter); + + document.onkeydown = function (event: KeyboardEvent) { + if (event.key == "ArrowUp") movementDirection.x = speed; + if (event.key == "ArrowDown") movementDirection.x = -speed; + if (event.key == "ArrowLeft") movementDirection.z = -speed; + if (event.key == "ArrowRight") movementDirection.z = speed; + if (event.key == " ") movementDirection.y = speed; + }; + + document.onkeyup = function (event: KeyboardEvent) { + if (event.key == "ArrowUp") movementDirection.x = 0.0; + if (event.key == "ArrowDown") movementDirection.x = 0.0; + if (event.key == "ArrowLeft") movementDirection.z = 0.0; + if (event.key == "ArrowRight") movementDirection.z = 0.0; + if (event.key == " ") movementDirection.y = 0.0; + }; + + let cameraPosition = { + eye: {x: -40.0, y: 19.730000000000008, z: 0.0}, + target: {x: 0.0, y: -0.4126, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/platform.ts b/typescript/testbed3d/src/demos/platform.ts new file mode 100644 index 000000000..fe51d9aea --- /dev/null +++ b/typescript/testbed3d/src/demos/platform.ts @@ -0,0 +1,153 @@ +import seedrandom from "seedrandom"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function generateTriMesh(nsubdivs: number, wx: number, wy: number, wz: number) { + let vertices = []; + let indices = []; + + let elementWidth = 1.0 / nsubdivs; + let rng = seedrandom("trimesh"); + + let i, j; + for (i = 0; i <= nsubdivs; ++i) { + for (j = 0; j <= nsubdivs; ++j) { + let x = (j * elementWidth - 0.5) * wx; + let y = rng() * wy; + let z = (i * elementWidth - 0.5) * wz; + + vertices.push(x, y, z); + } + } + + for (i = 0; i < nsubdivs; ++i) { + for (j = 0; j < nsubdivs; ++j) { + let i1 = (i + 0) * (nsubdivs + 1) + (j + 0); + let i2 = (i + 0) * (nsubdivs + 1) + (j + 1); + let i3 = (i + 1) * (nsubdivs + 1) + (j + 0); + let i4 = (i + 1) * (nsubdivs + 1) + (j + 1); + + indices.push(i1, i3, i2); + indices.push(i3, i4, i2); + } + } + + return { + vertices: new Float32Array(vertices), + indices: new Uint32Array(indices), + }; +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.kinematicVelocityBased(); + let platformBody = world.createRigidBody(bodyDesc); + let trimesh = generateTriMesh(20, 70.0, 4.0, 70.0); + let colliderDesc = RAPIER.ColliderDesc.trimesh( + trimesh.vertices, + trimesh.indices, + ); + world.createCollider(colliderDesc, platformBody); + let t = 0.0; + + let movePlatform = () => { + t += 0.016; + let dy = Math.sin(t) * 10.0; + let dang = Math.sin(t) * 0.2; + platformBody.setLinvel({x: 0.0, y: dy, z: 0.0}, true); + platformBody.setAngvel({x: 0.0, y: dang, z: 0.0}, true); + }; + + // Dynamic cubes. + let num = 4; + let numy = 10; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centery = shift / 2.0; + + let offset = -num * (rad * 2.0 + rad) * 0.5; + let i, j, k; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + for (k = 0; k < num; ++k) { + let x = i * shift + offset; + let y = j * shift + centery + 3.0; + let z = k * shift + offset; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc; + + switch (j % 5) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + rad, + ); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.roundCylinder( + rad, + rad, + rad / 10.0, + ); + break; + case 3: + colliderDesc = RAPIER.ColliderDesc.cone(rad, rad); + break; + case 4: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad / 2.0, + rad / 2.0, + ); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(rad, 0.0, 0.0); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(-rad, 0.0, 0.0); + break; + } + + world.createCollider(colliderDesc, body); + } + } + + offset -= 0.05 * rad * (num - 1.0); + } + + testbed.setWorld(world); + testbed.setpreTimestepAction(movePlatform); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/pyramid.ts b/typescript/testbed3d/src/demos/pyramid.ts new file mode 100644 index 000000000..9a63e47e4 --- /dev/null +++ b/typescript/testbed3d/src/demos/pyramid.ts @@ -0,0 +1,51 @@ +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(30.0, 0.1, 30.0); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let rad = 0.5; + let num = 10; + let i, j, k; + let shift = rad * 2.5; + let center = num * rad; + let height = 10.0; + + for (i = 0; i < num; ++i) { + for (j = i; j < num; ++j) { + for (k = i; k < num; ++k) { + let x = + (i * shift) / 2.0 + (k - i) * shift - height * rad - center; + let y = i * shift + height; + let z = + (i * shift) / 2.0 + (j - i) * shift - height * rad - center; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc = RAPIER.ColliderDesc.cuboid(rad, rad, rad); + world.createCollider(colliderDesc, body); + } + } + } + + testbed.setWorld(world); + let cameraPosition = { + eye: {x: -31.96000000000001, y: 19.730000000000008, z: -27.86}, + target: {x: -0.0505, y: -0.4126, z: -0.0229}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/trimesh.ts b/typescript/testbed3d/src/demos/trimesh.ts new file mode 100644 index 000000000..5a50bd3b2 --- /dev/null +++ b/typescript/testbed3d/src/demos/trimesh.ts @@ -0,0 +1,143 @@ +import seedrandom from "seedrandom"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function generateTriMesh(nsubdivs: number, wx: number, wy: number, wz: number) { + let vertices = []; + let indices = []; + + let elementWidth = 1.0 / nsubdivs; + let rng = seedrandom("trimesh"); + + let i, j; + for (i = 0; i <= nsubdivs; ++i) { + for (j = 0; j <= nsubdivs; ++j) { + let x = (j * elementWidth - 0.5) * wx; + let y = rng() * wy; + let z = (i * elementWidth - 0.5) * wz; + + vertices.push(x, y, z); + } + } + + for (i = 0; i < nsubdivs; ++i) { + for (j = 0; j < nsubdivs; ++j) { + let i1 = (i + 0) * (nsubdivs + 1) + (j + 0); + let i2 = (i + 0) * (nsubdivs + 1) + (j + 1); + let i3 = (i + 1) * (nsubdivs + 1) + (j + 0); + let i4 = (i + 1) * (nsubdivs + 1) + (j + 1); + + indices.push(i1, i3, i2); + indices.push(i3, i4, i2); + } + } + + return { + vertices: new Float32Array(vertices), + indices: new Uint32Array(indices), + }; +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let trimesh = generateTriMesh(20, 70.0, 4.0, 70.0); + let colliderDesc = RAPIER.ColliderDesc.trimesh( + trimesh.vertices, + trimesh.indices, + ); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let num = 4; + let numy = 10; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centery = shift / 2.0; + + let offset = -num * (rad * 2.0 + rad) * 0.5; + let i, j, k; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + for (k = 0; k < num; ++k) { + let x = i * shift + offset; + let y = j * shift + centery + 3.0; + let z = k * shift + offset; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc; + + switch (j % 5) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + rad, + ); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.roundCylinder( + rad, + rad, + rad / 10.0, + ); + break; + case 3: + colliderDesc = RAPIER.ColliderDesc.cone(rad, rad); + break; + case 4: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad / 2.0, + rad / 2.0, + ); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(rad, 0.0, 0.0); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(-rad, 0.0, 0.0); + break; + } + + world.createCollider(colliderDesc, body); + } + } + + offset -= 0.05 * rad * (num - 1.0); + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/demos/voxels.ts b/typescript/testbed3d/src/demos/voxels.ts new file mode 100644 index 000000000..936b87307 --- /dev/null +++ b/typescript/testbed3d/src/demos/voxels.ts @@ -0,0 +1,130 @@ +import seedrandom from "seedrandom"; +import type {Testbed} from "../Testbed"; + +type RAPIER_API = typeof import("@dimforge/rapier3d"); + +function generateVoxels(n: number) { + let points = []; + + let i, j; + for (i = 0; i <= n; ++i) { + for (j = 0; j <= n; ++j) { + let y = + Math.max( + -0.8, + Math.min( + Math.sin((i / n) * 10.0) * Math.cos((j / n) * 10.0), + 0.8, + ), + ) * 8.0; + points.push(i - n / 2.0, y, j - n / 2.0); + } + } + return { + points: new Float32Array(points), + voxelSize: {x: 1.0, y: 1.2, z: 1.5}, + }; +} + +export function initWorld(RAPIER: RAPIER_API, testbed: Testbed) { + let gravity = new RAPIER.Vector3(0.0, -9.81, 0.0); + let world = new RAPIER.World(gravity); + + // Create Ground. + let bodyDesc = RAPIER.RigidBodyDesc.fixed(); + let body = world.createRigidBody(bodyDesc); + let voxels = generateVoxels(100); + let colliderDesc = RAPIER.ColliderDesc.voxels( + voxels.points, + voxels.voxelSize, + ); + world.createCollider(colliderDesc, body); + + // Dynamic cubes. + let num = 10; + let numy = 4; + let rad = 1.0; + + let shift = rad * 2.0 + rad; + let centery = shift / 2.0; + + let offset = -num * (rad * 2.0 + rad) * 0.5; + let i, j, k; + + for (j = 0; j < numy; ++j) { + for (i = 0; i < num; ++i) { + for (k = 0; k < num; ++k) { + let x = i * shift + offset; + let y = j * shift + centery + 10.0; + let z = k * shift + offset; + + // Create dynamic cube. + let bodyDesc = RAPIER.RigidBodyDesc.dynamic().setTranslation( + x, + y, + z, + ); + let body = world.createRigidBody(bodyDesc); + let colliderDesc; + + switch (j % 5) { + case 0: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad, + rad, + rad, + ); + break; + case 1: + colliderDesc = RAPIER.ColliderDesc.ball(rad); + break; + case 2: + colliderDesc = RAPIER.ColliderDesc.roundCylinder( + rad, + rad, + rad / 10.0, + ); + break; + case 3: + colliderDesc = RAPIER.ColliderDesc.cone(rad, rad); + break; + case 4: + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad / 2.0, + rad / 2.0, + ); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(rad, 0.0, 0.0); + world.createCollider(colliderDesc, body); + colliderDesc = RAPIER.ColliderDesc.cuboid( + rad / 2.0, + rad, + rad / 2.0, + ).setTranslation(-rad, 0.0, 0.0); + break; + } + + world.createCollider(colliderDesc, body); + } + } + + offset -= 0.05 * rad * (num - 1.0); + } + + testbed.setWorld(world); + + let cameraPosition = { + eye: { + x: -88.48024008669711, + y: 46.911325612198354, + z: 83.56055570254844, + }, + target: {x: 0.0, y: 0.0, z: 0.0}, + }; + testbed.lookAt(cameraPosition); +} diff --git a/typescript/testbed3d/src/index.ts b/typescript/testbed3d/src/index.ts new file mode 100644 index 000000000..8aef2b9e8 --- /dev/null +++ b/typescript/testbed3d/src/index.ts @@ -0,0 +1,46 @@ +import {Testbed} from "./Testbed"; +import * as Trimesh from "./demos/trimesh"; +import * as Voxels from "./demos/voxels"; +import * as CollisionGroups from "./demos/collisionGroups"; +import * as Pyramid from "./demos/pyramid"; +import * as Keva from "./demos/keva"; +import * as Joints from "./demos/joints"; +import * as Fountain from "./demos/fountain"; +import * as Damping from "./demos/damping"; +import * as Heightfield from "./demos/heightfield"; +import * as LockedRotations from "./demos/lockedRotations"; +import * as ConvexPolyhedron from "./demos/convexPolyhedron"; +import * as CCD from "./demos/ccd"; +import * as Platform from "./demos/platform"; +import * as CharacterController from "./demos/characterController"; +import * as PidController from "./demos/pidController"; +import * as glbToTrimesh from "./demos/glbToTrimesh"; +import * as glbToConvexHull from "./demos/glbtoConvexHull"; +import * as CompoundShapes from "./demos/compoundShapes"; +import * as ConvexDecomposition from "./demos/convexDecomposition"; + +import("@dimforge/rapier3d").then((RAPIER) => { + let builders = new Map([ + ["collision groups", CollisionGroups.initWorld], + ["character controller", CharacterController.initWorld], + ["compound shapes", CompoundShapes.initWorld], + ["convex decomposition", ConvexDecomposition.initWorld], + ["convex polyhedron", ConvexPolyhedron.initWorld], + ["CCD", CCD.initWorld], + ["damping", Damping.initWorld], + ["fountain", Fountain.initWorld], + ["heightfield", Heightfield.initWorld], + ["joints", Joints.initWorld], + ["keva tower", Keva.initWorld], + ["locked rotations", LockedRotations.initWorld], + ["pid controller", PidController.initWorld], + ["platform", Platform.initWorld], + ["pyramid", Pyramid.initWorld], + ["triangle mesh", Trimesh.initWorld], + ["voxels", Voxels.initWorld], + ["GLTF to convexHull", glbToConvexHull.initWorld], + ["GLTF to trimesh", glbToTrimesh.initWorld], + ]); + let testbed = new Testbed(RAPIER, builders); + testbed.run(); +}); diff --git a/typescript/testbed3d/static/.htaccess b/typescript/testbed3d/static/.htaccess new file mode 100644 index 000000000..9bdb356b9 --- /dev/null +++ b/typescript/testbed3d/static/.htaccess @@ -0,0 +1,3 @@ +RewriteEngine On +RewriteCond %{SERVER_PORT} 80 +RewriteRule ^(.*)$ https://www.rapier.rs/$1 [R,L] diff --git a/typescript/testbed3d/static/index.html b/typescript/testbed3d/static/index.html new file mode 100644 index 000000000..d2a612213 --- /dev/null +++ b/typescript/testbed3d/static/index.html @@ -0,0 +1,18 @@ + + + + + Rapier3D JS bindings demo + + + + + + diff --git a/typescript/testbed3d/static/suzanne_blender_monkey.glb b/typescript/testbed3d/static/suzanne_blender_monkey.glb new file mode 100644 index 000000000..6b8819b0e Binary files /dev/null and b/typescript/testbed3d/static/suzanne_blender_monkey.glb differ diff --git a/typescript/testbed3d/tsconfig.json b/typescript/testbed3d/tsconfig.json new file mode 100644 index 000000000..5d07ecd80 --- /dev/null +++ b/typescript/testbed3d/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "outDir": "./dist/", + "noImplicitAny": true, + "module": "es2022", + "target": "es2022", + "allowJs": true, + "moduleResolution": "node", + "allowSyntheticDefaultImports": true + } +} diff --git a/typescript/testbed3d/webpack.config.js b/typescript/testbed3d/webpack.config.js new file mode 100644 index 000000000..0e5c98393 --- /dev/null +++ b/typescript/testbed3d/webpack.config.js @@ -0,0 +1,55 @@ +const webpack = require("webpack"); +const path = require("path"); +const CopyPlugin = require("copy-webpack-plugin"); + +const isDev = process.env.NODE_ENV === "development"; +const dist = path.resolve(__dirname, "dist"); + +/** + * @type {import('webpack-dev-server').Configuration} + */ +const devServer = { + static: { + directory: dist, + }, + allowedHosts: "all", + compress: true, +}; + +/** + * @type {import('webpack').Configuration} + */ +const webpackConfig = { + mode: isDev ? "development" : "production", + entry: "./src/index.ts", + devtool: "inline-source-map", + output: { + path: dist, + filename: "index.js", + }, + resolve: { + extensions: [".ts", ".js"], + }, + devServer, + performance: false, + experiments: { + asyncWebAssembly: true, + syncWebAssembly: true, + }, + module: { + rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, + ], + }, + plugins: [ + new CopyPlugin({ + patterns: [{from: "static", to: dist}], + }), + ], +}; + +module.exports = webpackConfig;