From 2e1ec07b237bd6036c7e957fbf3b6e5badb8886f Mon Sep 17 00:00:00 2001 From: lucas lelievre Date: Tue, 2 Dec 2025 14:49:45 +0100 Subject: [PATCH] Session flightlist (#1407) Co-authored-by: sctanf <36978460+sctanf@users.noreply.github.com> Co-authored-by: Butterscotch! Co-authored-by: Aed <145398159+Aed-1@users.noreply.github.com> --- Cargo.lock | 63 +- TRADEMARK.md | 64 +- gui/package.json | 16 +- gui/public/i18n/en/translation.ftl | 90 +- gui/public/images/mounting/MountingFeets.webp | Bin 0 -> 30678 bytes .../images/mounting/MountingFeetsSide.webp | Bin 0 -> 52158 bytes .../full-reset/end-full-reset-with-tail.ogg | Bin 0 -> 40167 bytes gui/public/sounds/full-reset/full-click-1.ogg | Bin 0 -> 6407 bytes gui/public/sounds/full-reset/full-click-2.ogg | Bin 0 -> 6330 bytes gui/public/sounds/full-reset/full-click-3.ogg | Bin 0 -> 6278 bytes .../full-reset/init-full-reset-with-tail.ogg | Bin 0 -> 43834 bytes gui/public/sounds/mew.ogg | Bin 0 -> 30095 bytes .../end-mounting-reset-with-tail.ogg | Bin 0 -> 40107 bytes .../init-mounting-reset-with-tail.ogg | Bin 0 -> 42955 bytes .../sounds/mounting-reset/mount-click-1.ogg | Bin 0 -> 6414 bytes .../sounds/mounting-reset/mount-click-2.ogg | Bin 0 -> 6350 bytes .../sounds/mounting-reset/mount-click-3.ogg | Bin 0 -> 6316 bytes gui/public/sounds/tracking/pause.ogg | Bin 0 -> 17453 bytes gui/public/sounds/tracking/play.ogg | Bin 0 -> 36218 bytes gui/public/sounds/yaw-reset/yaw-reset.ogg | Bin 0 -> 29358 bytes gui/src-tauri/Cargo.toml | 19 +- gui/src-tauri/capabilities/migrated.json | 13 +- gui/src/App.tsx | 25 +- gui/src/components/ClearMountingButton.tsx | 44 - gui/src/components/MainLayout.scss | 57 +- gui/src/components/MainLayout.tsx | 72 +- gui/src/components/Navbar.tsx | 16 +- gui/src/components/Sidebar.tsx | 251 ++ gui/src/components/Toolbar.tsx | 202 + gui/src/components/WidgetsComponent.tsx | 86 - gui/src/components/commons/A.tsx | 17 +- gui/src/components/commons/Button.tsx | 31 +- gui/src/components/commons/Checkbox.tsx | 8 +- gui/src/components/commons/FirmwareIcon.tsx | 86 + gui/src/components/commons/ProgressBar.tsx | 3 +- gui/src/components/commons/Tooltip.tsx | 78 +- gui/src/components/commons/Typography.tsx | 24 +- .../components/commons/icon/ChecklistIcon.tsx | 12 + gui/src/components/commons/icon/ClearIcon.tsx | 12 + gui/src/components/commons/icon/GearIcon.tsx | 6 +- gui/src/components/commons/icon/HomeIcon.tsx | 12 + .../components/commons/icon/LayoutIcon.tsx | 12 + gui/src/components/commons/icon/SkiIcon.tsx | 12 + gui/src/components/home/Home.tsx | 211 +- gui/src/components/home/HomeSettingsModal.tsx | 34 + gui/src/components/home/ResetButton.tsx | 236 +- .../onboarding/OnboardingLayout.tsx | 4 +- .../onboarding/pages/ConnectTracker.scss | 6 +- .../onboarding/pages/ConnectTracker.tsx | 67 +- .../body-proportions/ManualProportions.tsx | 1 - .../autobone-steps/Preparation.tsx | 6 +- .../mounting/mounting-steps/MountingReset.tsx | 2 +- .../mounting/mounting-steps/Preparation.tsx | 6 +- .../stay-aligned-steps/PreparationStep.tsx | 2 +- .../stay-aligned-steps/VerifyMounting.tsx | 2 +- .../trackers-assign/TrackerAssignment.tsx | 2 +- .../providers/StatusSystemContext.tsx | 10 - .../components/settings/SettingsLayout.scss | 6 +- .../settings/SettingsPageLayout.tsx | 2 +- .../components/settings/SettingsSidebar.tsx | 149 +- .../settings/pages/GeneralSettings.tsx | 36 +- .../settings/pages/HomeScreenSettings.tsx | 190 + .../settings/pages/InterfaceSettings.tsx | 24 +- gui/src/components/tracker/TrackerCard.tsx | 119 +- gui/src/components/tracker/TrackerWifi.tsx | 2 +- gui/src/components/tracker/TrackersTable.tsx | 526 ++- .../tracking-checklist/TrackingChecklist.tsx | 547 +++ .../TrackingChecklistModal.tsx | 36 + .../TrackingChecklistProvider.tsx | 19 + gui/src/components/vr-mode/VRModePage.tsx | 33 +- gui/src/components/vrc/VRCWarningsPage.tsx | 4 +- .../widgets/DeveloperModeWidget.tsx | 7 +- .../widgets/SkeletonVisualizerWidget.tsx | 137 +- gui/src/hooks/app.ts | 23 +- gui/src/hooks/body-parts.ts | 90 + gui/src/hooks/bvh.ts | 54 + gui/src/hooks/config.ts | 4 + gui/src/hooks/countdown.ts | 14 +- gui/src/hooks/pause-tracking.ts | 47 + gui/src/hooks/reset-settings.ts | 58 + gui/src/hooks/reset.ts | 151 + gui/src/hooks/status-system.ts | 207 - gui/src/hooks/tracking-checklist.ts | 193 + gui/src/hooks/vrc-config.ts | 26 +- gui/src/index.scss | 15 +- gui/src/sounds/sounds.ts | 134 +- gui/src/store/app-store.ts | 24 +- gui/src/utils/skeletonHelper.ts | 8 +- gui/tailwind.config.ts | 55 + gui/tsconfig.json | 4 +- pnpm-lock.yaml | 3777 +++++++++-------- .../java/dev/slimevr/NetworkProfileChecker.kt | 59 + .../src/main/java/dev/slimevr/VRServer.kt | 86 +- .../main/java/dev/slimevr/bridge/Bridge.kt | 2 + .../java/dev/slimevr/config/ResetsConfig.kt | 24 + .../dev/slimevr/config/TapDetectionConfig.kt | 10 +- .../slimevr/config/TrackingChecklistConfig.kt | 5 + .../main/java/dev/slimevr/config/VRCConfig.kt | 6 + .../main/java/dev/slimevr/config/VRConfig.kt | 6 +- .../slimevr/games/vrchat/VRCConfigHandler.kt | 50 +- .../main/java/dev/slimevr/osc/VMCHandler.kt | 2 +- .../java/dev/slimevr/osc/VRCOSCHandler.kt | 4 +- .../protocol/datafeed/DataFeedBuilder.java | 6 +- .../dev/slimevr/protocol/rpc/RPCHandler.kt | 223 +- .../rpc/games/vrchat/RPCVRCBuilder.kt | 9 +- .../rpc/games/vrchat/RPCVRChatHandler.kt | 18 +- .../protocol/rpc/reset/RPCResetHandler.java | 62 - .../protocol/rpc/reset/RPCResetHandler.kt | 124 + .../RPCTrackingChecklistHandler.kt | 73 + .../java/dev/slimevr/reset/ResetHandler.java | 30 - .../java/dev/slimevr/reset/ResetHandler.kt | 24 + .../java/dev/slimevr/reset/ResetListener.java | 8 - .../java/dev/slimevr/reset/ResetListener.kt | 7 + .../main/java/dev/slimevr/reset/ResetTimer.kt | 40 + .../java/dev/slimevr/status/StatusSystem.kt | 30 - .../tracking/processor/HumanPoseManager.kt | 63 +- .../processor/config/SkeletonConfigManager.kt | 3 + .../processor/skeleton/HumanSkeleton.kt | 68 +- .../processor/skeleton/TapDetection.kt | 92 +- .../skeleton/TapDetectionManager.java | 269 -- .../processor/skeleton/TapDetectionManager.kt | 116 + .../dev/slimevr/tracking/trackers/Tracker.kt | 151 +- .../tracking/trackers/TrackerResetsHandler.kt | 29 +- .../slimevr/tracking/trackers/TrackerUtils.kt | 14 + .../tracking/trackers/hid/HIDCommon.kt | 4 +- .../trackers/udp/TrackersUDPServer.kt | 40 +- .../TrackingChecklistManager.kt | 346 ++ .../java/dev/slimevr/unit/LegTweaksTests.kt | 4 +- .../dev/slimevr/unit/MountingResetTests.kt | 8 +- .../slimevr/unit/ReferenceAdjustmentsTests.kt | 6 +- .../java/dev/slimevr/unit/TestTrackerSet.kt | 4 +- ...ker.kt => DesktopNetworkProfileChecker.kt} | 87 +- .../src/main/java/dev/slimevr/desktop/Main.kt | 3 +- .../slimevr/desktop/platform/SteamVRBridge.kt | 32 +- .../platform/linux/UnixSocketBridge.java | 9 + .../windows/WindowsNamedPipeBridge.java | 9 + solarxr-protocol | 2 +- 137 files changed, 6693 insertions(+), 4215 deletions(-) create mode 100644 gui/public/images/mounting/MountingFeets.webp create mode 100644 gui/public/images/mounting/MountingFeetsSide.webp create mode 100644 gui/public/sounds/full-reset/end-full-reset-with-tail.ogg create mode 100644 gui/public/sounds/full-reset/full-click-1.ogg create mode 100644 gui/public/sounds/full-reset/full-click-2.ogg create mode 100644 gui/public/sounds/full-reset/full-click-3.ogg create mode 100644 gui/public/sounds/full-reset/init-full-reset-with-tail.ogg create mode 100644 gui/public/sounds/mew.ogg create mode 100644 gui/public/sounds/mounting-reset/end-mounting-reset-with-tail.ogg create mode 100644 gui/public/sounds/mounting-reset/init-mounting-reset-with-tail.ogg create mode 100644 gui/public/sounds/mounting-reset/mount-click-1.ogg create mode 100644 gui/public/sounds/mounting-reset/mount-click-2.ogg create mode 100644 gui/public/sounds/mounting-reset/mount-click-3.ogg create mode 100644 gui/public/sounds/tracking/pause.ogg create mode 100644 gui/public/sounds/tracking/play.ogg create mode 100644 gui/public/sounds/yaw-reset/yaw-reset.ogg delete mode 100644 gui/src/components/ClearMountingButton.tsx create mode 100644 gui/src/components/Sidebar.tsx create mode 100644 gui/src/components/Toolbar.tsx delete mode 100644 gui/src/components/WidgetsComponent.tsx create mode 100644 gui/src/components/commons/FirmwareIcon.tsx create mode 100644 gui/src/components/commons/icon/ChecklistIcon.tsx create mode 100644 gui/src/components/commons/icon/ClearIcon.tsx create mode 100644 gui/src/components/commons/icon/HomeIcon.tsx create mode 100644 gui/src/components/commons/icon/LayoutIcon.tsx create mode 100644 gui/src/components/commons/icon/SkiIcon.tsx create mode 100644 gui/src/components/home/HomeSettingsModal.tsx delete mode 100644 gui/src/components/providers/StatusSystemContext.tsx create mode 100644 gui/src/components/settings/pages/HomeScreenSettings.tsx create mode 100644 gui/src/components/tracking-checklist/TrackingChecklist.tsx create mode 100644 gui/src/components/tracking-checklist/TrackingChecklistModal.tsx create mode 100644 gui/src/components/tracking-checklist/TrackingChecklistProvider.tsx create mode 100644 gui/src/hooks/body-parts.ts create mode 100644 gui/src/hooks/bvh.ts create mode 100644 gui/src/hooks/pause-tracking.ts create mode 100644 gui/src/hooks/reset-settings.ts create mode 100644 gui/src/hooks/reset.ts delete mode 100644 gui/src/hooks/status-system.ts create mode 100644 gui/src/hooks/tracking-checklist.ts create mode 100644 server/core/src/main/java/dev/slimevr/NetworkProfileChecker.kt create mode 100644 server/core/src/main/java/dev/slimevr/config/TrackingChecklistConfig.kt create mode 100644 server/core/src/main/java/dev/slimevr/config/VRCConfig.kt delete mode 100644 server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.java create mode 100644 server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.kt create mode 100644 server/core/src/main/java/dev/slimevr/protocol/rpc/trackingchecklist/RPCTrackingChecklistHandler.kt delete mode 100644 server/core/src/main/java/dev/slimevr/reset/ResetHandler.java create mode 100644 server/core/src/main/java/dev/slimevr/reset/ResetHandler.kt delete mode 100644 server/core/src/main/java/dev/slimevr/reset/ResetListener.java create mode 100644 server/core/src/main/java/dev/slimevr/reset/ResetListener.kt create mode 100644 server/core/src/main/java/dev/slimevr/reset/ResetTimer.kt delete mode 100644 server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java create mode 100644 server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.kt create mode 100644 server/core/src/main/java/dev/slimevr/trackingchecklist/TrackingChecklistManager.kt rename server/desktop/src/main/java/dev/slimevr/desktop/{NetworkProfileChecker.kt => DesktopNetworkProfileChecker.kt} (78%) diff --git a/Cargo.lock b/Cargo.lock index 9d58167df..acdd46ade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1273,7 +1273,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.0", + "toml 0.9.2", "vswhom", "winreg 0.55.0", ] @@ -1431,6 +1431,19 @@ dependencies = [ "miniz_oxide 0.8.0", ] +[[package]] +name = "flexi_logger" +version = "0.29.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a5a6882b2e137c4f2664562995865084eb5a00611fba30c582ef10354c4ad8" +dependencies = [ + "chrono", + "log", + "nu-ansi-term", + "regex", + "thiserror 2.0.12", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2770,6 +2783,15 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.59.0", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -4380,6 +4402,7 @@ dependencies = [ "const_format", "dirs-next", "discord-sdk", + "flexi_logger", "glob", "itertools", "libloading 0.8.5", @@ -4759,7 +4782,7 @@ dependencies = [ "serde_json", "tauri-utils", "tauri-winres", - "toml 0.9.0", + "toml 0.9.2", "walkdir", ] @@ -4817,7 +4840,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.0", + "toml 0.9.2", "walkdir", ] @@ -4857,7 +4880,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.12", - "toml 0.9.0", + "toml 0.9.2", "url", ] @@ -5067,7 +5090,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.12", - "toml 0.9.0", + "toml 0.9.2", "url", "urlpattern", "uuid", @@ -5284,9 +5307,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f271e09bde39ab52250160a67e88577e0559ad77e9085de6e9051a2c4353f8f8" +checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac" dependencies = [ "indexmap 2.6.0", "serde", @@ -5294,7 +5317,7 @@ dependencies = [ "toml_datetime 0.7.0", "toml_parser", "toml_writer", - "winnow 0.7.11", + "winnow 0.7.12", ] [[package]] @@ -5348,16 +5371,16 @@ dependencies = [ "serde_spanned 0.6.9", "toml_datetime 0.6.11", "toml_write", - "winnow 0.7.11", + "winnow 0.7.12", ] [[package]] name = "toml_parser" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c1c469eda89749d2230d8156a5969a69ffe0d6d01200581cdc6110674d293e" +checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" dependencies = [ - "winnow 0.7.11", + "winnow 0.7.12", ] [[package]] @@ -5368,9 +5391,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "toml_writer" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b679217f2848de74cabd3e8fc5e6d66f40b7da40f8e1954d92054d9010690fd5" +checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" [[package]] name = "tower-service" @@ -6430,9 +6453,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" dependencies = [ "memchr", ] @@ -6656,7 +6679,7 @@ dependencies = [ "tracing", "uds_windows", "windows-sys 0.59.0", - "winnow 0.7.11", + "winnow 0.7.12", "xdg-home", "zbus_macros 5.4.0", "zbus_names 4.2.0", @@ -6711,7 +6734,7 @@ checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" dependencies = [ "serde", "static_assertions", - "winnow 0.7.11", + "winnow 0.7.12", "zvariant 5.7.0", ] @@ -6819,7 +6842,7 @@ dependencies = [ "endi", "enumflags2", "serde", - "winnow 0.7.11", + "winnow 0.7.12", "zvariant_derive 5.7.0", "zvariant_utils 3.2.1", ] @@ -6871,5 +6894,5 @@ dependencies = [ "quote", "serde", "syn 2.0.87", - "winnow 0.7.11", + "winnow 0.7.12", ] diff --git a/TRADEMARK.md b/TRADEMARK.md index a4332e3a3..919ae7188 100644 --- a/TRADEMARK.md +++ b/TRADEMARK.md @@ -1,33 +1,33 @@ -## SlimeVR is a trademark or a registered trademark of SlimeVR B.V. - -**Usage of SlimeVR software, hardware, or other intellectual property in this or other repositories does not grant you the right to use SlimeVR trademark as your own.** - -The purpose of a trademark is to remove uncertainty for users and customers regarding the product's manufacturer or endorsement. You're not allowed to market your product using SlimeVR name, and your usage of the name should be only factual and descriptive. For example, calling original SlimeVR products SlimeVR or describing compatibility of other products or derivatives. This applies to all products, including software, and hardware including non-official Full-Body Trackers. - -**Here are a few _acceptable_ uses of SlimeVR name when selling unofficial Slime trackers:** -* SlimeVR-compatible trackers -* Unofficial SlimeVR trackers / Non-official SlimeVR trackers -* DIY SlimeVR trackers -* Third-party SlimeVR Trackers -* Custom SlimeVR-compatible trackers -* < Your Brand > Slime Trackers -* Using "SlimeVR" as a search tag - -**_Unacceptable_ uses include, but are not limited to:** -* SlimeVR store -* Buy SlimeVR -* SlimeVR Trackers -* Original SlimeVR -* Official SlimeVR -* SlimeVR BMI270 (or any other IMU model along with SlimeVR name) -* < Your brand > SlimeVR / < your brand > SlimeVR Trackers - -Use of the SlimeVR name that can cause confusion is not allowed in any part of the listing, including, but not limited to: product title, product description, product metadata, site title, site name, site metadata, site texts, social media posts, or other advertisement. - -Also, please ensure you use the correct spelling and capitalization: only **"SlimeVR" is acceptable**. Not "Slimevr", "slimevr", or "Slime VR". You're allowed to use the word "slime" as you wish, it's not a trademark. - -Please understand that we have an obligation to reduce confusion for the customers, and we believe that our usage terms are generous compared to many other companies and products. This applies to all sellers or derivative products, we do not make exceptions. - ---- - +## SlimeVR is a trademark or a registered trademark of SlimeVR B.V. + +**Usage of SlimeVR software, hardware, or other intellectual property in this or other repositories does not grant you the right to use SlimeVR trademark as your own.** + +The purpose of a trademark is to remove uncertainty for users and customers regarding the product's manufacturer or endorsement. You're not allowed to market your product using SlimeVR name, and your usage of the name should be only factual and descriptive. For example, calling original SlimeVR products SlimeVR or describing compatibility of other products or derivatives. This applies to all products, including software, and hardware including non-official Full-Body Trackers. + +**Here are a few _acceptable_ uses of SlimeVR name when selling unofficial Slime trackers:** +* SlimeVR-compatible trackers +* Unofficial SlimeVR trackers / Non-official SlimeVR trackers +* DIY SlimeVR trackers +* Third-party SlimeVR Trackers +* Custom SlimeVR-compatible trackers +* < Your Brand > Slime Trackers +* Using "SlimeVR" as a search tag + +**_Unacceptable_ uses include, but are not limited to:** +* SlimeVR store +* Buy SlimeVR +* SlimeVR Trackers +* Original SlimeVR +* Official SlimeVR +* SlimeVR BMI270 (or any other IMU model along with SlimeVR name) +* < Your brand > SlimeVR / < your brand > SlimeVR Trackers + +Use of the SlimeVR name that can cause confusion is not allowed in any part of the listing, including, but not limited to: product title, product description, product metadata, site title, site name, site metadata, site texts, social media posts, or other advertisement. + +Also, please ensure you use the correct spelling and capitalization: only **"SlimeVR" is acceptable**. Not "Slimevr", "slimevr", or "Slime VR". You're allowed to use the word "slime" as you wish, it's not a trademark. + +Please understand that we have an obligation to reduce confusion for the customers, and we believe that our usage terms are generous compared to many other companies and products. This applies to all sellers or derivative products, we do not make exceptions. + +--- + If you have any questions about SlimeVR trademark or copyrighted materials, you can reach out to us at *tm[at]slimevr.dev*. \ No newline at end of file diff --git a/gui/package.json b/gui/package.json index 7a2f528ea..761c0a15f 100644 --- a/gui/package.json +++ b/gui/package.json @@ -16,15 +16,15 @@ "@sentry/vite-plugin": "^2.22.7", "@tailwindcss/typography": "^0.5.15", "@tanstack/react-query": "^5.48.0", - "@tauri-apps/api": "~2", - "@tauri-apps/plugin-dialog": "~2", - "@tauri-apps/plugin-fs": "~2", - "@tauri-apps/plugin-http": "~2", + "@tauri-apps/api": "^2.0.2", + "@tauri-apps/plugin-dialog": "^2.0.0", + "@tauri-apps/plugin-fs": "2.4.1", + "@tauri-apps/plugin-opener": "^2.4.0", + "@tauri-apps/plugin-http": "^2.5.0", "@tauri-apps/plugin-log": "~2", - "@tauri-apps/plugin-opener": "~2", - "@tauri-apps/plugin-os": "~2", - "@tauri-apps/plugin-shell": "~2", - "@tauri-apps/plugin-store": "~2", + "@tauri-apps/plugin-os": "^2.0.0", + "@tauri-apps/plugin-shell": "^2.3.0", + "@tauri-apps/plugin-store": "^2.4.1", "@tweenjs/tween.js": "^25.0.0", "@twemoji/svg": "^15.0.0", "ajv": "^8.17.1", diff --git a/gui/public/i18n/en/translation.ftl b/gui/public/i18n/en/translation.ftl index c26ef6e2f..8123e8802 100644 --- a/gui/public/i18n/en/translation.ftl +++ b/gui/public/i18n/en/translation.ftl @@ -238,9 +238,9 @@ reset-reset_all_warning_default-v2 = Are you sure you want to do this? reset-full = Full Reset -reset-mounting = Reset Mounting -reset-mounting-feet = Reset Feet Mounting -reset-mounting-fingers = Reset Fingers Mounting +reset-mounting = Mounting Calibration +reset-mounting-feet = Feet Calibration +reset-mounting-fingers = Fingers Calibration reset-yaw = Yaw Reset ## Serial detection stuff @@ -262,6 +262,7 @@ navbar-settings = Settings ## Biovision hierarchy recording bvh-start_recording = Record BVH +bvh-stop_recording = Save BVH recording bvh-recording = Recording... bvh-save_title = Save BVH recording @@ -277,8 +278,8 @@ widget-overlay-is_mirrored_label = Display Overlay as Mirror ## Widget: Drift compensation widget-drift_compensation-clear = Clear drift compensation -## Widget: Clear Reset Mounting -widget-clear_mounting = Clear Reset Mounting +## Widget: Clear Mounting calibration +widget-clear_mounting = Clear mounting calibration ## Widget: Developer settings widget-developer_mode = Developer Mode @@ -455,6 +456,7 @@ mounting_selection_menu-close = Close ## Sidebar settings settings-sidebar-title = Settings settings-sidebar-general = General +settings-sidebar-steamvr = SteamVR settings-sidebar-tracker_mechanics = Tracker mechanics settings-sidebar-stay_aligned = Stay Aligned settings-sidebar-fk_settings = Tracking settings @@ -462,9 +464,12 @@ settings-sidebar-gesture_control = Gesture control settings-sidebar-interface = Interface settings-sidebar-osc_router = OSC router settings-sidebar-osc_trackers = VRChat OSC Trackers +settings-sidebar-osc_vmc = VMC settings-sidebar-utils = Utilities settings-sidebar-serial = Serial console settings-sidebar-appearance = Appearance +settings-sidebar-home = Home Screen +settings-sidebar-checklist = Tracking checklist settings-sidebar-notifications = Notifications settings-sidebar-behavior = Behavior settings-sidebar-firmware-tool = DIY Firmware Tool @@ -654,7 +659,7 @@ settings-general-gesture_control-yawResetTaps = Taps for yaw reset settings-general-gesture_control-fullResetEnabled = Enable tap to full reset settings-general-gesture_control-fullResetDelay = Full reset delay settings-general-gesture_control-fullResetTaps = Taps for full reset -settings-general-gesture_control-mountingResetEnabled = Enable tap to reset mounting +settings-general-gesture_control-mountingResetEnabled = Enable tap to mounting calibration settings-general-gesture_control-mountingResetDelay = Mounting reset delay settings-general-gesture_control-mountingResetTaps = Taps for mounting reset # The number of trackers that can have higher acceleration before a tap is rejected @@ -879,6 +884,16 @@ settings-utils-advanced-open_logs = Logs folder settings-utils-advanced-open_logs-description = Open SlimeVR's logs folder in file explorer, containing the logs of the app settings-utils-advanced-open_logs-label = Open folder +## Home Screen +settings-home-list-layout = Trackers list layout +settings-home-list-layout-desc = Select one of the possible layouts of the home screen +settings-home-list-layout-grid = Grid +settings-home-list-layout-table = Table + +## Tracking Checlist +settings-tracking_checklist-active_steps = Active Steps +settings-tracking_checklist-active_steps-desc = List all the steps that will show in the tracking checklist. You can either disable or enable ignorable steps + ## Setup/onboarding menu onboarding-skip = Skip setup onboarding-continue = Continue @@ -1132,7 +1147,11 @@ onboarding-automatic_mounting-done-description = Your mounting calibration is co onboarding-automatic_mounting-done-restart = Try again onboarding-automatic_mounting-mounting_reset-title = Mounting Reset onboarding-automatic_mounting-mounting_reset-step-0 = 1. Squat in a "skiing" pose with your legs bent, your upper body tilted forwards, and your arms bent. -onboarding-automatic_mounting-mounting_reset-step-1 = 2. Press the "Reset Mounting" button and wait for 3 seconds before the trackers' mounting orientations will reset. +onboarding-automatic_mounting-mounting_reset-step-1 = 2. Press the "Mounting calibration" button and wait for 3 seconds before the trackers' mounting orientations will reset. + +onboarding-automatic_mounting-mounting_reset-feet-step-0 = 1. Stand on your toes with both feet pointing forward. Alternatively you can do it siting on a chair. +onboarding-automatic_mounting-mounting_reset-feet-step-1 = 2. Press the "Feet calibration" button and wait for 3 seconds before the trackers' mounting orientations will reset. + onboarding-automatic_mounting-preparation-title = Preparation onboarding-automatic_mounting-preparation-v2-step-0 = 1. Press the "Full Reset" button. onboarding-automatic_mounting-preparation-v2-step-1 = 2. Stand upright with your arms to your sides. Make sure to look forward. @@ -1305,6 +1324,8 @@ onboarding-stay_aligned-done = Done ## Home home-no_trackers = No trackers detected or assigned +home-settings = Home Page Settings +home-settings-close = Close ## Trackers Still On notification trackers_still_on-modal-title = Trackers still on @@ -1522,3 +1543,58 @@ error_collection_modal-description_v2 = { settings-interface-behavior-error_trac You can change this setting later in the Behavior section of the settings page. error_collection_modal-confirm = I agree error_collection_modal-cancel = I don't want to + + +tracking_checklist = Tracking Checklist +tracking_checklist-settings = Tracking Checklist Settings +tracking_checklist-settings-close = Close +tracking_checklist-status-incomplete = You are not prepared to use SlimeVR! +tracking_checklist-status-partial = {$count -> + [one] You have 1 warning! + *[many] You have {$count} warnings! +} +tracking_checklist-status-complete = You are prepared to use SlimeVR! +tracking_checklist-MOUNTING_CALIBRATION = Perform a mounting calibration +tracking_checklist-FEET_MOUNTING_CALIBRATION = Perform a feet mounting calibration +tracking_checklist-FULL_RESET = Perform a full Reset +tracking_checklist-FULL_RESET-desc = Some Trackers need a reset to be performed +tracking_checklist-STEAMVR_DISCONNECTED = SteamVR not running +tracking_checklist-STEAMVR_DISCONNECTED-desc = SteamVR is not running. Are you using it for vr? +tracking_checklist-STEAMVR_DISCONNECTED-open = Launch SteamVR +tracking_checklist-TRACKERS_REST_CALIBRATION = Calibrate your trackers +tracking_checklist-TRACKERS_REST_CALIBRATION-desc = You didn't perform tracker calibration. Please let your Slimes (highlighted in yellow) rest on a stable surface for a few secconds. +tracking_checklist-TRACKER_ERROR = Trackers with Errors +tracking_checklist-TRACKER_ERROR-desc = Some of your trackers have an error. Please restart the tracker. +tracking_checklist-VRCHAT_SETTINGS = Configure VRChat settings +tracking_checklist-VRCHAT_SETTINGS-desc = You have misconfigured VRchat Settings! This can impact your tracking experience. +tracking_checklist-VRCHAT_SETTINGS-open = Go to VRChat Warnings +tracking_checklist-UNASSIGNED_HMD = VR Headset not assigned to Head +tracking_checklist-UNASSIGNED_HMD-desc = The VR headset should be assigned as a head tracker. +tracking_checklist-NETWORK_PROFILE_PUBLIC = Change your network profile +tracking_checklist-NETWORK_PROFILE_PUBLIC-desc = {$count -> + [one] Your network profile is currently set to Public ({$adapters}). + This is not recommended for SlimeVR to function properly. + See how to fix it here. + *[many] Some of your network adapters are set to public: + {$adapters} + This is not recommended for SlimeVR to function properly. + See how to fix it here. +} +tracking_checklist-NETWORK_PROFILE_PUBLIC-open = Open Control Panel +tracking_checklist-STAY_ALIGNED_CONFIGURED = Configure Stay Aligned +tracking_checklist-STAY_ALIGNED_CONFIGURED-desc = Record the Stay Aligned poses for an improved imu drift +tracking_checklist-STAY_ALIGNED_CONFIGURED-open = Open Stay Aligned Wizard + +tracking_checklist-ignore = Ignore + +preview-mocap_mode_soon = Mocap Mode (Soon™) +preview-disable_render = Disable rendering +preview-disabled_render = Rendering disabled + +toolbar-mounting_calibration = Mounting Calibration +toolbar-mounting_calibration-default = Body +toolbar-mounting_calibration-feet = Feet +toolbar-mounting_calibration-fingers = Fingers +toolbar-drift_reset = Drift Reset +toolbar-assigned_trackers = {$count} trackers assigned +toolbar-unassigned_trackers = {$count} trackers unassigned diff --git a/gui/public/images/mounting/MountingFeets.webp b/gui/public/images/mounting/MountingFeets.webp new file mode 100644 index 0000000000000000000000000000000000000000..e56c6fc138782175cad8c06dd3c71532fe0bf708 GIT binary patch literal 30678 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 N|9AA&OW>c^{|CXwxrYD% literal 0 HcmV?d00001 diff --git a/gui/public/images/mounting/MountingFeetsSide.webp b/gui/public/images/mounting/MountingFeetsSide.webp new file mode 100644 index 0000000000000000000000000000000000000000..3b1240e065fe9b586154e279fe46b8f108c74607 GIT binary patch literal 52158 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�=8=??EVe<^8-v^~;-R`dmgU~;O{AH| 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 E0g}zAPXGV_ literal 0 HcmV?d00001 diff --git a/gui/public/sounds/full-reset/full-click-1.ogg b/gui/public/sounds/full-reset/full-click-1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4d392fa6eb6d0ce5581fe0864fb57605c9221006 GIT binary patch literal 6407 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 UZ)3!J>-Ct3oqwV9Wma?l3&b*)4gdfE literal 0 HcmV?d00001 diff --git a/gui/public/sounds/full-reset/full-click-2.ogg b/gui/public/sounds/full-reset/full-click-2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..b7f7794e7120c1f2a5a3e9a9f6adf8bbb6eacc79 GIT binary patch literal 6330 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 Wq%A~g+@0vPhw$KkbAtzv!oL9i8)yOm literal 0 HcmV?d00001 diff --git a/gui/public/sounds/full-reset/full-click-3.ogg b/gui/public/sounds/full-reset/full-click-3.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1a53f97a4c651c4a9c55e31081eb2c30ae04e5b9 GIT binary patch literal 6278 zcmbU_2{@Ep+mA{1G}h>scWjxlWrP}A3}YEvhDo*-OV(sx5=|LGk{Dhl$u=}XA!~0D zS+eii6Cs4RB$ZeF=NZ-ee&2sx-*;XAne&`E_c`}D&$;*eJl39`wh#jPQM6??JF%sZ zDVro)*r^~_?_hWcVN?b|-$8+v5Ul@tHfwn0uL7@R1JL?t@^)kbjQMv7+_Jfm5|}^i z9pI&69ps7f^L9PN+8$+wQd7lhsA5$$Q0U34)L#|D0q_ODL$ETmHX@L8jV(~NA))Tx zr{D=YGdl}{F5ELASdj?2oSFhy$~eP;mAt9)mOXn`F) z7r4EZ+S1P~JP-=OFN^p##5KYconDSUPKL89GN z`37dzRh9((`oyPzEHPc#ZF$)P^x!@-K00Hw7b$p^vz$2u#>8iH_}j&g13d2`Iw$kV zVX)R=fIf4hK^XKBX;sTmVK?UjCAcYT?bBMg-HJ5i!vZZ<(g0d~sb(fOxB_SD%cvQ1RAkUd zL=0ooqJU6Q?x_YG;w&SH&kE|olmM&vr{MmS?HAZJ_>bEEUcyFD4%9(4W!t^FWIM8b z*hz=qL!Z^fxjYViH6HzH{L;}K@&B$^zbpp=Mnh%UB+WG$+mRD%h3DQB@K4JL6z;ep z@#u=Id6lf?kW%jlb?X)NK_P;Tx}~j%%b-Z;u&9TvrpvH~$1vGrG|b~kt%p-xv_tI= zgV{8jSL31oupHP#q;V-zrfKYdTTUK2WpaOtj9HqjL)z}hOwU9*Gdp*VS-|semgALF zl9g1FkTjc+f=*jEHwVt`pa@mf@DDjmO}`V{fFf=VnF&Wq_NNw2c5Jxk?NMhQb}pWiPHUhEptyKS=f^EOMifLc{&Ts zMVBf7H(5H@=>Dwsc=r#mc)ro^Nv+f~VD_@swwCl0boE~K!~!2YS*~|4`6tN4lXY!F zT#Dx!ErvrIDwGT}bq4{+`~`xundX+1g0oDcCIAUTeCdUI`d@j{S?L%ed- zFEGu;Azo<<1PxdWXC@ZB6C{j#&?|VyM=fk?6AKiDet;t6(M)EsvMt$Rrm>38L6l6c z%`Wx(3BvJ{RVX(~Yc0th**;xr;~5^ERX;!`0BZmUK@>Jlhyn?9=>rzBQP2={Ve)V$ zU|UC}lBJMkikk!dM3Su8uui{vzC*4jeL&sDj_gGToP#4D#3KRz{03-;CGub;&^LuB zt$|AB0DZ*>m{R)G;mp~@0yGER&}F9rBziT%Lmi5bX?lSPjga_^9& z{8T6kHUZm~Wy6EV$f*+zxaDX(cyDGA&CImCW=svk1P)7%aVOKUJFjTW(Knk4nsNxb zy@eAzy!kA;Bq8X0GAS81E1_YGY0n8x*;y#;)`v66Aa&tpQAIR`wwz#o5>XuX!)OM; z%L%5DSOJ~Lq=7LBh8+=rDI^6suuL9;ZZxw&sAl6Uz1+sVrD6D5O($-fkM03Xa3Ca@?c2vgsp$ok z%|KiTC=x__JQ2>ykWvgWw;t?;R1%z|*(G7yCEWPI(Lv6}DFrr|&51?A`}G-cT?M@5x*5)sWP8X;Z5QbAw?)Fxqzsi`C) zv*u7THlJz-25ViDF98&wJ0fm=N^%*n7J;++VroR)$^aLf&6x}_U!``jsVE=i_QP&~ zrt3~Vm||yMNHsD5q7ZKf#%B~&w+v3O_|O0{S(p!5Kwn@*GGmCr%7voB`5=u5NDJ;W z;FJO&8rC{i55&BKr1`91emMHUc#M&sD*y<@0a&#;L8Xy?_5dD8h<~o22?A2$z?d9W zkjN!hL?iLQD=-Wy2@euypfwEIK_Vuf28ajxgGaMKIXK?S!7*PB%z_CT5uFd?F=+5$ z25W*uw{`M5Lr+kjsa{4=oift1N6&^h|z`Rag9nl%@Py_vnpnYmIBOKsEoJL;$qwx@!c*( zr8)XA*Cf?$pc!eTW!;*CBp*!s%P4cX>LEwpd$TXi6)^2jPcP%@(nuD{qR=tH*AS)t zSnE8OJi+Z8U;zSh1;%5@hd14%@z>4f?>i2b4War?8%x{>R(cX8DkZ zC)_(3c0F&524plwT;(3;i#(s$dJK*UkQxL%v?Uy+tWWJ>M{GTK47eeF zq+k(5X+aov1PCBg%{$SmXbGV{vyyF)K2mzGk+dt;)Zzw5QqmlBEbyGvZ;+b0=8%d? zUN^KOByjv3@;s7?66HLokKnhef1S8b=QW4?Tj2~XaMuHc3yJ`tSCf+9bz)|}mX4l2 z-pJULXkm4bWCvmdC`d>Tg3?4#()4Ux3jgKpsmLn=X@coOG+~g%=(BFS5KC#=2q^x7DgsKNO}9BK6mh_Q*|oz zLHpln-04&XD$~Xj^zBy0Nh?_A2A;`OzBdwbS>vzZ&|oHWvKF zJ%q0J7WZf_s>$QP$y57Q8cIrDt=0|yk@#ZQ^GWTaxuvUz5bq$~i=>a1yIS7`Q>J;G zxs*31xfMDs{c8*dqMx-(`*ghd98rsvIN-7FIwNu~_4_qc#c=fzV;=2GCocCdj6VNe zh;v8TwV|gQ1f>sJi0z2)iKPwW<#7i&5i><=70GM@dLhC6!l56!#7 zg1k+hEo$71{q~`PXVwC`)&=PfukOwMetkXdtKrPz+6NPoyU!}x=+^1a#?p$fTXVy8 zj!V3}T~T#mv}DSlY9rj&LD%YWVsBsesg3L3qFxeA6xe8N<_A$nS_2dkwryE5I``L$ z#KL2fjy1KnN;|*2yjr{%Ij-CKdGY;`g`L@MmnENH@6nAZ*Gn2va?I(ly&a2qoOU8h zWN56_=;1>`!n5bWt4qs4Uy4g)s}2=ZeDd=2?7OJE@F=;qPO}GjePNARcl%`h*>8J_ z`Y%>5eQ4@0*w@uoy|y@U^X7e~#k~W%pRMKC&WIcp(Y+Krw`JSPch_%F)YuGxck87_ zGc4w0*i-DyXNP4R2S2W^_g{W4Fze}Teb1@){sH@qzuwho>3nsV-Y)nVvB)5g;R3ms z1H-MuhSach=kz?C?9tZVGOlR-?;D&umyQI^H3a;oU7_sjHDrHJ{ON_byi+QjRet!d zM*}|Jn`s}vS6%JfD*9V>g`gicyo!A>+J1TR;ip!A-^e)jy0wlTBdU;n8fW$Iq|kFI zI-WgBZnyNlUY~V~@2Mb{kFS7~a8TId*8Q)+%ktdLR$>qLO87gk2t8oS5Oj=u`iJUXYBJQlNWUu|6OUlWSqPpz~&{E98E4L-PZ_M0!Y zJQnlytLm+l`_5Plj`X$!`cZ_)(=9CtqxwWTy@y>0i`$5({yiz`SIxvM5~>e8%K zndZEVq202{kGi8en86nuaX_N-7U`n)j4Ap!_riqK3R)+ue8F3?rS(vM?xTSY>b)NXK>FCnSXVZ!f zN4_o|{aALuFEHfWfEHF@#RrZCy<>ZZ!9C?Ov@{RK6`FOR>L(=#ZH`7_^7D(#64%`V@Hk zM{M8X$}T?&H>ngHk4h}tG1rtj{rXH@eOb|TgOPDTgP`O){TneD)J{KrF8f38*^)Z4 zlCxDn(hZr5w^Z$1)Wb<&Il#T?U~!i&FCwqeMAPGmx8)A&e(R3H?YjFOA+Mt^Ue8r6 zj_5;-<&?Yo`gT8WDD2@mcFs!s`O|s!`)Jc-QR}a=84A2YC;Lis7Z&y`S63g2bnbAk z6Z88Laq(vO&O`U~%8oA{eT#`{I;FBj+CwcP=GB?c?p$uXUKzHU7o&A1dt1KGg}spW z&XAdMbdJTXzfH&P7i4(A}D@`&JMq_ zkk4M2S!ahPW+pzI`L@-`qsZ^m;9dl3s=D7l;azF-p%&-arRNfTqWTIb2y%k%la>1S zG|9z@^xre$@Du4?={{w4ye)Xo6*j8-?JeS~2uSMhI}XI5B!+j-k>$Fu^_;52AD^4$ z_5MUal-M0mj7C|%byFVW_GH8O6*l|UuYY~yb>vaZjrt#Peba4Ws47Rcf7vKgl_rPx zbm>3SLct5z@zo^RuF8mlZ@ag)Ku1J!B(0m4S_D7i%tyBH^OGOUz5lqN^6}jDy(af2 zCiG1?v{4ES)>mgBXt+@FcS@J2;bT?K<9Q$pwedjb@%Q!qY%-9Zh_iqA0a3htL~iKF zmLnIK6G3;^E0K*YD`ka}e`+Dq9`JYK!Dp0Tg`!4f@LeuhR@hBMLt-s$GS@3iR3t@o zy4#wXS{7<|U7MRg{(zvU+yCmx#rpe6M zN+sZAk$=Wf4FxPJE9Wv7*wwdM&Xc==v7ahD+XmQ%}>WIMlio#8wmlSk5Pmo*nxLF|0mfY{+);seE!<B(it*;(1RSlL*)$Z408{r;2bP{96=!HY9oUv1Vp4M{P9%p3Zp=Z z079_%Ol;pnk)L9ZPG6AWi_YFd{z;yFGbdV+Z?hmfjBks!YD5%+scKACo^3+YxU?BX z&(mRucO&JW0_}bu z(jlV?F4riBgqpg72AG`mw46<+oSmkey|fejb?dye>-=?p`RkqezaB5j2FCdD|A`UpJpxdW+D0o6e9p8cPJr8i+WBMl`WHJW>spLTx0RI#-_i5vA+WI zz6;18NO!9NGAxtw{y*7FJI?g~okc8q=m8NBm)&;6-FB1`s+8UKjHve*?g2oWil{Pn z+H*=daCSQgfLY2>yf;RE@K_$}Un1O*9RNhwh&%0wdqHfdGL74FX*mc^IVenlsJO$( z|2=)Y=NE7z6scx$R?r6=5pVC&0tKff%zPk*`S(p=hrrBL@}!ZZqe0$BNoyH}c**16 zgVd90>I)N+?klEaV;W>W6onj20sYDwW3*haLG@~DgGE!fX; zED5!6`ZYLKdn9SSpdJsb1;r%ORM)Hjo$nvEDAZ3G`p&xqjtKglY+aA02i7i3QuYSX z?%MuO_7MT;_VyQHSE?_$R~U*B9z`BSG^u0wqv#B_9=aUTFJY3hg`bpFiD+^ieeZWp z4gh}G_gwsManH(sxi}{(n7)s;a)7;`@vbOtAL83CZ^stHWCOXFkqhMFFV*X54yC-( z*16S_It;lnsDymEqs$3JQOd9Hf|96Q2pH6Tp zjB|pBjRgQAP!-a3Ciy8xy;79jk+AF{M=e2Fqw^z-{uQ#BAljp%OmBiov?|j3lPv)I z$jCS!Pjn#UAlD)E6-!s0swnOE2cX(R0#pD1MdrB-rOY8`mh>^@;EP~^$52Xlf$$BP zw4NhZQa}dJjdVC#JaXee05nXHN8pD*G?Rh>0m=gbLMYuxWex?RR^2!i@F;?#@`9cZ zb10;l1Vg?j@N+mUgB(o&W zLC&BoD^U%qK@N?7!9r0DK{ZFcyv+vrai{uHMzJ`-Q4lQr4+ySJIxW8l9BY|mi6f!r zZzcO*poV{;``@vNdE54;+5t=+{{f@)v;!Cs0boRaJT53}2S;McG^rG0YC>MECMb&m z_a6{nVPBTv$;Z#xA zut)+icW3zkbkIFOcsCOBnmFT*2}Gm;XuBPw9N7Ix92BMKmDh0_L0Pn*Stz0hXB@s4 zuyJ*bxLnILn&2#pq@tpt5zfEOAUlB*-*qi2YG4NG2eKB}ruQUi-R-XDRzoRyF6Z3#NkMI=@kp{urY_un&(0>^U$`;7hnV^C$N=L;h`wERJ23^#$ zFegSvx}ipiGE;F0s!TRsNe@9^L}5X0N@*{8p^vt%q2}GsWSNsw~l+9;VF&`=vO8ZeBGyqW01_8+1BqImWBz@5zYNG);2mm2*cLj(z`B6?LnK4ckJP8m{a#44PP~p;u zHMP7$4u}~LEg)*|7ZY8pyUm9y6xu zk8M2kiZ(a5fUS!>CQ8*>#W?g8EmiJhmNf+k%9cn>iQa)aA*w~{vQ{OXgt_X4F(Ak$ zTj(GQg2pkbXE8b<-zI5u9oa!|t7MRO!vyrZbT9xBiw^+6U;fs~FFNa68%Qn$zzwwa zqOx~h88$^Oq45CQ=Lpq1Crv$=t&7^9UqC( z7pgztMa^`;mX#@VeZ)sc0opJ6P7p-PjET`sry}y}byp*qq8Aql@==s0TgSJ3J(S{Bp-gGP#6z%th{Z=MTon zf?IPKdWA{>g0y#BcV7c-p0eszg2SUb>vz{L_vgPOKoBGch^oI2{9;u9t%3bOhxp$S zF*x8>{J}OVKOETyR5>xK=yxONa{W|ALB|>7n%o#=S-Q*^aPuJlh|=DJRCo5C>dxj< zflt8)F|xFocl~l>?iyq7AE?TrfiQ@(yC$&mx4dtn%LQKqHr_Yk$liJAs1v6d(Xbpzw%cic0_8<9|*z|8vG+ zg8)!aF8~nDa)!z(tL(bM=%zoP+Grd*%uIT6)dyC^M_zFKG@|;Ii9frDY(q}Lt^oz1$eE2H#RZzWY7wsD5`Xux7IKtT9=e7@7E2nc^q#cfpgGXQs|;=8Bxflh|x z5C|kSIwm3{@e6zfo(rdd1MnwsL1k4X1%FR?1Y8R2xB4K+aL<8xfCZAJv1{*_)jchN za78VmR^IsOoy-FPId0zU#~x`xm`^o%+^!RA6KA z(XPC3cDtVQLI2V*N9yLWT5*lJ_wC6^S#kB`<>hw15)Ci_gxoOy;JA=F9uh)*tz#HV z%xWNBMJ~LDD*bqg(0yv%Z&YJp_}5viFpMi0wr$Sd>fO*9hNT;t+nPS;QCv+fCQKuB z_yc-V$^xqt@w1odq*CX8wcKG=-o2A^=DjvrE374?9lx^j(X+0$B4$C3#S!Cncfr=y zB+sSUuZx9Oo1dOeveiju>&7HP&qvW-5N!wPMuHia1i4#6=~DH2c2ZB3#ml5o6Lk`C0& zOCC>(Qa%o?#Tg&R7u9V#i#EI_mOCc=T0iF&?z6x=^X)5xhyKQ`eA)bi=Z%E+7ra$R zb+4lxPj+19TBDD8olk{ei{g*2kucCHI|}h_qiZn`;_%oszpTH^Bu^=BFX~SyNv*Ix z3aWkM)mi^O{W$lAD6tTBW)*rsd^N?g9=aYYh#H;#Ig^z(=f!|moXe!(YTG&cbKdwpA@O)O@Pi^jWy_Y(DM!hW$7qwQ7sU$8sbp3>HOmEr_V}!9wBo;oU#*o7qy+U5huYCBHgvw-4QV3JUw^ zhY)(rPTqLJs$aaV^V-I5gb+Emw%-mq$6Rz`u?ZgO^P4&icO30TT4!zT$;ePlUGNK+ zIHTnWplY=sYn|_$;a{e}4L+qEEI;>etL8=D{4C(ZtW~$^G0Fedo#rP~wF&$k3AIFF zMsIEYR1N!re6mi&R2m*>;C7Y9H5!%mu&uqQqFM{mA28TG{PRebSnf zfmW%5gvqO{y3LtXxK`JwezWS}bp{!d5kK{r2)`& z%qQmP=FNFMzAyJX_4F+;V!-o_tIsy?_uBy6t0OyF_HP}q7bT1igB^Z1QCf~0=6N)t z3l#DRtZWEvhnI9keKOWg7VBE4NCo6F$<8CW#bW|o*>C#sq|as!f6o=p3iHouGG zQZeKh;CrX_Sb*SqI;)^zu?^@RndsneAwnlWw7FCFG-*mvJtR?pEabk{0;;$8Q? zVw@hw)s_v}R^R*D^7J%cD4MlNc_|T*e%K@hx;C@yI@Q1z{Z+rP$pmIS;I%i-yO7qX zYqB4-dKjC2*;=M~Y4>EodvoWa|EgDCPpOE?6%i{1gYk1)eM9JR>ZkBZ1~?2}B}lLj zC$SUQ>kh|~qN|ujzAAXdDe4;29O*i&^|7bkDhGwpTkVa(LSS*|_S#VeH<9%?+1QI! zN>c5&x_U{1Z<*FBOE$BQg6rcbhlyLRO0Ojd1cIJu;j^nsAC(Dsbg# zr%Ga{e&-J?sOw8|`}pX4yGe>j6YsYuQXx1k-OkN82>IY3K%a5|XdfVH`9C}O*+^Qa z^W@&(M8e+(EbDNx za_P#hi}XFl=~a8Zqr(MEUn1`4E4gmB1)JPA%t~pxgDBGMs=fC02U@|ZlXA^?)SOl- zqX2dKutq(ZH@gI~bdkigeWvGB8gJvHrF#0{r;~-_O0{`iR-Yh;ss!Ig!?W`a4Vt%W zb{w&x8kphfyl0(St%nnGl6^))SFD36@EhL9&XXv})n$HLXH#|a>%*YeS5&b78 z-X)Pne7dO$GVJze8M)r|UiHEX?``UpnmHWK&!WSgqu=MYw-n@yNdx)BHPY8=jzLE(nD z)B#sS%;?R=q^U@T$opvlBZZXp2vBH579kSly;q<*mY&a}`6To`U)|OZx=JShXZ%;2 z{Ph7(ZEx!}hLSC{mc3SPeEeJR+SD_>y%hkQ+&EOEM!C4LR?bKi+QZk+sFEj&aB+n% zxvBEb5SI-r*<;K4p-%zu)CQ$Hc@MsW!_S6jU~T5thOyvIJQrDVwZg-}Md+c%`bwA) zR}`e&^~l@7_j#@(B^l(+i;ti)#|=2z-!|T@7*!-- zM;!`IFG4I-)(3_R$`2vHd_c$b!cQCIoi&C?1Y60Ew*hm~EDmmsoF*bD;m@f?^ETSe zPymmumsn|s6%DW1$>uqU9=_8D2oB~{k@k6 zs@Z=0NpyQV-HYUHKv(zllNB}&(Knr7B!KWoV0p;!CO2@becF8sAKqvvt#>T0a(>U; zn)rEHr|7n|`wC~2X3o}n07#&lcA4BTF2O|uy}QM+F%crDvxvl9jN}bq{d6Bz1_1Ie zihwpDsHWqf`v}m1}`C400uJoPSXaE!1x4SW&q4McFGI3_{)P>9YzQ*lpYke`xNqM_)YR z@NxTuFExS$3=G8TGw1!t$_py2en^)7SwLR6X@0Dy(60hX2tb62_q7(FPET_O_eg)K zlm%%EmDfzcKbpIL_kL27u%qFNVK=_47{W9KSbf^AC1VCa4v2h15ZSFmegO8;j{p{d z-?9k6;zkjGOwYcUhX4@Zt53jHYbVBbZh2^ADtw90%gW1^#+y^JdV!|r97pBPH4;8Q zhX8xO(~owNX8t^$TkmUQK;?nwA(B~Sg6IuIoxf)jDSq8&1p zTjtr5tE6##tQL|n1RzV;!wQ?I>}F(3zXFMi=JO?q!)KCbZd;tcGz$kc$9#4Uu}F2N z-_g@}|8e!b;M1s8`zrqGW_+wT*40Q!+Ke$*44bv|d#vtv44|M-nRBVN3uY@oT#f)3 z-oMXF5on{;-OGB?oe>-QQlj;j%l3ig!L5&yv(xM1>atiR?PeahdY|%>xSuMD$EycE zA?fU`=;n?adcG~!QolLA!Hk#kBBC(7^Qt*P5?_N+964=70Ez(BIx93k_=O|%K~C&# zni|#O8`|>4Hsm(cCNwAbu&u|cFog=S8JZW|cDL<1_<0SwP{|F~hykKWpaMj?-@&)~ zxsaH5zw;LIMGoEXn~R#W{_nb(KHjsg4oUvzxW3UbN<|g|*0R45QqWG|!b*+T_CZcG zWjL2`xK+pGGcx7bCHaE{Y3f_!)8A;l2cFF zQ!zHrtl`{FG~{PF@^G!q3mPB=%^#kA6YW~m`S#=~ZZN#{x2QL6Wa!9;YD+=qYg?nG zLw!2dpVr-IN{tT{ept~nY`lS0N;Wsff5jWu(4N=5QM#HKC$|_2e&-co5{v1F)(kJ} zexZ+v!>NH50#BdX>%GpF5YOXZCCU5qu|NwMd+?>Lyo`?bpV&$jtboh3Zg0JoE5xrd zjyJ=lECNPK9AC%zVr@9D+7v6vs?bJ-W!b!rd&5Mb+CQ>Tqj17#7H9Fk&hc|Srbq>8-(-@YSx8frJ8u!U}!#^EaTlarHmSj93 zZ)xuO^!`T(#ug)etnw8#m+KH`b$dk3IwzLx5gh(|;w8+-^!@SZ%#*^iMw7{;cF`m}ugF@#NzW#&>EKX1eS->3$xg4^ zSuPHPcqGF#_*0HW3Uh*CkVq1a)xh4z94^Y^ZAw^xqDP&a7sMS^3w{J zq90$IG)cav`!xD)O zon8ws90f#(fak({-A_gM5WSiog~CX_1c*Nl6+EpzC0pU5MY+=kKwCnTPrH7l79Qtm zsr)yW1s98E4n}4visV!+SGys(kd4OEc$E2^>S3Xyt6m%&iIdaDQ2QwFDQi+w z$Ee7D8Ew83q2};|k-cbjnqsD;YDWXmlz60^^+eVZ^^>=3f9H9l)k+$;m31)ooS9bJh|WSlYXX> z++9)POSN6^l;nEJ4YR=|s_<$o^NqEqc0mU=`Y$cMm6uyhqQ0l$YNv6J@}NEnJo^xK z>1;bFy+dJUB&Z)8-XtKhJ*W990QqEdb1&yH{VQpDfH|Tk-=qd3X=>KEo@Hf->Ksdd z0nn$x{L{MW^Wrkic=rpuF=OyHMA-k27naf!Zo(3csQR#Iq^RZ=xbT$Ssaa^X7NIWY zR4fEa#@dJqjI6>YYY@)~2$4kKD3; zO-T`i`*1~Dn*1Pka9_lp0`ZoeQ#jMZaM4o>vnB=ilP4?DKUc^;k|+*Ie?7agt?`ad zHs;Tfj8<8swhsUC6YcSZdKUgre*`F)N-pU+1`R+H#BkQ@C8E)nF2fpIHA zV*rSFf9v66od? zeDtB7Cy;;-D@`b27Qd=O!E6(5mlYTG(A{9JVNg{eC}Kao*s+^7qulYiIf!An0HCEzZw_J6gC^r+dgmO_7{bzd&I}?y1J;y!F^c(+v#lJ5wc-|0 z8V~X`-h0i87M1*NaRBy%oSdu4gF*uxipZ0KUGbS`TE|V*vy*O44{utz2;3-Lpjwm~~~YvMOgZfr{!n z53$>1#*RGg0uevTVbBiv7am^rca&IiqgMlC0I>gp+-4!C(^(ufJU{5d{QK_jgP`C)g-t`Dh}O3;<^#+oi!h@CYj%Zd3yE^kKh)xj^?zD~Jb_DGYX zu{;qiPX39$uAxPJmGw=Gj0%djZ{^jdig7(aF=j*r2?6T)JMyrKJwRGe&j>5JaEO-s2W1r}QO| zQJOzIW}WF2xX4U(+f}xa@G@=fH>)C~i&X8G3|?+#p~lj*7z*L|O< z)zQo=T8Tx*@A1WnfE{ifrNR+P_&Q#fHOe+~@TKkSI*g}leuWG2v&Ic^q`DhX*sCiv z@nedp7^ticr=uu?>;|O+hQwrYt*4p1H^V(qkadvpP>=x;eUfxk@azQuyNW)o<^gVM zxj)zT2B+3$7tW$OpMP7w#%-U8ekDFbvQn9@A284wDKbKNV}r&{lMjyhHP2_s6oQ!O z3-mydfHdlXAb89O3jEsT5Y3k(!}k_`&fd4Imp8q;{{s7YQr#0GvxLlx%Nh9o4*aTe z+J4J=ME)!O3`3jMIph!(jPPC#)1U%vtm!w{gw!Yy*7yZ-Ti}aAs|F+n0!^@We320X zmHr#0{82&OqKVAiIRDL|tn>8uO^z3Ct5#8~hkO94HB~^_)cjbw#cl-iG%q&mceuG^ z@%T-+hUY@{3E`%!EY=z>y~eaqt09@Z+I(I^C@tV!*4dl@K=+vwoq8xs&kl-Iu+BvMZ6 zgr%qr0o{zyQ29Ras-{M$4dRW0`DeYbRpsW3&!auyfiD|5)~%8i5wq~_q%TGS35rr7 zV{}E2u&Em=bk67W8vjae#R>L_a+g@?`FFBX>Q8~)E#-!YQ2t7jrz7%Zm+zq{eZUv5 z!&(tf#0MVhZ-5vGQ0p$vN{RM2hTP=#OY+Tu(%6^5eg|`hr{^?S-UIp=?t*7n7ZY0T zaR?bwI^sVgZeU{l8;q5L`8VFc<}ZDr1N~ke_EXm%*T_N5CFR13ZRs}83PkCC%q6JtX8 zPC>uQLY%$b-Ek^0rof3Ppr?_WpcFi9orYhzFH+eQW(nL9xap&h%9r z34lG|?I8`&==Syj1UzW8K-<@%trRRq9zY0XU<8iWE$K9t-abhI^g#)(eZp{Rvp8&& z%rrlL&u07)Z23m;(Gy^CO-WeLfGj!u%r)_ks#;kcc)hUm26FX1I2sL*zb#++^g{*M zdy0wv>ryE_0`c}u2|x>JEAg4oL6l}#MEOYhH*yZeW}go>n>`F$a>Mxe_E7g4V*)qo z@#mYsY&U8Jg3n5amn@tXbNsI>6q;D9czdg_e#yN1=0-2QK}^}VjQn_gv&%}tK}~xk zT~B-Ha&v|a@!?XZ%5HpC0JqPECatJcl5L>9g>lUM3F2Oth1f1 z786C}F|dft!{`towY_dT)i{`+H|kQ=g2HkH(x>K^T9yNePgB@(RmlV8^rfVRQ> z1+U|3W}G&@OF?^E3^m14V@Cb5`CDfaVDZ4C`5UnF!5C6D#sciO5h4MV+n)1V2;%03 zQCCjeZ3)ja>~6H3j9DY@r5;H}0kxKYWo{#+s1qYb%Q;U0OO@?dp5dC0nP}`}@52f; z3DdYzL!8`OYd(k>|FG?@>%|520|qf<%4FA1sgynIBa=U|M~Q{+qptT{9CHN(GZXz&ji)^X z1(mP9lHmHnaA87=E+bvCKRvlfN1eF)?X+Js%+L2aD9xQR_pi7$dP>JPHS7s+d+@rt zoVgTJPz%qU#e2j#E{Jy!zOH&$hnw%I;G>rdcL+j^gp>rH5%P8AVR^ii?LV5|zWoU`VLCW9emwc!2V&^{PFQ3(5`{sN`%#ibtzKTQw}Z@JYU(U^kQm8|2It^VoBN{m8z24TiewL;4`-l#AY?1=xkH0hEQVa2G$Ugx} zz$g55S#8nvPrHDy^6(9kvk0uXwf^74Qi3WhMzaQ&E!XuZ8-nq8Q&*k>K7=P!)6)v2 zK5nE5CCD&%1t(Ho{-1+^SGlm*W^ZEp?1DxCIBY=K*c!lFkmBzbg*3V=UqA<*%tNH{ z2V{f*@Ab-k;TJ6;u;yB)$*wz$!%4g_Cu$$gGzBzT4fF&ML;qYY90@nfU%IuV%W=~o z->d*o29u+D!Ns@ofXLB1y#y`D2a=}%4M1)u$hX7{2#xCqzK;QZH42+e=5j#44&$&! zq6kStK}8DQ`eFE)imURZv0jFV$qdB>boP~}JlpFKjT>J&!*M8b`+Y0sTFU54stZrL0kUwTi@L6a;(}JrbgV4jPM!b3Ni%cHBFzHoAr;8-)s6kqKTj)hR&qlsG_ zXb{*N4#Z|(alp-&XTJqb#|vJ}J98ONr+!EJAY=#uz8o}dd>H=j`y+PGC7JFe4%%K* zH5K$olVtDxEog%=spvaMri$8-Th=Or;3RIu&5brCYOcicS}l-6xb|vE;H~7CYH-pg z4{nhv44r5OE+7uxv+Z#ns$|}2)_Y(Fv|(8&YK9{L*Zb=25a4BiLbp96`x6dy`?_*z zSHzeW;VEZ*+L~7xWHdkqL_hd*k-LPgrjjg&tmA0TL#Y2tAgk5J;r+RQN91*TYJA!2 zr5kjkx+FhMdQC!cwY~Xj+k|O4QNKL-zyQ4SRW3O$@uCl^&-sK?lgq3g~ z;<&V2ieb%HfEbWBE%4al3!a*=#|<-p#11i;o$W1KDCqBwjd6brYacClWE!PIUw}`J z4JR2Ik_bOVX~OQ|Eqbg+Rwj+}AnH$X(pb$&lB`}(pY?c2S^b|JGehNpijlRD1JvS* zIlArRm)7&XfA}ssIMBpvChALVv3mGX$2@Q3yx{FA>%e2$Ja6g25n_mb*UBiIr1jy% z0*@qQRlQ5?JG}C|?2ll3`PQny>kfHB;Ey@Wf}oGyhLvwjqeo{0*|y6S()ek6m+3MI z09`TAS^=!^&QVMbnjP9L%F%(g39J1fOX$Y?xF#%gz)SBKWh6R;=JCDCX~X>C-J3aY z=I&01Z~ML=v1Fp(zUP^XWt5R}qWhWFhSV|S=DTwVmp*}*;uw>shdC@~E`PE=VDgPK zWlW#3U!+{DOU$$U)LeK~v_L6t&4~L_Qwp?hk|C9>KVS5A$c6f_xO7BOL7!x*pKs|( zjPFGEoR1|yRFQI*mcLXJJKKvameCU%!m_L2twgnNzoVX4%;)v#vf z4TkMrZRx{G*P{*m(faE{Ag8%PWj)XT3@#ZLI(P6R@|5E~lIx_WeC5(?yK~r}Xtcq2 zRb}Qf+vsz3sbn;K%%8teyCX355E8KybjxY?ko`w{i}TQ$9HPY1$xSE|6eDG~L%;QG z{uOyotFH71{wo(VhXtfaLv2IkcY)0o@})gysxJ>d5239KiIpgzX1aOJWhV8T>_aRT zS3VT%LrA;S7U7kD9y_L)x>5v87KWHd!-rLt3DkW|f1zmRfA6O?33QjxzP8avZ4*fM z*l`gaj{P>0@qHuI2p!Pr}fC7*&)HVaP z%K7$e2={UEw!P2AUKicHG-&~lhr_*E?dMW7K9?bLEtlU%XhtVCrMJcVrPiBudUuF# z%h!`{$=A~8b92qy;@hugUB)6~ugyaBB4x z8%Kys+r!DREezwznyafQrSu+|6^{5OF==6IAJ>vAIW^aa2c8;i{|tDxk-x$75(TO7 z^EO= zSJaQ*bH5W#ZD{_OI82nZ8Afh(>VBN(5a?;`zqiJb0^k0m8Mqi8ANz-1C`nUqY;tn! zdK^dMscfs7V=q#|QUCm2!XJ&3^`8PyHjc*~)}!B`uI~W+sl??|$uFoz#Zk^N1dnV{ zplS8j6hI0IM-?g0RKc}IKpQYwP5ePdx{jBOU>*1;qyYYW>@MAf6z;+&#WLHKc<@Ge zHGC320dEEW8o=)*_`+?c+9+J@SVbLHGpOB57n=VAzCn9}#?{#V;aR0HZ%JriA7)VY zX9gT#(H&L-cef=hlgRg;b2L0c?BBSwK?IH#;AR_jkPjWAesC7p$EsV@s5_m??}O@v35pxCZAcrINw&~_PF4jj{{7z z>s9jU?}o>TUJY+59BupQNYwK(=ucw1MI3D&h4u>zp`gYkd7b8LI$sp;Rp<-d;tnw@ zhJO}zW~`;p)~64P{S|bz+Qt%L$vxH+JL#CO?el)DD1dUlo^oY*{l|39iEH41u{fgW z1J-ri-G|x%mx_b%qxAh3)_%Svg`=-Ee>>xScpBp8l!`Bg4@YFjfhmw0k1U9=Itv{qP1s| z5QR}7*3IImX5{MU%TEi$EBbyBNN&;xfW^&D|30rK-mg$3@YVoSs^8)KURqRVdxA_u zisk~bx5D{<7y?^NUHKSzA1YFx0ss$J=jY3`6N|~Aw`)%~-$B(*9)ON_qu{dup@cNA zip$sHxR~gMXZ@nEjM9hi{y?+6zC088^3CXR#6797m6m9a@$mC)l#@XH{k+~y zH@0dW@6K~x+M05+$$sxPr-D@$#Z14sTkpA0Bk4kHk`;w1yfGDjGs`)!;--Zw&IF}K0@EG0vR~8><=jhYLC1s&lxW-H`fC$N5d~{F1#2w1+>;(U_Wfh z$SjAAH`7|V``++pv#1RDU}Ylpz{Gh|NbE}CQ)kaO(313{iYS&<9^EvDk|t9(y?(;g zaA?=rZbcN7jj3piVv0?-iPUb}w5u|UFKiP#b93BXW2auGnKNPV z@{M`C>#Hfp=MqB_zrQOaM%5lOXl(5?TJVjRkXAnM;ns%4lJpicB%e?zoz+Y(7Ko#m zunV|(ZR=hUpChAJY`=Bm_4jkY@40E&87XNgG}e$*)m%^VHKUMKVKj5|B967IyRgjX zk32R-<%NH!S}@4gW=}eLYJiR_Ko_9b9XtOkW!i19rFs1E!}QxtGCQmSch_|~#vU`p z@dGz@AIN)}=AYa7XBdAb%f#Xt^L-}m-ZFSQ%XSZe@vx~JmdvYIgPS*egr}7~=1B1l zWj3-;p9TqUCgEc*KW`1e7br|WMm|mMM5MM9viNyx%S)!Uwp)AVn}bIjp|P2;MCnN| zdXB*82~d*OycmJ28EL7*xT_+tH?FH!0^u$zt>^^&1HQupIYXbGMD`_^51kd&4FZN2 zXH4m3=1RbNUcK;jD9H;>=hwn*E8dNWfVb1mL@K&r2JTI=&56doA-4w>0R9`-K<&SFxa6Ahx78nSSBF}ratZZgU=n(@LVDwC3dMXU2+aV;RN(StJRujCbmW&dla0THn8=^j@r|1bZ2yZA33-Y_r|DweuMO9)#FP`^NUaX z@ZU;y5~{C1o;3?UeU4_&-4A<(ZcY1QCHpY?8b6{#sK>TG^^>IFWm_&1w1^b%)3YQ@ z)Ce|I=6x?q7QwNN|Z2p%n>f|4gv-u z7FmR2jho$lh&0Qa%{B-h7bY^Y2$yTzW&?nc*Pg09KsG;%pZ`>-Zm*kE2jL+N0KL6E z>W9Gg#wE+$F^5qMA?jEFKxPO@P?bQqSG>~Y>z%S6y*X4Feyx2+d+K2ysJhQ`mY!eF zbEA1gx{o9zNRsn(OA?Y)|%+t4;*XeqT^{#pM37?zWg!V)^Qq4m{{CH&h8HV%(LE-YHGC>4*K<+gSE~x z%$=tRZ@(%EOcr0g+vQ0f3LY$M{_XTN6{5*{xN-TLOum*&bmiRU(qWaCQhE})*_xd> zL;Juo>YeeoPPHKp5$xZgx`&huz8}9t=OWm*Ez>FSx;(E?A}jVBHt4o2y;^Z1^mg!? zni=`Cw?iSz+%F;}uXMXGNJC>nf&Ya;w-vSPNW9^juujV?pnkm8AKx#g^DxmZSIt3S z*MB(>OTkj*m5+U>STsOmLH$CbpW`UJN*ZdYjGLAZUNs}=S69Zug>C3H7kJ-=2=SQj zzFUTCchHEZ*_@+Mpnf~*i%2w`EFDf$xnP6UFT77Of- zWPwqTo2QD49)+`Nm+BAf{q2CaeCbF(L5Eg`S7Ca zo_K&oRMw>JH5;ZF4g`8qopNAxcv!G713Td~%gg_)hUM|I?Q?eFWPU9E^Q%3FsNQeD zWPnYlH?B>>Y4QR4MO~(51B%AW_*QeoGc`xjptQ#;B%Nb7F~<4JkvkfJC7!VWNv`BT zH2KiG8&xz7ZoV5Z0a`~)$mk7k%HGi2|WprBU}WRZ+y1bMUU=}Z-5AVLKx`ce|h8u`7_k}LHnU107dy)DBO*} zTAxYz_ojgMNgob$wX{cmR(vMc@-dJA2F!mg9S%nD@A>cv4rD3~KKtsgvI8 zj+a*hpS7tE-oMyW=@lt`iW%OqyW2Ex`)Mv&KwIWU=+t}b6O0!1*bx^F#5kRdey$a;SP5i`wRM+is`pW3?U&`7Yn=$Huv28x3Fk z`eT+f?3~0Fn!KHAdK2g2qM^b=@QG@O^B^ zCTd}ae4Q5`{&%e|%W?=g^y+cSqusJ|glk$@L;+#9EQ%*U8e6#wcUf0`b$Uj;#=EFj zW>0VlfAL=8IJLcK%E|P3w0#=y`?CV@f1_H{&*VjYh`KPdcMIFVc|mSSH`_+~xaLu=KGhsN>NpXgUjFmqC>QRjl+5mJkQ zV&5xPSh$DlR@2GJXaQG2_A<}!kYU*N=7#v_7q7~xpr4&G9L`^eUOzFh+)74fsaVX~ zQzhr^ulSAfAgT65Y+?I06ZN;PlL*j zZE-Y37dx2|UkXL_J>EK-;TgQ!K3TU<#99ryftWDY@x1in`Eq-FJl+! z1&#N!QaNo8?m^Lkl3R?}) zYZ|cy?o^Z#)qxZkR<++4wdSa~ulng|-fvk7hRnel&$l=(-nlDDr5<^0uAW^CULDRf z8?a8&R>0b4>x53|ztS8XySVF49wS9|!r0wl4wLx~)Xz(9&*Vs&JyI%rIjU3^Nu(=j z2~j^MYuc`$BhA^Kgk%HdZRVNu@K2TrXB53q8CuF&xM2gZk3tLJNw!RoK$@#?9WFZ)IDrtPs1;;r?;XR*7FT4)k0)~TX(_+D(AOE3-iI1^GAAa}AV&Q%=-2L)n3MQ5KL&*Yvetx$GwMLGMTc1vb2g2=* z3l|r=D%kB_8#Y$1boegjWtA%(V@I}2E>~UG7tTI!-Jhkr_F*0SRMofNd##@Js44pT+7zo{J9Iz}ZP0ocKc`$x+Bayu1YfMgsPYlsyZL*$DA3Z-S?OIJNhamM9*oXYDg)Ce18dhn}V!YKPRSy*5Qse->dAaXnvRRp{*auS;rei4?zq2!<} zy5a5whK)#kkeWB%og(h=x#E3ZMIXmoiO9wPPIp^{YTcb?69bhn0B^%DnhIWs9MGF_ zmfO~)-j6{$;>YneO4cDWLp>luw-P&oGTf>zjq*Nf6hK&KTWrn++5}5djoG;DmGqHW z-^l}4H&!Lhkk@U4tGV*zGIylS2+(oT`Q?$?MU%BO=Nd+o%ZoqPmCzJ`|KygVGI`)&2_GeK&&b7%OmX zpXYU*_uPl_3Y^_8?2gILFG~$~DhB`h%!{k1C%hgmWtwuMH-;p98Gad;lI6lGZVZk_ z->B-~WNc=sXH0#nVt(FjeZ1so!HMJZ2rZ&l9}mn)wxBbvvOy2*Ae*rtI)w(0(g%=$_}s-=Ux&3xkgnYZ;B6P1%30yrWZ+ z)M}{8Qu&nVZ<^uAqLv09c~)x^5_+{1NQW+cA~Njr|H2Lxg#EL;T|_zPRoOw`3Yv1v z-%pPPp49e)AJYJb*@$^C*cz^SWEMtBE2xH$L7|Z>7K;r3FQnERqtW?dryy0<(iaM^?IRB@86(MP8$gUt-Q-&2q4cpN zR+aQTxR&%_4hL&$eJ8ha<%%FMY)`dY>cZPY4=eeVge4_*A|?Azqg- z_Vp>VVKH=D5E2hf;(6EvD1iC1Kr=4p&t4ETknNA5m zh?7DjAFaQ%-I*s5gm%o5Q=EtuS%!AqgQTd4_v;%NuVCU($NSRQdkMC+K6PsiM)k4F zLv_Q{#!Fs=BtVT?{k;GZ-xXQ@0=g=aWYf$Y93IdEl&gSHbXsU>ftg%{$dbA(4%`3nNjcQ^}zyn31hR5Df{>+PO+!IwP zxp!0sn%gRn@7i5OlHS<63pzef9^5%3I7nQR3f>m_{-eWFtxYy%j5!eLNK?b`cPEgW zuOW4?sx8Hc{MQpQrGM5KpsCEBj{P!45Qi^e%JR6 z&QX40S^DSktKE>_&V3O z4tCm6Jitsok!_v-V`n-nCM?M{~v0wbAO9|H9 zJm4S~YIYGz!_@v8X2^)wwo6%=)suRoYqJE`o{=e3Zs(x0pZhz7!)Ogc4lX9lUYx)i zO|>VE!5bY^uSn3|KQR}5N#@Ae#2$eek5VGaEixbN3_FKz%SsE(sBi)yYwPFG*#P1T z9;aiBTkvibt2pXlR6MzgxP5Lb1`H7cF*81%OFMyL=Us2;2Lt_91Xsu>)>c1+ePGZL zA2LQEvYdn|q&jJubX!~|<5|f}MX0zy9iM4FQ2gJjWn2>GN1Rv~SPWx)H;!)uetxkt zyeAU_GprJA3Oz_S1#kSZV^!oyVEr5G{st-2Mr)RCaRlfNJE96FT1&1r^_ z2D96QV8W51*k(-|pVv=b-SYNb{IU7D_w+Z-lKq!+eVm@@g?$@7>D7v73>P0dwx&=C zis&h`fYt>fl^PyJ_*>2ygOa-!Wz9Ll0aa@bHQeS+d(-1P(8K_?z}kiv-fo)s(oEwf zAE=6WfUJ1@33~1EBPFQO-#oob-0!3i_x;BB&$+UTB|7Q^3wTuL5^N=A@W`w83-Hqv zhuzS3z^|1wkJugNz zbU2$B=h0Sd%iV4l74b7EQ=jtuJGb55{F+XTJ_x97Q!SBoO~=esEWKHRuIai}DOS@( zIPl(uxM2f7Yvw_p{Dp^3X$Oqb`)${7)T(o_T1`@Hp3*!3s_gj4-Hkp?C`}J{_!nbm zF8Nr4e{LLow(>eTssU%CEKbduW=p=s`hN_>4T{+vx*$epjtCZ_OtcM>d||cV205?T zcU+toe&hPQ(jg~q0Xw6RyR2JcEG|i3A5`SrdIG!j=3(vt3YlURN=*+6NwQ28)TB6+fl~Wnbh{6iY-|ml(9y!rPUtAaq zfw%^Ur_d)C$nl~#ITTBh9h85axnAHowLrk?#ajWbD-E!`ho##U*ffkcZZ>C?p;JFy zF7C{x{K_jpT#-`PtYINzqjik)fjoU!*cg5)olfT-6ZQW&;H?pvdgbZ7oH5Btk4LNf zx(8AfhB%E?RB-+{qZR66{?2eLE*iNO-ad+HzzTiymRsD7{J1;o`Nu-hh?aJ!MO$Yz z`h(kgHeKMMt1Cmw%-O(d(MsN@#1)D2z+=>xn?$#ik=0*VHO;O>#ZF?|iKmZg^FH0^ z*!)l5)uc{L#mh*jumls4TaxvMVQWjEVtymX(JMaQ`lm?55^j>EBj6TKI9sHf1~*38 z;oQycgm_N~{i%<3(?ut{xUj~#e~c#ZZ{Ck~Ln`;k>DJ`;uf}sB<{D6+l1SI*K}*E^ zEfK`U2#eR3lfdKnwH_3hFYby}PJhk{r8207fel59hi&XGG?xw~2FEj{Pl|0Ox50Sug z$_Uv{w53U}z|g5-qtz9;Y^Wrszu?;+g;vau3}-!i((XD)SBeNEP;Sf0njCcByCm1P z;Cq@-0HRp@b(HfOGZ5f8y2~E+CD{metC=Ct=_*)-JNd_9bp9;-j%gD*Ry!xszbX-e z@=aZE;Mey3YF+1?aRX&;LHH)+QK>Uu1P|DZ;jy)?kBX^Ng>*^(s2VXOO!zLX5UWxz zkDP)d2Gxl_o%me$2yi*bRMWKaiW~B&f_NzW!8NpeQ=yzVjQ@P#xX@dG@mk1@InFSU zrjcN|>Y)>gCFI5>)htQ*aIdjhCbjc9EnBL=jcM1^dEvFC^!>=9+BoXk;4kSHO_4)k zZjCqX2CmuQ?UJP(h!noqaL(ZN+laXrrL_!0wa0^%RBBVxNc!4e(bkkdtQupHxO~8k zh4Y`JH%v_PqreAB4qibWZ-xyKf6P5L$2X)@4MO*>$KPm-6jr3d0DreOetVH-QHH7N zKRfRR(-ue?va7wtJOBDs08y z%PpPpuw0!3@n=j(0~sA=pZ@hXfJe|V7;T-M3!N1jFchpB^M>B!8P(nLvzo48(5xgF zeQXwG{-Noj;60EW9DguFl)4C|)C~8@Q!o5A6Ss0r&s7h%gA*>!3dV+t-9}pfmh<%m zLly(`mo3VAsN&b$+D4A;e19RN`Oi$@8)D9@LchqhXHy$*2lz>!bXE*D;8m4*t)Cj! zze|cVlJmQe>^H7YV-GtyWur^M92FZ4Oc|yrTpj#oflFe?Z)FyjEVnpMetNk8Poxli zRvQe{4+Ja3SxmE(7r!p6712MB=PcK~_4UQXrs|FA{F2y%rio-Cv8g850Xyd}GR{!^ z!}|nKDoq&kUyIHeEK{HQa|L-*Q#Ltlxt!3g&XW{;N3TOC?;V1iE8zzva@9Ol<}v`| zrFQ>`A`QIeY(fxlh>;KwE{>ebD-Utj6F_Tz8Oe2;M6Nv9g(`~l(4rt#BR zMQeCMPRf=;(F8#dEGNtZe%9d@MhPUKh0&=TN(y!3TSilen(;=%R+`}8-&t>!L0hI& z2)5gJGW(EAr&i?OKfCh&`|Iv@_&y3|k5Cge^giumf2iJ2;$li)==X?j`}eFw4QB2{ z6S8aXZ3DSVB~kBb%IRvxF@`T1@8B=#daPDm&(gF{09Snr(y3UnO*_^>Vb51Y61JNQ z9rC(qJWrr1l?Oiig6N={H5a}U+kp}jT@jOGq8}nxsY89xCaZOEZiS?>;r1n+NCcA? z&C_l~BlxX0R?bh~1TNJ?G+Rk)c}|7X&j=@vPUR-uDxdFWXpV${=(lL&@#R4)6)xbmk<>IVJyi3OXFuD*XI98 zerYF{3lP2)oZ_gTY*Ylkpm$rfDbTOxhP;n#4B`=4hfp#=9+!aNjWPLw`%W=grOAsd|6x*YFx-kO^=FF~{5nel0v%K-|N+ z+@I78eFOSVpYZJ875WpITrE=u&oCtx`J2DyT@Fs;KNiL6DHsg~HyuY`Ibb&)v2wE$ zYW0*}b^TS}2*L48Qua1Kv=K{`*GVawUBz_~V;Wom=u(>CWaoMVz6Is2+aH@{o`5B zBbwuADhYkH56|sDtAD7HqPFlma`;lOQDMqFt+g!&x2E~pM>`r+iwY@NwBMQNf$NPh zyN&HFn#|MB1c4JNf)o(-)Me_csi<%sF9(&e;UT`()(5WMJ@|@tZ)Mip8iBvNPztjv z&UqtA#m@TRhC;U}TG=Ng*zNwv0Ci9l>YDDV&OX_JC_!lQ5-pgU{1~tytqpez@yYDF z#kDzS@`0*N)ez#RQ;K1%>jY@4?h(IkLX6#O7!`18=GqdHgm;=RN>9#ou)>wC@h-t{ z28)sRc@e?HwM<0F)3)`BhfOQ6D29;ppZw@-|C}a|cXZ+}<_O2xOu|gk0NS^0n_?0Q zWy*KZQdkqT{x6xm(7hgtypEls1&Z@}Er;1m<##OxyQIGr*~X`A%?C>!qmf;e=DTRw z+3D|urzaCO6P!HRmg*0CQ$VlPSATy;2YpI?Ip~^I*?f315`svvoN5t2G_%RiLwQV~ zX1;&sV;21cE}1|!o48+;|CV%+6*>A~X24|1h)dxNopdX?>$LNQXTXS1Tjrd6UjkE~ zHQHF$HB3~w5dIYuJco}RPL1@aznD{J=PxX7=IZone1n(4sw)n!H=c^b=-+wK;p5HH zuF1gT)Dc<~=qlB=+GL?~O+XXBsS?*D(w+VVa&UKEdoZy`t3+-0OT%v5$GF>zXliu= zRhQuXWa|e!`@6Lj#hM>Q703Rf`E2I=SE>6np~U#wBa?~OcTT1mTk?2cdB!fMs5389 zz`RN9|0meHtuto>YoGgdm+-_NFy*yf*YvlTzqW6VgiTRJgmoqP%YdReyt!J@!!%`J z(G=SoN_$tDO*ne+0&5Ebz|FxGxBt>=Z`S1*7te*rUzIFd>rfZqY8hZB7ROu@O=hNP z(IUEY`T-erpl?b49>_Y4MSz`!?w36A4&9=Wga&s9y-Qdee_CSLWSJcz%}lH#++oYZ(6tP%B!bp;}|+3 zv3*ts$5yv^CLvPbHqlWZ-#Bg;H$C{5)dU687oJe}gWjAI>7BW-TsVQ*fBZannkl;_ z%sYXAEuQNnPo>{^@!6Cr5tpytFZZPaZ$9mJQnQ2a(HxI--S4GVk)~?qUULsDZA{;B zOs!*C&gW&KB+p2>GXddies$mby18<^;ziW$Cn&-6qm})$6!mqSuN9Xr5P8>r zBG8GDb8d&7cu3v%G>!(F&m(ik1Frybj!a&-2<>^^4JTeb1vsGGzu-*gAH#MXCR#}- zrOHwB-p@O@voG&1xS-}N3ref)w-MNX4cfeV1eeCUkeKM*y`xd0k}D^c~l>{U?^X z_kO`I^)xB3M=a@9FwNN%JYZuUYLr?zQvXQvHh;qyRlH`YUd7I8(;Kr zZ2Q|f`~ayPI#V*eh&i$x&OOTF(0szC8M=^-- zi#5?;;WBSOET#Bm2*68f+$Ip3z}xz>;=|uV$3-jtjtMczs5+VBA~op@#(|LN5IR4E zJ=sRQy?2^}09WnM)PH3_#`Jw;q|0g!q^2yT%UVApNueS}Po0~C!x+A-jJs}dZC6aH z=1XSV#J*>-=cI>pHppvexdgXblnitJ^^m?O>ZZUVV_h!n&`|w}&b~>afZTFTL{EN% zutI)Q&5YnV8`xz#$fSuLB}&T?)Z_$baq2cL&1N>sv5Qe4%iE*=|AL zTF9G4O`GFEN|tVtASQEZZO~=lm-IhyJ^3E|=7)F7yW%q~K8 zS!qvSDG)%=7zJ8bF^9~Q4-z<|Y_ZgeKgmOmAk9dy!W8IeS#v_ot)m$7Fe1KCX*g0; zNDTqH2ITHvWROU!q1AMFyP`)ywBi?Z8mXCo2kXJ(k3U-&Qa*`+?FP#F5H{VLn_A4Q!* ze!+Z_rpy&{rFlG=1hThPPIaGqo|J{E&_~%8=<2A37D*G~{Z$_~oFKJ`UX|G>!{&}N z+po)?vOi*vVT&ARe4Y*`W%R&#@Y8E|F0a5%cD6bio;RGfU^><;eLx1W-!oml-(AoJ z+?&ZlaG)k{?o)VnO$Iht^1i^SIl}eISu-P_@{wZkfp|%1;(^ZH+dC%F=}^F4u~C5q z*&Ni{^ltX#!H-p8Ae8eK#*Mg+0f719!3#GI&B&+L-v>|+u0^HG9LOCc4eoH|Iy)PLjE2gT#8-m04_`rRx|X2oTG@|v z(tG?e^#80p_C1g79~biYpA`XvT(#Onx`UHLUj#ZyGP0mp1pe`*ZJWc?}$&^(5ErdB4F+cJCA7t8Mw-@*~s+?1ze&=H;-XHag)k*+uG22k~xevu90p*({cqmuB5W{Us?qMo~es z6%VD;{Ii&}b_r|CClf0N(Bb6uC5(R@EM03uwGrM4&y9dxKmiH7tU!%KSzs5yv`XY;zO)gPa#6=ZZ4QHT-(1G zL&+1V5qqTB&&<reZ5hmc!CzhmG^NT+$y;1R@T6P_UW@fG&Py0#;IB~qb0kfmZzR%t*5044@V0W z(Gq@n*Hm7_`Aa(OU*VT*r#rM3^W$k=q1|!2hVCAvIYB&9#Qr|H!1hvF={#&4Jk~p zbu-dwQgGwOhMutx5HhM^b|3N8w%Dsa`gJMxG_x!{QST~HYKkgLrMK|vy~EZMBvHt* zw<~BvC5zgnCNa>#j($QOfHqaXkN?Bh4n?622)!osx$ff39gG z5MeJoAwuD=<2T_)wDlC;KUVE9c@Abfz9WWZ(k9o0^?vch>7vx^C7<+0yDS@`uPnyK zUxx+m<0m?!_2A*RewjBC3Pq1s>(erl@3CqBmf3G>vsH&^l|YdBIl=5|Vy4fKKNJOU z7fJA>!OqLKkKJDfe=lB=N+xEHdRYoS;W-pQ*UWqa>xsbz^PVR>*G0K`FH{28H4Pdc zR2M@G{8^r?7i3)@9;^Nuo|R(OF>~NOt>{Q7Vq&9pYNMAJOWy!+#`)o1CuNqd5C& zk?@U*OF+~bv9^6SHAF~SBJ$SaXAcO<;fYw$uy{J>)ieBe;Ws4t`P9R^TEW*|Bx;TV z=ZpF+NU}QV|0?7V8-d)DwFWq+kl9y$w_j}F){=F3D5)~8{~*dDVg8-en>XKz=7y>1 zsD-dNsXyRLoVsg~%1_G4pm!J3~m^MzpuLuG9?-G^4-^uc@e zT5JQ6FVm|}pv}xbF0}NfjI%3LZiIart62%Od}7`%R+kpmP{L^!Z)3}-IiB>OdbF~E z2H_+8VJa}*?u<1tIaI>`bx7`jKzpNvvP~c>#+zyOqse@qSFMSAhFIk;F$xQAT%Zar$)0tw4A5b&jQ#$Q@XAsFm?YifQknwn#gYNi z^Z>z|yNgJV%s8)483*cB=dR;LPZ+aRck3MjRMr9{?=r-crPBjZM6+x&rITEF6}dvQ1(jti&$$$PSj9dGio{RrkVu# z0FGrm|Aw;=9aipRE*rC1(|+6Y`!T<49QAXBEF!<8uL*AnZG@;;yzw3InRQH>va6wB&1^9w>z{89anrNhIqtxcN~+ip3pd|<=m78PYw3zJm+mZ z(_Ks$Vl>D41}AGpJ8xYC4{kACCA*HW=JkCSX8CMC*WvO*aRkNQUT7^S<8f*5Bdrtu zuklxyY-n3RMHB?DiXviGGgmxuw_wF_5Kw@c@^R9f6%UU6Tp|HMju?D{QkGkw`WB0SJ}VY|37 z+{2u0GKtPDn%6e#T%-MFEt>-Sz%tfkZwXhq`_sPXCiEvKsPUakR8#c!ma}Vjz|1zs zT;+VT7jerPk-y3at?v-N@IvLKeUWXl93fbR&59hm269Y`8$QmqK~G?d2nO9R3u${^ z4zl$&=AA_z+oWb3yBdC3X#3H6!`SUW4C7)x7r``@I-O)V$==@0+LFS{>e|=3$Xvgx zVCVT}p0%x>&dnx2>gB`iq{Ath{<>Y%FTIv`*LVGklZ*c_?PXAK>C9dSr^WP!g0{@q zii%Cao#$5-NkY--q@CWcfxDWt=9(;>QKBLB#FZnMVjL$vqqHXLXTxOtZ4P#XA}InY zo*qEbp}og}xg;|B>k_p2QPS6Bgypqu_^uGZI=g5gX#kQ45t}TOYB{jK1n^0H&6tuq ztdz!s#!8n;%7AZiPyVHBl;|s;zDFRchC*vT3s7!{jk4;$=&ya%wmoTz&%IaZY|hs- z$p+`RSeEb9J)%`nL4B#$Z$AChc!sxo^eA0j1-vZCWb<`pVL_{2L6%+3Ku1>%k9TJG zPK7Wt28+U;q);&~twgWt1%8=wI)GQs6(m=eY)Mu!>^gc7@0bkNDq1ppkz8<$4d+GO z2{83`b7M;2J#s!og;f6>7oRDpuRS_{*Yd3tQW`x_2PgPPPrpITciFw|@YAc3h`L{3 zFGkmf>6Lvf@2_5B&h8N(u-atjL03EqxXZ}Fx~;mLH^Q9NEi)AzD2BfR4$UEg`4KiT z+92VG2r|nU9bn#jX$Tx|rR+1fx?x$bIL9?Df5A{U?j`jb%6@xz)e!`g5VjiYUP}$D z9cWE`S6-u)DiD3AOrFC+1h}7PCXbxewUTZ9;Ft(|jyQBWV`pd8tSH6MjU-ta0rS7vno7iRrqd6RO?%NRHCFsjBdyEFH**rs!%{g=m~ zD7Iz2C@W;}jOn#I+Rkcg_E_7+vz5yv>+x-|*;daLS-{dwUIo=9GblQkavZY^clAGL=cD4F!UOAS zA-Dry--}rDWs|*XGNAM{1P1_IARE$l*CUxcX>!j_pU+pjk2*4xvw+}}mDKBqf{dbf7qVjwD=_a4z#(a6~e!~N&smFdhqbqt1;txrL81kt{j*Dgf3*U*il z9YkA2ex2)m(Z)K9p!STh4X2-@Ue@3o30PQs_utS6{0#9ANNbaY-EH;#cHU~1{Rn!s z;tpYLWr1LregQ7*X>hu?`U_6qSQOw;TjqLW0O7cwJ1}jTlYE|xrnBmCp~BH<>A_WX zNvKa`?7r@3k!#&VwLrnnpS8Hek;koEd!jjPV-owb$Hz;3zL8+LW8$_wn@pXPZS}Ss z65RujPLSS8`rdb#bgpdvF~y0)6SAv@z@?;2ft2=$eadSB2=`^n1Q6G2fgs)(zj0tv z=`fvR;#uksP`Jx8l2j`h2}#-m$CHK(Zug6kjY(`$E;J7t>RhDdLaj(i^a;h?g8>mx z=_2^>8A8`Q3JTH- z(C~$n8YdIl4KZhCPV*rt%ys{zQQ*BUsPk|w_HT3342ge7&=*dFv=aY3JovtMy0z_x z7J{#{XrI*4JDk<2_<+20`9*u? zI|}Mc?tl>aytm4q=1-8XjlPH8_U0+Bx6keV2=Nor`^B<$W&LhE{q{ELK&p@o@FA>b z=LIO9M`{Vzb%7z!k&Y(3B`Fu|p+O;Y#ETtMFEXPxt481XgvtG_c&@O~Z;=m?Ke3AC zYhpDEjUmShfyInLA?z7>Pw4--Wq|bj_?F$PU0pSACC4;P>+fTLjWtQ++1#3HA7Xii zztZqHKOdFwzH42~vh}QI;HdggN}W#Xd~stozk1M~BjqKZ`4}ftqaCpj{-dTI6R&|V zIq=jD%1ReiYsI4LwP+948`4!j6TV`$jwuB8h$^P_4&}j$Z^|ssIR=s12R|Tn#y;+w^5Qy9n6AI^)nQIYBb06WMn%aIA7a*DFNlsxoWu0#;v(rIF|v<*R;7 zpr+i%-@MKHDbfaQyhfA_?C&5KH%NZ|u{ULWx=HBr%ds8xKnw4|?JUjcH74%crRC8~ z>4H&pxVhL98>bK#wjH~~duN&vCS{ZJx9@nt1Lb*yd>qSxj+BDw)kC`{d7q2){8U)g zYEm5+vO7Baj~xKZ=<^%uews{^2)C1km(>P}mNYIh)h@w)6qX=T?fnT}aG757q{4KZ z`Sag8$+>5zh!L}|bIB9>lh8d9iL;--p4kL?FcE393VuZqd!UcTaqUeUF6N1^J20G~?Ml0uJ5r1f5+XhMZZm#@~Lod|)9N z15Fd%eRKw?If=tom#tQM;xBMJ=rn?UlXx>&Md3E5>06~G2(AimQusUeLCDW&+z zl6m}WT-!W5j0P5I^q6Tv_uk3j+5FL+;w~`F^<{8b9igT*G)FLq0Hv_>8XBPYyVle& z$@W}kMNf~6%~t&;KJp4@$Td>_`vouHzoC9CWwIhRR|1wYJ<}FovLUJ-+E9?t{qkyl z_9OU%Lt4`0o-a9YQWqb{K$(rLc-wJwSV#>FE!9_S|8mQiU0wX5KiiV+3x%q~-CLGSjlieG)q z6kW}{$<o1u4fN0?$fH zycJSm{OWx_&(;G!)qB9Cz*8`z0MSA{zrumtAL5ETGWxkh`xg#8A_zVA$~Nxb2}Y^yzB09jMEKPBnluJWc*9f2(iz6Ri@VSkqyJ`o6u zUxT;9-W=mwg?%-%$bqv%M0BqIiKAt7)$tCa?Bb@!_CvG6zoF2FDIhII;Ol#0Ol~`% z*ZJ(mzZM28Ti>}{th~Oyz}r9HBlJr1Swm3d$~6u`SIeo6lP=bxADz4P`vs!ou;k2n zcOIkByjUmjIS<^s(|f7ned{BV1Pi0NNdzRccWI%{6rEgcq!IZr9?@5gV!vH~C(*Ke z02VwiTj85{)z?NJJ$qBK7N^_b`Fv*dEzx-Nv0tOKPa|VlT$C^5_L~5+^UE{skfZV* zMXC_{odZjGul>x99!=2Lwg*d}BL3-<#0x(?3v<_yv?D;{2xmDy%3$`<^`PJ&D{ zNdl}|M0L`qG*N-{N)jcAf-rCHkNw#QuJb8P4K_1Wc1q8MUgIbJEW~h+b_a9SBH`KS@j%!23TDF|mo#cZeK)^ck#9e7)fjSm5&A@7AEgX6=GA!XP z2(-){!F^b37RW_a|5KC#9`gU8=tn)@CkOT`Id^>Yv5B&ORQ*3cf8V!dJ)WVG<8jp4 zyBi=e^3m~*#!ijKjB~zi%$2RF0s=c8j{8!> zwpi{jMH76I6ZY{Q>Tvs>I5hlT`KSEPs)c4DWL1jMOu#qJ#+N_o`A2#Z$XNgj?~0Fb z!PoB=^CSk{p`@dF5BzgQ#vyyZ#@)#h!%Y6W6}J(_;AMF(`mb|fK0G83vLF_8VjYZ~ zmvDG=2udcPqGiZKHY~SAiHi#t%VD_Y5=<_{d$xLC!yGRd3Fd!>3I`G_=9vdB3G4`#J9)N5FVc-S z&*vp_+(YL)ly-*eGS2_qw}t7(RMCIBs5v zQTa+F-1Qdmo7#kO_D3H#>D?$P`PYc5^>kzc9hT6OD;NE$;I8Gb*3VroX)d#Oz;d?6 zl0P(nuk2vURZl|0RbXA;^QRn_u}rJl06-1Eyj5n=r#Ebf>BW_-*b;TAcavrw^xiPl z3PDeHVNYG=J|F;tHccNyJZzAql(anyf4K5QtX+|<4~O4?Pl^GhL9$^Cf6I9#a20E) zx}ytLzSDVMv#B0P&#~k0N81V^ud}+bIhlL~>Jg35iZy}qk!bDym%mRtmYs^Ftz68@G@(NtdSWakY}qf-*!zB!kt|i0A#^ltd|}9qq+qPhd_1 zJnPuZbla3|zlMC?u7Ha^1r=+ni^Q*&6et$3yIFO03DH(@jx&c->8@wXt}i(6(U8jW zlz97;I|xsc)ZBou^qxw&ivE=aQw>+$?^C_0$((#)!1aV{o*On~AT6UsDj;n6h5PT^ z7hk5M`<;rz*IX>HPWztY*C-ww*>FrGAFU(YNE!y>~_5VuBO5n_(az7nVm%6k!S>DPOX1 zC0DdMp5VZ<01y~#JV(ui5)TlYfS$;A9#&t$8)Jq+?geDOZSJlfFfm+hxy7We^q&O* zGTAzMo^x(t;ck=q=K1t~Jra{W(Gsb|iZKQgPN5={z>U$yBgZ^*@n2tkSp1)ha+TiJv znzvo$kS-q8zQpinP7ATwcJp4)^m^b;l_7U^Ze6|CQY6iNl>JI-#-?~`nPmijIVTrMMqX@8yFRD#9 zAhs@L?5_--?UA3L7|3ZdhSA7o&U7cJx6^yWW>xzxk7D`GkI@WQMDkFGV=znqI=z-- zhLp;#CK@^6sM@v$`g!kvWf&0p{iB|3!fip38n>sOCx$Dz#`_~+KCfUQp_(IukxpwQgK7p&Lm&oO&aWp$N2=qsNOO#*s|^$X%_a^9KvPvKs{XY;fblJx^p zUBg-d+IU=9p;I;1U4g*#ODMVHkrUe%?82;fVCV6Z&u2%Gh2?*h#fGANZS_wsgMeFC zH3#w2k)6Jga*s}$5+G-E?U%4LT~z7bHgZ8K1DkvwEbK()jrOHmlun zQ-g?0$!gJ*A>_a&s&KWNA>w~K^1VA5&B!TTu@Fk${x&vP=1!nWPKL(klD#(f#19@~ zDpFIij~#kp^RV{3JNp7Po%(NFZP#8EZ~L`_fcRGQ2Lq>#H@1NmQZ#OB@xG>m%?Isl zSb9A=iRDpBxt~mN!ccaq9H}F<{DDvR*ld zk2#FcDNo#2UEG=vV9~FBji_9r-(w273wk6BGHQpO3VvwXV>;Ur|Qd1U)niwCYdjTBu#gCr;|A+Vt*u(Qr4R^Wjk-bJQm zb1-V#it(4js+}Eh;$CjM>{&lz1Cj=S=l@GFz_UpM0iSp_hv%KjB6j^Ohe_O7TdKQw zaeT!F_;#gf4+k6JeQ-lP^2>Hj;O=&7>!B6-?u!t!O?CYO&mK4bxBfn*N|Hs>FKpyf zNn@-lbZ^lyV^}BfAai=eqcMo_{5RJUs=l92|e^P6{l25|yKQ7moO zQ)Y8lqw_>7UQ=`FK_pZinNmZtSRU0+DzX55)Yl($MDuyXc|qW^MK5=^<`OX%N|&zE zTmyC~9&KOfSdF0)sQK)e>GUaONO(*3R`lIh*X1Q5-eX2J|DvBOfp&+5L7R1tZrUcj zmV87Y{3HkPiNiydl;?PRSzw?;zR3P!o)H+jxK}%pocQ7ZjUnKhnH|9D% z_@+wBj*tI~KkIpKJlfe;*CCE0)?@LJOg^7W)QPy<&~g8$I5Bz6SZr&+F6DkP+(#V5 zKa|1s%UQ4dXSK_4L72@(JxpqbW@aW!5lw*b-H(5e1nKtCIFlco9MeBsqF4WVrbT) z`?7htRG7`D+k@N&brPPvw#!eP6C^Q;#nTSa9ebY=KQ_ySYQQFAeTmFhC?=|EC*VeQL&b>?}{F}98Xp)~Ym>QLCRv@NgwiMQ$q;9Pbo)7#| zZ{#f@(9QYhbF;WLhd8ZW!`J4w)wf#>u!R$lUb+VLfnf(kH+GgIk8v} zAU}n>;?UJ`lyIis)Q1J;n2iGVNyM`}@f6ePp8YnTWxrBt($~27_x(~4c5z`oK=Q@X zlwtUq5$QIh|9e8jdfqgVDHEg7(Xt?+fVlt$Xu`HhqOALd=EWOz2}=kN%Xjg?RJXIiJf_|*w`IP3@Q=YbMg3^l!2glguqJ50uD zpPYB=dl$?b0z??V<$3ji?`TJZnKf0~w$R$Klphh2&D1duhWC($JJW%o1^0fILKRc5 z@Usasy8|5F+-ICQd6`~`8}~1htVXe~_E7LI;!Ov1kN@uYz)rOwZ3#$esrq6G)%>O{ zmK#cWP%h3iblSR((dPzQ4so2|<5@l>>(OV2P`8fd6^bkM(b&ZEz}||75+34UDK3=V z7nc7ze*v!2C)t~CTjExuqC#cm`t*dq?4}d_<77u`HzPO)cr|@-F1|HFKiLU%;8zXX zi``P@CgmqC1A}crOM!RXt5!HPf6}6>u|kVmwM?dM(o#mV&MQu>mzo13f1ARC^BSuM z9gz0RJEyhx;t_EhgqgUK*T1F$N!g1+~XY^L(Z zE&koppM{*oc97xBo0h882&0dP2OtJMqiFxd?r{I+##z1Gc=a} z1L1({VlS5}PH4${VNC>Y6N8D0K4qlF^O2(J*EMrLH25kihzc;A_WFzI&05FazMi12 zfy}!rCYJPMK1*2v8U3q?1^FLx~k6kC4_KHgYe2+o!|Y9z0*0Autc z?7e5!k0<=*cXxUvMykzyWA*RwyeAhFy@6XknEFyxbx|BJ+LU#1_7WHX`1d}EVh;!V zC@!y5o#o8w&RxB$#PSij=~voy*rK^+@Tlc~T^$bpACmZICv^CYm3c;pKFsQrAk)A9Wf%*HA$G9Zl z0=)MR`qrE0nm&;<7(5asp>VtykHVapU~GqiK@A7)qa?tBz&z+pW)M1mP42K~`45eZ z>!I;#gP1Z{UzGfb8f0nnq4!m##}C{8^=bf6r@wn|LiWzjacK0QiMmR8E@kC&h95QY zx0ex+y{>JG#c6URL&?l>$hul${+1P$#76}7Xmgi0U1yB~V#UX3m#9ZG<=nf1FSq9| zbGe9oMTVUvn!%F`u^;~=?2<`F%&aWo6nBcJP8r7i*(c(xTF}&+3uVoXXsayTRT(jo z_S4oNF8FB?WUV7^*0aRP<-wRk#0tXgk?BwslVEngfM>%VyXck5`LVPr@}Gk&kscy* zGr(6MMCv*a0(Ai9y|_=&pLLW^#wuTVu-C<`Bf|=AIqG<+Goo6Pyz(HvB=r<*h-_L)|F5X;j%WM({(l)oYgH9RjoMXv)~2n|YEfEy zmD+o6v5HphS$k7^?^%l4YJ?K8gCItXAo5E;-}n3dyZ#g4yG3&#_&^ z_&)B;^nb#5JrcVk@V3&pb*~pHtM+_<#i}H3+>a2kFoE&-{H5iO58-r0S1?V-pD#Cj z0hJz(7@4>~gy-U%bni2ght03~xKk}BGG&&oruhQEiPe1-GlErLVNHyAmr3hm#r#Iz zI+o{m?1T#W3>+786KtrdC`ccXa?ni_{Br6hMWNmFXk078uS|cQb{XT^;Jji{x~9*k zw2Q_TXy@huz`{w-0W{@2p6@=>%_6-D_A##yjU}t#n2aU15I~5K%0=l!W!QI}f3Mv* z-r@!Km$^=9GQbeCKaY^97xDBy(`|ZCtv%crL6A}3D>nW<2isilcwfuWI=7w0y{xJw zf#yI7e7<0xZ!@_Rgcsye&I`Pw{ui>Dl2Z{Qju8#XE!Sx;Qwja=td&zFYHb?W%fxJ;Ps+rh9gOi3BsR zY*o@^^0njgunS%$gUBciD)-1bMxKS%bpwg>Dh}993xn43pwt-FkbeDcRE6VfLeI&fod7fr_k24Te2sz`eRUSF+ zdbCbB-V*;)>N)M&ciybm+zrqA4ZeMH#oq!U-x)!2L!xpZ^PTfjg8zGiBvx6>W5^KQAbH51hR?%GPo8u?y-v2vi>+i}9U3+^i zH~Y@1x^{gaqo=VpJSc*O_m zb{V@@v0aU+51DT%`FX4eqY!`oMiP}YLe7_S_bIGxjGq%cAItyj%dVlUkM=~s`RnJ% z{!F-Ty%Y4u_a(V8IsTdGD~*+sOB5~OJVS)qhJ2Au?My(~$Hra!-H^E( z)Ls|Ci0d_uz~Mvs|2rE1;PK$6FMpLlX^kl%*9KFnH4R|aI zbk`j|)l}sPBxK43VW(U$!tr2@z20PL%s(FYhgJ{lqv096Wb6&=Be zlx}&f*jVKey70tUu9Iw)Z?;`aRU^SyEXhTApZ6)_C;CEXzU-8d<{e0t?%9iyAKlY) zx{@WDx`FI>iH>8(GCETX)a|Wk7#8cYdGu?GO2lpKO1-F~^WXGLSehB`W$!-YovPP9 z1J%1J9#nNTzV{J3){ipa`C!9~?J#bX^eC}o<{h{J2Qck9Nry+Y-sq}(n+OH^sJFj> zQ8*9lbLf3aC#RElz7CMH(ZH&8uX{s)th?4>_p2mkd{Kl3jVo!J!i6dY_qL2EKTB1p z;=CI_PVVAhbq@Et4;|f?Ysv-xgzZ&&e7qy}QODS=XyDPNu&6A|)wZz*8R65lRJ)}$*RnP+ zG;wbVWbVJEUtHX2MEfl|&q46xRLrF{sDk-%ByyZRB!8bmPz0VFUi@iVMF-^K7wgxB z?E}rdD}@dWXdPczpBO$2TPQi&9^fXgbvxbJJUYQ=CQp8EVRYqYNbiyPvGlfJ@al;U z(lx_c9Xe$DRX?X_0$;G?v#g67OkKQ(E6^Zl_3-%o%21+PF75@efH5IWXHCKdV5fL& z*mmn!-(2}N)$wk*&G$7rYy?P-`-fsY+PaZ{r-jTo((^^rFD-b~BitY`qaXYdB9blD zHY-SN<%e?^s)Wi}?!E2UFDhsDv(qm#!y?bmH(a|RYwFX*Ym(j@F+w)e z>v6Av!|elTz<9IL*G5j#Mf53b;Yx^S9LXx>cRi#7F#BE~Mc;Zpdm<@lt^34=F9+NK ze@zD=-2SJ62s`)f^2B(cs$u7yS?jDsop0NM+{wovJRS# z69-P9=jhaS8KW>;M|H6H`!(?`d{CeBl%rsU#h^Z9^cxY+OBpZP9EIy{~`n(uJH( zr2kk2?n)tLRRiSts)9Z%{>$a`SXfMJM&8%Ch-hOMHVT+2Sl~<&KP`$J)A@GemPM>X zCcAj@cJ!=%p+GYCx_wNh26H29AkpeP!!J;9Epe8@HuI>8?Oip-AH?A*^F7I7vYzT& zY&PCOOZ$|>( z@wMNvrT&O2EFs5K^cYN2>@Vf9$bF-ctVZjq8FEawLdY2$!KW0Gl;4?04lknf6AwB4 z7-?=H!PVC~#2KNNu;XLjW2^bjA~L>`vx7Fo^3~!=08fm@BPU0bZav8W6Y00ESvUq4 z+GqWC%g@o6OW1X*YR^48?)aEXNVlNmJ<0u!cXQ@K4~R&2vu#I-!Ag1emqz2*iJh_j z$9kk3-Db#!@(K0p@9+uI5GIGbke^y7YkaN@9VGF3@8-H72&xD;5C^Uf+`NRXQ%Uhz zlh97!+`b5ETt|Xraa2T3%r|qqGVjmOKv_j=O#*x(TI6EsE_R7$>B(?dj^K_OD;8v5E;vJhzype*tN{|^A**h#MU-x8A ztTvB*JJ!(;;NN+ugi;8C`v0;97tNY{kvBH7T(x$Sq`lB#m%P{;k!l=|csRG;>kg@) zPp2ahr|0#xcY&!6^Y5TEbHow3J|I7g$Qi-wIs9GmVcskUYBs|dL%>zq`)n*a@jsP< zk4q#nOt!AQ`S$HYsH$~Qhhf`qqnB5Xu1$xQ7e0u>Z?H6Jmvu$0;}^)#b51K1%)9oc z$#hK;uBmGl(B{A(`y~GRD7WXL!f)@8hSo-}16;Wo>G)Z(xm$8_hE|%`wbZ#YmKv*L!gqILs+{njXK-rf4QUx*8%ds6sZU{HdV&A$n2{{0XILN3(oJ7XCnJ zktroiX7c409P($_(b#S)_0Jg5x3&ujyeA0UF1OGX1DsEpq3JP5m;F|(W}#qtRe570 zSv+uR9~LHXunSBgL0gzioFJr)du}jOO$lah7hpCAbvolh>nb}>&PJ!OnQ60kNFN*t z@b_Sm0LMS}8VI@@OGVvyUn$>Ro*(w9on~p$Ksbv8J*)q;^3gXU$WzzR&F*KJ;@#4Ya?zB=Ar4!+U<_H(pI7!Ye|s4195NTw$f^>?RTy^rpl!sYnRW% zNjBL1#7N~Y&ZVxQTK8vW*5ysgy`nh6nVe-WZR~-bsRB6XAzAOod*+ZqS6b@o%QiW2 z%GZ7%piJeTDl!1jxTA3I(YWNp9Fia3Jw9B>pMXbLd4&%_OOCR>Fh}XK``IMulVCUv zXDK-A(&;^F^QY~7&3*QO=AYep*A#;;$1fKa9NF68>ubwn!Q-I`toF)Ie17}V_s@@n z&$}Awr`pBOXMYM8GGtrBPR;9ClSDLTq;pD+{Cs7}{5EvXU=?x+t`Vh2vj_KKwZkcL z7SeZyP_VvsJA7aUDv?&7?c*%;b+G6M)>J(|OwH#;UfUS|{$vDl#J{LaBGzo#YF(Ao z&7`LW4(a)GT29rzTG|R|3tydm;hnQ|Ry@Wwaw)+UAu+DIc#CnGe%_9T^b6O+;bGxF z9-z_#2DVlI3KjdmLIvRd`S=pq>Lxr<=b1uU`jT|>1KpcqKWrb?Pify;rjCS0J-bF< zUh_A9@+n*_tZhkY)BxWLsX}D}a^t?G!#!RJk;WHyvt!dv5!uDc%^y6PP@)%3XOR9i z*11dg%TP0;V-N2*+<#h0`RmaLG+R@(!E${mVe)pr zT2oXv(X-=Rs_O~`~(_$fT;-2c;d+!WR3is&T3y{hbEPp9*YplmvK|)JWE}Qcb zNMEqy&o=W8&};_J8A2A?=AsDVujQvtU{Fz@=W-O|I3SGUex*;>Gd_zv0OgbgLH494 zAa3IJKDfH{q%OFE|C@C6Kil+Cp=ft4M>A8svQmv$J3{70Ui>g2g|+Jzdob#as#F6@2UA# z-efE+$tAQmolOlD(CJ9bEi|a*oKAanDhB5SyDQ;FTY6fZ=#L#w8(->W-8@zdc;vO* zErbVX3@YFOx11jb5yxR&?|- ^Z*22nxjxX=`Gjnz9d@JJ2F5ds_hjnasK5f0IE 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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/mew.ogg b/gui/public/sounds/mew.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5b7de503ece7ea1157db6dee651139a1c0c43e74 GIT binary patch literal 30095 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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/mounting-reset/init-mounting-reset-with-tail.ogg b/gui/public/sounds/mounting-reset/init-mounting-reset-with-tail.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c3104a524bb8587d94c3aa3518dfd72616ca46b6 GIT binary patch literal 42955 zcmbTd1z1(h_b#HCg z7@<};WLCoE9(gXIqAI5b1~)woce5#Xw<&i&t;8UmIzO$tAf4$Ty|W-A!r*`6x!=;+ zUA&(<1q8@^#uvZJ@R^GE^9tW*#K7QU1ifB-?d8x4?Ym7MqgiRN1IX8-RfYT3;Qh=RQAaw6?=qLxsm?s8^Ez2|T@0LoNU znYqK6>x~Onmx~}6-?+Z&iIp8VmVNZE5bned0HPeE9ZsY@AUBj*#+XfHATz6q@GA?p`K@^JFe03TNJT4o_$ z%GkFM)fBq=!o-w&3EB=4t%9;-=uPU#Od3vh8I;0E&i$M7!bw3bDI5jMh&EEOI*E+H zdRC*!sD(3{U|X%>P2jyw#u|rlbfvzN z7f1gq;D0s839suDY0oEWnM!K8QRaa|E`=km5nKr+E;$u^y%Bu3F#1Z9mOkT7QY<5r@0w~`{GDF)Fm(VlUR zVC*AflYBh!{*QlhUBblJI_s3h>A#_Y%N`P-1OO;fR8rJZhg_c}kEsWqg$h1~QF{wU zZb+qfA9<1iQg~iuLou&DZTt}g4HEC_|(3 zLa2tG%cYx#%BrYk75zgd(GVa6;4)dX)nGbTW7PK#nfJTFcBY1M4pe(;1r@nu z^JK08u8_~x;%YPl&(;1V3&quhR9yA)wi;x|-0Dl2U&afKfMnr+NN{YD>G?%qTdQO% z90`>mYw79l@gbjga3rS8l1m>>O~|U$ zgnVYg{fER?n}{#WV^LAlT5qVt&>~P%t4S)d{g=G6pZ5V)P*fwQW|m~#%Q+Qi)?N7z zSqPHVAPE342r2*raC=2T7D8b30PucAGah7HR|T^iu3UtPRfHW&L{cb0=O=dz5v%eLNPibH3Fk-^e1Gne*p#K_`uPTsPsUbfrd+344o$S zfw)y+POOw;vO zgJgsrVsduLB-nYM}!;2mm2zS0%_e*%2-lsZlN^JPD9dGSPR8 zP~ujLGqbv54#*jhEg);}fcx7kudoPQAXGJuK|t$i#QzUhAiy#@79fhuQyk%_%tfGS z*)0uFfS}?)p)|!1?EB zVn>yOuuTTV=yP)mI65g}qm^xxOv1$IX>un&+fag}bcw{2_#LVJQMpJ}+Pb8JFjuuO z79=^O3tgl^(j->-ELQtt#Uy>MD<|k}l??E0n1X(n_Cr9_(h&dz%8lFtV?I~3f#N~{ zyg+L&E`8^fVN>Q3n)GwLk5ayK(o{n^I!R5iz@dXa8!9E(!A9yk?7RL3#n94RBEYc* z4)b*-x?qcMq?+{ep=G&*ajd6;P6@&tz)2){=m^mn@8*aNE*XSB5?#XhP|^Y)P;OAT zVu>>rs-p3sX1QQXOBH%z@iS0@_KUFtB+;{CW3`!BgO#P}b92U(KXC+th7Fu;C`Vpk zl(KYTwR#vwR-h_aSYsR(4psrNgKuKXOcQs9B5teQpwEp~-WRG?RJLa5T=bElsT$R` zY2H|rVPxo>_1@>JjaHUrApi_(%fx?r~$9=`8&DWn{xUn*eYE zK)X^gcc(s+F=1e|H8ZAIm{>@?SttD(_4*|ErWj3??pWo1txy_QS%%jPc{t*ou{j{} z8C*xT2Zd@?r5}P;h5~344eUokKvpyammw@{oE!l59pPn{<74b7nQnS^dQ#j$seDX8 z6r1Y#D=K3SN!bFF(9kWw(CIBDIl#%qGs?=E*#|svb((sM9e^E3L4c|#ihw0w_cMf7 z@Fxo0CSDvrxYq*%8sG_)G|)pF7#Yksm&}3do{EQ?9RPwH`R4wlp+-7ALaL9lF15!P)BH&>HbbCoH!$W5B1ln&PDh-J8Sj zu$xl0{VLHwXQ>VvRUWaGcJuPCot!iOwUJs84PmW>)z!DYb+whTOEPS(4{vvu92`vZ zJemVL+4!^s7#Uu-x=H=MF^$rL$~z08?;zbsu;M;N?vfJ~OHDS=`eYsS=CU&{z}FwQ zJCp1y9i~R^Oc|H61-VkYjd11W$%3JNIW+mtY$>;$&UGYZ(uswGX*6Xrj=xfJgo;H; zKsB}$(rQWjv1`yU!Tt?3p-2~wP^Y!M$KvWzZJ+zj@80yOdXcd&yaC;;!MgrfyMnBf z)Otc!dT0B;d@IwMhXh`HLc~M9@z2axZ<1SNMblJ%Ma!MM1PgGiWUT%YhG>(&GwZv; zqG8}vI!EVc1$}M)`>L7PM6m1j6>Au&k9x^= zee%)CRt$088HZ~$k`SUn@9PAld`kUt!VcqDcWv617p^B+3!QOav}`Zd3;oS*4n@*c z&c^nj8yiE1l?NYg*keB9Gi^I47aFP)D>uCtsXALszrNwr^>Uz!;plKla>Uf$576ZMs9GF0Pt~g7ky>!KDkU zY8m!5zPdw}y6+aPWy2fSaN^^zCr=oVN(YoAMSfkl)PI*-s#-)J6M&4fbZFA-Sj0S5 z`y46Tt`0o^Q3Cme4Z$~%xhh!@6xyIF%fEGx4Nl~uW|i=^R&s4?}^3G1asL{ zgL4`a)kB;PzYXR}@)=f1ylu7Aj7GtAAwJ!owz)!nk9i9hR#(TvP1SXG7_!rVGoaP10_r+59X40vqo%h`{1UC+yCAI$$0}aUuKT(f7wG zK@#BFqhrbF`tj21EbU4*BtgrTBY~j!=M7~NqMN^uf`OlAZSeG$u5FQ$RK2*ZV_CD& zk0eKS8d5ZcCei*Q8GpL3vK0dTlFMaYMQ%JtHN*BSTS*%jw^)fkRe49I8^^AsB$cH} zE>d=Aq{UWWOd;n-YURO>`mW^|uetzjkHG$H4VPdf+F+C6t&hWclY;4N{jtsVRtU42 z$l~wcw?*l5O7&$i!zsu?7FY#>m+dpheYFX{i48O?Y$urF5_bH;H*V)M1~=whJU)h< z@8r;b+}_(CbhFr3iS;QP++f?MtDQK>(GK7}Xsd5?MoazDC%MFT{=(*Hmv1O-5#12} z)Jbr!EAr7BhRT_5!q(W~*ko(E_^o}9U+MQ#aU1?gS-HG?ZEB{=mXT21qnUCWMMg>Y zr~AR&@6jD}8;%S+Ir21({%UHk^@9bEH8vzq9JW$M)0|M*8>s#SR0a>`Q2{ZfOH?e? zVJfRuNNO!?3M<|p>SG&1LkmG%oGP4u+u#V_+vUp;L5GNj6O~KC9s;*DNC(d^&}Z}W z3*)GtE$KWSd43^`BRpT9h^w6Ss1QeaPhDtI^EOoY^{K8+`|=s#Dr0ibNdtkXuRXFS zgz(J&nWGqD+Z=^1^f_d?Nj8hXEgG-l)t!wYC1d;HZDc-jdvbHIf>Jy>xI2|*p|~ZT z@#kRa=4@ofB6W-33P0HDNLjQWmkMz?p_CjB=z&+aLfr}e^K1et! zH4Uaz0$ivJx_9xi)cLl-w{*Mfm(i9XEvhYa>&1R!eZtf}-B3v}?1d9m9L1CYgR~ag zi8F^*q^qJ5L|%9)kf4=Z&-mehk%kVdYNpLl>HwvnhJ=zy@Az|t+PqF{L_n3GqGI}u z+*+&ml-B2U$I*@)VfmfNAu^oApmtIxL) zRG)~l?oVA+zYg89b>pGw>E0AmZ=G+M&!DZXna^KLs=q=CD=EpDOY3oQNxE_!ota&6 z$w)8C7irN19wtUinpXhJh4yxT9@?H<1r^@vKvW~N8+KZo{~Z5%l3J4fmPJQL2e7fn z0&eq=mNkL}=v#L#<86WZ610P*Fb`$n`Nh{L%VIU*AEHc#)`^6At5rDK`F`IJYh3f` zc=tAoX7jmUf9SQ-xhS)b8lv#vS_q#9bVcsumW!?*R@*P(V z;|-|ak|)kCYdm7)_Md8ZD>c?%Ry}FjlB)W`7S9zW@E|B+K9Uf zstZlteg!5rqsoPsf*RsD0Bq8_J`Qq+uK3^jrC$kOOegX8_|lD7Bs8Ye$31*$!G*nM z=Ksm)Fz40DycyY+&U=7vH~+7ywd{i+urMkJtl+evZz4dH8rTUfuHtH*^;pUlSUAtT9nk z6@u#Z(~BWgeDmx;`N3-f`Tt*AJJ&Q0oe0^@nuobfcuxh zfCMRQWA4tE2Wn|+eoju)0(*KHG$ngZt+j8No|SopDH-&;)TqUUK4BL7!sYT9k%>wo{q|> z;6LINvd%rpw|KJnP(6-`v`nV@s;?5N*AjUcPX;k1B$jMM24*=;XqH0}U?2wGRDa(> zgCGE*7*Tfj_`oA?lQT1W0r(T(xgMF;D)~RZnoH!g5G#huT!tU_xztyq;C`FW>BZKH zv?$a2wV1>*@$D?5IdtO65~*#6jkt|ucz+XqiVQr@>NI%>3}WUz$b`HQC!QCjmPClY zXGzj_T6r?AJcg{X$6J=bbiQ@1J^Lsi^@# z4!q-5B0iOPv?#EHR?&ln*4m%vgu7R~r@Qas5?|Ad{)p*p5B$JIc;7#83_^+mSYCBB zOe7Z-7YIE$<-HQ4Zs|7L7bbfuC0-153rZd6dMVhkmDR8RaQXO5)B!Z6u zB6XA72>r~}1~Dv$WO}85fQDU-ANkn&Mmb8VU%?*26j0I$zAm>KDXhE{cq7L1z+Rg@ z2Of4Ftv=u$vu!BSP4$_+61u)dzhPEsEHScr#l35zUv+kLs|zu~JUG84X?rL-*@{X4 zdzx8z1i-4PE-(1t{bzU;v|QMBo^o$Pa13>)Ttx>NY&alz)awZ>U&#!OR&Mp{+UPCO4M3 z=pPv!E@s+6S^T^m4bA68ewp8SYl#bTV%O5t(OiPrw>|G^ZP?7HrdR92)z7@ciETbV zdGjf?z8&8!^HziAp4Qf~dNOx?U);V`rx%-yFa4ezC8jm5vMs_P9Z;={8f{Li0?e_q z=JcxD`tb^r^Ll%%NEf5|DHnx+BDaB8tYtFWQ`>HFxmxJjQ)7(gJJ)+|7W!4Xas?t9 zbNez}f_k@`x32i;JR?O;LqEN1&Fh(F2EUB$cpUTfAo)dCm1v2l9c5^I?|$gWnbGhW zW$%xHlYc921>N%yOxRTPR|wgYuQSjJ1*+LAtDY&#)quC>`3TIt#(Q)8Rja2_(Nx(h zhFo!|F*Nm~w@z2}dp2vcXJoFM2|K4=4-OE+-8>M1hAA{uplt<(;9yqqkthSu3k)C8 zWss4;J~0h1>0ztDD%s@!*)pOd7H}gA)s(Gj>$EQVr#1#Hsy~$z#GpKSVi`}&|IpQ} zJIa;j?U8;_PQvDvMXulie{mE;L4Vt~!apAj>cTQWe;SYdtInzg1<@zDT@jYO0T zF`_(5OvEJ0u$$Gp97-G4Xe)OnGF*+BCcAE~oaMvfxDXY?t5>*> zY&7EkB-^E+Wp~w=g-?EgSMxSje8>rb&mo*cwr@}X%RFdb@WwWRB1+pXiJ}HzFOHb` zr^Fsl9bx|JIk?r90OVS|-6j9782#9^uLv{ts7_+}JKP#CAoU2(fy=_e!=i) zZtmQ|c4PPZtxW|2vI~{7d)J^TXB17_r`i&vwojkVwBU(m;HmIG#}3MW7qGiy2k;CR zKtCFvC4d{kCE&{7zc_dyJRBYZPk`sZv&m4uu0o|pB~GSpXEe|PUQmp}34V}Kr@L6k z2EbQ5R;K-avO?E4_{}iJj@%~pr)-j1C+kW}^D!4*@FQNgO_y1r0>8G$uBRrC5k5J_l8lDo_bH+w^Fk&m@t|DH*MOp zjS$x4XAk@4?H4*vhfZ0Ob4d~4$1?ire+0bcPR{q>Z&jQu87nm#=nErZt$ z4babb|oKd$?OazFZ4z+jo}(7t=P^B=E{m8bce>8ul=$`1bh*J z0Ot}m8!GUy%mN^YDu*H8BKKE9@hRmreaABV0x}_RaJaTusW|rh{6yI|KDXob z=X^2G5;?zR&!h~#aY>SXJb=MvqQ44VLOh4ufR>*ge#4=&+zAu*hjI~fF$Y6-hIp|b z0YE4qDspNvN^CF5fpgEmx|~u8A+sN(@BR9ZeIYhaN|VnTH=MWKN|&r^SH6m$)xYo3 zG4e7RO;;{zLP98!JK9|;y49(lbZw9GkY+Ts47xF^#pjCVy_K6co>bb2#oIi-6=3_i zoSAErJs1p{)FFB0*Tw~g2Bf+QJfHdI(tq6>2TJBw_)l+wdNXwrZoecHca_X z$~75S`oEJJ(hkUHOOcIG$#YQp^ zC4(<<)Q%EZkcP*^JtdP;r(XM(#?*QneoH^^(q-R~F+9{6Gm;5m7xsXWW0InSo{Vt? z>^rdP#Z17(6Kk31>T{Z%H3dtd0w`J-3G_H0-`}oitEjjhqO4hLx{xK&@o7KdY1tfz zBaMscVJH|r3;p6rJW~H{M&p5wt89^Sd*NF2NJ4k+_wNNGiKu>G}{Oaz`jovdf*zcMtI$%Fbpy@1nL|UI*{_2U|Es)}a2)w}9{)x9`Zug4H zy0B}#H6g-KxMuhADy&gZVew`ct{q)yZ!Yv= zUqvTL(XO#zy?j^P5sedtV{QwRK)?Z_&iSb+?ABbFC6jb&VAS7EqJb1lV9xBunF1nh z1Ti#Y2FTVQw!@!yh?=MleSKQ=UEWAINkkIHQ!J}wvg_(j-oJ416V^>*=1c)9vWOjN~kG+?uDV0Ka~L~`o@wkr>f)4 z=;9gdh)XTqCU#96dX~q9xx!$|AFQn3;0ficoKzh`SmK8$@ARZ?yqH7S=*MtAF1HAb zY!Niq)L!GU&QSR|Y~X;p=?{%wb1!u=k>knroYCYHs7ZtiRpT6p=8IbIuDNffi=OUr*OKBur}ei`1zGx!ITLNxA>8CPW@7lvT{Hj#m>!M^NH7*!^{Soy92z4P4DOUOWd%n}$OvJ88(#M}1D5;pVv zt@HgEKLGr&c;)y4MZ#s{*y3WIw&aa-g@PQ*x$>vYUwpi4IL1#KUDs|ju8&v@1PwBn zm&ubWM6=wNlRt-cw>$vE<$y#ky4L zS|YxBj2Sm07hBzo_#t!gE*Bwr_Kw?J!lxg}8+~fqUsRYjFU}@~)n_F6X^Qx#Bz#JWiK4O=^je~O+d?< zN{>jDt2k@g#>_9CNtTRoo{Z5aUl+;VQPtK7y$b!%uhz^M!BhR*#B6UtXZ6|S^3{1# z!c}vPZZgtg9081+t0FWT6JV!hK|RlG^FUy~nYZ_Q*FyXbVVG_C^ien}xXm?y57{xn zENLkArk=HZz-yy`-GAAkl~NQ!YV`R1+AUMTxnuyDO?%Ek^Hyhd4jYK4Kwok z&1|a7$OOo0Oi90vxXPjSU)0r^^drQqwI3LBvg{X}sg8YCA*J~_a4`#m4e(}^RIQot z`7t;Dmdezc&OAPM6C{D=}C^SXxZ%#y>7f}`>~sy^@0<2j#`=uAAWz- zwSz#Uu4(&DroGF+Ph>Nd4$^*c!)e94n_l^wsxRCbuCPz4!?ssXluQb6tW;h28gK>HEd}?544j9m_D_nJN^f*mT~MfU3i*Z>uKM8U2Z)yin*hKV00|U| z&wrha(t!z}08-n!1un1_U&m|=pjgNCD-QP1Z7!xMSKU4d`ad7w9_3KBDs&KQ9}`DAklvuy-iBmE*dY68&+}f8^m~$F)Y-3?7kvp^Lort^ zzBk^ZmeJi|B95iGOZ4+}FPP!`HgD)29}BimHZ@M`G=^O+ZM4A0Y@^|g3TGjF0`3+b z+q)tL$%5>gm*yQ;KUvJySX+1Wdu-+w8@u+uG0?f#sLj6dJ(7j_{<6bUExk6waIM=q}&2i@1L z!)?w&H1(=Z4S&!4x!h{~3~2$}NdO>5tq0N+`luJZjW9Ch5j+1F0xRdfBRmTOa6kH) z8Lw{0@94Ws`&SI2)Uko>vsaKii=^AQT_sSnqUI>NqDB-N zI#`d0hA8;}YW}JXM#)Y=WPLceqmc!k_+J?L(=F{OOl|^*f(!!Ji&6R(Z$U zrG=z+dQ#ttgud-2PGCU< zhwS+qAp)|b?>iy$gqW$o@xDRRk3eBr6y!GKCd`8z4B#A3sNO~N*F&@s@Iu?2H;S#C zXejewX@fB3r)Pe{vZ_+;tW$lA4R5Na#Tj{$FBd&vY_fkgg9O7;`+CFbaC4q#MT~2B;VR|Z=jD{Xr#+)=KElE|u$^)=dtFKS za+=i;*_64}-m}cw)g7)`J+vpgS}TRNxXjIAz-yBlxjVIJMvTaD{XPb9R7$a+(KU^j z=+)7_)jFkr-!l%6J>)2S2hWmXSA^n)-V2({L&&KiFA@#r(joOzS&JWb?LA4PY(U#( z`3qKL*bCeIeh)E57$HT(uX*eOXb&ouqrC4edgHH${*d7|WSoA=x2h2G#SWECc!)1% zv%_3G)quQ?AQ@bQW+_PZCP(bs`_xh@&WE29!+o4`I1(`%dB0Wd+bFC~UQO$h{E~EP ze0YGkazyTm0}Lx%`}802zCD@)(O?De&)$}X(Q zZr}DhwY&4_F+<7tyBEHUQo6K!A&94}hZe=z!ksZqu1!4`flwFMbpO;ZJGfT*C6(i! zb7xyvneu5C)sxxeE;4qX|Llvb8AVOnuOmx^za-JgRJQ}hvS+h#&H>n5zAB-e&7@=4 zcCCKTB*J?>in=HD&F8`&AR9-k-U92es|x55jdx5%XSH}inC3UL-5u{gSzbr&%%(#W z(M>{)`^Q^Yc_h&%qEnpv{#)74mdRs(um(I{RwCfVq-Lv2k=#W};-&nY!gT&)XaQ-m z?&!6BNIRm#ya8bCABP8Bl~7t9r)4_urkYnO4b^i(1+eTR{V?#`0`?6l5&t=$@V;Xk zaDOl2&J>4*qx#~(%iwMBA$U8y6y6N)gm;1I_uCFo=Ts^UqITKCsLIC(BQ4<2cDAsI zv|u+tK**G!vOjc%Pk68E`}Tl-p+EF>3be{T6Jo;^b~uD`@NS^%6aeI}KD~Wpf5r&h zXaMXO{HIU23%6c|^CB-J#^^U<3S;xpf=)gd+Dh!bxcTS8-cmIaXc^WsOJGlB75Pmh ztEw;LJL=K?{&uCXB=IMDBq%KA*=I$0{*{2!W(@LQx#KEN3j@e=@t=8lbHt-Ko24Vl zlr7Hfmo263*%6QO3=JTdCC+KSi|~HrwBXj=J=mF_EYRXNk;K)x%3!7Sfb18+SB9 z6JPQIWpOEFdvu*Qg}10L*C852yk^zu=A5l-H$(jeWdeu1H+Uwmj!5UAX=z?{@F7ba z!YA!#{JVcFR(vVm31l{DlQC=xv96-4EoV0(08x7kj(Vq2z{8L4kZ!9H&*AODuYd1w za9L|?R6e!xXHZWW;alx`9$Id4E!jaCYU@qzg4#khVlrgXqR^K=H8hzKF8mVJ(PuFq z5TPLF27vSPvq)Ej&Ew72aL=vgN0ENat^5@w3w*GK%qDLdci6K(Q;NV3Lm2nsjipAX z;|R^Y3Kpq(_*Jv1>?p7O@vGms%0_KSyvRRl#exnH4PIYF#@hSUobr12A|xrc*%nF^l}bW>y*5-@rDCk@L}1_sZRWkUhzU`Qz( z`om`#6{yTVta(KFAj7smx&d2eo(*T7H0{0Q-oj`?oeDSDo4=&a>>daCDX(NGDO7mW z2uyQ#<6Wt3cr-Af8gRA$Fk@krd5-8*phei18fe%&DzG(iE*me9WF_9LvZ#i!Xz7*V zS;FhQK{}IL-1uT!Vy&A*gUoKr>tubi(fhaVP0gBuTS8yjV{e6B&J|Kz3xrhvWG<^L@IH zi+#G!Qp#Y@+EtH50NRenP`6d%8v&DR6}Yf~K+U!8mq#-GS7!7YxbJM{36{R@D?~{6 zT`PX5!Y*0Ol7;r2%v7y3kLPDNq~O=9@RO#n6kL~mVYJd*lza7~kSK2DiQ_l$0PyV_ zqPb;&|78cNsv=~u`sD#!-aB^KE5hiI-(wf;8cNqJzCFNM{4|xE6FhWJ-R0TV-T3kR zjH7s@L;Kyn(+yWuyis_MeWupZA|Qf&wP%p=6mb0gUf?N=cv%(k^lIZ8oqtnanD>F` z)Y38{si6}hVsgn_^r6WuMCp1&fWjz7^zIlE7NsQ1KryZwVv|#oI5}>#W4cPxy4|u9 zxipt|Bgm>-=CYBDBALB=_Cw>(7o=NZY{e|pQlhl zdd`wezIoGRO39~v^VGBUye}W)E|^k{mEga=lG)u1v`3*`{-K=7&?!T<)-=hl8g2JC!hIu#%XK{J6qgpjZOT$VTBu$V4!qIKd|Z4j**`)-~o|hQJJDXAoN53ISa+!8wk3ncwxaZB6WFY?*S;n)poeb zXj#FcOEOi#(G=DPc+4^5&%@N1z^J2l^qic%m51KPDr%VEw87pGFqY8vV^1)yVvL5@F1+~7Jn(Rvp0-T^&8w!s&GuS=)wG+ zaM=KAVMWPVhHwx5Pn3-XLqD%ih!4pk*@ElZKllCgo((yvP4hkd=mVch@E*kCrQJVy zuB$&%m(*Og{a*C(GbSH0{ofg31;S8=I$rD^O2$Q-FruLRiehA@3^4=_4=mh;ALOt{ zYBX7XgLoo2>RXt}d3XUkB4$76HqW2O9gsIVE&1G1OW;vf=LUK>NR;v|bk(NT8X-E! z(7nBs1_0rfxR)zXCL&dFw_2lEggW~*?As-&G92$A4*JpQ6WUPD=h^-5h#u+8IEuOR zX&&Vv^vqwMu)xSa{P}{rjtQK9n&qckeo!8A^4q3l44p!db>kZsSEIuZ+Ed!5q4_xk z$N6%4UQJ{G_B5fT4U@Qz=*zFa_fvtrlOWRxi~h^dF(Il;{+ZMaW&)46FtU z`@tb38}u%-O%L@y+`^;MBDtJJAr%vWq`#(hb(xy+y|j}%)}&cVk3)F0gjg|&y4BU! zr%VF8u!eG{eBc=PFFXpE3J8CNJJfvT{CSaPKVDL#Z=rMX4YKHNXUDemL*#Ujz&n1u zy>MBIWTqzWkO02)&XYvF|7PJz8v>)TCoTxAd5i(EgZ;0sTKPA0-F zMv30X>W9;%&z>2!{sg}$1wWRolD$PCu6rLeBjBE}*U&X8LqE~w6`=+4c>@c5N zAmY@tq&dH7uZ3akd_<&$f?R=iak9n24 zI3|a?UpmakZm)Cux=?j)1ezf-&qA((MFwCWK#3LmP}`6f@5y@0}Rkz=6P9B)`de{kZOcS4o z^sybcB*7bwTQT4>v*WZ~43GBN!j|Owrdz9q7{y*=Bs%aOP75`u(#A`%EXjDyKrdR& zn~t8#NBumlOC$E!+4)>)F?KLbh(KtQelvNyOm|h>RY%k#$qiL_6VLsO;;h~J#t!qa z|CE5=TF#wxDWXM=F!|hxit~-J>5DLtIs38{$)fWY4mgMTud5b%9p zPP@WCvaejw3>^tdLF+U(fYy(@SB9Z7)JwOnpNwO0|Bx+DbwsV!A~qiSZnH149W1vY zkN~JyJGf7o_G^9vT#_(lW}qeRSsT0rh^wgUD(~cGe%}EPxxq{G!H5amei=+!oGy2kWUzzM37kFP?0(w1+ySKt9HN zMu*588$<>^C4AV%&NcQMb82xLE{sTxn~Y`cjmhpVO>uw0qD_-D!(L=&``d}U7Tu%# zcA`k#>TPIR%C5MB#Y@Ls8lM{BNUcWLXnp5UFZs@G^44^*w(%$^8xl`dU1v<(u*~kdW z;L$h8=GuPA)*<`usop+|(GnwH%3riruMu65!53TP31l)-aLfA>c@t!RAf9{-u^kS8kwxuMYY9 z!TJ-+j_3iZj5+l!uf$T{p0E@Cb)$?MK1BJ)UY^fe>Fp@t8%Rz2bkPgbHm!%@8jY$* zQwbPvo*lzW2vwOEO)O{Mwz)CW^~0&5_#b(KSxO&0meB5~I5di_dS9LKD8KQ8MY>I7 z#o#2nJ^+k~K&~y9f9<#M05Is)UYT6$h}&^q1{=w|d37cvd&y@ANQHeR^6?G!6R!ex zpl#@e(YQPV+S@y*fM{b4A^M%?0)8koH&0K@CT>N8W~f||c_f;!H9jD>(EM%3qQitf z=FTuyZ@B2ZEnC^xUG@{khUMM+ zgf(N#s+@4=yv&urV-9~G4$c2z+}0;h2wB`I)tnOZh-rv8l8(|jsZV?&HQCy}ms%^1 zwa`yhJ$;s1^JTTb%RWt8KmegjmrrV7H$H4N0&-CQC#}M+ep*xk>&-+7X(>O~l@(A85;2EOTuIX+`A_+1 zypNgVx_U}F+xS9~%L5}Zk>!YSr1-AwOetLMH1GsoV*0szkBdt>bU8Wh-Fn8_IfM5Q z54QVF7H7zahIY1szWp0R>-?YV7qtM&koL(Jucu4)c4Gi+Tg0Ci zTtt7+JTDvBs@KkRG8os@CjkTu6&zpck^oiN??ixy%eLf(Mby-y_qW050|U%Ry5=(# zdkQQ(TZ59n_6wiv#>n#-cky_%&UF`!9VC+b@$Y0{kNF5g#pRsyv?(Cd!nIA8yb_*` z-}X~V&><&R_T61R-WwvPXsu~9OnODnrG>A{@T;HLPZCky3i~g3eeo>)<-c}axpm4) zzS*c`%7fMYDq^$eo#CJ3RHPy8RAwXhtAx15MTm|uRDu~k94KJJsyM5#80FxzRJX-} zs6y8gP1TT+uyUf7m6|0JmF<3xC&4fKiTsmaUOe`Elsl<`uYLKGeTvEaG*XR<>yRJX zsG*7bV+;J(`fLwkuF6ZwmNw+QTzcoWcQ{ zjVW)xY)^&v!liB>BsL}?bf3HezeCus!uhoO(svb(=ie=vK!5w?=Z%yTwhv_^w!F=n zx#?R3MD^jEHTk>{F8it9OeE78zL-f<{7z5W6VGZg2GXk%)g1sJ5>t5D$CrZcbszE0 zhpEY}WNzlR9|+{LUN*2-f5!>XqoX}Yx9U{8?!abcC>1WImkN_e^mr|y13&%o$Q^4H zBXMOdqqT8laxmVGK^^dV*LzFUVpln`8!Y0!_vTjf^X!iSF;fn;493c~LOzI%#Tw_O zNSX4&Nm=ulI_Ap9CxhduYaK&+gJMr@Z_vFxf9Su2UZgKj^4{vX<~j<9IQy^XcQrx2 zDA!jPW8*uKs}vUN3G>tZI24?4FmAM7A=1n!XXQvpcYfd2+c;xjhkov>vT9W-qeR!N zaw9^(JViXWJ%y1WT#;}5pl3q$${5EWaxT*MA-u?`m$n1S3zg*?BqOgsDdQy zthv}g-_3seAceE_`h8D|=g}3*xBfx;TQj@?sAHPq0mccU#)}%R$3qE@G4^ZR!6anf ztDM(~7}esc%Wvr7@EsGJQggW(7ps=$$l7o|wFF?Y3>!uKLcugeUxuW+J==tWLqTn(BBYAj!0Ljh6L;rg)CmEyX9m#$CxDR`ZEIxJBn&Z08RhU>& zY%twT>mmI8i1EtCLmhHN<+*%iH&a#{=VSO1VoUxo$C$l(6^TXM_}HAw2vXFK1^9NMZ4KCTA-_HNn-7djavc{5tp2u+Sr2LxU!wjWh*6?i1VH z9l4qFSN;Vfm#oX9s!Z5XE|`)ODGH$hc^;y$=30RIhI*hK=@W2>MdOZWzVw6?h6sSd z-GVDcqt(5v3RImcAsL11^kh-+XKQtwh!JId4pWb&<4eZKFG&^iMpI4;;)9H8(;*ByMqeDoV=|!T_}E-4qin@OiiLe3Q}j5= zOCaJB)(kKHR$=>jUVT=8fG~+^o6Rov+0(N0NvNBH4)D?)sbMd*!GYp#a2rO8ZrFAq zVPn0`#mn=#%Y13r3nY2)hl=-Iq!_Q@1Z_9;cvcnZ)xr)WyX2P|<#vw`_kl(7%g;x( zM4I9Ad>i~z{ZogC7=sDawe=!4PP<|{*YKmMzLfNwShqno^YLeu4ot1(pmDAhb46g< z-l+t|Kbvxq3UEi!wp|^#U6qYR>6!}$nU>T&g9=8FOs9oyjcW##1%I2XDjhEaa5Z{` zRKJkud11o=@l@8!o_(sK_pCcc!X*DzoU@-Si#=6!w+=ku8R^z1A$x>H(=uafr}?9V z;%kq_TZH55kzE4ac0yh7d|3WsLUxHkZPebq%tD);{S@w4e%^;yELoC@f9EGY5Z6rD zsI<9a)@2o!3XN>6T|RV$j1VW2f*vU?6qUb13ta3B6FSc-Lc3i~+%|^b*lKzK<|~^K zFhy0;_E*`gZ9ACZ(D7lfg`^xUbK;Tv-r>b(2z~dkF{?7z^i2cr?q2dbZe%}mMml@p zm`k85{s>FZ|)j$zWV9;c?;`9drkLb>}NT%ZDEhwq2PR3LW24O#Z37W0!3wq#I(^G&#BQg^%(1 zT_JI`mDtjX{cI9xixU=HQYLC~Q6WUe%(gHM)JW(y?3+SwgW1u($OlPWqbAG5O&K;t z6xk=74cwalLsKz>S7rPH`{;?oB1MpB^aWW?Tlyr;7YNI@^gj!lL$jCSl3g~6u+!E> zEv(U+vs_H~zGMSPcgBjEm4bo;r>B>zd-VtDNB_maKPJu3J4dp3b4XSP$ zR^wtpH#XxC2U|qcW7iYcX_|qu_6`6EXmk|D0>B}TDXmox^3zwu26chio$27;uWVtY z05pN8=ex&HBDOiT#$LPaYSEAJ@psA54oDVXt8~R}?Jzj)H8ZKN|H_&bnu_)*_NQgp z8C7KVIwI#HThQxXd+@FDBy&G;_^EvN!!f3OFqV5nVsNOFW2GXeFz!2f*@LG@gO>3O z*5ox-<%D*(IU7e=GZwe?@V^-6cV2%>);{wbVS918SYrCQ+by2m5N;&19t?6aFY;`n z2Wu&R5J@dW?cleZ9{A=eb@7~2YU$BtutC;(?g~FVZ+Eg}LB|!pir$>noUy%1mH49G zE>Svp2|g3KVs(7cWMIlZCI8!1W&im~0Y+{^g=!vcT+uvg8SVjoodC=1jr__{Q$)WZ z4pM4P_^SUAf`JaY?d7H-4denpWI$$_U{g|)b3B`N%k+B?!bz#$!3K_Ra4LwRG0P_| znZS!qx|!_nRhutF5y{B<=Y%1k{`fekhq4EvJ4BLm*d&$kaVSMG;gCA3s;<;9{Hu`ccQ7cUnRHtoY(5rJH`7r_%T|@6}Kg7YyT@V#f5NPK~U78q*n5r*aY|)^|Li2H;#q_!H9au_v&a z!yFNU%PZxrPg+}%nMk!>nj~Ic*Tir-C*{}cwizDhb455pY6Ps|>DXd~%<%o?)_P&^ z2}Vv}Z?_buupog`;)6S<@66THdVK3(@dW?475qX1^v(e1qkk^Rb~{U5Q&ec*n}P+X zbw}T1t6O0M-jh=Sp+02m;Ggd)CT9lq#>CK+7eqd?>veum{=W^5`Uv+Bap554qbp>H z1@n5`#@xB2Lo^Q>%TBT6{EoxiAMS?$-hnPq4Y{OfUyR1FqgX=RNH-NbX&8MLhtre5 zUr0!2OR9}nL03Jio_<)+PBCii*mh;LJe%zau;FM$|8Md%h^9-oaJ57=mz3~4@IURJ z39a1x^S2!K#lUnR(=oxqkk-iXmsntEnNYXT%-v=13m-&8HPkXQc>TxIyqd@1xRTX} z;il{Q7wJ|)Gpj4Bw^E7n6VkU1G5#J$C?Xi^ccO<~)NbH18rFZ5GWcmwJ|rE!n}K3% z@;5cTbL>`3h#9K*oo8*Wn~_t*YsP+B3B52wd_T@G33T!u^#!3^Ye6|1Z>Wk>BRoxC zJ5gC$zt$3x5&RR3ceBW3TgrsKYIUz#40f$qV+7^)2NELRYKF~*JQYrTo&R}eO~mN9 zq(05^SMzW1Ab4#x>0D_$R913cYk)5Hh#QWFZ_D(|lwRG9(+A6Xy+0(OKJDjlVIoD+p0m+|Jkvtg zmjs>O7w*abhe1m;Tr3cQOS3^2%SLim5~yH}T=^37&LgcJnV<(fB}h{+l;q;w&M$%r z5&-Z*ggH2-PUZ!i-oSXj*N-+dvE7&9bihY~h|so^Gw zII+4BvYcRK1NL>M$RC_*(Chvi;HQ@AgYfhD6S!k(T7K@eIE*LaP_MhoJsL|J;Fj21 zq8i5O_h6iXNWtOydfy9_?{W&ukxYi;jQ{R8yt4~F2A=XZCiDK_drF1j6EU%hU&LDK z^Ob=+by8x;YHp;(`+`Z@qm$uU9C(@Es$+8JOWyIx&QT>NQtghxZvV&a6c4S%&8yS= z2?Jj6p+1L4A?<|5<+ISQWl~Kk&~3w5CJr5$8V)DYCtyh`f;aaFILadXv9D8Yo$|uV z6OgLn-Q(SHXNvMz^=GRW@9%XY2HX7%k(Fyth`o1$>rawSMxCisZ6%}+l9B)rOY|Yp zER_<7b|b$2YPZG0GI!V#&(#|vtN;3WJYtHhbvutF(@vnk7NrwXdE?G0*&@lc)=X5w ztAE=PwSTAz>D>OMt2}c>Lt~hyryJ{tn0A`SugQNd0DJxHO_xwR8@-m`%;!t?6WWVw zpzKQJ8MKv1ib-pwH3yjmG}dYW!jF1Ms|qFH?|0I?)>K8nx48 z+T7}fcWMgL5UgPibyj@Xxbi#2ktG^aWK~qKtkky$F*&D8nD6XQ8vly>QWkpz#s+R; zzH5Pd@3m{r9LWSrXzGvFzqWX~Uec6O5fWnlC4FVASM?23&ye3*@X*bh`=1#DHuvtV zJP{(7I1R%$yg5^zwf?#{K+@~Ux9JW{zbxwcUz5+!ziH^7CZB(n%uTNFHsd8LlS0fT z#u8I6|GyGH5`!;)gE@TK-MwrSvY(25d$7sk!#xd3pt<@WaHxRE#3O{1;q{qg>QV8I z&%BK1aZ8fzKv(z7Nq~v-0I+^~W(kDe`E`-+25^-VQQWZ-trJ+0RP{%7d$${WGUR{$ z(Imq0@@+Gz>&#f!joy?ogC9J9&ZEmm*~D6D1mu^1DVk|u<@Kh(|6TP13UnJj89~3E zvcu*kqH8GW1ad69> zSTQu#JR(@H_Wk}GFk}go&p)CFNXU%lv~a#+Z`#HwfvYPRj(gQZIs__f0#bs3M}IhPYu`#-oz)B zxi(Yk3l7xhr_Cq(esY?odP6(XK(6Ly8J~H-S1Ulgcke;33SAz9NucoEl-iH919;41 zbjIQR_Pg3Q>%Kn#`sk(OyE@X z4KH*4Z4%@01X*FrYYw+dQJC8D(OkN9F!VzoEhf`d#qZ#p_a^8~nosE&2aD#b@2{Lw ztd+OI*vjm@R#J>c+51LHp@~t7MsfWa z1k3%!GQvRSjbHXXZstHRNhvaf9O$8S1Fr`E(Ri*o^kZ-mGbs@AmPXA>{>n(}=8Eu@ zkZ5)v1e$so*r&XqAuDfoP4aZUh=f%EdjDT+s9;t9@v3mS)y*l9$9hHz+^=;GpbKVi zqE%n_Ge2>e>}@>R(+9C!oLo(aIeuGO=QyVqcK;~T?}VjMHr{3A!8@PZMb)&*HSg3| ztKhf{k(3qoJ|a>xt+eHOh^z7Zd<&5x zMN1coivfpVjwjNC{gHkTZN)L$R5Kh5?UUg{U>orws5c&y|E*t!_pKk%xf80!-9EC$@p z9zLV|9T!HvbXkk#?t(gV-g)fVnos+nKjSa;(~6thGqTLTOgKB*?y0&&TTZS(h0$`# znc(v_w*WcZ@XM|ZtK_u)v8MiEC92R?$qSWCCu!i0c{e;$48tu z%%kM58Ns2|Xv)eO&_O-F_gtif?DIj+=5+M@d&^=Hs;tkfG2EB^;{W#y$H>T-B+5Ci zq|%(BCg<1%}vi{d9!A?M7-vq7Te>AZ1)4kLB_*GZq(`yX%fh~8+r&bRZ* zQ95=J$t?3}qeqIMl0=|8)*pR?z#oX!z`WYaT)7iLpp2pmPyA?GT9eSXj)QJWQ_;u~4bJ)_w)I?gtW(;3By7%0}YCGWc!BlGW z%QQ}hZ&$RnWOAEoq$2`TmXEIhlB@tvCKpA8mLZi=S=NW&fWiSui#PWMoH_IvYP;Y8 zl^&vim4u)ZcNGdX9>0IBoVKseA@NAhyisy$9rxpD%VN;*@p((VILrwzfn9`*;%c2Q zMWs`$ORTL%nYEYVP`F^mWLws)pkV2ZK;JsePb>_ylBf2YPyUj(&Qz%EaT>3zQbrpa zlw3cry+M(6X;*exT>%~U|7DK>U}8lkw1lZCCrY4+=p>`zdU$Q8x4{}5)xCkwIIb8V z5FeYjY~(-GHFUJ`T`5($G{Q;S)P^*TB~U9pH}AaHqNfy}�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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/mounting-reset/mount-click-1.ogg b/gui/public/sounds/mounting-reset/mount-click-1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..4df5da9b5aa30ce007c61cfe225cfd67c1a4edb6 GIT binary patch literal 6414 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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/mounting-reset/mount-click-2.ogg b/gui/public/sounds/mounting-reset/mount-click-2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1a09506774fabf387e42bd5ef1ecaaf1233eb841 GIT binary patch literal 6350 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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/tracking/play.ogg b/gui/public/sounds/tracking/play.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9abee87ca2640020395734ff1d5cb557c37ed30b GIT binary patch literal 36218 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 literal 0 HcmV?d00001 diff --git a/gui/public/sounds/yaw-reset/yaw-reset.ogg b/gui/public/sounds/yaw-reset/yaw-reset.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9a7578b643f1582f407eb3c947de69900f0052d4 GIT binary patch literal 29358 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 + } @@ -91,7 +93,7 @@ function Layout() { + } @@ -99,11 +101,19 @@ function Layout() { + } /> + + + + } + /> + } @@ -135,6 +145,7 @@ function Layout() { } /> } /> } /> + } /> } /> - +
@@ -305,7 +316,7 @@ export default function App() { {websocketAPI.isConnected && }
-
+
diff --git a/gui/src/components/ClearMountingButton.tsx b/gui/src/components/ClearMountingButton.tsx deleted file mode 100644 index 384ab4aa2..000000000 --- a/gui/src/components/ClearMountingButton.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Localized } from '@fluent/react'; -import { ClearMountingResetRequestT, RpcMessage } from 'solarxr-protocol'; -import { useWebsocketAPI } from '@/hooks/websocket-api'; -import { BigButton } from './commons/BigButton'; -import { TrashIcon } from './commons/icon/TrashIcon'; -import { Quaternion } from 'three'; -import { QuaternionFromQuatT, similarQuaternions } from '@/maths/quaternion'; -import { useMemo } from 'react'; -import { useAtomValue } from 'jotai'; -import { assignedTrackersAtom } from '@/store/app-store'; - -const _q = new Quaternion(); - -export function ClearMountingButton() { - const { sendRPCPacket } = useWebsocketAPI(); - const assignedTrackers = useAtomValue(assignedTrackersAtom); - - const trackerWithMounting = useMemo( - () => - assignedTrackers.some( - (d) => - !similarQuaternions( - QuaternionFromQuatT(d?.tracker.info?.mountingResetOrientation), - _q - ) - ), - [assignedTrackers] - ); - - const clearMounting = () => { - const record = new ClearMountingResetRequestT(); - sendRPCPacket(RpcMessage.ClearMountingResetRequest, record); - }; - - return ( - - } - onClick={clearMounting} - disabled={!trackerWithMounting} - /> - - ); -} diff --git a/gui/src/components/MainLayout.scss b/gui/src/components/MainLayout.scss index 53c9dc396..a304b3a25 100644 --- a/gui/src/components/MainLayout.scss +++ b/gui/src/components/MainLayout.scss @@ -1,24 +1,67 @@ +:root { + --toolbar-h: 120px; +} + .main-layout { display: grid; grid-template: 't t' var(--topbar-h) - 's c' calc(100% - var(--topbar-h)) + 'n c' calc(100% - var(--topbar-h)) / var(--navbar-w) calc(100% - var(--navbar-w)); - &:has(.widgets) { + &.full { grid-template: 't t t' var(--topbar-h) - 's c w' calc(100% - var(--topbar-h)) - / var(--navbar-w) calc(100% - var(--navbar-w) - var(--widget-w)) var( - --widget-w - ); + 'n b s' var(--toolbar-h) + 'n c s' calc(100% - var(--topbar-h) - var(--toolbar-h)) + / var(--navbar-w) calc(100% - var(--navbar-w) - var(--right-section-w)) var(--right-section-w); + } + + @screen nsm { + --right-section-w: 40%; + } + + @screen sm { + --right-section-w: 35%; + } + + @screen md { + --right-section-w: 30%; + } + + @screen lg { + --right-section-w: 25%; + } + + @screen xl { + --right-section-w: 22%; } @screen mobile { + --checklist-h: 30px; + + &.checklist-ok { + --checklist-h: 0px; + } + + &.full { + grid-template: + 't' var(--topbar-h) + 'l' var(--checklist-h) + 'b' var(--toolbar-h) + 'c' calc( + 100% - var(--topbar-h) - var(--checklist-h) - var(--toolbar-h) - var( + --navbar-h + ) + ) + 'n' calc(var(--navbar-h)) + / 100%; + } + grid-template: 't' var(--topbar-h) 'c' calc(100% - var(--topbar-h) - var(--navbar-h)) - 's' calc(var(--navbar-h)) + 'n' calc(var(--navbar-h)) / 100%; } } diff --git a/gui/src/components/MainLayout.tsx b/gui/src/components/MainLayout.tsx index a8c6b81b0..c3ca4dde0 100644 --- a/gui/src/components/MainLayout.tsx +++ b/gui/src/components/MainLayout.tsx @@ -9,20 +9,25 @@ import { import { Navbar } from './Navbar'; import { TopBar } from './TopBar'; import { useWebsocketAPI } from '@/hooks/websocket-api'; -import { WidgetsComponent } from './WidgetsComponent'; import './MainLayout.scss'; +import { Toolbar } from './Toolbar'; +import { Sidebar } from './Sidebar'; +import { TrackingChecklistMobile } from './tracking-checklist/TrackingChecklist'; +import { useTrackingChecklist } from '@/hooks/tracking-checklist'; export function MainLayout({ children, background = true, - widgets = true, + full = false, isMobile = undefined, }: { children: ReactNode; background?: boolean; isMobile?: boolean; - widgets?: boolean; + showToolbarSettings?: boolean; + full?: boolean; }) { + const { completion } = useTrackingChecklist(); const { sendRPCPacket } = useWebsocketAPI(); const [ProportionsLastPageOpen, setProportionsLastPageOpen] = useState(true); @@ -58,33 +63,42 @@ export function MainLayout({ }); return ( -
-
-
- -
-
- -
-
- {children} -
- {!isMobile && widgets && ( -
- -
- )} +
+
+
+
+ +
+ +
+ {children} +
+ {full && isMobile && completion !== 'complete' && ( + + )} + {full && ( +
+ +
+ )} + {!isMobile && full && ( +
+ +
+ )}
); } diff --git a/gui/src/components/Navbar.tsx b/gui/src/components/Navbar.tsx index cfaf81d00..a2d3f8cc6 100644 --- a/gui/src/components/Navbar.tsx +++ b/gui/src/components/Navbar.tsx @@ -2,14 +2,14 @@ import { useLocalization } from '@fluent/react'; import classnames from 'classnames'; import { ReactNode } from 'react'; import { NavLink, useMatch } from 'react-router-dom'; -import { CubeIcon } from './commons/icon/CubeIcon'; import { GearIcon } from './commons/icon/GearIcon'; import { HumanIcon } from './commons/icon/HumanIcon'; import { RulerIcon } from './commons/icon/RulerIcon'; import { SparkleIcon } from './commons/icon/SparkleIcon'; -import { WrenchIcon } from './commons/icon/WrenchIcons'; import { useBreakpoint } from '@/hooks/breakpoint'; import { useConfig } from '@/hooks/config'; +import { HomeIcon } from './commons/icon/HomeIcon'; +import { SkiIcon } from './commons/icon/SkiIcon'; export function NavButton({ to, @@ -34,7 +34,7 @@ export function NavButton({ state={state} className={classnames( 'flex flex-col justify-center xs:gap-4 mobile:gap-2', - 'xs:w-[85px] mobile:w-[80px] mobile:h-[80px]', + 'xs:w-[85px] mobile:w-[65px] mobile:h-[65px]', 'xs:py-3 mobile:py-4 rounded-md mobile:rounded-b-none group select-text', { 'bg-accent-background-50 fill-accent-background-20': doesMatch, @@ -44,16 +44,16 @@ export function NavButton({ >
{icon}
- }> + }> {l10n.getString('navbar-home')} } + icon={} > {l10n.getString('navbar-mounting')} diff --git a/gui/src/components/Sidebar.tsx b/gui/src/components/Sidebar.tsx new file mode 100644 index 000000000..97b45e08e --- /dev/null +++ b/gui/src/components/Sidebar.tsx @@ -0,0 +1,251 @@ +import { useTrackingChecklist } from '@/hooks/tracking-checklist'; +import { TrackingChecklist } from './tracking-checklist/TrackingChecklist'; +import { SkeletonVisualizerWidget } from './widgets/SkeletonVisualizerWidget'; +import { useEffect, useLayoutEffect, useMemo, useState } from 'react'; +import classNames from 'classnames'; +import { Typography } from './commons/Typography'; +import { useLocaleConfig } from '@/i18n/config'; +import { useWebsocketAPI } from '@/hooks/websocket-api'; +import { + RpcMessage, + SkeletonConfigRequestT, + SkeletonConfigResponseT, +} from 'solarxr-protocol'; +import { Tooltip } from './commons/Tooltip'; +import { Vector3 } from 'three'; +import { RecordIcon } from './commons/icon/RecordIcon'; +import { PauseIcon } from './commons/icon/PauseIcon'; +import { HumanIcon } from './commons/icon/HumanIcon'; +import { EyeIcon } from './commons/icon/EyeIcon'; +import { useConfig } from '@/hooks/config'; +import { useBHV } from '@/hooks/bvh'; +import { usePauseTracking } from '@/hooks/pause-tracking'; +import { PlayIcon } from './commons/icon/PlayIcon'; + +export function PreviewControls({ open }: { open: boolean }) { + const [userHeight, setUserHeight] = useState(''); + const { currentLocales } = useLocaleConfig(); + const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); + + const { + state: bvhState, + toggle: toggleBVH, + available: bvhAvailable, + } = useBHV(); + const { paused, toggle: toggleTracking } = usePauseTracking(); + + const { cmFormat } = useMemo(() => { + const cmFormat = Intl.NumberFormat(currentLocales, { + style: 'unit', + unit: 'centimeter', + maximumFractionDigits: 1, + }); + return { cmFormat }; + }, [currentLocales]); + useRPCPacket( + RpcMessage.SkeletonConfigResponse, + (data: SkeletonConfigResponseT) => { + if (data.userHeight) + setUserHeight(cmFormat.format((data.userHeight * 100) / 0.936)); + } + ); + + useEffect(() => { + sendRPCPacket( + RpcMessage.SkeletonConfigRequest, + new SkeletonConfigRequestT() + ); + }, []); + + return ( + <> + + } + > +
+ {userHeight} +
+
+
+
+ {bvhAvailable && ( + + } + preferedDirection="top" + > +
toggleBVH()} + > + {bvhState === 'idle' && } + {bvhState !== 'idle' && ( +
+ )} +
+ + )} + + } + preferedDirection="top" + > +
toggleTracking()} + > + {!paused && } + {paused && } +
+
+ + } + preferedDirection="top" + > +
+ +
+
+
+
+ + ); +} + +function PreviewSection({ open }: { open: boolean }) { + const { config, setConfig } = useConfig(); + const [disabledRender, setDisabledRender] = useState(config?.skeletonPreview); + + const toggleRender = () => { + setConfig({ skeletonPreview: disabledRender }); + }; + + useLayoutEffect(() => { + // need useLayoutEffect to make sure that the state is corect before the first render of the skeleton + setDisabledRender(!config?.skeletonPreview); + }, [config]); + + return ( +
+ toggleRender()} + onInit={(context) => { + context.addView({ + left: 0, + bottom: 0, + width: 1, + height: 1, + position: new Vector3(3, 2.5, -3), + onHeightChange(v, newHeight) { + v.controls.target.set(0, newHeight / 2.2, 0.1); + const scale = Math.max(1, newHeight) / 1.3; + v.camera.zoom = 1 / scale; + }, + }); + }} + /> + } + > +
toggleRender()} + > + +
+
+ +
+ ); +} + +export function Sidebar() { + const { completion } = useTrackingChecklist(); + const [closed, setClosed] = useState(true); + const [closing, setClosing] = useState(false); + + const closedHight = '90px'; + const checklistSize = closed ? closedHight : 'calc(100% - 16px)'; + const previewSize = closed ? `calc(100% - ${closedHight} - 24px)` : '0%'; + + const toggleClosed = () => setClosed((closed) => !closed); + + useLayoutEffect(() => { + setClosing(true); + const ref = setTimeout(() => setClosing(false), 1000); + return () => { + clearTimeout(ref); + setClosing(false); + }; + }, [closed]); + + useEffect(() => { + if (completion === 'complete') { + setClosed(true); + } else if (completion === 'incomplete') { + setClosed(false); + } + }, [completion]); + + return ( + <> +
+ +
+
+ +
+ + ); +} diff --git a/gui/src/components/Toolbar.tsx b/gui/src/components/Toolbar.tsx new file mode 100644 index 000000000..a3558c242 --- /dev/null +++ b/gui/src/components/Toolbar.tsx @@ -0,0 +1,202 @@ +import { Typography } from './commons/Typography'; +import classNames from 'classnames'; +import { ResetType } from 'solarxr-protocol'; +import { + BODY_PARTS_GROUPS, + MountingResetGroup, + ResetBtnStatus, + useReset, + UseResetOptions, +} from '@/hooks/reset'; +import { Tooltip } from './commons/Tooltip'; +import { useAtomValue } from 'jotai'; +import { assignedTrackersAtom } from '@/store/app-store'; +import { useBreakpoint } from '@/hooks/breakpoint'; +import { useMemo } from 'react'; +import { ResetButtonIcon } from './home/ResetButton'; + +const MAINBUTTON_CLASSES = ({ disabled }: { disabled: boolean }) => + classNames( + 'relative overflow-clip', + 'flex h-full items-center justify-center gap-2 px-4 bg-background-60 rounded-lg fill-background-10 aspect-square md:aspect-auto', + { + 'cursor-pointer hover:bg-background-50 bg-background-60': !disabled, + 'cursor-not-allowed bg-background-70 brightness-75': disabled, + } + ); + +function ButtonProgress({ + progress, + status, +}: { + progress: number; + status: ResetBtnStatus; +}) { + return ( +
+ ); +} + +function BasicResetButton(options: UseResetOptions & { customName?: string }) { + const { isMd } = useBreakpoint('md'); + const { + triggerReset, + status, + name: resetName, + timer, + progress: resetProress, + disabled, + duration, + } = useReset(options); + + const progress = status === 'counting' ? resetProress / duration : 0; + + const name = options.customName || resetName; + + const skiReset = + options.type === ResetType.Mounting && options.group === 'default'; + + return ( + } + preferedDirection="top" + > +
!disabled && triggerReset()} + > +
+ +
+ +
+ +
+ + +
+ + {timer} + +
+
+
+ ); +} + +export function Toolbar() { + const assignedTrackers = useAtomValue(assignedTrackersAtom); + + const { visibleGroups, groupVisibility } = useMemo(() => { + const groupVisibility = Object.keys(BODY_PARTS_GROUPS) + .filter((k) => ['fingers'].includes(k)) + .reduce( + (curr, key) => { + const group = key as MountingResetGroup; + curr[group] = assignedTrackers.some( + ({ tracker }) => + tracker.info?.bodyPart && + BODY_PARTS_GROUPS[group].includes(tracker.info?.bodyPart) + ); + + return curr; + }, + {} as Record + ); + + return { + groupVisibility, + visibleGroups: Object.values(groupVisibility).filter((v) => v).length, + }; + }, [assignedTrackers]); + + return ( + <> +
+
+
+ +
+ + +
+
+
+ +
+ + + {groupVisibility['fingers'] && ( + + )} +
+
+
+
+ + ); +} diff --git a/gui/src/components/WidgetsComponent.tsx b/gui/src/components/WidgetsComponent.tsx deleted file mode 100644 index 214e3d21b..000000000 --- a/gui/src/components/WidgetsComponent.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Localized, useLocalization } from '@fluent/react'; -import { BVHButton } from './BVHButton'; -import { TrackingPauseButton } from './TrackingPauseButton'; -import { ResetButton } from './home/ResetButton'; -import { OverlayWidget } from './widgets/OverlayWidget'; -import { TipBox } from './commons/TipBox'; -import { DeveloperModeWidget } from './widgets/DeveloperModeWidget'; -import { useConfig } from '@/hooks/config'; -import { ResetType, StatusData } from 'solarxr-protocol'; -import { useMemo } from 'react'; -import { parseStatusToLocale, useStatusContext } from '@/hooks/status-system'; -import { ClearMountingButton } from './ClearMountingButton'; -import { ToggleableSkeletonVisualizerWidget } from './widgets/SkeletonVisualizerWidget'; -import { useAtomValue } from 'jotai'; -import { flatTrackersAtom } from '@/store/app-store'; -import { A } from './commons/A'; - -function UnprioritizedStatuses() { - const { l10n } = useLocalization(); - const trackers = useAtomValue(flatTrackersAtom); - const { statuses } = useStatusContext(); - const unprioritizedStatuses = useMemo( - () => Object.values(statuses).filter((status) => !status.prioritized), - [statuses] - ); - - return ( -
- {unprioritizedStatuses.map((status) => ( - - ), - }} - > - - {`Warning, you should fix ${StatusData[status.dataType]}`} - - - ))} -
- ); -} - -export function WidgetsComponent() { - const { config } = useConfig(); - - return ( - <> -
- - - - - - - {!window.__ANDROID__?.isThere() && } - -
-
- -
-
- -
- - {config?.debug && ( -
- -
- )} - - ); -} diff --git a/gui/src/components/commons/A.tsx b/gui/src/components/commons/A.tsx index 765200252..834f0abca 100644 --- a/gui/src/components/commons/A.tsx +++ b/gui/src/components/commons/A.tsx @@ -1,14 +1,23 @@ -import { openUrl } from '@tauri-apps/plugin-opener'; +import { open } from '@tauri-apps/plugin-shell'; +import classNames from 'classnames'; import { ReactNode } from 'react'; -export function A({ href, children }: { href?: string; children?: ReactNode }) { +export function A({ + href, + children, + className, +}: { + href?: string; + children?: ReactNode; + className?: string; +}) { return (
- href && openUrl(href).catch(() => window.open(href, '_blank')) + href && open(href).catch(() => window.open(href, '_blank')) } - className="underline" + className={classNames(className, 'underline', 'cursor-pointer')} > {children} diff --git a/gui/src/components/commons/Button.tsx b/gui/src/components/commons/Button.tsx index d87832388..1b4141cbb 100644 --- a/gui/src/components/commons/Button.tsx +++ b/gui/src/components/commons/Button.tsx @@ -2,6 +2,7 @@ import classNames from 'classnames'; import React, { ReactNode, useMemo } from 'react'; import { NavLink } from 'react-router-dom'; import { LoaderIcon, SlimeState } from './icon/LoaderIcon'; +import { Localized, LocalizedProps } from '@fluent/react'; function ButtonContent({ loading, @@ -17,11 +18,11 @@ function ButtonContent({
{icon && ( -
+
{icon}
)} @@ -44,7 +45,9 @@ export type ButtonProps = { loading?: boolean; rounded?: boolean; state?: any; -} & React.ButtonHTMLAttributes; + id?: string; +} & React.ButtonHTMLAttributes & + Omit; export function Button({ children, @@ -55,6 +58,10 @@ export function Button({ state = {}, icon, rounded = false, + attrs, + id, + vars, + elems, ...props }: ButtonProps) { const classes = useMemo(() => { @@ -95,7 +102,7 @@ export function Button({ ); }, [variant, disabled, rounded, props.className]); - return to ? ( + const content = to ? ( disabled && ev.preventDefault()} > - {children} + {id && ( + + {children} + + )} + {!id && children} ) : ( ); + + return content; } diff --git a/gui/src/components/commons/Checkbox.tsx b/gui/src/components/commons/Checkbox.tsx index 35d238115..bc76715d2 100644 --- a/gui/src/components/commons/Checkbox.tsx +++ b/gui/src/components/commons/Checkbox.tsx @@ -3,7 +3,7 @@ import { forwardRef, useMemo } from 'react'; import { Control, Controller } from 'react-hook-form'; export const CHECKBOX_CLASSES = classNames( - 'bg-background-50 border-background-50 rounded-md w-5 h-5 text-accent-background-30 focus:border-accent-background-40 focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent' + 'bg-background-50 border-background-50 cursor-pointer rounded-md w-5 h-5 text-accent-background-30 focus:border-accent-background-40 focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent' ); export const CheckboxInternal = forwardRef< @@ -34,7 +34,9 @@ export const CheckboxInternal = forwardRef< const classes = useMemo(() => { const vriantsMap = { checkbox: { - checkbox: CHECKBOX_CLASSES, + checkbox: classNames(CHECKBOX_CLASSES, { + 'brightness-50 hover:cursor-not-allowed': disabled, + }), toggle: '', pin: '', }, @@ -47,7 +49,7 @@ export const CheckboxInternal = forwardRef< }, }; return vriantsMap[variant]; - }, [variant]); + }, [variant, disabled]); return (
+
+
+ +
+
+ ); + + return showUpdate !== 'can-update' ? ( + + + + } + > +
{content}
+
+ ) : ( + + {content} + + ); +} + +export function FirmwareIcon({ + tracker, + device, +}: { + tracker: TrackerDataT; + device?: DeviceDataT; +}) { + const { currentFirmwareRelease } = useAppContext(); + + const showUpdate = + tracker.status !== TrackerStatusEnum.DISCONNECTED && + currentFirmwareRelease && + device && + checkForUpdate(currentFirmwareRelease, device); + + return ( +
+ {showUpdate && + showUpdate !== 'unavailable' && + showUpdate !== 'updated' && } +
+ ); +} diff --git a/gui/src/components/commons/ProgressBar.tsx b/gui/src/components/commons/ProgressBar.tsx index 85aeef24d..3e51932cd 100644 --- a/gui/src/components/commons/ProgressBar.tsx +++ b/gui/src/components/commons/ProgressBar.tsx @@ -53,8 +53,9 @@ export function Bar({ }) { const value = useMemo( () => Math.min(Math.max((progress * parts) / 1 - index, 0), 1), - [index, progress] + [index, progress, parts] ); + return (
const getFloatingTooltipPosition = ( preferedDirection: TooltipProps['preferedDirection'], + blockedDirections: Direction[], mode: TooltipProps['mode'], childrenRect: DOMRect, - tooltipRect: DOMRect + tooltipRect: DOMRect, + spacing: number ) => { - const spacing = 10; - const getPosition = ( direction: TooltipProps['preferedDirection'] ): TooltipPos => { @@ -135,9 +141,10 @@ const getFloatingTooltipPosition = ( const pos = getPosition(preferedDirection); if (isNotInside({ ...pos, height: tooltipRect.height }, windowRect)) { const [firstPos] = ['left', 'top', 'right', 'bottom'] + .filter((dir) => !blockedDirections.includes(dir as Direction)) .map((dir) => ({ dir, - area: getPosition(dir as TooltipProps['preferedDirection']), + area: getPosition(dir as Direction), })) .toSorted( (a, b) => @@ -226,12 +233,17 @@ const getFloatingTooltipPosition = ( export function FloatingTooltip({ childRef, preferedDirection, + blockedDirections = [], mode, children, + spacing, }: { - childRef: MutableRefObject; + childRef: MutableRefObject; children: ReactNode; -} & Pick) { +} & Pick< + TooltipProps, + 'mode' | 'preferedDirection' | 'blockedDirections' | 'spacing' +>) { const tooltipRef = useRef(null); const [tooltipStyle, setTooltipStyle] = useState(); @@ -245,9 +257,11 @@ export function FloatingTooltip({ setTooltipStyle( getFloatingTooltipPosition( preferedDirection, + blockedDirections, mode, childrenRect, - tooltipRect + tooltipRect, + spacing ?? 20 ) ); }; @@ -314,7 +328,7 @@ export function DrawerTooltip({ childRef, }: { children: ReactNode; - childRef: MutableRefObject; + childRef: MutableRefObject; }) { const touchTimestamp = useRef(0); const touchTimeout = useRef(0); @@ -377,17 +391,12 @@ export function DrawerTooltip({ if (childRef.current && childRef.current.children[0]) { const elem = childRef.current.children[0] as HTMLElement; - elem.addEventListener('mousedown', touchStart); // for debug on desktop - elem.addEventListener('mouseup', touchEnd); // for debug on desktop elem.addEventListener('scroll', scroll); - elem.addEventListener('click', touchEnd); elem.addEventListener('touchstart', touchStart); elem.addEventListener('touchend', touchEnd); return () => { - elem.removeEventListener('mousedown', touchStart); // for debug on desktop - elem.removeEventListener('mouseup', touchEnd); // for debug on desktop elem.removeEventListener('scroll', scroll); elem.removeEventListener('touchstart', touchStart); @@ -396,6 +405,7 @@ export function DrawerTooltip({ }; } }, []); + // FIXME: Completely broken not sure why. Will be solved when tooltips on mobile actually work return ( <> @@ -444,33 +454,53 @@ export function Tooltip({ content, children, preferedDirection, + blockedDirections = [], mode = 'center', + variant = 'auto', disabled = false, + tag = 'div', + spacing = 20, }: TooltipProps) { - const childRef = useRef(null); + const childRef = useRef(null); const { isMobile } = useBreakpoint('mobile'); - const portal = createPortal( - isMobile ? ( + let portal = null; + if (variant === 'auto') { + portal = isMobile ? ( {content} ) : ( {content} - ), - document.body - ); + ); + } + + if (variant === 'drawer') + portal = {content}; + + if (variant === 'floating') + portal = ( + + {content} + + ); return ( <> -
- {children} -
- {!disabled && portal} + {createElement(tag, { className: 'contents', ref: childRef }, children)} + {!disabled && createPortal(portal, document.body)} ); } diff --git a/gui/src/components/commons/Typography.tsx b/gui/src/components/commons/Typography.tsx index fb1917ede..03de1ea73 100644 --- a/gui/src/components/commons/Typography.tsx +++ b/gui/src/components/commons/Typography.tsx @@ -1,4 +1,5 @@ import { useConfig } from '@/hooks/config'; +import { Localized, LocalizedProps } from '@fluent/react'; import classNames from 'classnames'; import { createElement, ReactNode, useMemo } from 'react'; @@ -12,6 +13,10 @@ export function Typography({ truncate = false, textAlign, sentryMask = false, + id, + attrs, + elems, + vars, }: { variant?: | 'main-title' @@ -39,7 +44,8 @@ export function Typography({ | 'text-end'; children?: ReactNode; sentryMask?: boolean; -}) { + id?: string; +} & Omit) { const tag = useMemo(() => { const tags = { 'main-title': 'h1', @@ -52,7 +58,7 @@ export function Typography({ }, [variant]); const { config } = useConfig(); - return createElement( + const element = createElement( tag, { className: classNames([ @@ -71,12 +77,22 @@ export function Typography({ whitespace, textAlign, italic && 'italic', - truncate && 'leading-3 text-ellipsis', + truncate && 'leading-[1.2rem] text-ellipsis', truncate && (config?.textSize ?? 12) > 12 && 'line-clamp-1', truncate && (config?.textSize ?? 12) <= 12 && 'line-clamp-2', sentryMask && 'sentry-mask', ]), }, - children || [] + children || id || [] ); + + if (id) { + return ( + + {element} + + ); + } + + return element; } diff --git a/gui/src/components/commons/icon/ChecklistIcon.tsx b/gui/src/components/commons/icon/ChecklistIcon.tsx new file mode 100644 index 000000000..e710a40b3 --- /dev/null +++ b/gui/src/components/commons/icon/ChecklistIcon.tsx @@ -0,0 +1,12 @@ +export function Checklist({ size = 24 }: { size?: number }) { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/ClearIcon.tsx b/gui/src/components/commons/icon/ClearIcon.tsx new file mode 100644 index 000000000..85bbde08d --- /dev/null +++ b/gui/src/components/commons/icon/ClearIcon.tsx @@ -0,0 +1,12 @@ +export function ClearIcon({ size = 24 }: { size?: number }) { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/GearIcon.tsx b/gui/src/components/commons/icon/GearIcon.tsx index 668ea636b..87a46a1b3 100644 --- a/gui/src/components/commons/icon/GearIcon.tsx +++ b/gui/src/components/commons/icon/GearIcon.tsx @@ -1,8 +1,8 @@ -export function GearIcon() { +export function GearIcon({ size = 20 }: { size?: number }) { return ( diff --git a/gui/src/components/commons/icon/HomeIcon.tsx b/gui/src/components/commons/icon/HomeIcon.tsx new file mode 100644 index 000000000..18d4f03df --- /dev/null +++ b/gui/src/components/commons/icon/HomeIcon.tsx @@ -0,0 +1,12 @@ +export function HomeIcon() { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/LayoutIcon.tsx b/gui/src/components/commons/icon/LayoutIcon.tsx new file mode 100644 index 000000000..a82a78480 --- /dev/null +++ b/gui/src/components/commons/icon/LayoutIcon.tsx @@ -0,0 +1,12 @@ +export function LayoutIcon({ size = 16 }: { size?: number }) { + return ( + + + + ); +} diff --git a/gui/src/components/commons/icon/SkiIcon.tsx b/gui/src/components/commons/icon/SkiIcon.tsx new file mode 100644 index 000000000..e6dee6626 --- /dev/null +++ b/gui/src/components/commons/icon/SkiIcon.tsx @@ -0,0 +1,12 @@ +export function SkiIcon({ size = 24 }: { size?: number }) { + return ( + + + + ); +} diff --git a/gui/src/components/home/Home.tsx b/gui/src/components/home/Home.tsx index b5a9898c3..1243811b8 100644 --- a/gui/src/components/home/Home.tsx +++ b/gui/src/components/home/Home.tsx @@ -1,31 +1,28 @@ -import { Localized, useLocalization } from '@fluent/react'; -import { Link, NavLink, useNavigate } from 'react-router-dom'; -import { StatusData, TrackerDataT } from 'solarxr-protocol'; +import { useLocalization } from '@fluent/react'; +import { NavLink, useNavigate } from 'react-router-dom'; +import { TrackerDataT } from 'solarxr-protocol'; import { useConfig } from '@/hooks/config'; import { Typography } from '@/components/commons/Typography'; import { TrackerCard } from '@/components/tracker/TrackerCard'; import { TrackersTable } from '@/components/tracker/TrackersTable'; -import { - parseStatusToLocale, - trackerStatusRelated, - useStatusContext, -} from '@/hooks/status-system'; -import { useMemo } from 'react'; -import { WarningBox } from '@/components/commons/TipBox'; import { HeadsetIcon } from '@/components/commons/icon/HeadsetIcon'; -import classNames from 'classnames'; import { useAtomValue } from 'jotai'; -import { flatTrackersAtom } from '@/store/app-store'; -import { useVRCConfig } from '@/hooks/vrc-config'; - -const DONT_REPEAT_STATUSES = [StatusData.StatusTrackerReset]; +import { + assignedTrackersAtom, + unassignedTrackersAtom, +} from '@/store/app-store'; +import { useTrackingChecklist } from '@/hooks/tracking-checklist'; +import { Checklist } from '@/components/commons/icon/ChecklistIcon'; +import { useState } from 'react'; +import { HomeSettingsModal } from './HomeSettingsModal'; +import { LayoutIcon } from '@/components/commons/icon/LayoutIcon'; export function Home() { const { l10n } = useLocalization(); const { config } = useConfig(); - const trackers = useAtomValue(flatTrackersAtom); - const { statuses } = useStatusContext(); - const { invalidConfig } = useVRCConfig(); + const trackers = useAtomValue(assignedTrackersAtom); + const unassignedTrackers = useAtomValue(unassignedTrackersAtom); + const { highlightedTrackers } = useTrackingChecklist(); const navigate = useNavigate(); const sendToSettings = (tracker: TrackerDataT) => { @@ -34,95 +31,121 @@ export function Home() { ); }; - const filteredStatuses = useMemo(() => { - const dontRepeat = new Map(DONT_REPEAT_STATUSES.map((x) => [x, false])); - return Object.entries(statuses).filter(([, value]) => { - if (dontRepeat.get(value.dataType)) return false; - if (dontRepeat.has(value.dataType)) dontRepeat.set(value.dataType, true); - return true; - }); - }, [statuses]); + const settingsOpenState = useState(false); + const [, setSettingsOpen] = settingsOpenState; return (
+ -
-
- {filteredStatuses - .filter(([, status]) => status.prioritized) - .map(([, status]) => ( - - - {`Warning, you should fix ${StatusData[status.dataType]}`} - - - ))} - {invalidConfig && ( - -
-
- -
-
- -
- -
- -
-
-
- )} + + + +
+
+ +
+
setSettingsOpen(true)} + > + +
-
- {trackers.length === 0 && ( -
- - {l10n.getString('home-no_trackers')} - -
- )} + {trackers.length === 0 && ( +
+ + {l10n.getString('home-no_trackers')} + +
+ )} - {!config?.debug && trackers.length > 0 && ( -
- {trackers.map(({ tracker, device }, index) => ( - sendToSettings(tracker)} - smol - showUpdates - interactable - warning={Object.values(statuses).some((status) => - trackerStatusRelated(tracker, status) - )} - /> - ))} -
- )} - {config?.debug && trackers.length > 0 && ( -
- sendToSettings(tracker)} + {config?.homeLayout == 'default' && trackers.length > 0 && ( +
+ {trackers.map(({ tracker, device }, index) => ( + sendToSettings(tracker)} + smol + showUpdates + interactable + warning={ + !!highlightedTrackers?.trackers.find( + (t) => + t?.deviceId?.id === tracker.trackerId?.deviceId?.id && + t?.trackerNum === tracker.trackerId?.trackerNum + ) && highlightedTrackers.step + } /> + ))} +
+ )} + + {config?.homeLayout === 'table' && trackers.length > 0 && ( +
+ sendToSettings(tracker)} + /> +
+ )} + + {unassignedTrackers.length > 0 && ( + <> +
+ +
- )} -
+ {config?.homeLayout == 'default' && ( +
+ {unassignedTrackers.map(({ tracker, device }, index) => ( + sendToSettings(tracker)} + smol + showUpdates + interactable + warning={ + !!highlightedTrackers?.trackers.find( + (t) => + t?.deviceId?.id === tracker.trackerId?.deviceId?.id && + t?.trackerNum === tracker.trackerId?.trackerNum + ) && highlightedTrackers.step + } + /> + ))} +
+ )} + {config?.homeLayout === 'table' && ( +
+ sendToSettings(tracker)} + /> +
+ )} + + )}
); diff --git a/gui/src/components/home/HomeSettingsModal.tsx b/gui/src/components/home/HomeSettingsModal.tsx new file mode 100644 index 000000000..dc269930c --- /dev/null +++ b/gui/src/components/home/HomeSettingsModal.tsx @@ -0,0 +1,34 @@ +import { Dispatch, SetStateAction } from 'react'; +import { BaseModal } from '@/components/commons/BaseModal'; +import { Typography } from '@/components/commons/Typography'; +import { Button } from '@/components/commons/Button'; +import { HomeLayoutSettings } from '@/components/settings/pages/HomeScreenSettings'; + +export function HomeSettingsModal({ + open, +}: { + open: [boolean, Dispatch>]; +}) { + return ( + { + open[1](false); + }} + > +
+ + +
+
+
+
+ ); +} diff --git a/gui/src/components/home/ResetButton.tsx b/gui/src/components/home/ResetButton.tsx index 78d1c7fda..e3901a890 100644 --- a/gui/src/components/home/ResetButton.tsx +++ b/gui/src/components/home/ResetButton.tsx @@ -1,219 +1,67 @@ -import { useLocalization } from '@fluent/react'; -import { useEffect, useMemo, useRef, useState } from 'react'; -import { - BodyPart, - ResetRequestT, - ResetType, - RpcMessage, - StatusData, -} from 'solarxr-protocol'; -import { useConfig } from '@/hooks/config'; -import { useCountdown } from '@/hooks/countdown'; -import { useWebsocketAPI } from '@/hooks/websocket-api'; -import { - playSoundOnResetEnded, - playSoundOnResetStarted, -} from '@/sounds/sounds'; -import { BigButton } from '@/components/commons/BigButton'; +import { Localized } from '@fluent/react'; +import { ResetType } from 'solarxr-protocol'; import { Button } from '@/components/commons/Button'; -import { - MountingResetIcon, - YawResetIcon, - FullResetIcon, -} from '@/components/commons/icon/ResetIcon'; -import { useStatusContext } from '@/hooks/status-system'; import classNames from 'classnames'; +import { useReset, UseResetOptions } from '@/hooks/reset'; +import { + FullResetIcon, + YawResetIcon, +} from '@/components/commons/icon/ResetIcon'; +import { ReactNode } from 'react'; +import { SkiIcon } from '@/components/commons/icon/SkiIcon'; import { FootIcon } from '@/components/commons/icon/FootIcon'; import { FingersIcon } from '@/components/commons/icon/FingersIcon'; +export function ResetButtonIcon(options: UseResetOptions) { + if (options.type === ResetType.Mounting && !options.group) + options.group = 'default'; + + if (options.type === ResetType.Yaw) return ; + if (options.type === ResetType.Full) return ; + if (options.type === ResetType.Mounting) { + if (options.group === 'default') return ; + if (options.group === 'feet') return ; + if (options.group === 'fingers') return ; + } +} + export function ResetButton({ - type, - size = 'big', - bodyPartsToReset = 'default', className, onReseted, + children, + ...options }: { className?: string; - type: ResetType; - size: 'big' | 'small'; - bodyPartsToReset?: 'default' | 'feet' | 'fingers'; + children?: ReactNode; onReseted?: () => void; -}) { - const { l10n } = useLocalization(); - const { sendRPCPacket } = useWebsocketAPI(); - const { statuses } = useStatusContext(); - const { config } = useConfig(); - const finishedTimeoutRef = useRef(-1); - const [isFinished, setFinished] = useState(false); - - const needsFullReset = useMemo( - () => - type === ResetType.Mounting && - Object.values(statuses).some( - (status) => status.dataType === StatusData.StatusTrackerReset - ), - [statuses] +} & UseResetOptions) { + const { triggerReset, status, timer, disabled, name } = useReset( + options, + onReseted ); - const feetBodyParts = [BodyPart.LEFT_FOOT, BodyPart.RIGHT_FOOT]; - const fingerBodyParts = [ - BodyPart.LEFT_THUMB_METACARPAL, - BodyPart.LEFT_THUMB_PROXIMAL, - BodyPart.LEFT_THUMB_DISTAL, - BodyPart.LEFT_INDEX_PROXIMAL, - BodyPart.LEFT_INDEX_INTERMEDIATE, - BodyPart.LEFT_INDEX_DISTAL, - BodyPart.LEFT_MIDDLE_PROXIMAL, - BodyPart.LEFT_MIDDLE_INTERMEDIATE, - BodyPart.LEFT_MIDDLE_DISTAL, - BodyPart.LEFT_RING_PROXIMAL, - BodyPart.LEFT_RING_INTERMEDIATE, - BodyPart.LEFT_RING_DISTAL, - BodyPart.LEFT_LITTLE_PROXIMAL, - BodyPart.LEFT_LITTLE_INTERMEDIATE, - BodyPart.LEFT_LITTLE_DISTAL, - BodyPart.RIGHT_THUMB_METACARPAL, - BodyPart.RIGHT_THUMB_PROXIMAL, - BodyPart.RIGHT_THUMB_DISTAL, - BodyPart.RIGHT_INDEX_PROXIMAL, - BodyPart.RIGHT_INDEX_INTERMEDIATE, - BodyPart.RIGHT_INDEX_DISTAL, - BodyPart.RIGHT_MIDDLE_PROXIMAL, - BodyPart.RIGHT_MIDDLE_INTERMEDIATE, - BodyPart.RIGHT_MIDDLE_DISTAL, - BodyPart.RIGHT_RING_PROXIMAL, - BodyPart.RIGHT_RING_INTERMEDIATE, - BodyPart.RIGHT_RING_DISTAL, - BodyPart.RIGHT_LITTLE_PROXIMAL, - BodyPart.RIGHT_LITTLE_INTERMEDIATE, - BodyPart.RIGHT_LITTLE_DISTAL, - ]; - - const reset = () => { - const req = new ResetRequestT(); - req.resetType = type; - switch (bodyPartsToReset) { - case 'default': - // Server handles it. Usually all body parts except fingers. - req.bodyParts = []; - break; - case 'feet': - req.bodyParts = feetBodyParts; - break; - case 'fingers': - req.bodyParts = fingerBodyParts; - break; - } - sendRPCPacket(RpcMessage.ResetRequest, req); - }; - - const { isCounting, startCountdown, timer } = useCountdown({ - duration: type === ResetType.Yaw ? 0 : undefined, - onCountdownEnd: () => { - maybePlaySoundOnResetEnd(type); - reset(); - setFinished(true); - if (finishedTimeoutRef.current !== -1) - clearTimeout(finishedTimeoutRef.current); - finishedTimeoutRef.current = setTimeout(() => { - setFinished(false); - finishedTimeoutRef.current = -1; - }, 2000) as unknown as number; - if (onReseted) onReseted(); - }, - }); - - const text = useMemo(() => { - switch (type) { - case ResetType.Yaw: - return l10n.getString( - 'reset-yaw' + - (bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '') - ); - case ResetType.Mounting: - return l10n.getString( - 'reset-mounting' + - (bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '') - ); - case ResetType.Full: - return l10n.getString( - 'reset-full' + - (bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '') - ); - } - }, [type, bodyPartsToReset]); - - const getIcon = () => { - switch (type) { - case ResetType.Yaw: - return ; - case ResetType.Mounting: - switch (bodyPartsToReset) { - case 'default': - return ; - case 'feet': - return ; - case 'fingers': - return ; - } - } - return ; - }; - - const maybePlaySoundOnResetEnd = (type: ResetType) => { - if (!config?.feedbackSound) return; - playSoundOnResetEnded(type, config?.feedbackSoundVolume); - }; - - const maybePlaySoundOnResetStart = () => { - if (!config?.feedbackSound) return; - if (type !== ResetType.Yaw) - playSoundOnResetStarted(config?.feedbackSoundVolume); - }; - - const triggerReset = () => { - setFinished(false); - startCountdown(); - maybePlaySoundOnResetStart(); - }; - - useEffect(() => { - return () => { - if (finishedTimeoutRef.current !== -1) - clearTimeout(finishedTimeoutRef.current); - }; - }, []); - - return size === 'small' ? ( + return ( - ) : ( - - {!isCounting || type === ResetType.Yaw ? text : String(timer)} - ); } diff --git a/gui/src/components/onboarding/OnboardingLayout.tsx b/gui/src/components/onboarding/OnboardingLayout.tsx index 64501ac9c..46ee15aa2 100644 --- a/gui/src/components/onboarding/OnboardingLayout.tsx +++ b/gui/src/components/onboarding/OnboardingLayout.tsx @@ -34,8 +34,6 @@ export function OnboardingLayout({ children }: { children: ReactNode }) {
) : ( - - {children} - + {children} ); } diff --git a/gui/src/components/onboarding/pages/ConnectTracker.scss b/gui/src/components/onboarding/pages/ConnectTracker.scss index 36acf8219..c44a97333 100644 --- a/gui/src/components/onboarding/pages/ConnectTracker.scss +++ b/gui/src/components/onboarding/pages/ConnectTracker.scss @@ -12,9 +12,9 @@ grid-template: 's t' var(--connect-tracker-layout-top) 's c' calc(100% - var(--connect-tracker-layout-top)) - / calc(var(--connect-tracker-layout-sidebar)) calc( - 100% - var(--connect-tracker-layout-sidebar) - ); + / calc(var(--connect-tracker-layout-sidebar)) calc(100% - var( + --connect-tracker-layout-sidebar + )); @screen mobile { grid-template: diff --git a/gui/src/components/onboarding/pages/ConnectTracker.tsx b/gui/src/components/onboarding/pages/ConnectTracker.tsx index 9933454f1..1b22b178b 100644 --- a/gui/src/components/onboarding/pages/ConnectTracker.tsx +++ b/gui/src/components/onboarding/pages/ConnectTracker.tsx @@ -5,8 +5,9 @@ import { useNavigate } from 'react-router-dom'; import { RpcMessage, StartWifiProvisioningRequestT, - StatusData, StopWifiProvisioningRequestT, + TrackingChecklistPublicNetworksT, + TrackingChecklistStepId, WifiProvisioningStatus, WifiProvisioningStatusResponseT, } from 'solarxr-protocol'; @@ -24,9 +25,9 @@ import './ConnectTracker.scss'; import { useAtomValue } from 'jotai'; import { connectedIMUTrackersAtom } from '@/store/app-store'; import { BaseModal } from '@/components/commons/BaseModal'; -import { parseStatusToLocale, useStatusContext } from '@/hooks/status-system'; import { A } from '@/components/commons/A'; import { CONNECT_TRACKER } from '@/utils/tauri'; +import { useTrackingChecklist } from '@/hooks/tracking-checklist'; const statusLabelMap = { [WifiProvisioningStatus.NONE]: @@ -74,9 +75,34 @@ const statusProgressMap = { [WifiProvisioningStatus.COULD_NOT_FIND_SERVER]: 0.8, }; +export function InvalidNetworkProfileWarning({ + extraData, +}: { + extraData: TrackingChecklistPublicNetworksT; +}) { + return ( +
+ + ), + }} + vars={{ + count: extraData.adapters.length, + adapters: extraData.adapters.join(', '), + }} + > + WARNING + +
+ ); +} + export function ConnectTrackersPage() { const { l10n } = useLocalization(); - const { statuses } = useStatusContext(); + const { visibleSteps } = useTrackingChecklist(); const connectedIMUTrackers = useAtomValue(connectedIMUTrackersAtom); const { applyProgress, state } = useOnboarding(); @@ -165,11 +191,13 @@ export function ConnectTrackersPage() { [connectedIMUTrackers.length] ); - const filteredStatuses = useMemo(() => { - return Object.entries(statuses).filter( - ([, value]) => value.dataType == StatusData.StatusPublicNetwork + const invalidNetworkProfile = useMemo(() => { + return visibleSteps.find( + (step) => + step.id === TrackingChecklistStepId.NETWORK_PROFILE_PUBLIC && + !step.valid ); - }, [statuses]); + }, [visibleSteps]); return ( <> @@ -243,24 +271,13 @@ export function ConnectTrackersPage() { > Conditional tip - {filteredStatuses.map(([, status]) => ( -
- - ), - }} - > - - {`Warning, you should fix ${StatusData[status.dataType]}`} - - -
- ))} + {invalidNetworkProfile && ( + + )}
diff --git a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Preparation.tsx b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Preparation.tsx index 5d7c58d06..7dd87b6ae 100644 --- a/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Preparation.tsx +++ b/gui/src/components/onboarding/pages/body-proportions/autobone-steps/Preparation.tsx @@ -69,11 +69,7 @@ export function PreparationStep({ > {l10n.getString('onboarding-automatic_mounting-prev_step')} - +
diff --git a/gui/src/components/onboarding/pages/mounting/mounting-steps/MountingReset.tsx b/gui/src/components/onboarding/pages/mounting/mounting-steps/MountingReset.tsx index 5edcb13c6..1943d757e 100644 --- a/gui/src/components/onboarding/pages/mounting/mounting-steps/MountingReset.tsx +++ b/gui/src/components/onboarding/pages/mounting/mounting-steps/MountingReset.tsx @@ -58,8 +58,8 @@ export function MountingResetStep({ {l10n.getString('onboarding-automatic_mounting-prev_step')}
diff --git a/gui/src/components/onboarding/pages/mounting/mounting-steps/Preparation.tsx b/gui/src/components/onboarding/pages/mounting/mounting-steps/Preparation.tsx index b4689779e..bc9ca3b7c 100644 --- a/gui/src/components/onboarding/pages/mounting/mounting-steps/Preparation.tsx +++ b/gui/src/components/onboarding/pages/mounting/mounting-steps/Preparation.tsx @@ -69,11 +69,7 @@ export function PreparationStep({ > {l10n.getString('onboarding-automatic_mounting-prev_step')} - +
diff --git a/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/PreparationStep.tsx b/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/PreparationStep.tsx index 06097a7f8..78a6c5abe 100644 --- a/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/PreparationStep.tsx +++ b/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/PreparationStep.tsx @@ -53,7 +53,7 @@ export function PreparationStep({
); diff --git a/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/VerifyMounting.tsx b/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/VerifyMounting.tsx index 03c983f52..59d3678d8 100644 --- a/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/VerifyMounting.tsx +++ b/gui/src/components/onboarding/pages/stay-aligned/stay-aligned-steps/VerifyMounting.tsx @@ -54,8 +54,8 @@ export function VerifyMountingStep({ {l10n.getString('onboarding-automatic_mounting-prev_step')}
diff --git a/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx b/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx index b84ecece5..c3a20dd9a 100644 --- a/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx +++ b/gui/src/components/onboarding/pages/trackers-assign/TrackerAssignment.tsx @@ -281,7 +281,7 @@ export function TrackersAssignPage() {
- + {l10n.getString('onboarding-assign_trackers-title')} diff --git a/gui/src/components/providers/StatusSystemContext.tsx b/gui/src/components/providers/StatusSystemContext.tsx deleted file mode 100644 index f04bf420b..000000000 --- a/gui/src/components/providers/StatusSystemContext.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { ReactNode } from 'react'; -import { StatusSystemC, useProvideStatusContext } from '@/hooks/status-system'; - -export function StatusProvider({ children }: { children: ReactNode }) { - const context = useProvideStatusContext(); - - return ( - {children} - ); -} diff --git a/gui/src/components/settings/SettingsLayout.scss b/gui/src/components/settings/SettingsLayout.scss index 3cc388710..eb70bef5e 100644 --- a/gui/src/components/settings/SettingsLayout.scss +++ b/gui/src/components/settings/SettingsLayout.scss @@ -7,9 +7,9 @@ grid-template: 't t t' var(--topbar-h) 'n s c' calc(100% - var(--topbar-h)) - / var(--navbar-w) var(--settings-sidebar-w) calc( - 100% - var(--navbar-w) - var(--settings-sidebar-w) - ); + / var(--navbar-w) var(--settings-sidebar-w) calc(100% - var(--navbar-w) - var( + --settings-sidebar-w + )); @screen lg { --settings-sidebar-w: 270px; diff --git a/gui/src/components/settings/SettingsPageLayout.tsx b/gui/src/components/settings/SettingsPageLayout.tsx index 29329894f..d69057ca4 100644 --- a/gui/src/components/settings/SettingsPageLayout.tsx +++ b/gui/src/components/settings/SettingsPageLayout.tsx @@ -64,7 +64,7 @@ export function SettingsPagePaneLayout({ {...props} >
-
+
{icon}
diff --git a/gui/src/components/settings/SettingsSidebar.tsx b/gui/src/components/settings/SettingsSidebar.tsx index ffb09640a..3628c55e6 100644 --- a/gui/src/components/settings/SettingsSidebar.tsx +++ b/gui/src/components/settings/SettingsSidebar.tsx @@ -1,18 +1,17 @@ import classNames from 'classnames'; -import { ReactNode, useMemo } from 'react'; +import { useMemo } from 'react'; import { NavLink, useLocation, useMatch } from 'react-router-dom'; import { Typography } from '@/components/commons/Typography'; -import { useLocalization } from '@fluent/react'; import { useVRCConfig } from '@/hooks/vrc-config'; export function SettingsLink({ to, scrollTo, - children, + id, }: { + id: string; to: string; scrollTo?: string; - children: ReactNode; }) { const { state } = useLocation(); const doesMatch = useMatch({ @@ -35,94 +34,118 @@ export function SettingsLink({ 'bg-background-60': isActive, })} > - {children} + ); } export function SettingsSidebar() { - const { l10n } = useLocalization(); const { state: vrcConfigState } = useVRCConfig(); return (
- - {l10n.getString('settings-sidebar-title')} - +
- - {l10n.getString('settings-sidebar-general')} - +
- - SteamVR - - - {l10n.getString('settings-sidebar-stay_aligned')} - - - {l10n.getString('settings-sidebar-tracker_mechanics')} - - - {l10n.getString('settings-sidebar-fk_settings')} - - - {l10n.getString('settings-sidebar-gesture_control')} - + + + + +
- - {l10n.getString('settings-sidebar-interface')} - +
- - {l10n.getString('settings-sidebar-notifications')} - - - {l10n.getString('settings-sidebar-behavior')} - - - {l10n.getString('settings-sidebar-appearance')} - + + + + +
OSC
- - {l10n.getString('settings-sidebar-osc_router')} - - - {l10n.getString('settings-sidebar-osc_trackers')} - - - VMC - + + +
- - {l10n.getString('settings-sidebar-utils')} - +
- - {l10n.getString('settings-sidebar-serial')} - - - {l10n.getString('settings-sidebar-firmware-tool')} - + +
{vrcConfigState?.isSupported && (
- - {l10n.getString('settings-sidebar-vrc_warnings')} - +
)}
- - {l10n.getString('settings-sidebar-advanced')} - +
diff --git a/gui/src/components/settings/pages/GeneralSettings.tsx b/gui/src/components/settings/pages/GeneralSettings.tsx index 4d4f5694c..d55478deb 100644 --- a/gui/src/components/settings/pages/GeneralSettings.tsx +++ b/gui/src/components/settings/pages/GeneralSettings.tsx @@ -9,7 +9,6 @@ import { ModelRatiosT, ModelSettingsT, ModelTogglesT, - ResetsSettingsT, RpcMessage, SettingsRequestT, SettingsResponseT, @@ -38,6 +37,11 @@ import { serializeStayAlignedSettings, deserializeStayAlignedSettings, } from './components/StayAlignedSettings'; +import { + defaultResetSettings, + loadResetSettings, + ResetSettingsForm, +} from '@/hooks/reset-settings'; export type SettingsForm = { trackers: { @@ -95,13 +99,7 @@ export type SettingsForm = { legTweaks: { correctionStrength: number; }; - resetsSettings: { - resetMountingFeet: boolean; - armsMountingResetMode: number; - yawResetSmoothTime: number; - saveMountingReset: boolean; - resetHmdPitch: boolean; - }; + resetsSettings: ResetSettingsForm; stayAligned: StayAlignedSettingsForm; }; @@ -156,22 +154,14 @@ const defaultValues: SettingsForm = { numberTrackersOverThreshold: 1, }, legTweaks: { correctionStrength: 0.3 }, - resetsSettings: { - resetMountingFeet: false, - armsMountingResetMode: 0, - yawResetSmoothTime: 0.0, - saveMountingReset: false, - resetHmdPitch: false, - }, + resetsSettings: defaultResetSettings, stayAligned: defaultStayAlignedSettings, }; export function GeneralSettings() { const { l10n } = useLocalization(); const { config } = useConfig(); - // const { state } = useLocation(); const { currentLocales } = useLocaleConfig(); - // const pageRef = useRef(null); const percentageFormat = new Intl.NumberFormat(currentLocales, { style: 'percent', @@ -288,17 +278,7 @@ export function GeneralSettings() { settings.stayAligned = serializeStayAlignedSettings(values.stayAligned); if (values.resetsSettings) { - const resetsSettings = new ResetsSettingsT(); - resetsSettings.resetMountingFeet = - values.resetsSettings.resetMountingFeet; - resetsSettings.armsMountingResetMode = - values.resetsSettings.armsMountingResetMode; - resetsSettings.yawResetSmoothTime = - values.resetsSettings.yawResetSmoothTime; - resetsSettings.saveMountingReset = - values.resetsSettings.saveMountingReset; - resetsSettings.resetHmdPitch = values.resetsSettings.resetHmdPitch; - settings.resetsSettings = resetsSettings; + settings.resetsSettings = loadResetSettings(values.resetsSettings); } sendRPCPacket(RpcMessage.ChangeSettingsRequest, settings); diff --git a/gui/src/components/settings/pages/HomeScreenSettings.tsx b/gui/src/components/settings/pages/HomeScreenSettings.tsx new file mode 100644 index 000000000..483202db8 --- /dev/null +++ b/gui/src/components/settings/pages/HomeScreenSettings.tsx @@ -0,0 +1,190 @@ +import { CheckBox } from '@/components/commons/Checkbox'; +import { CheckIcon } from '@/components/commons/icon/CheckIcon'; +import { HomeIcon } from '@/components/commons/icon/HomeIcon'; +import { Typography } from '@/components/commons/Typography'; +import { + SettingsPageLayout, + SettingsPagePaneLayout, +} from '@/components/settings/SettingsPageLayout'; +import { Config, useConfig } from '@/hooks/config'; +import { + trackingchecklistIdtoLabel, + useTrackingChecklist, +} from '@/hooks/tracking-checklist'; +import { useLocalization } from '@fluent/react'; +import classNames from 'classnames'; +import { ReactNode, useEffect } from 'react'; +import { useForm } from 'react-hook-form'; +import { TrackingChecklistStepId } from 'solarxr-protocol'; + +type StepsForm = { steps: Record }; +export function TrackingChecklistSettings({ + variant, +}: { + variant: 'settings' | 'modal'; +}) { + const { l10n } = useLocalization(); + const { ignoredSteps, steps, ignoreStep } = useTrackingChecklist(); + + const { control, reset, handleSubmit } = useForm({ + defaultValues: { + steps: steps.reduce( + (curr, { id }) => ({ [id]: !ignoredSteps.includes(id), ...curr }), + {} + ), + }, + mode: 'onChange', + }); + + useEffect(() => { + reset({ + steps: steps.reduce( + (curr, { id }) => ({ [id]: !ignoredSteps.includes(id), ...curr }), + {} + ), + }); + }, [ignoredSteps]); + + const onSubmit = (values: StepsForm) => { + for (const [id, value] of Object.entries(values.steps)) { + const stepId = +id; + if (!stepId) continue; + + // doing it this way prevents calling ignore step for every step. + // that prevent sending a packet for steps that didnt change + if (!value && !ignoredSteps.includes(stepId)) { + ignoreStep(stepId, true); + } + + if (value && ignoredSteps.includes(stepId)) { + ignoreStep(stepId, false); + } + } + }; + + return ( +
+
+ + +
+
+ {steps + .filter((step) => step.enabled) + .map((step) => ( +
+ +
+ ))} +
+
+ ); +} + +export function LayoutSelector({ + children, + name, + active = false, + onClick, +}: { + children: ReactNode; + name: string; + active: boolean; + onClick: () => void; +}) { + return ( +
+
+ +
+
+ {children} +
+ ); +} + +export function HomeLayoutSettings() { + const { config, setConfig } = useConfig(); + + const setLayout = (layout: Config['homeLayout']) => + setConfig({ homeLayout: layout }); + + return ( +
+
+ + +
+
+ setLayout('default')} + > +
+
+
+
+
+
+ + setLayout('table')} + > +
+
+
+
+
+
+ +
+
+ ); +} + +export function HomeScreenSettings() { + return ( + +
+ }> + + + + }> + + + +
+
+ ); +} diff --git a/gui/src/components/settings/pages/InterfaceSettings.tsx b/gui/src/components/settings/pages/InterfaceSettings.tsx index 67a780270..126710a88 100644 --- a/gui/src/components/settings/pages/InterfaceSettings.tsx +++ b/gui/src/components/settings/pages/InterfaceSettings.tsx @@ -20,6 +20,7 @@ import { ArrowRightLeftIcon } from '@/components/commons/icon/ArrowIcons'; import { isTrayAvailable } from '@/utils/tauri'; import { isTauri } from '@tauri-apps/api/core'; import { TauriFileInput } from '@/components/commons/TauriFileInput'; +import { DeveloperModeWidget } from '@/components/widgets/DeveloperModeWidget'; interface InterfaceSettingsForm { appearance: { @@ -304,16 +305,19 @@ export function InterfaceSettings() { )}
-
- +
+
+ +
+ {config?.debug && }
diff --git a/gui/src/components/tracker/TrackerCard.tsx b/gui/src/components/tracker/TrackerCard.tsx index 9fd3bd0c7..00dafabe0 100644 --- a/gui/src/components/tracker/TrackerCard.tsx +++ b/gui/src/components/tracker/TrackerCard.tsx @@ -4,6 +4,7 @@ import { DeviceDataT, TrackerDataT, TrackerStatus as TrackerStatusEnum, + TrackingChecklistStepT, } from 'solarxr-protocol'; import { Typography } from '@/components/commons/Typography'; import { TrackerBattery } from './TrackerBattery'; @@ -12,61 +13,10 @@ import { TrackerStatus } from './TrackerStatus'; import classNames from 'classnames'; import { useTracker } from '@/hooks/tracker'; import { BodyPartIcon } from '@/components/commons/BodyPartIcon'; -import { DownloadIcon } from '@/components/commons/icon/DownloadIcon'; -import { Link } from 'react-router-dom'; -import { useAppContext } from '@/hooks/app'; import { Tooltip } from '@/components/commons/Tooltip'; -import { Localized } from '@fluent/react'; -import { checkForUpdate } from '@/hooks/firmware-update'; - -function UpdateIcon({ - showUpdate, -}: { - showUpdate: - | 'can-update' - | 'low-battery' - | 'updated' - | 'unavailable' - | 'blocked'; -}) { - const content = ( -
-
-
- -
-
- ); - - return showUpdate !== 'can-update' ? ( - - - - } - > -
{content}
-
- ) : ( - - {content} - - ); -} +import { FirmwareIcon } from '@/components/commons/FirmwareIcon'; +import { WarningIcon } from '@/components/commons/icon/WarningIcon'; +import { trackingchecklistIdtoLabel } from '@/hooks/tracking-checklist'; function TrackerBig({ device, @@ -125,21 +75,39 @@ function TrackerBig({ function TrackerSmol({ device, tracker, + warning, }: { tracker: TrackerDataT; device?: DeviceDataT; + warning?: TrackingChecklistStepT | boolean; }) { const { useName } = useTracker(tracker); const trackerName = useName(); return ( -
-
- +
+
+ {warning && ( +
+ +
+ )} +
+ +
-
- + +
+ {trackerName} @@ -191,19 +159,12 @@ export function TrackerCard({ bg?: string; shakeHighlight?: boolean; onClick?: MouseEventHandler; - warning?: boolean; + warning?: TrackingChecklistStepT | boolean; showUpdates?: boolean; }) { - const { currentFirmwareRelease } = useAppContext(); const { useVelocity } = useTracker(tracker); const velocity = useVelocity(); - const showUpdate = - showUpdates && - tracker.status !== TrackerStatusEnum.DISCONNECTED && - currentFirmwareRelease && - device && - checkForUpdate(currentFirmwareRelease, device); return (
- {smol && } + {smol && ( + + + +
+ ) + } + > + + + )} {!smol && }
- {showUpdate && - showUpdate !== 'unavailable' && - showUpdate !== 'updated' && } + {showUpdates && }
); } diff --git a/gui/src/components/tracker/TrackerWifi.tsx b/gui/src/components/tracker/TrackerWifi.tsx index 10cde1bcd..319833a19 100644 --- a/gui/src/components/tracker/TrackerWifi.tsx +++ b/gui/src/components/tracker/TrackerWifi.tsx @@ -6,7 +6,7 @@ export function TrackerWifi({ ping, rssiShowNumeric, disabled, - textColor = 'secondary', + textColor = 'primary', }: { rssi: number | null; ping: number | null; diff --git a/gui/src/components/tracker/TrackersTable.tsx b/gui/src/components/tracker/TrackersTable.tsx index f9a4fcc8b..371f42add 100644 --- a/gui/src/components/tracker/TrackersTable.tsx +++ b/gui/src/components/tracker/TrackersTable.tsx @@ -1,13 +1,6 @@ -import { useLocalization } from '@fluent/react'; import classNames from 'classnames'; -import { IPv4 } from 'ip-num'; -import { MouseEventHandler, ReactNode, useMemo, useState } from 'react'; -import { - BodyPart, - TrackerDataT, - TrackerIdT, - TrackerStatus as TrackerStatusEnum, -} from 'solarxr-protocol'; +import { IPv4 } from 'ip-num/IPNumber'; +import { createContext, ReactNode, useContext, useMemo } from 'react'; import { useConfig } from '@/hooks/config'; import { useTracker } from '@/hooks/tracker'; import { BodyPartIcon } from '@/components/commons/BodyPartIcon'; @@ -16,37 +9,22 @@ import { formatVector3 } from '@/utils/formatting'; import { TrackerBattery } from './TrackerBattery'; import { TrackerStatus } from './TrackerStatus'; import { TrackerWifi } from './TrackerWifi'; -import { trackerStatusRelated, useStatusContext } from '@/hooks/status-system'; import { FlatDeviceTracker } from '@/store/app-store'; import { StayAlignedInfo } from '@/components/stay-aligned/StayAlignedInfo'; - -enum DisplayColumn { - NAME, - TYPE, - BATTERY, - PING, - TPS, - ROTATION, - TEMPERATURE, - LINEAR_ACCELERATION, - POSITION, - STAY_ALIGNED, - URL, -} - -const displayColumns: { [k: string]: boolean } = { - [DisplayColumn.NAME]: true, - [DisplayColumn.TYPE]: true, - [DisplayColumn.BATTERY]: true, - [DisplayColumn.PING]: true, - [DisplayColumn.TPS]: true, - [DisplayColumn.ROTATION]: true, - [DisplayColumn.TEMPERATURE]: true, - [DisplayColumn.LINEAR_ACCELERATION]: true, - [DisplayColumn.POSITION]: true, - [DisplayColumn.STAY_ALIGNED]: true, - [DisplayColumn.URL]: true, -}; +import { Tooltip } from '@/components/commons/Tooltip'; +import { WarningIcon } from '@/components/commons/icon/WarningIcon'; +import { FirmwareIcon } from '@/components/commons/FirmwareIcon'; +import { + BodyPart, + TrackerDataT, + TrackerStatus as TrackerStatusEnum, + TrackingChecklistStepT, +} from 'solarxr-protocol'; +import { + highlightedTrackers, + trackingchecklistIdtoLabel, + useTrackingChecklist, +} from '@/hooks/tracking-checklist'; const isHMD = ({ tracker }: FlatDeviceTracker) => tracker.info?.isHmd || tracker.info?.bodyPart === BodyPart.HEAD; @@ -58,15 +36,36 @@ const isSlime = ({ device }: FlatDeviceTracker) => const getTrackerName = ({ tracker }: FlatDeviceTracker) => tracker?.info?.customName?.toString() || ''; -export function TrackerNameCell({ tracker }: { tracker: TrackerDataT }) { +export function TrackerNameCell({ + tracker, + warning, +}: { + tracker: TrackerDataT; + warning: TrackingChecklistStepT | boolean; +}) { const { useName } = useTracker(tracker); const name = useName(); return ( -
-
- +
+
+ {warning && ( +
+ +
+ )} +
+ +
@@ -103,60 +102,195 @@ export function TrackerRotCell({ ); } -export function RowContainer({ +function Header({ + name, + className, + first = false, + last = false, + show = true, +}: { + first?: boolean; + last?: boolean; + name: string; + className?: string; + show?: boolean; +}) { + return ( + +
+ +
+ + ); +} + +function Cell({ children, - rounded = 'none', - hover, - tracker, - onClick, - onMouseOver, - onMouseOut, - warning, + first = false, + last = false, + show = true, }: { children: ReactNode; - rounded?: 'left' | 'right' | 'none'; - hover: boolean; - tracker: TrackerDataT; - onClick?: MouseEventHandler; - onMouseOver?: MouseEventHandler; - onMouseOut?: MouseEventHandler; - warning: boolean; + first?: boolean; + last?: boolean; + show?: boolean; }) { + const { tracker } = useContext(TrackerRowProvider); const { useVelocity } = useTracker(tracker); const velocity = useVelocity(); return ( -
+
{children}
-
+ + ); +} + +const TrackerRowProvider = createContext(undefined as never); + +function Row({ + data, + highlightedTrackers, + clickedTracker, +}: { + data: FlatDeviceTracker; + highlightedTrackers: highlightedTrackers | undefined; + clickedTracker: (tracker: TrackerDataT) => void; +}) { + const { config } = useConfig(); + const fontColor = config?.devSettings?.highContrast ? 'primary' : 'secondary'; + const moreInfo = config?.devSettings?.moreInfo; + + const { tracker, device } = data; + + const warning = + !!highlightedTrackers?.trackers.find( + (t) => + t?.deviceId?.id === tracker.trackerId?.deviceId?.id && + t?.trackerNum === tracker.trackerId?.trackerNum + ) && highlightedTrackers.step; + + return ( + + + + +
+ ) + } + tag="tr" + spacing={-5} + > + <> +
+
+ +
+
+ clickedTracker(tracker)}> + + + + + + {device?.hardwareInfo?.manufacturer || '--'} + + + + {device?.hardwareStatus?.batteryPctEstimate != null && ( + + )} + + + {(device?.hardwareStatus?.rssi != null || + device?.hardwareStatus?.ping != null) && ( + + )} + + + {tracker.tps && ( + {tracker.tps} + )} + + + + + + {tracker?.temp && tracker?.temp?.temp != 0 && ( + + {tracker.temp.temp.toFixed(2)} + + )} + + + {tracker.linearAcceleration && ( + + {formatVector3(tracker.linearAcceleration, 1)} + + )} + + + {tracker.position && ( + + {formatVector3(tracker.position, 2)} + + )} + + + + + + + udp:// + {IPv4.fromNumber( + device?.hardwareInfo?.ipAddress?.addr || 0 + ).toString()} + + + + + + ); } @@ -167,14 +301,8 @@ export function TrackersTable({ clickedTracker: (tracker: TrackerDataT) => void; flatTrackers: FlatDeviceTracker[]; }) { - const { l10n } = useLocalization(); - const [hoverTracker, setHoverTracker] = useState(null); const { config } = useConfig(); - const { statuses } = useStatusContext(); - - const trackerEqual = (id: TrackerIdT | null) => - id?.trackerNum == hoverTracker?.trackerNum && - (!id?.deviceId || id.deviceId.id == hoverTracker?.deviceId?.id); + const { highlightedTrackers } = useTrackingChecklist(); const filteringEnabled = config?.debug && config?.devSettings?.filterSlimesAndHMD; @@ -191,201 +319,51 @@ export function TrackersTable({ return list; }, [flatTrackers, filteringEnabled, sortingEnabled]); - const fontColor = config?.devSettings?.highContrast ? 'primary' : 'secondary'; const moreInfo = config?.devSettings?.moreInfo; - const hasTemperature = !!filteredSortedTrackers.find( - ({ tracker }) => tracker?.temp && tracker?.temp?.temp != 0 - ); - displayColumns[DisplayColumn.TEMPERATURE] = hasTemperature || false; - displayColumns[DisplayColumn.POSITION] = moreInfo || false; - displayColumns[DisplayColumn.LINEAR_ACCELERATION] = moreInfo || false; - displayColumns[DisplayColumn.STAY_ALIGNED] = moreInfo || false; - displayColumns[DisplayColumn.URL] = moreInfo || false; - const displayColumnsKeys = Object.keys(displayColumns).filter( - (k) => displayColumns[k] - ); - const firstColumnId = +displayColumnsKeys[0]; - const lastColumnId = +displayColumnsKeys[displayColumnsKeys.length - 1]; - - function column({ - id, - label, - labelClassName, - row, - }: { - id: DisplayColumn; - label: string; - labelClassName?: string; - row: (data: FlatDeviceTracker) => ReactNode | null; - }) { - let rounded: 'left' | 'right' | 'none' = 'none'; - if (firstColumnId === id) rounded = 'left'; - else if (lastColumnId === id) rounded = 'right'; - - if (!displayColumns[id]) return <>; - - return ( -
-
- {label} -
- {filteredSortedTrackers.map((data, index) => ( - clickedTracker(data.tracker)} - hover={trackerEqual(data.tracker.trackerId)} - onMouseOver={() => setHoverTracker(data.tracker.trackerId)} - onMouseOut={() => setHoverTracker(null)} - warning={Object.values(statuses).some((status) => - trackerStatusRelated(data.tracker, status) - )} - > - {row(data) || <>} - - ))} -
- ); - } - return ( -
- {column({ - id: DisplayColumn.NAME, - label: l10n.getString('tracker-table-column-name'), - row: ({ tracker }) => , - })} - - {column({ - id: DisplayColumn.TYPE, - label: l10n.getString('tracker-table-column-type'), - row: ({ device }) => ( - - {device?.hardwareInfo?.manufacturer || '--'} - - ), - })} - - {column({ - id: DisplayColumn.BATTERY, - label: l10n.getString('tracker-table-column-battery'), - row: ({ device, tracker }) => - device?.hardwareStatus?.batteryPctEstimate != null && ( - - ), - })} - - {column({ - id: DisplayColumn.PING, - label: l10n.getString('tracker-table-column-ping'), - row: ({ device, tracker }) => - (device?.hardwareStatus?.rssi != null || - device?.hardwareStatus?.ping != null) && ( - - ), - })} - - {column({ - id: DisplayColumn.TPS, - label: l10n.getString('tracker-table-column-tps'), - row: ({ tracker }) => ( - - {tracker?.tps != null ? <>{tracker.tps} : <>} - - ), - })} - - {column({ - id: DisplayColumn.ROTATION, - label: l10n.getString('tracker-table-column-rotation'), - labelClassName: classNames({ - 'w-44': config?.devSettings?.preciseRotation, - 'w-32': !config?.devSettings?.preciseRotation, - }), - row: ({ tracker }) => ( - + + +
+
+
+
+
+
- ), - })} - - {column({ - id: DisplayColumn.TEMPERATURE, - label: l10n.getString('tracker-table-column-temperature'), - row: ({ tracker }) => - tracker?.temp && - tracker?.temp?.temp != 0 && ( - - {`${tracker.temp.temp.toFixed(2)}`} - - ), - })} - - {column({ - id: DisplayColumn.LINEAR_ACCELERATION, - label: l10n.getString('tracker-table-column-linear-acceleration'), - labelClassName: 'w-36', - row: ({ tracker }) => - tracker.linearAcceleration && ( - - {formatVector3(tracker.linearAcceleration, 1)} - - ), - })} - - {column({ - id: DisplayColumn.POSITION, - label: l10n.getString('tracker-table-column-position'), - labelClassName: 'w-36', - row: ({ tracker }) => - tracker.position && ( - - {formatVector3(tracker.position, 2)} - - ), - })} - - {column({ - id: DisplayColumn.STAY_ALIGNED, - label: l10n.getString('tracker-table-column-stay_aligned'), - labelClassName: 'w-36', - row: ({ tracker }) => ( - - ), - })} - - {column({ - id: DisplayColumn.URL, - label: l10n.getString('tracker-table-column-url'), - row: ({ device }) => ( - - udp:// - {IPv4.fromNumber( - device?.hardwareInfo?.ipAddress?.addr || 0 - ).toString()} - - ), - })} +
+
+
+
+
+
+ {filteredSortedTrackers.map((data) => ( + + ))} +
); } diff --git a/gui/src/components/tracking-checklist/TrackingChecklist.tsx b/gui/src/components/tracking-checklist/TrackingChecklist.tsx new file mode 100644 index 000000000..1e3271e82 --- /dev/null +++ b/gui/src/components/tracking-checklist/TrackingChecklist.tsx @@ -0,0 +1,547 @@ +import { + TrackingChecklistStep, + TrackingChecklistContext, + useTrackingChecklist, + trackingchecklistIdtoLabel, +} from '@/hooks/tracking-checklist'; +import classNames from 'classnames'; +import { + ResetType, + TrackingChecklistPublicNetworksT, + TrackingChecklistStepId, +} from 'solarxr-protocol'; +import { ReactNode, useEffect, useMemo, useState } from 'react'; +import { openUrl } from '@tauri-apps/plugin-opener'; +import { CheckIcon } from '@/components/commons/icon/CheckIcon'; +import { Typography } from '@/components/commons/Typography'; +import { Button } from '@/components/commons/Button'; +import { ResetButton } from '@/components/home/ResetButton'; +import { A } from '@/components/commons/A'; +import { LoaderIcon, SlimeState } from '@/components/commons/icon/LoaderIcon'; +import { ProgressBar } from '@/components/commons/ProgressBar'; +import { CrossIcon } from '@/components/commons/icon/CrossIcon'; +import { + ArrowDownIcon, + ArrowRightIcon, +} from '@/components/commons/icon/ArrowIcons'; +import { Localized } from '@fluent/react'; +import { WrenchIcon } from '@/components/commons/icon/WrenchIcons'; +import { TrackingChecklistModal } from './TrackingChecklistModal'; +import { NavLink, useNavigate } from 'react-router-dom'; +import { useBreakpoint } from '@/hooks/breakpoint'; + +function Step({ + step: { status, id, optional, firstRequired }, + children, +}: { + step: TrackingChecklistStep; + index: number; + children: ReactNode; +}) { + const [open, setOpen] = useState(firstRequired); + + const canBeOpened = + (status === 'skipped' || status === 'invalid') && !firstRequired; + + useEffect(() => { + if (!canBeOpened) setOpen(false); + }, [open]); + + return ( +
+
{ + if (canBeOpened) setOpen((open) => !open); + }} + > +
+ {status === 'skipped' && } + {status === 'complete' && } + {(status === 'invalid' || status === 'blocked') && ( +
+ )} +
+
+ + {canBeOpened && ( +
+ +
+ )} +
+
+ {(firstRequired || open) && children && ( +
{children}
+ )} +
+ ); +} + +const stepContentLookup: Record< + number, + ( + step: TrackingChecklistStep, + context: TrackingChecklistContext + ) => JSX.Element +> = { + [TrackingChecklistStepId.TRACKERS_REST_CALIBRATION]: (step, { toggle }) => { + return ( +
+ +
+ {step.ignorable && ( +
+
+ ); + }, + [TrackingChecklistStepId.FULL_RESET]: () => { + return ( +
+ +
+ + + +
+
+
+ + Reset position +
+
+ + Reset position side +
+
+ + Reset position wrong +
+
+
+ +
+
+ ); + }, + [TrackingChecklistStepId.STEAMVR_DISCONNECTED]: (step, { toggle }) => { + return ( + <> +
+ +
+
+
+ + ); + }, + [TrackingChecklistStepId.TRACKER_ERROR]: () => { + return ; + }, + [TrackingChecklistStepId.UNASSIGNED_HMD]: () => { + return ; + }, + [TrackingChecklistStepId.NETWORK_PROFILE_PUBLIC]: (step, { toggle }) => { + const data = step.extraData as TrackingChecklistPublicNetworksT | null; + return ( + <> +
+ + ), + }} + whitespace="whitespace-pre-wrap" + /> +
+
+
+ + ); + }, + [TrackingChecklistStepId.VRCHAT_SETTINGS]: (step, { toggle }) => { + return ( + <> +
+ +
+
+
+ + ); + }, + [TrackingChecklistStepId.MOUNTING_CALIBRATION]: (step, { toggle }) => { + return ( +
+ + +
+ mounting reset ski pose +
+
+ + {step.ignorable && ( +
+
+ ); + }, + [TrackingChecklistStepId.FEET_MOUNTING_CALIBRATION]: (step, { toggle }) => { + return ( +
+ + +
+
+ mounting reset ski pose +
+
+ mounting reset ski pose +
+
+
+ + {step.ignorable && ( +
+
+ ); + }, + [TrackingChecklistStepId.STAY_ALIGNED_CONFIGURED]: (step, { toggle }) => { + return ( + <> +
+ +
+
+
+ + ); + }, +}; + +export function TrackingChecklistMobile() { + const context = useTrackingChecklist(); + const { completion, firstRequired, warnings } = context; + + return ( +
+ +
+ {completion === 'incomplete' ? 'Required:' : 'Warning:'}{' '} + +
+ +
+
+ ); +} + +export function TrackingChecklist({ + closable = true, + closed, + closing, + toggleClosed, +}: { + closable?: boolean; + closed: boolean; + closing: boolean; + toggleClosed: () => void; +}) { + const context = useTrackingChecklist(); + const { visibleSteps, progress, completion, warnings } = context; + + const slimeState = useMemo(() => { + if (completion === 'complete') return SlimeState.HAPPY; + if (completion === 'incomplete') return SlimeState.CURIOUS; + if (completion === 'partial') return SlimeState.SAD; + return SlimeState.HAPPY; + }, [completion]); + + const settingsOpenState = useState(false); + const [, setSettingsOpen] = settingsOpenState; + + return ( + <> +
+
+
+ +
+
+
setSettingsOpen(true)} + > + +
+ {closable && ( +
toggleClosed()} + > + {closed && } + {!closed && } +
+ )} +
+
+
+ {visibleSteps.map((step, index) => ( + + {stepContentLookup[step.id]?.(step, context) || undefined} + + ))} +
+
+
toggleClosed()} + > +
+
+
+
+ {completion === 'incomplete' && ( + + )} + {completion === 'partial' && ( + + )} + {completion == 'complete' && ( + + )} +
+
+
+
+ {!closed && ( + + )} + +
+
+ +
+
+
+
+ + + ); +} + +export function ChecklistPage() { + const nav = useNavigate(); + const { isMobile } = useBreakpoint('mobile'); + + useEffect(() => { + if (!isMobile) nav('/'); + }, [isMobile]); + + return ( +
+ {}} + /> +
+ ); +} diff --git a/gui/src/components/tracking-checklist/TrackingChecklistModal.tsx b/gui/src/components/tracking-checklist/TrackingChecklistModal.tsx new file mode 100644 index 000000000..687491ee8 --- /dev/null +++ b/gui/src/components/tracking-checklist/TrackingChecklistModal.tsx @@ -0,0 +1,36 @@ +import { Dispatch, SetStateAction } from 'react'; +import { BaseModal } from '@/components/commons/BaseModal'; +import { Typography } from '@/components/commons/Typography'; +import { Button } from '@/components/commons/Button'; +import { TrackingChecklistSettings } from '@/components/settings/pages/HomeScreenSettings'; + +export function TrackingChecklistModal({ + open, +}: { + open: [boolean, Dispatch>]; +}) { + return ( + { + open[1](false); + }} + > +
+ + +
+
+
+
+ ); +} diff --git a/gui/src/components/tracking-checklist/TrackingChecklistProvider.tsx b/gui/src/components/tracking-checklist/TrackingChecklistProvider.tsx new file mode 100644 index 000000000..0f65226dc --- /dev/null +++ b/gui/src/components/tracking-checklist/TrackingChecklistProvider.tsx @@ -0,0 +1,19 @@ +import { + TrackingChecklistContectC, + provideTrackingChecklist, +} from '@/hooks/tracking-checklist'; +import { ReactNode } from 'react'; + +export function TrackingChecklistProvider({ + children, +}: { + children: ReactNode; +}) { + const context = provideTrackingChecklist(); + + return ( + + {children} + + ); +} diff --git a/gui/src/components/vr-mode/VRModePage.tsx b/gui/src/components/vr-mode/VRModePage.tsx index d2e42dc6f..e651fab51 100644 --- a/gui/src/components/vr-mode/VRModePage.tsx +++ b/gui/src/components/vr-mode/VRModePage.tsx @@ -1,7 +1,10 @@ import { useEffect } from 'react'; import { useBreakpoint } from '@/hooks/breakpoint'; -import { WidgetsComponent } from '@/components/WidgetsComponent'; -import { useNavigate } from 'react-router-dom'; +import { NavLink, useNavigate } from 'react-router-dom'; +import { SkeletonVisualizerWidget } from '@/components/widgets/SkeletonVisualizerWidget'; +import { Checklist } from '@/components/commons/icon/ChecklistIcon'; +import { PreviewControls } from '@/components/Sidebar'; +import { Vector3 } from 'three'; export function VRModePage() { const nav = useNavigate(); @@ -12,8 +15,30 @@ export function VRModePage() { }, [isMobile]); return ( -
- +
+ { + context.addView({ + left: 0, + bottom: 0, + width: 1, + height: 1, + position: new Vector3(3, 2.5, -3), + onHeightChange(v, newHeight) { + v.controls.target.set(0, newHeight / 2.4, 0.1); + const scale = Math.max(1, newHeight) / 1; + v.camera.zoom = 1 / scale; + }, + }); + }} + /> + + + +
); } diff --git a/gui/src/components/vrc/VRCWarningsPage.tsx b/gui/src/components/vrc/VRCWarningsPage.tsx index 1b4df42fd..7de15bf97 100644 --- a/gui/src/components/vrc/VRCWarningsPage.tsx +++ b/gui/src/components/vrc/VRCWarningsPage.tsx @@ -100,7 +100,7 @@ const onOffKey = (value: boolean) => export function VRCWarningsPage() { const { l10n } = useLocalization(); - const { state, toggleMutedSettings, mutedSettings } = useVRCConfig(); + const { state, toggleMutedSettings } = useVRCConfig(); const { currentLocales } = useLocaleConfig(); const meterFormat = Intl.NumberFormat(currentLocales, { @@ -115,7 +115,7 @@ export function VRCWarningsPage() { const settingRowProps = (key: keyof VRCConfigStateSupported['validity']) => ({ mute: () => toggleMutedSettings(key), - muted: mutedSettings.includes(key), + muted: state.muted.includes(key), valid: state.validity[key] == true, }); diff --git a/gui/src/components/widgets/DeveloperModeWidget.tsx b/gui/src/components/widgets/DeveloperModeWidget.tsx index d26896cc4..fbe77bae5 100644 --- a/gui/src/components/widgets/DeveloperModeWidget.tsx +++ b/gui/src/components/widgets/DeveloperModeWidget.tsx @@ -4,7 +4,6 @@ import { useConfig } from '@/hooks/config'; import { useWebsocketAPI } from '@/hooks/websocket-api'; import { CheckBox } from '@/components/commons/Checkbox'; import { useLocalization } from '@fluent/react'; -import { Typography } from '@/components/commons/Typography'; export interface DeveloperModeWidgetForm { highContrast: boolean; @@ -57,6 +56,7 @@ export function DeveloperModeWidget() { key={index} control={control} variant="toggle" + outlined name={name} label={l10n.getString(`widget-developer_mode-${label}`)} /> @@ -73,10 +73,7 @@ export function DeveloperModeWidget() { }; return ( -
-
- {l10n.getString('widget-developer_mode')} -
+ {Object.entries(toggles).map(makeToggle)}
); diff --git a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx index 078d743bf..2aa41503f 100644 --- a/gui/src/components/widgets/SkeletonVisualizerWidget.tsx +++ b/gui/src/components/widgets/SkeletonVisualizerWidget.tsx @@ -10,7 +10,6 @@ import * as THREE from 'three'; import { BodyPart, BoneT } from 'solarxr-protocol'; import { QuaternionFromQuatT, isIdentity } from '@/maths/quaternion'; import classNames from 'classnames'; -import { Button } from '@/components/commons/Button'; import { useLocalization } from '@fluent/react'; import { ErrorBoundary } from 'react-error-boundary'; import { Typography } from '@/components/commons/Typography'; @@ -18,8 +17,9 @@ import { useAtomValue } from 'jotai'; import { bonesAtom } from '@/store/app-store'; import { useConfig } from '@/hooks/config'; import { Tween } from '@tweenjs/tween.js'; +import { EyeIcon } from '@/components/commons/icon/EyeIcon'; -const GROUND_COLOR = '#4444aa'; +const GROUND_COLOR = '#2c2c6b'; // Just need to know the length of the total body, so don't need right legs const Y_PARTS = [ @@ -32,61 +32,6 @@ const Y_PARTS = [ BodyPart.LEFT_LOWER_LEG, ]; -interface SkeletonVisualizerWidgetProps { - height?: number | string; - maxHeight?: number | string; -} - -export function ToggleableSkeletonVisualizerWidget({ - height, - maxHeight, -}: SkeletonVisualizerWidgetProps) { - const { l10n } = useLocalization(); - const [enabled, setEnabled] = useState(false); - - useEffect(() => { - const state = localStorage.getItem('skeletonModelPreview'); - if (state) setEnabled(state === 'true'); - }, []); - - return ( - <> - {!enabled && ( - - )} - {enabled && ( -
- -
- -
-
- )} - - ); -} - export type SkeletonPreviewView = { left: number; bottom: number; @@ -110,7 +55,7 @@ function initializePreview( const resolution = new THREE.Vector2(canvas.clientWidth, canvas.clientHeight); const scene = new THREE.Scene(); - const renderer = new THREE.WebGLRenderer({ + let renderer: THREE.WebGLRenderer | null = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true, @@ -195,7 +140,7 @@ function initializePreview( const render = (delta: number) => { views.forEach((v) => { - if (v.hidden) return; + if (v.hidden || !renderer) return; v.controls.update(delta); const left = Math.floor(resolution.x * v.left); @@ -251,6 +196,7 @@ function initializePreview( resize: (width: number, height: number) => { resolution.set(width, height); skeletonHelper.resolution.copy(resolution); + if (!renderer) return; renderer.setSize(width, height); }, setFrameInterval: (interval: number) => { @@ -276,9 +222,11 @@ function initializePreview( } }, destroy: () => { - skeletonHelper.dispose(); - renderer.dispose(); cancelAnimationFrame(animationFrameId); + skeletonHelper.dispose(); + if (!renderer) return; + renderer.dispose(); + renderer = null; // Very important for js to free the WebGL context. dispose does not to it alone }, addView: ({ left, @@ -297,6 +245,8 @@ function initializePreview( hidden?: boolean; onHeightChange: (view: SkeletonPreviewView, newHeight: number) => void; }) => { + if (!renderer) return; + const camera = new THREE.PerspectiveCamera( 20, resolution.width / resolution.height, @@ -344,8 +294,10 @@ type PreviewContext = ReturnType; function SkeletonVisualizer({ onInit, + disabled = false, }: { onInit: (context: PreviewContext) => void; + disabled?: boolean; }) { const { config } = useConfig(); @@ -362,15 +314,15 @@ function SkeletonVisualizer({ useEffect(() => { if (bones.size === 0) return; const context = previewContext.current; - if (!context) return; + if (!context || disabled) return; context.rebuildSkeleton(createChildren(bones, BoneKind.root), bones); - }, [bones.size]); + }, [bones.size, disabled]); useEffect(() => { const context = previewContext.current; - if (!context) return; + if (!context || disabled) return; context.updatesBones(bones); - }, [bones]); + }, [bones, disabled]); const onResize = (e: ResizeObserverEntry) => { const context = previewContext.current; @@ -393,6 +345,7 @@ function SkeletonVisualizer({ }; useLayoutEffect(() => { + if (disabled) return; if (!canvasRef.current || !containerRef.current) throw 'invalid state - no canvas or container'; resizeObserver.current.observe(containerRef.current); @@ -416,11 +369,12 @@ function SkeletonVisualizer({ if (!previewContext.current || !containerRef.current) return; resizeObserver.current.unobserve(containerRef.current); previewContext.current.destroy(); + previewContext.current = null; containerRef.current.removeEventListener('mouseenter', onEnter); containerRef.current.removeEventListener('mouseleave', onLeave); }; - }, []); + }, [disabled]); return (
@@ -444,20 +398,53 @@ export function SkeletonVisualizerWidget({ }, }); }, + disabled = false, + toggleDisabled, }: { onInit?: (context: PreviewContext) => void; + disabled?: boolean; + toggleDisabled?: () => void; }) { const { l10n } = useLocalization(); + const [error, setError] = useState(false); return ( - - {l10n.getString('tips-failed_webgl')} - - } - > - - +
+
+ setError(true)} fallback={<>}> + + +
+
+
toggleDisabled?.()} + > + + +
+
+
+
+ + {l10n.getString('tips-failed_webgl')} + +
+
+
); } diff --git a/gui/src/hooks/app.ts b/gui/src/hooks/app.ts index 69fb07431..60a8fb8a0 100644 --- a/gui/src/hooks/app.ts +++ b/gui/src/hooks/app.ts @@ -3,16 +3,13 @@ import { DataFeedMessage, DataFeedUpdateT, ResetResponseT, - ResetStatus, - ResetType, RpcMessage, StartDataFeedT, } from 'solarxr-protocol'; -import { playSoundOnResetEnded, playSoundOnResetStarted } from '@/sounds/sounds'; +import { handleResetSounds } from '@/sounds/sounds'; import { useConfig } from './config'; import { useBonesDataFeedConfig, useDataFeedConfig } from './datafeed-config'; import { useWebsocketAPI } from './websocket-api'; -import { error } from '@/utils/logging'; import { useAtomValue, useSetAtom } from 'jotai'; import { bonesAtom, datafeedAtom, devicesAtom } from '@/store/app-store'; import { updateSentryContext } from '@/utils/sentry'; @@ -55,23 +52,9 @@ export function useProvideAppContext(): AppContext { updateSentryContext(devices); }, [devices]); - useRPCPacket(RpcMessage.ResetResponse, ({ status, resetType }: ResetResponseT) => { + useRPCPacket(RpcMessage.ResetResponse, (resetResponse: ResetResponseT) => { if (!config?.feedbackSound) return; - try { - switch (status) { - case ResetStatus.STARTED: { - if (resetType !== ResetType.Yaw) - playSoundOnResetStarted(config?.feedbackSoundVolume); - break; - } - case ResetStatus.FINISHED: { - playSoundOnResetEnded(resetType, config?.feedbackSoundVolume); - break; - } - } - } catch (e) { - error(e); - } + handleResetSounds(config?.feedbackSoundVolume ?? 1, resetResponse); }); useEffect(() => { diff --git a/gui/src/hooks/body-parts.ts b/gui/src/hooks/body-parts.ts new file mode 100644 index 000000000..a2ac2766f --- /dev/null +++ b/gui/src/hooks/body-parts.ts @@ -0,0 +1,90 @@ +import { BodyPart } from 'solarxr-protocol'; + +export const ALL_BODY_PARTS = [ + BodyPart.NONE, + BodyPart.HEAD, + BodyPart.NECK, + BodyPart.CHEST, + BodyPart.WAIST, + BodyPart.HIP, + BodyPart.LEFT_UPPER_LEG, + BodyPart.RIGHT_UPPER_LEG, + BodyPart.LEFT_LOWER_LEG, + BodyPart.RIGHT_LOWER_LEG, + BodyPart.LEFT_FOOT, + BodyPart.RIGHT_FOOT, + BodyPart.LEFT_LOWER_ARM, + BodyPart.RIGHT_LOWER_ARM, + BodyPart.LEFT_UPPER_ARM, + BodyPart.RIGHT_UPPER_ARM, + BodyPart.LEFT_HAND, + BodyPart.RIGHT_HAND, + BodyPart.LEFT_SHOULDER, + BodyPart.RIGHT_SHOULDER, + BodyPart.UPPER_CHEST, + BodyPart.LEFT_HIP, + BodyPart.RIGHT_HIP, + BodyPart.LEFT_THUMB_METACARPAL, + BodyPart.LEFT_THUMB_PROXIMAL, + BodyPart.LEFT_THUMB_DISTAL, + BodyPart.LEFT_INDEX_PROXIMAL, + BodyPart.LEFT_INDEX_INTERMEDIATE, + BodyPart.LEFT_INDEX_DISTAL, + BodyPart.LEFT_MIDDLE_PROXIMAL, + BodyPart.LEFT_MIDDLE_INTERMEDIATE, + BodyPart.LEFT_MIDDLE_DISTAL, + BodyPart.LEFT_RING_PROXIMAL, + BodyPart.LEFT_RING_INTERMEDIATE, + BodyPart.LEFT_RING_DISTAL, + BodyPart.LEFT_LITTLE_PROXIMAL, + BodyPart.LEFT_LITTLE_INTERMEDIATE, + BodyPart.LEFT_LITTLE_DISTAL, + BodyPart.RIGHT_THUMB_METACARPAL, + BodyPart.RIGHT_THUMB_PROXIMAL, + BodyPart.RIGHT_THUMB_DISTAL, + BodyPart.RIGHT_INDEX_PROXIMAL, + BodyPart.RIGHT_INDEX_INTERMEDIATE, + BodyPart.RIGHT_INDEX_DISTAL, + BodyPart.RIGHT_MIDDLE_PROXIMAL, + BodyPart.RIGHT_MIDDLE_INTERMEDIATE, + BodyPart.RIGHT_MIDDLE_DISTAL, + BodyPart.RIGHT_RING_PROXIMAL, + BodyPart.RIGHT_RING_INTERMEDIATE, + BodyPart.RIGHT_RING_DISTAL, + BodyPart.RIGHT_LITTLE_PROXIMAL, + BodyPart.RIGHT_LITTLE_INTERMEDIATE, + BodyPart.RIGHT_LITTLE_DISTAL, +]; +export const FEET_BODY_PARTS = [BodyPart.LEFT_FOOT, BodyPart.RIGHT_FOOT]; +export const FINGER_BODY_PARTS = [ + BodyPart.LEFT_THUMB_METACARPAL, + BodyPart.LEFT_THUMB_PROXIMAL, + BodyPart.LEFT_THUMB_DISTAL, + BodyPart.LEFT_INDEX_PROXIMAL, + BodyPart.LEFT_INDEX_INTERMEDIATE, + BodyPart.LEFT_INDEX_DISTAL, + BodyPart.LEFT_MIDDLE_PROXIMAL, + BodyPart.LEFT_MIDDLE_INTERMEDIATE, + BodyPart.LEFT_MIDDLE_DISTAL, + BodyPart.LEFT_RING_PROXIMAL, + BodyPart.LEFT_RING_INTERMEDIATE, + BodyPart.LEFT_RING_DISTAL, + BodyPart.LEFT_LITTLE_PROXIMAL, + BodyPart.LEFT_LITTLE_INTERMEDIATE, + BodyPart.LEFT_LITTLE_DISTAL, + BodyPart.RIGHT_THUMB_METACARPAL, + BodyPart.RIGHT_THUMB_PROXIMAL, + BodyPart.RIGHT_THUMB_DISTAL, + BodyPart.RIGHT_INDEX_PROXIMAL, + BodyPart.RIGHT_INDEX_INTERMEDIATE, + BodyPart.RIGHT_INDEX_DISTAL, + BodyPart.RIGHT_MIDDLE_PROXIMAL, + BodyPart.RIGHT_MIDDLE_INTERMEDIATE, + BodyPart.RIGHT_MIDDLE_DISTAL, + BodyPart.RIGHT_RING_PROXIMAL, + BodyPart.RIGHT_RING_INTERMEDIATE, + BodyPart.RIGHT_RING_DISTAL, + BodyPart.RIGHT_LITTLE_PROXIMAL, + BodyPart.RIGHT_LITTLE_INTERMEDIATE, + BodyPart.RIGHT_LITTLE_DISTAL, +]; diff --git a/gui/src/hooks/bvh.ts b/gui/src/hooks/bvh.ts new file mode 100644 index 000000000..e9202d432 --- /dev/null +++ b/gui/src/hooks/bvh.ts @@ -0,0 +1,54 @@ +import { useLocalization } from '@fluent/react'; +import { isTauri } from '@tauri-apps/api/core'; +import { useEffect, useState } from 'react'; +import { RecordBVHRequestT, RecordBVHStatusT, RpcMessage } from 'solarxr-protocol'; +import { useWebsocketAPI } from './websocket-api'; +import { useConfig } from './config'; +import { save } from '@tauri-apps/plugin-dialog'; + +export function useBHV() { + const { config } = useConfig(); + const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); + const [state, setState] = useState<'idle' | 'recording' | 'saving'>('idle'); + const { l10n } = useLocalization(); + + useEffect(() => { + sendRPCPacket(RpcMessage.RecordBVHStatusRequest, new RecordBVHRequestT()); + }, []); + + const toggle = async () => { + const record = new RecordBVHRequestT(state === 'recording'); + + if (isTauri() && state === 'idle') { + if (config?.bvhDirectory) { + record.path = config.bvhDirectory; + } else { + setState('saving'); + record.path = await save({ + title: l10n.getString('bvh-save_title'), + filters: [ + { + name: 'BVH', + extensions: ['bvh'], + }, + ], + defaultPath: 'bvh-recording.bvh', + }); + setState('idle'); + } + } + + sendRPCPacket(RpcMessage.RecordBVHRequest, record); + }; + + useRPCPacket(RpcMessage.RecordBVHStatus, (data: RecordBVHStatusT) => { + setState(data.recording ? 'recording' : 'idle'); + }); + + return { + available: + typeof window.__ANDROID__ === 'undefined' || !window.__ANDROID__?.isThere(), + state, + toggle, + }; +} diff --git a/gui/src/hooks/config.ts b/gui/src/hooks/config.ts index 1e69b343d..934afd7b0 100644 --- a/gui/src/hooks/config.ts +++ b/gui/src/hooks/config.ts @@ -46,6 +46,8 @@ export interface Config { showNavbarOnboarding: boolean; vrcMutedWarnings: string[]; bvhDirectory: string | null; + homeLayout: 'default' | 'table'; + skeletonPreview: boolean; } export interface ConfigContext { @@ -75,6 +77,8 @@ export const defaultConfig: Config = { vrcMutedWarnings: [], devSettings: defaultDevSettings, bvhDirectory: null, + homeLayout: 'default', + skeletonPreview: true, }; interface CrossStorage { diff --git a/gui/src/hooks/countdown.ts b/gui/src/hooks/countdown.ts index 38905033f..e07463c6a 100644 --- a/gui/src/hooks/countdown.ts +++ b/gui/src/hooks/countdown.ts @@ -17,13 +17,16 @@ export function useCountdown({ const startCountdown = () => { setIsCounting(true); setDisplayTimer(duration); + if (countdownTimer.current) { + clearTimer(); + } + counter.current = 0; countdownTimer.current = setInterval( () => { counter.current++; setDisplayTimer(duration - counter.current); if (counter.current >= duration) { - clearInterval(countdownTimer.current); resetEnd(); } }, @@ -31,15 +34,20 @@ export function useCountdown({ ); }; + const clearTimer = () => { + clearInterval(countdownTimer.current); + countdownTimer.current = undefined; + }; + const resetEnd = () => { setIsCounting(false); - clearInterval(countdownTimer.current); + clearTimer(); onCountdownEnd(); }; const abortCountdown = () => { setIsCounting(false); - clearInterval(countdownTimer.current); + clearTimer(); }; return { diff --git a/gui/src/hooks/pause-tracking.ts b/gui/src/hooks/pause-tracking.ts new file mode 100644 index 000000000..2760b14b8 --- /dev/null +++ b/gui/src/hooks/pause-tracking.ts @@ -0,0 +1,47 @@ +import { useEffect, useState } from 'react'; +import { useWebsocketAPI } from './websocket-api'; +import { + RpcMessage, + SetPauseTrackingRequestT, + TrackingPauseStateRequestT, + TrackingPauseStateResponseT, +} from 'solarxr-protocol'; +import { restartAndPlay, trackingPauseSound, trackingPlaySound } from '@/sounds/sounds'; +import { useConfig } from './config'; + +export function usePauseTracking() { + const { config } = useConfig(); + const { useRPCPacket, sendRPCPacket } = useWebsocketAPI(); + const [paused, setPaused] = useState(false); + + const toggle = () => { + const pause = new SetPauseTrackingRequestT(!paused); + sendRPCPacket(RpcMessage.SetPauseTrackingRequest, pause); + + if (!config) return; + if (pause.pauseTracking) { + restartAndPlay(trackingPauseSound, config.feedbackSoundVolume); + } else { + restartAndPlay(trackingPlaySound, config.feedbackSoundVolume); + } + }; + + useRPCPacket( + RpcMessage.TrackingPauseStateResponse, + (data: TrackingPauseStateResponseT) => { + setPaused(data.trackingPaused); + } + ); + + useEffect(() => { + sendRPCPacket( + RpcMessage.TrackingPauseStateRequest, + new TrackingPauseStateRequestT() + ); + }, []); + + return { + toggle, + paused, + }; +} diff --git a/gui/src/hooks/reset-settings.ts b/gui/src/hooks/reset-settings.ts new file mode 100644 index 000000000..8b94e20fa --- /dev/null +++ b/gui/src/hooks/reset-settings.ts @@ -0,0 +1,58 @@ +import { + ChangeSettingsRequestT, + ResetsSettingsT, + RpcMessage, + SettingsResetRequestT, + SettingsResponseT, +} from 'solarxr-protocol'; +import { useWebsocketAPI } from './websocket-api'; +import { useEffect, useState } from 'react'; + +export interface ResetSettingsForm { + resetMountingFeet: boolean; + armsMountingResetMode: number; + yawResetSmoothTime: number; + saveMountingReset: boolean; + resetHmdPitch: boolean; +} + +export const defaultResetSettings = { + resetMountingFeet: false, + armsMountingResetMode: 0, + yawResetSmoothTime: 0.0, + saveMountingReset: false, + resetHmdPitch: false, +}; + +export function loadResetSettings(resetSettingsForm: ResetSettingsForm) { + const resetsSettings = new ResetsSettingsT(); + resetsSettings.resetMountingFeet = resetSettingsForm.resetMountingFeet; + resetsSettings.armsMountingResetMode = resetSettingsForm.armsMountingResetMode; + resetsSettings.yawResetSmoothTime = resetSettingsForm.yawResetSmoothTime; + resetsSettings.saveMountingReset = resetSettingsForm.saveMountingReset; + resetsSettings.resetHmdPitch = resetSettingsForm.resetHmdPitch; + + return resetsSettings; +} + +export function useResetSettings() { + const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); + const [settings, setSettings] = useState(defaultResetSettings); + + useEffect(() => + sendRPCPacket(RpcMessage.SettingsRequest, new SettingsResetRequestT()) + ); + + useRPCPacket(RpcMessage.SettingsResponse, (settings: SettingsResponseT) => { + if (settings.resetsSettings) setSettings(settings.resetsSettings); + }); + + return { + update: (resetSettingsForm: Partial) => { + const req = new ChangeSettingsRequestT(); + const res = loadResetSettings({ ...settings, ...resetSettingsForm }); + req.resetsSettings = res; + sendRPCPacket(RpcMessage.ChangeSettingsRequest, req); + }, + }; +} diff --git a/gui/src/hooks/reset.ts b/gui/src/hooks/reset.ts new file mode 100644 index 000000000..712b15387 --- /dev/null +++ b/gui/src/hooks/reset.ts @@ -0,0 +1,151 @@ +import { useEffect, useMemo, useRef, useState } from 'react'; +import { + BodyPart, + ResetRequestT, + ResetResponseT, + ResetStatus, + ResetType, + RpcMessage, +} from 'solarxr-protocol'; +import { useWebsocketAPI } from './websocket-api'; +import { useAtomValue } from 'jotai'; +import { assignedTrackersAtom } from '@/store/app-store'; +import { FEET_BODY_PARTS, FINGER_BODY_PARTS } from './body-parts'; +import { useLocaleConfig } from '@/i18n/config'; + +export type ResetBtnStatus = 'idle' | 'counting' | 'finished'; + +export type MountingResetGroup = 'default' | 'feet' | 'fingers'; +export type UseResetOptions = + | { type: ResetType.Full | ResetType.Yaw } + | { type: ResetType.Mounting; group: MountingResetGroup }; + +export const BODY_PARTS_GROUPS: Record = { + default: [], + feet: FEET_BODY_PARTS, + fingers: FINGER_BODY_PARTS, +}; + +export function useReset(options: UseResetOptions, onReseted?: () => void) { + if (options.type === ResetType.Mounting && !options.group) options.group = 'default'; + + const { currentLocales } = useLocaleConfig(); + const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); + + const finishedTimeoutRef = useRef(); + const [status, setStatus] = useState('idle'); + const [progress, setProgress] = useState(0); + const [duration, setDuration] = useState(0); + + const parts = BODY_PARTS_GROUPS['group' in options ? options.group : 'default']; + + const triggerReset = () => { + const req = new ResetRequestT(); + req.resetType = options.type; + req.bodyParts = parts; + sendRPCPacket(RpcMessage.ResetRequest, req); + }; + + const onResetFinished = () => { + setStatus('finished'); + if (onReseted) onReseted(); + }; + + const onResetCanceled = () => { + if (status !== 'finished') setStatus('idle'); + }; + + useEffect(() => { + if (status === 'finished') { + finishedTimeoutRef.current = setTimeout(() => { + setStatus('idle'); // only do that if we were on finished status. Allows to reset the outlined border + }, 2000); + } else { + clearTimeout(finishedTimeoutRef.current); + } + return () => { + clearTimeout(finishedTimeoutRef.current); + }; + }, [status]); + + const onResetProgress = (progress: number, duration: number) => { + setProgress(progress / 1000); + setDuration(duration / 1000); + }; + + useRPCPacket( + RpcMessage.ResetResponse, + ({ status, resetType, progress, duration, bodyParts }: ResetResponseT) => { + if ( + resetType !== options.type || + (resetType == ResetType.Mounting && + JSON.stringify(parts) !== JSON.stringify(bodyParts)) + ) { + onResetCanceled(); + return; + } + onResetProgress(progress, duration); + switch (status) { + case ResetStatus.FINISHED: { + onResetFinished(); + break; + } + case ResetStatus.STARTED: { + setStatus('counting'); + break; + } + } + } + ); + + const name = useMemo(() => { + switch (options.type) { + case ResetType.Yaw: + return 'reset-yaw'; + case ResetType.Full: + return 'reset-full'; + case ResetType.Mounting: + if (options.group !== 'default') return `reset-mounting-${options.group}`; + return 'reset-mounting'; + default: + return 'unhandled'; + } + }, [options.type]); + + let disabled = status === 'counting'; + if (options.type === ResetType.Mounting && options.group !== 'default') { + const assignedTrackers = useAtomValue(assignedTrackersAtom); + + if ( + !assignedTrackers.some( + ({ tracker }) => + tracker.info?.bodyPart && + BODY_PARTS_GROUPS[options.group].includes(tracker.info?.bodyPart) + ) + ) + disabled = true; + } + + const localized = useMemo( + () => + Intl.NumberFormat('en-US', { + maximumFractionDigits: 1, + unit: 'second', + unitDisplay: 'narrow', + style: 'unit', + }), + [currentLocales] + ); + + return { + triggerReset, + progress, + duration, + status, + disabled, + name, + timer: localized.format(duration - progress), + }; +} + +export function useMountingReset() {} diff --git a/gui/src/hooks/status-system.ts b/gui/src/hooks/status-system.ts deleted file mode 100644 index 38226301e..000000000 --- a/gui/src/hooks/status-system.ts +++ /dev/null @@ -1,207 +0,0 @@ -import { createContext, useEffect, useReducer, useContext } from 'react'; -import { - BodyPart, - RpcMessage, - StatusData, - StatusMessageT, - StatusPublicNetworkT, - StatusSteamVRDisconnectedT, - StatusSystemFixedT, - StatusSystemRequestT, - StatusSystemResponseT, - StatusSystemUpdateT, - StatusTrackerErrorT, - StatusTrackerResetT, - StatusUnassignedHMDT, - TrackerDataT, -} from 'solarxr-protocol'; -import { useWebsocketAPI } from './websocket-api'; -import { FluentVariable } from '@fluent/bundle'; -import { ReactLocalization } from '@fluent/react'; -import { FlatDeviceTracker } from '@/store/app-store'; - -type StatusSystemStateAction = - | StatusSystemStateFixedAction - | StatusSystemStateNewAction - | StatusSystemStateUpdateAction; - -interface StatusSystemStateFixedAction { - type: RpcMessage.StatusSystemFixed; - data: number; -} - -interface StatusSystemStateUpdateAction { - type: RpcMessage.StatusSystemUpdate; - data: StatusMessageT; -} - -interface StatusSystemStateNewAction { - type: RpcMessage.StatusSystemResponse; - data: StatusMessageT[]; -} - -interface StatusSystemState { - statuses: { - [id: number]: StatusMessageT; - }; -} - -export interface StatusSystemContext { - statuses: { - [id: number]: StatusMessageT; - }; -} - -function reducer( - state: StatusSystemState, - action: StatusSystemStateAction -): StatusSystemState { - switch (action.type) { - case RpcMessage.StatusSystemFixed: { - const newState = { - statuses: { ...state.statuses }, - }; - delete newState.statuses[action.data]; - return newState; - } - case RpcMessage.StatusSystemUpdate: { - return { - statuses: { ...state.statuses, [action.data.id]: action.data }, - }; - } - case RpcMessage.StatusSystemResponse: { - return { - // Convert the array into an object, we dont want to have an array on our map! - statuses: action.data.reduce((prev, cur) => ({ ...prev, [cur.id]: cur }), {}), - }; - } - } -} - -export function useProvideStatusContext(): StatusSystemContext { - const { useRPCPacket, sendRPCPacket, isConnected } = useWebsocketAPI(); - const [state, dispatch] = useReducer(reducer, { statuses: {} }); - - useRPCPacket( - RpcMessage.StatusSystemResponse, - ({ currentStatuses }: StatusSystemResponseT) => - dispatch({ type: RpcMessage.StatusSystemResponse, data: currentStatuses }) - ); - - useRPCPacket(RpcMessage.StatusSystemFixed, ({ fixedStatusId }: StatusSystemFixedT) => - dispatch({ type: RpcMessage.StatusSystemFixed, data: fixedStatusId }) - ); - - useRPCPacket( - RpcMessage.StatusSystemUpdate, - ({ newStatus }: StatusSystemUpdateT) => - newStatus && dispatch({ type: RpcMessage.StatusSystemUpdate, data: newStatus }) - ); - - useEffect(() => { - if (!isConnected) return; - sendRPCPacket(RpcMessage.StatusSystemRequest, new StatusSystemRequestT()); - }, [isConnected]); - - return state; -} - -export const StatusSystemC = createContext(undefined as never); - -export function useStatusContext() { - const context = useContext(StatusSystemC); - if (!context) { - throw new Error('useStatusContext must be within a StatusSystemContext Provider'); - } - return context; -} - -export function parseStatusToLocale( - status: StatusMessageT, - trackers: FlatDeviceTracker[] | null, - l10n: ReactLocalization -): Record { - switch (status.dataType) { - case StatusData.NONE: - case StatusData.StatusTrackerReset: - case StatusData.StatusUnassignedHMD: - return {}; - case StatusData.StatusPublicNetwork: { - const data = status.data as StatusPublicNetworkT; - return { - adapters: data.adapters.join(', '), - count: data.adapters.length, - }; - } - case StatusData.StatusSteamVRDisconnected: { - const data = status.data as StatusSteamVRDisconnectedT; - if (typeof data.bridgeSettingsName === 'string') { - return { type: data.bridgeSettingsName }; - } - return {}; - } - case StatusData.StatusTrackerError: { - const data = status.data as StatusTrackerErrorT; - if (data.trackerId?.trackerNum === undefined || !trackers) { - return {}; - } - - const tracker = trackers.find( - ({ tracker }) => - tracker?.trackerId?.trackerNum == data.trackerId?.trackerNum && - tracker?.trackerId?.deviceId?.id == data.trackerId?.deviceId?.id - ); - if (!tracker) - return { - trackerName: 'unknown', - }; - const name = tracker.tracker.info?.customName - ? tracker.tracker.info?.customName - : tracker.tracker.info?.bodyPart - ? l10n.getString('body_part-' + BodyPart[tracker.tracker.info?.bodyPart]) - : tracker.tracker.info?.displayName || 'unknown'; - if (typeof name !== 'string') { - return { - trackerName: new TextDecoder().decode(name), - }; - } - return { trackerName: name }; - } - } -} - -export const doesntContainTrackerInfo: readonly StatusData[] = [StatusData.NONE]; -export function trackerStatusRelated( - tracker: TrackerDataT, - status: StatusMessageT -): boolean { - if (doesntContainTrackerInfo.includes(status.dataType)) { - return false; - } - - switch (status.dataType) { - case StatusData.StatusTrackerReset: { - const data = status.data as StatusTrackerResetT; - return ( - data.trackerId?.trackerNum == tracker.trackerId?.trackerNum && - data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id - ); - } - case StatusData.StatusTrackerError: { - const data = status.data as StatusTrackerErrorT; - return ( - data.trackerId?.trackerNum == tracker.trackerId?.trackerNum && - data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id - ); - } - case StatusData.StatusUnassignedHMD: { - const data = status.data as StatusUnassignedHMDT; - return ( - data.trackerId?.trackerNum == tracker.trackerId?.trackerNum && - data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id - ); - } - default: - return false; - } -} diff --git a/gui/src/hooks/tracking-checklist.ts b/gui/src/hooks/tracking-checklist.ts new file mode 100644 index 000000000..b63cae9c9 --- /dev/null +++ b/gui/src/hooks/tracking-checklist.ts @@ -0,0 +1,193 @@ +import { + TrackingChecklistRequestT, + TrackingChecklistResponseT, + TrackingChecklistStepId, + TrackingChecklistStepT, + TrackingChecklistStepVisibility, + IgnoreTrackingChecklistStepRequestT, + RpcMessage, + TrackerIdT, +} from 'solarxr-protocol'; +import { useWebsocketAPI } from './websocket-api'; +import { createContext, useContext, useEffect, useMemo, useState } from 'react'; + +export const trackingchecklistIdtoLabel: Record = { + [TrackingChecklistStepId.UNKNOWN]: '', + [TrackingChecklistStepId.TRACKERS_REST_CALIBRATION]: + 'tracking_checklist-TRACKERS_REST_CALIBRATION', + [TrackingChecklistStepId.FULL_RESET]: 'tracking_checklist-FULL_RESET', + [TrackingChecklistStepId.VRCHAT_SETTINGS]: 'tracking_checklist-VRCHAT_SETTINGS', + [TrackingChecklistStepId.STEAMVR_DISCONNECTED]: + 'tracking_checklist-STEAMVR_DISCONNECTED', + [TrackingChecklistStepId.UNASSIGNED_HMD]: 'tracking_checklist-UNASSIGNED_HMD', + [TrackingChecklistStepId.TRACKER_ERROR]: 'tracking_checklist-TRACKER_ERROR', + [TrackingChecklistStepId.NETWORK_PROFILE_PUBLIC]: + 'tracking_checklist-NETWORK_PROFILE_PUBLIC', + [TrackingChecklistStepId.MOUNTING_CALIBRATION]: + 'tracking_checklist-MOUNTING_CALIBRATION', + [TrackingChecklistStepId.FEET_MOUNTING_CALIBRATION]: + 'tracking_checklist-FEET_MOUNTING_CALIBRATION', + [TrackingChecklistStepId.STAY_ALIGNED_CONFIGURED]: + 'tracking_checklist-STAY_ALIGNED_CONFIGURED', +}; + +export type TrackingChecklistStepStatus = + | 'complete' + | 'skipped' + | 'blocked' + | 'invalid'; +export type TrackingChecklistStep = TrackingChecklistStepT & { + status: TrackingChecklistStepStatus; + firstRequired: boolean; +}; +export type highlightedTrackers = { + step: TrackingChecklistStep; + trackers: Array; +}; + +const stepVisibility = ({ visibility, status, firstRequired }: TrackingChecklistStep) => + firstRequired || + visibility === TrackingChecklistStepVisibility.ALWAYS || + (visibility === TrackingChecklistStepVisibility.WHEN_INVALID && status != 'complete'); + +const createStep = ( + steps: TrackingChecklistStepT[], + step: TrackingChecklistStepT, + index: number +): TrackingChecklistStep => { + const previousSteps = steps.slice(0, index); + const previousBlocked = previousSteps.some( + ({ valid, optional }) => !valid && !optional + ); + + let status: TrackingChecklistStepStatus = 'complete'; + if (previousBlocked && !step.valid) status = 'blocked'; + if (!previousBlocked && !step.valid) status = 'invalid'; + + const firstRequiredIndex = steps.findIndex( + (s, index) => !s.valid || (index === steps.length - 1 && !s.valid) + ); + + const skipped = + steps.find( + (s, sIndex) => + (sIndex > index && s.valid && !s.optional) || sIndex === steps.length - 1 + ) || index === steps.length - 1; + if (!step.valid && step.optional && skipped) status = 'skipped'; + + return { + ...step, + status, + firstRequired: + firstRequiredIndex === index || + (firstRequiredIndex === -1 && index === steps.length - 1 && !step.valid), + pack: () => 0, + }; +}; + +export type TrackingChecklistContext = ReturnType; +export type Steps = { + steps: TrackingChecklistStepT[]; + visibleSteps: TrackingChecklistStep[]; + ignoredSteps: TrackingChecklistStepId[]; +}; +export function provideTrackingChecklist() { + const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); + const [steps, setSteps] = useState({ + steps: [], + visibleSteps: [], + ignoredSteps: [], + }); + + useRPCPacket( + RpcMessage.TrackingChecklistResponse, + (data: TrackingChecklistResponseT) => { + const activeSteps = data.steps.filter( + (step) => !data.ignoredSteps.includes(step.id) && step.enabled + ); + setSteps({ + steps: data.steps, + visibleSteps: activeSteps + .map((step: TrackingChecklistStepT, index) => + createStep(activeSteps, step, index) + ) + .filter(stepVisibility), + ignoredSteps: data.ignoredSteps, + }); + } + ); + + useEffect(() => { + sendRPCPacket(RpcMessage.TrackingChecklistRequest, new TrackingChecklistRequestT()); + }, []); + + const firstRequired = useMemo( + () => + steps.visibleSteps.find( + (step) => !step.valid && step.status != 'blocked' && !step.optional + ), + [steps] + ); + + const highlightedTrackers: highlightedTrackers | undefined = useMemo(() => { + if (!firstRequired || !firstRequired.extraData) return undefined; + if ('trackersId' in firstRequired.extraData) { + return { step: firstRequired, trackers: firstRequired.extraData.trackersId }; + } + if ('trackerId' in firstRequired.extraData && firstRequired.extraData.trackerId) { + return { step: firstRequired, trackers: [firstRequired.extraData.trackerId] }; + } + return { step: firstRequired, trackers: [] }; + }, [firstRequired]); + + const progress = useMemo(() => { + const completeSteps = steps.visibleSteps.filter( + (step) => step.status === 'complete' || step.status === 'skipped' + ); + return Math.min(1, completeSteps.length / steps.visibleSteps.length); + }, [steps]); + + const completion: 'complete' | 'partial' | 'incomplete' = useMemo(() => { + if (progress === 1 && steps.visibleSteps.find((step) => step.status === 'skipped')) + return 'partial'; + return progress === 1 || steps.visibleSteps.length === 0 + ? 'complete' + : 'incomplete'; + }, [progress, steps]); + + const warnings = useMemo( + () => steps.visibleSteps.filter((step) => !step.valid), + [steps] + ); + + const ignoreStep = (step: TrackingChecklistStepId, ignore: boolean) => { + const res = new IgnoreTrackingChecklistStepRequestT(); + res.stepId = step; + res.ignore = ignore; + sendRPCPacket(RpcMessage.IgnoreTrackingChecklistStepRequest, res); + }; + + return { + ...steps, + firstRequired, + highlightedTrackers, + progress, + completion, + warnings, + ignoreStep, + toggle: (step: TrackingChecklistStepId) => + ignoreStep(step, !steps.ignoredSteps.includes(step)), + }; +} + +export const TrackingChecklistContectC = createContext( + undefined as never +); + +export function useTrackingChecklist() { + const context = useContext(TrackingChecklistContectC); + if (!context) { + throw new Error('useTrackingChecklist must be within a TrackingChecklistProvider'); + } + return context; +} diff --git a/gui/src/hooks/vrc-config.ts b/gui/src/hooks/vrc-config.ts index 6251807b5..e38305df4 100644 --- a/gui/src/hooks/vrc-config.ts +++ b/gui/src/hooks/vrc-config.ts @@ -3,19 +3,19 @@ import { useWebsocketAPI } from './websocket-api'; import { RpcMessage, VRCAvatarMeasurementType, + VRCConfigSettingToggleMuteT, VRCConfigStateChangeResponseT, VRCConfigStateRequestT, VRCSpineMode, VRCTrackerModel, } from 'solarxr-protocol'; -import { useConfig } from './config'; type NonNull = { [P in keyof T]: NonNullable; }; export type VRCConfigStateSupported = { isSupported: true } & NonNull< - Pick + Pick >; export type VRCConfigState = { isSupported: false } | VRCConfigStateSupported; @@ -45,7 +45,6 @@ export const avatarMeasurementTypeTranslationMap: Record< export function useVRCConfig() { const { sendRPCPacket, useRPCPacket } = useWebsocketAPI(); - const { config, setConfig } = useConfig(); const [state, setState] = useState(null); useLayoutEffect(() => { @@ -59,31 +58,20 @@ export function useVRCConfig() { } ); - const mutedSettings = useMemo(() => { - if (!state?.isSupported) return []; - return Object.keys(state.validity).filter((k) => - config?.vrcMutedWarnings.includes(k) - ); - }, [state, config]); - const invalidConfig = useMemo(() => { if (!state?.isSupported) return false; return Object.entries(state.validity) - .filter(([k]) => !config?.vrcMutedWarnings.includes(k)) + .filter(([k]) => !state.muted.includes(k)) .some(([, v]) => !v); - }, [state, config]); + }, [state]); return { state, invalidConfig, - mutedSettings, toggleMutedSettings: async (key: keyof VRCConfigStateSupported['validity']) => { - if (!config) return; - const index = config.vrcMutedWarnings.findIndex((v) => v === key); - if (index === -1) config.vrcMutedWarnings.push(key); - else config?.vrcMutedWarnings.splice(index, 1); - await setConfig(config); - console.log(config.vrcMutedWarnings); + const req = new VRCConfigSettingToggleMuteT(); + req.key = key; + sendRPCPacket(RpcMessage.VRCConfigSettingToggleMute, req); }, }; } diff --git a/gui/src/index.scss b/gui/src/index.scss index 1cadf718d..28c5673d6 100644 --- a/gui/src/index.scss +++ b/gui/src/index.scss @@ -63,12 +63,11 @@ body { background: theme('colors.background.20'); --navbar-w: 101px; - --widget-w: 274px; --topbar-h: 38px; @screen mobile { --topbar-h: 44px; - --navbar-h: 90px; + --navbar-h: 73px; } } @@ -91,7 +90,7 @@ body { --accent-background-50: 46, 33, 69; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 164, 79, 237; --window-icon-stroke: 192, 161, 216; @@ -153,7 +152,7 @@ body { --accent-background-50: 19, 57, 19; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 54, 161, 54; --window-icon-stroke: 129, 213, 130; @@ -179,7 +178,7 @@ body { --accent-background-50: 57, 57, 19; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 161, 160, 54; --window-icon-stroke: 213, 212, 129; @@ -205,7 +204,7 @@ body { --accent-background-50: 57, 34, 19; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 161, 95, 54; --window-icon-stroke: 213, 162, 129; @@ -231,7 +230,7 @@ body { --accent-background-50: 57, 19, 19; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 161, 54, 54; --window-icon-stroke: 213, 129, 129; @@ -257,7 +256,7 @@ body { --accent-background-50: 39, 39, 39; --success: 80, 232, 151; - --warning: 216, 205, 55; + --warning: 255, 225, 53; --critical: 223, 109, 140; --special: 121, 121, 121; --window-icon-stroke: 172, 172, 172; diff --git a/gui/src/sounds/sounds.ts b/gui/src/sounds/sounds.ts index b890ebd41..2e55e5130 100644 --- a/gui/src/sounds/sounds.ts +++ b/gui/src/sounds/sounds.ts @@ -1,4 +1,4 @@ -import { ResetType } from 'solarxr-protocol'; +import { ResetResponseT, ResetStatus, ResetType } from 'solarxr-protocol'; import Xylophone, { ValidNote } from './xylophone'; const tones: ValidNote[][] = [ @@ -10,47 +10,46 @@ const tones: ValidNote[][] = [ ]; const xylophone = new Xylophone(); - -export async function playSoundOnResetEnded(resetType: ResetType, volume = 1) { - switch (resetType) { - case ResetType.Yaw: { - xylophone.play({ - notes: ['C4'], - offset: 0.15, - type: 'custom', - volume, - }); - break; - } - case ResetType.Full: { - xylophone.play({ - notes: ['E3', 'G3'], - offset: 0.15, - type: 'custom', - volume, - }); - break; - } - case ResetType.Mounting: { - xylophone.play({ - notes: ['G3', 'B3', 'D4'], - offset: 0.15, - type: 'custom', - volume, - }); - break; - } +const mew = createAudio('/sounds/mew.ogg'); +const resetSounds: Record< + ResetType, + { + initial: HTMLAudioElement | null; + tick: HTMLAudioElement[] | null; + end: HTMLAudioElement; + mew: HTMLAudioElement | null; } -} +> = { + [ResetType.Full]: { + initial: createAudio('/sounds/full-reset/init-full-reset-with-tail.ogg'), + tick: [ + createAudio('/sounds/full-reset/full-click-1.ogg'), + createAudio('/sounds/full-reset/full-click-2.ogg'), + createAudio('/sounds/full-reset/full-click-3.ogg'), + ], + end: createAudio('/sounds/full-reset/end-full-reset-with-tail.ogg'), + mew, + }, + [ResetType.Yaw]: { + initial: null, + tick: null, + end: createAudio('/sounds/yaw-reset/yaw-reset.ogg'), + mew: null, + }, + [ResetType.Mounting]: { + initial: createAudio('/sounds/mounting-reset/init-mounting-reset-with-tail.ogg'), + tick: [ + createAudio('/sounds/mounting-reset/mount-click-1.ogg'), + createAudio('/sounds/mounting-reset/mount-click-2.ogg'), + createAudio('/sounds/mounting-reset/mount-click-3.ogg'), + ], + end: createAudio('/sounds/mounting-reset/end-mounting-reset-with-tail.ogg'), + mew, + }, +}; -export async function playSoundOnResetStarted(volume = 1) { - await xylophone.play({ - notes: ['A4'], - offset: 0.4, - type: 'custom', - volume, - }); -} +export const trackingPauseSound = createAudio('/sounds/tracking/pause.ogg'); +export const trackingPlaySound = createAudio('/sounds/tracking/play.ogg'); let lastTap = 0; export async function playTapSetupSound(volume = 1) { @@ -84,3 +83,58 @@ export async function playTapSetupSound(volume = 1) { lastTap = 0; } } + +function createAudio(path: string): HTMLAudioElement { + const audio = new Audio(path); + audio.preload = 'auto'; + audio.load(); + return audio; +} + +export function restartAndPlay(audio: HTMLAudioElement | null, volume: number) { + if (!audio) return; + try { + audio.load(); // LINUX: Solves wierd bug where webkit would unload sounds wierdly and make the sounds not play anymore + + audio.volume = Math.min(1, Math.pow(volume, Math.E) + 0.05); + audio.currentTime = 0; + const playPromise = audio.play(); + if (playPromise !== undefined) { + playPromise.catch((error) => { + console.error('Audio playback failed:', error); + }); + } + } catch (error) { + console.error('Audio error:', error); + } +} + +export function handleResetSounds( + volume: number, + { progress, status, resetType }: ResetResponseT +) { + if (!resetSounds) throw 'sounds not loaded'; + const sounds = resetSounds[resetType]; + + if (status === ResetStatus.STARTED) { + if (progress === 0) { + performance.mark('sound_start'); + restartAndPlay(sounds.initial, volume); + } + + if (sounds.tick) { + const tickIndex = (progress / 1000) % sounds.tick.length; + if (progress >= 1000 && sounds.tick[tickIndex]) { + restartAndPlay(sounds.tick[tickIndex], volume); + } + } + } + + if (status === ResetStatus.FINISHED) { + performance.mark('sound_end'); + console.log(performance.measure('sound', 'sound_start', 'sound_end')); + + restartAndPlay(sounds.end, volume); + restartAndPlay(sounds.mew, volume); + } +} diff --git a/gui/src/store/app-store.ts b/gui/src/store/app-store.ts index 3b48ab44a..5786b8cc8 100644 --- a/gui/src/store/app-store.ts +++ b/gui/src/store/app-store.ts @@ -9,6 +9,7 @@ import { } from 'solarxr-protocol'; import { selectAtom } from 'jotai/utils'; import { isEqual } from '@react-hookz/deep-equal'; +import { FEET_BODY_PARTS, FINGER_BODY_PARTS } from '@/hooks/body-parts'; export interface FlatDeviceTracker { device?: DeviceDataT; @@ -45,14 +46,18 @@ export const unassignedTrackersAtom = atom((get) => { return trackers.filter(({ tracker }) => tracker.info?.bodyPart === BodyPart.NONE); }); -export const connectedIMUTrackersAtom = atom((get) => { +export const connectedTrackersAtom = atom((get) => { const trackers = get(flatTrackersAtom); return trackers.filter( - ({ tracker }) => - tracker.status !== TrackerStatus.DISCONNECTED && tracker.info?.isImu + ({ tracker }) => tracker.status !== TrackerStatus.DISCONNECTED ); }); +export const connectedIMUTrackersAtom = atom((get) => { + const trackers = get(connectedTrackersAtom); + return trackers.filter(({ tracker }) => tracker.info?.isImu); +}); + export const computedTrackersAtom = selectAtom( datafeedAtom, (datafeed) => datafeed.syntheticTrackers.map((tracker) => ({ tracker })), @@ -95,3 +100,16 @@ export const trackerFromIdAtom = ({ (a) => a, isEqual ); + +export const feetAssignedTrackers = atom((get) => + get(assignedTrackersAtom).some( + (t) => t.tracker.info?.bodyPart && FEET_BODY_PARTS.includes(t.tracker.info.bodyPart) + ) +); + +export const fingerAssignedTrackers = atom((get) => + get(assignedTrackersAtom).some( + (t) => + t.tracker.info?.bodyPart && FINGER_BODY_PARTS.includes(t.tracker.info.bodyPart) + ) +); diff --git a/gui/src/utils/skeletonHelper.ts b/gui/src/utils/skeletonHelper.ts index 0ff8f8e23..eb77d95a4 100644 --- a/gui/src/utils/skeletonHelper.ts +++ b/gui/src/utils/skeletonHelper.ts @@ -188,11 +188,11 @@ export class BoneKind extends Bone { case BodyPart.NONE: throw 'Unexpected body part'; case BodyPart.HEAD: - return new Color('black'); + return new Color('gold'); case BodyPart.NECK: return new Color('silver'); case BodyPart.UPPER_CHEST: - return new Color('blue'); + return new Color('chartreuse'); case BodyPart.CHEST: return new Color('purple'); case BodyPart.WAIST: @@ -201,13 +201,13 @@ export class BoneKind extends Bone { return new Color('orange'); case BodyPart.LEFT_UPPER_LEG: case BodyPart.RIGHT_UPPER_LEG: - return new Color('blue'); + return new Color('chartreuse'); case BodyPart.LEFT_LOWER_LEG: case BodyPart.RIGHT_LOWER_LEG: return new Color('teal'); case BodyPart.LEFT_FOOT: case BodyPart.RIGHT_FOOT: - return new Color('#00ffcc'); + return new Color('gold'); case BodyPart.LEFT_LOWER_ARM: case BodyPart.RIGHT_LOWER_ARM: return new Color('red'); diff --git a/gui/tailwind.config.ts b/gui/tailwind.config.ts index 34ab01a0b..cf61eee43 100644 --- a/gui/tailwind.config.ts +++ b/gui/tailwind.config.ts @@ -3,6 +3,7 @@ import forms from '@tailwindcss/forms'; import typography from '@tailwindcss/typography'; import gradient from 'tailwind-gradient-mask-image'; import type { Config } from 'tailwindcss'; +import { transform } from 'typescript'; const colors = { 'blue-gray': { @@ -172,6 +173,7 @@ const config = { nsm: { raw: 'not (min-width: 900px)' }, sm: '900px', md: '1100px', + nmd: { raw: 'not (min-width: 1100px)' }, 'md-max': { raw: 'not (min-width: 1100px)' }, lg: '1300px', xl: '1600px', @@ -228,6 +230,54 @@ const config = { 'animation-timing-function': 'cubic-bezier(0.8, 0, 1, 1)', }, }, + 'timer-tick': { + "0%, 40%": { + transform: 'scale(1)', + }, + "20%": { + transform: 'scale(1.3)', + }, + }, + 'spin-ccw': { + '0%': { + transform: 'rotate(0deg)', + }, + '100%': { + transform: 'rotate(-360deg)', + }, + }, + skiing: { + '0%, 100%': { + transform: 'rotate(0deg) translateX(0%) translateY(0%)', + }, + '10%': { + transform: 'rotate(12deg) translateX(-5%) translateY(5%)', + }, + '20%': { + transform: 'rotate(10deg) translateX(0%) translateY(0%)', + }, + '30%': { + transform: 'rotate(12deg) translateX(5%) translateY(-5%)', + }, + '40%': { + transform: 'rotate(10deg) translateX(0%) translateY(0%)', + }, + '50%': { + transform: 'rotate(12deg) translateX(-5%) translateY(5%)', + }, + '60%': { + transform: 'rotate(10deg) translateX(0%) translateY(0%)', + }, + '70%': { + transform: 'rotate(12deg) translateX(5%) translateY(-5%)', + }, + '80%': { + transform: 'rotate(10deg) translateX(0%) translateY(0%)', + }, + '90%': { + transform: 'rotate(10deg) translateX(-5%) translateY(5%)', + }, + }, }, backgroundImage: { slime: `linear-gradient(135deg, ${colors.purple[100]} 50%, ${colors['blue-gray'][700]} 50% 100%)`, @@ -240,6 +290,11 @@ const config = { 'trans-flag': `linear-gradient(135deg, ${colors['trans-blue'][800]} 40%, ${colors['trans-blue'][700]} 40% 70%, ${colors['trans-blue'][600]} 70% 100%)`, 'asexual-flag': `linear-gradient(135deg, ${colors['asexual'][100]} 30%, ${colors['asexual'][200]} 30% 50%, ${colors['asexual'][300]} 50% 70%, ${colors['asexual'][400]} 70% 100%)`, }, + animation: { + 'spin-ccw': 'spin-ccw 1s linear infinite', + 'timer-tick': 'timer-tick 1s linear infinite', + skiing: 'skiing 1s linear infinite', + }, }, data: { checked: 'checked=true', diff --git a/gui/tsconfig.json b/gui/tsconfig.json index 5de11b699..a89d9f33b 100644 --- a/gui/tsconfig.json +++ b/gui/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target": "es2022", - "lib": ["dom", "dom.iterable", "ES2023"], + "target": "es2023", + "lib": ["dom", "dom.iterable", "es2023"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 571c03745..7a4cf380e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,10 +10,10 @@ importers: devDependencies: husky: specifier: ^9.1.6 - version: 9.1.7 + version: 9.1.6 lint-staged: specifier: ^15.2.10 - version: 15.5.2 + version: 15.2.10 gui: dependencies: @@ -25,61 +25,61 @@ importers: version: 0.15.2(@fluent/bundle@0.18.0)(react@18.3.1) '@fontsource/poppins': specifier: ^5.1.0 - version: 5.2.6 + version: 5.1.0 '@formatjs/intl-localematcher': specifier: ^0.2.32 version: 0.2.32 '@hookform/resolvers': specifier: ^3.6.0 - version: 3.10.0(react-hook-form@7.65.0(react@18.3.1)) + version: 3.6.0(react-hook-form@7.66.0(react@18.3.1)) '@react-hookz/deep-equal': specifier: ^3.0.3 - version: 3.0.4 + version: 3.0.3 '@react-three/drei': specifier: ^9.114.3 - version: 9.122.0(@react-three/fiber@8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.24)(@types/three@0.163.0)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)(use-sync-external-store@1.5.0(react@18.3.1)) + version: 9.114.5(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.11)(@types/three@0.163.0)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@react-three/fiber': specifier: ^8.17.10 - version: 8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + version: 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@sentry/react': specifier: ^9.9.0 - version: 9.46.0(react@18.3.1) + version: 9.9.0(react@18.3.1) '@sentry/vite-plugin': specifier: ^2.22.7 - version: 2.23.1 + version: 2.22.7 '@tailwindcss/typography': specifier: ^0.5.15 - version: 0.5.16(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.9.2))) + version: 0.5.15(tailwindcss@3.4.14(ts-node@9.1.1(typescript@5.6.3))) '@tanstack/react-query': specifier: ^5.48.0 - version: 5.87.1(react@18.3.1) + version: 5.48.0(react@18.3.1) '@tauri-apps/api': - specifier: ~2 - version: 2.8.0 + specifier: ^2.0.2 + version: 2.0.2 '@tauri-apps/plugin-dialog': - specifier: ~2 - version: 2.4.0 + specifier: ^2.0.0 + version: 2.0.0 '@tauri-apps/plugin-fs': - specifier: ~2 - version: 2.4.2 + specifier: 2.4.1 + version: 2.4.1 '@tauri-apps/plugin-http': - specifier: ~2 - version: 2.5.2 + specifier: ^2.5.0 + version: 2.5.0 '@tauri-apps/plugin-log': specifier: ~2 - version: 2.7.0 + version: 2.7.1 '@tauri-apps/plugin-opener': - specifier: ~2 - version: 2.5.0 - '@tauri-apps/plugin-os': - specifier: ~2 - version: 2.3.1 - '@tauri-apps/plugin-shell': - specifier: ~2 - version: 2.3.1 - '@tauri-apps/plugin-store': - specifier: ~2 + specifier: ^2.4.0 version: 2.4.0 + '@tauri-apps/plugin-os': + specifier: ^2.0.0 + version: 2.0.0 + '@tauri-apps/plugin-shell': + specifier: ^2.3.0 + version: 2.3.0 + '@tauri-apps/plugin-store': + specifier: ^2.4.1 + version: 2.4.1 '@tweenjs/tween.js': specifier: ^25.0.0 version: 25.0.0 @@ -103,10 +103,10 @@ importers: version: 2.0.1 ip-num: specifier: ^1.5.1 - version: 1.5.2 + version: 1.5.1 jotai: specifier: ^2.12.2 - version: 2.13.1(@babel/core@7.28.4)(@babel/template@7.27.2)(@types/react@18.3.24)(react@18.3.1) + version: 2.12.2(@types/react@18.3.11)(react@18.3.1) prompts: specifier: ^2.4.2 version: 2.4.2 @@ -118,31 +118,31 @@ importers: version: 18.3.1(react@18.3.1) react-error-boundary: specifier: ^4.0.13 - version: 4.1.2(react@18.3.1) + version: 4.0.13(react@18.3.1) react-helmet: specifier: ^6.1.0 version: 6.1.0(react@18.3.1) react-hook-form: specifier: ^7.63.0 - version: 7.65.0(react@18.3.1) + version: 7.66.0(react@18.3.1) react-markdown: specifier: ^9.0.1 - version: 9.1.0(@types/react@18.3.24)(react@18.3.1) + version: 9.0.1(@types/react@18.3.11)(react@18.3.1) react-modal: specifier: ^3.16.1 - version: 3.16.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react-responsive: specifier: ^10.0.0 - version: 10.0.1(react@18.3.1) + version: 10.0.0(react@18.3.1) react-router-dom: specifier: ^6.26.2 - version: 6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 6.27.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) remark-gfm: specifier: ^4.0.0 - version: 4.0.1 + version: 4.0.0 semver: specifier: ^7.6.3 - version: 7.7.2 + version: 7.6.3 solarxr-protocol: specifier: file:../solarxr-protocol version: link:../solarxr-protocol @@ -151,47 +151,47 @@ importers: version: 0.163.0 ts-pattern: specifier: ^5.4.0 - version: 5.8.0 + version: 5.5.0 typescript: specifier: ^5.6.3 - version: 5.9.2 + version: 5.6.3 use-double-tap: specifier: ^1.3.6 - version: 1.3.7(react@18.3.1) + version: 1.3.6(react@18.3.1) yup: specifier: ^1.4.0 - version: 1.7.0 + version: 1.4.0 devDependencies: '@dword-design/eslint-plugin-import-alias': specifier: ^4.0.9 version: 4.0.9 '@openapi-codegen/cli': specifier: ^2.0.2 - version: 2.0.4(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 2.0.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@openapi-codegen/typescript': specifier: ^8.0.2 - version: 8.1.1 + version: 8.0.2 '@stylistic/eslint-plugin': specifier: ^5.5.0 - version: 5.5.0(eslint@9.39.0(jiti@1.21.6)) + version: 5.5.0(eslint@9.39.1(jiti@1.21.6)) '@tailwindcss/forms': specifier: ^0.5.9 - version: 0.5.10(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.9.2))) + version: 0.5.9(tailwindcss@3.4.14(ts-node@9.1.1(typescript@5.6.3))) '@tauri-apps/cli': specifier: ~2 - version: 2.8.4 + version: 2.0.3 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 '@types/node': specifier: ^24.3.1 - version: 24.3.1 + version: 24.10.0 '@types/react': specifier: ^18.3.11 - version: 18.3.24 + version: 18.3.11 '@types/react-dom': specifier: ^18.3.0 - version: 18.3.7(@types/react@18.3.24) + version: 18.3.0 '@types/react-helmet': specifier: ^6.1.11 version: 6.1.11 @@ -200,61 +200,61 @@ importers: version: 3.16.3 '@types/semver': specifier: ^7.5.8 - version: 7.7.1 + version: 7.5.8 '@types/three': specifier: ^0.163.0 version: 0.163.0 '@typescript-eslint/eslint-plugin': specifier: ^7.18.0 - version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) '@typescript-eslint/parser': specifier: ^7.18.0 - version: 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + version: 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) '@vitejs/plugin-react': specifier: ^4.3.2 - version: 4.7.0(vite@5.4.19(@types/node@24.3.1)(sass@1.92.0)(terser@5.31.1)) + version: 4.3.2(vite@5.4.9(@types/node@24.10.0)(sass@1.80.2)(terser@5.31.1)) autoprefixer: specifier: ^10.4.20 - version: 10.4.21(postcss@8.5.6) + version: 10.4.20(postcss@8.4.38) cross-env: specifier: ^7.0.3 version: 7.0.3 dotenv: specifier: ^16.4.5 - version: 16.6.1 + version: 16.4.5 eslint: specifier: ^9.39.0 - version: 9.39.0(jiti@1.21.6) + version: 9.39.1(jiti@1.21.6) eslint-config-airbnb: specifier: ^19.0.4 - version: 19.0.4(eslint-plugin-import@2.32.0)(eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.0(jiti@1.21.6)))(eslint-plugin-react-hooks@4.6.2(eslint@9.39.0(jiti@1.21.6)))(eslint-plugin-react@7.37.5(eslint@9.39.0(jiti@1.21.6)))(eslint@9.39.0(jiti@1.21.6)) + version: 19.0.4(eslint-plugin-import@2.32.0)(eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1(jiti@1.21.6)))(eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@1.21.6)))(eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.6)))(eslint@9.39.1(jiti@1.21.6)) eslint-import-resolver-typescript: specifier: ^3.10.1 - version: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.6)) + version: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.6)) eslint-plugin-import: specifier: ^2.32.0 - version: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)) + version: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)) eslint-plugin-jsx-a11y: specifier: ^6.10.2 - version: 6.10.2(eslint@9.39.0(jiti@1.21.6)) + version: 6.10.2(eslint@9.39.1(jiti@1.21.6)) eslint-plugin-react: specifier: ^7.37.5 - version: 7.37.5(eslint@9.39.0(jiti@1.21.6)) + version: 7.37.5(eslint@9.39.1(jiti@1.21.6)) eslint-plugin-react-hooks: specifier: ^4.6.2 - version: 4.6.2(eslint@9.39.0(jiti@1.21.6)) + version: 4.6.2(eslint@9.39.1(jiti@1.21.6)) globals: specifier: ^15.10.0 - version: 15.15.0 + version: 15.10.0 prettier: specifier: ^3.3.3 - version: 3.6.2 + version: 3.3.3 rollup-plugin-visualizer: specifier: ^5.12.0 - version: 5.14.0(rollup@4.50.0) + version: 5.12.0(rollup@4.24.0) sass: specifier: ^1.79.4 - version: 1.92.0 + version: 1.80.2 spdx-satisfies: specifier: ^5.0.1 version: 5.0.1 @@ -263,13 +263,13 @@ importers: version: 1.2.0 tailwindcss: specifier: ^3.4.13 - version: 3.4.17(ts-node@9.1.1(typescript@5.9.2)) + version: 3.4.14(ts-node@9.1.1(typescript@5.6.3)) typescript-eslint: specifier: ^8.46.2 - version: 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + version: 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) vite: specifier: ^5.4.8 - version: 5.4.19(@types/node@24.3.1)(sass@1.92.0)(terser@5.31.1) + version: 5.4.9(@types/node@24.10.0)(sass@1.80.2)(terser@5.31.1) solarxr-protocol: dependencies: @@ -286,21 +286,21 @@ importers: packages: - '@alcalzone/ansi-tokenize@0.1.3': - resolution: {integrity: sha512-3yWxPTq3UQ/FY9p1ErPxIyfT64elWaMvM9lIHnaqpyft63tkxodF5aUElYHrdisWve5cETkh1+KBw1yJuW0aRw==} - engines: {node: '>=14.13.1'} - '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - '@apollo/client@3.14.0': - resolution: {integrity: sha512-0YQKKRIxiMlIou+SekQqdCo0ZTHxOcES+K8vKB53cIDpwABNR0P0yRzPgsbgcj3zRJniD93S/ontsnZsCLZrxQ==} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@apollo/client@3.10.6': + resolution: {integrity: sha512-3lLFGJtzC1/mEnK11BRf+Bf8536kBQUSB1G9yMtcRsxmY+tCKdTPzsP3fMUKy10BPIE0sDUY1pux3iMPIn2vow==} peerDependencies: graphql: ^15.0.0 || ^16.0.0 - graphql-ws: ^5.5.5 || ^6.0.3 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc + graphql-ws: ^5.5.5 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 subscriptions-transport-ws: ^0.9.0 || ^0.11.0 peerDependenciesMeta: graphql-ws: @@ -312,98 +312,189 @@ packages: subscriptions-transport-ws: optional: true - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.24.7': + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.4': - resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} + '@babel/code-frame@7.25.7': + resolution: {integrity: sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.4': - resolution: {integrity: sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==} + '@babel/compat-data@7.24.7': + resolution: {integrity: sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + '@babel/compat-data@7.25.8': + resolution: {integrity: sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/core@7.24.7': + resolution: {integrity: sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/core@7.25.8': + resolution: {integrity: sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/generator@7.24.7': + resolution: {integrity: sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/generator@7.25.7': + resolution: {integrity: sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.24.7': + resolution: {integrity: sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.25.7': + resolution: {integrity: sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.24.7': + resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.24.7': + resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.24.7': + resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.7': + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.25.7': + resolution: {integrity: sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.24.7': + resolution: {integrity: sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-module-transforms@7.25.7': + resolution: {integrity: sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.7': + resolution: {integrity: sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-simple-access@7.24.7': + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-simple-access@7.25.7': + resolution: {integrity: sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-split-export-declaration@7.24.7': + resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helper-string-parser@7.24.7': + resolution: {integrity: sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/helper-string-parser@7.25.7': + resolution: {integrity: sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.24.7': + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.25.7': + resolution: {integrity: sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.24.7': + resolution: {integrity: sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.25.7': + resolution: {integrity: sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.7': + resolution: {integrity: sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.25.7': + resolution: {integrity: sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.7': + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.25.7': + resolution: {integrity: sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.7': + resolution: {integrity: sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + '@babel/parser@7.25.8': + resolution: {integrity: sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.24.7': + resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + '@babel/plugin-transform-react-jsx-source@7.24.7': + resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.24.7': + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/template@7.24.7': + resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': - resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} + '@babel/template@7.25.7': + resolution: {integrity: sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@babel/traverse@7.24.7': + resolution: {integrity: sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.25.7': + resolution: {integrity: sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.7': + resolution: {integrity: sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.25.8': + resolution: {integrity: sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==} engines: {node: '>=6.9.0'} '@dword-design/dedent@0.7.0': resolution: {integrity: sha512-OFmAmzKiDUh9m7WRMYcoEOPI7b5tS5hdqQmtKDwF+ZssVJv8a+GHo9VOtFsmlw3h8Roh/9QzFWIsjSFZyQUMdg==} - '@dword-design/endent@1.4.7': - resolution: {integrity: sha512-yK1ivALMq9Eys6O9SgO+jBpRbQBLruFL2FvWMWPcoqiY1hPDHleY02Vir6jN6j7tDiMog3tjVtqKb4eWXdKo1w==} + '@dword-design/endent@1.4.1': + resolution: {integrity: sha512-e2sCTzth5kyRdM0o+yEb5wBVzUdJL8Y6HblRGRV0Bif0knf1ZjRLhUjdCrqM+Muirb68X/xJzgdRDJVmLqgXGA==} '@dword-design/eslint-plugin-import-alias@4.0.9': resolution: {integrity: sha512-GbDZ0HJOnLgc8X2iGM+SW/2Y2Zi8qJ96+zsJWO4nhfEmHSKPcC3MUldVFLrrHy1z5R+MEba6tp7455U2UYB0bQ==} @@ -414,11 +505,11 @@ packages: engines: {node: '>=14'} deprecated: Use lodash and endent - '@emnapi/core@1.5.0': - resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + '@emnapi/core@1.7.0': + resolution: {integrity: sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + '@emnapi/runtime@1.7.0': + resolution: {integrity: sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} @@ -561,12 +652,22 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.4.0': + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.10.1': + resolution: {integrity: sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} @@ -587,8 +688,8 @@ packages: resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.39.0': - resolution: {integrity: sha512-BIhe0sW91JGPiaF1mOuPy5v8NflqfjIcDNpC+LbW9f609WVRX1rArrhi6Z2ymvrAry9jw+5POTj4t2t62o8Bmw==} + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.7': @@ -619,8 +720,8 @@ packages: peerDependencies: '@fluent/bundle': '>= 0.13.0' - '@fontsource/poppins@5.2.6': - resolution: {integrity: sha512-NFr0121+vWCfzLDVvSZOzwAjRUaNj6QHA9gtUh/KHHoWf1Qn23EkwVFs63XZ6UtF5K1b3UNmCx77YEMGgV7BOQ==} + '@fontsource/poppins@5.1.0': + resolution: {integrity: sha512-tpLXlnNi2fwQjiipvuj4uNFHCdoLA8izRsKdoexZuEzjx0r/g1aKLf4ta6lFgF7L+/+AFdmaXFlUwwvmDzYH+g==} '@formatjs/intl-localematcher@0.2.32': resolution: {integrity: sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==} @@ -630,8 +731,8 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@hookform/resolvers@3.10.0': - resolution: {integrity: sha512-79Dv+3mDF7i+2ajj7SkypSKHhl1cbln1OGavqrsF7p6mbUv11xpqpacPsGDCTRvCSjEEIez2ef1NveSVL3b0Ag==} + '@hookform/resolvers@3.6.0': + resolution: {integrity: sha512-UBcpyOX3+RR+dNnqBd0lchXpoL8p4xC21XP8H6Meb8uve5Br1GCnmg0PcBoKKqPKgGu9GHQ/oygcmPrQhetwqw==} peerDependencies: react-hook-form: ^7.0.0 @@ -655,37 +756,36 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - '@mediapipe/tasks-vision@0.10.17': - resolution: {integrity: sha512-CZWV/q6TTe8ta61cZXjfnnHsfWIdFhms03M9T7Cnd5y2mdpylJM0rF1qRq+wsQVRMLz1OYPVEBU9ph2Bx8cxrg==} + '@mediapipe/tasks-vision@0.10.8': + resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==} '@mgit-at/typescript-flatbuffers-codegen@0.1.3': resolution: {integrity: sha512-sf9vaoiR/SR0dpV568GhsoLbd6659StJ4Gl9jszZL/bsJJaF5VmLYbI57OSI4JDm+L6d3osVMl9mkchox9j6/g==} hasBin: true - '@monogrid/gainmap-js@3.1.0': - resolution: {integrity: sha512-Obb0/gEd/HReTlg8ttaYk+0m62gQJmCblMOjHSMHRrBP2zdfKMHLCRbh/6ex9fSUJMKdjjIEiohwkbGD3wj2Nw==} + '@monogrid/gainmap-js@3.0.5': + resolution: {integrity: sha512-53sCTG4FaJBaAq/tcufARtVYDMDGqyBT9i7F453pWGhZ5LqubDHDWtYoHo9VhQqMcHTEexdJqSsR58y+9HVmQA==} peerDependencies: three: '>= 0.159.0' @@ -708,12 +808,12 @@ packages: resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} engines: {node: '>=12.4.0'} - '@openapi-codegen/cli@2.0.4': - resolution: {integrity: sha512-ekeOMArpFZBTTOHYkKb08wE7XXC46CCgFhTzrbQSYc7Xj23GIiR130pcCn2tipb5PZcPL4nlwkZdMJC+WhWGvw==} + '@openapi-codegen/cli@2.0.2': + resolution: {integrity: sha512-uBk6yOBSBIgGWA2ok/IjBS03UwVAIpnan0lKz2sk3tsSe8rVIjOnQPxGYvSuByfxzdIu+nrPom2meqtcjlMvDQ==} hasBin: true - '@openapi-codegen/typescript@8.1.1': - resolution: {integrity: sha512-KGnFyoQc4lhtVVvX6lk2btF9GDDUbu8Jvn5C89aHuyIA4nor/Rlt7f7QHaYpecFDX8RZrPcYGrDZ8OFNUkEOlA==} + '@openapi-codegen/typescript@8.0.2': + resolution: {integrity: sha512-7X9WR+qlIMcMxiBgheGzyQcChLSPVqNYf9SAFJdTOJQLWfy+gaXiDonUC8WC7p6Hpz7eM6OLU1i7f/h+2RlH1w==} '@parcel/watcher-android-arm64@2.4.1': resolution: {integrity: sha512-LOi/WTbbh3aTn2RYddrO8pnapixAziFl6SMxHM69r3tvdSm94JtCenaKgk1GRg5FJ5wpMCpHeW+7yqPlvZv7kg==} @@ -795,58 +895,59 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@react-hookz/deep-equal@3.0.4': - resolution: {integrity: sha512-QpcSUTP1I0lI8/GvSEvclkoEGRWjbYxuUWaecxr8eJRceivGF18wHoJwaej2NYxMn7SqhKaZ9JYQvmdATiSG8A==} + '@react-hookz/deep-equal@3.0.3': + resolution: {integrity: sha512-SLy+NmiDpncqc2d9TR4Y4R7f8lUFOQK9WbnIq02A6wDxy+dTHfA2Np0dPvj0SFp6i1nqERLmEUe9MxPLuO/IqA==} engines: {node: '>=18.0.0'} + deprecated: Package is deprecated and will be deleted soon. Use @ver0/deep-equal instead. - '@react-spring/animated@9.7.5': - resolution: {integrity: sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg==} + '@react-spring/animated@9.6.1': + resolution: {integrity: sha512-ls/rJBrAqiAYozjLo5EPPLLOb1LM0lNVQcXODTC1SMtS6DbuBCPaKco5svFUQFMP2dso3O+qcC4k9FsKc0KxMQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/core@9.7.5': - resolution: {integrity: sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w==} + '@react-spring/core@9.6.1': + resolution: {integrity: sha512-3HAAinAyCPessyQNNXe5W0OHzRfa8Yo5P748paPcmMowZ/4sMfaZ2ZB6e5x5khQI8NusOHj8nquoutd6FRY5WQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/rafz@9.7.5': - resolution: {integrity: sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw==} + '@react-spring/rafz@9.6.1': + resolution: {integrity: sha512-v6qbgNRpztJFFfSE3e2W1Uz+g8KnIBs6SmzCzcVVF61GdGfGOuBrbjIcp+nUz301awVmREKi4eMQb2Ab2gGgyQ==} - '@react-spring/shared@9.7.5': - resolution: {integrity: sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw==} + '@react-spring/shared@9.6.1': + resolution: {integrity: sha512-PBFBXabxFEuF8enNLkVqMC9h5uLRBo6GQhRMQT/nRTnemVENimgRd+0ZT4yFnAQ0AxWNiJfX3qux+bW2LbG6Bw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@react-spring/three@9.7.5': - resolution: {integrity: sha512-RxIsCoQfUqOS3POmhVHa1wdWS0wyHAUway73uRLp3GAL5U2iYVNdnzQsep6M2NZ994BlW8TcKuMtQHUqOsy6WA==} + '@react-spring/three@9.6.1': + resolution: {integrity: sha512-Tyw2YhZPKJAX3t2FcqvpLRb71CyTe1GvT3V+i+xJzfALgpk10uPGdGaQQ5Xrzmok1340DAeg2pR/MCfaW7b8AA==} peerDependencies: '@react-three/fiber': '>=6.0' react: ^16.8.0 || ^17.0.0 || ^18.0.0 three: '>=0.126' - '@react-spring/types@9.7.5': - resolution: {integrity: sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g==} + '@react-spring/types@9.6.1': + resolution: {integrity: sha512-POu8Mk0hIU3lRXB3bGIGe4VHIwwDsQyoD1F394OK7STTiX9w4dG3cTLljjYswkQN+hDSHRrj4O36kuVa7KPU8Q==} - '@react-three/drei@9.122.0': - resolution: {integrity: sha512-SEO/F/rBCTjlLez7WAlpys+iGe9hty4rNgjZvgkQeXFSiwqD4Hbk/wNHMAbdd8vprO2Aj81mihv4dF5bC7D0CA==} + '@react-three/drei@9.114.5': + resolution: {integrity: sha512-nXD/wOwQVaaKF1WXG5Ah3ief+Mojm5YInlk91tanzEYdG+5Vhno34AFn3xt0XKMAaHA+Lkjfi+BpqnVama+JPA==} peerDependencies: - '@react-three/fiber': ^8 - react: ^18 - react-dom: ^18 + '@react-three/fiber': '>=8.0' + react: '>=18.0' + react-dom: '>=18.0' three: '>=0.137' peerDependenciesMeta: react-dom: optional: true - '@react-three/fiber@8.18.0': - resolution: {integrity: sha512-FYZZqD0UUHUswKz3LQl2Z7H24AhD14XGTsIRw3SJaXUxyfVMi+1yiZGmqTcPt/CkPpdU7rrxqcyQ1zJE5DjvIQ==} + '@react-three/fiber@8.17.10': + resolution: {integrity: sha512-S6bqa4DqUooEkInYv/W+Jklv2zjSYCXAhm6qKpAQyOXhTEt5gBXnA7W6aoJ0bjmp9pAeaSj/AZUoz1HCSof/uA==} peerDependencies: expo: '>=43.0' expo-asset: '>=8.4' expo-file-system: '>=11.0' expo-gl: '>=11.0' - react: '>=18 <19' - react-dom: '>=18 <19' + react: '>=18.0' + react-dom: '>=18.0' react-native: '>=0.64' three: '>=0.133' peerDependenciesMeta: @@ -863,147 +964,119 @@ packages: react-native: optional: true - '@remix-run/router@1.23.0': - resolution: {integrity: sha512-O3rHJzAQKamUz1fvE0Qaw0xSFqsA/yafi2iqeE0pvdFtCO1viYx8QL6f3Ln/aCCTLxs68SLf0KPM9eSeM8yBnA==} + '@remix-run/router@1.20.0': + resolution: {integrity: sha512-mUnk8rPJBI9loFDZ+YzPGdeniYK+FTmRD1TMCz7ev2SNIozyKKpnGgsxO34u6Z4z/t0ITuu7voi/AshfsGsgFg==} engines: {node: '>=14.0.0'} - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.50.0': - resolution: {integrity: sha512-lVgpeQyy4fWN5QYebtW4buT/4kn4p4IJ+kDNB4uYNT5b8c8DLJDg6titg20NIg7E8RWwdWZORW6vUFfrLyG3KQ==} + '@rollup/rollup-android-arm-eabi@4.24.0': + resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.50.0': - resolution: {integrity: sha512-2O73dR4Dc9bp+wSYhviP6sDziurB5/HCym7xILKifWdE9UsOe2FtNcM+I4xZjKrfLJnq5UR8k9riB87gauiQtw==} + '@rollup/rollup-android-arm64@4.24.0': + resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.50.0': - resolution: {integrity: sha512-vwSXQN8T4sKf1RHr1F0s98Pf8UPz7pS6P3LG9NSmuw0TVh7EmaE+5Ny7hJOZ0M2yuTctEsHHRTMi2wuHkdS6Hg==} + '@rollup/rollup-darwin-arm64@4.24.0': + resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.50.0': - resolution: {integrity: sha512-cQp/WG8HE7BCGyFVuzUg0FNmupxC+EPZEwWu2FCGGw5WDT1o2/YlENbm5e9SMvfDFR6FRhVCBePLqj0o8MN7Vw==} + '@rollup/rollup-darwin-x64@4.24.0': + resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.50.0': - resolution: {integrity: sha512-UR1uTJFU/p801DvvBbtDD7z9mQL8J80xB0bR7DqW7UGQHRm/OaKzp4is7sQSdbt2pjjSS72eAtRh43hNduTnnQ==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.50.0': - resolution: {integrity: sha512-G/DKyS6PK0dD0+VEzH/6n/hWDNPDZSMBmqsElWnCRGrYOb2jC0VSupp7UAHHQ4+QILwkxSMaYIbQ72dktp8pKA==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.50.0': - resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==} + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': + resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm-musleabihf@4.50.0': - resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==} + '@rollup/rollup-linux-arm-musleabihf@4.24.0': + resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.50.0': - resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==} + '@rollup/rollup-linux-arm64-gnu@4.24.0': + resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.50.0': - resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==} + '@rollup/rollup-linux-arm64-musl@4.24.0': + resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-loongarch64-gnu@4.50.0': - resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.50.0': - resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==} + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': + resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.50.0': - resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==} + '@rollup/rollup-linux-riscv64-gnu@4.24.0': + resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.50.0': - resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.50.0': - resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==} + '@rollup/rollup-linux-s390x-gnu@4.24.0': + resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.50.0': - resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==} + '@rollup/rollup-linux-x64-gnu@4.24.0': + resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.50.0': - resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==} + '@rollup/rollup-linux-x64-musl@4.24.0': + resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.50.0': - resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.50.0': - resolution: {integrity: sha512-q7cIIdFvWQoaCbLDUyUc8YfR3Jh2xx3unO8Dn6/TTogKjfwrax9SyfmGGK6cQhKtjePI7jRfd7iRYcxYs93esg==} + '@rollup/rollup-win32-arm64-msvc@4.24.0': + resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.50.0': - resolution: {integrity: sha512-XzNOVg/YnDOmFdDKcxxK410PrcbcqZkBmz+0FicpW5jtjKQxcW1BZJEQOF0NJa6JO7CZhett8GEtRN/wYLYJuw==} + '@rollup/rollup-win32-ia32-msvc@4.24.0': + resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.50.0': - resolution: {integrity: sha512-xMmiWRR8sp72Zqwjgtf3QbZfF1wdh8X2ABu3EaozvZcyHJeU0r+XAnXdKgs4cCAp6ORoYoCygipYP1mjmbjrsg==} + '@rollup/rollup-win32-x64-msvc@4.24.0': + resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} cpu: [x64] os: [win32] '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - '@sentry-internal/browser-utils@9.46.0': - resolution: {integrity: sha512-Q0CeHym9wysku8mYkORXmhtlBE0IrafAI+NiPSqxOBKXGOCWKVCvowHuAF56GwPFic2rSrRnub5fWYv7T1jfEQ==} + '@sentry-internal/browser-utils@9.9.0': + resolution: {integrity: sha512-V/YhKLis98JFkqBGZaEBlDNFpJHJjoCvNb05raAYXdITfDIl37Kxqj0zX+IzyRhqnswkQ+DBTyoEoci09IR2bQ==} engines: {node: '>=18'} - '@sentry-internal/feedback@9.46.0': - resolution: {integrity: sha512-KLRy3OolDkGdPItQ3obtBU2RqDt9+KE8z7r7Gsu7c6A6A89m8ZVlrxee3hPQt6qp0YY0P8WazpedU3DYTtaT8w==} + '@sentry-internal/feedback@9.9.0': + resolution: {integrity: sha512-hrxuOLm0Xsnx75hTNt3eLgNNjER3egrHZShdRzlMiakfKpA9f2X10z75vlZmT5ZUygDQnp9UVUnu28cDuVb9Zw==} engines: {node: '>=18'} - '@sentry-internal/replay-canvas@9.46.0': - resolution: {integrity: sha512-QcBjrdRWFJrrrjbmrr2bbrp2R9RYj1KMEbhHNT2Lm1XplIQw+tULEKOHxNtkUFSLR1RNje7JQbxhzM1j95FxVQ==} + '@sentry-internal/replay-canvas@9.9.0': + resolution: {integrity: sha512-YK0ixGjquahGpNsQskCEVwycdHlwNBLCx9XJr1BmGnlOw6fUCmpyVetaGg/ZyhkzKGNXAGoTa4s7FUFnAG4bKg==} engines: {node: '>=18'} - '@sentry-internal/replay@9.46.0': - resolution: {integrity: sha512-+8JUblxSSnN0FXcmOewbN+wIc1dt6/zaSeAvt2xshrfrLooVullcGsuLAiPhY0d/e++Fk06q1SAl9g4V0V13gg==} + '@sentry-internal/replay@9.9.0': + resolution: {integrity: sha512-EWczKMu3qiZ0SUUWU3zkGod+AWD/VQCLiQw+tw+PEpdHbRZIdYKsEptengZCFKthrwe2QmYpVCTSRxGvujJ/6g==} engines: {node: '>=18'} - '@sentry/babel-plugin-component-annotate@2.23.1': - resolution: {integrity: sha512-l1z8AvI6k9I+2z49OgvP3SlzB1M0Lw24KtceiJibNaSyQwxsItoT9/XftZ/8BBtkosVmNOTQhL1eUsSkuSv1LA==} + '@sentry/babel-plugin-component-annotate@2.22.7': + resolution: {integrity: sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ==} engines: {node: '>= 14'} - '@sentry/browser@9.46.0': - resolution: {integrity: sha512-NOnCTQCM0NFuwbyt4DYWDNO2zOTj1mCf43hJqGDFb1XM9F++7zAmSNnCx4UrEoBTiFOy40McJwBBk9D1blSktA==} + '@sentry/browser@9.9.0': + resolution: {integrity: sha512-pIMdkOC+iggZefBs6ck5fL1mBhbLzjdw/8K99iqSeDh+lLvmlHVZajAhPlmw50xfH8CyQ1s22dhcL+zXbg3NKw==} engines: {node: '>=18'} - '@sentry/bundler-plugin-core@2.23.1': - resolution: {integrity: sha512-JA6utNiwMKv6Jfj0Hmk0DI/XUizSHg7HhhkFETKhRlYEhZAdkyz1atDBg0ncKNgRBKyHeSYWcMFtUyo26VB76w==} + '@sentry/bundler-plugin-core@2.22.7': + resolution: {integrity: sha512-ouQh5sqcB8vsJ8yTTe0rf+iaUkwmeUlGNFi35IkCFUQlWJ22qS6OfvNjOqFI19e6eGUXks0c/2ieFC4+9wJ+1g==} engines: {node: '>= 14'} '@sentry/cli-darwin@2.39.1': @@ -1052,18 +1125,18 @@ packages: engines: {node: '>= 10'} hasBin: true - '@sentry/core@9.46.0': - resolution: {integrity: sha512-it7JMFqxVproAgEtbLgCVBYtQ9fIb+Bu0JD+cEplTN/Ukpe6GaolyYib5geZqslVxhp2sQgT+58aGvfd/k0N8Q==} + '@sentry/core@9.9.0': + resolution: {integrity: sha512-GxKvx8PSgoWhLLS+/WBGIXy7rsFcnJBPDqFXIfcAGy89k2j06d9IP0kiIc63qBGStSUkh5FFJLPTakZ5RXiFXA==} engines: {node: '>=18'} - '@sentry/react@9.46.0': - resolution: {integrity: sha512-2NTlke1rKAJO2JIY1RCrv8EjfXXkLc+AC61PpgF1QjH/cz0NuCZ6gpQi6M5qS7anAGPjaOE1t3QdLeOEI/Q3kA==} + '@sentry/react@9.9.0': + resolution: {integrity: sha512-7BE2Lx5CNtHtlNSS7Z9HxKquohC0xhdFceO3NlMXlx+dZuVCMoQmLISB8SQEcHw+2VO24MvtP3LPEzdeNbkIfg==} engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - '@sentry/vite-plugin@2.23.1': - resolution: {integrity: sha512-avtjtIQ019sZW3FklpmNNsQOnYZjCHpnVxgDGElfZb+AaR4AvtHNlxXLJp+iqEfSK+Xok8MJarJqIgCaWcF40Q==} + '@sentry/vite-plugin@2.22.7': + resolution: {integrity: sha512-sYRNiNm4toQGq2BfZSJPdw36em3eQaLu+3NTFpA7Hl4g3Sp2Rt3CYObnW5bxlFEruRhxzvdyB383N9OefVZ6KA==} engines: {node: '>= 14'} '@sindresorhus/is@5.6.0': @@ -1076,71 +1149,71 @@ packages: peerDependencies: eslint: '>=9.0.0' - '@swc/core-darwin-arm64@1.13.5': - resolution: {integrity: sha512-lKNv7SujeXvKn16gvQqUQI5DdyY8v7xcoO3k06/FJbHJS90zEwZdQiMNRiqpYw/orU543tPaWgz7cIYWhbopiQ==} + '@swc/core-darwin-arm64@1.6.5': + resolution: {integrity: sha512-RGQhMdni2v1/ANQ/2K+F+QYdzaucekYBewZcX1ogqJ8G5sbPaBdYdDN1qQ4kHLCIkPtGP6qC7c71qPEqL2RidQ==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.13.5': - resolution: {integrity: sha512-ILd38Fg/w23vHb0yVjlWvQBoE37ZJTdlLHa8LRCFDdX4WKfnVBiblsCU9ar4QTMNdeTBEX9iUF4IrbNWhaF1Ng==} + '@swc/core-darwin-x64@1.6.5': + resolution: {integrity: sha512-/pSN0/Jtcbbb9+ovS9rKxR3qertpFAM3OEJr/+Dh/8yy7jK5G5EFPIrfsw/7Q5987ERPIJIH6BspK2CBB2tgcg==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.13.5': - resolution: {integrity: sha512-Q6eS3Pt8GLkXxqz9TAw+AUk9HpVJt8Uzm54MvPsqp2yuGmY0/sNaPPNVqctCX9fu/Nu8eaWUen0si6iEiCsazQ==} + '@swc/core-linux-arm-gnueabihf@1.6.5': + resolution: {integrity: sha512-B0g/dROCE747RRegs/jPHuKJgwXLracDhnqQa80kFdgWEMjlcb7OMCgs5OX86yJGRS4qcYbiMGD0Pp7Kbqn3yw==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.13.5': - resolution: {integrity: sha512-aNDfeN+9af+y+M2MYfxCzCy/VDq7Z5YIbMqRI739o8Ganz6ST+27kjQFd8Y/57JN/hcnUEa9xqdS3XY7WaVtSw==} + '@swc/core-linux-arm64-gnu@1.6.5': + resolution: {integrity: sha512-W8meapgXTq8AOtSvDG4yKR8ant2WWD++yOjgzAleB5VAC+oC+aa8YJROGxj8HepurU8kurqzcialwoMeq5SZZQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-arm64-musl@1.13.5': - resolution: {integrity: sha512-9+ZxFN5GJag4CnYnq6apKTnnezpfJhCumyz0504/JbHLo+Ue+ZtJnf3RhyA9W9TINtLE0bC4hKpWi8ZKoETyOQ==} + '@swc/core-linux-arm64-musl@1.6.5': + resolution: {integrity: sha512-jyCKqoX50Fg8rJUQqh4u5PqnE7nqYKXHjVH2WcYr114/MU21zlsI+YL6aOQU1XP8bJQ2gPQ1rnlnGJdEHiKS/w==} engines: {node: '>=10'} cpu: [arm64] os: [linux] - '@swc/core-linux-x64-gnu@1.13.5': - resolution: {integrity: sha512-WD530qvHrki8Ywt/PloKUjaRKgstQqNGvmZl54g06kA+hqtSE2FTG9gngXr3UJxYu/cNAjJYiBifm7+w4nbHbA==} + '@swc/core-linux-x64-gnu@1.6.5': + resolution: {integrity: sha512-G6HmUn/RRIlXC0YYFfBz2qh6OZkHS/KUPkhoG4X9ADcgWXXjOFh6JrefwsYj8VBAJEnr5iewzjNfj+nztwHaeA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-linux-x64-musl@1.13.5': - resolution: {integrity: sha512-Luj8y4OFYx4DHNQTWjdIuKTq2f5k6uSXICqx+FSabnXptaOBAbJHNbHT/06JZh6NRUouaf0mYXN0mcsqvkhd7Q==} + '@swc/core-linux-x64-musl@1.6.5': + resolution: {integrity: sha512-AQpBjBnelQDSbeTJA50AXdS6+CP66LsXIMNTwhPSgUfE7Bx1ggZV11Fsi4Q5SGcs6a8Qw1cuYKN57ZfZC5QOuA==} engines: {node: '>=10'} cpu: [x64] os: [linux] - '@swc/core-win32-arm64-msvc@1.13.5': - resolution: {integrity: sha512-cZ6UpumhF9SDJvv4DA2fo9WIzlNFuKSkZpZmPG1c+4PFSEMy5DFOjBSllCvnqihCabzXzpn6ykCwBmHpy31vQw==} + '@swc/core-win32-arm64-msvc@1.6.5': + resolution: {integrity: sha512-MZTWM8kUwS30pVrtbzSGEXtek46aXNb/mT9D6rsS7NvOuv2w+qZhjR1rzf4LNbbn5f8VnR4Nac1WIOYZmfC5ng==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.13.5': - resolution: {integrity: sha512-C5Yi/xIikrFUzZcyGj9L3RpKljFvKiDMtyDzPKzlsDrKIw2EYY+bF88gB6oGY5RGmv4DAX8dbnpRAqgFD0FMEw==} + '@swc/core-win32-ia32-msvc@1.6.5': + resolution: {integrity: sha512-WZdu4gISAr3yOm1fVwKhhk6+MrP7kVX0KMP7+ZQFTN5zXQEiDSDunEJKVgjMVj3vlR+6mnAqa/L0V9Qa8+zKlQ==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.13.5': - resolution: {integrity: sha512-YrKdMVxbYmlfybCSbRtrilc6UA8GF5aPmGKBdPvjrarvsmf4i7ZHGCEnLtfOMd3Lwbs2WUZq3WdMbozYeLU93Q==} + '@swc/core-win32-x64-msvc@1.6.5': + resolution: {integrity: sha512-ezXgucnMTzlFIxQZw7ls/5r2hseFaRoDL04cuXUOs97E8r+nJSmFsRQm/ygH5jBeXNo59nyZCalrjJAjwfgACA==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.13.5': - resolution: {integrity: sha512-WezcBo8a0Dg2rnR82zhwoR6aRNxeTGfK5QCD6TQ+kg3xx/zNT02s/0o+81h/3zhvFSB24NtqEr8FTw88O5W/JQ==} + '@swc/core@1.6.5': + resolution: {integrity: sha512-tyVvUK/HDOUUsK6/GmWvnqUtD9oDpPUA4f7f7JCOV8hXxtfjMtAZeBKf93yrB1XZet69TDR7EN0hFC6i4MF0Ig==} engines: {node: '>=10'} peerDependencies: - '@swc/helpers': '>=0.5.17' + '@swc/helpers': '*' peerDependenciesMeta: '@swc/helpers': optional: true @@ -1148,131 +1221,131 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/types@0.1.24': - resolution: {integrity: sha512-tjTMh3V4vAORHtdTprLlfoMptu1WfTZG9Rsca6yOKyNYsRr+MUXutKmliB17orgSZk5DpnDxs8GUdd/qwYxOng==} + '@swc/types@0.1.9': + resolution: {integrity: sha512-qKnCno++jzcJ4lM4NTfYifm1EFSCeIfKiAHAfkENZAV5Kl9PjJIyd2yeeVv6c/2CckuLyv2NmRC5pv6pm2WQBg==} '@szmarczak/http-timer@5.0.1': resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} engines: {node: '>=14.16'} - '@tailwindcss/forms@0.5.10': - resolution: {integrity: sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==} + '@tailwindcss/forms@0.5.9': + resolution: {integrity: sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==} peerDependencies: - tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' - '@tailwindcss/typography@0.5.16': - resolution: {integrity: sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==} + '@tailwindcss/typography@0.5.15': + resolution: {integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==} peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' - '@tanstack/query-core@5.87.1': - resolution: {integrity: sha512-HOFHVvhOCprrWvtccSzc7+RNqpnLlZ5R6lTmngb8aq7b4rc2/jDT0w+vLdQ4lD9bNtQ+/A4GsFXy030Gk4ollA==} + '@tanstack/query-core@5.48.0': + resolution: {integrity: sha512-lZAfPPeVIqXCswE9SSbG33B6/91XOWt/Iq41bFeWb/mnHwQSIfFRbkS4bfs+WhIk9abRArF9Id2fp0Mgo+hq6Q==} - '@tanstack/react-query@5.87.1': - resolution: {integrity: sha512-YKauf8jfMowgAqcxj96AHs+Ux3m3bWT1oSVKamaRPXSnW2HqSznnTCEkAVqctF1e/W9R/mPcyzzINIgpOH94qg==} + '@tanstack/react-query@5.48.0': + resolution: {integrity: sha512-GDExbjYWzvDokyRqMSWXdrPiYpp95Aig0oeMIrxTaruOJJgWiWfUP//OAaowm2RrRkGVsavSZdko/XmIrrV2Nw==} peerDependencies: - react: ^18 || ^19 + react: ^18.0.0 - '@tauri-apps/api@2.8.0': - resolution: {integrity: sha512-ga7zdhbS2GXOMTIZRT0mYjKJtR9fivsXzsyq5U3vjDL0s6DTMwYRm0UHNjzTY5dh4+LSC68Sm/7WEiimbQNYlw==} + '@tauri-apps/api@2.0.2': + resolution: {integrity: sha512-3wSwmG+1kr6WrgAFKK5ijkNFPp8TT3FLj3YHUb5EwMO+3FxX4uWlfSWkeeBy+Kc1RsKzugtYLuuya+98Flj+3w==} - '@tauri-apps/cli-darwin-arm64@2.8.4': - resolution: {integrity: sha512-BKu8HRkYV01SMTa7r4fLx+wjgtRK8Vep7lmBdHDioP6b8XH3q2KgsAyPWfEZaZIkZ2LY4SqqGARaE9oilNe0oA==} + '@tauri-apps/api@2.6.0': + resolution: {integrity: sha512-hRNcdercfgpzgFrMXWwNDBN0B7vNzOzRepy6ZAmhxi5mDLVPNrTpo9MGg2tN/F7JRugj4d2aF7E1rtPXAHaetg==} + + '@tauri-apps/api@2.9.0': + resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==} + + '@tauri-apps/cli-darwin-arm64@2.0.3': + resolution: {integrity: sha512-jIsbxGWS+As1ZN7umo90nkql/ZAbrDK0GBT6UsgHSz5zSwwArICsZFFwE1pLZip5yoiV5mn3TGG2c1+v+0puzQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@2.8.4': - resolution: {integrity: sha512-imb9PfSd/7G6VAO7v1bQ2A3ZH4NOCbhGJFLchxzepGcXf9NKkfun157JH9mko29K6sqAwuJ88qtzbKCbWJTH9g==} + '@tauri-apps/cli-darwin-x64@2.0.3': + resolution: {integrity: sha512-ROITHtLTA1muyrwgyuwyasmaLCGtT4as/Kd1kerXaSDtFcYrnxiM984ZD0+FDUEDl5BgXtYa/sKKkKQFjgmM0A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': - resolution: {integrity: sha512-Ml215UnDdl7/fpOrF1CNovym/KjtUbCuPgrcZ4IhqUCnhZdXuphud/JT3E8X97Y03TZ40Sjz8raXYI2ET0exzw==} + '@tauri-apps/cli-linux-arm-gnueabihf@2.0.3': + resolution: {integrity: sha512-bQ3EZwCFfrLg/ZQ2I8sLuifSxESz4TP56SleTkKsPtTIZgNnKpM88PRDz4neiRroHVOq8NK0X276qi9LjGcXPw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@2.8.4': - resolution: {integrity: sha512-pbcgBpMyI90C83CxE5REZ9ODyIlmmAPkkJXtV398X3SgZEIYy5TACYqlyyv2z5yKgD8F8WH4/2fek7+jH+ZXAw==} + '@tauri-apps/cli-linux-arm64-gnu@2.0.3': + resolution: {integrity: sha512-aLfAA8P9OTErVUk3sATxtXqpAtlfDPMPp4fGjDysEELG/MyekGhmh2k/kG/i32OdPeCfO+Nr37wJksARJKubGw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-arm64-musl@2.8.4': - resolution: {integrity: sha512-zumFeaU1Ws5Ay872FTyIm7z8kfzEHu8NcIn8M6TxbJs0a7GRV21KBdpW1zNj2qy7HynnpQCqjAYXTUUmm9JAOw==} + '@tauri-apps/cli-linux-arm64-musl@2.0.3': + resolution: {integrity: sha512-I4MVD7nf6lLLRmNQPpe5beEIFM6q7Zkmh77ROA5BNu/+vHNL5kiTMD+bmd10ZL2r753A6pO7AvqkIxcBuIl0tg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': - resolution: {integrity: sha512-qiqbB3Zz6IyO201f+1ojxLj65WYj8mixL5cOMo63nlg8CIzsP23cPYUrx1YaDPsCLszKZo7tVs14pc7BWf+/aQ==} - engines: {node: '>= 10'} - cpu: [riscv64] - os: [linux] - - '@tauri-apps/cli-linux-x64-gnu@2.8.4': - resolution: {integrity: sha512-TaqaDd9Oy6k45Hotx3pOf+pkbsxLaApv4rGd9mLuRM1k6YS/aw81YrsMryYPThrxrScEIUcmNIHaHsLiU4GMkw==} + '@tauri-apps/cli-linux-x64-gnu@2.0.3': + resolution: {integrity: sha512-C6Jkx2zZGKkoi+sg5FK9GoH/0EvAaOgrZfF5azV5EALGba46g7VpWcZgp9zFUd7K2IzTi+0OOY8TQ2OVfKZgew==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-linux-x64-musl@2.8.4': - resolution: {integrity: sha512-ot9STAwyezN8w+bBHZ+bqSQIJ0qPZFlz/AyscpGqB/JnJQVDFQcRDmUPFEaAtt2UUHSWzN3GoTJ5ypqLBp2WQA==} + '@tauri-apps/cli-linux-x64-musl@2.0.3': + resolution: {integrity: sha512-qi4ghmTfSAl+EEUDwmwI9AJUiOLNSmU1RgiGgcPRE+7A/W+Am9UnxYySAiRbB/gJgTl9sj/pqH5Y9duP1/sqHg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@tauri-apps/cli-win32-arm64-msvc@2.8.4': - resolution: {integrity: sha512-+2aJ/g90dhLiOLFSD1PbElXX3SoMdpO7HFPAZB+xot3CWlAZD1tReUFy7xe0L5GAR16ZmrxpIDM9v9gn5xRy/w==} + '@tauri-apps/cli-win32-arm64-msvc@2.0.3': + resolution: {integrity: sha512-UXxHkYmFesC97qVmZre4vY7oDxRDtC2OeKNv0bH+iSnuUp/ROxzJYGyaelnv9Ybvgl4YVqDCnxgB28qMM938TA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@2.8.4': - resolution: {integrity: sha512-yj7WDxkL1t9Uzr2gufQ1Hl7hrHuFKTNEOyascbc109EoiAqCp0tgZ2IykQqOZmZOHU884UAWI1pVMqBhS/BfhA==} + '@tauri-apps/cli-win32-ia32-msvc@2.0.3': + resolution: {integrity: sha512-D+xoaa35RGlkXDpnL5uDTpj29untuC5Wp6bN9snfgFDagD0wnFfC8+2ZQGu16bD0IteWqDI0OSoIXhNvy+F+wg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@2.8.4': - resolution: {integrity: sha512-XuvGB4ehBdd7QhMZ9qbj/8icGEatDuBNxyYHbLKsTYh90ggUlPa/AtaqcC1Fo69lGkTmq9BOKrs1aWSi7xDonA==} + '@tauri-apps/cli-win32-x64-msvc@2.0.3': + resolution: {integrity: sha512-eWV9XWb4dSYHXl13OtYWLjX1JHphUEkHkkGwJrhr8qFBm7RbxXxQvrsUEprSi51ug/dwJenjJgM4zR8By4htfw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@2.8.4': - resolution: {integrity: sha512-ejUZBzuQRcjFV+v/gdj/DcbyX/6T4unZQjMSBZwLzP/CymEjKcc2+Fc8xTORThebHDUvqoXMdsCZt8r+hyN15g==} + '@tauri-apps/cli@2.0.3': + resolution: {integrity: sha512-JwEyhc5BAVpn4E8kxzY/h7+bVOiXQdudR1r3ODMfyyumZBfgIWqpD/WuTcPq6Yjchju1BSS+80jAE/oYwI/RKg==} engines: {node: '>= 10'} hasBin: true - '@tauri-apps/plugin-dialog@2.4.0': - resolution: {integrity: sha512-OvXkrEBfWwtd8tzVCEXIvRfNEX87qs2jv6SqmVPiHcJjBhSF/GUvjqUNIDmKByb5N8nvDqVUM7+g1sXwdC/S9w==} + '@tauri-apps/plugin-dialog@2.0.0': + resolution: {integrity: sha512-ApNkejXP2jpPBSifznPPcHTXxu9/YaRW+eJ+8+nYwqp0lLUtebFHG4QhxitM43wwReHE81WAV1DQ/b+2VBftOA==} - '@tauri-apps/plugin-fs@2.4.2': - resolution: {integrity: sha512-YGhmYuTgXGsi6AjoV+5mh2NvicgWBfVJHHheuck6oHD+HC9bVWPaHvCP0/Aw4pHDejwrvT8hE3+zZAaWf+hrig==} + '@tauri-apps/plugin-fs@2.4.1': + resolution: {integrity: sha512-vJlKZVGF3UAFGoIEVT6Oq5L4HGDCD78WmA4uhzitToqYiBKWAvZR61M6zAyQzHqLs0ADemkE4RSy/5sCmZm6ZQ==} - '@tauri-apps/plugin-http@2.5.2': - resolution: {integrity: sha512-x1mQKHSLDk4mS2S938OTeyk8L7QyLpCrKZCZcjkljGsvTvRMojCvI9SeJ1kaxc7t8xSilkC7WdId8xER9TIGLg==} + '@tauri-apps/plugin-http@2.5.0': + resolution: {integrity: sha512-l4M2DUIsOBIMrbj4dJZwrB4mJiB7OA/2Tj3gEbX2fjq5MOpETklJPKfDvzUTDwuq4lIKCKKykz8E8tpOgvi0EQ==} - '@tauri-apps/plugin-log@2.7.0': - resolution: {integrity: sha512-81XQ2f93x4vmIB5OY0XlYAxy60cHdYLs0Ki8Qp38tNATRiuBit+Orh3frpY3qfYQnqEvYVyRub7YRJWlmW2RRA==} + '@tauri-apps/plugin-log@2.7.1': + resolution: {integrity: sha512-jdb+o0wxQc8PjnLktgGpOs9Dh1YupaOGDXzO+Y8peA1UZ1ep3eXv4E1oiJ7nIQVN0XUFDDhnn3aBszl8ijhR+A==} - '@tauri-apps/plugin-opener@2.5.0': - resolution: {integrity: sha512-B0LShOYae4CZjN8leiNDbnfjSrTwoZakqKaWpfoH6nXiJwt6Rgj6RnVIffG3DoJiKsffRhMkjmBV9VeilSb4TA==} + '@tauri-apps/plugin-opener@2.4.0': + resolution: {integrity: sha512-43VyN8JJtvKWJY72WI/KNZszTpDpzHULFxQs0CJBIYUdCRowQ6Q1feWTDb979N7nldqSuDOaBupZ6wz2nvuWwQ==} - '@tauri-apps/plugin-os@2.3.1': - resolution: {integrity: sha512-ty5V8XDUIFbSnrk3zsFoP3kzN+vAufYzalJSlmrVhQTImIZa1aL1a03bOaP2vuBvfR+WDRC6NgV2xBl8G07d+w==} + '@tauri-apps/plugin-os@2.0.0': + resolution: {integrity: sha512-M7hG/nNyQYTJxVG/UhTKhp9mpXriwWzrs9mqDreB8mIgqA3ek5nHLdwRZJWhkKjZrnDT4v9CpA9BhYeplTlAiA==} - '@tauri-apps/plugin-shell@2.3.1': - resolution: {integrity: sha512-jjs2WGDO/9z2pjNlydY/F5yYhNsscv99K5lCmU5uKjsVvQ3dRlDhhtVYoa4OLDmktLtQvgvbQjCFibMl6tgGfw==} + '@tauri-apps/plugin-shell@2.3.0': + resolution: {integrity: sha512-6GIRxO2z64uxPX4CCTuhQzefvCC0ew7HjdBhMALiGw74vFBDY95VWueAHOHgNOMV4UOUAFupyidN9YulTe5xlA==} - '@tauri-apps/plugin-store@2.4.0': - resolution: {integrity: sha512-PjBnlnH6jyI71MGhrPaxUUCsOzc7WO1mbc4gRhME0m2oxLgCqbksw6JyeKQimuzv4ysdpNO3YbmaY2haf82a3A==} + '@tauri-apps/plugin-store@2.4.1': + resolution: {integrity: sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA==} - '@tweenjs/tween.js@23.1.3': - resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} + '@tweenjs/tween.js@23.1.2': + resolution: {integrity: sha512-kMCNaZCJugWI86xiEHaY338CU5JpD0B97p1j1IKNn/Zto8PgACjQx0UxbHjmOcLl/dDOBnItwD07KmCs75pxtQ==} '@tweenjs/tween.js@25.0.0': resolution: {integrity: sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==} @@ -1280,20 +1353,23 @@ packages: '@twemoji/svg@15.0.0': resolution: {integrity: sha512-ZSPef2B6nBaYnfgdTbAy4jgW95o7pi2xPGwGCU+WMTxo7J6B1lMPTWwSq/wTuiMq+N0khQ90CcvYp1wFoQpo/w==} - '@tybys/wasm-util@0.10.0': - resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} '@types/babel__template@7.4.4': resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/babel__traverse@7.20.6': + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + + '@types/debounce@1.2.4': + resolution: {integrity: sha512-jBqiORIzKDOToaF63Fm//haOCHuwQuLa2202RK4MozpA6lh93eCBc+/8+wZn5OzjJt3ySdc+74SXWXB55Ewtyw==} '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} @@ -1304,8 +1380,8 @@ packages: '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.6': + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} '@types/file-saver@2.0.7': resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==} @@ -1328,19 +1404,17 @@ packages: '@types/ms@0.7.34': resolution: {integrity: sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==} - '@types/node@24.3.1': - resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==} + '@types/node@24.10.0': + resolution: {integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==} '@types/offscreencanvas@2019.7.3': resolution: {integrity: sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==} - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@types/prop-types@15.7.12': + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 + '@types/react-dom@18.3.0': + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} '@types/react-helmet@6.1.11': resolution: {integrity: sha512-0QcdGLddTERotCXo3VFlUSWO3ztraw8nZ6e3zJSgG7apwV5xt+pJUS8ewPBqT4NYB1optGLprNQzFleIY84u/g==} @@ -1351,19 +1425,17 @@ packages: '@types/react-reconciler@0.26.7': resolution: {integrity: sha512-mBDYl8x+oyPX/VBb3E638N0B7xG+SPk/EAMcVPeexqus/5aTpTphQi0curhhshOqRrc9t6OPoJfEUkbymse/lQ==} - '@types/react-reconciler@0.28.9': - resolution: {integrity: sha512-HHM3nxyUZ3zAylX8ZEyrDNd2XZOnQ0D5XfunJF5FLQnZbHHYq4UWvW1QfelQNXv1ICNkwYhfxjwfnqivYB6bFg==} - peerDependencies: - '@types/react': '*' + '@types/react-reconciler@0.28.8': + resolution: {integrity: sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==} - '@types/react@18.3.24': - resolution: {integrity: sha512-0dLEBsA1kI3OezMBF8nSsb7Nk19ZnsyE1LLhB8r27KbgU5H4pvuqZLdtE+aUkJVoXgTVuA+iLIwmZ0TuK4tx6A==} + '@types/react@18.3.11': + resolution: {integrity: sha512-r6QZ069rFTjrEYgFdOck1gK7FLVsgJE7tTz0pQBczlBNUhBNk0MQH4UbnFSwjpQLMkLzgqvBBa+qGpLje16eTQ==} - '@types/semver@7.7.1': - resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + '@types/semver@7.5.8': + resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/stats.js@0.17.4': - resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} + '@types/stats.js@0.17.3': + resolution: {integrity: sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==} '@types/three@0.163.0': resolution: {integrity: sha512-uIdDhsXRpQiBUkflBS/i1l3JX14fW6Ot9csed60nfbZNXHDTRsnV2xnTVwXcgbvTiboAR4IW+t+lTL5f1rqIqA==} @@ -1374,8 +1446,11 @@ packages: '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - '@types/webxr@0.5.23': - resolution: {integrity: sha512-GPe4AsfOSpqWd3xA/0gwoKod13ChcfV67trvxaW2krUbgb9gxQjnCx8zGshzMl8LSHZlNH5gQ8LNScsDuc7nGQ==} + '@types/webxr@0.5.16': + resolution: {integrity: sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==} + + '@types/yoga-layout@1.9.2': + resolution: {integrity: sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==} '@typescript-eslint/eslint-plugin@7.18.0': resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} @@ -1388,11 +1463,11 @@ packages: typescript: optional: true - '@typescript-eslint/eslint-plugin@8.46.2': - resolution: {integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==} + '@typescript-eslint/eslint-plugin@8.46.4': + resolution: {integrity: sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.46.2 + '@typescript-eslint/parser': ^8.46.4 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' @@ -1406,15 +1481,15 @@ packages: typescript: optional: true - '@typescript-eslint/parser@8.46.2': - resolution: {integrity: sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==} + '@typescript-eslint/parser@8.46.4': + resolution: {integrity: sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - '@typescript-eslint/project-service@8.46.2': - resolution: {integrity: sha512-PULOLZ9iqwI7hXcmL4fVfIsBi6AN9YxRc0frbvmg8f+4hQAjQ5GYNKK0DIArNo+rOKmR/iBYwkpBmnIwin4wBg==} + '@typescript-eslint/project-service@8.46.4': + resolution: {integrity: sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1423,12 +1498,12 @@ packages: resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/scope-manager@8.46.2': - resolution: {integrity: sha512-LF4b/NmGvdWEHD2H4MsHD8ny6JpiVNDzrSZr3CsckEgCbAGZbYM4Cqxvi9L+WqDMT+51Ozy7lt2M+d0JLEuBqA==} + '@typescript-eslint/scope-manager@8.46.4': + resolution: {integrity: sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.46.2': - resolution: {integrity: sha512-a7QH6fw4S57+F5y2FIxxSDyi5M4UfGF+Jl1bCGd7+L4KsaUY80GsiF/t0UoRFDHAguKlBaACWJRmdrc6Xfkkag==} + '@typescript-eslint/tsconfig-utils@8.46.4': + resolution: {integrity: sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1443,8 +1518,8 @@ packages: typescript: optional: true - '@typescript-eslint/type-utils@8.46.2': - resolution: {integrity: sha512-HbPM4LbaAAt/DjxXaG9yiS9brOOz6fabal4uvUmaUYe6l3K1phQDMQKBRUrr06BQkxkvIZVVHttqiybM9nJsLA==} + '@typescript-eslint/type-utils@8.46.4': + resolution: {integrity: sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1454,8 +1529,8 @@ packages: resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/types@8.46.2': - resolution: {integrity: sha512-lNCWCbq7rpg7qDsQrd3D6NyWYu+gkTENkG5IKYhUIcxSb59SQC/hEQ+MrG4sTgBVghTonNWq42bA/d4yYumldQ==} + '@typescript-eslint/types@8.46.4': + resolution: {integrity: sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@typescript-eslint/typescript-estree@7.18.0': @@ -1467,8 +1542,8 @@ packages: typescript: optional: true - '@typescript-eslint/typescript-estree@8.46.2': - resolution: {integrity: sha512-f7rW7LJ2b7Uh2EiQ+7sza6RDZnajbNbemn54Ob6fRwQbgcIn+GWfyuHDHRYgRoZu1P4AayVScrRW+YfbTvPQoQ==} + '@typescript-eslint/typescript-estree@8.46.4': + resolution: {integrity: sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' @@ -1479,8 +1554,8 @@ packages: peerDependencies: eslint: ^8.56.0 - '@typescript-eslint/utils@8.46.2': - resolution: {integrity: sha512-sExxzucx0Tud5tE0XqR0lT0psBQvEpnpiul9XbGUB1QwpWJJAps1O/Z7hJxLGiZLBKMCutjTzDgmd1muEhBnVg==} + '@typescript-eslint/utils@8.46.4': + resolution: {integrity: sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -1490,12 +1565,12 @@ packages: resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} engines: {node: ^18.18.0 || >=20.0.0} - '@typescript-eslint/visitor-keys@8.46.2': - resolution: {integrity: sha512-tUFMXI4gxzzMXt4xpGJEsBsTox0XbNQ1y94EwlD/CuZwFcQP79xfQqMhau9HsRc/J0cAPA/HZt1dZPtGn9V/7w==} + '@typescript-eslint/visitor-keys@8.46.4': + resolution: {integrity: sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@ungap/structured-clone@1.2.0': + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} '@unrs/resolver-binding-android-arm-eabi@1.11.1': resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} @@ -1600,11 +1675,11 @@ packages: peerDependencies: react: '>= 16.8.0' - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + '@vitejs/plugin-react@4.3.2': + resolution: {integrity: sha512-hieu+o05v4glEBucTcKMK3dlES0OeJlD9YVOAPraVMOInBCwzumaIFiUjr4bHK7NPgnAHgiskUoceKercrN8vg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vite: ^4.2.0 || ^5.0.0 '@wry/caches@1.0.1': resolution: {integrity: sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==} @@ -1618,6 +1693,10 @@ packages: resolution: {integrity: sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==} engines: {node: '>=8'} + '@wry/trie@0.4.3': + resolution: {integrity: sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==} + engines: {node: '>=8'} + '@wry/trie@0.5.0': resolution: {integrity: sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==} engines: {node: '>=8'} @@ -1627,6 +1706,11 @@ packages: peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn@8.12.0: + resolution: {integrity: sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==} + engines: {node: '>=0.4.0'} + hasBin: true + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} @@ -1642,6 +1726,10 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + ansi-escapes@7.0.0: resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} engines: {node: '>=18'} @@ -1650,10 +1738,14 @@ packages: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.0: - resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1745,16 +1837,16 @@ packages: ast-types-flow@0.0.8: resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} - auto-bind@5.0.1: - resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + auto-bind@4.0.0: + resolution: {integrity: sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==} + engines: {node: '>=8'} - autoprefixer@10.4.21: - resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} + autoprefixer@10.4.20: + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: @@ -1797,8 +1889,8 @@ packages: brace-expansion@1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -1807,8 +1899,13 @@ packages: browser-fs-access@0.35.0: resolution: {integrity: sha512-sLoadumpRfsjprP8XzVjpQc0jK8yqHBx0PtUTGYj2fftT+P/t+uyDAQdMgGAPKD011in/O+YYGh7fIs0oG/viw==} - browserslist@4.25.4: - resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} + browserslist@4.23.1: + resolution: {integrity: sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + browserslist@4.24.0: + resolution: {integrity: sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -1860,13 +1957,16 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - camera-controls@2.10.1: - resolution: {integrity: sha512-KnaKdcvkBJ1Irbrzl8XD6WtZltkRjp869Jx8c0ujs9K+9WD+1D7ryBsCiVqJYUqt6i/HR5FxT7RLASieUD+Q5w==} + camera-controls@2.8.5: + resolution: {integrity: sha512-7VTwRk7Nu1nRKsY7bEt9HVBfKt8DETvzyYhLN4OW26OByBayMDB5fUaNcPI+z++vG23RH5yqn6ZRhZcgLQy2rA==} peerDependencies: three: '>=0.126.1' - caniuse-lite@1.0.30001741: - resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} + caniuse-lite@1.0.30001636: + resolution: {integrity: sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==} + + caniuse-lite@1.0.30001669: + resolution: {integrity: sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==} case@1.6.3: resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} @@ -1875,12 +1975,16 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.6.0: - resolution: {integrity: sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==} + chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} character-entities-html4@2.1.0: @@ -1903,16 +2007,19 @@ packages: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} - cli-cursor@4.0.0: - resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} cli-cursor@5.0.0: resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} @@ -1923,6 +2030,10 @@ packages: engines: {node: '>=8.0.0', npm: '>=5.0.0'} hasBin: true + cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + cli-truncate@4.0.0: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} @@ -1939,14 +2050,20 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - code-excerpt@4.0.0: - resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + code-excerpt@3.0.0: + resolution: {integrity: sha512-VHNTVhd7KsLGOqfX3SyeO8RyYPMp1GJOg194VITk04WMYCv4plV68YWe6TJZxd9MhobjtpMRnVky01gqZsalaw==} + engines: {node: '>=10'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1956,8 +2073,8 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - commander@13.1.0: - resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} commander@2.20.3: @@ -1976,9 +2093,9 @@ packages: convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - convert-to-spaces@2.0.1: - resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + convert-to-spaces@1.0.2: + resolution: {integrity: sha512-cj09EBuObp9gZNQCzc7hByQyrs6jVGE+o9kSJmeUoj+GiPiJvi5LYqEH/Hmme4+MTLHM+Ejtq+FChpjjEnsPdQ==} + engines: {node: '>= 4'} create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -1988,6 +2105,10 @@ packages: engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} hasBin: true + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -2030,6 +2151,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + debounce@1.2.1: + resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2038,8 +2162,17 @@ packages: supports-color: optional: true - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.3.5: + resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -2059,9 +2192,6 @@ packages: decode-named-character-reference@1.0.2: resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} - decode-named-character-reference@1.2.0: - resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} - decompress-response@6.0.0: resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} @@ -2101,8 +2231,8 @@ packages: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - detect-gpu@5.0.70: - resolution: {integrity: sha512-bqerEP1Ese6nt3rFkwPnGbsUF9a4q+gMmpTVVOEzoCyeCc+y7/RvJnQZJx1JwhgQI5Ntg0Kgat8Uu7XpBqnz1w==} + detect-gpu@5.0.38: + resolution: {integrity: sha512-36QeGHSXYcJ/RfrnPEScR8GDprbXFG4ZhXsfVNVHztZr38+fRxgHnJl3CjYXXjbeRUhu3ZZBJh6Lg0A9v0Qd8A==} detect-libc@1.0.3: resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} @@ -2130,8 +2260,8 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} engines: {node: '>=12'} draco3d@1.5.7: @@ -2151,11 +2281,14 @@ packages: resolution: {integrity: sha512-uW2UKSsuty9ANJ3YByIQE4ANkD8nqUPO7r6Fwcc1ADKPe9FRdcPpMl3VEput4JSvKBJ4J86npIC2MLP0pYkCuw==} hasBin: true - electron-to-chromium@1.5.214: - resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + electron-to-chromium@1.4.803: + resolution: {integrity: sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==} - emoji-regex@10.5.0: - resolution: {integrity: sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==} + electron-to-chromium@1.5.41: + resolution: {integrity: sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==} + + emoji-regex@10.3.0: + resolution: {integrity: sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2228,9 +2361,6 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - es-toolkit@1.39.10: - resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==} - es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} @@ -2247,6 +2377,10 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} @@ -2353,8 +2487,8 @@ packages: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.39.0: - resolution: {integrity: sha512-iy2GE3MHrYTL5lrCtMZ0X1KLEKKUjmK0kzwcnefhR66txcEmXZD2YWgR5GNdcEwkNx3a0siYkSvl0vIC+Svjmg==} + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -2367,8 +2501,8 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -2406,8 +2540,8 @@ packages: fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} fast-json-parse@1.0.3: @@ -2451,8 +2585,8 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - find-babel-config@2.1.2: - resolution: {integrity: sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==} + find-babel-config@2.1.1: + resolution: {integrity: sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA==} find-up@3.0.0: resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} @@ -2472,8 +2606,8 @@ packages: flatbuffers@22.10.26: resolution: {integrity: sha512-sdO3emf/BlLfOogW6KwHuXg16APR/E86jNacDXfSInPzt8SSEzxlHcqDekfM/IJ1CGC5bvDksfNufNhS8h1FRA==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} for-each@0.3.3: resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} @@ -2482,8 +2616,8 @@ packages: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + foreground-child@3.2.1: + resolution: {integrity: sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==} engines: {node: '>=14'} form-data-encoder@2.1.4: @@ -2527,10 +2661,13 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.3.1: - resolution: {integrity: sha512-R1QfovbPsKmosqTnPoRFiJ7CF9MLRgb53ChvMZm+r4p76/+8yKDy17qLL2PKInORy2RkZZekuK0efYgmzTkXyQ==} + get-east-asian-width@1.2.0: + resolution: {integrity: sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==} engines: {node: '>=18'} + get-intrinsic@1.2.1: + resolution: {integrity: sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} @@ -2563,8 +2700,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + get-tsconfig@4.13.0: + resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2574,20 +2711,25 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + glob@10.4.1: + resolution: {integrity: sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==} + engines: {node: '>=16 || 14 >=14.18'} hasBin: true glob@9.3.5: resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} engines: {node: '>=16 || 14 >=14.17'} + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@15.15.0: - resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} + globals@15.10.0: + resolution: {integrity: sha512-tqFIbz83w4Y5TCbtgjZjApohbuh7K9BxGYFm7ifwDR240tvdb7P9x+/9VvUKlmkPoiknoJtanI8UOrqxS3a7lQ==} engines: {node: '>=18'} globalthis@1.0.4: @@ -2611,7 +2753,6 @@ packages: got-fetch@5.1.10: resolution: {integrity: sha512-Gwj/A2htjvLEcY07PKDItv0WCPEs3dV2vWeZ+9TVBSKSTuWEZ4oXaMD0ZAOsajwx2orahQWN4HI0MfRyWSZsbg==} engines: {node: '>=14.0.0'} - deprecated: please use built-in fetch in nodejs peerDependencies: got: ^12.0.0 @@ -2631,16 +2772,16 @@ packages: peerDependencies: graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 - graphql@15.10.1: - resolution: {integrity: sha512-BL/Xd/T9baO6NFzoMpiMD7YUZ62R6viR5tp/MULVEnbYJXZA//kRNW7J0j1w/wXArgL0sCxhDfK5dczSKn3+cg==} + graphql@15.9.0: + resolution: {integrity: sha512-GCOQdvm7XxV1S4U4CGrsdlEN37245eC8P9zaYCMr6K1BG0IPGy5lUwmJsEOGyl1GD6HXjOtl2keCP9asRBwNvA==} engines: {node: '>= 10.x'} has-bigints@1.0.2: resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -2673,12 +2814,16 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - hast-util-to-jsx-runtime@2.3.6: - resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + hast-util-to-jsx-runtime@2.3.2: + resolution: {integrity: sha512-1ngXYb+V9UT5h+PxNRa1O1FYguZK/XL+gkeqvp7EdHlB9oHUG0eYRo/vY5inBdcqo3RkPMC58/H94HvkbfGdyg==} hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} @@ -2686,8 +2831,8 @@ packages: highlight.js@10.7.3: resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - hls.js@1.6.11: - resolution: {integrity: sha512-tdDwOAgPGXohSiNE4oxGr3CI9Hx9lsGLFe6TULUvRk2TfHS+w1tSAJntrvxsHaxvjtr6BXsDZM7NOqJFhU4mmg==} + hls.js@1.5.17: + resolution: {integrity: sha512-wA66nnYFvQa1o4DO/BFgLNRKnBTVXpNeldGRBJ2Y0SvFtdwvFKCbqa9zhHoZLoxHhZ+jYsj3aIBkWQQCPNOhMw==} hoist-non-react-statics@3.3.2: resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} @@ -2695,8 +2840,8 @@ packages: html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} http2-client@1.3.5: resolution: {integrity: sha512-EC2utToWl4RKfs5zd36Mxq7nzHHBuomZboI0yYL6Y0RmBgT7Sgkq4rQ0ezFTYoIsSs7Tm9SJe+o2FcAg6GBhGA==} @@ -2717,8 +2862,8 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - husky@9.1.7: - resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + husky@9.1.6: + resolution: {integrity: sha512-sqbjZKK7kf44hfdE94EoX8MZNk0n7HeW37O4YrVGCF4wzgQjp+akPAkfUK5LZ6KuR/6sqeAVuXHji+RzQgOn5A==} engines: {node: '>=18'} hasBin: true @@ -2728,8 +2873,8 @@ packages: ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + ignore@5.3.1: + resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} engines: {node: '>= 4'} ignore@7.0.5: @@ -2742,33 +2887,30 @@ packages: immer@10.1.1: resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==} - immutable@5.1.3: - resolution: {integrity: sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==} + immutable@4.3.6: + resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} engines: {node: '>=6'} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} - ink@5.2.1: - resolution: {integrity: sha512-BqcUyWrG9zq5HIwW6JcfFHsIYebJkWWb4fczNah1goUO0vv5vneIlfwuS85twyJ5hYR/y18FlAYUxrO9ChIWVg==} - engines: {node: '>=18'} + ink@3.2.0: + resolution: {integrity: sha512-firNp1q3xxTzoItj/eOOSZQnYSlyrWks5llCTVX37nJ59K3eXbQ8PtzCguqo8YI19EELo5QxaKnJd4VxzhU8tg==} + engines: {node: '>=10'} peerDependencies: - '@types/react': '>=18.0.0' - react: '>=18.0.0' - react-devtools-core: ^4.19.1 + '@types/react': '>=16.8.0' + react: '>=16.8.0' peerDependenciesMeta: '@types/react': optional: true - react-devtools-core: - optional: true inline-style-parser@0.2.4: resolution: {integrity: sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==} @@ -2784,8 +2926,8 @@ packages: intl-pluralrules@2.0.1: resolution: {integrity: sha512-astxTLzIdXPeN0K9Rumi6LfMpm3rvNO0iJE+h/k8Kr/is+wPbRe4ikyDjlLr6VTh/mEfNv8RjN+gu3KwDiuhqg==} - ip-num@1.5.2: - resolution: {integrity: sha512-CUxHEJuJk74GIQA75LD9RDkpK/3NJv8yRnseOh79AlRmFwT1HgYPKDOiVkd0QVR5MNwMj9EnOnS1yJn9CaYNZA==} + ip-num@1.5.1: + resolution: {integrity: sha512-QziFxgxq3mjIf5CuwlzXFYscHxgLqdEdJKRo2UJ5GurL5zrSRMzT/O+nK0ABimoFH8MWF8YwIiwECYsHc1LpUQ==} is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -2805,8 +2947,8 @@ packages: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} engines: {node: '>= 0.4'} is-bigint@1.0.4: @@ -2835,6 +2977,17 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} + is-ci@2.0.0: + resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} + hasBin: true + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -2867,6 +3020,9 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.1: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} @@ -2879,12 +3035,12 @@ packages: resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} engines: {node: '>=12'} - is-fullwidth-code-point@5.1.0: - resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} engines: {node: '>=18'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} engines: {node: '>= 0.4'} is-glob@4.0.3: @@ -2894,11 +3050,6 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - is-in-ci@1.0.0: - resolution: {integrity: sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==} - engines: {node: '>=18'} - hasBin: true - is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} @@ -3012,26 +3163,21 @@ packages: peerDependencies: react: '>=18.0' - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jackspeak@3.4.0: + resolution: {integrity: sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==} + engines: {node: '>=14'} jiti@1.21.6: resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} hasBin: true - jotai@2.13.1: - resolution: {integrity: sha512-cRsw6kFeGC9Z/D3egVKrTXRweycZ4z/k7i2MrfCzPYsL9SIWcPXTyqv258/+Ay8VUEcihNiE/coBLE6Kic6b8A==} + jotai@2.12.2: + resolution: {integrity: sha512-oN8715y7MkjXlSrpyjlR887TOuc/NLZMs9gvgtfWH/JP47ChwO0lR2ijSwBvPMYyXRAPT+liIAhuBavluKGgtA==} engines: {node: '>=12.20.0'} peerDependencies: - '@babel/core': '>=7.0.0' - '@babel/template': '>=7.0.0' '@types/react': '>=17.0.0' react: '>=17.0.0' peerDependenciesMeta: - '@babel/core': - optional: true - '@babel/template': - optional: true '@types/react': optional: true react: @@ -3044,8 +3190,13 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + jsesc@3.0.2: + resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} hasBin: true @@ -3070,8 +3221,8 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} @@ -3098,20 +3249,24 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} engines: {node: '>=14'} lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@15.5.2: - resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} + lint-staged@15.2.10: + resolution: {integrity: sha512-5dY5t743e1byO19P9I4b3x8HJwalIznL5E1FWYnU6OWw33KxNBSLAc6Cy7F2PsFEO8FKnLwjwm5hx7aMF0jzZg==} engines: {node: '>=18.12.0'} hasBin: true - listr2@8.3.3: - resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} + listr2@8.2.5: + resolution: {integrity: sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==} engines: {node: '>=18.0.0'} locate-path@3.0.0: @@ -3149,17 +3304,18 @@ packages: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@10.2.2: + resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==} + engines: {node: 14 || >=16.14} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - maath@0.10.8: - resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==} + maath@0.10.7: + resolution: {integrity: sha512-zQ2xd7dNOIVTjAS+hj22fyj1EFYmOJX6tzKjZ92r6WDoq8hyFxjuGA2q950tmR4iC/EKXoMQdSipkaJVuUHDTg==} peerDependencies: - '@types/three': '>=0.134.0' - three: '>=0.134.0' + '@types/three': '>=0.144.0' + three: '>=0.144.0' magic-string@0.30.8: resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} @@ -3205,8 +3361,8 @@ packages: mdast-util-mdx-expression@2.0.1: resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} - mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + mdast-util-mdx-jsx@3.1.3: + resolution: {integrity: sha512-bfOjvNt+1AcbPLTFMFWY149nJz0OjmewJs3LQQ5pIyVGxP4CdOqNVJL6kTaM5c68p8q82Xv3nCyFfUnuEcH3UQ==} mdast-util-mdxjs-esm@2.0.1: resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} @@ -3280,9 +3436,6 @@ packages: micromark-util-character@2.1.0: resolution: {integrity: sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==} - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - micromark-util-chunked@2.0.0: resolution: {integrity: sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==} @@ -3301,9 +3454,6 @@ packages: micromark-util-encode@2.0.0: resolution: {integrity: sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==} - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - micromark-util-html-tag-name@2.0.0: resolution: {integrity: sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==} @@ -3316,24 +3466,15 @@ packages: micromark-util-sanitize-uri@2.0.0: resolution: {integrity: sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==} - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - micromark-util-subtokenize@2.0.1: resolution: {integrity: sha512-jZNtiFl/1aY73yS3UGQkutD0UbhTt68qnRpw2Pifmz5wV9h8gOVsN70v+Lq/f1rKaU/W8pxRe8y8Q9FX1AOe1Q==} micromark-util-symbol@2.0.0: resolution: {integrity: sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==} - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - micromark-util-types@2.0.0: resolution: {integrity: sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==} - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - micromark@4.0.0: resolution: {integrity: sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==} @@ -3376,8 +3517,8 @@ packages: resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.4: + resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -3391,19 +3532,22 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - napi-postinstall@0.3.3: - resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true @@ -3429,8 +3573,11 @@ packages: node-readfiles@0.2.0: resolution: {integrity: sha512-SU00ZarexNlE4Rjdm83vglt5Y9yiQ+XI1XpflWlb7q7UTN1JUItm69xMeiQCTxtTfnzt+83T8Cx+vI2ED++VDA==} - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -3440,8 +3587,8 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} - normalize-url@8.0.2: - resolution: {integrity: sha512-Ee/R3SyN4BuynXcnTaekmaVdbDAEiNrHqjQIA37mHU8G9pf7aaAD4ZX3XjBLo6rsdcxA/gtkcNYZLt30ACgynw==} + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} engines: {node: '>=14.16'} npm-run-path@4.0.1: @@ -3548,8 +3695,8 @@ packages: openapi3-ts@2.0.2: resolution: {integrity: sha512-TxhYBMoqx9frXyOgnRHufjQfPXomTIHYKhSKJ6jHfj13kS8OEIhvmE8CTuQyKtjjWttAjX5DPxM1vmalEpo8Qw==} - optimism@0.18.1: - resolution: {integrity: sha512-mLXNwWPa9dgFyDqkNi54sjDyNJ9/fTI6WGBLgnXku1vdKY/jovHfZT5r+aiVeFFLOz+foPNOm5YJ4mqgld2GBQ==} + optimism@0.18.0: + resolution: {integrity: sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -3583,15 +3730,12 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-entities@4.0.1: + resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} parse5-htmlparser2-tree-adapter@6.0.1: resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} @@ -3602,9 +3746,9 @@ packages: parse5@6.0.1: resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - patch-console@2.0.0: - resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + patch-console@1.0.0: + resolution: {integrity: sha512-nxl9nrnLQmh64iTzMfyylSlRozL7kAXIaxw1fVcLYdyhNkJCRUzirRZTikXGJsg+hc4fqpneTK6iU2H1Q8THSA==} + engines: {node: '>=10'} path-exists@3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} @@ -3638,6 +3782,9 @@ packages: engines: {node: '>=0.10'} hasBin: true + picocolors@1.0.1: + resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} @@ -3658,8 +3805,8 @@ packages: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} pkg-up@3.1.0: @@ -3674,10 +3821,6 @@ packages: resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} engines: {node: '>= 0.4'} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -3702,8 +3845,8 @@ packages: ts-node: optional: true - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + postcss-nested@6.0.1: + resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 @@ -3712,15 +3855,19 @@ packages: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + postcss-selector-parser@6.1.0: + resolution: {integrity: sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==} engines: {node: '>=4'} postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.4.38: + resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.4.47: + resolution: {integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==} engines: {node: ^10 || ^12 || >=14} potpack@1.0.2: @@ -3730,8 +3877,8 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + prettier@3.3.3: + resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==} engines: {node: '>=14'} hasBin: true @@ -3752,8 +3899,8 @@ packages: property-expr@2.0.6: resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -3777,13 +3924,16 @@ packages: peerDependencies: react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 + react-devtools-core@4.28.5: + resolution: {integrity: sha512-cq/o30z9W2Wb4rzBefjv5fBalHU0rJGZCHAkf/RHSBWSSYwh8PlQTqqOJmgIIbBtpj27T6FIPXeomIjZtCNVqA==} + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: react: ^18.3.1 - react-error-boundary@4.1.2: - resolution: {integrity: sha512-GQDxZ5Jd+Aq/qUxbCm1UtzmL/s++V7zKgE8yMktJiCQXCCFZnMZh9ng+6/Ne6PjNSXH0L9CjeOEREfRnq6Duag==} + react-error-boundary@4.0.13: + resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} peerDependencies: react: '>=16.13.1' @@ -3795,8 +3945,8 @@ packages: peerDependencies: react: '>=16.3.0' - react-hook-form@7.65.0: - resolution: {integrity: sha512-xtOzDz063WcXvGWaHgLNrNzlsdFgtUWcb32E6WFaGTd7kPZG3EeDusjdZfUsPwKCKVXy1ZlntifaHZ4l8pAsmw==} + react-hook-form@7.66.0: + resolution: {integrity: sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 @@ -3807,17 +3957,24 @@ packages: react-lifecycles-compat@3.0.4: resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==} - react-markdown@9.1.0: - resolution: {integrity: sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==} + react-markdown@9.0.1: + resolution: {integrity: sha512-186Gw/vF1uRkydbsOIkcGXw7aHq0sZOCRFFjGrr7b9+nVZg4UfA4enXCaxm4fUzecU38sWfrNDitGhshuU7rdg==} peerDependencies: '@types/react': '>=18' react: '>=18' - react-modal@3.16.3: - resolution: {integrity: sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw==} + react-modal@3.16.1: + resolution: {integrity: sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==} + engines: {node: '>=8'} peerDependencies: - react: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19 - react-dom: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 || ^19 + react: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 + react-dom: ^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18 + + react-reconciler@0.26.2: + resolution: {integrity: sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^17.0.2 react-reconciler@0.27.0: resolution: {integrity: sha512-HmMDKciQjYmBRGuuhIaKA1ba/7a+UsM5FzOZsMO2JYHt9Jh8reCb7j1eDC95NOyUlKM9KRyvdx0flBuDvYSBoA==} @@ -3825,31 +3982,25 @@ packages: peerDependencies: react: ^18.0.0 - react-reconciler@0.29.2: - resolution: {integrity: sha512-zZQqIiYgDCTP/f1N/mAR10nJGrPD2ZR+jDSEsKWJHYC7Cm2wodlwbR3upZRdC3cjIjSlTLNVyO7Iu0Yy7t2AYg==} - engines: {node: '>=0.10.0'} - peerDependencies: - react: ^18.3.1 - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} - react-responsive@10.0.1: - resolution: {integrity: sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g==} + react-responsive@10.0.0: + resolution: {integrity: sha512-N6/UiRLGQyGUqrarhBZmrSmHi2FXSD++N5VbSKsBBvWfG0ZV7asvUBluSv5lSzdMyEVjzZ6Y8DL4OHABiztDOg==} engines: {node: '>=14'} peerDependencies: react: '>=16.8.0' - react-router-dom@6.30.1: - resolution: {integrity: sha512-llKsgOkZdbPU1Eg3zK8lCn+sjD9wMRZZPuzmdWWX5SUs8OFkN5HnFVC0u5KMeMaC9aoancFI/KoLuKPqN+hxHw==} + react-router-dom@6.27.0: + resolution: {integrity: sha512-+bvtFWMC0DgAFrfKXKG9Fc+BcXWRUO1aJIihbB79xaeq0v5UzfvnM5houGUm1Y461WVRcgAQ+Clh5rdb1eCx4g==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' react-dom: '>=16.8' - react-router@6.30.1: - resolution: {integrity: sha512-X1m21aEmxGXqENEPG3T6u0Th7g0aS4ZmoNynhbs+Cn+q+QGTLt+d5IQ2bHAXKzKcxGJjxACpVbnYQSCRcfxHlQ==} + react-router@6.27.0: + resolution: {integrity: sha512-YA+HGZXz4jaAkVoYBE98VQl+nVzI+cVI2Oj/06F5ZM+0u3TgedN9Y9kmMRo2mnkSK2nCpNQn0DVob4HCsY/WLw==} engines: {node: '>=14.0.0'} peerDependencies: react: '>=16.8' @@ -3859,15 +4010,6 @@ packages: peerDependencies: react: ^16.3.0 || ^17.0.0 || ^18.0.0 - react-use-measure@2.1.7: - resolution: {integrity: sha512-KrvcAo13I/60HpwGO5jpW7E9DfusKyLPLvuHlUyP5zqnmAPhNc6qTRjUQrdTADl0lpPpDVU2/Gg51UlOGHXbdg==} - peerDependencies: - react: '>=16.13' - react-dom: '>=16.13' - peerDependenciesMeta: - react-dom: - optional: true - react@18.3.1: resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} engines: {node: '>=0.10.0'} @@ -3887,9 +4029,16 @@ packages: resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} + reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} + reftools@1.1.9: resolution: {integrity: sha512-OVede/NQE13xBQ+ob5CKd5KyeJYU2YInb1bmV4nRoOfquZPkAkxuOXicSe1PvqIuZZ4kD13sPKBbR7UFDmli6w==} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regexp.prototype.flags@1.5.2: resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} engines: {node: '>= 0.4'} @@ -3909,14 +4058,14 @@ packages: react: optional: true - remark-gfm@4.0.1: - resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-gfm@4.0.0: + resolution: {integrity: sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==} remark-parse@11.0.0: resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} - remark-rehype@11.1.2: - resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-rehype@11.1.1: + resolution: {integrity: sha512-g/osARvjkBXb6Wo0XvAeXQohVta8i84ACbenPpoSsxTOQH/Ae0/RGP4WZgnMH5pMLpsj4FG7OHmcIcXxpza8eQ==} remark-stringify@11.0.0: resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} @@ -3942,11 +4091,6 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} - hasBin: true - resolve@1.22.8: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true @@ -3955,48 +4099,49 @@ packages: resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true + response-iterator@0.2.6: + resolution: {integrity: sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==} + engines: {node: '>=0.8'} + responselike@3.0.0: resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} engines: {node: '>=14.16'} - restore-cursor@4.0.0: - resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} restore-cursor@5.1.0: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - rollup-plugin-visualizer@5.14.0: - resolution: {integrity: sha512-VlDXneTDaKsHIw8yzJAFWtrzguoJ/LnQ+lMpoVfYJ3jJF4Ihe5oYLAqLklIK/35lgUY+1yEzCkHyZ1j4A5w5fA==} - engines: {node: '>=18'} + rollup-plugin-visualizer@5.12.0: + resolution: {integrity: sha512-8/NU9jXcHRs7Nnj07PF2o4gjxmm9lXIrZ8r175bT9dK8qoLlvKTwRMArRCMgpMGlq8CTLugRvEmyMeMXIU2pNQ==} + engines: {node: '>=14'} hasBin: true peerDependencies: - rolldown: 1.x rollup: 2.x || 3.x || 4.x peerDependenciesMeta: - rolldown: - optional: true rollup: optional: true - rollup@4.50.0: - resolution: {integrity: sha512-/Zl4D8zPifNmyGzJS+3kVoyXeDeT/GrsJM94sACNg9RtUE0hrHa1bNPtRSrfHTMH5HjRzce6K7rlTh3Khiw+pw==} + rollup@4.24.0: + resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} safe-array-concat@1.1.2: resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} @@ -4018,11 +4163,14 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - sass@1.92.0: - resolution: {integrity: sha512-KDNI0BxgIRDAfJgzNm5wuy+4yOCIZyrUbjSpiU/JItfih+KGXAVefKL53MTml054MmBA3DDKIBMSI/7XLxZJ3A==} + sass@1.80.2: + resolution: {integrity: sha512-9wXY8cGBlUmoUoT+vwOZOFCiS+naiWVjqlreN9ar9PudXbGwlMTFwCR5K9kB4dFumJ6ib98wZyAObJKsWf1nAA==} engines: {node: '>=14.0.0'} hasBin: true + scheduler@0.20.2: + resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} + scheduler@0.21.0: resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} @@ -4033,8 +4181,13 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} engines: {node: '>=10'} hasBin: true @@ -4061,6 +4214,9 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + should-equal@2.0.0: resolution: {integrity: sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==} @@ -4117,6 +4273,10 @@ packages: resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} engines: {node: '>=12'} + slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + slice-ansi@5.0.0: resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} engines: {node: '>=12'} @@ -4140,9 +4300,9 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} + source-map@0.7.4: + resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} + engines: {node: '>= 8'} space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -4156,8 +4316,8 @@ packages: spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + spdx-license-ids@3.0.18: + resolution: {integrity: sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==} spdx-ranges@2.1.1: resolution: {integrity: sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==} @@ -4172,11 +4332,8 @@ packages: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} - stats-gl@2.4.2: - resolution: {integrity: sha512-g5O9B0hm9CvnM36+v7SFl39T7hmAlv541tU81ME8YeSb3i1CIP5/QdDeSB3A0la0bKNHpxpwxOVRo2wFTYEosQ==} - peerDependencies: - '@types/three': '*' - three: '*' + stats-gl@2.2.8: + resolution: {integrity: sha512-94G5nZvduDmzxBS7K0lYnynYwreZpkknD8g5dZmU6mpwIhy3caCrjAm11Qm1cbyx7mqix7Fp00RkbsonzKWnoQ==} stats.js@0.17.0: resolution: {integrity: sha512-hNKz8phvYLPEcRkeG1rsGmV5ChMjKDAWU7/OJJdDErPBNChQXxCo3WZurGpnWc6gZhAzEPFad1aVgyOANH1sMw==} @@ -4201,8 +4358,8 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + string-width@7.1.0: + resolution: {integrity: sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==} engines: {node: '>=18'} string.prototype.includes@2.0.1: @@ -4259,17 +4416,18 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - style-to-js@1.1.17: - resolution: {integrity: sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==} - - style-to-object@1.0.9: - resolution: {integrity: sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==} + style-to-object@1.0.8: + resolution: {integrity: sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==} sucrase@3.35.0: resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} engines: {node: '>=16 || 14 >=14.17'} hasBin: true + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -4294,8 +4452,8 @@ packages: tailwind-gradient-mask-image@1.2.0: resolution: {integrity: sha512-tUJaGhvqbJFiVKJu6EU5n//KvGdVvY3L3VOFNqjztk13+ifAk00pcSNHBTgHfUiBGOEzDn0gFRbSmsftUV1lXA==} - tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} + tailwindcss@3.4.14: + resolution: {integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==} engines: {node: '>=14.0.0'} hasBin: true @@ -4317,8 +4475,8 @@ packages: peerDependencies: three: '>= 0.151.0' - three-stdlib@2.36.0: - resolution: {integrity: sha512-kv0Byb++AXztEGsULgMAs8U2jgUdz6HPpAB/wDJnLiLlaWQX2APHhiTJIN7rqW+Of0eRgcp7jn05U1BsCP3xBA==} + three-stdlib@2.30.3: + resolution: {integrity: sha512-rYr8PqMljMza+Ct8kQk90Y7y+YcWoPu1thfYv5YGCp0hytNRbxSQWXY4GpdTGymCj3bDggEBpxso53C3pPwhIw==} peerDependencies: three: '>=0.128.0' @@ -4331,10 +4489,14 @@ packages: tinycolor2@1.6.0: resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -4348,24 +4510,24 @@ packages: trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - troika-three-text@0.52.4: - resolution: {integrity: sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==} + troika-three-text@0.49.1: + resolution: {integrity: sha512-lXGWxgjJP9kw4i4Wh+0k0Q/7cRfS6iOME4knKht/KozPu9GcFA9NnNpRvehIhrUawq9B0ZRw+0oiFHgRO+4Wig==} peerDependencies: three: '>=0.125.0' - troika-three-utils@0.52.4: - resolution: {integrity: sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==} + troika-three-utils@0.49.0: + resolution: {integrity: sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==} peerDependencies: three: '>=0.125.0' - troika-worker-utils@0.52.0: - resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==} + troika-worker-utils@0.49.0: + resolution: {integrity: sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==} trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - ts-api-utils@1.4.3: - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + ts-api-utils@1.3.0: + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} engines: {node: '>=16'} peerDependencies: typescript: '>=4.2.0' @@ -4390,8 +4552,8 @@ packages: peerDependencies: typescript: '>=2.7' - ts-pattern@5.8.0: - resolution: {integrity: sha512-kIjN2qmWiHnhgr5DAkAafF9fwb0T5OhMVSWrm8XEdTFnX6+wfXwYOFjeF86UZ54vduqiR7BfqScFmXSzSaH8oA==} + ts-pattern@5.5.0: + resolution: {integrity: sha512-jqbIpTsa/KKTJYWgPNsFNbLVpwCgzXfFJ1ukNn4I8hMwyQzHMJnk/BqWzggB0xpkILuKzaO/aMYhS0SkaJyKXg==} tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} @@ -4399,8 +4561,8 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tslib@2.6.3: + resolution: {integrity: sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==} tsutils@3.21.0: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -4418,14 +4580,18 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.12.0: + resolution: {integrity: sha512-53RyidyjvkGpnWPMF9bQgFtWp+Sl8O2Rp13VavmJgfAP9WWG6q6TkrKU8iyJdnwnfgHI6k2hTlgqH4aSdjoTbg==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + type-fest@2.19.0: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - typed-array-buffer@1.0.2: resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} engines: {node: '>= 0.4'} @@ -4458,8 +4624,8 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - typescript-eslint@8.46.2: - resolution: {integrity: sha512-vbw8bOmiuYNdzzV3lsiWv6sRwjyuKJMQqWulBOU7M0RrxedXledX8G8kBbQeiOYDnTfiXz0Y4081E1QMNB6iQg==} + typescript-eslint@8.46.4: + resolution: {integrity: sha512-KALyxkpYV5Ix7UhvjTwJXZv76VWsHG+NjNlt/z+a17SOQSiOcBdUXdbJdyXi7RPxrBFECtFOiPwUJQusJuCqrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 @@ -4475,8 +4641,8 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + typescript@5.6.3: + resolution: {integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==} engines: {node: '>=14.17'} hasBin: true @@ -4487,8 +4653,8 @@ packages: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} @@ -4518,8 +4684,14 @@ packages: unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + update-browserslist-db@1.0.16: + resolution: {integrity: sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-browserslist-db@1.1.1: + resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -4527,15 +4699,15 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - use-double-tap@1.3.7: - resolution: {integrity: sha512-OOgpAtT1U96D8jX6w/ODWhLMDpS92wVYIQyQQ0hDnOgLrPHNrkYSjTnkoPT41GaO30xF5OBJ7mAxF34sHxnLng==} + use-double-tap@1.3.6: + resolution: {integrity: sha512-zWmzlihSTuLJpT+YJqhVUySV8UNvmdmaXokBEIh+FxR4m/vaSk2cS5hlqEPDj64rmkHlL7zfRTrJPw30Jd0OZA==} peerDependencies: react: '>=16.8.0' - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} + use-sync-external-store@1.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -4544,14 +4716,18 @@ packages: resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} engines: {node: '>= 4'} - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + vfile-message@4.0.2: + resolution: {integrity: sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==} vfile@6.0.3: resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - vite@5.4.19: - resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} + vite@5.4.9: + resolution: {integrity: sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -4593,8 +4769,8 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webpack-sources@3.3.3: - resolution: {integrity: sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==} + webpack-sources@3.2.3: + resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} engines: {node: '>=10.13.0'} webpack-virtual-modules@0.5.0: @@ -4610,6 +4786,10 @@ packages: resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} + which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + which-builtin-type@1.2.1: resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} @@ -4631,14 +4811,18 @@ packages: engines: {node: '>= 8'} hasBin: true - widest-line@5.0.0: - resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} - engines: {node: '>=18'} + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} @@ -4654,12 +4838,12 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + utf-8-validate: ^5.0.2 peerDependenciesMeta: bufferutil: optional: true @@ -4677,9 +4861,14 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} - engines: {node: '>= 14.6'} + yaml@2.4.5: + resolution: {integrity: sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==} + engines: {node: '>= 14'} + hasBin: true + + yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} + engines: {node: '>= 14'} hasBin: true yargs-parser@20.2.9: @@ -4706,11 +4895,12 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoga-layout@3.2.1: - resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + yoga-layout-prebuilt@1.10.0: + resolution: {integrity: sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==} + engines: {node: '>=8'} - yup@1.7.0: - resolution: {integrity: sha512-VJce62dBd+JQvoc+fCVq+KZfPHr+hXaxCcVgotfwWvlR0Ja3ffYKaJBT8rptPOSKOGJDCUnW2C2JWpud7aRP6Q==} + yup@1.4.0: + resolution: {integrity: sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==} zen-observable-ts@1.2.5: resolution: {integrity: sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==} @@ -4727,8 +4917,8 @@ packages: react: optional: true - zustand@4.5.7: - resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + zustand@4.5.2: + resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==} engines: {node: '>=12.7.0'} peerDependencies: '@types/react': '>=16.8' @@ -4742,51 +4932,34 @@ packages: react: optional: true - zustand@5.0.8: - resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} snapshots: - '@alcalzone/ansi-tokenize@0.1.3': - dependencies: - ansi-styles: 6.2.1 - is-fullwidth-code-point: 4.0.0 - '@alloc/quick-lru@5.2.0': {} - '@apollo/client@3.14.0(@types/react@18.3.24)(graphql@15.10.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@ampproject/remapping@2.3.0': dependencies: - '@graphql-typed-document-node/core': 3.2.0(graphql@15.10.1) + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + '@apollo/client@3.10.6(@types/react@18.3.11)(graphql@15.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@graphql-typed-document-node/core': 3.2.0(graphql@15.9.0) '@wry/caches': 1.0.1 '@wry/equality': 0.5.7 '@wry/trie': 0.5.0 - graphql: 15.10.1 - graphql-tag: 2.12.6(graphql@15.10.1) + graphql: 15.9.0 + graphql-tag: 2.12.6(graphql@15.9.0) hoist-non-react-statics: 3.3.2 - optimism: 0.18.1 + optimism: 0.18.0 prop-types: 15.8.1 - rehackt: 0.1.0(@types/react@18.3.24)(react@18.3.1) + rehackt: 0.1.0(@types/react@18.3.11)(react@18.3.1) + response-iterator: 0.2.6 symbol-observable: 4.0.0 ts-invariant: 0.10.3 - tslib: 2.8.1 + tslib: 2.6.3 zen-observable-ts: 1.2.5 optionalDependencies: react: 18.3.1 @@ -4794,133 +4967,280 @@ snapshots: transitivePeerDependencies: - '@types/react' - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.24.7': dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 + '@babel/highlight': 7.24.7 + picocolors: 1.0.1 - '@babel/compat-data@7.28.4': {} - - '@babel/core@7.28.4': + '@babel/code-frame@7.25.7': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/remapping': 2.3.5 + '@babel/highlight': 7.25.7 + picocolors: 1.0.1 + + '@babel/compat-data@7.24.7': {} + + '@babel/compat-data@7.25.8': {} + + '@babel/core@7.24.7': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-compilation-targets': 7.24.7 + '@babel/helper-module-transforms': 7.24.7(@babel/core@7.24.7) + '@babel/helpers': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.3.5 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.28.3': + '@babel/core@7.25.8': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - jsesc: 3.1.0 + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/helper-compilation-targets': 7.25.7 + '@babel/helper-module-transforms': 7.25.7(@babel/core@7.25.8) + '@babel/helpers': 7.25.7 + '@babel/parser': 7.25.8 + '@babel/template': 7.25.7 + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.8 + convert-source-map: 2.0.0 + debug: 4.3.5 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@babel/helper-compilation-targets@7.27.2': + '@babel/generator@7.24.7': dependencies: - '@babel/compat-data': 7.28.4 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.4 + '@babel/types': 7.24.7 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + '@babel/generator@7.25.7': + dependencies: + '@babel/types': 7.25.8 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.0.2 + + '@babel/helper-compilation-targets@7.24.7': + dependencies: + '@babel/compat-data': 7.24.7 + '@babel/helper-validator-option': 7.24.7 + browserslist: 4.23.1 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': + '@babel/helper-compilation-targets@7.25.7': dependencies: - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/compat-data': 7.25.8 + '@babel/helper-validator-option': 7.25.7 + browserslist: 4.24.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-environment-visitor@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-function-name@7.24.7': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/helper-hoist-variables@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-module-imports@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.4)': + '@babel/helper-module-imports@7.25.7': dependencies: - '@babel/core': 7.28.4 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.8 transitivePeerDependencies: - supports-color - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.4': + '@babel/helper-module-transforms@7.24.7(@babel/core@7.24.7)': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - - '@babel/parser@7.28.4': - dependencies: - '@babel/types': 7.28.4 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.4)': - dependencies: - '@babel/core': 7.28.4 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/runtime@7.28.4': {} - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - - '@babel/traverse@7.28.4': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.4 - '@babel/template': 7.27.2 - '@babel/types': 7.28.4 - debug: 4.4.3 + '@babel/core': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 transitivePeerDependencies: - supports-color - '@babel/types@7.28.4': + '@babel/helper-module-transforms@7.25.7(@babel/core@7.25.8)': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 + '@babel/core': 7.25.8 + '@babel/helper-module-imports': 7.25.7 + '@babel/helper-simple-access': 7.25.7 + '@babel/helper-validator-identifier': 7.25.7 + '@babel/traverse': 7.25.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.24.7': {} + + '@babel/helper-simple-access@7.24.7': + dependencies: + '@babel/traverse': 7.24.7 + '@babel/types': 7.24.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-simple-access@7.25.7': + dependencies: + '@babel/traverse': 7.25.7 + '@babel/types': 7.25.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-split-export-declaration@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/helper-string-parser@7.24.7': {} + + '@babel/helper-string-parser@7.25.7': {} + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/helper-validator-identifier@7.25.7': {} + + '@babel/helper-validator-option@7.24.7': {} + + '@babel/helper-validator-option@7.25.7': {} + + '@babel/helpers@7.24.7': + dependencies: + '@babel/template': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/helpers@7.25.7': + dependencies: + '@babel/template': 7.25.7 + '@babel/types': 7.25.8 + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/highlight@7.25.7': + dependencies: + '@babel/helper-validator-identifier': 7.25.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.0.1 + + '@babel/parser@7.24.7': + dependencies: + '@babel/types': 7.24.7 + + '@babel/parser@7.25.8': + dependencies: + '@babel/types': 7.25.8 + + '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.8)': + dependencies: + '@babel/core': 7.25.8 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.8)': + dependencies: + '@babel/core': 7.25.8 + '@babel/helper-plugin-utils': 7.24.7 + + '@babel/runtime@7.24.7': + dependencies: + regenerator-runtime: 0.14.1 + + '@babel/template@7.24.7': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + + '@babel/template@7.25.7': + dependencies: + '@babel/code-frame': 7.25.7 + '@babel/parser': 7.25.8 + '@babel/types': 7.25.8 + + '@babel/traverse@7.24.7': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-hoist-variables': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/traverse@7.25.7': + dependencies: + '@babel/code-frame': 7.25.7 + '@babel/generator': 7.25.7 + '@babel/parser': 7.25.8 + '@babel/template': 7.25.7 + '@babel/types': 7.25.8 + debug: 4.3.5 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.24.7': + dependencies: + '@babel/helper-string-parser': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + '@babel/types@7.25.8': + dependencies: + '@babel/helper-string-parser': 7.25.7 + '@babel/helper-validator-identifier': 7.25.7 + to-fast-properties: 2.0.0 '@dword-design/dedent@0.7.0': dependencies: babel-plugin-add-module-exports: 1.0.4 - '@dword-design/endent@1.4.7': + '@dword-design/endent@1.4.1': dependencies: - dedent: '@dword-design/dedent@0.7.0' + '@dword-design/dedent': 0.7.0 fast-json-parse: 1.0.3 objectorarray: 1.0.5 '@dword-design/eslint-plugin-import-alias@4.0.9': dependencies: - '@babel/core': 7.28.4 + '@babel/core': 7.24.7 '@dword-design/functions': 5.0.27 babel-plugin-module-resolver: 5.0.2 deepmerge: 4.3.1 @@ -4930,25 +5250,25 @@ snapshots: '@dword-design/functions@5.0.27': dependencies: - '@dword-design/endent': 1.4.7 + '@dword-design/endent': 1.4.1 delay: 5.0.0 lodash: 4.17.21 tinycolor2: 1.6.0 - '@emnapi/core@1.5.0': + '@emnapi/core@1.7.0': dependencies: '@emnapi/wasi-threads': 1.1.0 - tslib: 2.8.1 + tslib: 2.6.3 optional: true - '@emnapi/runtime@1.5.0': + '@emnapi/runtime@1.7.0': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 optional: true '@emnapi/wasi-threads@1.1.0': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 optional: true '@esbuild/aix-ppc64@0.21.5': @@ -5020,17 +5340,24 @@ snapshots: '@esbuild/win32-x64@0.21.5': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.0(jiti@1.21.6))': + '@eslint-community/eslint-utils@4.4.0(eslint@9.39.1(jiti@1.21.6))': dependencies: - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@1.21.6))': + dependencies: + eslint: 9.39.1(jiti@1.21.6) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.10.1': {} + '@eslint-community/regexpp@4.12.2': {} '@eslint/config-array@0.21.1': dependencies: '@eslint/object-schema': 2.1.7 - debug: 4.4.3 + debug: 4.3.7 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -5046,18 +5373,18 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.3 + debug: 4.3.7 espree: 10.4.0 globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 + ignore: 5.3.1 + import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@9.39.0': {} + '@eslint/js@9.39.1': {} '@eslint/object-schema@2.1.7': {} @@ -5081,19 +5408,19 @@ snapshots: dependencies: '@fluent/bundle': 0.18.0 - '@fontsource/poppins@5.2.6': {} + '@fontsource/poppins@5.1.0': {} '@formatjs/intl-localematcher@0.2.32': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 - '@graphql-typed-document-node/core@3.2.0(graphql@15.10.1)': + '@graphql-typed-document-node/core@3.2.0(graphql@15.9.0)': dependencies: - graphql: 15.10.1 + graphql: 15.9.0 - '@hookform/resolvers@3.10.0(react-hook-form@7.65.0(react@18.3.1))': + '@hookform/resolvers@3.6.0(react-hook-form@7.66.0(react@18.3.1))': dependencies: - react-hook-form: 7.65.0(react@18.3.1) + react-hook-form: 7.66.0(react@18.3.1) '@humanfs/core@0.19.1': {} @@ -5115,38 +5442,30 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 - '@jridgewell/gen-mapping@0.3.13': + '@jridgewell/gen-mapping@0.3.5': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.30 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/source-map@0.3.11': + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 optional: true - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.4.15': {} - '@jridgewell/trace-mapping@0.3.30': + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - optional: true - - '@mediapipe/tasks-vision@0.10.17': {} + '@mediapipe/tasks-vision@0.10.8': {} '@mgit-at/typescript-flatbuffers-codegen@0.1.3': dependencies: @@ -5160,16 +5479,16 @@ snapshots: typescript: 4.8.4 yargs: 16.2.0 - '@monogrid/gainmap-js@3.1.0(three@0.163.0)': + '@monogrid/gainmap-js@3.0.5(three@0.163.0)': dependencies: promise-worker-transferable: 1.0.4 three: 0.163.0 '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@emnapi/core': 1.5.0 - '@emnapi/runtime': 1.5.0 - '@tybys/wasm-util': 0.10.0 + '@emnapi/core': 1.7.0 + '@emnapi/runtime': 1.7.0 + '@tybys/wasm-util': 0.10.1 optional: true '@nodelib/fs.scandir@2.1.5': @@ -5186,26 +5505,26 @@ snapshots: '@nolyfill/is-core-module@1.0.39': {} - '@openapi-codegen/cli@2.0.4(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@openapi-codegen/cli@2.0.2(@types/react@18.3.11)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@apollo/client': 3.14.0(@types/react@18.3.24)(graphql@15.10.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@swc/core': 1.13.5 + '@apollo/client': 3.10.6(@types/react@18.3.11)(graphql@15.9.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@swc/core': 1.6.5 case: 1.6.3 - chalk: 5.6.0 + chalk: 5.3.0 cli-highlight: 2.1.11 clipanion: 3.2.1(typanion@3.14.0) fs-extra: 10.1.0 got: 12.6.1 got-fetch: 5.1.10(got@12.6.1) - graphql: 15.10.1 - ink: 5.2.1(@types/react@18.3.24)(react@18.3.1) + graphql: 15.9.0 + ink: 3.2.0(@types/react@18.3.11)(react@18.3.1) js-yaml: 4.1.0 openapi3-ts: 2.0.2 - prettier: 3.6.2 - rxjs: 7.8.2 + prettier: 3.3.3 + rxjs: 7.8.1 slash: 4.0.0 swagger2openapi: 7.0.8 - tslib: 2.8.1 + tslib: 2.6.3 typanion: 3.14.0 typescript: 4.8.2 transitivePeerDependencies: @@ -5215,18 +5534,17 @@ snapshots: - encoding - graphql-ws - react - - react-devtools-core - react-dom - subscriptions-transport-ws - utf-8-validate - '@openapi-codegen/typescript@8.1.1': + '@openapi-codegen/typescript@8.0.2': dependencies: case: 1.6.3 lodash: 4.17.21 openapi3-ts: 2.0.2 pluralize: 8.0.0 - tslib: 2.8.1 + tslib: 2.6.3 tsutils: 3.21.0(typescript@4.8.2) typescript: 4.8.2 @@ -5285,204 +5603,186 @@ snapshots: '@parcel/watcher-win32-arm64': 2.4.1 '@parcel/watcher-win32-ia32': 2.4.1 '@parcel/watcher-win32-x64': 2.4.1 - optional: true '@pkgjs/parseargs@0.11.0': optional: true - '@react-hookz/deep-equal@3.0.4': {} + '@react-hookz/deep-equal@3.0.3': {} - '@react-spring/animated@9.7.5(react@18.3.1)': + '@react-spring/animated@9.6.1(react@18.3.1)': dependencies: - '@react-spring/shared': 9.7.5(react@18.3.1) - '@react-spring/types': 9.7.5 + '@react-spring/shared': 9.6.1(react@18.3.1) + '@react-spring/types': 9.6.1 react: 18.3.1 - '@react-spring/core@9.7.5(react@18.3.1)': + '@react-spring/core@9.6.1(react@18.3.1)': dependencies: - '@react-spring/animated': 9.7.5(react@18.3.1) - '@react-spring/shared': 9.7.5(react@18.3.1) - '@react-spring/types': 9.7.5 + '@react-spring/animated': 9.6.1(react@18.3.1) + '@react-spring/rafz': 9.6.1 + '@react-spring/shared': 9.6.1(react@18.3.1) + '@react-spring/types': 9.6.1 react: 18.3.1 - '@react-spring/rafz@9.7.5': {} + '@react-spring/rafz@9.6.1': {} - '@react-spring/shared@9.7.5(react@18.3.1)': + '@react-spring/shared@9.6.1(react@18.3.1)': dependencies: - '@react-spring/rafz': 9.7.5 - '@react-spring/types': 9.7.5 + '@react-spring/rafz': 9.6.1 + '@react-spring/types': 9.6.1 react: 18.3.1 - '@react-spring/three@9.7.5(@react-three/fiber@8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0)': + '@react-spring/three@9.6.1(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0)': dependencies: - '@react-spring/animated': 9.7.5(react@18.3.1) - '@react-spring/core': 9.7.5(react@18.3.1) - '@react-spring/shared': 9.7.5(react@18.3.1) - '@react-spring/types': 9.7.5 - '@react-three/fiber': 8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + '@react-spring/animated': 9.6.1(react@18.3.1) + '@react-spring/core': 9.6.1(react@18.3.1) + '@react-spring/shared': 9.6.1(react@18.3.1) + '@react-spring/types': 9.6.1 + '@react-three/fiber': 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) react: 18.3.1 three: 0.163.0 - '@react-spring/types@9.7.5': {} + '@react-spring/types@9.6.1': {} - '@react-three/drei@9.122.0(@react-three/fiber@8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.24)(@types/three@0.163.0)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)(use-sync-external-store@1.5.0(react@18.3.1))': + '@react-three/drei@9.114.5(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(@types/react@18.3.11)(@types/three@0.163.0)(immer@10.1.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': dependencies: - '@babel/runtime': 7.28.4 - '@mediapipe/tasks-vision': 0.10.17 - '@monogrid/gainmap-js': 3.1.0(three@0.163.0) - '@react-spring/three': 9.7.5(@react-three/fiber@8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0) - '@react-three/fiber': 8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) + '@babel/runtime': 7.24.7 + '@mediapipe/tasks-vision': 0.10.8 + '@monogrid/gainmap-js': 3.0.5(three@0.163.0) + '@react-spring/three': 9.6.1(@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0))(react@18.3.1)(three@0.163.0) + '@react-three/fiber': 8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0) '@use-gesture/react': 10.3.1(react@18.3.1) - camera-controls: 2.10.1(three@0.163.0) + camera-controls: 2.8.5(three@0.163.0) cross-env: 7.0.3 - detect-gpu: 5.0.70 + detect-gpu: 5.0.38 glsl-noise: 0.0.0 - hls.js: 1.6.11 - maath: 0.10.8(@types/three@0.163.0)(three@0.163.0) + hls.js: 1.5.17 + maath: 0.10.7(@types/three@0.163.0)(three@0.163.0) meshline: 3.3.1(three@0.163.0) react: 18.3.1 react-composer: 5.0.3(react@18.3.1) - stats-gl: 2.4.2(@types/three@0.163.0)(three@0.163.0) + stats-gl: 2.2.8 stats.js: 0.17.0 suspend-react: 0.1.3(react@18.3.1) three: 0.163.0 three-mesh-bvh: 0.7.8(three@0.163.0) - three-stdlib: 2.36.0(three@0.163.0) - troika-three-text: 0.52.4(three@0.163.0) - tunnel-rat: 0.1.2(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1) + three-stdlib: 2.30.3(three@0.163.0) + troika-three-text: 0.49.1(three@0.163.0) + tunnel-rat: 0.1.2(@types/react@18.3.11)(immer@10.1.1)(react@18.3.1) utility-types: 3.11.0 - zustand: 5.0.8(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) + uuid: 9.0.1 + zustand: 3.7.2(react@18.3.1) optionalDependencies: react-dom: 18.3.1(react@18.3.1) transitivePeerDependencies: - '@types/react' - '@types/three' - immer - - use-sync-external-store - '@react-three/fiber@8.18.0(@types/react@18.3.24)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': + '@react-three/fiber@8.17.10(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.163.0)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.24.7 + '@types/debounce': 1.2.4 '@types/react-reconciler': 0.26.7 - '@types/webxr': 0.5.23 + '@types/webxr': 0.5.16 base64-js: 1.5.1 buffer: 6.0.3 - its-fine: 1.2.5(@types/react@18.3.24)(react@18.3.1) + debounce: 1.2.1 + its-fine: 1.2.5(react@18.3.1) react: 18.3.1 react-reconciler: 0.27.0(react@18.3.1) - react-use-measure: 2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) scheduler: 0.21.0 suspend-react: 0.1.3(react@18.3.1) three: 0.163.0 zustand: 3.7.2(react@18.3.1) optionalDependencies: react-dom: 18.3.1(react@18.3.1) - transitivePeerDependencies: - - '@types/react' - '@remix-run/router@1.23.0': {} + '@remix-run/router@1.20.0': {} - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.50.0': + '@rollup/rollup-android-arm-eabi@4.24.0': optional: true - '@rollup/rollup-android-arm64@4.50.0': + '@rollup/rollup-android-arm64@4.24.0': optional: true - '@rollup/rollup-darwin-arm64@4.50.0': + '@rollup/rollup-darwin-arm64@4.24.0': optional: true - '@rollup/rollup-darwin-x64@4.50.0': + '@rollup/rollup-darwin-x64@4.24.0': optional: true - '@rollup/rollup-freebsd-arm64@4.50.0': + '@rollup/rollup-linux-arm-gnueabihf@4.24.0': optional: true - '@rollup/rollup-freebsd-x64@4.50.0': + '@rollup/rollup-linux-arm-musleabihf@4.24.0': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.50.0': + '@rollup/rollup-linux-arm64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.50.0': + '@rollup/rollup-linux-arm64-musl@4.24.0': optional: true - '@rollup/rollup-linux-arm64-gnu@4.50.0': + '@rollup/rollup-linux-powerpc64le-gnu@4.24.0': optional: true - '@rollup/rollup-linux-arm64-musl@4.50.0': + '@rollup/rollup-linux-riscv64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.50.0': + '@rollup/rollup-linux-s390x-gnu@4.24.0': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.50.0': + '@rollup/rollup-linux-x64-gnu@4.24.0': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.50.0': + '@rollup/rollup-linux-x64-musl@4.24.0': optional: true - '@rollup/rollup-linux-riscv64-musl@4.50.0': + '@rollup/rollup-win32-arm64-msvc@4.24.0': optional: true - '@rollup/rollup-linux-s390x-gnu@4.50.0': + '@rollup/rollup-win32-ia32-msvc@4.24.0': optional: true - '@rollup/rollup-linux-x64-gnu@4.50.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.50.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.50.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.50.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.50.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.50.0': + '@rollup/rollup-win32-x64-msvc@4.24.0': optional: true '@rtsao/scc@1.1.0': {} - '@sentry-internal/browser-utils@9.46.0': + '@sentry-internal/browser-utils@9.9.0': dependencies: - '@sentry/core': 9.46.0 + '@sentry/core': 9.9.0 - '@sentry-internal/feedback@9.46.0': + '@sentry-internal/feedback@9.9.0': dependencies: - '@sentry/core': 9.46.0 + '@sentry/core': 9.9.0 - '@sentry-internal/replay-canvas@9.46.0': + '@sentry-internal/replay-canvas@9.9.0': dependencies: - '@sentry-internal/replay': 9.46.0 - '@sentry/core': 9.46.0 + '@sentry-internal/replay': 9.9.0 + '@sentry/core': 9.9.0 - '@sentry-internal/replay@9.46.0': + '@sentry-internal/replay@9.9.0': dependencies: - '@sentry-internal/browser-utils': 9.46.0 - '@sentry/core': 9.46.0 + '@sentry-internal/browser-utils': 9.9.0 + '@sentry/core': 9.9.0 - '@sentry/babel-plugin-component-annotate@2.23.1': {} + '@sentry/babel-plugin-component-annotate@2.22.7': {} - '@sentry/browser@9.46.0': + '@sentry/browser@9.9.0': dependencies: - '@sentry-internal/browser-utils': 9.46.0 - '@sentry-internal/feedback': 9.46.0 - '@sentry-internal/replay': 9.46.0 - '@sentry-internal/replay-canvas': 9.46.0 - '@sentry/core': 9.46.0 + '@sentry-internal/browser-utils': 9.9.0 + '@sentry-internal/feedback': 9.9.0 + '@sentry-internal/replay': 9.9.0 + '@sentry-internal/replay-canvas': 9.9.0 + '@sentry/core': 9.9.0 - '@sentry/bundler-plugin-core@2.23.1': + '@sentry/bundler-plugin-core@2.22.7': dependencies: - '@babel/core': 7.28.4 - '@sentry/babel-plugin-component-annotate': 2.23.1 + '@babel/core': 7.25.8 + '@sentry/babel-plugin-component-annotate': 2.22.7 '@sentry/cli': 2.39.1 - dotenv: 16.6.1 + dotenv: 16.4.5 find-up: 5.0.0 glob: 9.3.5 magic-string: 0.30.8 @@ -5531,18 +5831,18 @@ snapshots: - encoding - supports-color - '@sentry/core@9.46.0': {} + '@sentry/core@9.9.0': {} - '@sentry/react@9.46.0(react@18.3.1)': + '@sentry/react@9.9.0(react@18.3.1)': dependencies: - '@sentry/browser': 9.46.0 - '@sentry/core': 9.46.0 + '@sentry/browser': 9.9.0 + '@sentry/core': 9.9.0 hoist-non-react-statics: 3.3.2 react: 18.3.1 - '@sentry/vite-plugin@2.23.1': + '@sentry/vite-plugin@2.22.7': dependencies: - '@sentry/bundler-plugin-core': 2.23.1 + '@sentry/bundler-plugin-core': 2.22.7 unplugin: 1.0.1 transitivePeerDependencies: - encoding @@ -5550,65 +5850,65 @@ snapshots: '@sindresorhus/is@5.6.0': {} - '@stylistic/eslint-plugin@5.5.0(eslint@9.39.0(jiti@1.21.6))': + '@stylistic/eslint-plugin@5.5.0(eslint@9.39.1(jiti@1.21.6))': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.6)) - '@typescript-eslint/types': 8.46.2 - eslint: 9.39.0(jiti@1.21.6) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.6)) + '@typescript-eslint/types': 8.46.4 + eslint: 9.39.1(jiti@1.21.6) eslint-visitor-keys: 4.2.1 espree: 10.4.0 estraverse: 5.3.0 picomatch: 4.0.3 - '@swc/core-darwin-arm64@1.13.5': + '@swc/core-darwin-arm64@1.6.5': optional: true - '@swc/core-darwin-x64@1.13.5': + '@swc/core-darwin-x64@1.6.5': optional: true - '@swc/core-linux-arm-gnueabihf@1.13.5': + '@swc/core-linux-arm-gnueabihf@1.6.5': optional: true - '@swc/core-linux-arm64-gnu@1.13.5': + '@swc/core-linux-arm64-gnu@1.6.5': optional: true - '@swc/core-linux-arm64-musl@1.13.5': + '@swc/core-linux-arm64-musl@1.6.5': optional: true - '@swc/core-linux-x64-gnu@1.13.5': + '@swc/core-linux-x64-gnu@1.6.5': optional: true - '@swc/core-linux-x64-musl@1.13.5': + '@swc/core-linux-x64-musl@1.6.5': optional: true - '@swc/core-win32-arm64-msvc@1.13.5': + '@swc/core-win32-arm64-msvc@1.6.5': optional: true - '@swc/core-win32-ia32-msvc@1.13.5': + '@swc/core-win32-ia32-msvc@1.6.5': optional: true - '@swc/core-win32-x64-msvc@1.13.5': + '@swc/core-win32-x64-msvc@1.6.5': optional: true - '@swc/core@1.13.5': + '@swc/core@1.6.5': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.24 + '@swc/types': 0.1.9 optionalDependencies: - '@swc/core-darwin-arm64': 1.13.5 - '@swc/core-darwin-x64': 1.13.5 - '@swc/core-linux-arm-gnueabihf': 1.13.5 - '@swc/core-linux-arm64-gnu': 1.13.5 - '@swc/core-linux-arm64-musl': 1.13.5 - '@swc/core-linux-x64-gnu': 1.13.5 - '@swc/core-linux-x64-musl': 1.13.5 - '@swc/core-win32-arm64-msvc': 1.13.5 - '@swc/core-win32-ia32-msvc': 1.13.5 - '@swc/core-win32-x64-msvc': 1.13.5 + '@swc/core-darwin-arm64': 1.6.5 + '@swc/core-darwin-x64': 1.6.5 + '@swc/core-linux-arm-gnueabihf': 1.6.5 + '@swc/core-linux-arm64-gnu': 1.6.5 + '@swc/core-linux-arm64-musl': 1.6.5 + '@swc/core-linux-x64-gnu': 1.6.5 + '@swc/core-linux-x64-musl': 1.6.5 + '@swc/core-win32-arm64-msvc': 1.6.5 + '@swc/core-win32-ia32-msvc': 1.6.5 + '@swc/core-win32-x64-msvc': 1.6.5 '@swc/counter@0.1.3': {} - '@swc/types@0.1.24': + '@swc/types@0.1.9': dependencies: '@swc/counter': 0.1.3 @@ -5616,138 +5916,140 @@ snapshots: dependencies: defer-to-connect: 2.0.1 - '@tailwindcss/forms@0.5.10(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.9.2)))': + '@tailwindcss/forms@0.5.9(tailwindcss@3.4.14(ts-node@9.1.1(typescript@5.6.3)))': dependencies: mini-svg-data-uri: 1.4.4 - tailwindcss: 3.4.17(ts-node@9.1.1(typescript@5.9.2)) + tailwindcss: 3.4.14(ts-node@9.1.1(typescript@5.6.3)) - '@tailwindcss/typography@0.5.16(tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.9.2)))': + '@tailwindcss/typography@0.5.15(tailwindcss@3.4.14(ts-node@9.1.1(typescript@5.6.3)))': dependencies: lodash.castarray: 4.4.0 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 - tailwindcss: 3.4.17(ts-node@9.1.1(typescript@5.9.2)) + tailwindcss: 3.4.14(ts-node@9.1.1(typescript@5.6.3)) - '@tanstack/query-core@5.87.1': {} + '@tanstack/query-core@5.48.0': {} - '@tanstack/react-query@5.87.1(react@18.3.1)': + '@tanstack/react-query@5.48.0(react@18.3.1)': dependencies: - '@tanstack/query-core': 5.87.1 + '@tanstack/query-core': 5.48.0 react: 18.3.1 - '@tauri-apps/api@2.8.0': {} + '@tauri-apps/api@2.0.2': {} - '@tauri-apps/cli-darwin-arm64@2.8.4': + '@tauri-apps/api@2.6.0': {} + + '@tauri-apps/api@2.9.0': {} + + '@tauri-apps/cli-darwin-arm64@2.0.3': optional: true - '@tauri-apps/cli-darwin-x64@2.8.4': + '@tauri-apps/cli-darwin-x64@2.0.3': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@2.8.4': + '@tauri-apps/cli-linux-arm-gnueabihf@2.0.3': optional: true - '@tauri-apps/cli-linux-arm64-gnu@2.8.4': + '@tauri-apps/cli-linux-arm64-gnu@2.0.3': optional: true - '@tauri-apps/cli-linux-arm64-musl@2.8.4': + '@tauri-apps/cli-linux-arm64-musl@2.0.3': optional: true - '@tauri-apps/cli-linux-riscv64-gnu@2.8.4': + '@tauri-apps/cli-linux-x64-gnu@2.0.3': optional: true - '@tauri-apps/cli-linux-x64-gnu@2.8.4': + '@tauri-apps/cli-linux-x64-musl@2.0.3': optional: true - '@tauri-apps/cli-linux-x64-musl@2.8.4': + '@tauri-apps/cli-win32-arm64-msvc@2.0.3': optional: true - '@tauri-apps/cli-win32-arm64-msvc@2.8.4': + '@tauri-apps/cli-win32-ia32-msvc@2.0.3': optional: true - '@tauri-apps/cli-win32-ia32-msvc@2.8.4': + '@tauri-apps/cli-win32-x64-msvc@2.0.3': optional: true - '@tauri-apps/cli-win32-x64-msvc@2.8.4': - optional: true - - '@tauri-apps/cli@2.8.4': + '@tauri-apps/cli@2.0.3': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.8.4 - '@tauri-apps/cli-darwin-x64': 2.8.4 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.8.4 - '@tauri-apps/cli-linux-arm64-gnu': 2.8.4 - '@tauri-apps/cli-linux-arm64-musl': 2.8.4 - '@tauri-apps/cli-linux-riscv64-gnu': 2.8.4 - '@tauri-apps/cli-linux-x64-gnu': 2.8.4 - '@tauri-apps/cli-linux-x64-musl': 2.8.4 - '@tauri-apps/cli-win32-arm64-msvc': 2.8.4 - '@tauri-apps/cli-win32-ia32-msvc': 2.8.4 - '@tauri-apps/cli-win32-x64-msvc': 2.8.4 + '@tauri-apps/cli-darwin-arm64': 2.0.3 + '@tauri-apps/cli-darwin-x64': 2.0.3 + '@tauri-apps/cli-linux-arm-gnueabihf': 2.0.3 + '@tauri-apps/cli-linux-arm64-gnu': 2.0.3 + '@tauri-apps/cli-linux-arm64-musl': 2.0.3 + '@tauri-apps/cli-linux-x64-gnu': 2.0.3 + '@tauri-apps/cli-linux-x64-musl': 2.0.3 + '@tauri-apps/cli-win32-arm64-msvc': 2.0.3 + '@tauri-apps/cli-win32-ia32-msvc': 2.0.3 + '@tauri-apps/cli-win32-x64-msvc': 2.0.3 - '@tauri-apps/plugin-dialog@2.4.0': + '@tauri-apps/plugin-dialog@2.0.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-fs@2.4.2': + '@tauri-apps/plugin-fs@2.4.1': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.6.0 - '@tauri-apps/plugin-http@2.5.2': + '@tauri-apps/plugin-http@2.5.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.6.0 - '@tauri-apps/plugin-log@2.7.0': + '@tauri-apps/plugin-log@2.7.1': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 - '@tauri-apps/plugin-opener@2.5.0': + '@tauri-apps/plugin-opener@2.4.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.6.0 - '@tauri-apps/plugin-os@2.3.1': + '@tauri-apps/plugin-os@2.0.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.0.2 - '@tauri-apps/plugin-shell@2.3.1': + '@tauri-apps/plugin-shell@2.3.0': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.6.0 - '@tauri-apps/plugin-store@2.4.0': + '@tauri-apps/plugin-store@2.4.1': dependencies: - '@tauri-apps/api': 2.8.0 + '@tauri-apps/api': 2.9.0 - '@tweenjs/tween.js@23.1.3': {} + '@tweenjs/tween.js@23.1.2': {} '@tweenjs/tween.js@25.0.0': {} '@twemoji/svg@15.0.0': {} - '@tybys/wasm-util@0.10.0': + '@tybys/wasm-util@0.10.1': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 optional: true '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 - '@types/babel__generator': 7.27.0 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 + '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 + '@types/babel__traverse': 7.20.6 - '@types/babel__generator@7.27.0': + '@types/babel__generator@7.6.8': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.24.7 '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.28.4 - '@babel/types': 7.28.4 + '@babel/parser': 7.24.7 + '@babel/types': 7.24.7 - '@types/babel__traverse@7.28.0': + '@types/babel__traverse@7.20.6': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.24.7 + + '@types/debounce@1.2.4': {} '@types/debug@4.1.12': dependencies: @@ -5757,9 +6059,9 @@ snapshots: '@types/estree-jsx@1.0.5': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.6 - '@types/estree@1.0.8': {} + '@types/estree@1.0.6': {} '@types/file-saver@2.0.7': {} @@ -5779,48 +6081,48 @@ snapshots: '@types/ms@0.7.34': {} - '@types/node@24.3.1': + '@types/node@24.10.0': dependencies: - undici-types: 7.10.0 + undici-types: 7.16.0 '@types/offscreencanvas@2019.7.3': {} - '@types/prop-types@15.7.15': {} + '@types/prop-types@15.7.12': {} - '@types/react-dom@18.3.7(@types/react@18.3.24)': + '@types/react-dom@18.3.0': dependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 '@types/react-helmet@6.1.11': dependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 '@types/react-modal@3.16.3': dependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 '@types/react-reconciler@0.26.7': dependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 - '@types/react-reconciler@0.28.9(@types/react@18.3.24)': + '@types/react-reconciler@0.28.8': dependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 - '@types/react@18.3.24': + '@types/react@18.3.11': dependencies: - '@types/prop-types': 15.7.15 + '@types/prop-types': 15.7.12 csstype: 3.1.3 - '@types/semver@7.7.1': {} + '@types/semver@7.5.8': {} - '@types/stats.js@0.17.4': {} + '@types/stats.js@0.17.3': {} '@types/three@0.163.0': dependencies: - '@tweenjs/tween.js': 23.1.3 - '@types/stats.js': 0.17.4 - '@types/webxr': 0.5.23 + '@tweenjs/tween.js': 23.1.2 + '@types/stats.js': 0.17.3 + '@types/webxr': 0.5.16 fflate: 0.8.2 meshoptimizer: 0.18.1 @@ -5828,74 +6130,76 @@ snapshots: '@types/unist@3.0.3': {} - '@types/webxr@0.5.23': {} + '@types/webxr@0.5.16': {} - '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@types/yoga-layout@1.9.2': {} + + '@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + '@eslint-community/regexpp': 4.10.1 + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) '@typescript-eslint/scope-manager': 7.18.0 - '@typescript-eslint/type-utils': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/utils': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + '@typescript-eslint/type-utils': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.18.0 - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 5.3.1 natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.9.2) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.9.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/type-utils': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.46.2 - eslint: 9.39.0(jiti@1.21.6) + '@eslint-community/regexpp': 4.10.1 + '@typescript-eslint/parser': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.46.4 + '@typescript-eslint/type-utils': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/utils': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.46.4 + eslint: 9.39.1(jiti@1.21.6) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.1 - eslint: 9.39.0(jiti@1.21.6) + debug: 4.3.5 + eslint: 9.39.1(jiti@1.21.6) optionalDependencies: - typescript: 5.9.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/parser@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.2) - '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3 - eslint: 9.39.0(jiti@1.21.6) - typescript: 5.9.2 + '@typescript-eslint/scope-manager': 8.46.4 + '@typescript-eslint/types': 8.46.4 + '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.46.4 + debug: 4.3.7 + eslint: 9.39.1(jiti@1.21.6) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.46.2(typescript@5.9.2)': + '@typescript-eslint/project-service@8.46.4(typescript@5.6.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.2) - '@typescript-eslint/types': 8.46.2 - debug: 4.4.3 - typescript: 5.9.2 + '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.6.3) + '@typescript-eslint/types': 8.46.4 + debug: 4.3.7 + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -5904,93 +6208,93 @@ snapshots: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - '@typescript-eslint/scope-manager@8.46.2': + '@typescript-eslint/scope-manager@8.46.4': dependencies: - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 + '@typescript-eslint/types': 8.46.4 + '@typescript-eslint/visitor-keys': 8.46.4 - '@typescript-eslint/tsconfig-utils@8.46.2(typescript@5.9.2)': + '@typescript-eslint/tsconfig-utils@8.46.4(typescript@5.6.3)': dependencies: - typescript: 5.9.2 + typescript: 5.6.3 - '@typescript-eslint/type-utils@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/type-utils@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.2) - '@typescript-eslint/utils': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - debug: 4.4.3 - eslint: 9.39.0(jiti@1.21.6) - ts-api-utils: 1.4.3(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + '@typescript-eslint/utils': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + debug: 4.3.5 + eslint: 9.39.1(jiti@1.21.6) + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.9.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.2) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - debug: 4.4.3 - eslint: 9.39.0(jiti@1.21.6) - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + '@typescript-eslint/types': 8.46.4 + '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.6.3) + '@typescript-eslint/utils': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + debug: 4.3.7 + eslint: 9.39.1(jiti@1.21.6) + ts-api-utils: 2.1.0(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color '@typescript-eslint/types@7.18.0': {} - '@typescript-eslint/types@8.46.2': {} + '@typescript-eslint/types@8.46.4': {} - '@typescript-eslint/typescript-estree@7.18.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@7.18.0(typescript@5.6.3)': dependencies: '@typescript-eslint/types': 7.18.0 '@typescript-eslint/visitor-keys': 7.18.0 - debug: 4.4.3 + debug: 4.3.5 globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 1.4.3(typescript@5.9.2) + minimatch: 9.0.4 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.3) optionalDependencies: - typescript: 5.9.2 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.46.2(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.46.4(typescript@5.6.3)': dependencies: - '@typescript-eslint/project-service': 8.46.2(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.46.2(typescript@5.9.2) - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/visitor-keys': 8.46.2 - debug: 4.4.3 - fast-glob: 3.3.3 + '@typescript-eslint/project-service': 8.46.4(typescript@5.6.3) + '@typescript-eslint/tsconfig-utils': 8.46.4(typescript@5.6.3) + '@typescript-eslint/types': 8.46.4 + '@typescript-eslint/visitor-keys': 8.46.4 + debug: 4.3.7 + fast-glob: 3.3.2 is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.2 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + minimatch: 9.0.4 + semver: 7.6.3 + ts-api-utils: 2.1.0(typescript@5.6.3) + typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/utils@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.4.0(eslint@9.39.1(jiti@1.21.6)) '@typescript-eslint/scope-manager': 7.18.0 '@typescript-eslint/types': 7.18.0 - '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.9.2) - eslint: 9.39.0(jiti@1.21.6) + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.3) + eslint: 9.39.1(jiti@1.21.6) transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/utils@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2)': + '@typescript-eslint/utils@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.6)) - '@typescript-eslint/scope-manager': 8.46.2 - '@typescript-eslint/types': 8.46.2 - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.2) - eslint: 9.39.0(jiti@1.21.6) - typescript: 5.9.2 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.6)) + '@typescript-eslint/scope-manager': 8.46.4 + '@typescript-eslint/types': 8.46.4 + '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.6.3) + eslint: 9.39.1(jiti@1.21.6) + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -5999,12 +6303,12 @@ snapshots: '@typescript-eslint/types': 7.18.0 eslint-visitor-keys: 3.4.3 - '@typescript-eslint/visitor-keys@8.46.2': + '@typescript-eslint/visitor-keys@8.46.4': dependencies: - '@typescript-eslint/types': 8.46.2 + '@typescript-eslint/types': 8.46.4 eslint-visitor-keys: 4.2.1 - '@ungap/structured-clone@1.3.0': {} + '@ungap/structured-clone@1.2.0': {} '@unrs/resolver-binding-android-arm-eabi@1.11.1': optional: true @@ -6072,43 +6376,48 @@ snapshots: '@use-gesture/core': 10.3.1 react: 18.3.1 - '@vitejs/plugin-react@4.7.0(vite@5.4.19(@types/node@24.3.1)(sass@1.92.0)(terser@5.31.1))': + '@vitejs/plugin-react@4.3.2(vite@5.4.9(@types/node@24.10.0)(sass@1.80.2)(terser@5.31.1))': dependencies: - '@babel/core': 7.28.4 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) - '@rolldown/pluginutils': 1.0.0-beta.27 + '@babel/core': 7.25.8 + '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.8) + '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.8) '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 5.4.19(@types/node@24.3.1)(sass@1.92.0)(terser@5.31.1) + react-refresh: 0.14.2 + vite: 5.4.9(@types/node@24.10.0)(sass@1.80.2)(terser@5.31.1) transitivePeerDependencies: - supports-color '@wry/caches@1.0.1': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 '@wry/context@0.7.4': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 '@wry/equality@0.5.7': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 + + '@wry/trie@0.4.3': + dependencies: + tslib: 2.6.3 '@wry/trie@0.5.0': dependencies: - tslib: 2.8.1 + tslib: 2.6.3 acorn-jsx@5.3.2(acorn@8.15.0): dependencies: acorn: 8.15.0 + acorn@8.12.0: {} + acorn@8.15.0: {} agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -6126,13 +6435,21 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + ansi-escapes@7.0.0: dependencies: environment: 1.1.0 ansi-regex@5.0.1: {} - ansi-regex@6.2.0: {} + ansi-regex@6.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 ansi-styles@4.3.0: dependencies: @@ -6220,7 +6537,7 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 + es-shim-unscopables: 1.0.2 array.prototype.flatmap@1.3.2: dependencies: @@ -6234,7 +6551,7 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 es-abstract: 1.24.0 - es-shim-unscopables: 1.1.0 + es-shim-unscopables: 1.0.2 array.prototype.tosorted@1.1.4: dependencies: @@ -6267,18 +6584,18 @@ snapshots: ast-types-flow@0.0.8: {} - async-function@1.0.0: {} + astral-regex@2.0.0: {} - auto-bind@5.0.1: {} + auto-bind@4.0.0: {} - autoprefixer@10.4.21(postcss@8.5.6): + autoprefixer@10.4.20(postcss@8.4.38): dependencies: - browserslist: 4.25.4 - caniuse-lite: 1.0.30001741 + browserslist: 4.24.0 + caniuse-lite: 1.0.30001669 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.6 + picocolors: 1.0.1 + postcss: 8.4.38 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -6293,11 +6610,11 @@ snapshots: babel-plugin-module-resolver@5.0.2: dependencies: - find-babel-config: 2.1.2 + find-babel-config: 2.1.1 glob: 9.3.5 pkg-up: 3.1.0 reselect: 4.1.8 - resolve: 1.22.10 + resolve: 1.22.8 bail@2.0.2: {} @@ -6316,7 +6633,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@2.0.1: dependencies: balanced-match: 1.0.2 @@ -6326,12 +6643,19 @@ snapshots: browser-fs-access@0.35.0: {} - browserslist@4.25.4: + browserslist@4.23.1: dependencies: - caniuse-lite: 1.0.30001741 - electron-to-chromium: 1.5.214 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.4) + caniuse-lite: 1.0.30001636 + electron-to-chromium: 1.4.803 + node-releases: 2.0.14 + update-browserslist-db: 1.0.16(browserslist@4.23.1) + + browserslist@4.24.0: + dependencies: + caniuse-lite: 1.0.30001669 + electron-to-chromium: 1.5.41 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.0) buffer-from@1.1.2: {} @@ -6346,10 +6670,10 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 get-stream: 6.0.1 - http-cache-semantics: 4.2.0 + http-cache-semantics: 4.1.1 keyv: 4.5.4 mimic-response: 4.0.0 - normalize-url: 8.0.2 + normalize-url: 8.0.1 responselike: 3.0.0 cached-iterable@0.3.0: {} @@ -6362,7 +6686,7 @@ snapshots: call-bind@1.0.2: dependencies: function-bind: 1.1.2 - get-intrinsic: 1.2.4 + get-intrinsic: 1.2.1 call-bind@1.0.7: dependencies: @@ -6375,7 +6699,7 @@ snapshots: call-bind@1.0.8: dependencies: call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 + es-define-property: 1.0.0 get-intrinsic: 1.3.0 set-function-length: 1.2.2 @@ -6390,22 +6714,30 @@ snapshots: camelcase-css@2.0.1: {} - camera-controls@2.10.1(three@0.163.0): + camera-controls@2.8.5(three@0.163.0): dependencies: three: 0.163.0 - caniuse-lite@1.0.30001741: {} + caniuse-lite@1.0.30001636: {} + + caniuse-lite@1.0.30001669: {} case@1.6.3: {} ccount@2.0.1: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.6.0: {} + chalk@5.3.0: {} character-entities-html4@2.1.0: {} @@ -6431,13 +6763,15 @@ snapshots: dependencies: readdirp: 4.0.2 + ci-info@2.0.0: {} + classnames@2.5.1: {} - cli-boxes@3.0.0: {} + cli-boxes@2.2.1: {} - cli-cursor@4.0.0: + cli-cursor@3.1.0: dependencies: - restore-cursor: 4.0.0 + restore-cursor: 3.1.0 cli-cursor@5.0.0: dependencies: @@ -6452,10 +6786,15 @@ snapshots: parse5-htmlparser2-tree-adapter: 6.0.1 yargs: 16.2.0 + cli-truncate@2.1.0: + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + cli-truncate@4.0.0: dependencies: slice-ansi: 5.0.0 - string-width: 7.2.0 + string-width: 7.1.0 clipanion@3.2.1(typanion@3.14.0): dependencies: @@ -6473,21 +6812,27 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - code-excerpt@4.0.0: + code-excerpt@3.0.0: dependencies: - convert-to-spaces: 2.0.1 + convert-to-spaces: 1.0.2 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} colorette@2.0.20: {} comma-separated-tokens@2.0.3: {} - commander@13.1.0: {} + commander@12.1.0: {} commander@2.20.3: optional: true @@ -6500,13 +6845,19 @@ snapshots: convert-source-map@2.0.0: {} - convert-to-spaces@2.0.1: {} + convert-to-spaces@1.0.2: {} create-require@1.1.1: {} cross-env@7.0.3: dependencies: - cross-spawn: 7.0.6 + cross-spawn: 7.0.3 + + cross-spawn@7.0.3: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 cross-spawn@7.0.6: dependencies: @@ -6558,11 +6909,17 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + debounce@1.2.1: {} + debug@3.2.7: dependencies: ms: 2.1.3 - debug@4.4.1: + debug@4.3.5: + dependencies: + ms: 2.1.2 + + debug@4.3.7: dependencies: ms: 2.1.3 @@ -6574,10 +6931,6 @@ snapshots: dependencies: character-entities: 2.0.2 - decode-named-character-reference@1.2.0: - dependencies: - character-entities: 2.0.2 - decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 @@ -6613,7 +6966,7 @@ snapshots: dependencies: es-define-property: 1.0.0 es-errors: 1.3.0 - gopd: 1.2.0 + gopd: 1.0.1 define-lazy-prop@2.0.0: {} @@ -6627,12 +6980,11 @@ snapshots: dequal@2.0.3: {} - detect-gpu@5.0.70: + detect-gpu@5.0.38: dependencies: webgl-constants: 1.1.1 - detect-libc@1.0.3: - optional: true + detect-libc@1.0.3: {} devlop@1.1.0: dependencies: @@ -6652,7 +7004,7 @@ snapshots: dependencies: esutils: 2.0.3 - dotenv@16.6.1: {} + dotenv@16.4.5: {} draco3d@1.5.7: {} @@ -6668,9 +7020,11 @@ snapshots: ebnf@1.9.1: {} - electron-to-chromium@1.5.214: {} + electron-to-chromium@1.4.803: {} - emoji-regex@10.5.0: {} + electron-to-chromium@1.5.41: {} + + emoji-regex@10.3.0: {} emoji-regex@8.0.0: {} @@ -6815,7 +7169,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 - es-set-tostringtag: 2.1.0 + es-set-tostringtag: 2.0.3 function-bind: 1.1.2 get-intrinsic: 1.3.0 globalthis: 1.0.4 @@ -6837,7 +7191,7 @@ snapshots: es-set-tostringtag@2.0.3: dependencies: - get-intrinsic: 1.2.4 + get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -6865,10 +7219,8 @@ snapshots: es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 - is-date-object: 1.1.0 - is-symbol: 1.1.1 - - es-toolkit@1.39.10: {} + is-date-object: 1.0.5 + is-symbol: 1.0.4 es6-promise@3.3.1: {} @@ -6902,29 +7254,31 @@ snapshots: escalade@3.2.0: {} + escape-string-regexp@1.0.5: {} + escape-string-regexp@2.0.0: {} escape-string-regexp@4.0.0: {} escape-string-regexp@5.0.0: {} - eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.6)): + eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.6)): dependencies: confusing-browser-globals: 1.0.11 - eslint: 9.39.0(jiti@1.21.6) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)) + eslint: 9.39.1(jiti@1.21.6) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)) object.assign: 4.1.5 object.entries: 1.1.8 semver: 6.3.1 - eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0)(eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.0(jiti@1.21.6)))(eslint-plugin-react-hooks@4.6.2(eslint@9.39.0(jiti@1.21.6)))(eslint-plugin-react@7.37.5(eslint@9.39.0(jiti@1.21.6)))(eslint@9.39.0(jiti@1.21.6)): + eslint-config-airbnb@19.0.4(eslint-plugin-import@2.32.0)(eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1(jiti@1.21.6)))(eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@1.21.6)))(eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.6)))(eslint@9.39.1(jiti@1.21.6)): dependencies: - eslint: 9.39.0(jiti@1.21.6) - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.6)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.0(jiti@1.21.6)) - eslint-plugin-react: 7.37.5(eslint@9.39.0(jiti@1.21.6)) - eslint-plugin-react-hooks: 4.6.2(eslint@9.39.0(jiti@1.21.6)) + eslint: 9.39.1(jiti@1.21.6) + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.6)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)) + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.1(jiti@1.21.6)) + eslint-plugin-react: 7.37.5(eslint@9.39.1(jiti@1.21.6)) + eslint-plugin-react-hooks: 4.6.2(eslint@9.39.1(jiti@1.21.6)) object.assign: 4.1.5 object.entries: 1.1.8 @@ -6936,33 +7290,33 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.6)): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.6)): dependencies: '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 9.39.0(jiti@1.21.6) - get-tsconfig: 4.10.1 + debug: 4.4.3 + eslint: 9.39.1(jiti@1.21.6) + get-tsconfig: 4.13.0 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - eslint: 9.39.0(jiti@1.21.6) + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + eslint: 9.39.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.0(jiti@1.21.6)) + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.39.1(jiti@1.21.6)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -6971,9 +7325,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.0(jiti@1.21.6)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.1(jiti@1.21.6)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -6985,13 +7339,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 7.18.0(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) + '@typescript-eslint/parser': 7.18.0(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.0(jiti@1.21.6)): + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.1(jiti@1.21.6)): dependencies: aria-query: 5.3.2 array-includes: 3.1.8 @@ -7001,7 +7355,7 @@ snapshots: axobject-query: 4.1.0 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) hasown: 2.0.2 jsx-ast-utils: 3.3.5 language-tags: 1.0.9 @@ -7010,11 +7364,11 @@ snapshots: safe-regex-test: 1.0.3 string.prototype.includes: 2.0.1 - eslint-plugin-react-hooks@4.6.2(eslint@9.39.0(jiti@1.21.6)): + eslint-plugin-react-hooks@4.6.2(eslint@9.39.1(jiti@1.21.6)): dependencies: - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) - eslint-plugin-react@7.37.5(eslint@9.39.0(jiti@1.21.6)): + eslint-plugin-react@7.37.5(eslint@9.39.1(jiti@1.21.6)): dependencies: array-includes: 3.1.8 array.prototype.findlast: 1.2.5 @@ -7022,7 +7376,7 @@ snapshots: array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 es-iterator-helpers: 1.2.1 - eslint: 9.39.0(jiti@1.21.6) + eslint: 9.39.1(jiti@1.21.6) estraverse: 5.3.0 hasown: 2.0.2 jsx-ast-utils: 3.3.5 @@ -7045,35 +7399,35 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@9.39.0(jiti@1.21.6): + eslint@9.39.1(jiti@1.21.6): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.0(jiti@1.21.6)) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@1.21.6)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.21.1 '@eslint/config-helpers': 0.4.2 '@eslint/core': 0.17.0 '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.0 + '@eslint/js': 9.39.1 '@eslint/plugin-kit': 0.4.1 '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 + '@types/estree': 1.0.6 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.3.7 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - esquery: 1.6.0 + esquery: 1.5.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 8.0.0 find-up: 5.0.0 glob-parent: 6.0.2 - ignore: 5.3.2 + ignore: 5.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 @@ -7092,7 +7446,7 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 4.2.1 - esquery@1.6.0: + esquery@1.5.0: dependencies: estraverse: 5.3.0 @@ -7110,7 +7464,7 @@ snapshots: execa@4.1.0: dependencies: - cross-spawn: 7.0.6 + cross-spawn: 7.0.3 get-stream: 5.2.0 human-signals: 1.1.1 is-stream: 2.0.1 @@ -7122,7 +7476,7 @@ snapshots: execa@8.0.1: dependencies: - cross-spawn: 7.0.6 + cross-spawn: 7.0.3 get-stream: 8.0.1 human-signals: 5.0.0 is-stream: 3.0.0 @@ -7138,13 +7492,13 @@ snapshots: fast-deep-equal@3.1.3: {} - fast-glob@3.3.3: + fast-glob@3.3.2: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.8 + micromatch: 4.0.7 fast-json-parse@1.0.3: {} @@ -7158,7 +7512,7 @@ snapshots: fastq@1.17.1: dependencies: - reusify: 1.1.0 + reusify: 1.0.4 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -7176,9 +7530,10 @@ snapshots: dependencies: to-regex-range: 5.0.1 - find-babel-config@2.1.2: + find-babel-config@2.1.1: dependencies: json5: 2.2.3 + path-exists: 4.0.0 find-up@3.0.0: dependencies: @@ -7191,14 +7546,14 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.3.1 keyv: 4.5.4 flatbuffers@1.12.0: {} flatbuffers@22.10.26: {} - flatted@3.3.3: {} + flatted@3.3.1: {} for-each@0.3.3: dependencies: @@ -7208,9 +7563,9 @@ snapshots: dependencies: is-callable: 1.2.7 - foreground-child@3.3.1: + foreground-child@3.2.1: dependencies: - cross-spawn: 7.0.6 + cross-spawn: 7.0.3 signal-exit: 4.1.0 form-data-encoder@2.1.4: {} @@ -7220,7 +7575,7 @@ snapshots: fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.1.0 universalify: 2.0.1 fs.realpath@1.0.0: {} @@ -7252,7 +7607,14 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.3.1: {} + get-east-asian-width@1.2.0: {} + + get-intrinsic@1.2.1: + dependencies: + function-bind: 1.1.2 + has: 1.0.3 + has-proto: 1.0.3 + has-symbols: 1.0.3 get-intrinsic@1.2.4: dependencies: @@ -7300,7 +7662,7 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.10.1: + get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -7312,13 +7674,12 @@ snapshots: dependencies: is-glob: 4.0.3 - glob@10.4.5: + glob@10.4.1: dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 + foreground-child: 3.2.1 + jackspeak: 3.4.0 + minimatch: 9.0.4 minipass: 7.1.2 - package-json-from-dist: 1.0.1 path-scurry: 1.11.1 glob@9.3.5: @@ -7328,9 +7689,11 @@ snapshots: minipass: 4.2.8 path-scurry: 1.11.1 + globals@11.12.0: {} + globals@14.0.0: {} - globals@15.15.0: {} + globals@15.10.0: {} globalthis@1.0.4: dependencies: @@ -7341,8 +7704,8 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 + fast-glob: 3.3.2 + ignore: 5.3.1 merge2: 1.4.1 slash: 3.0.0 @@ -7376,22 +7739,22 @@ snapshots: graphemer@1.4.0: {} - graphql-tag@2.12.6(graphql@15.10.1): + graphql-tag@2.12.6(graphql@15.9.0): dependencies: - graphql: 15.10.1 - tslib: 2.8.1 + graphql: 15.9.0 + tslib: 2.6.3 - graphql@15.10.1: {} + graphql@15.9.0: {} has-bigints@1.0.2: {} - has-bigints@1.1.0: {} + has-flag@3.0.0: {} has-flag@4.0.0: {} has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.1 + es-define-property: 1.0.0 has-proto@1.0.3: {} @@ -7405,19 +7768,23 @@ snapshots: has-tostringtag@1.0.0: dependencies: - has-symbols: 1.1.0 + has-symbols: 1.0.3 has-tostringtag@1.0.2: dependencies: - has-symbols: 1.1.0 + has-symbols: 1.0.3 + + has@1.0.3: + dependencies: + function-bind: 1.1.2 hasown@2.0.2: dependencies: function-bind: 1.1.2 - hast-util-to-jsx-runtime@2.3.6: + hast-util-to-jsx-runtime@2.3.2: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.6 '@types/hast': 3.0.4 '@types/unist': 3.0.3 comma-separated-tokens: 2.0.3 @@ -7425,13 +7792,13 @@ snapshots: estree-util-is-identifier-name: 3.0.0 hast-util-whitespace: 3.0.0 mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdx-jsx: 3.1.3 mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 + property-information: 6.5.0 space-separated-tokens: 2.0.2 - style-to-js: 1.1.17 + style-to-object: 1.0.8 unist-util-position: 5.0.0 - vfile-message: 4.0.3 + vfile-message: 4.0.2 transitivePeerDependencies: - supports-color @@ -7441,7 +7808,7 @@ snapshots: highlight.js@10.7.3: {} - hls.js@1.6.11: {} + hls.js@1.5.17: {} hoist-non-react-statics@3.3.2: dependencies: @@ -7449,7 +7816,7 @@ snapshots: html-url-attributes@3.0.1: {} - http-cache-semantics@4.2.0: {} + http-cache-semantics@4.1.1: {} http2-client@1.3.5: {} @@ -7461,7 +7828,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.3.7 transitivePeerDependencies: - supports-color @@ -7469,13 +7836,13 @@ snapshots: human-signals@5.0.0: {} - husky@9.1.7: {} + husky@9.1.6: {} hyphenate-style-name@1.1.0: {} ieee754@1.2.1: {} - ignore@5.3.2: {} + ignore@5.3.1: {} ignore@7.0.5: {} @@ -7484,46 +7851,45 @@ snapshots: immer@10.1.1: optional: true - immutable@5.1.3: {} + immutable@4.3.6: {} - import-fresh@3.3.1: + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 imurmurhash@0.1.4: {} - indent-string@5.0.0: {} + indent-string@4.0.0: {} - ink@5.2.1(@types/react@18.3.24)(react@18.3.1): + ink@3.2.0(@types/react@18.3.11)(react@18.3.1): dependencies: - '@alcalzone/ansi-tokenize': 0.1.3 - ansi-escapes: 7.0.0 - ansi-styles: 6.2.1 - auto-bind: 5.0.1 - chalk: 5.6.0 - cli-boxes: 3.0.0 - cli-cursor: 4.0.0 - cli-truncate: 4.0.0 - code-excerpt: 4.0.0 - es-toolkit: 1.39.10 - indent-string: 5.0.0 - is-in-ci: 1.0.0 - patch-console: 2.0.0 + ansi-escapes: 4.3.2 + auto-bind: 4.0.0 + chalk: 4.1.2 + cli-boxes: 2.2.1 + cli-cursor: 3.1.0 + cli-truncate: 2.1.0 + code-excerpt: 3.0.0 + indent-string: 4.0.0 + is-ci: 2.0.0 + lodash: 4.17.21 + patch-console: 1.0.0 react: 18.3.1 - react-reconciler: 0.29.2(react@18.3.1) - scheduler: 0.23.2 + react-devtools-core: 4.28.5 + react-reconciler: 0.26.2(react@18.3.1) + scheduler: 0.20.2 signal-exit: 3.0.7 - slice-ansi: 7.1.0 + slice-ansi: 3.0.0 stack-utils: 2.0.6 - string-width: 7.2.0 - type-fest: 4.41.0 - widest-line: 5.0.0 - wrap-ansi: 9.0.0 - ws: 8.18.3 - yoga-layout: 3.2.1 + string-width: 4.2.3 + type-fest: 0.12.0 + widest-line: 3.1.0 + wrap-ansi: 6.2.0 + ws: 7.5.10 + yoga-layout-prebuilt: 1.10.0 optionalDependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 transitivePeerDependencies: - bufferutil - utf-8-validate @@ -7534,7 +7900,7 @@ snapshots: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.1.0 + side-channel: 1.0.6 internal-slot@1.1.0: dependencies: @@ -7544,7 +7910,7 @@ snapshots: intl-pluralrules@2.0.1: {} - ip-num@1.5.2: {} + ip-num@1.5.1: {} is-alphabetical@2.0.1: {} @@ -7569,13 +7935,9 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-async-function@2.1.1: + is-async-function@2.0.0: dependencies: - async-function: 1.0.0 - call-bound: 1.0.4 - get-proto: 1.0.1 has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 is-bigint@1.0.4: dependencies: @@ -7583,7 +7945,7 @@ snapshots: is-bigint@1.1.0: dependencies: - has-bigints: 1.1.0 + has-bigints: 1.0.2 is-binary-path@2.1.0: dependencies: @@ -7591,7 +7953,7 @@ snapshots: is-boolean-object@1.1.2: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.2 has-tostringtag: 1.0.0 is-boolean-object@1.2.2: @@ -7601,10 +7963,22 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.2 + semver: 7.7.3 is-callable@1.2.7: {} + is-ci@2.0.0: + dependencies: + ci-info: 2.0.0 + + is-core-module@2.13.1: + dependencies: + hasown: 2.0.2 + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -7634,6 +8008,10 @@ snapshots: is-extglob@2.1.1: {} + is-finalizationregistry@1.0.2: + dependencies: + call-bind: 1.0.8 + is-finalizationregistry@1.1.1: dependencies: call-bound: 1.0.4 @@ -7642,16 +8020,13 @@ snapshots: is-fullwidth-code-point@4.0.0: {} - is-fullwidth-code-point@5.1.0: + is-fullwidth-code-point@5.0.0: dependencies: - get-east-asian-width: 1.3.1 + get-east-asian-width: 1.2.0 - is-generator-function@1.1.0: + is-generator-function@1.0.10: dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 is-glob@4.0.3: dependencies: @@ -7659,8 +8034,6 @@ snapshots: is-hexadecimal@2.0.1: {} - is-in-ci@1.0.0: {} - is-map@2.0.3: {} is-negative-zero@2.0.3: {} @@ -7717,7 +8090,7 @@ snapshots: is-symbol@1.0.4: dependencies: - has-symbols: 1.1.0 + has-symbols: 1.0.3 is-symbol@1.1.1: dependencies: @@ -7759,20 +8132,18 @@ snapshots: iterator.prototype@1.1.5: dependencies: define-data-property: 1.1.4 - es-object-atoms: 1.1.1 + es-object-atoms: 1.0.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 has-symbols: 1.1.0 set-function-name: 2.0.2 - its-fine@1.2.5(@types/react@18.3.24)(react@18.3.1): + its-fine@1.2.5(react@18.3.1): dependencies: - '@types/react-reconciler': 0.28.9(@types/react@18.3.24) + '@types/react-reconciler': 0.28.8 react: 18.3.1 - transitivePeerDependencies: - - '@types/react' - jackspeak@3.4.3: + jackspeak@3.4.0: dependencies: '@isaacs/cliui': 8.0.2 optionalDependencies: @@ -7780,11 +8151,9 @@ snapshots: jiti@1.21.6: {} - jotai@2.13.1(@babel/core@7.28.4)(@babel/template@7.27.2)(@types/react@18.3.24)(react@18.3.1): + jotai@2.12.2(@types/react@18.3.11)(react@18.3.1): optionalDependencies: - '@babel/core': 7.28.4 - '@babel/template': 7.27.2 - '@types/react': 18.3.24 + '@types/react': 18.3.11 react: 18.3.1 js-tokens@4.0.0: {} @@ -7793,7 +8162,9 @@ snapshots: dependencies: argparse: 2.0.1 - jsesc@3.1.0: {} + jsesc@2.5.2: {} + + jsesc@3.0.2: {} json-buffer@3.0.1: {} @@ -7809,7 +8180,7 @@ snapshots: json5@2.2.3: {} - jsonfile@6.2.0: + jsonfile@6.1.0: dependencies: universalify: 2.0.1 optionalDependencies: @@ -7843,26 +8214,28 @@ snapshots: dependencies: immediate: 3.0.6 - lilconfig@3.1.3: {} + lilconfig@2.1.0: {} + + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} - lint-staged@15.5.2: + lint-staged@15.2.10: dependencies: - chalk: 5.6.0 - commander: 13.1.0 - debug: 4.4.1 + chalk: 5.3.0 + commander: 12.1.0 + debug: 4.3.7 execa: 8.0.1 - lilconfig: 3.1.3 - listr2: 8.3.3 + lilconfig: 3.1.2 + listr2: 8.2.5 micromatch: 4.0.8 pidtree: 0.6.0 string-argv: 0.3.2 - yaml: 2.8.1 + yaml: 2.5.1 transitivePeerDependencies: - supports-color - listr2@8.3.3: + listr2@8.2.5: dependencies: cli-truncate: 4.0.0 colorette: 2.0.20 @@ -7904,20 +8277,20 @@ snapshots: lowercase-keys@3.0.0: {} - lru-cache@10.4.3: {} + lru-cache@10.2.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - maath@0.10.8(@types/three@0.163.0)(three@0.163.0): + maath@0.10.7(@types/three@0.163.0)(three@0.163.0): dependencies: '@types/three': 0.163.0 three: 0.163.0 magic-string@0.30.8: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.4.15 make-error@1.3.6: {} @@ -8021,7 +8394,7 @@ snapshots: transitivePeerDependencies: - supports-color - mdast-util-mdx-jsx@3.2.0: + mdast-util-mdx-jsx@3.1.3: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 @@ -8031,10 +8404,10 @@ snapshots: devlop: 1.1.0 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 - parse-entities: 4.0.2 + parse-entities: 4.0.1 stringify-entities: 4.0.4 unist-util-stringify-position: 4.0.0 - vfile-message: 4.0.3 + vfile-message: 4.0.2 transitivePeerDependencies: - supports-color @@ -8058,9 +8431,9 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 + '@ungap/structured-clone': 1.2.0 devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 + micromark-util-sanitize-uri: 2.0.0 trim-lines: 3.0.1 unist-util-position: 5.0.0 unist-util-visit: 5.0.0 @@ -8109,7 +8482,7 @@ snapshots: micromark-util-resolve-all: 2.0.0 micromark-util-subtokenize: 2.0.1 micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 micromark-extension-gfm-autolink-literal@2.1.0: dependencies: @@ -8171,45 +8544,40 @@ snapshots: micromark-factory-destination@2.0.0: dependencies: - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 micromark-factory-label@2.0.0: dependencies: devlop: 1.1.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 micromark-factory-space@2.0.0: dependencies: micromark-util-character: 2.1.0 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 micromark-factory-title@2.0.0: dependencies: micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 micromark-factory-whitespace@2.0.0: dependencies: micromark-factory-space: 2.0.0 - micromark-util-character: 2.1.1 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-character: 2.1.0 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 micromark-util-character@2.1.0: dependencies: micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.2 - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 micromark-util-chunked@2.0.0: dependencies: @@ -8219,7 +8587,7 @@ snapshots: dependencies: micromark-util-character: 2.1.0 micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 micromark-util-combine-extensions@2.0.0: dependencies: @@ -8239,8 +8607,6 @@ snapshots: micromark-util-encode@2.0.0: {} - micromark-util-encode@2.0.1: {} - micromark-util-html-tag-name@2.0.0: {} micromark-util-normalize-identifier@2.0.0: @@ -8249,7 +8615,7 @@ snapshots: micromark-util-resolve-all@2.0.0: dependencies: - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 micromark-util-sanitize-uri@2.0.0: dependencies: @@ -8257,31 +8623,21 @@ snapshots: micromark-util-encode: 2.0.0 micromark-util-symbol: 2.0.0 - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - micromark-util-subtokenize@2.0.1: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.0 - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 + micromark-util-symbol: 2.0.0 + micromark-util-types: 2.0.0 micromark-util-symbol@2.0.0: {} - micromark-util-symbol@2.0.1: {} - micromark-util-types@2.0.0: {} - micromark-util-types@2.0.2: {} - micromark@4.0.0: dependencies: '@types/debug': 4.1.12 - debug: 4.4.3 + debug: 4.3.7 decode-named-character-reference: 1.0.2 devlop: 1.1.0 micromark-core-commonmark: 2.0.1 @@ -8293,10 +8649,10 @@ snapshots: micromark-util-encode: 2.0.0 micromark-util-normalize-identifier: 2.0.0 micromark-util-resolve-all: 2.0.0 - micromark-util-sanitize-uri: 2.0.1 + micromark-util-sanitize-uri: 2.0.0 micromark-util-subtokenize: 2.0.1 micromark-util-symbol: 2.0.0 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 transitivePeerDependencies: - supports-color @@ -8304,7 +8660,6 @@ snapshots: dependencies: braces: 3.0.3 picomatch: 2.3.1 - optional: true micromatch@4.0.8: dependencies: @@ -8329,11 +8684,11 @@ snapshots: minimatch@8.0.4: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.0.1 - minimatch@9.0.5: + minimatch@9.0.4: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.0.1 minimist@1.2.8: {} @@ -8341,6 +8696,8 @@ snapshots: minipass@7.1.2: {} + ms@2.1.2: {} + ms@2.1.3: {} mz@2.7.0: @@ -8349,14 +8706,13 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.11: {} + nanoid@3.3.7: {} - napi-postinstall@0.3.3: {} + napi-postinstall@0.3.4: {} natural-compare@1.4.0: {} - node-addon-api@7.1.1: - optional: true + node-addon-api@7.1.1: {} node-fetch-h2@2.3.0: dependencies: @@ -8370,13 +8726,15 @@ snapshots: dependencies: es6-promise: 3.3.1 - node-releases@2.0.19: {} + node-releases@2.0.14: {} + + node-releases@2.0.18: {} normalize-path@3.0.0: {} normalize-range@0.1.2: {} - normalize-url@8.0.2: {} + normalize-url@8.0.1: {} npm-run-path@4.0.1: dependencies: @@ -8485,7 +8843,7 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.0.0 objectorarray@1.0.5: {} @@ -8515,12 +8873,12 @@ snapshots: dependencies: yaml: 1.10.2 - optimism@0.18.1: + optimism@0.18.0: dependencies: '@wry/caches': 1.0.1 '@wry/context': 0.7.4 - '@wry/trie': 0.5.0 - tslib: 2.8.1 + '@wry/trie': 0.4.3 + tslib: 2.6.3 optionator@0.9.4: dependencies: @@ -8557,18 +8915,17 @@ snapshots: p-try@2.2.0: {} - package-json-from-dist@1.0.1: {} - parent-module@1.0.1: dependencies: callsites: 3.1.0 - parse-entities@4.0.2: + parse-entities@4.0.1: dependencies: '@types/unist': 2.0.11 + character-entities: 2.0.2 character-entities-legacy: 3.0.0 character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.0.2 is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 @@ -8581,7 +8938,7 @@ snapshots: parse5@6.0.1: {} - patch-console@2.0.0: {} + patch-console@1.0.0: {} path-exists@3.0.0: {} @@ -8595,13 +8952,15 @@ snapshots: path-scurry@1.11.1: dependencies: - lru-cache: 10.4.3 + lru-cache: 10.2.2 minipass: 7.1.2 path-type@4.0.0: {} pegjs@0.10.0: {} + picocolors@1.0.1: {} + picocolors@1.1.1: {} picomatch@2.3.1: {} @@ -8612,7 +8971,7 @@ snapshots: pify@2.3.0: {} - pirates@4.0.7: {} + pirates@4.0.6: {} pkg-up@3.1.0: dependencies: @@ -8622,48 +8981,52 @@ snapshots: possible-typed-array-names@1.0.0: {} - possible-typed-array-names@1.1.0: {} - - postcss-import@15.1.0(postcss@8.5.6): + postcss-import@15.1.0(postcss@8.4.38): dependencies: - postcss: 8.5.6 + postcss: 8.4.38 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.8 - postcss-js@4.0.1(postcss@8.5.6): + postcss-js@4.0.1(postcss@8.4.38): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.6 + postcss: 8.4.38 - postcss-load-config@4.0.2(postcss@8.5.6)(ts-node@9.1.1(typescript@5.9.2)): + postcss-load-config@4.0.2(postcss@8.4.38)(ts-node@9.1.1(typescript@5.6.3)): dependencies: - lilconfig: 3.1.3 - yaml: 2.8.1 + lilconfig: 3.1.2 + yaml: 2.4.5 optionalDependencies: - postcss: 8.5.6 - ts-node: 9.1.1(typescript@5.9.2) + postcss: 8.4.38 + ts-node: 9.1.1(typescript@5.6.3) - postcss-nested@6.2.0(postcss@8.5.6): + postcss-nested@6.0.1(postcss@8.4.38): dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.1.2 + postcss: 8.4.38 + postcss-selector-parser: 6.1.0 postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@6.1.2: + postcss-selector-parser@6.1.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 postcss-value-parser@4.2.0: {} - postcss@8.5.6: + postcss@8.4.38: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.7 + picocolors: 1.0.1 + source-map-js: 1.2.0 + + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -8671,7 +9034,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.6.2: {} + prettier@3.3.3: {} progress@2.0.3: {} @@ -8693,7 +9056,7 @@ snapshots: property-expr@2.0.6: {} - property-information@7.1.0: {} + property-information@6.5.0: {} proxy-from-env@1.1.0: {} @@ -8713,15 +9076,23 @@ snapshots: prop-types: 15.8.1 react: 18.3.1 + react-devtools-core@4.28.5: + dependencies: + shell-quote: 1.8.1 + ws: 7.5.10 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 react: 18.3.1 scheduler: 0.23.2 - react-error-boundary@4.1.2(react@18.3.1): + react-error-boundary@4.0.13(react@18.3.1): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.24.7 react: 18.3.1 react-fast-compare@3.2.2: {} @@ -8734,7 +9105,7 @@ snapshots: react-fast-compare: 3.2.2 react-side-effect: 2.1.2(react@18.3.1) - react-hook-form@7.65.0(react@18.3.1): + react-hook-form@7.66.0(react@18.3.1): dependencies: react: 18.3.1 @@ -8742,25 +9113,24 @@ snapshots: react-lifecycles-compat@3.0.4: {} - react-markdown@9.1.0(@types/react@18.3.24)(react@18.3.1): + react-markdown@9.0.1(@types/react@18.3.11)(react@18.3.1): dependencies: '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@types/react': 18.3.24 + '@types/react': 18.3.11 devlop: 1.1.0 - hast-util-to-jsx-runtime: 2.3.6 + hast-util-to-jsx-runtime: 2.3.2 html-url-attributes: 3.0.1 mdast-util-to-hast: 13.2.0 react: 18.3.1 remark-parse: 11.0.0 - remark-rehype: 11.1.2 + remark-rehype: 11.1.1 unified: 11.0.5 unist-util-visit: 5.0.0 vfile: 6.0.3 transitivePeerDependencies: - supports-color - react-modal@3.16.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-modal@3.16.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: exenv: 1.2.2 prop-types: 15.8.1 @@ -8769,21 +9139,22 @@ snapshots: react-lifecycles-compat: 3.0.4 warning: 4.0.3 + react-reconciler@0.26.2(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react: 18.3.1 + scheduler: 0.20.2 + react-reconciler@0.27.0(react@18.3.1): dependencies: loose-envify: 1.4.0 react: 18.3.1 scheduler: 0.21.0 - react-reconciler@0.29.2(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + react-refresh@0.14.2: {} - react-refresh@0.17.0: {} - - react-responsive@10.0.1(react@18.3.1): + react-responsive@10.0.0(react@18.3.1): dependencies: hyphenate-style-name: 1.1.0 matchmediaquery: 0.4.2 @@ -8791,28 +9162,22 @@ snapshots: react: 18.3.1 shallow-equal: 3.1.0 - react-router-dom@6.30.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + react-router-dom@6.27.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@remix-run/router': 1.23.0 + '@remix-run/router': 1.20.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - react-router: 6.30.1(react@18.3.1) + react-router: 6.27.0(react@18.3.1) - react-router@6.30.1(react@18.3.1): + react-router@6.27.0(react@18.3.1): dependencies: - '@remix-run/router': 1.23.0 + '@remix-run/router': 1.20.0 react: 18.3.1 react-side-effect@2.1.2(react@18.3.1): dependencies: react: 18.3.1 - react-use-measure@2.1.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - react@18.3.1: dependencies: loose-envify: 1.4.0 @@ -8838,8 +9203,20 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 + reflect.getprototypeof@1.0.6: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + which-builtin-type: 1.1.3 + reftools@1.1.9: {} + regenerator-runtime@0.14.1: {} + regexp.prototype.flags@1.5.2: dependencies: call-bind: 1.0.7 @@ -8856,12 +9233,12 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - rehackt@0.1.0(@types/react@18.3.24)(react@18.3.1): + rehackt@0.1.0(@types/react@18.3.11)(react@18.3.1): optionalDependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 react: 18.3.1 - remark-gfm@4.0.1: + remark-gfm@4.0.0: dependencies: '@types/mdast': 4.0.4 mdast-util-gfm: 3.0.0 @@ -8876,12 +9253,12 @@ snapshots: dependencies: '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.2 - micromark-util-types: 2.0.2 + micromark-util-types: 2.0.0 unified: 11.0.5 transitivePeerDependencies: - supports-color - remark-rehype@11.1.2: + remark-rehype@11.1.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -8907,29 +9284,25 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.10: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@1.22.8: dependencies: - is-core-module: 2.16.1 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 resolve@2.0.0-next.5: dependencies: - is-core-module: 2.16.1 + is-core-module: 2.15.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 + response-iterator@0.2.6: {} + responselike@3.0.0: dependencies: lowercase-keys: 3.0.0 - restore-cursor@4.0.0: + restore-cursor@3.1.0: dependencies: onetime: 5.1.2 signal-exit: 3.0.7 @@ -8939,53 +9312,48 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - reusify@1.1.0: {} + reusify@1.0.4: {} rfdc@1.4.1: {} - rollup-plugin-visualizer@5.14.0(rollup@4.50.0): + rollup-plugin-visualizer@5.12.0(rollup@4.24.0): dependencies: open: 8.4.2 - picomatch: 4.0.3 - source-map: 0.7.6 + picomatch: 2.3.1 + source-map: 0.7.4 yargs: 17.7.2 optionalDependencies: - rollup: 4.50.0 + rollup: 4.24.0 - rollup@4.50.0: + rollup@4.24.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.6 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.50.0 - '@rollup/rollup-android-arm64': 4.50.0 - '@rollup/rollup-darwin-arm64': 4.50.0 - '@rollup/rollup-darwin-x64': 4.50.0 - '@rollup/rollup-freebsd-arm64': 4.50.0 - '@rollup/rollup-freebsd-x64': 4.50.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.50.0 - '@rollup/rollup-linux-arm-musleabihf': 4.50.0 - '@rollup/rollup-linux-arm64-gnu': 4.50.0 - '@rollup/rollup-linux-arm64-musl': 4.50.0 - '@rollup/rollup-linux-loongarch64-gnu': 4.50.0 - '@rollup/rollup-linux-ppc64-gnu': 4.50.0 - '@rollup/rollup-linux-riscv64-gnu': 4.50.0 - '@rollup/rollup-linux-riscv64-musl': 4.50.0 - '@rollup/rollup-linux-s390x-gnu': 4.50.0 - '@rollup/rollup-linux-x64-gnu': 4.50.0 - '@rollup/rollup-linux-x64-musl': 4.50.0 - '@rollup/rollup-openharmony-arm64': 4.50.0 - '@rollup/rollup-win32-arm64-msvc': 4.50.0 - '@rollup/rollup-win32-ia32-msvc': 4.50.0 - '@rollup/rollup-win32-x64-msvc': 4.50.0 + '@rollup/rollup-android-arm-eabi': 4.24.0 + '@rollup/rollup-android-arm64': 4.24.0 + '@rollup/rollup-darwin-arm64': 4.24.0 + '@rollup/rollup-darwin-x64': 4.24.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.24.0 + '@rollup/rollup-linux-arm-musleabihf': 4.24.0 + '@rollup/rollup-linux-arm64-gnu': 4.24.0 + '@rollup/rollup-linux-arm64-musl': 4.24.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 + '@rollup/rollup-linux-riscv64-gnu': 4.24.0 + '@rollup/rollup-linux-s390x-gnu': 4.24.0 + '@rollup/rollup-linux-x64-gnu': 4.24.0 + '@rollup/rollup-linux-x64-musl': 4.24.0 + '@rollup/rollup-win32-arm64-msvc': 4.24.0 + '@rollup/rollup-win32-ia32-msvc': 4.24.0 + '@rollup/rollup-win32-x64-msvc': 4.24.0 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.2: + rxjs@7.8.1: dependencies: - tslib: 2.8.1 + tslib: 2.6.3 safe-array-concat@1.1.2: dependencies: @@ -9019,13 +9387,17 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - sass@1.92.0: + sass@1.80.2: dependencies: - chokidar: 4.0.1 - immutable: 5.1.3 - source-map-js: 1.2.0 - optionalDependencies: '@parcel/watcher': 2.4.1 + chokidar: 4.0.1 + immutable: 4.3.6 + source-map-js: 1.2.0 + + scheduler@0.20.2: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 scheduler@0.21.0: dependencies: @@ -9037,7 +9409,9 @@ snapshots: semver@6.3.1: {} - semver@7.7.2: {} + semver@7.6.3: {} + + semver@7.7.3: {} set-function-length@1.2.2: dependencies: @@ -9045,7 +9419,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 get-intrinsic: 1.2.4 - gopd: 1.2.0 + gopd: 1.0.1 has-property-descriptors: 1.0.2 set-function-name@2.0.2: @@ -9069,6 +9443,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.1: {} + should-equal@2.0.0: dependencies: should-type: 1.4.0 @@ -9140,6 +9516,12 @@ snapshots: slash@4.0.0: {} + slice-ansi@3.0.0: + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + slice-ansi@5.0.0: dependencies: ansi-styles: 6.2.1 @@ -9148,7 +9530,7 @@ snapshots: slice-ansi@7.1.0: dependencies: ansi-styles: 6.2.1 - is-fullwidth-code-point: 5.1.0 + is-fullwidth-code-point: 5.0.0 source-map-js@1.2.0: {} @@ -9161,7 +9543,7 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.6: {} + source-map@0.7.4: {} space-separated-tokens@2.0.2: {} @@ -9176,9 +9558,9 @@ snapshots: spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.22 + spdx-license-ids: 3.0.18 - spdx-license-ids@3.0.22: {} + spdx-license-ids@3.0.18: {} spdx-ranges@2.1.1: {} @@ -9194,16 +9576,15 @@ snapshots: dependencies: escape-string-regexp: 2.0.0 - stats-gl@2.4.2(@types/three@0.163.0)(three@0.163.0): + stats-gl@2.2.8: dependencies: '@types/three': 0.163.0 - three: 0.163.0 stats.js@0.17.0: {} stop-iteration-iterator@1.0.0: dependencies: - internal-slot: 1.1.0 + internal-slot: 1.0.7 stop-iteration-iterator@1.1.0: dependencies: @@ -9224,10 +9605,10 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 - string-width@7.2.0: + string-width@7.1.0: dependencies: - emoji-regex: 10.5.0 - get-east-asian-width: 1.3.1 + emoji-regex: 10.3.0 + get-east-asian-width: 1.2.0 strip-ansi: 7.1.0 string.prototype.includes@2.0.1: @@ -9243,7 +9624,7 @@ snapshots: define-properties: 1.2.1 es-abstract: 1.24.0 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.0.0 get-intrinsic: 1.3.0 gopd: 1.2.0 has-symbols: 1.1.0 @@ -9279,13 +9660,13 @@ snapshots: call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.0.0 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 stringify-entities@4.0.4: dependencies: @@ -9298,7 +9679,7 @@ snapshots: strip-ansi@7.1.0: dependencies: - ansi-regex: 6.2.0 + ansi-regex: 6.0.1 strip-bom@3.0.0: {} @@ -9308,24 +9689,24 @@ snapshots: strip-json-comments@3.1.1: {} - style-to-js@1.1.17: - dependencies: - style-to-object: 1.0.9 - - style-to-object@1.0.9: + style-to-object@1.0.8: dependencies: inline-style-parser: 0.2.4 sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 - glob: 10.4.5 + glob: 10.4.1 lines-and-columns: 1.2.4 mz: 2.7.0 - pirates: 4.0.7 + pirates: 4.0.6 ts-interface-checker: 0.1.13 + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -9356,36 +9737,36 @@ snapshots: tailwind-gradient-mask-image@1.2.0: {} - tailwindcss@3.4.17(ts-node@9.1.1(typescript@5.9.2)): + tailwindcss@3.4.14(ts-node@9.1.1(typescript@5.6.3)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.3.3 + fast-glob: 3.3.2 glob-parent: 6.0.2 is-glob: 4.0.3 jiti: 1.21.6 - lilconfig: 3.1.3 - micromatch: 4.0.8 + lilconfig: 2.1.0 + micromatch: 4.0.7 normalize-path: 3.0.0 object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.0.1(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6)(ts-node@9.1.1(typescript@5.9.2)) - postcss-nested: 6.2.0(postcss@8.5.6) - postcss-selector-parser: 6.1.2 - resolve: 1.22.10 + picocolors: 1.0.1 + postcss: 8.4.38 + postcss-import: 15.1.0(postcss@8.4.38) + postcss-js: 4.0.1(postcss@8.4.38) + postcss-load-config: 4.0.2(postcss@8.4.38)(ts-node@9.1.1(typescript@5.6.3)) + postcss-nested: 6.0.1(postcss@8.4.38) + postcss-selector-parser: 6.1.0 + resolve: 1.22.8 sucrase: 3.35.0 transitivePeerDependencies: - ts-node terser@5.31.1: dependencies: - '@jridgewell/source-map': 0.3.11 + '@jridgewell/source-map': 0.3.6 acorn: 8.15.0 commander: 2.20.3 source-map-support: 0.5.21 @@ -9403,11 +9784,11 @@ snapshots: dependencies: three: 0.163.0 - three-stdlib@2.36.0(three@0.163.0): + three-stdlib@2.30.3(three@0.163.0): dependencies: '@types/draco3d': 1.4.10 '@types/offscreencanvas': 2019.7.3 - '@types/webxr': 0.5.23 + '@types/webxr': 0.5.16 draco3d: 1.5.7 fflate: 0.6.10 potpack: 1.0.2 @@ -9419,11 +9800,13 @@ snapshots: tinycolor2@1.6.0: {} - tinyglobby@0.2.14: + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 + to-fast-properties@2.0.0: {} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -9434,35 +9817,35 @@ snapshots: trim-lines@3.0.1: {} - troika-three-text@0.52.4(three@0.163.0): + troika-three-text@0.49.1(three@0.163.0): dependencies: bidi-js: 1.0.3 three: 0.163.0 - troika-three-utils: 0.52.4(three@0.163.0) - troika-worker-utils: 0.52.0 + troika-three-utils: 0.49.0(three@0.163.0) + troika-worker-utils: 0.49.0 webgl-sdf-generator: 1.1.1 - troika-three-utils@0.52.4(three@0.163.0): + troika-three-utils@0.49.0(three@0.163.0): dependencies: three: 0.163.0 - troika-worker-utils@0.52.0: {} + troika-worker-utils@0.49.0: {} trough@2.2.0: {} - ts-api-utils@1.4.3(typescript@5.9.2): + ts-api-utils@1.3.0(typescript@5.6.3): dependencies: - typescript: 5.9.2 + typescript: 5.6.3 - ts-api-utils@2.1.0(typescript@5.9.2): + ts-api-utils@2.1.0(typescript@5.6.3): dependencies: - typescript: 5.9.2 + typescript: 5.6.3 ts-interface-checker@0.1.13: {} ts-invariant@0.10.3: dependencies: - tslib: 2.8.1 + tslib: 2.6.3 ts-node@9.1.1(typescript@4.8.4): dependencies: @@ -9474,18 +9857,18 @@ snapshots: typescript: 4.8.4 yn: 3.1.1 - ts-node@9.1.1(typescript@5.9.2): + ts-node@9.1.1(typescript@5.6.3): dependencies: arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 source-map-support: 0.5.21 - typescript: 5.9.2 + typescript: 5.6.3 yn: 3.1.1 optional: true - ts-pattern@5.8.0: {} + ts-pattern@5.5.0: {} tsconfig-paths@3.15.0: dependencies: @@ -9496,16 +9879,16 @@ snapshots: tslib@1.14.1: {} - tslib@2.8.1: {} + tslib@2.6.3: {} tsutils@3.21.0(typescript@4.8.2): dependencies: tslib: 1.14.1 typescript: 4.8.2 - tunnel-rat@0.1.2(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1): + tunnel-rat@0.1.2(@types/react@18.3.11)(immer@10.1.1)(react@18.3.1): dependencies: - zustand: 4.5.7(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1) + zustand: 4.5.2(@types/react@18.3.11)(immer@10.1.1)(react@18.3.1) transitivePeerDependencies: - '@types/react' - immer @@ -9517,9 +9900,11 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@2.19.0: {} + type-fest@0.12.0: {} - type-fest@4.41.0: {} + type-fest@0.21.3: {} + + type-fest@2.19.0: {} typed-array-buffer@1.0.2: dependencies: @@ -9544,7 +9929,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: call-bind: 1.0.8 - for-each: 0.3.5 + for-each: 0.3.3 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 @@ -9562,7 +9947,7 @@ snapshots: dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 - for-each: 0.3.5 + for-each: 0.3.3 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 @@ -9580,20 +9965,20 @@ snapshots: typed-array-length@1.0.7: dependencies: call-bind: 1.0.8 - for-each: 0.3.5 + for-each: 0.3.3 gopd: 1.2.0 is-typed-array: 1.1.15 - possible-typed-array-names: 1.1.0 - reflect.getprototypeof: 1.0.10 + possible-typed-array-names: 1.0.0 + reflect.getprototypeof: 1.0.6 - typescript-eslint@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2): + typescript-eslint@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2))(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/parser': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.2) - '@typescript-eslint/utils': 8.46.2(eslint@9.39.0(jiti@1.21.6))(typescript@5.9.2) - eslint: 9.39.0(jiti@1.21.6) - typescript: 5.9.2 + '@typescript-eslint/eslint-plugin': 8.46.4(@typescript-eslint/parser@8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3))(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/parser': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + '@typescript-eslint/typescript-estree': 8.46.4(typescript@5.6.3) + '@typescript-eslint/utils': 8.46.4(eslint@9.39.1(jiti@1.21.6))(typescript@5.6.3) + eslint: 9.39.1(jiti@1.21.6) + typescript: 5.6.3 transitivePeerDependencies: - supports-color @@ -9601,7 +9986,7 @@ snapshots: typescript@4.8.4: {} - typescript@5.9.2: {} + typescript@5.6.3: {} unbox-primitive@1.0.2: dependencies: @@ -9613,11 +9998,11 @@ snapshots: unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 - has-bigints: 1.1.0 + has-bigints: 1.0.2 has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.10.0: {} + undici-types@7.16.0: {} unified@11.0.5: dependencies: @@ -9656,14 +10041,14 @@ snapshots: unplugin@1.0.1: dependencies: - acorn: 8.15.0 + acorn: 8.12.0 chokidar: 3.6.0 - webpack-sources: 3.3.3 + webpack-sources: 3.2.3 webpack-virtual-modules: 0.5.0 unrs-resolver@1.11.1: dependencies: - napi-postinstall: 0.3.3 + napi-postinstall: 0.3.4 optionalDependencies: '@unrs/resolver-binding-android-arm-eabi': 1.11.1 '@unrs/resolver-binding-android-arm64': 1.11.1 @@ -9685,9 +10070,15 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - update-browserslist-db@1.1.3(browserslist@4.25.4): + update-browserslist-db@1.0.16(browserslist@4.23.1): dependencies: - browserslist: 4.25.4 + browserslist: 4.23.1 + escalade: 3.1.2 + picocolors: 1.0.1 + + update-browserslist-db@1.1.1(browserslist@4.24.0): + dependencies: + browserslist: 4.24.0 escalade: 3.2.0 picocolors: 1.1.1 @@ -9695,11 +10086,11 @@ snapshots: dependencies: punycode: 2.3.1 - use-double-tap@1.3.7(react@18.3.1): + use-double-tap@1.3.6(react@18.3.1): dependencies: react: 18.3.1 - use-sync-external-store@1.5.0(react@18.3.1): + use-sync-external-store@1.2.0(react@18.3.1): dependencies: react: 18.3.1 @@ -9707,7 +10098,9 @@ snapshots: utility-types@3.11.0: {} - vfile-message@4.0.3: + uuid@9.0.1: {} + + vfile-message@4.0.2: dependencies: '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 @@ -9715,17 +10108,17 @@ snapshots: vfile@6.0.3: dependencies: '@types/unist': 3.0.3 - vfile-message: 4.0.3 + vfile-message: 4.0.2 - vite@5.4.19(@types/node@24.3.1)(sass@1.92.0)(terser@5.31.1): + vite@5.4.9(@types/node@24.10.0)(sass@1.80.2)(terser@5.31.1): dependencies: esbuild: 0.21.5 - postcss: 8.5.6 - rollup: 4.50.0 + postcss: 8.4.47 + rollup: 4.24.0 optionalDependencies: - '@types/node': 24.3.1 + '@types/node': 24.10.0 fsevents: 2.3.3 - sass: 1.92.0 + sass: 1.80.2 terser: 5.31.1 warning@4.0.3: @@ -9738,7 +10131,7 @@ snapshots: webidl-conversions@3.0.1: {} - webpack-sources@3.3.3: {} + webpack-sources@3.2.3: {} webpack-virtual-modules@0.5.0: {} @@ -9763,15 +10156,30 @@ snapshots: is-string: 1.1.1 is-symbol: 1.1.1 + which-builtin-type@1.1.3: + dependencies: + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.19 + which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.1.1 + is-async-function: 2.0.0 is-date-object: 1.1.0 is-finalizationregistry: 1.1.1 - is-generator-function: 1.1.0 + is-generator-function: 1.0.10 is-regex: 1.2.1 is-weakref: 1.1.1 isarray: 2.0.5 @@ -9808,12 +10216,18 @@ snapshots: dependencies: isexe: 2.0.0 - widest-line@5.0.0: + widest-line@3.1.0: dependencies: - string-width: 7.2.0 + string-width: 4.2.3 word-wrap@1.2.5: {} + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 @@ -9829,12 +10243,12 @@ snapshots: wrap-ansi@9.0.0: dependencies: ansi-styles: 6.2.1 - string-width: 7.2.0 + string-width: 7.1.0 strip-ansi: 7.1.0 wrappy@1.0.2: {} - ws@8.18.3: {} + ws@7.5.10: {} y18n@5.0.8: {} @@ -9842,7 +10256,9 @@ snapshots: yaml@1.10.2: {} - yaml@2.8.1: {} + yaml@2.4.5: {} + + yaml@2.5.1: {} yargs-parser@20.2.9: {} @@ -9861,7 +10277,7 @@ snapshots: yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.2.0 + escalade: 3.1.2 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 @@ -9872,9 +10288,11 @@ snapshots: yocto-queue@0.1.0: {} - yoga-layout@3.2.1: {} + yoga-layout-prebuilt@1.10.0: + dependencies: + '@types/yoga-layout': 1.9.2 - yup@1.7.0: + yup@1.4.0: dependencies: property-expr: 2.0.6 tiny-case: 1.0.3 @@ -9891,19 +10309,12 @@ snapshots: optionalDependencies: react: 18.3.1 - zustand@4.5.7(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1): + zustand@4.5.2(@types/react@18.3.11)(immer@10.1.1)(react@18.3.1): dependencies: - use-sync-external-store: 1.5.0(react@18.3.1) + use-sync-external-store: 1.2.0(react@18.3.1) optionalDependencies: - '@types/react': 18.3.24 + '@types/react': 18.3.11 immer: 10.1.1 react: 18.3.1 - zustand@5.0.8(@types/react@18.3.24)(immer@10.1.1)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)): - optionalDependencies: - '@types/react': 18.3.24 - immer: 10.1.1 - react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) - zwitch@2.0.4: {} diff --git a/server/core/src/main/java/dev/slimevr/NetworkProfileChecker.kt b/server/core/src/main/java/dev/slimevr/NetworkProfileChecker.kt new file mode 100644 index 000000000..4c6e77b0a --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/NetworkProfileChecker.kt @@ -0,0 +1,59 @@ +package dev.slimevr + +data class NetworkInfo( + val name: String?, + val description: String?, + val category: NetworkCategory?, + val connectivity: Set?, + val connected: Boolean?, +) + +/** + * @see NLM_NETWORK_CATEGORY enumeration (netlistmgr.h) + */ +enum class NetworkCategory(val value: Int) { + PUBLIC(0), + PRIVATE(1), + DOMAIN_AUTHENTICATED(2), + ; + + companion object { + fun fromInt(value: Int) = values().find { it.value == value } + } +} + +/** + * @see NLM_CONNECTIVITY enumeration (netlistmgr.h) + */ +enum class ConnectivityFlags(val value: Int) { + DISCONNECTED(0), + IPV4_NOTRAFFIC(0x1), + IPV6_NOTRAFFIC(0x2), + IPV4_SUBNET(0x10), + IPV4_LOCALNETWORK(0x20), + IPV4_INTERNET(0x40), + IPV6_SUBNET(0x100), + IPV6_LOCALNETWORK(0x200), + IPV6_INTERNET(0x400), + ; + + companion object { + fun fromInt(value: Int): Set = if (value == 0) { + setOf(DISCONNECTED) + } else { + values().filter { it != DISCONNECTED && (value and it.value) != 0 }.toSet() + } + } +} + +abstract class NetworkProfileChecker { + abstract val isSupported: Boolean + abstract val publicNetworks: List +} + +class NetworkProfileCheckerStub : NetworkProfileChecker() { + override val isSupported: Boolean + get() = false + override val publicNetworks: List + get() = listOf() +} diff --git a/server/core/src/main/java/dev/slimevr/VRServer.kt b/server/core/src/main/java/dev/slimevr/VRServer.kt index 519ebf9e6..0112b4ccc 100644 --- a/server/core/src/main/java/dev/slimevr/VRServer.kt +++ b/server/core/src/main/java/dev/slimevr/VRServer.kt @@ -18,6 +18,8 @@ import dev.slimevr.posestreamer.BVHRecorder import dev.slimevr.protocol.ProtocolAPI import dev.slimevr.protocol.rpc.settings.RPCSettingsHandler import dev.slimevr.reset.ResetHandler +import dev.slimevr.reset.ResetTimerManager +import dev.slimevr.reset.resetTimer import dev.slimevr.serial.ProvisioningHandler import dev.slimevr.serial.SerialHandler import dev.slimevr.serial.SerialHandlerStub @@ -28,6 +30,7 @@ import dev.slimevr.tracking.processor.HumanPoseManager import dev.slimevr.tracking.processor.skeleton.HumanSkeleton import dev.slimevr.tracking.trackers.* import dev.slimevr.tracking.trackers.udp.TrackersUDPServer +import dev.slimevr.trackingchecklist.TrackingChecklistManager import dev.slimevr.util.ann.VRServerThread import dev.slimevr.websocketapi.WebSocketVRBridge import io.eiren.util.ann.ThreadSafe @@ -55,6 +58,7 @@ class VRServer @JvmOverloads constructor( serialHandlerProvider: (VRServer) -> SerialHandler = { _ -> SerialHandlerStub() }, flashingHandlerProvider: (VRServer) -> SerialFlashingHandler? = { _ -> null }, vrcConfigHandlerProvider: (VRServer) -> VRCConfigHandler = { _ -> VRCConfigHandlerStub() }, + networkProfileProvider: (VRServer) -> NetworkProfileChecker = { _ -> NetworkProfileCheckerStub() }, acquireMulticastLock: () -> Any? = { null }, @JvmField val configManager: ConfigManager, ) : Thread("VRServer") { @@ -99,6 +103,7 @@ class VRServer @JvmOverloads constructor( @JvmField val protocolAPI: ProtocolAPI private val timer = Timer() + private val resetTimerManager = ResetTimerManager() val fpsTimer = NanoTimer() @JvmField @@ -113,6 +118,10 @@ class VRServer @JvmOverloads constructor( @JvmField val handshakeHandler = HandshakeHandler() + val trackingChecklistManager: TrackingChecklistManager + + val networkProfileChecker: NetworkProfileChecker + init { // UwU deviceManager = DeviceManager(this) @@ -126,6 +135,8 @@ class VRServer @JvmOverloads constructor( autoBoneHandler = AutoBoneHandler(this) firmwareUpdateHandler = FirmwareUpdateHandler(this) vrcConfigManager = VRChatConfigManager(this, vrcConfigHandlerProvider(this)) + networkProfileChecker = networkProfileProvider(this) + trackingChecklistManager = TrackingChecklistManager(this) protocolAPI = ProtocolAPI(this) val computedTrackers = humanPoseManager.computedTrackers @@ -164,6 +175,7 @@ class VRServer @JvmOverloads constructor( for (tracker in computedTrackers) { registerTracker(tracker) } + instance = this } @@ -300,7 +312,7 @@ class VRServer @JvmOverloads constructor( queueTask { humanPoseManager.resetTrackersYaw(resetSourceName, bodyParts) } } - fun resetTrackersMounting(resetSourceName: String?, bodyParts: List = TrackerUtils.allBodyPartsButFingers) { + fun resetTrackersMounting(resetSourceName: String?, bodyParts: List? = null) { queueTask { humanPoseManager.resetTrackersMounting(resetSourceName, bodyParts) } } @@ -330,40 +342,52 @@ class VRServer @JvmOverloads constructor( } } - fun scheduleResetTrackersFull(resetSourceName: String?, delay: Long) { - if (delay > 0) { - resetHandler.sendStarted(ResetType.Full) - } - timer.schedule(delay) { - queueTask { - humanPoseManager.resetTrackersFull(resetSourceName) - resetHandler.sendFinished(ResetType.Full) - } - } + fun scheduleResetTrackersFull(resetSourceName: String?, delay: Long, bodyParts: List = ArrayList()) { + resetTimer( + resetTimerManager, + delay, + onTick = { progress -> + resetHandler.sendStarted(ResetType.Full, bodyParts, progress, delay.toInt()) + }, + onComplete = { + queueTask { + humanPoseManager.resetTrackersFull(resetSourceName, bodyParts) + resetHandler.sendFinished(ResetType.Full, bodyParts, delay.toInt()) + } + }, + ) } - fun scheduleResetTrackersYaw(resetSourceName: String?, delay: Long) { - if (delay > 0) { - resetHandler.sendStarted(ResetType.Yaw) - } - timer.schedule(delay) { - queueTask { - humanPoseManager.resetTrackersYaw(resetSourceName) - resetHandler.sendFinished(ResetType.Yaw) - } - } + fun scheduleResetTrackersYaw(resetSourceName: String?, delay: Long, bodyParts: List = TrackerUtils.allBodyPartsButFingers) { + resetTimer( + resetTimerManager, + delay, + onTick = { progress -> + resetHandler.sendStarted(ResetType.Yaw, bodyParts, progress, delay.toInt()) + }, + onComplete = { + queueTask { + humanPoseManager.resetTrackersYaw(resetSourceName, bodyParts) + resetHandler.sendFinished(ResetType.Yaw, bodyParts, delay.toInt()) + } + }, + ) } - fun scheduleResetTrackersMounting(resetSourceName: String?, delay: Long) { - if (delay > 0) { - resetHandler.sendStarted(ResetType.Mounting) - } - timer.schedule(delay) { - queueTask { - humanPoseManager.resetTrackersMounting(resetSourceName) - resetHandler.sendFinished(ResetType.Mounting) - } - } + fun scheduleResetTrackersMounting(resetSourceName: String?, delay: Long, bodyParts: List? = null) { + resetTimer( + resetTimerManager, + delay, + onTick = { progress -> + resetHandler.sendStarted(ResetType.Mounting, bodyParts, progress, delay.toInt()) + }, + onComplete = { + queueTask { + humanPoseManager.resetTrackersMounting(resetSourceName, bodyParts) + resetHandler.sendFinished(ResetType.Mounting, bodyParts, delay.toInt()) + } + }, + ) } fun scheduleSetPauseTracking(pauseTracking: Boolean, sourceName: String?, delay: Long) { diff --git a/server/core/src/main/java/dev/slimevr/bridge/Bridge.kt b/server/core/src/main/java/dev/slimevr/bridge/Bridge.kt index ca869e367..5750b53b3 100644 --- a/server/core/src/main/java/dev/slimevr/bridge/Bridge.kt +++ b/server/core/src/main/java/dev/slimevr/bridge/Bridge.kt @@ -53,4 +53,6 @@ interface ISteamVRBridge : Bridge { fun getAutomaticSharedTrackers(): Boolean fun setAutomaticSharedTrackers(value: Boolean) + + fun getBridgeConfigKey(): String } diff --git a/server/core/src/main/java/dev/slimevr/config/ResetsConfig.kt b/server/core/src/main/java/dev/slimevr/config/ResetsConfig.kt index ce33bddd8..65cc761d8 100644 --- a/server/core/src/main/java/dev/slimevr/config/ResetsConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/ResetsConfig.kt @@ -29,6 +29,24 @@ enum class ArmsResetModes(val id: Int) { } } +enum class MountingMethods(val id: Int) { + MANUAL(0), + AUTOMATIC(1), + ; + + companion object { + val values = MountingMethods.entries.toTypedArray() + + @JvmStatic + fun fromId(id: Int): MountingMethods? { + for (filter in values) { + if (filter.id == id) return filter + } + return null + } + } +} + class ResetsConfig { // Always reset mounting for feet @@ -46,6 +64,12 @@ class ResetsConfig { // Reset the HMD's pitch upon full reset var resetHmdPitch = false + var lastMountingMethod = MountingMethods.AUTOMATIC + + var yawResetDelay = 0.0f + var fullResetDelay = 3.0f + var mountingResetDelay = 3.0f + fun updateTrackersResetsSettings() { for (t in VRServer.instance.allTrackers) { t.resetsHandler.readResetConfig(this) diff --git a/server/core/src/main/java/dev/slimevr/config/TapDetectionConfig.kt b/server/core/src/main/java/dev/slimevr/config/TapDetectionConfig.kt index 721addd0b..0e5a83cde 100644 --- a/server/core/src/main/java/dev/slimevr/config/TapDetectionConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/TapDetectionConfig.kt @@ -14,20 +14,16 @@ class TapDetectionConfig { var mountingResetEnabled = true var setupMode = false var yawResetTaps = 2 - // clamp to 2-3 to prevent errors set(yawResetTaps) { - field = FastMath.clamp(yawResetTaps.toFloat(), 2f, 10f).toInt() - field = yawResetTaps + field = yawResetTaps.coerceIn(2, 10) } var fullResetTaps = 3 set(fullResetTaps) { - field = FastMath.clamp(fullResetTaps.toFloat(), 2f, 10f).toInt() - field = fullResetTaps + field = fullResetTaps.coerceIn(2, 10) } var mountingResetTaps = 3 set(mountingResetTaps) { - field = FastMath.clamp(mountingResetTaps.toFloat(), 2f, 10f).toInt() - field = mountingResetTaps + field = mountingResetTaps.coerceIn(2, 10) } var numberTrackersOverThreshold = 1 } diff --git a/server/core/src/main/java/dev/slimevr/config/TrackingChecklistConfig.kt b/server/core/src/main/java/dev/slimevr/config/TrackingChecklistConfig.kt new file mode 100644 index 000000000..182a97bff --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/config/TrackingChecklistConfig.kt @@ -0,0 +1,5 @@ +package dev.slimevr.config + +class TrackingChecklistConfig { + val ignoredStepsIds: MutableList = mutableListOf() +} diff --git a/server/core/src/main/java/dev/slimevr/config/VRCConfig.kt b/server/core/src/main/java/dev/slimevr/config/VRCConfig.kt new file mode 100644 index 000000000..fd40b13dd --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/config/VRCConfig.kt @@ -0,0 +1,6 @@ +package dev.slimevr.config + +class VRCConfig { + // List of fields ignored in vrc warnings - @see VRCConfigValidity + val mutedWarnings: MutableList = mutableListOf() +} diff --git a/server/core/src/main/java/dev/slimevr/config/VRConfig.kt b/server/core/src/main/java/dev/slimevr/config/VRConfig.kt index de6bc9319..0a01a4d42 100644 --- a/server/core/src/main/java/dev/slimevr/config/VRConfig.kt +++ b/server/core/src/main/java/dev/slimevr/config/VRConfig.kt @@ -54,6 +54,10 @@ class VRConfig { val overlay: OverlayConfig = OverlayConfig() + val trackingChecklist: TrackingChecklistConfig = TrackingChecklistConfig() + + val vrcConfig: VRCConfig = VRCConfig() + init { // Initialize default settings for OSC Router oscRouter.portIn = 9002 @@ -104,7 +108,7 @@ class VRConfig { tracker.readConfig(config) if (tracker.isImu()) tracker.resetsHandler.readDriftCompensationConfig(driftCompensation) tracker.resetsHandler.readResetConfig(resetsConfig) - if (tracker.needsReset) { + if (tracker.allowReset) { tracker.saveMountingResetOrientation(config) } if (tracker.allowFiltering) { diff --git a/server/core/src/main/java/dev/slimevr/games/vrchat/VRCConfigHandler.kt b/server/core/src/main/java/dev/slimevr/games/vrchat/VRCConfigHandler.kt index 8e54d5de8..fc2829e80 100644 --- a/server/core/src/main/java/dev/slimevr/games/vrchat/VRCConfigHandler.kt +++ b/server/core/src/main/java/dev/slimevr/games/vrchat/VRCConfigHandler.kt @@ -78,11 +78,11 @@ data class VRCConfigValidity( val shoulderTrackingOk: Boolean, val shoulderWidthCompensationOk: Boolean, val userHeightOk: Boolean, - val calibrationOk: Boolean, + val calibrationRangeOk: Boolean, val calibrationVisualsOk: Boolean, - val tackerModelOk: Boolean, + val trackerModelOk: Boolean, val spineModeOk: Boolean, - val avatarMeasurementOk: Boolean, + val avatarMeasurementTypeOk: Boolean, ) abstract class VRCConfigHandler { @@ -98,13 +98,14 @@ class VRCConfigHandlerStub : VRCConfigHandler() { } interface VRCConfigListener { - fun onChange(validity: VRCConfigValidity, values: VRCConfigValues, recommended: VRCConfigRecommendedValues) + fun onChange(validity: VRCConfigValidity, values: VRCConfigValues, recommended: VRCConfigRecommendedValues, muted: List) } class VRChatConfigManager(val server: VRServer, private val handler: VRCConfigHandler) { private val listeners: MutableList = CopyOnWriteArrayList() var currentValues: VRCConfigValues? = null + var currentValidity: VRCConfigValidity? = null val isSupported: Boolean get() = handler.isSupported @@ -113,6 +114,31 @@ class VRChatConfigManager(val server: VRServer, private val handler: VRCConfigHa handler.initHandler(::onChange) } + fun toggleMuteWarning(key: String) { + val keys = VRCConfigValidity::class.java.declaredFields.asSequence().map { p -> p.name } + if (!keys.contains(key)) return + + if (!server.configManager.vrConfig.vrcConfig.mutedWarnings.contains(key)) { + server.configManager.vrConfig.vrcConfig.mutedWarnings.add(key) + } else { + server.configManager.vrConfig.vrcConfig.mutedWarnings.remove(key) + } + + server.configManager.saveConfig() + + val recommended = recommendedValues() + val validity = currentValidity ?: return + val values = currentValues ?: return + listeners.forEach { + it.onChange( + validity, + values, + recommended, + server.configManager.vrConfig.vrcConfig.mutedWarnings, + ) + } + } + /** * shoulderTrackingDisabled should be true if: * The user isn't tracking their whole arms from their controllers: @@ -160,20 +186,28 @@ class VRChatConfigManager(val server: VRServer, private val handler: VRCConfigHa legacyModeOk = values.legacyMode == recommended.legacyMode, shoulderTrackingOk = values.shoulderTrackingDisabled == recommended.shoulderTrackingDisabled, spineModeOk = recommended.spineMode.contains(values.spineMode), - tackerModelOk = values.trackerModel == recommended.trackerModel, - calibrationOk = abs(values.calibrationRange - recommended.calibrationRange) < 0.1, + trackerModelOk = values.trackerModel == recommended.trackerModel, + calibrationRangeOk = abs(values.calibrationRange - recommended.calibrationRange) < 0.1, userHeightOk = abs(server.humanPoseManager.realUserHeight - values.userHeight) < 0.1, calibrationVisualsOk = values.calibrationVisuals == recommended.calibrationVisuals, - avatarMeasurementOk = values.avatarMeasurementType == recommended.avatarMeasurementType, + avatarMeasurementTypeOk = values.avatarMeasurementType == recommended.avatarMeasurementType, shoulderWidthCompensationOk = values.shoulderWidthCompensation == recommended.shoulderWidthCompensation, ) + fun forceUpdate() { + val values = currentValues + if (values != null) { + this.onChange(values) + } + } + fun onChange(values: VRCConfigValues) { val recommended = recommendedValues() val validity = checkValidity(values, recommended) + currentValidity = validity currentValues = values listeners.forEach { - it.onChange(validity, values, recommended) + it.onChange(validity, values, recommended, server.configManager.vrConfig.vrcConfig.mutedWarnings) } } } diff --git a/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt b/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt index 775f305e7..52b40325e 100644 --- a/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/osc/VMCHandler.kt @@ -290,7 +290,7 @@ class VMCHandler( userEditable = true, isComputed = position != null, usesTimeout = true, - needsReset = position != null, + allowReset = position != null, ) trackerDevice!!.trackers[trackerDevice!!.trackers.size] = tracker byTrackerNameTracker[name] = tracker diff --git a/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt b/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt index abfbaa379..17c0459fd 100644 --- a/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/osc/VRCOSCHandler.kt @@ -275,7 +275,7 @@ class VRCOSCHandler( hasPosition = true, userEditable = true, isComputed = true, - needsReset = trackerPosition != TrackerPosition.HEAD, + allowReset = trackerPosition != TrackerPosition.HEAD, usesTimeout = true, ) vrsystemTrackersDevice!!.trackers[trackerPosition.ordinal] = tracker @@ -368,7 +368,7 @@ class VRCOSCHandler( hasPosition = true, userEditable = true, isComputed = true, - needsReset = true, + allowReset = true, usesTimeout = true, ) oscTrackersDevice!!.trackers[trackerId] = tracker diff --git a/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java b/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java index b2efbd0ab..3c256ff2f 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java +++ b/server/core/src/main/java/dev/slimevr/protocol/datafeed/DataFeedBuilder.java @@ -141,7 +141,7 @@ public class DataFeedBuilder { TrackerInfo.addAllowDriftCompensation(fbb, false); } - if (tracker.getNeedsMounting()) { + if (tracker.getAllowMounting()) { Quaternion quaternion = tracker.getResetsHandler().getMountingOrientation(); Quaternion mountResetFix = tracker.getResetsHandler().getMountRotFix(); TrackerInfo.addMountingOrientation(fbb, createQuat(fbb, quaternion)); @@ -215,7 +215,7 @@ public class DataFeedBuilder { if (trackerTemperatureOffset != 0) TrackerData.addTemp(fbb, trackerTemperatureOffset); } - if (tracker.getNeedsMounting() && tracker.getHasRotation()) { + if (tracker.getAllowMounting() && tracker.getHasRotation()) { if (mask.getRotationReferenceAdjusted()) { TrackerData .addRotationReferenceAdjusted(fbb, createQuat(fbb, tracker.getRotation())); @@ -227,7 +227,7 @@ public class DataFeedBuilder { createQuat(fbb, tracker.getIdentityAdjustedRotation()) ); } - } else if (tracker.getNeedsReset() && tracker.getHasRotation()) { + } else if (tracker.getAllowReset() && tracker.getHasRotation()) { if (mask.getRotationReferenceAdjusted()) { TrackerData .addRotationReferenceAdjusted(fbb, createQuat(fbb, tracker.getRotation())); diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt index ffb90ab08..873befeaf 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/RPCHandler.kt @@ -1,6 +1,7 @@ package dev.slimevr.protocol.rpc import com.google.flatbuffers.FlatBufferBuilder +import dev.slimevr.config.MountingMethods import dev.slimevr.config.config import dev.slimevr.protocol.GenericConnection import dev.slimevr.protocol.ProtocolAPI @@ -18,6 +19,7 @@ import dev.slimevr.protocol.rpc.setup.RPCHandshakeHandler import dev.slimevr.protocol.rpc.setup.RPCTapSetupHandler import dev.slimevr.protocol.rpc.setup.RPCUtil.getLocalIp import dev.slimevr.protocol.rpc.status.RPCStatusHandler +import dev.slimevr.protocol.rpc.trackingchecklist.RPCTrackingChecklistHandler import dev.slimevr.protocol.rpc.trackingpause.RPCTrackingPause import dev.slimevr.tracking.processor.config.SkeletonConfigOffsets import dev.slimevr.tracking.processor.stayaligned.poses.RelaxedPose @@ -48,184 +50,104 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler - this.onResetRequest( - conn, - messageHeader, - ) - } - registerPacketListener( - RpcMessage.ClearMountingResetRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onClearMountingResetRequest( - conn, - messageHeader, - ) - } registerPacketListener( RpcMessage.AssignTrackerRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onAssignTrackerRequest( - conn, - messageHeader, - ) - } + ::onAssignTrackerRequest, + ) registerPacketListener( RpcMessage.ClearDriftCompensationRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onClearDriftCompensationRequest( - conn, - messageHeader, - ) - } + ::onClearDriftCompensationRequest, + ) registerPacketListener( RpcMessage.RecordBVHRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onRecordBVHRequest( - conn, - messageHeader, - ) - } + ::onRecordBVHRequest, + ) registerPacketListener( RpcMessage.RecordBVHStatusRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onBVHStatusRequest( - conn, - messageHeader, - ) - } + ::onBVHStatusRequest, + ) registerPacketListener( RpcMessage.SkeletonResetAllRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onSkeletonResetAllRequest( - conn, - messageHeader, - ) - } + ::onSkeletonResetAllRequest, + ) registerPacketListener( RpcMessage.SkeletonConfigRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onSkeletonConfigRequest( - conn, - messageHeader, - ) - } + ::onSkeletonConfigRequest, + ) registerPacketListener( RpcMessage.ChangeSkeletonConfigRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onChangeSkeletonConfigRequest( - conn, - messageHeader, - ) - } + ::onChangeSkeletonConfigRequest, + ) registerPacketListener( RpcMessage.OverlayDisplayModeChangeRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onOverlayDisplayModeChangeRequest( - conn, - messageHeader, - ) - } + ::onOverlayDisplayModeChangeRequest, + ) registerPacketListener( RpcMessage.OverlayDisplayModeRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onOverlayDisplayModeRequest( - conn, - messageHeader, - ) - } + ::onOverlayDisplayModeRequest, + ) registerPacketListener( RpcMessage.ServerInfosRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onServerInfosRequest( - conn, - messageHeader, - ) - } + ::onServerInfosRequest, + ) registerPacketListener( RpcMessage.LegTweaksTmpChange, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onLegTweaksTmpChange( - conn, - messageHeader, - ) - } + ::onLegTweaksTmpChange, + ) registerPacketListener( RpcMessage.LegTweaksTmpClear, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onLegTweaksTmpClear( - conn, - messageHeader, - ) - } + ::onLegTweaksTmpClear, + ) registerPacketListener( RpcMessage.StatusSystemRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onStatusSystemRequest( - conn, - messageHeader, - ) - } + ::onStatusSystemRequest, + ) registerPacketListener( RpcMessage.SetPauseTrackingRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onSetPauseTrackingRequest( - conn, - messageHeader, - ) - } + ::onSetPauseTrackingRequest, + ) registerPacketListener( RpcMessage.HeightRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onHeightRequest( - conn, - messageHeader, - ) - } + ::onHeightRequest, + ) registerPacketListener( RpcMessage.MagToggleRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onMagToggleRequest(conn, messageHeader) - } + ::onMagToggleRequest, + ) registerPacketListener( RpcMessage.ChangeMagToggleRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onChangeMagToggleRequest(conn, messageHeader) - } + ::onChangeMagToggleRequest, + ) registerPacketListener( RpcMessage.EnableStayAlignedRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onEnableStayAlignedRequest(conn, messageHeader) - } + ::onEnableStayAlignedRequest, + ) registerPacketListener( RpcMessage.DetectStayAlignedRelaxedPoseRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onDetectStayAlignedRelaxedPoseRequest(conn, messageHeader) - } + ::onDetectStayAlignedRelaxedPoseRequest, + ) registerPacketListener( RpcMessage.ResetStayAlignedRelaxedPoseRequest, - ) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onResetStayAlignedRelaxedPoseRequest(conn, messageHeader) - } + ::onResetStayAlignedRelaxedPoseRequest, + ) } private fun onServerInfosRequest( @@ -347,55 +269,6 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler() - if (req.bodyPartsLength() > 0) { - val buffer = req.bodyPartsAsByteBuffer() - while (buffer.hasRemaining()) { - bodyParts.add(buffer.get().toInt()) - } - } - - if (req.resetType() == ResetType.Yaw) { - if (bodyParts.isEmpty()) { - api.server.resetTrackersYaw(RESET_SOURCE_NAME) - } else { - api.server.resetTrackersYaw(RESET_SOURCE_NAME, bodyParts.toList()) - } - } - if (req.resetType() == ResetType.Full) { - if (bodyParts.isEmpty()) { - api.server.resetTrackersFull(RESET_SOURCE_NAME) - } else { - api.server.resetTrackersFull(RESET_SOURCE_NAME, bodyParts.toList()) - } - } - if (req.resetType() == ResetType.Mounting) { - if (bodyParts.isEmpty()) { - api.server.resetTrackersMounting(RESET_SOURCE_NAME) - } else { - api.server.resetTrackersMounting(RESET_SOURCE_NAME, bodyParts.toList()) - } - } - } - - fun onClearMountingResetRequest( - conn: GenericConnection, - messageHeader: RpcMessageHeader, - ) { - if (messageHeader - .message(ClearMountingResetRequest()) !is ClearMountingResetRequest - ) { - return - } - - api.server.clearTrackersMounting(RESET_SOURCE_NAME) - } - fun onAssignTrackerRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { val req = messageHeader .message(AssignTrackerRequest()) as? AssignTrackerRequest ?: return @@ -415,7 +288,7 @@ class RPCHandler(private val api: ProtocolAPI) : ProtocolHandler, ): Int { if (!isSupported) { VRCConfigStateChangeResponse.startVRCConfigStateChangeResponse(fbb) @@ -71,11 +72,13 @@ fun buildVRCConfigStateResponse( val validityOffset = buildVRCConfigValidity(fbb, validity) val valuesOffset = buildVRCConfigValues(fbb, values) val recommendedOffset = buildVRCConfigRecommendedValues(fbb, recommended) + val mutedOffset = VRCConfigStateChangeResponse.createMutedVector(fbb, muted.map { fbb.createString(it) }.toIntArray()) VRCConfigStateChangeResponse.startVRCConfigStateChangeResponse(fbb) VRCConfigStateChangeResponse.addIsSupported(fbb, true) VRCConfigStateChangeResponse.addValidity(fbb, validityOffset) VRCConfigStateChangeResponse.addState(fbb, valuesOffset) VRCConfigStateChangeResponse.addRecommended(fbb, recommendedOffset) + VRCConfigStateChangeResponse.addMuted(fbb, mutedOffset) return VRCConfigStateChangeResponse.endVRCConfigStateChangeResponse(fbb) } diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/games/vrchat/RPCVRChatHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/games/vrchat/RPCVRChatHandler.kt index 2d4bd9277..481e918d3 100644 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/games/vrchat/RPCVRChatHandler.kt +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/games/vrchat/RPCVRChatHandler.kt @@ -18,12 +18,8 @@ class RPCVRChatHandler( init { api.server.vrcConfigManager.addListener(this) - rpcHandler.registerPacketListener(RpcMessage.VRCConfigStateRequest) { conn: GenericConnection, messageHeader: RpcMessageHeader -> - this.onConfigStateRequest( - conn, - messageHeader, - ) - } + rpcHandler.registerPacketListener(RpcMessage.VRCConfigStateRequest, ::onConfigStateRequest) + rpcHandler.registerPacketListener(RpcMessage.VRCConfigSettingToggleMute, ::onToggleMuteRequest) } private fun onConfigStateRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { @@ -41,6 +37,7 @@ class RPCVRChatHandler( validity = validity, values = values, recommended = api.server.vrcConfigManager.recommendedValues(), + muted = api.server.configManager.vrConfig.vrcConfig.mutedWarnings, ) val outbound = rpcHandler.createRPCMessage( @@ -52,7 +49,13 @@ class RPCVRChatHandler( conn.send(fbb.dataBuffer()) } - override fun onChange(validity: VRCConfigValidity, values: VRCConfigValues, recommended: VRCConfigRecommendedValues) { + private fun onToggleMuteRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { + val req = messageHeader.message(VRCConfigSettingToggleMute()) as VRCConfigSettingToggleMute? + ?: return + api.server.vrcConfigManager.toggleMuteWarning(req.key()) + } + + override fun onChange(validity: VRCConfigValidity, values: VRCConfigValues, recommended: VRCConfigRecommendedValues, muted: List) { val fbb = FlatBufferBuilder(32) val response = buildVRCConfigStateResponse( @@ -61,6 +64,7 @@ class RPCVRChatHandler( validity = validity, values = values, recommended = recommended, + muted, ) val outbound = rpcHandler.createRPCMessage( diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.java b/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.java deleted file mode 100644 index 9dcb7ffc9..000000000 --- a/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.java +++ /dev/null @@ -1,62 +0,0 @@ -package dev.slimevr.protocol.rpc.reset; - -import java.util.function.Consumer; - -import com.google.flatbuffers.FlatBufferBuilder; - -import dev.slimevr.protocol.GenericConnection; - -import dev.slimevr.protocol.ProtocolAPI; -import dev.slimevr.protocol.rpc.RPCHandler; -import dev.slimevr.reset.ResetListener; -import solarxr_protocol.rpc.ResetResponse; -import solarxr_protocol.rpc.ResetStatus; -import solarxr_protocol.rpc.RpcMessage; - - -public class RPCResetHandler implements ResetListener { - public RPCHandler rpcHandler; - public ProtocolAPI api; - - public RPCResetHandler(RPCHandler rpcHandler, ProtocolAPI api) { - this.rpcHandler = rpcHandler; - this.api = api; - - this.api.server.resetHandler.addListener(this); - } - - public void sendResetStatusResponse(int resetType, int status) { - FlatBufferBuilder fbb = new FlatBufferBuilder(32); - ResetResponse.startResetResponse(fbb); - ResetResponse.addResetType(fbb, resetType); - ResetResponse.addStatus(fbb, status); - int update = ResetResponse.endResetResponse(fbb); - int outbound = rpcHandler.createRPCMessage(fbb, RpcMessage.ResetResponse, update); - fbb.finish(outbound); - - this.forAllListeners((conn) -> { - conn.send(fbb.dataBuffer()); - }); - } - - @Override - public void onStarted(int resetType) { - sendResetStatusResponse(resetType, ResetStatus.STARTED); - } - - @Override - public void onFinished(int resetType) { - sendResetStatusResponse(resetType, ResetStatus.FINISHED); - } - - public void forAllListeners(Consumer action) { - this.api - .getAPIServers() - .forEach( - (server) -> server - .getAPIConnections() - .forEach(action) - ); - } -} - diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.kt new file mode 100644 index 000000000..fd9e598ae --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/reset/RPCResetHandler.kt @@ -0,0 +1,124 @@ +package dev.slimevr.protocol.rpc.reset + +import com.google.flatbuffers.FlatBufferBuilder +import dev.slimevr.protocol.GenericConnection +import dev.slimevr.protocol.ProtocolAPI +import dev.slimevr.protocol.ProtocolAPIServer +import dev.slimevr.protocol.rpc.RPCHandler +import dev.slimevr.reset.ResetListener +import solarxr_protocol.rpc.ClearMountingResetRequest +import solarxr_protocol.rpc.ResetRequest +import solarxr_protocol.rpc.ResetResponse +import solarxr_protocol.rpc.ResetStatus +import solarxr_protocol.rpc.ResetType +import solarxr_protocol.rpc.RpcMessage +import solarxr_protocol.rpc.RpcMessageHeader +import java.util.function.Consumer + +class RPCResetHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) : ResetListener { + val resetsConfig = api.server.configManager.vrConfig.resetsConfig + + init { + this.api.server.resetHandler.addListener(this) + + rpcHandler.registerPacketListener(RpcMessage.ResetRequest, ::onResetRequest) + rpcHandler.registerPacketListener(RpcMessage.ClearMountingResetRequest, ::onClearMountingResetRequest) + } + + fun onResetRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { + val req = messageHeader.message(ResetRequest()) as? ResetRequest ?: return + + // Get the list of bodyparts we want to reset + // If empty, check in HumanSkeleton will reset all + val bodyParts = mutableListOf() + if (req.bodyPartsLength() > 0) { + val buffer = req.bodyPartsAsByteBuffer() + while (buffer.hasRemaining()) { + bodyParts.add(buffer.get().toInt()) + } + } + + if (req.resetType() == ResetType.Yaw) { + if (bodyParts.isEmpty()) { + api.server.scheduleResetTrackersYaw(RESET_SOURCE_NAME, (resetsConfig.yawResetDelay * 1000).toLong()) + } else { + api.server.scheduleResetTrackersYaw(RESET_SOURCE_NAME, (resetsConfig.yawResetDelay * 1000).toLong(), bodyParts.toList()) + } + } + if (req.resetType() == ResetType.Full) { + if (bodyParts.isEmpty()) { + api.server.scheduleResetTrackersFull(RESET_SOURCE_NAME, (resetsConfig.fullResetDelay * 1000).toLong()) + } else { + api.server.scheduleResetTrackersFull(RESET_SOURCE_NAME, (resetsConfig.fullResetDelay * 1000).toLong(), bodyParts.toList()) + } + } + if (req.resetType() == ResetType.Mounting) { + if (bodyParts.isEmpty()) { + api.server.scheduleResetTrackersMounting(RESET_SOURCE_NAME, (resetsConfig.mountingResetDelay * 1000).toLong()) + } else { + api.server.scheduleResetTrackersMounting(RESET_SOURCE_NAME, (resetsConfig.mountingResetDelay * 1000).toLong(), bodyParts.toList()) + } + } + } + + fun sendResetStatusResponse(resetType: Int, status: Int, bodyParts: List? = null, progress: Int = 0, duration: Int = 0) { + val fbb = FlatBufferBuilder(32) + + val bodyPartsOffset = if (bodyParts != null) ResetResponse.createBodyPartsVector(fbb, bodyParts.map { it.toByte() }.toByteArray()) else 0 + + ResetResponse.startResetResponse(fbb) + ResetResponse.addResetType(fbb, resetType) + ResetResponse.addStatus(fbb, status) + if (bodyPartsOffset >= 0) { + ResetResponse.addBodyParts(fbb, bodyPartsOffset) + } + ResetResponse.addProgress(fbb, progress) + ResetResponse.addDuration(fbb, duration) + val update = ResetResponse.endResetResponse(fbb) + val outbound = rpcHandler.createRPCMessage(fbb, RpcMessage.ResetResponse, update) + fbb.finish(outbound) + + this.forAllListeners( + Consumer { conn: GenericConnection -> + conn.send(fbb.dataBuffer()) + }, + ) + } + + fun onClearMountingResetRequest( + conn: GenericConnection, + messageHeader: RpcMessageHeader, + ) { + if (messageHeader + .message(ClearMountingResetRequest()) !is ClearMountingResetRequest + ) { + return + } + + api.server.clearTrackersMounting(RESET_SOURCE_NAME) + } + + override fun onStarted(resetType: Int, bodyParts: List?, progress: Int, duration: Int) { + sendResetStatusResponse(resetType, ResetStatus.STARTED, bodyParts, progress, duration) + } + + override fun onFinished(resetType: Int, bodyParts: List?, duration: Int) { + sendResetStatusResponse(resetType, ResetStatus.FINISHED, bodyParts, duration, duration) + } + + fun forAllListeners(action: Consumer?) { + this.api + .getAPIServers() + .forEach( + Consumer { server: ProtocolAPIServer? -> + server!! + .getAPIConnections() + .forEach(action) + }, + ) + } + + companion object { + const val RESET_SOURCE_NAME = "WebSocketAPI" + } +} diff --git a/server/core/src/main/java/dev/slimevr/protocol/rpc/trackingchecklist/RPCTrackingChecklistHandler.kt b/server/core/src/main/java/dev/slimevr/protocol/rpc/trackingchecklist/RPCTrackingChecklistHandler.kt new file mode 100644 index 000000000..ca6f6b34e --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/protocol/rpc/trackingchecklist/RPCTrackingChecklistHandler.kt @@ -0,0 +1,73 @@ +package dev.slimevr.protocol.rpc.trackingchecklist + +import com.google.flatbuffers.FlatBufferBuilder +import dev.slimevr.protocol.GenericConnection +import dev.slimevr.protocol.ProtocolAPI +import dev.slimevr.protocol.rpc.RPCHandler +import dev.slimevr.trackingchecklist.TrackingChecklistListener +import solarxr_protocol.rpc.* + +class RPCTrackingChecklistHandler( + private val rpcHandler: RPCHandler, + var api: ProtocolAPI, +) : TrackingChecklistListener { + + init { + api.server.trackingChecklistManager.addListener(this) + + rpcHandler.registerPacketListener(RpcMessage.TrackingChecklistRequest, ::onTrackingChecklistRequest) + rpcHandler.registerPacketListener(RpcMessage.IgnoreTrackingChecklistStepRequest, ::onToggleTrackingChecklistRequest) + } + + fun buildTrackingChecklistResponse(fbb: FlatBufferBuilder): Int = TrackingChecklistResponse.pack( + fbb, + TrackingChecklistResponseT().apply { + steps = api.server.trackingChecklistManager.steps.toTypedArray() + ignoredSteps = api.server.configManager.vrConfig.trackingChecklist.ignoredStepsIds.toIntArray() + }, + ) + + private fun onTrackingChecklistRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { + val fbb = FlatBufferBuilder(32) + val response = buildTrackingChecklistResponse(fbb) + val outbound = rpcHandler.createRPCMessage( + fbb, + RpcMessage.TrackingChecklistResponse, + response, + ) + fbb.finish(outbound) + conn.send(fbb.dataBuffer()) + } + + private fun onToggleTrackingChecklistRequest(conn: GenericConnection, messageHeader: RpcMessageHeader) { + val req = messageHeader.message(IgnoreTrackingChecklistStepRequest()) as IgnoreTrackingChecklistStepRequest? + ?: return + val step = api.server.trackingChecklistManager.steps.find { it.id == req.stepId() } ?: error("invalid step id requested") + + api.server.trackingChecklistManager.ignoreStep(step, req.ignore()) + + val fbb = FlatBufferBuilder(32) + val response = buildTrackingChecklistResponse(fbb) + val outbound = rpcHandler.createRPCMessage( + fbb, + RpcMessage.TrackingChecklistResponse, + response, + ) + fbb.finish(outbound) + conn.send(fbb.dataBuffer()) + } + + override fun onStepsUpdate() { + val fbb = FlatBufferBuilder(32) + val response = buildTrackingChecklistResponse(fbb) + val outbound = rpcHandler.createRPCMessage( + fbb, + RpcMessage.TrackingChecklistResponse, + response, + ) + fbb.finish(outbound) + this.api.apiServers.forEach { apiServer -> + apiServer.apiConnections.forEach { it.send(fbb.dataBuffer()) } + } + } +} diff --git a/server/core/src/main/java/dev/slimevr/reset/ResetHandler.java b/server/core/src/main/java/dev/slimevr/reset/ResetHandler.java deleted file mode 100644 index ef28c1090..000000000 --- a/server/core/src/main/java/dev/slimevr/reset/ResetHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.slimevr.reset; - -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - - -public class ResetHandler { - - private final List listeners = new CopyOnWriteArrayList<>(); - - public ResetHandler() { - - } - - public void sendStarted(int resetType) { - this.listeners.forEach((listener) -> listener.onStarted(resetType)); - } - - public void sendFinished(int resetType) { - this.listeners.forEach((listener) -> listener.onFinished(resetType)); - } - - public void addListener(ResetListener listener) { - this.listeners.add(listener); - } - - public void removeListener(ResetListener l) { - listeners.removeIf(listener -> l == listener); - } -} diff --git a/server/core/src/main/java/dev/slimevr/reset/ResetHandler.kt b/server/core/src/main/java/dev/slimevr/reset/ResetHandler.kt new file mode 100644 index 000000000..69a68c6cb --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/reset/ResetHandler.kt @@ -0,0 +1,24 @@ +package dev.slimevr.reset + +import java.util.concurrent.CopyOnWriteArrayList +import java.util.function.Consumer + +class ResetHandler { + private val listeners: MutableList = CopyOnWriteArrayList() + + fun sendStarted(resetType: Int, bodyParts: List? = null, progress: Int = 0, duration: Int = 0) { + this.listeners.forEach { listener: ResetListener -> listener.onStarted(resetType, bodyParts, progress, duration) } + } + + fun sendFinished(resetType: Int, bodyParts: List? = null, duration: Int) { + this.listeners.forEach { listener: ResetListener -> listener.onFinished(resetType, bodyParts, duration) } + } + + fun addListener(listener: ResetListener) { + this.listeners.add(listener) + } + + fun removeListener(l: ResetListener) { + listeners.removeIf { listener: ResetListener -> l === listener } + } +} diff --git a/server/core/src/main/java/dev/slimevr/reset/ResetListener.java b/server/core/src/main/java/dev/slimevr/reset/ResetListener.java deleted file mode 100644 index de3b8ea95..000000000 --- a/server/core/src/main/java/dev/slimevr/reset/ResetListener.java +++ /dev/null @@ -1,8 +0,0 @@ -package dev.slimevr.reset; - -public interface ResetListener { - - void onStarted(int resetType); - - void onFinished(int resetType); -} diff --git a/server/core/src/main/java/dev/slimevr/reset/ResetListener.kt b/server/core/src/main/java/dev/slimevr/reset/ResetListener.kt new file mode 100644 index 000000000..b50fd3a91 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/reset/ResetListener.kt @@ -0,0 +1,7 @@ +package dev.slimevr.reset + +interface ResetListener { + fun onStarted(resetType: Int, bodyParts: List? = null, progress: Int, duration: Int) + + fun onFinished(resetType: Int, bodyParts: List? = null, duration: Int) +} diff --git a/server/core/src/main/java/dev/slimevr/reset/ResetTimer.kt b/server/core/src/main/java/dev/slimevr/reset/ResetTimer.kt new file mode 100644 index 000000000..2734e2af3 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/reset/ResetTimer.kt @@ -0,0 +1,40 @@ +package dev.slimevr.reset + +import java.util.Timer +import java.util.TimerTask +import kotlin.concurrent.schedule +import kotlin.math.floor +import kotlin.math.min + +class ResetTimerManager { + val timer: Timer = Timer() + val timers: ArrayList = arrayListOf() + + fun cancelTimers() { + timers.forEach { it.cancel() } + } +} + +fun resetTimer(resetTimerManager: ResetTimerManager, delay: Long, onTick: (progress: Int) -> Unit, onComplete: () -> Unit) { + resetTimerManager.cancelTimers() + + if (delay == 0L) { + onComplete() + return + } + + val ticks: Int = floor(delay / 1000f).toInt() + for (tick in 0..ticks) { + if (tick * 1000L == delay) continue + resetTimerManager.timers.add( + resetTimerManager.timer.schedule(tick * 1000L) { + onTick(tick * 1000) + }, + ) + } + resetTimerManager.timers.add( + resetTimerManager.timer.schedule(delay) { + onComplete() + }, + ) +} diff --git a/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt b/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt index fe590b6be..bd521f9a8 100644 --- a/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt +++ b/server/core/src/main/java/dev/slimevr/status/StatusSystem.kt @@ -28,36 +28,6 @@ class StatusSystem { status }.toTypedArray() - /** - * @return the ID of the status, 0 is not a valid ID, can be used as replacement of null - */ - @JvmName("addStatusInt") - fun addStatus(statusData: StatusDataUnion, prioritized: Boolean = false): UInt { - val id = idCounter.getAndUpdate { - (it.toUInt() + 1u).toInt() // the simple way of making unsigned math - } - statuses[id] = statusData - if (prioritized) { - prioritizedStatuses.add(id) - } - - listeners.forEach { - it.onStatusChanged(id.toUInt(), statusData, prioritized) - } - - return id.toUInt() - } - - @JvmName("removeStatusInt") - fun removeStatus(id: UInt) { - statuses.remove(id.toInt()) - prioritizedStatuses.remove(id.toInt()) - - listeners.forEach { - it.onStatusRemoved(id) - } - } - fun hasStatusType(dataType: Byte): Boolean = statuses.any { it.value.type == dataType } diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/HumanPoseManager.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/HumanPoseManager.kt index 6d7324249..f1fa12269 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/HumanPoseManager.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/HumanPoseManager.kt @@ -20,11 +20,6 @@ import io.github.axisangles.ktmath.Quaternion.Companion.IDENTITY import io.github.axisangles.ktmath.Vector3 import io.github.axisangles.ktmath.Vector3.Companion.POS_Y import org.apache.commons.math3.util.Precision -import solarxr_protocol.datatypes.DeviceIdT -import solarxr_protocol.datatypes.TrackerIdT -import solarxr_protocol.rpc.StatusData -import solarxr_protocol.rpc.StatusDataUnion -import solarxr_protocol.rpc.StatusUnassignedHMDT import java.util.function.Consumer import kotlin.math.* @@ -526,7 +521,7 @@ class HumanPoseManager(val server: VRServer?) { for (tracker in server!!.allTrackers) { if (( tracker.isImu() && - tracker.needsReset + tracker.allowReset ) && tracker.resetsHandler.lastResetQuaternion != null ) { @@ -574,8 +569,15 @@ class HumanPoseManager(val server: VRServer?) { } @JvmOverloads - fun resetTrackersMounting(resetSourceName: String?, bodyParts: List = TrackerUtils.allBodyPartsButFingers) { - skeleton.resetTrackersMounting(resetSourceName, bodyParts) + fun resetTrackersMounting(resetSourceName: String?, bodyParts: List? = null) { + val finalBodyParts = bodyParts + ?: if (server?.configManager?.vrConfig?.resetsConfig?.resetMountingFeet == true) { + TrackerUtils.allBodyPartsButFingers + } else { + TrackerUtils.allBodyPartsButFingersAndFeets + } + + skeleton.resetTrackersMounting(resetSourceName, finalBodyParts) } fun clearTrackersMounting(resetSourceName: String?) { @@ -677,51 +679,12 @@ class HumanPoseManager(val server: VRServer?) { return } server.allTrackers - .filter { !it.isInternal && it.trackerPosition != null } + .filter { it.trackerPosition != null } .forEach { - it.checkReportRequireReset() - } - } - - private var lastMissingHmdStatus = 0u - fun checkReportMissingHmd() { - // Check if this is main skeleton, there is no head tracker currently, - // and there is an available HMD one - if (server == null) return - val tracker = VRServer.instance.allTrackers.firstOrNull { it.isHmd && !it.isInternal && it.status.sendData } - if (skeleton.headTracker == null && - lastMissingHmdStatus == 0u && - tracker != null - ) { - reportMissingHmd(tracker) - } else if (lastMissingHmdStatus != 0u && - (skeleton.headTracker != null || tracker == null) - ) { - server.statusSystem.removeStatus(lastMissingHmdStatus) - lastMissingHmdStatus = 0u - } - } - - private fun reportMissingHmd(tracker: Tracker) { - require(lastMissingHmdStatus == 0u) { - "${::lastMissingHmdStatus.name} must be 0u, but was $lastMissingHmdStatus" - } - require(server != null) { - "${::server.name} must not be null" - } - - val status = StatusDataUnion().apply { - type = StatusData.StatusUnassignedHMD - value = StatusUnassignedHMDT().apply { - trackerId = TrackerIdT().apply { - if (tracker.device != null) { - deviceId = DeviceIdT().apply { id = tracker.device.id } - } - trackerNum = tracker.trackerNum + if (it.allowReset && !it.needReset) { + it.needReset = true } } - } - lastMissingHmdStatus = server.statusSystem.addStatus(status, true) } // #endregion diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt index 62adbaec4..7cdec98b7 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/config/SkeletonConfigManager.kt @@ -91,6 +91,9 @@ class SkeletonConfigManager( // Re-calculate user height userHeightFromOffsets = calculateUserHeight() userNeckHeightFromOffsets = userHeightFromOffsets - getOffset(SkeletonConfigOffsets.NECK) + + // Update vrc config checker if user height change + humanPoseManager?.server?.vrcConfigManager?.forceUpdate() } fun setOffset(config: SkeletonConfigOffsets, newValue: Float?) { diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt index 9edbbc0e6..865b417bf 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/HumanSkeleton.kt @@ -1,6 +1,7 @@ package dev.slimevr.tracking.processor.skeleton import dev.slimevr.VRServer +import dev.slimevr.config.MountingMethods import dev.slimevr.config.StayAlignedConfig import dev.slimevr.tracking.processor.Bone import dev.slimevr.tracking.processor.BoneType @@ -124,7 +125,6 @@ class HumanSkeleton( var headTracker: Tracker? by Delegates.observable(null) { _, old, new -> if (old == new) return@observable - humanPoseManager.checkReportMissingHmd() humanPoseManager.checkTrackersRequiringReset() } var neckTracker: Tracker? = null @@ -212,7 +212,7 @@ class HumanSkeleton( // Modules var legTweaks = LegTweaks(this) - var tapDetectionManager = TapDetectionManager(this) + var tapDetectionManager: TapDetectionManager? = null var localizer = Localizer(this) var ikSolver = IKSolver(headBone) @@ -232,12 +232,9 @@ class HumanSkeleton( ) : this(humanPoseManager) { setTrackersFromList(server.allTrackers) tapDetectionManager = TapDetectionManager( + server, this, humanPoseManager, - server.configManager.vrConfig.tapDetection, - server.resetHandler, - server.tapSetupHandler, - server.allTrackers, ) legTweaks.setConfig(server.configManager.vrConfig.legTweaks) localizer.setEnabled(humanPoseManager.getToggle(SkeletonConfigToggles.SELF_LOCALIZATION)) @@ -475,7 +472,7 @@ class HumanSkeleton( humanPoseManager.updateNodeOffsetsInSkeleton() // Update tap detection's trackers - tapDetectionManager.updateConfig(trackers) + tapDetectionManager?.refresh() // Rebuild Ik Solver ikSolver.buildChains(trackers) @@ -539,7 +536,7 @@ class HumanSkeleton( */ @VRServerThread fun updatePose() { - tapDetectionManager.update() + tapDetectionManager?.update() StayAligned.adjustNextTracker(trackerSkeleton, stayAlignedConfig) @@ -1556,7 +1553,7 @@ class HumanSkeleton( // Resets all axes of the trackers with the HMD as reference. for (tracker in trackersToReset) { // Only reset if tracker needsReset - if (tracker != null && (tracker.needsReset || tracker.isHmd) && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { + if (tracker != null && (tracker.allowReset || tracker.isHmd) && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { tracker.resetsHandler.resetFull(referenceRotation) } } @@ -1579,16 +1576,16 @@ class HumanSkeleton( var referenceRotation = IDENTITY headTracker?.let { if (bodyParts.isEmpty() || bodyParts.contains(BodyPart.HEAD)) { - // Only reset if head needsReset and isn't computed - if (it.needsReset && !it.isComputed) { + // Only reset if head allowReset and isn't computed + if (it.allowReset && !it.isComputed) { it.resetsHandler.resetYaw(referenceRotation) } } referenceRotation = it.getRotation() } for (tracker in trackersToReset) { - // Only reset if tracker needsReset - if (tracker != null && tracker.needsReset && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { + // Only reset if tracker allowReset + if (tracker != null && tracker.allowReset && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { tracker.resetsHandler.resetYaw(referenceRotation) } } @@ -1610,7 +1607,7 @@ class HumanSkeleton( // If there's a server present (required for status) and any tracker reports a // non-zero reset status (indicates reset required), then block mounting reset, // as it requires a full reset first - if (humanPoseManager.server != null && trackersToReset.any { it != null && it.lastResetStatus != 0u }) { + if (humanPoseManager.server != null && trackersToReset.any { it != null && it.needReset }) { LogManager.info("[HumanSkeleton] Reset: mounting ($resetSourceName) failed, reset required") return } @@ -1619,45 +1616,70 @@ class HumanSkeleton( var referenceRotation = IDENTITY headTracker?.let { if (bodyParts.isEmpty() || bodyParts.contains(BodyPart.HEAD)) { - // Only reset if head needsMounting or is computed but not HMD - if (it.needsMounting || (it.isComputed && !it.isHmd)) { + // Only reset if head allowMounting or is computed but not HMD + if (it.allowMounting || (it.isComputed && !it.isHmd)) { it.resetsHandler.resetMounting(referenceRotation) } } referenceRotation = it.getRotation() } - // If onlyFeet is true, feet will be forced to be mounting reset in their reset handlers. - val onlyFeet = bodyParts.isNotEmpty() && bodyParts.all { it == BodyPart.LEFT_FOOT || it == BodyPart.RIGHT_FOOT } for (tracker in trackersToReset) { // Only reset if tracker needsMounting - if (tracker != null && tracker.needsMounting && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { - tracker.resetsHandler.resetMounting(referenceRotation, onlyFeet) + if (tracker != null && tracker.allowMounting && (bodyParts.isEmpty() || bodyParts.contains(tracker.trackerPosition?.bodyPart))) { + tracker.resetsHandler.resetMounting(referenceRotation) } } legTweaks.resetBuffer() localizer.reset() + + if (humanPoseManager.server != null) { + humanPoseManager.server.configManager.vrConfig.resetsConfig.lastMountingMethod = + MountingMethods.AUTOMATIC + if (!humanPoseManager.server.trackingChecklistManager.resetMountingCompleted) { + humanPoseManager.server.trackingChecklistManager.resetMountingCompleted = bodyParts.any { it -> + val defaultParts = if (humanPoseManager.server.configManager.vrConfig.resetsConfig.resetMountingFeet) { + TrackerUtils.allBodyPartsButFingers + } else { + TrackerUtils.allBodyPartsButFingersAndFeets + } + + return@any defaultParts.contains(it) + } + } + if (!humanPoseManager.server.trackingChecklistManager.feetResetMountingCompleted) { + humanPoseManager.server.trackingChecklistManager.feetResetMountingCompleted = bodyParts.any { TrackerUtils.feetsBodyParts.contains(it) } + } + humanPoseManager.server.configManager.saveConfig() + } + LogManager.info("[HumanSkeleton] Reset: mounting ($resetSourceName)") } @VRServerThread fun clearTrackersMounting(resetSourceName: String?) { headTracker?.let { - if (it.needsMounting) it.resetsHandler.clearMounting() + if (it.allowMounting) it.resetsHandler.clearMounting() } for (tracker in trackersToReset) { if (tracker != null && - tracker.needsMounting + tracker.allowMounting ) { tracker.resetsHandler.clearMounting() } } legTweaks.resetBuffer() LogManager.info("[HumanSkeleton] Clear: mounting ($resetSourceName)") + + if (humanPoseManager.server != null) { + humanPoseManager.server.trackingChecklistManager.resetMountingCompleted = false + humanPoseManager.server.trackingChecklistManager.feetResetMountingCompleted = false + humanPoseManager.server.configManager.saveConfig() + } } fun updateTapDetectionConfig() { - tapDetectionManager.updateConfig(null) + tapDetectionManager?.refresh() } fun updateLegTweaksConfig() { diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt index 340888844..073709eab 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetection.kt @@ -4,73 +4,27 @@ import dev.slimevr.tracking.trackers.Tracker import java.util.* // class that monitors the acceleration of the waist, hip, chest or upper chest trackers to detect taps -// and use this to trigger a varaity of resets (if your wondering why no single tap class exists, it's because +// and use this to trigger a variety of resets (if your wondering why no single tap class exists, it's because // to many false positives) -class TapDetection { - // server and related classes - private val skeleton: HumanSkeleton? +class TapDetection(val skeleton: HumanSkeleton, val trackerToWatch: Tracker, val numberTrackersOverThreshold: Int, val tapToComplete: Int, val onTapCompleted: () -> Unit) { - // tap detection - @JvmField - var enabled: Boolean = false private val accelList = LinkedList() - private val tapTimes = LinkedList() - var tracker: Tracker? = null - private set - private var numberTrackersOverThreshold = 1 - - private var timeWindowNS = 0.6f * NS_CONVERTER - - // state - var detectionTime: Float = -1.0f - private set - var taps: Int = 0 - private set + private val tapTimestamps = LinkedList() + private var timeWindowNS = 0.3f * tapToComplete * NS_CONVERTER private var waitForLowAccel = false - constructor(skeleton: HumanSkeleton?) { - this.skeleton = skeleton - } - - constructor( - skeleton: HumanSkeleton?, - trackerToWatch: Tracker?, - ) { - this.skeleton = skeleton - this.tracker = trackerToWatch - } - - // set the tracker to watch and detect taps on - fun setTrackerToWatch(tracker: Tracker?) { - this.tracker = tracker - } - - fun setNumberTrackersOverThreshold(numberTrackersOverThreshold: Int) { - this.numberTrackersOverThreshold = numberTrackersOverThreshold - } - // reset the lists for detecting taps - fun resetDetector() { - tapTimes.clear() + fun reset() { + tapTimestamps.clear() accelList.clear() - taps = 0 - } - - // set the max taps this detector is configured to detect - fun setMaxTaps(maxTaps: Int) { - timeWindowNS = 0.3f * maxTaps * NS_CONVERTER + waitForLowAccel = false } // main function for tap detection fun update() { - if (skeleton == null || !enabled) return - - if (tracker == null) return - // get the acceleration of the tracker and add it to the list val time = System.nanoTime().toFloat() - val listval = floatArrayOf(tracker!!.getAcceleration().len(), time) - accelList.add(listval) + accelList.add(floatArrayOf(trackerToWatch.getAcceleration().len(), time)) // remove old values from the list (if they are too old) while (time - accelList.first()[1] > CLUMP_TIME_NS) { @@ -82,7 +36,7 @@ class TapDetection { if (accelDelta > NEEDED_ACCEL_DELTA && !waitForLowAccel) { // after a tap is added to the list, a lower acceleration // is needed before another tap can be added - tapTimes.add(time) + tapTimestamps.add(time) waitForLowAccel = true } @@ -92,25 +46,23 @@ class TapDetection { } // remove old taps from the list (if they are too old) - if (!tapTimes.isEmpty()) { - while (time - tapTimes.first() > timeWindowNS) { - tapTimes.removeFirst() - if (tapTimes.isEmpty()) return + if (!tapTimestamps.isEmpty()) { + while (time - tapTimestamps.first() > timeWindowNS) { + tapTimestamps.removeFirst() + if (tapTimestamps.isEmpty()) return } } - // if the user is moving their body too much, reset the tap list - if (!isUserStatic(tracker!!)) { - tapTimes.clear() - accelList.clear() + // if we have no taps within the timeframe or + // if the user is moving their body too much, reset the tap detector + if (!isUserStatic(trackerToWatch)) { + reset() + return } - // get the amount of taps in the list - // and set the detection time - val newTaps = tapTimes.size - if (newTaps > taps) { - taps = newTaps - detectionTime = time + if (tapTimestamps.size >= tapToComplete) { + onTapCompleted() + reset() } } @@ -141,7 +93,7 @@ class TapDetection { // you need two or more trackers for this feature to be reliable) private fun isUserStatic(trackerToExclude: Tracker): Boolean { var num = 0 - if (skeleton!!.upperChestTracker != null && + if (skeleton.upperChestTracker != null && skeleton.upperChestTracker != trackerToExclude ) { if (skeleton.upperChestTracker!!.getAcceleration().lenSq() diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java deleted file mode 100644 index 404f38c6a..000000000 --- a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.java +++ /dev/null @@ -1,269 +0,0 @@ -package dev.slimevr.tracking.processor.skeleton; - - -import dev.slimevr.VRServer; -import dev.slimevr.config.TapDetectionConfig; -import dev.slimevr.reset.ResetHandler; -import dev.slimevr.setup.TapSetupHandler; -import dev.slimevr.tracking.processor.HumanPoseManager; -import dev.slimevr.tracking.trackers.Tracker; -import dev.slimevr.tracking.trackers.TrackerUtils; -import solarxr_protocol.rpc.ResetType; -import solarxr_protocol.rpc.StatusData; - -import java.util.ArrayList; -import java.util.List; - - -/** - * Handles tap detection for reset - */ -public class TapDetectionManager { - private static final String resetSourceName = "TapDetection"; - private static final int tapsForSetupMode = 2; - - // server and related classes - private final HumanSkeleton skeleton; - private HumanPoseManager humanPoseManager; - private TapDetectionConfig config; - - // tap detectors - private TapDetection yawResetDetector; - private TapDetection fullResetDetector; - private TapDetection mountingResetDetector; - - private ArrayList tapDetectors; - - // number of taps to detect - private int yawResetTaps = 2; - private int fullResetTaps = 3; - private int mountingResetTaps = 3; - - // delay - private static final float NS_CONVERTER = 1.0e9f; - private float fullResetDelayNs = 0.20f * NS_CONVERTER; - private float yawResetDelayNs = 1.00f * NS_CONVERTER; - private float mountingResetDelayNs = 1.00f * NS_CONVERTER; - - // feedback - private boolean yawResetAllowPlaySound = true; - private boolean fullResetAllowPlaySound = true; - private boolean mountingResetAllowPlaySound = true; - - private ResetHandler resetHandler; - private TapSetupHandler tapSetupHandler; - - public TapDetectionManager(HumanSkeleton skeleton) { - this.skeleton = skeleton; - } - - public TapDetectionManager( - HumanSkeleton skeleton, - HumanPoseManager humanPoseManager, - TapDetectionConfig config, - ResetHandler resetHandler, - TapSetupHandler tapSetupHandler, - List trackers - ) { - this.skeleton = skeleton; - this.humanPoseManager = humanPoseManager; - this.config = config; - this.resetHandler = resetHandler; - this.tapSetupHandler = tapSetupHandler; - - updateConfig(trackers); - } - - public void updateConfig(List trackers) { - // check the skeleton for new trackers - yawResetDetector = new TapDetection(skeleton, getTrackerToWatchYawReset()); - fullResetDetector = new TapDetection(skeleton, getTrackerToWatchFullReset()); - mountingResetDetector = new TapDetection(skeleton, getTrackerToWatchMountingReset()); - - if (trackers != null) { - tapDetectors = new ArrayList<>(); - for (Tracker tracker : trackers) { - TapDetection tapDetector = new TapDetection(skeleton, tracker); - tapDetector.enabled = true; - tapDetectors.add(tapDetector); - } - } - - if (this.config == null) { - return; - } - - this.yawResetDelayNs = config.getYawResetDelay() * NS_CONVERTER; - this.fullResetDelayNs = config.getFullResetDelay() * NS_CONVERTER; - this.mountingResetDelayNs = config.getMountingResetDelay() * NS_CONVERTER; - yawResetDetector.enabled = config.getYawResetEnabled(); - fullResetDetector.enabled = config.getFullResetEnabled(); - mountingResetDetector.enabled = config.getMountingResetEnabled(); - yawResetTaps = config.getYawResetTaps(); - fullResetTaps = config.getFullResetTaps(); - mountingResetTaps = config.getMountingResetTaps(); - yawResetDetector.setMaxTaps(yawResetTaps); - fullResetDetector.setMaxTaps(fullResetTaps); - mountingResetDetector.setMaxTaps(mountingResetTaps); - yawResetDetector - .setNumberTrackersOverThreshold( - config.getNumberTrackersOverThreshold() - ); - fullResetDetector - .setNumberTrackersOverThreshold( - config.getNumberTrackersOverThreshold() - ); - mountingResetDetector - .setNumberTrackersOverThreshold( - config.getNumberTrackersOverThreshold() - ); - } - - public void update() { - if ( - yawResetDetector == null - || fullResetDetector == null - || mountingResetDetector == null - || tapDetectors == null - || config == null - ) - return; - - // if setup mode is enabled, update the tap detectors for each tracker - if (config.getSetupMode()) { - for (TapDetection tapDetector : tapDetectors) { - tapDetector.update(); - - if (tapDetector.getTaps() >= tapsForSetupMode) { - tapSetupHandler.sendTap(tapDetector.getTracker()); - tapDetector.resetDetector(); - } - } - } else { - // update the tap detectors - yawResetDetector.update(); - fullResetDetector.update(); - mountingResetDetector.update(); - - // check if any tap detectors have detected taps - checkYawReset(); - checkFullReset(); - checkMountingReset(); - } - } - - private void checkYawReset() { - boolean tapped = (yawResetTaps <= yawResetDetector.getTaps()); - - if (tapped && yawResetAllowPlaySound) { - this.resetHandler.sendStarted(ResetType.Yaw); - yawResetAllowPlaySound = false; - } - - if ( - tapped && System.nanoTime() - yawResetDetector.getDetectionTime() > yawResetDelayNs - ) { - if (humanPoseManager != null) - humanPoseManager.resetTrackersYaw(resetSourceName); - else - skeleton.resetTrackersYaw(resetSourceName); - - yawResetDetector.resetDetector(); - yawResetAllowPlaySound = true; - this.resetHandler.sendFinished(ResetType.Yaw); - } - } - - private void checkFullReset() { - boolean tapped = (fullResetTaps <= fullResetDetector.getTaps()); - - if (tapped && fullResetAllowPlaySound) { - this.resetHandler.sendStarted(ResetType.Full); - fullResetAllowPlaySound = false; - } - - if ( - tapped && System.nanoTime() - fullResetDetector.getDetectionTime() > fullResetDelayNs - ) { - if (humanPoseManager != null) - humanPoseManager.resetTrackersFull(resetSourceName); - else - skeleton.resetTrackersFull(resetSourceName); - - fullResetDetector.resetDetector(); - fullResetAllowPlaySound = true; - this.resetHandler.sendFinished(ResetType.Full); - } - } - - private void checkMountingReset() { - // Don't allow mounting if tracker needs reset - VRServer server = humanPoseManager.getServer(); - if (server != null && server.statusSystem.hasStatusType(StatusData.StatusTrackerReset)) { - mountingResetDetector.resetDetector(); - return; - } - - boolean tapped = (mountingResetTaps <= mountingResetDetector.getTaps()); - - if (tapped && mountingResetAllowPlaySound) { - this.resetHandler.sendStarted(ResetType.Mounting); - mountingResetAllowPlaySound = false; - } - - if ( - tapped - && System.nanoTime() - mountingResetDetector.getDetectionTime() - > mountingResetDelayNs - ) { - // This will ask the skeleton for a mounting reset on every tracker - // except fingers. - // However, feet being reset or not will end up being decided on a - // per-tracker basis - // due to the setting being in ResetsConfig.kt - skeleton - .resetTrackersMounting( - resetSourceName, - TrackerUtils.INSTANCE.getAllBodyPartsButFingers() - ); - - mountingResetDetector.resetDetector(); - mountingResetAllowPlaySound = true; - this.resetHandler.sendFinished(ResetType.Mounting); - } - } - - - // returns either the chest tracker, hip tracker, or waist tracker depending - // on which one is available - // if none are available, returns null - private Tracker getTrackerToWatchYawReset() { - if (skeleton.getUpperChestTracker() != null) - return skeleton.getUpperChestTracker(); - else if (skeleton.getChestTracker() != null) - return skeleton.getChestTracker(); - else if (skeleton.getHipTracker() != null) - return skeleton.getHipTracker(); - else if (skeleton.getWaistTracker() != null) - return skeleton.getWaistTracker(); - else - return null; - } - - private Tracker getTrackerToWatchFullReset() { - if (skeleton.getLeftUpperLegTracker() != null) - return skeleton.getLeftUpperLegTracker(); - else if (skeleton.getLeftLowerLegTracker() != null) - return skeleton.getLeftLowerLegTracker(); - return null; - } - - private Tracker getTrackerToWatchMountingReset() { - if (skeleton.getRightUpperLegTracker() != null) - return skeleton.getRightUpperLegTracker(); - else if (skeleton.getRightLowerLegTracker() != null) - return skeleton.getRightLowerLegTracker(); - return null; - } - -} diff --git a/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.kt b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.kt new file mode 100644 index 000000000..50f5b5e7c --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/tracking/processor/skeleton/TapDetectionManager.kt @@ -0,0 +1,116 @@ +package dev.slimevr.tracking.processor.skeleton + +import dev.slimevr.VRServer +import dev.slimevr.tracking.processor.HumanPoseManager +import dev.slimevr.tracking.trackers.Tracker + +class TapDetectionManager( + val server: VRServer, + val skeleton: HumanSkeleton, + val humanPoseManager: HumanPoseManager, +) { + private var tapDetectors: ArrayList = arrayListOf() + var yawResetDetector: TapDetection? = null + var fullResetDetector: TapDetection? = null + var mountingResetDetector: TapDetection? = null + + var config = server.configManager.vrConfig.tapDetection + + init { + refresh() + } + + fun registerSingleTapDetectors() { + for (tracker in server.allTrackers) { + tapDetectors.add( + TapDetection(skeleton, tracker, config.numberTrackersOverThreshold, 2) { + server.tapSetupHandler.sendTap(tracker) + }, + ) + } + } + + fun registerResetsDetectors() { + val yawTracker = yawResetTracker + yawResetDetector = if (yawTracker != null && config.yawResetEnabled) { + TapDetection(skeleton, yawTracker, config.numberTrackersOverThreshold, config.yawResetTaps) { + server.scheduleResetTrackersYaw(RESET_SOURCE_NAME, (config.yawResetDelay * 1000).toLong()) + } + } else { + null + } + + val fullTracker = fullResetTracker + fullResetDetector = if (fullTracker != null && config.fullResetEnabled) { + TapDetection(skeleton, fullTracker, config.numberTrackersOverThreshold, config.fullResetTaps) { + server.scheduleResetTrackersFull(RESET_SOURCE_NAME, (config.fullResetDelay * 1000).toLong()) + } + } else { + null + } + + val mountingTracker = mountingResetTracker + mountingResetDetector = if (mountingTracker != null && config.mountingResetEnabled) { + TapDetection(skeleton, mountingTracker, config.numberTrackersOverThreshold, config.mountingResetTaps) { + server.scheduleResetTrackersMounting(RESET_SOURCE_NAME, (config.mountingResetDelay * 1000).toLong()) + } + } else { + null + } + } + + /** + * Called when the list of available trackers gets updated + * or when the tap settings get changed + * it re-create the tap detectors according to the configs and available trackers + */ + fun refresh() { + tapDetectors.clear() + registerSingleTapDetectors() + registerResetsDetectors() + } + + fun update() { + // We disable the resets detectors during the assignment phase so you cant + // trigger a reset while assigning + if (config.setupMode) { + for (detector in tapDetectors) { + detector.update() + } + } else { + yawResetDetector?.update() + fullResetDetector?.update() + mountingResetDetector?.update() + } + } + + private val mountingResetTracker: Tracker? + get() { + return arrayOf( + skeleton.rightUpperLegTracker, + skeleton.rightLowerLegTracker, + ).firstNotNullOfOrNull { it } + } + + private val fullResetTracker: Tracker? + get() { + return arrayOf( + skeleton.leftUpperLegTracker, + skeleton.leftLowerLegTracker, + ).firstNotNullOfOrNull { it } + } + + private val yawResetTracker: Tracker? + get() { + return arrayOf( + skeleton.upperChestTracker, + skeleton.chestTracker, + skeleton.hipTracker, + skeleton.waistTracker, + ).firstNotNullOfOrNull { it } + } + + companion object { + const val RESET_SOURCE_NAME: String = "TapDetection" + } +} diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt index caa4bfadd..e88cfdffd 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/Tracker.kt @@ -11,12 +11,6 @@ import dev.slimevr.util.InterpolationHandler import io.eiren.util.BufferedTimer import io.github.axisangles.ktmath.Quaternion import io.github.axisangles.ktmath.Vector3 -import solarxr_protocol.datatypes.DeviceIdT -import solarxr_protocol.datatypes.TrackerIdT -import solarxr_protocol.rpc.StatusData -import solarxr_protocol.rpc.StatusDataUnion -import solarxr_protocol.rpc.StatusTrackerErrorT -import solarxr_protocol.rpc.StatusTrackerResetT import kotlin.properties.Delegates const val TIMEOUT_MS = 2_000L @@ -71,9 +65,23 @@ class Tracker @JvmOverloads constructor( * [trackRotDirection] is set to false. */ val allowFiltering: Boolean = false, - val needsReset: Boolean = false, - val needsMounting: Boolean = false, + + /** + * If true, the tracker can be reset + */ + val allowReset: Boolean = false, + /** + * If true, the tracker can do mounting calibration + */ + val allowMounting: Boolean = false, + val isHmd: Boolean = false, + + /** + * If true, the tracker need the user to perform a reset + */ + var needReset: Boolean = false, + /** * Whether to track the direction of the tracker's rotation * (positive vs negative rotation). This needs to be disabled for AutoBone and @@ -108,33 +116,27 @@ class Tracker @JvmOverloads constructor( var magStatus: MagnetometerStatus = magStatus private set + /** + * Watch the rest calibration status + */ + var hasCompletedRestCalibration: Boolean? = null + /** * If the tracker has gotten disconnected after it was initialized first time */ - var statusResetRecently = false - private var alreadyInitialized = false var status: TrackerStatus by Delegates.observable(TrackerStatus.DISCONNECTED) { _, old, new -> if (old == new) return@observable - if (!new.reset) { - if (alreadyInitialized) { - statusResetRecently = true - } - alreadyInitialized = true + if (allowReset && !old.reset && new.reset && !needReset) { + needReset = true } + if (!isInternal && VRServer.instanceInitialized) { // If the status of a non-internal tracker has changed, inform // the VRServer to recreate the skeleton, as it may need to // assign or un-assign the tracker to a body part VRServer.instance.updateSkeletonModel() VRServer.instance.refreshTrackersDriftCompensationEnabled() - - if (isHmd) { - VRServer.instance.humanPoseManager.checkReportMissingHmd() - } - checkReportErrorStatus() - checkReportRequireReset() - VRServer.instance.trackerStatusChanged(this, old, new) } } @@ -142,16 +144,18 @@ class Tracker @JvmOverloads constructor( var trackerPosition: TrackerPosition? by Delegates.observable(trackerPosition) { _, old, new -> if (old == new) return@observable + if (allowReset && !needReset) { + needReset = true + } + if (!isInternal) { // Set default mounting orientation for that body part new?.let { resetsHandler.mountingOrientation = it.defaultMounting() } - - checkReportRequireReset() } } // Computed value to simplify availability checks - val hasAdjustedRotation = hasRotation && (allowFiltering || needsReset) + val hasAdjustedRotation = hasRotation && (allowFiltering || allowReset) /** * It's like the ID, but it should be local to the device if it has one @@ -163,11 +167,11 @@ class Tracker @JvmOverloads constructor( init { // IMPORTANT: Look here for the required states of inputs - require(!needsReset || (hasRotation && needsReset)) { - "If ${::needsReset.name} is true, then ${::hasRotation.name} must also be true" + require(!allowReset || (hasRotation && allowReset)) { + "If ${::allowReset.name} is true, then ${::hasRotation.name} must also be true" } - require(!needsMounting || (needsReset && needsMounting)) { - "If ${::needsMounting.name} is true, then ${::needsReset.name} must also be true" + require(!allowMounting || (allowReset && allowMounting)) { + "If ${::allowMounting.name} is true, then ${::allowReset.name} must also be true" } require(!isHmd || (hasPosition && isHmd)) { "If ${::isHmd.name} is true, then ${::hasPosition.name} must also be true" @@ -177,76 +181,6 @@ class Tracker @JvmOverloads constructor( // } } - fun checkReportRequireReset() { - if (needsReset && - trackerPosition != null && - lastResetStatus == 0u && - !status.reset && - (isImu() || !statusResetRecently && trackerDataType != TrackerDataType.FLEX_ANGLE) - ) { - reportRequireReset() - } else if (lastResetStatus != 0u && (trackerPosition == null || status.reset)) { - VRServer.instance.statusSystem.removeStatus(lastResetStatus) - lastResetStatus = 0u - } - } - - /** - * If 0 then it's null - */ - var lastResetStatus = 0u - private fun reportRequireReset() { - require(lastResetStatus == 0u) { - "lastResetStatus must be 0u, but was $lastResetStatus" - } - - val tempTrackerNum = this.trackerNum - val statusMsg = StatusTrackerResetT().apply { - trackerId = TrackerIdT().apply { - if (device != null) { - deviceId = DeviceIdT().apply { id = device.id } - } - trackerNum = tempTrackerNum - } - } - val status = StatusDataUnion().apply { - type = StatusData.StatusTrackerReset - value = statusMsg - } - lastResetStatus = VRServer.instance.statusSystem.addStatus(status, true) - } - - private fun checkReportErrorStatus() { - if (status == TrackerStatus.ERROR && lastErrorStatus == 0u) { - reportErrorStatus() - } else if (lastErrorStatus != 0u && status != TrackerStatus.ERROR) { - VRServer.instance.statusSystem.removeStatus(lastErrorStatus) - lastErrorStatus = 0u - } - } - - var lastErrorStatus = 0u - private fun reportErrorStatus() { - require(lastErrorStatus == 0u) { - "lastResetStatus must be 0u, but was $lastErrorStatus" - } - - val tempTrackerNum = this.trackerNum - val statusMsg = StatusTrackerErrorT().apply { - trackerId = TrackerIdT().apply { - if (device != null) { - deviceId = DeviceIdT().apply { id = device.id } - } - trackerNum = tempTrackerNum - } - } - val status = StatusDataUnion().apply { - type = StatusData.StatusTrackerError - value = statusMsg - } - lastErrorStatus = VRServer.instance.statusSystem.addStatus(status, true) - } - /** * Reads/loads from the given config */ @@ -257,7 +191,7 @@ class Tracker @JvmOverloads constructor( config.designation?.let { designation -> getByDesignation(designation)?.let { trackerPosition = it } } ?: run { trackerPosition = null } - if (needsMounting) { + if (allowMounting) { // Load manual mounting config.mountingOrientation?.let { resetsHandler.mountingOrientation = it.toValue() } } @@ -271,11 +205,6 @@ class Tracker @JvmOverloads constructor( resetsHandler.allowDriftCompensation = it } } - if (!isInternal && - !(!isImu() && (trackerPosition == TrackerPosition.LEFT_HAND || trackerPosition == TrackerPosition.RIGHT_HAND)) - ) { - checkReportRequireReset() - } } /** @@ -284,7 +213,7 @@ class Tracker @JvmOverloads constructor( fun writeConfig(config: TrackerConfig) { trackerPosition?.let { config.designation = it.designation } ?: run { config.designation = null } customName?.let { config.customName = it } - if (needsMounting) { + if (allowMounting) { // Save manual mounting config.mountingOrientation = resetsHandler.mountingOrientation.toObject() } @@ -364,7 +293,7 @@ class Tracker @JvmOverloads constructor( } // Reset if needed and is not computed and internal - return if (needsReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) { + return if (allowReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) { // Adjust to reset, mounting and drift compensation resetsHandler.getReferenceAdjustedDriftRotationFrom(rot) } else { @@ -384,7 +313,7 @@ class Tracker @JvmOverloads constructor( rot = Quaternion.rotationAroundYAxis(stayAligned.yawCorrection.toRad()) * rot // Reset if needed and is not computed and internal - return if (needsReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) { + return if (needReset && !(isComputed && isInternal) && trackerDataType == TrackerDataType.ROTATION) { // Adjust to reset, mounting and drift compensation resetsHandler.getReferenceAdjustedDriftRotationFrom(rot) } else { @@ -406,7 +335,7 @@ class Tracker @JvmOverloads constructor( } // Reset if needed or is a computed tracker besides head - return if (needsReset && !(isComputed && trackerPosition != TrackerPosition.HEAD) && trackerDataType == TrackerDataType.ROTATION) { + return if (allowReset && !(isComputed && trackerPosition != TrackerPosition.HEAD) && trackerDataType == TrackerDataType.ROTATION) { // Adjust to reset and mounting resetsHandler.getIdentityAdjustedDriftRotationFrom(rot) } else { @@ -442,7 +371,7 @@ class Tracker @JvmOverloads constructor( /** * Gets the world-adjusted acceleration */ - fun getAcceleration(): Vector3 = if (needsReset) { + fun getAcceleration(): Vector3 = if (allowReset) { resetsHandler.getReferenceAdjustedAccel(_rotation, _acceleration) } else { _acceleration @@ -488,7 +417,7 @@ class Tracker @JvmOverloads constructor( /** * Gets the magnetic field vector, in mGauss. */ - fun getMagVector() = if (needsReset) { + fun getMagVector() = if (allowReset) { resetsHandler.getReferenceAdjustedAccel(_rotation, _magVector) } else { _magVector diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt index 6b6c962cc..ddc5e1b2e 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerResetsHandler.kt @@ -15,10 +15,7 @@ import kotlin.math.* private const val DRIFT_COOLDOWN_MS = 50000L -/** - * Class taking care of full reset, yaw reset, mounting reset, - * and drift compensation logic. - */ +/** Class taking care of full reset, yaw reset, mounting reset, and drift compensation logic. */ class TrackerResetsHandler(val tracker: Tracker) { private val HalfHorizontal = EulerAngles( @@ -38,7 +35,6 @@ class TrackerResetsHandler(val tracker: Tracker) { private var compensateDrift = false private var driftPrediction = false private var driftCompensationEnabled = false - private var resetMountingFeet = false private var armsResetMode = ArmsResetModes.BACK private var yawResetSmoothTime = 0.0f var saveMountingReset = false @@ -165,7 +161,6 @@ class TrackerResetsHandler(val tracker: Tracker) { * Reads/loads reset settings from the given config */ fun readResetConfig(config: ResetsConfig) { - resetMountingFeet = config.resetMountingFeet armsResetMode = config.mode yawResetSmoothTime = config.yawResetSmoothTime saveMountingReset = config.saveMountingReset @@ -275,7 +270,7 @@ class TrackerResetsHandler(val tracker: Tracker) { val mountingAdjustedRotation = tracker.getRawRotation() * mountingOrientation // Gyrofix - if (tracker.needsMounting || (tracker.trackerPosition == TrackerPosition.HEAD && !tracker.isHmd)) { + if (tracker.allowMounting || (tracker.trackerPosition == TrackerPosition.HEAD && !tracker.isHmd)) { gyroFix = if (tracker.isComputed) { fixGyroscope(tracker.getRawRotation()) } else { @@ -307,7 +302,7 @@ class TrackerResetsHandler(val tracker: Tracker) { } // Rotate attachmentFix by 180 degrees as a workaround for t-pose (down) - if (tposeDownFix != Quaternion.IDENTITY && tracker.needsMounting) { + if (tposeDownFix != Quaternion.IDENTITY && tracker.allowMounting) { attachmentFix *= HalfHorizontal } @@ -329,9 +324,8 @@ class TrackerResetsHandler(val tracker: Tracker) { } private fun postProcessResetFull(reference: Quaternion) { - if (this.tracker.lastResetStatus != 0u) { - VRServer.instance.statusSystem.removeStatus(this.tracker.lastResetStatus) - this.tracker.lastResetStatus = 0u + if (this.tracker.needReset) { + this.tracker.needReset = false } tracker.resetFilteringQuats(reference) @@ -376,13 +370,7 @@ class TrackerResetsHandler(val tracker: Tracker) { ) } - // Remove the status if yaw reset was performed after the tracker - // was disconnected and connected. - if (this.tracker.lastResetStatus != 0u && this.tracker.statusResetRecently) { - VRServer.instance.statusSystem.removeStatus(this.tracker.lastResetStatus) - this.tracker.statusResetRecently = false - this.tracker.lastResetStatus = 0u - } + this.tracker.needReset = false // Reset Stay Aligned (before resetting filtering, which depends on the // tracker's rotation) @@ -394,17 +382,14 @@ class TrackerResetsHandler(val tracker: Tracker) { /** * Perform the math to align the tracker to go forward * and stores it in mountRotFix, and adjusts yawFix - * If forceFeet is true, always reset feet regardless of resetMountingFeet's value. */ - fun resetMounting(reference: Quaternion, forceFeet: Boolean = false) { + fun resetMounting(reference: Quaternion) { if (tracker.trackerDataType == TrackerDataType.FLEX_RESISTANCE) { tracker.trackerFlexHandler.resetMax() tracker.resetFilteringQuats(reference) return } else if (tracker.trackerDataType == TrackerDataType.FLEX_ANGLE) { return - } else if (!resetMountingFeet && tracker.trackerPosition.isFoot() && !forceFeet) { - return } constraintFix = Quaternion.IDENTITY diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt index 8aa27052d..f3e73b3ee 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/TrackerUtils.kt @@ -102,4 +102,18 @@ object TrackerUtils { BodyPart.RIGHT_HAND, BodyPart.LEFT_SHOULDER, BodyPart.RIGHT_SHOULDER, BodyPart.LEFT_FOOT, BodyPart.RIGHT_FOOT, ) + + val allBodyPartsButFingersAndFeets = listOf( + BodyPart.HEAD, BodyPart.NECK, BodyPart.UPPER_CHEST, + BodyPart.CHEST, BodyPart.WAIST, BodyPart.HIP, + BodyPart.LEFT_UPPER_LEG, BodyPart.RIGHT_UPPER_LEG, BodyPart.LEFT_LOWER_LEG, + BodyPart.RIGHT_LOWER_LEG, BodyPart.LEFT_LOWER_ARM, BodyPart.RIGHT_LOWER_ARM, + BodyPart.LEFT_UPPER_ARM, BodyPart.RIGHT_UPPER_ARM, BodyPart.LEFT_HAND, + BodyPart.RIGHT_HAND, BodyPart.LEFT_SHOULDER, BodyPart.RIGHT_SHOULDER, + ) + + val feetsBodyParts = listOf( + BodyPart.LEFT_FOOT, + BodyPart.RIGHT_FOOT, + ) } diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt index 6e18e05ec..79879fa41 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/hid/HIDCommon.kt @@ -90,8 +90,8 @@ class HIDCommon { userEditable = true, imuType = sensorType, allowFiltering = true, - needsReset = true, - needsMounting = true, + allowReset = true, + allowMounting = true, usesTimeout = false, magStatus = magStatus, ) diff --git a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt index 7f25b97b7..343b2ae24 100644 --- a/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt +++ b/server/core/src/main/java/dev/slimevr/tracking/trackers/udp/TrackersUDPServer.kt @@ -174,7 +174,16 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker // Set up new sensor for older firmware. // Firmware after 7 should send sensor status packet and sensor // will be created when it's received - setUpSensor(connection, 0, handshake.imuType, 1, MagnetometerStatus.NOT_SUPPORTED, null, TrackerDataType.ROTATION) + setUpSensor( + connection, + 0, + handshake.imuType, + 1, + MagnetometerStatus.NOT_SUPPORTED, + null, + TrackerDataType.ROTATION, + null, + ) } connection } @@ -186,7 +195,16 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker } private val mainScope = CoroutineScope(SupervisorJob()) - private fun setUpSensor(connection: UDPDevice, trackerId: Int, sensorType: IMUType, sensorStatus: Int, magStatus: MagnetometerStatus, trackerPosition: TrackerPosition?, trackerDataType: TrackerDataType) { + private fun setUpSensor( + connection: UDPDevice, + trackerId: Int, + sensorType: IMUType, + sensorStatus: Int, + magStatus: MagnetometerStatus, + trackerPosition: TrackerPosition?, + trackerDataType: TrackerDataType, + hasCompletedRestCalibration: Boolean?, + ) { LogManager.info("[TrackerServer] Sensor $trackerId for ${connection.name} status: $sensorStatus") var imuTracker = connection.getTracker(trackerId) if (imuTracker == null) { @@ -210,8 +228,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker userEditable = true, imuType = if (trackerDataType == TrackerDataType.ROTATION) sensorType else null, allowFiltering = true, - needsReset = true, - needsMounting = true, + allowReset = true, + allowMounting = true, usesTimeout = true, magStatus = magStatus, trackerDataType = trackerDataType, @@ -223,6 +241,8 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker val status = UDPPacket15SensorInfo.getStatus(sensorStatus) if (status != null) imuTracker.status = status + imuTracker.hasCompletedRestCalibration = hasCompletedRestCalibration + if (magStatus == MagnetometerStatus.NOT_SUPPORTED) return if (magStatus == MagnetometerStatus.ENABLED && (!VRServer.instance.configManager.vrConfig.server.useMagnetometerOnAllTrackers || imuTracker.config.shouldHaveMagEnabled == false) @@ -484,6 +504,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker magStatus, packet.trackerPosition, packet.trackerDataType, + packet.hasCompletedRestCalibration, ) // Send ack bb.limit(bb.capacity()) @@ -510,14 +531,15 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker when (packet.type) { UDPPacket21UserAction.RESET_FULL -> { name = "Full reset" - VRServer.instance.resetHandler.sendStarted(ResetType.Full) - VRServer.instance.resetTrackersFull(RESET_SOURCE_NAME) + VRServer.instance.scheduleResetTrackersFull( + RESET_SOURCE_NAME, + (VRServer.instance.configManager.vrConfig.resetsConfig.fullResetDelay * 1000).toLong(), + ) } UDPPacket21UserAction.RESET_YAW -> { name = "Yaw reset" - VRServer.instance.resetHandler.sendStarted(ResetType.Yaw) - VRServer.instance.resetTrackersYaw(RESET_SOURCE_NAME) + VRServer.instance.scheduleResetTrackersYaw(RESET_SOURCE_NAME, (VRServer.instance.configManager.vrConfig.resetsConfig.yawResetDelay * 1000).toLong()) } UDPPacket21UserAction.RESET_MOUNTING -> { @@ -526,7 +548,7 @@ class TrackersUDPServer(private val port: Int, name: String, private val tracker .instance .resetHandler .sendStarted(ResetType.Mounting) - VRServer.instance.resetTrackersMounting(RESET_SOURCE_NAME) + VRServer.instance.scheduleResetTrackersMounting(RESET_SOURCE_NAME, (VRServer.instance.configManager.vrConfig.resetsConfig.mountingResetDelay * 1000).toLong()) } UDPPacket21UserAction.PAUSE_TRACKING -> { diff --git a/server/core/src/main/java/dev/slimevr/trackingchecklist/TrackingChecklistManager.kt b/server/core/src/main/java/dev/slimevr/trackingchecklist/TrackingChecklistManager.kt new file mode 100644 index 000000000..4ac2ba608 --- /dev/null +++ b/server/core/src/main/java/dev/slimevr/trackingchecklist/TrackingChecklistManager.kt @@ -0,0 +1,346 @@ +package dev.slimevr.trackingchecklist + +import dev.slimevr.VRServer +import dev.slimevr.bridge.ISteamVRBridge +import dev.slimevr.config.MountingMethods +import dev.slimevr.games.vrchat.VRCConfigListener +import dev.slimevr.games.vrchat.VRCConfigRecommendedValues +import dev.slimevr.games.vrchat.VRCConfigValidity +import dev.slimevr.games.vrchat.VRCConfigValues +import dev.slimevr.tracking.trackers.Tracker +import dev.slimevr.tracking.trackers.TrackerStatus +import dev.slimevr.tracking.trackers.TrackerUtils +import dev.slimevr.tracking.trackers.udp.TrackerDataType +import solarxr_protocol.datatypes.DeviceIdT +import solarxr_protocol.datatypes.TrackerIdT +import solarxr_protocol.rpc.* +import java.util.* +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.concurrent.timerTask + +interface TrackingChecklistListener { + fun onStepsUpdate() +} + +class TrackingChecklistManager(private val vrServer: VRServer) : VRCConfigListener { + + private val listeners: MutableList = CopyOnWriteArrayList() + val steps: MutableList = mutableListOf() + + private val updateTrackingChecklistTimer = Timer("TrackingChecklistTimer") + + // Simple flag set to true if reset mounting was performed at least once. + // This value is only runtime and never saved + var resetMountingCompleted = false + var feetResetMountingCompleted = false + + init { + vrServer.vrcConfigManager.addListener(this) + + createSteps() + updateTrackingChecklistTimer.scheduleAtFixedRate( + timerTask { + updateChecklist() + }, + 0, + 1000, + ) + } + + fun addListener(channel: TrackingChecklistListener) { + listeners.add(channel) + } + + fun removeListener(channel: TrackingChecklistListener) { + listeners.removeIf { channel == it } + } + + fun buildTrackersIds(trackers: List): Array = trackers.map { tracker -> + TrackerIdT().apply { + if (tracker.device != null) { + deviceId = DeviceIdT().apply { id = tracker.device.id } + } + trackerNum = tracker.trackerNum + } + }.toTypedArray() + + private fun createSteps() { + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.NETWORK_PROFILE_PUBLIC + enabled = vrServer.networkProfileChecker.isSupported + optional = false + ignorable = true + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.STEAMVR_DISCONNECTED + enabled = true + optional = false + ignorable = true + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.TRACKER_ERROR + valid = true // Default to valid + enabled = true + optional = false + ignorable = false + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.TRACKERS_REST_CALIBRATION + enabled = true + optional = false + ignorable = true + visibility = TrackingChecklistStepVisibility.ALWAYS + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.FULL_RESET + enabled = true + optional = false + ignorable = false + visibility = TrackingChecklistStepVisibility.ALWAYS + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.MOUNTING_CALIBRATION + valid = false + enabled = vrServer.configManager.vrConfig.resetsConfig.lastMountingMethod == MountingMethods.AUTOMATIC + optional = false + ignorable = true + visibility = TrackingChecklistStepVisibility.ALWAYS + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.FEET_MOUNTING_CALIBRATION + valid = false + enabled = false + optional = false + ignorable = true + visibility = TrackingChecklistStepVisibility.ALWAYS + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.UNASSIGNED_HMD + enabled = true + optional = false + ignorable = false + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.STAY_ALIGNED_CONFIGURED + enabled = true + optional = true + ignorable = true + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + + steps.add( + TrackingChecklistStepT().apply { + id = TrackingChecklistStepId.VRCHAT_SETTINGS + enabled = vrServer.vrcConfigManager.isSupported + optional = true + ignorable = true + visibility = TrackingChecklistStepVisibility.WHEN_INVALID + }, + ) + } + + fun updateChecklist() { + val assignedTrackers = + vrServer.allTrackers.filter { it.trackerPosition != null && it.status != TrackerStatus.DISCONNECTED } + val imuTrackers = + assignedTrackers.filter { it.isImu() && it.trackerDataType != TrackerDataType.FLEX_ANGLE } + + val trackersWithError = + imuTrackers.filter { it.status == TrackerStatus.ERROR } + updateValidity( + TrackingChecklistStepId.TRACKER_ERROR, + trackersWithError.isEmpty(), + ) { + if (trackersWithError.isNotEmpty()) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistTrackerError + value = TrackingChecklistTrackerErrorT().apply { + trackersId = buildTrackersIds(trackersWithError) + } + } + } else { + it.extraData = null + } + } + + val trackerRequireReset = imuTrackers.filter { + it.status !== TrackerStatus.ERROR && !it.isInternal && it.allowReset && it.needReset + } + updateValidity(TrackingChecklistStepId.FULL_RESET, trackerRequireReset.isEmpty()) { + if (trackerRequireReset.isNotEmpty()) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistTrackerReset + value = TrackingChecklistTrackerResetT().apply { + trackersId = buildTrackersIds(trackerRequireReset) + } + } + resetMountingCompleted = false + feetResetMountingCompleted = false + } else { + it.extraData = null + } + } + + val hmd = + assignedTrackers.firstOrNull { it.isHmd && !it.isInternal && it.status.sendData } + val assignedHmd = hmd == null || vrServer.humanPoseManager.skeleton.headTracker != null + updateValidity(TrackingChecklistStepId.UNASSIGNED_HMD, assignedHmd) { + if (!assignedHmd) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistUnassignedHMD + value = TrackingChecklistUnassignedHMDT().apply { + trackerId = TrackerIdT().apply { + if (hmd.device != null) { + deviceId = DeviceIdT().apply { id = hmd.device.id } + } + trackerNum = hmd.trackerNum + } + } + } + } else { + it.extraData = null + } + } + + val trackersNeedCalibration = imuTrackers.filter { + it.hasCompletedRestCalibration == false + } + updateValidity( + TrackingChecklistStepId.TRACKERS_REST_CALIBRATION, + trackersNeedCalibration.isEmpty(), + ) { + // Don't show the step if none of the trackers connected support IMU calibration + it.enabled = imuTrackers.any { t -> + t.hasCompletedRestCalibration != null + } + if (trackersNeedCalibration.isNotEmpty()) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistNeedCalibration + value = TrackingChecklistNeedCalibrationT().apply { + trackersId = buildTrackersIds(trackersNeedCalibration) + } + } + } else { + it.extraData = null + } + } + + val steamVRBridge = vrServer.getVRBridge(ISteamVRBridge::class.java) + if (steamVRBridge != null) { + val steamvrConnected = steamVRBridge.isConnected() + updateValidity( + TrackingChecklistStepId.STEAMVR_DISCONNECTED, + steamvrConnected, + ) { + if (!steamvrConnected) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistSteamVRDisconnected + value = TrackingChecklistSteamVRDisconnectedT().apply { + bridgeSettingsName = steamVRBridge.getBridgeConfigKey() + } + } + } else { + it.extraData = null + } + } + } + + if (vrServer.networkProfileChecker.isSupported) { + updateValidity(TrackingChecklistStepId.NETWORK_PROFILE_PUBLIC, vrServer.networkProfileChecker.publicNetworks.isEmpty()) { + if (vrServer.networkProfileChecker.publicNetworks.isNotEmpty()) { + it.extraData = TrackingChecklistExtraDataUnion().apply { + type = TrackingChecklistExtraData.TrackingChecklistPublicNetworks + value = TrackingChecklistPublicNetworksT().apply { + adapters = vrServer.networkProfileChecker.publicNetworks.map { it.name }.toTypedArray() + } + } + } else { + it.extraData = null + } + } + } + + updateValidity(TrackingChecklistStepId.MOUNTING_CALIBRATION, resetMountingCompleted) { + it.enabled = vrServer.configManager.vrConfig.resetsConfig.lastMountingMethod == MountingMethods.AUTOMATIC + } + + updateValidity(TrackingChecklistStepId.FEET_MOUNTING_CALIBRATION, feetResetMountingCompleted) { + it.enabled = + vrServer.configManager.vrConfig.resetsConfig.lastMountingMethod == MountingMethods.AUTOMATIC && + !vrServer.configManager.vrConfig.resetsConfig.resetMountingFeet && + imuTrackers.any { t -> TrackerUtils.feetsBodyParts.contains(t.trackerPosition?.bodyPart) } + } + + updateValidity(TrackingChecklistStepId.STAY_ALIGNED_CONFIGURED, vrServer.configManager.vrConfig.stayAlignedConfig.enabled) + + listeners.forEach { it.onStepsUpdate() } + } + + private fun updateValidity(id: Int, valid: Boolean, beforeUpdate: ((step: TrackingChecklistStepT) -> Unit)? = null) { + require(id != TrackingChecklistStepId.UNKNOWN) { + "id is unknown" + } + val step = steps.find { it.id == id } ?: return + step.valid = valid + if (beforeUpdate != null) { + beforeUpdate(step) + } + } + + override fun onChange( + validity: VRCConfigValidity, + values: VRCConfigValues, + recommended: VRCConfigRecommendedValues, + muted: List, + ) { + updateValidity( + TrackingChecklistStepId.VRCHAT_SETTINGS, + VRCConfigValidity::class.java.declaredFields.asSequence().all { p -> + p.isAccessible = true + return@all p.get(validity) == true || muted.contains(p.name) + }, + ) + listeners.forEach { it.onStepsUpdate() } + } + + fun ignoreStep(step: TrackingChecklistStepT, ignore: Boolean) { + if (!step.ignorable) return + val ignoredSteps = vrServer.configManager.vrConfig.trackingChecklist.ignoredStepsIds + if (ignore && !ignoredSteps.contains(step.id)) { + ignoredSteps.add(step.id) + } else if (!ignore) { + ignoredSteps.remove(step.id) + } + vrServer.configManager.saveConfig() + } +} diff --git a/server/core/src/test/java/dev/slimevr/unit/LegTweaksTests.kt b/server/core/src/test/java/dev/slimevr/unit/LegTweaksTests.kt index 4676adc5f..830a60f9d 100644 --- a/server/core/src/test/java/dev/slimevr/unit/LegTweaksTests.kt +++ b/server/core/src/test/java/dev/slimevr/unit/LegTweaksTests.kt @@ -26,8 +26,8 @@ class LegTweaksTests { hasRotation = true, isComputed = true, imuType = null, - needsReset = false, - needsMounting = false, + allowReset = false, + allowMounting = false, isHmd = true, trackRotDirection = false, ) diff --git a/server/core/src/test/java/dev/slimevr/unit/MountingResetTests.kt b/server/core/src/test/java/dev/slimevr/unit/MountingResetTests.kt index c046ab914..c7de28c0d 100644 --- a/server/core/src/test/java/dev/slimevr/unit/MountingResetTests.kt +++ b/server/core/src/test/java/dev/slimevr/unit/MountingResetTests.kt @@ -45,8 +45,8 @@ class MountingResetTests { null, hasRotation = true, imuType = IMUType.UNKNOWN, - needsReset = true, - needsMounting = true, + allowReset = true, + allowMounting = true, trackRotDirection = false, ) @@ -130,8 +130,8 @@ class MountingResetTests { null, hasRotation = true, imuType = IMUType.UNKNOWN, - needsReset = true, - needsMounting = true, + allowReset = true, + allowMounting = true, trackRotDirection = false, ) diff --git a/server/core/src/test/java/dev/slimevr/unit/ReferenceAdjustmentsTests.kt b/server/core/src/test/java/dev/slimevr/unit/ReferenceAdjustmentsTests.kt index a28d8c85e..5a90b1ddb 100644 --- a/server/core/src/test/java/dev/slimevr/unit/ReferenceAdjustmentsTests.kt +++ b/server/core/src/test/java/dev/slimevr/unit/ReferenceAdjustmentsTests.kt @@ -93,7 +93,7 @@ class ReferenceAdjustmentsTests { null, hasRotation = true, imuType = IMUType.UNKNOWN, - needsReset = true, + allowReset = true, ) tracker.setRotation(trackerQuat) tracker.resetsHandler.resetFull(referenceQuat) @@ -125,7 +125,7 @@ class ReferenceAdjustmentsTests { null, hasRotation = true, imuType = IMUType.UNKNOWN, - needsReset = true, + allowReset = true, ) tracker.setRotation(trackerQuat) tracker.resetsHandler.resetYaw(referenceQuat) @@ -153,7 +153,7 @@ class ReferenceAdjustmentsTests { null, hasRotation = true, imuType = IMUType.UNKNOWN, - needsReset = true, + allowReset = true, ) tracker.setRotation(trackerQuat) tracker.resetsHandler.resetFull(referenceQuat) diff --git a/server/core/src/test/java/dev/slimevr/unit/TestTrackerSet.kt b/server/core/src/test/java/dev/slimevr/unit/TestTrackerSet.kt index 92ec22b60..cac3f3851 100644 --- a/server/core/src/test/java/dev/slimevr/unit/TestTrackerSet.kt +++ b/server/core/src/test/java/dev/slimevr/unit/TestTrackerSet.kt @@ -58,8 +58,8 @@ class TestTrackerSet( hasPosition = positional || isHmd, hasRotation = true, isComputed = computed || isHmd, - needsReset = resetHead || !isHmd, - needsMounting = resetHead || !isHmd, + allowReset = resetHead || !isHmd, + allowMounting = resetHead || !isHmd, isHmd = isHmd, trackRotDirection = false, ) diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/NetworkProfileChecker.kt b/server/desktop/src/main/java/dev/slimevr/desktop/DesktopNetworkProfileChecker.kt similarity index 78% rename from server/desktop/src/main/java/dev/slimevr/desktop/NetworkProfileChecker.kt rename to server/desktop/src/main/java/dev/slimevr/desktop/DesktopNetworkProfileChecker.kt index 0655c4023..3fbf79667 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/NetworkProfileChecker.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/DesktopNetworkProfileChecker.kt @@ -13,60 +13,15 @@ import com.sun.jna.platform.win32.WTypes import com.sun.jna.platform.win32.WinNT.HRESULT import com.sun.jna.ptr.IntByReference import com.sun.jna.ptr.PointerByReference +import dev.slimevr.ConnectivityFlags +import dev.slimevr.NetworkCategory +import dev.slimevr.NetworkInfo +import dev.slimevr.NetworkProfileChecker import dev.slimevr.VRServer import io.eiren.util.OperatingSystem -import solarxr_protocol.rpc.StatusData -import solarxr_protocol.rpc.StatusDataUnion -import solarxr_protocol.rpc.StatusPublicNetworkT import java.util.* import kotlin.concurrent.scheduleAtFixedRate -data class NetworkInfo( - val name: String?, - val description: String?, - val category: NetworkCategory?, - val connectivity: Set?, - val connected: Boolean?, -) - -/** - * @see NLM_NETWORK_CATEGORY enumeration (netlistmgr.h) - */ -enum class NetworkCategory(val value: Int) { - PUBLIC(0), - PRIVATE(1), - DOMAIN_AUTHENTICATED(2), - ; - - companion object { - fun fromInt(value: Int) = values().find { it.value == value } - } -} - -/** - * @see NLM_CONNECTIVITY enumeration (netlistmgr.h) - */ -enum class ConnectivityFlags(val value: Int) { - DISCONNECTED(0), - IPV4_NOTRAFFIC(0x1), - IPV6_NOTRAFFIC(0x2), - IPV4_SUBNET(0x10), - IPV4_LOCALNETWORK(0x20), - IPV4_INTERNET(0x40), - IPV6_SUBNET(0x100), - IPV6_LOCALNETWORK(0x200), - IPV6_INTERNET(0x400), - ; - - companion object { - fun fromInt(value: Int): Set = if (value == 0) { - setOf(DISCONNECTED) - } else { - values().filter { it != DISCONNECTED && (value and it.value) != 0 }.toSet() - } - } -} - /** * @see INetworkConnection interface (netlistmgr.h) */ @@ -308,38 +263,22 @@ fun enumerateNetworks(): List? { return null } -class NetworkProfileChecker(private val server: VRServer) { +class DesktopNetworkProfileChecker(private val server: VRServer) : NetworkProfileChecker() { private val updateTickTimer = Timer("NetworkProfileCheck") - private var lastPublicNetworkStatus: UInt = 0u - private var numPublicNetworks = 0 + private var publicNetworksLocal: List = listOf() + + override val isSupported: Boolean + get() = OperatingSystem.currentPlatform == OperatingSystem.WINDOWS + + override val publicNetworks: List + get() = publicNetworksLocal init { if (OperatingSystem.currentPlatform == OperatingSystem.WINDOWS) { this.updateTickTimer.scheduleAtFixedRate(0, 3000) { - val currentNumPublicNetworks = enumerateNetworks()?.filter { net -> + publicNetworksLocal = enumerateNetworks()?.filter { net -> net.connected == true && net.category == NetworkCategory.PUBLIC } ?: listOf() - val currentNumPublicNetworksCount = currentNumPublicNetworks.count() - - if (numPublicNetworks != currentNumPublicNetworksCount) { - numPublicNetworks = currentNumPublicNetworksCount - if (lastPublicNetworkStatus != 0u) { - server.statusSystem.removeStatus(lastPublicNetworkStatus) - lastPublicNetworkStatus = 0u - } - - if (lastPublicNetworkStatus == 0u && numPublicNetworks > 0) { - lastPublicNetworkStatus = server.statusSystem.addStatus( - StatusDataUnion().apply { - type = StatusData.StatusPublicNetwork - value = StatusPublicNetworkT().apply { - adapters = currentNumPublicNetworks.map { it.name }.toTypedArray() - } - }, - false, - ) - } - } } } } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt index 4e05dd316..22267c260 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/Main.kt @@ -129,12 +129,11 @@ fun main(args: Array) { { _ -> DesktopSerialHandler() }, { _ -> DesktopSerialFlashingHandler() }, { _ -> DesktopVRCConfigHandler() }, + { server -> DesktopNetworkProfileChecker(server) }, configManager = configManager, ) vrServer.start() - NetworkProfileChecker(vrServer) - // Start service for USB HID trackers DesktopHIDManager( "Sensors HID service", diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt b/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt index 863e17931..8a369ba34 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/SteamVRBridge.kt @@ -15,20 +15,18 @@ import dev.slimevr.tracking.trackers.TrackerRole.Companion.getById import dev.slimevr.tracking.trackers.TrackerUtils.getTrackerForSkeleton import dev.slimevr.util.ann.VRServerThread import io.eiren.util.collections.FastList -import solarxr_protocol.rpc.StatusData -import solarxr_protocol.rpc.StatusDataUnion -import solarxr_protocol.rpc.StatusSteamVRDisconnectedT abstract class SteamVRBridge( protected val server: VRServer, threadName: String, bridgeName: String, - protected val bridgeSettingsKey: String, + val bridgeSettingsKey: String, protected val shareableTrackers: List, ) : ProtobufBridge(bridgeName), Runnable { protected val runnerThread: Thread = Thread(this, threadName) protected val config: BridgeConfig = server.configManager.vrConfig.getBridge(bridgeSettingsKey) + var connected: Boolean = false @VRServerThread override fun startBridge() { @@ -187,7 +185,7 @@ abstract class SteamVRBridge( hasRotation = true, userEditable = true, isComputed = true, - needsReset = true, + allowReset = true, isHmd = isHmd, ) @@ -428,33 +426,13 @@ abstract class SteamVRBridge( } } - /** - * When 0, then it means null - */ - protected var lastSteamVRStatus: Int = 0 - @BridgeThread protected fun reportDisconnected() { - if (lastSteamVRStatus != 0) { - return - } - val statusData = StatusSteamVRDisconnectedT() - statusData.bridgeSettingsName = bridgeSettingsKey - - val status = StatusDataUnion() - status.type = StatusData.StatusSteamVRDisconnected - status.value = statusData - lastSteamVRStatus = instance.statusSystem - .addStatus(status, false).toInt() + connected = false } @BridgeThread protected fun reportConnected() { - if (lastSteamVRStatus == 0) { - return - } - instance.statusSystem - .removeStatus(lastSteamVRStatus.toUInt()) - lastSteamVRStatus = 0 + connected = true } } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java index d9b49bff3..1c29cedd2 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/linux/UnixSocketBridge.java @@ -8,6 +8,7 @@ import dev.slimevr.desktop.platform.SteamVRBridge; import dev.slimevr.tracking.trackers.Tracker; import io.eiren.util.ann.ThreadSafe; import io.eiren.util.logging.LogManager; +import org.jetbrains.annotations.NotNull; import java.io.File; import java.io.IOException; @@ -25,6 +26,7 @@ import java.util.List; public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { public final String socketPath; public final UnixDomainSocketAddress socketAddress; + private final String bridgeSettingsKey; private final ByteBuffer dst = ByteBuffer.allocate(2048).order(ByteOrder.LITTLE_ENDIAN); private final ByteBuffer src = ByteBuffer.allocate(2048).order(ByteOrder.LITTLE_ENDIAN); @@ -41,6 +43,7 @@ public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { List shareableTrackers ) { super(server, "Named socket thread", bridgeName, bridgeSettingsKey, shareableTrackers); + this.bridgeSettingsKey = bridgeSettingsKey; this.socketPath = socketPath; this.socketAddress = UnixDomainSocketAddress.of(socketPath); @@ -250,5 +253,11 @@ public class UnixSocketBridge extends SteamVRBridge implements AutoCloseable { public boolean isConnected() { return channel != null && channel.isConnected(); } + + @NotNull + @Override + public String getBridgeConfigKey() { + return bridgeSettingsKey; + } } diff --git a/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java index ab577eb9a..5099fccd8 100644 --- a/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java +++ b/server/desktop/src/main/java/dev/slimevr/desktop/platform/windows/WindowsNamedPipeBridge.java @@ -14,6 +14,7 @@ import dev.slimevr.desktop.platform.SteamVRBridge; import dev.slimevr.tracking.trackers.Tracker; import io.eiren.util.ann.ThreadSafe; import io.eiren.util.logging.LogManager; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.util.List; @@ -37,6 +38,7 @@ public class WindowsNamedPipeBridge extends SteamVRBridge { private static final Advapi32 adv32 = Advapi32.INSTANCE; protected final String pipeName; + protected final String bridgeSettingsKey; private final byte[] buffArray = new byte[2048]; protected WindowsPipe pipe; protected WinNT.HANDLE openEvent = k32.CreateEvent(null, false, false, null); @@ -63,6 +65,7 @@ public class WindowsNamedPipeBridge extends SteamVRBridge { ) { super(server, "Named pipe thread", bridgeName, bridgeSettingsKey, shareableTrackers); this.pipeName = pipeName; + this.bridgeSettingsKey = bridgeSettingsKey; overlappedWait.hEvent = rxEvent; } @@ -321,4 +324,10 @@ public class WindowsNamedPipeBridge extends SteamVRBridge { public boolean isConnected() { return pipe != null && pipe.state == PipeState.OPEN; } + + @NotNull + @Override + public String getBridgeConfigKey() { + return this.bridgeSettingsKey; + } } diff --git a/solarxr-protocol b/solarxr-protocol index 2fe6f9cf8..024c28cad 160000 --- a/solarxr-protocol +++ b/solarxr-protocol @@ -1 +1 @@ -Subproject commit 2fe6f9cf8d775174336e559b3bc8e948f3da12c2 +Subproject commit 024c28cadbe03002c66723f7e3ce8bf655392f0f