commit f6b790a515ad06b0dc137c021158238e6164fcde Author: Laurent Dubertrand Date: Mon Mar 9 19:35:08 2026 +0100 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2f0d303 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +node_modules +.npm-cache/* +client/.angular/cache/* +.env +server/server/data/privatechat.sqlite +server/server/data/privatechat.sqlite-shm +server/server/data/privatechat.sqlite-wal +server/server/data/master.key +client/dist/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d44cb3 --- /dev/null +++ b/README.md @@ -0,0 +1,99 @@ +# PrivateChat + +PrivateChat is a two-part application: + +- An Angular 21 + Bootstrap frontend for authentication, peer discovery, and direct chat. +- A Fastify + WebSocket backend for JWT-based authentication, Redis-backed sessions, and initial WebRTC signaling. + +Once two clients discover each other through the backend, text, JSON payloads, and file transfers move over a direct WebRTC data channel. Signaling is only allowed for clients with an active authenticated backend session. + +## Features + +- Register and log in with JWTs that are bound to active Redis sessions. +- Sign in with either a password or a registered WebAuthn access key. +- Persist users in a local SQLite database with encrypted credential storage. +- Persist the JWT signing secret in the SQLite database, encrypted at rest. +- Allow authenticated users to register multiple WebAuthn access keys. +- Discover online peers through a signaling WebSocket. +- Establish direct WebRTC peer connections. +- Exchange plain text messages, structured JSON payloads, and files. +- Keep signaling on the backend and user content on the peer-to-peer data channel. + +## Run locally + +Requirements: + +- Node.js 20+ recommended. +- npm 10+. +- A local Redis instance reachable at `redis://127.0.0.1:6379/0` by default. + +Install the root runner dependency: + +```bash +npm install +``` + +Start both apps: + +```bash +npm run dev +``` + +Configuration defaults now live in the repo root [`.env`](/var/approot/PrivateChat/.env). The backend loads that file with `dotenv` at startup, and the frontend generates `client/public/env.js` from the same file before `ng serve` and `ng build`. + +To serve the prebuilt Angular app from Fastify and run only one server: + +```bash +npm run build +npm run start --prefix server +``` + +The backend serves `client/dist/client/browser` on the same origin as the API and WebSocket endpoints. + +Default endpoints: + +- Frontend: `http://localhost:4200` +- Backend: `http://localhost:3000` + +The backend automatically creates: + +- `server/data/privatechat.sqlite` for users and encrypted secret material. +- `server/data/master.key` if `PRIVATECHAT_MASTER_KEY` is not supplied. + +The frontend lets you override the backend URL from the login screen if you need a different host or port. + +## Apple client + +The repo also includes a multiplatform SwiftUI client in `apple-client/` for macOS and iOS/iPadOS. + +- The native Settings UI manages backend URL, password auth, passkey auth, and access-key registration. +- The main chat surface embeds the Angular client bundle in a WKWebView, so the WebRTC chat workspace stays aligned with the web app. +- Generate the Xcode project with `xcodegen generate --spec apple-client/project.yml --project-root apple-client`. +- A build of the Apple app automatically rebuilds the Angular client into `apple-client/WebApp/` before bundling it. + +## Backend environment + +The backend accepts these environment variables: + +- `PORT`: HTTP and WebSocket port. Default `3000`. +- `REDIS_URL`: Local Redis connection string. Default `redis://127.0.0.1:6379/0`. +- `SESSION_TTL_SECONDS`: Redis session TTL. Default `43200`. +- `SQLITE_PATH`: Optional SQLite database path. +- `PRIVATECHAT_DATA_DIR`: Base directory for generated local storage. +- `PRIVATECHAT_MASTER_KEY`: Optional master key for encrypting SQLite secret material and user credentials. +- `PRIVATECHAT_MASTER_KEY_PATH`: Optional file path for the generated master key. +- `PRIVATECHAT_WEB_DIST_DIR`: Directory containing the prebuilt Angular browser bundle. Default `client/dist/client/browser`. +- `CORS_ORIGIN`: Optional allowed browser origin. If omitted, the server reflects request origins. +- `WEBAUTHN_ORIGIN`: Browser origin allowed to register access keys. Default `http://localhost:4200`. +- `WEBAUTHN_RP_ID`: WebAuthn RP ID. Default hostname of `WEBAUTHN_ORIGIN`. +- `WEBAUTHN_RP_NAME`: Friendly RP name for browser access-key prompts. Default `PrivateChat`. +- `WEBAUTHN_USER_VERIFICATION`: WebAuthn user-verification policy for access-key registration. Supported values: `discouraged`, `preferred`, `required`. Default `preferred`. +- `WEBAUTHN_CHALLENGE_TTL_SECONDS`: Pending access-key registration challenge TTL in Redis. Default `300`. + +## Frontend environment + +- `PRIVATECHAT_CLIENT_SERVER_URL`: Default backend URL preloaded into the Angular app before local storage overrides apply. + +## Production note + +This project uses the Fastify server only for auth and signaling. The chat payload itself stays peer-to-peer over WebRTC. For production deployment, replace the local master key strategy with your preferred secret-management system, keep Redis durable enough for your session policy, and configure TURN infrastructure if peers cannot connect with STUN alone. diff --git a/apple-client/PrivateChatApple.xcodeproj/project.pbxproj b/apple-client/PrivateChatApple.xcodeproj/project.pbxproj new file mode 100644 index 0000000..f148c1d --- /dev/null +++ b/apple-client/PrivateChatApple.xcodeproj/project.pbxproj @@ -0,0 +1,381 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXBuildFile section */ + 0CF99BBF9D1A04B9E2F5DFC8 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07E2A8E4DEFCE88D5553B5B /* ContentView.swift */; }; + 1A645AC02B000D539C39368C /* PasskeyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FF93F2A1FD25DB9E957AA6 /* PasskeyManager.swift */; }; + 3B90CADE868971A576AE57A7 /* AppModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16E71E386D6B12B015DC0103 /* AppModels.swift */; }; + 3BEB977AA98055EF05F97989 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 977F5A04FC063DC80BB9CE26 /* SettingsView.swift */; }; + 861A055BD65866A57B6BBC0E /* EmbeddedWebAppView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 09649C45C63E1AD1704C0D78 /* EmbeddedWebAppView.swift */; }; + D02DE21893F9BFC1519D511C /* BackendClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 591916AA72EF25C5E6F3CCBB /* BackendClient.swift */; }; + E854B030B8ACED01056B39FD /* PrivateChatAppleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF8901583248E9FADEEB357 /* PrivateChatAppleApp.swift */; }; + FD0B1329E00BFC563CA92B34 /* SettingsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8826CE950551697F8A2238FD /* SettingsStore.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 08E8FBDE6277D997AAD09FFE /* PrivateChatApple.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = PrivateChatApple.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 09649C45C63E1AD1704C0D78 /* EmbeddedWebAppView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedWebAppView.swift; sourceTree = ""; }; + 16E71E386D6B12B015DC0103 /* AppModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppModels.swift; sourceTree = ""; }; + 38FF93F2A1FD25DB9E957AA6 /* PasskeyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasskeyManager.swift; sourceTree = ""; }; + 591916AA72EF25C5E6F3CCBB /* BackendClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackendClient.swift; sourceTree = ""; }; + 8826CE950551697F8A2238FD /* SettingsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStore.swift; sourceTree = ""; }; + 977F5A04FC063DC80BB9CE26 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; + A07E2A8E4DEFCE88D5553B5B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + FDF8901583248E9FADEEB357 /* PrivateChatAppleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateChatAppleApp.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + 63815A93152EA7A84CECAE92 /* App */ = { + isa = PBXGroup; + children = ( + 16E71E386D6B12B015DC0103 /* AppModels.swift */, + 591916AA72EF25C5E6F3CCBB /* BackendClient.swift */, + A07E2A8E4DEFCE88D5553B5B /* ContentView.swift */, + 09649C45C63E1AD1704C0D78 /* EmbeddedWebAppView.swift */, + 38FF93F2A1FD25DB9E957AA6 /* PasskeyManager.swift */, + FDF8901583248E9FADEEB357 /* PrivateChatAppleApp.swift */, + 8826CE950551697F8A2238FD /* SettingsStore.swift */, + 977F5A04FC063DC80BB9CE26 /* SettingsView.swift */, + ); + name = App; + path = Sources/App; + sourceTree = ""; + }; + 66E649CB0A00080FE1C2DC25 /* Products */ = { + isa = PBXGroup; + children = ( + 08E8FBDE6277D997AAD09FFE /* PrivateChatApple.app */, + ); + name = Products; + sourceTree = ""; + }; + CBDB6BA6F0BD33470718D8EF = { + isa = PBXGroup; + children = ( + 63815A93152EA7A84CECAE92 /* App */, + 66E649CB0A00080FE1C2DC25 /* Products */, + ); + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 3438777E81C60FEE7970CAF2 /* PrivateChatApple */ = { + isa = PBXNativeTarget; + buildConfigurationList = 03EBB318C449F01FB0639745 /* Build configuration list for PBXNativeTarget "PrivateChatApple" */; + buildPhases = ( + 473BDD4E02B992BD309F5028 /* Build Embedded Angular Client */, + 0B1A447B1617CF6E1E4F4EA9 /* Sources */, + 04166E69061744AF9B27795E /* Copy Embedded Angular Client */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PrivateChatApple; + packageProductDependencies = ( + ); + productName = PrivateChatApple; + productReference = 08E8FBDE6277D997AAD09FFE /* PrivateChatApple.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 12B40BE574717A46063F45C8 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + TargetAttributes = { + 3438777E81C60FEE7970CAF2 = { + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = A55C1DFA666ADF74C56D34DA /* Build configuration list for PBXProject "PrivateChatApple" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = CBDB6BA6F0BD33470718D8EF; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 3438777E81C60FEE7970CAF2 /* PrivateChatApple */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + 04166E69061744AF9B27795E /* Copy Embedded Angular Client */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Copy Embedded Angular Client"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -euo pipefail\nDESTINATION=\"$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/WebApp\"\nrm -rf \"$DESTINATION\"\nmkdir -p \"$DESTINATION\"\ncp -R \"$SRCROOT/WebApp/.\" \"$DESTINATION\"\n"; + }; + 473BDD4E02B992BD309F5028 /* Build Embedded Angular Client */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Build Embedded Angular Client"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "set -euo pipefail\ncd \"$SRCROOT/..\"\nmkdir -p \"$SRCROOT/WebApp\"\nnpm run build --prefix client -- --base-href ./ --output-path \"$SRCROOT/WebApp\"\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0B1A447B1617CF6E1E4F4EA9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 3B90CADE868971A576AE57A7 /* AppModels.swift in Sources */, + D02DE21893F9BFC1519D511C /* BackendClient.swift in Sources */, + 0CF99BBF9D1A04B9E2F5DFC8 /* ContentView.swift in Sources */, + 861A055BD65866A57B6BBC0E /* EmbeddedWebAppView.swift in Sources */, + 1A645AC02B000D539C39368C /* PasskeyManager.swift in Sources */, + E854B030B8ACED01056B39FD /* PrivateChatAppleApp.swift in Sources */, + FD0B1329E00BFC563CA92B34 /* SettingsStore.swift in Sources */, + 3BEB977AA98055EF05F97989 /* SettingsView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 0356A63804EF725F92924B9B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_KEY_CFBundleDisplayName = PrivateChat; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_NAME = PrivateChatApple; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + 2E89E0E6371B30AE59C3646B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + MACOSX_DEPLOYMENT_TARGET = 14.4; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.privatechat.apple; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 6.0; + }; + name = Release; + }; + 8269FBF8D3B1C19B7CA65298 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + GENERATE_INFOPLIST_FILE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 17.4; + MACOSX_DEPLOYMENT_TARGET = 14.4; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.privatechat.apple; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; + }; + name = Debug; + }; + 9A5E4F1577926AC0869DBE31 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGNING_ALLOWED = NO; + CODE_SIGNING_REQUIRED = NO; + CODE_SIGN_IDENTITY = "iPhone Developer"; + INFOPLIST_KEY_CFBundleDisplayName = PrivateChat; + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.social-networking"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_NAME = PrivateChatApple; + SDKROOT = auto; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SUPPORTS_MACCATALYST = NO; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; + SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = YES; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 03EBB318C449F01FB0639745 /* Build configuration list for PBXNativeTarget "PrivateChatApple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 9A5E4F1577926AC0869DBE31 /* Debug */, + 0356A63804EF725F92924B9B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + A55C1DFA666ADF74C56D34DA /* Build configuration list for PBXProject "PrivateChatApple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8269FBF8D3B1C19B7CA65298 /* Debug */, + 2E89E0E6371B30AE59C3646B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 12B40BE574717A46063F45C8 /* Project object */; +} diff --git a/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/xcuserdata/laurent.xcuserdatad/UserInterfaceState.xcuserstate b/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/xcuserdata/laurent.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..e878cee Binary files /dev/null and b/apple-client/PrivateChatApple.xcodeproj/project.xcworkspace/xcuserdata/laurent.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/apple-client/PrivateChatApple.xcodeproj/xcuserdata/laurent.xcuserdatad/xcschemes/xcschememanagement.plist b/apple-client/PrivateChatApple.xcodeproj/xcuserdata/laurent.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..6d5f581 --- /dev/null +++ b/apple-client/PrivateChatApple.xcodeproj/xcuserdata/laurent.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + PrivateChatApple.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/apple-client/Sources/App/AppModels.swift b/apple-client/Sources/App/AppModels.swift new file mode 100644 index 0000000..3b6ab3b --- /dev/null +++ b/apple-client/Sources/App/AppModels.swift @@ -0,0 +1,133 @@ +import Foundation + +struct UserProfile: Codable, Equatable { + let id: String + let username: String + let displayName: String +} + +struct AuthResponse: Codable { + let token: String + let user: UserProfile +} + +struct AccessKeySummary: Codable, Equatable, Identifiable { + let id: String + let credentialId: String + let label: String + let transports: [String] + let deviceType: String + let backedUp: Bool + let aaguid: String + let createdAt: String +} + +struct AccessKeyListResponse: Codable { + let credentials: [AccessKeySummary] +} + +struct SessionResponse: Codable { + let user: UserProfile +} + +struct RegistrationOptionsResponse: Codable { + struct RelyingParty: Codable { + let name: String + let id: String + } + + struct UserEntity: Codable { + let id: String + let name: String + let displayName: String + } + + let expectedOrigin: String? + let rp: RelyingParty + let user: UserEntity + let challenge: String +} + +struct AuthenticationOptionsResponse: Codable { + let attemptId: String + let expectedOrigin: String? + let challenge: String + let rpId: String? +} + +struct APIErrorResponse: Codable, Error { + let message: String +} + +struct PasskeyRegistrationPayload: Encodable { + struct Response: Encodable { + let clientDataJSON: String + let attestationObject: String + let transports: [String]? + } + + let id: String + let rawId: String + let response: Response + let clientExtensionResults: [String: String] + let type: String +} + +struct PasskeyAuthenticationPayload: Encodable { + struct Response: Encodable { + let clientDataJSON: String + let authenticatorData: String + let signature: String + let userHandle: String? + } + + let id: String + let rawId: String + let response: Response + let clientExtensionResults: [String: String] + let type: String +} + +extension Data { + init?(base64URLEncoded value: String) { + var normalized = value.replacingOccurrences(of: "-", with: "+").replacingOccurrences(of: "_", with: "/") + let padding = (4 - normalized.count % 4) % 4 + normalized.append(String(repeating: "=", count: padding)) + self.init(base64Encoded: normalized) + } + + func base64URLEncodedString() -> String { + base64EncodedString() + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "=", with: "") + } +} + +extension Encodable { + func jsonString() -> String { + let encoder = JSONEncoder() + encoder.outputFormatting = [.withoutEscapingSlashes] + + guard let data = try? encoder.encode(AnyEncodable(self)), + let string = String(data: data, encoding: .utf8) + else { + return "null" + } + + return string + } +} + +private struct AnyEncodable: Encodable { + private let encodeValue: (Encoder) throws -> Void + + init(_ value: some Encodable) { + encodeValue = value.encode + } + + func encode(to encoder: Encoder) throws { + try encodeValue(encoder) + } +} + diff --git a/apple-client/Sources/App/BackendClient.swift b/apple-client/Sources/App/BackendClient.swift new file mode 100644 index 0000000..3fbd55d --- /dev/null +++ b/apple-client/Sources/App/BackendClient.swift @@ -0,0 +1,150 @@ +import Foundation + +struct BackendClient { + let baseURL: URL + + func register(username: String, password: String, displayName: String) async throws -> AuthResponse { + try await post( + path: "/api/auth/register", + body: RegisterRequest( + username: username, + password: password, + displayName: displayName.isEmpty ? nil : displayName + ), + token: nil + ) + } + + func login(username: String, password: String) async throws -> AuthResponse { + try await post( + path: "/api/auth/login", + body: LoginRequest(username: username, password: password), + token: nil + ) + } + + func restoreSession(token: String) async throws -> SessionResponse { + try await get(path: "/api/auth/session", token: token) + } + + func logout(token: String) async throws { + let _: EmptyResponse = try await post(path: "/api/auth/logout", body: EmptyBody(), token: token) + } + + func listAccessKeys(token: String) async throws -> [AccessKeySummary] { + let response: AccessKeyListResponse = try await get(path: "/api/webauthn/credentials", token: token) + return response.credentials + } + + func startAccessKeyRegistration(label: String?, token: String) async throws -> RegistrationOptionsResponse { + try await post( + path: "/api/webauthn/register/options", + body: RegisterAccessKeyRequest(label: label?.isEmpty == false ? label : nil), + token: token + ) + } + + func finishAccessKeyRegistration(payload: PasskeyRegistrationPayload, token: String) async throws { + let _: EmptyResponse = try await post( + path: "/api/webauthn/register/verify", + body: VerifyRegistrationRequest(credential: payload), + token: token + ) + } + + func startAccessKeyAuthentication() async throws -> AuthenticationOptionsResponse { + try await post(path: "/api/webauthn/authenticate/options", body: EmptyBody(), token: nil) + } + + func finishAccessKeyAuthentication( + attemptId: String, + payload: PasskeyAuthenticationPayload + ) async throws -> AuthResponse { + try await post( + path: "/api/webauthn/authenticate/verify", + body: VerifyAuthenticationRequest(attemptId: attemptId, credential: payload), + token: nil + ) + } + + private func get(path: String, token: String?) async throws -> Response { + var request = URLRequest(url: baseURL.appending(path: path)) + request.httpMethod = "GET" + request.setValue("application/json", forHTTPHeaderField: "Accept") + + if let token { + request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") + } + + return try await perform(request) + } + + private func post( + path: String, + body: Body, + token: String? + ) async throws -> Response { + var request = URLRequest(url: baseURL.appending(path: path)) + request.httpMethod = "POST" + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue("application/json", forHTTPHeaderField: "Content-Type") + + if let token { + request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") + } + + request.httpBody = try JSONEncoder().encode(body) + return try await perform(request) + } + + private func perform(_ request: URLRequest) async throws -> Response { + let (data, rawResponse) = try await URLSession.shared.data(for: request) + let response = rawResponse as? HTTPURLResponse + + guard let response else { + throw APIErrorResponse(message: "The backend did not return a valid HTTP response.") + } + + let decoder = JSONDecoder() + + if (200 ..< 300).contains(response.statusCode) { + if Response.self == EmptyResponse.self { + return EmptyResponse() as! Response + } + + return try decoder.decode(Response.self, from: data) + } + + if let apiError = try? decoder.decode(APIErrorResponse.self, from: data) { + throw apiError + } + + throw APIErrorResponse(message: "The backend returned HTTP \(response.statusCode).") + } +} + +private struct EmptyBody: Encodable {} +private struct EmptyResponse: Decodable {} +private struct RegisterRequest: Encodable { + let username: String + let password: String + let displayName: String? +} + +private struct LoginRequest: Encodable { + let username: String + let password: String +} + +private struct RegisterAccessKeyRequest: Encodable { + let label: String? +} + +private struct VerifyRegistrationRequest: Encodable { + let credential: PasskeyRegistrationPayload +} + +private struct VerifyAuthenticationRequest: Encodable { + let attemptId: String + let credential: PasskeyAuthenticationPayload +} diff --git a/apple-client/Sources/App/ContentView.swift b/apple-client/Sources/App/ContentView.swift new file mode 100644 index 0000000..098a6df --- /dev/null +++ b/apple-client/Sources/App/ContentView.swift @@ -0,0 +1,57 @@ +import SwiftUI + +struct ContentView: View { + @Bindable var settings: SettingsStore + + #if !os(macOS) + @State private var showSettings = false + #endif + + var body: some View { + NavigationStack { + EmbeddedWebAppView(settings: settings) + .toolbar { + #if os(macOS) + ToolbarItem(placement: .primaryAction) { + SettingsLink { + Image(systemName: "gearshape") + } + } + #else + ToolbarItem(placement: .topBarTrailing) { + Button { + showSettings = true + } label: { + Image(systemName: "gearshape") + } + } + #endif + } + .overlay(alignment: .bottom) { + if let user = settings.currentUser { + Text("Signed in as \(user.displayName)") + .font(.footnote) + .padding(.horizontal, 12) + .padding(.vertical, 8) + .background(.ultraThinMaterial, in: Capsule()) + .padding(.bottom, 16) + } + } + #if !os(macOS) + .sheet(isPresented: $showSettings) { + NavigationStack { + SettingsView(settings: settings) + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button("Done") { + showSettings = false + } + } + } + } + } + #endif + } + } +} + diff --git a/apple-client/Sources/App/EmbeddedWebAppView.swift b/apple-client/Sources/App/EmbeddedWebAppView.swift new file mode 100644 index 0000000..cd211cb --- /dev/null +++ b/apple-client/Sources/App/EmbeddedWebAppView.swift @@ -0,0 +1,112 @@ +import SwiftUI +import WebKit + +struct EmbeddedWebAppView: View { + @Bindable var settings: SettingsStore + + var body: some View { + PlatformWebView(script: settings.injectionScript, reloadToken: settings.webStateVersion) + .ignoresSafeArea() + } +} + +#if os(macOS) +struct PlatformWebView: NSViewRepresentable { + let script: String + let reloadToken: UUID + + func makeCoordinator() -> Coordinator { + Coordinator() + } + + func makeNSView(context: Context) -> WKWebView { + context.coordinator.makeWebView(script: script) + } + + func updateNSView(_ webView: WKWebView, context: Context) { + context.coordinator.update(webView: webView, script: script, reloadToken: reloadToken) + } +} +#else +struct PlatformWebView: UIViewRepresentable { + let script: String + let reloadToken: UUID + + func makeCoordinator() -> Coordinator { + Coordinator() + } + + func makeUIView(context: Context) -> WKWebView { + context.coordinator.makeWebView(script: script) + } + + func updateUIView(_ webView: WKWebView, context: Context) { + context.coordinator.update(webView: webView, script: script, reloadToken: reloadToken) + } +} +#endif + +final class Coordinator: NSObject, WKNavigationDelegate { + private var lastReloadToken: UUID? + private var pendingRefreshTask: Task? + + func makeWebView(script: String) -> WKWebView { + let configuration = WKWebViewConfiguration() + let contentController = WKUserContentController() + contentController.addUserScript( + WKUserScript(source: script, injectionTime: .atDocumentStart, forMainFrameOnly: true) + ) + configuration.userContentController = contentController + + let webView = WKWebView(frame: .zero, configuration: configuration) + webView.navigationDelegate = self + #if os(macOS) + webView.setValue(false, forKey: "drawsBackground") + #endif + loadIndex(into: webView) + return webView + } + + func update(webView: WKWebView, script: String, reloadToken: UUID) { + guard lastReloadToken != reloadToken else { + return + } + + lastReloadToken = reloadToken + pendingRefreshTask?.cancel() + pendingRefreshTask = Task { @MainActor [weak webView] in + await Task.yield() + + guard !Task.isCancelled, let webView else { + return + } + + webView.evaluateJavaScript(script) { _, _ in + DispatchQueue.main.async { + webView.reload() + } + } + } + } + + private func loadIndex(into webView: WKWebView) { + let indexURL = + Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "WebApp/browser") + ?? Bundle.main.url(forResource: "index", withExtension: "html", subdirectory: "WebApp") + + guard let indexURL else { + let fallbackHTML = """ + + +

Embedded chat bundle not found

+

The Apple app expects the Angular client to be built into the bundled WebApp folder.

+ + + """ + webView.loadHTMLString(fallbackHTML, baseURL: nil) + return + } + + webView.loadFileURL(indexURL, allowingReadAccessTo: indexURL.deletingLastPathComponent()) + } +} diff --git a/apple-client/Sources/App/PasskeyManager.swift b/apple-client/Sources/App/PasskeyManager.swift new file mode 100644 index 0000000..a9c1647 --- /dev/null +++ b/apple-client/Sources/App/PasskeyManager.swift @@ -0,0 +1,126 @@ +import AuthenticationServices +import Foundation + +#if os(macOS) +import AppKit +#else +import UIKit +#endif + +@MainActor +final class PasskeyManager: NSObject { + private var continuation: CheckedContinuation? + + func register(options: RegistrationOptionsResponse) async throws -> PasskeyRegistrationPayload { + guard let challengeData = Data(base64URLEncoded: options.challenge), + let userData = Data(base64URLEncoded: options.user.id) + else { + throw APIErrorResponse(message: "The backend returned malformed access key registration options.") + } + + let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: options.rp.id) + let clientData = ASPublicKeyCredentialClientData( + challenge: challengeData, + origin: options.expectedOrigin ?? "http://localhost:4200" + ) + let request = provider.createCredentialRegistrationRequest( + clientData: clientData, + name: options.user.name, + userID: userData + ) + + let authorization = try await perform(requests: [request]) + + guard let registration = authorization.credential as? ASAuthorizationPlatformPublicKeyCredentialRegistration else { + throw APIErrorResponse(message: "The platform did not return a valid access key registration.") + } + + return PasskeyRegistrationPayload( + id: registration.credentialID.base64URLEncodedString(), + rawId: registration.credentialID.base64URLEncodedString(), + response: .init( + clientDataJSON: registration.rawClientDataJSON.base64URLEncodedString(), + attestationObject: registration.rawAttestationObject?.base64URLEncodedString() ?? "", + transports: nil + ), + clientExtensionResults: [:], + type: "public-key" + ) + } + + func authenticate(options: AuthenticationOptionsResponse) async throws -> PasskeyAuthenticationPayload { + guard let challengeData = Data(base64URLEncoded: options.challenge) else { + throw APIErrorResponse(message: "The backend returned malformed access key sign-in options.") + } + + let rpId = options.rpId + ?? URL(string: options.expectedOrigin ?? "")?.host + ?? "localhost" + let provider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: rpId) + let clientData = ASPublicKeyCredentialClientData( + challenge: challengeData, + origin: options.expectedOrigin ?? "http://localhost:4200" + ) + let request = provider.createCredentialAssertionRequest(clientData: clientData) + let authorization = try await perform(requests: [request]) + + guard let assertion = authorization.credential as? ASAuthorizationPlatformPublicKeyCredentialAssertion else { + throw APIErrorResponse(message: "The platform did not return a valid access key assertion.") + } + + return PasskeyAuthenticationPayload( + id: assertion.credentialID.base64URLEncodedString(), + rawId: assertion.credentialID.base64URLEncodedString(), + response: .init( + clientDataJSON: assertion.rawClientDataJSON.base64URLEncodedString(), + authenticatorData: assertion.rawAuthenticatorData.base64URLEncodedString(), + signature: assertion.signature.base64URLEncodedString(), + userHandle: assertion.userID.base64URLEncodedString() + ), + clientExtensionResults: [:], + type: "public-key" + ) + } + + private func perform(requests: [ASAuthorizationRequest]) async throws -> ASAuthorization { + try await withCheckedThrowingContinuation { continuation in + self.continuation = continuation + let controller = ASAuthorizationController(authorizationRequests: requests) + controller.delegate = self + controller.presentationContextProvider = self + controller.performRequests() + } + } +} + +extension PasskeyManager: ASAuthorizationControllerDelegate { + func authorizationController( + controller _: ASAuthorizationController, + didCompleteWithAuthorization authorization: ASAuthorization + ) { + continuation?.resume(returning: authorization) + continuation = nil + } + + func authorizationController( + controller _: ASAuthorizationController, + didCompleteWithError error: Error + ) { + continuation?.resume(throwing: error) + continuation = nil + } +} + +extension PasskeyManager: ASAuthorizationControllerPresentationContextProviding { + func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { + #if os(macOS) + return NSApplication.shared.keyWindow ?? NSApplication.shared.windows.first ?? ASPresentationAnchor() + #else + return UIApplication.shared.connectedScenes + .compactMap { $0 as? UIWindowScene } + .flatMap(\.windows) + .first(where: \.isKeyWindow) ?? ASPresentationAnchor() + #endif + } +} + diff --git a/apple-client/Sources/App/PrivateChatAppleApp.swift b/apple-client/Sources/App/PrivateChatAppleApp.swift new file mode 100644 index 0000000..ddd353e --- /dev/null +++ b/apple-client/Sources/App/PrivateChatAppleApp.swift @@ -0,0 +1,18 @@ +import SwiftUI + +@main +struct PrivateChatAppleApp: App { + @State private var settings = SettingsStore() + + var body: some Scene { + WindowGroup { + ContentView(settings: settings) + } + + #if os(macOS) + Settings { + SettingsView(settings: settings) + } + #endif + } +} diff --git a/apple-client/Sources/App/SettingsStore.swift b/apple-client/Sources/App/SettingsStore.swift new file mode 100644 index 0000000..5a17ebf --- /dev/null +++ b/apple-client/Sources/App/SettingsStore.swift @@ -0,0 +1,227 @@ +import Foundation +import Observation + +@MainActor +@Observable +final class SettingsStore { + enum AuthMode: String, CaseIterable, Identifiable { + case login + case register + + var id: String { rawValue } + } + + var backendURLString: String + var currentUser: UserProfile? + var accessKeys: [AccessKeySummary] + var authMode: AuthMode = .login + var username = "" + var password = "" + var displayName = "" + var accessKeyLabel = "" + var infoMessage: String? + var errorMessage: String? + var isBusy = false + private(set) var webStateVersion = UUID() + + private let defaults = UserDefaults.standard + private let passkeyManager = PasskeyManager() + + private enum Keys { + static let backendURL = "privatechat.apple.backendURL" + static let token = "privatechat.apple.token" + static let user = "privatechat.apple.user" + } + + init() { + backendURLString = defaults.string(forKey: Keys.backendURL) ?? "http://localhost:3000" + accessKeys = [] + + if let data = defaults.data(forKey: Keys.user), + let user = try? JSONDecoder().decode(UserProfile.self, from: data) + { + currentUser = user + } + + Task { + await restoreSessionIfPossible() + } + } + + var token: String? { + defaults.string(forKey: Keys.token) + } + + var isAuthenticated: Bool { + token != nil && currentUser != nil + } + + var injectionScript: String { + let serverValue = backendURLString.jsonString() + let tokenValue = (token ?? "").jsonString() + let userValue: String + + if let currentUser { + userValue = currentUser.jsonString() + } else { + userValue = "null" + } + + return """ + (function() { + try { + localStorage.setItem('privatechat.embeddedMode', '1'); + localStorage.setItem('privatechat.serverUrl', \(serverValue)); + if (\(tokenValue) && \(tokenValue) !== '""') { + localStorage.setItem('privatechat.token', \(tokenValue)); + } else { + localStorage.removeItem('privatechat.token'); + } + if (\(userValue) !== null) { + localStorage.setItem('privatechat.user', JSON.stringify(\(userValue))); + } else { + localStorage.removeItem('privatechat.user'); + } + } catch (error) { + console.error('Failed to sync native settings into localStorage', error); + } + })(); + """ + } + + func saveBackendURL() { + defaults.set(backendURLString, forKey: Keys.backendURL) + invalidateWebState(info: "Backend URL updated.") + } + + func authenticate() async { + await runTask { [self] in + switch authMode { + case .login: + let response = try await self.apiClient().login(username: self.username, password: self.password) + try await self.applyAuthResponse(response, success: "Signed in as \(response.user.displayName).") + case .register: + let response = try await self.apiClient().register( + username: self.username, + password: self.password, + displayName: self.displayName + ) + try await self.applyAuthResponse(response, success: "Account created for \(response.user.displayName).") + } + } + } + + func signInWithAccessKey() async { + await runTask { [self] in + let options = try await self.apiClient().startAccessKeyAuthentication() + let credential = try await self.passkeyManager.authenticate(options: options) + let response = try await self.apiClient().finishAccessKeyAuthentication( + attemptId: options.attemptId, + payload: credential + ) + try await self.applyAuthResponse(response, success: "Signed in as \(response.user.displayName).") + } + } + + func registerAccessKey() async { + guard let token else { + errorMessage = "Sign in before registering an access key." + return + } + + await runTask { [self] in + let options = try await self.apiClient().startAccessKeyRegistration( + label: self.accessKeyLabel.isEmpty ? nil : self.accessKeyLabel, + token: token + ) + let payload = try await self.passkeyManager.register(options: options) + try await self.apiClient().finishAccessKeyRegistration(payload: payload, token: token) + self.accessKeyLabel = "" + self.accessKeys = try await self.apiClient().listAccessKeys(token: token) + self.infoMessage = "Access key registered." + } + } + + func signOut() async { + guard let token else { + clearAuthState(info: "Signed out.") + return + } + + await runTask { [self] in + try? await self.apiClient().logout(token: token) + self.clearAuthState(info: "Signed out.") + self.authMode = .login + } + } + + func restoreSessionIfPossible() async { + guard let token else { + return + } + + await runTask(clearMessages: false) { [self] in + let response = try await self.apiClient().restoreSession(token: token) + self.currentUser = response.user + self.accessKeys = try await self.apiClient().listAccessKeys(token: token) + self.infoMessage = "Restored session for \(response.user.displayName)." + self.invalidateWebState() + } + } + + private func apiClient() throws -> BackendClient { + guard let url = URL(string: backendURLString.trimmingCharacters(in: .whitespacesAndNewlines)), + url.scheme?.hasPrefix("http") == true + else { + throw APIErrorResponse(message: "Enter a valid backend URL before continuing.") + } + + return BackendClient(baseURL: url) + } + + private func applyAuthResponse(_ response: AuthResponse, success: String) async throws { + currentUser = response.user + defaults.set(response.token, forKey: Keys.token) + defaults.set(try JSONEncoder().encode(response.user), forKey: Keys.user) + accessKeys = try await apiClient().listAccessKeys(token: response.token) + password = "" + infoMessage = success + invalidateWebState() + } + + private func clearAuthState(info: String) { + currentUser = nil + accessKeys = [] + defaults.removeObject(forKey: Keys.token) + defaults.removeObject(forKey: Keys.user) + infoMessage = info + errorMessage = nil + invalidateWebState() + } + + private func invalidateWebState(info: String? = nil) { + if let info { + infoMessage = info + } + + webStateVersion = UUID() + } + + private func runTask(clearMessages: Bool = true, operation: @escaping () async throws -> Void) async { + if clearMessages { + errorMessage = nil + infoMessage = nil + } + + isBusy = true + defer { isBusy = false } + + do { + try await operation() + } catch let apiError as APIErrorResponse { + errorMessage = apiError.message + } catch { + errorMessage = error.localizedDescription + } + } +} diff --git a/apple-client/Sources/App/SettingsView.swift b/apple-client/Sources/App/SettingsView.swift new file mode 100644 index 0000000..f470975 --- /dev/null +++ b/apple-client/Sources/App/SettingsView.swift @@ -0,0 +1,127 @@ +import SwiftUI + +struct SettingsView: View { + @Bindable var settings: SettingsStore + + var body: some View { + Form { + Section("Backend") { + TextField("Backend URL", text: $settings.backendURLString) + .onSubmit { + settings.saveBackendURL() + } + .platformCredentialField() + + Button("Apply Backend URL") { + settings.saveBackendURL() + } + } + + Section("Session") { + if let user = settings.currentUser { + LabeledContent("Signed in as", value: user.displayName) + LabeledContent("Username", value: user.username) + + Button("Sign out", role: .destructive) { + Task { + await settings.signOut() + } + } + } else { + Picker("Mode", selection: $settings.authMode) { + ForEach(SettingsStore.AuthMode.allCases) { mode in + Text(mode == .login ? "Log in" : "Register").tag(mode) + } + } + .pickerStyle(.segmented) + + if settings.authMode == .register { + TextField("Display name", text: $settings.displayName) + } + + TextField("Username", text: $settings.username) + .platformCredentialField() + + SecureField("Password", text: $settings.password) + + Button(settings.authMode == .login ? "Authenticate" : "Create account") { + Task { + await settings.authenticate() + } + } + .disabled(settings.isBusy) + + Button("Use access key") { + Task { + await settings.signInWithAccessKey() + } + } + .disabled(settings.isBusy) + } + } + + Section("Access Keys") { + if settings.currentUser == nil { + Text("Sign in before registering or listing access keys.") + .foregroundStyle(.secondary) + } else { + TextField("New access key label", text: $settings.accessKeyLabel) + Button("Register access key") { + Task { + await settings.registerAccessKey() + } + } + .disabled(settings.isBusy) + + if settings.accessKeys.isEmpty { + Text("No access keys registered yet.") + .foregroundStyle(.secondary) + } else { + ForEach(settings.accessKeys) { key in + VStack(alignment: .leading, spacing: 4) { + Text(key.label) + .font(.headline) + Text("Device: \(key.deviceType)\(key.backedUp ? " / backed up" : "")") + .font(.subheadline) + .foregroundStyle(.secondary) + Text("Transports: \(key.transports.isEmpty ? "unspecified" : key.transports.joined(separator: ", "))") + .font(.footnote) + .foregroundStyle(.secondary) + } + .padding(.vertical, 4) + } + } + } + } + + if let infoMessage = settings.infoMessage { + Section("Status") { + Text(infoMessage) + .foregroundStyle(.secondary) + } + } + + if let errorMessage = settings.errorMessage { + Section("Error") { + Text(errorMessage) + .foregroundStyle(.red) + } + } + } + .formStyle(.grouped) + .padding() + .frame(minWidth: 420, minHeight: 520) + } +} + +private extension View { + @ViewBuilder + func platformCredentialField() -> some View { + #if os(iOS) + textInputAutocapitalization(.never) + .autocorrectionDisabled() + #else + self + #endif + } +} diff --git a/apple-client/WebApp/3rdpartylicenses.txt b/apple-client/WebApp/3rdpartylicenses.txt new file mode 100644 index 0000000..8fbe069 --- /dev/null +++ b/apple-client/WebApp/3rdpartylicenses.txt @@ -0,0 +1,355 @@ + +-------------------------------------------------------------------------------- +Package: @angular/core +License: "MIT" + +The MIT License + +Copyright (c) 2010-2026 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- +Package: rxjs +License: "Apache-2.0" + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) 2015-2018 Google, Inc., Netflix, Inc., Microsoft Corp. and contributors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +-------------------------------------------------------------------------------- +Package: tslib +License: "0BSD" + +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +-------------------------------------------------------------------------------- +Package: @angular/common +License: "MIT" + +The MIT License + +Copyright (c) 2010-2026 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- +Package: @angular/platform-browser +License: "MIT" + +The MIT License + +Copyright (c) 2010-2026 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- +Package: @angular/router +License: "MIT" + +The MIT License + +Copyright (c) 2010-2026 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- +Package: @angular/forms +License: "MIT" + +The MIT License + +Copyright (c) 2010-2026 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-------------------------------------------------------------------------------- diff --git a/apple-client/WebApp/browser/favicon.ico b/apple-client/WebApp/browser/favicon.ico new file mode 100644 index 0000000..57614f9 Binary files /dev/null and b/apple-client/WebApp/browser/favicon.ico differ diff --git a/apple-client/WebApp/browser/index.html b/apple-client/WebApp/browser/index.html new file mode 100644 index 0000000..c9d0f92 --- /dev/null +++ b/apple-client/WebApp/browser/index.html @@ -0,0 +1,16 @@ + + + + + PrivateChat + + + + + + + + + + + diff --git a/apple-client/WebApp/browser/main-YTU56RI2.js b/apple-client/WebApp/browser/main-YTU56RI2.js new file mode 100644 index 0000000..1ba77c8 --- /dev/null +++ b/apple-client/WebApp/browser/main-YTU56RI2.js @@ -0,0 +1,8 @@ +var qv=Object.defineProperty,Zv=Object.defineProperties;var Yv=Object.getOwnPropertyDescriptors;var kf=Object.getOwnPropertySymbols;var Kv=Object.prototype.hasOwnProperty,Qv=Object.prototype.propertyIsEnumerable;var Ff=(e,t,n)=>t in e?qv(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,y=(e,t)=>{for(var n in t||={})Kv.call(t,n)&&Ff(e,n,t[n]);if(kf)for(var n of kf(t))Qv.call(t,n)&&Ff(e,n,t[n]);return e},A=(e,t)=>Zv(e,Yv(t));var Me=null,Xi=!1,Yc=1,Jv=null,ye=Symbol("SIGNAL");function M(e){let t=Me;return Me=e,t}function es(){return Me}var un={version:0,lastCleanEpoch:0,dirty:!1,producers:void 0,producersTail:void 0,consumers:void 0,consumersTail:void 0,recomputing:!1,consumerAllowSignalWrites:!1,consumerIsAlwaysLive:!1,kind:"unknown",producerMustRecompute:()=>!1,producerRecomputeValue:()=>{},consumerMarkedDirty:()=>{},consumerOnSignalRead:()=>{}};function Fn(e){if(Xi)throw new Error("");if(Me===null)return;Me.consumerOnSignalRead(e);let t=Me.producersTail;if(t!==void 0&&t.producer===e)return;let n,r=Me.recomputing;if(r&&(n=t!==void 0?t.nextProducer:Me.producers,n!==void 0&&n.producer===e)){Me.producersTail=n,n.lastReadVersion=e.version;return}let o=e.consumersTail;if(o!==void 0&&o.consumer===Me&&(!r||eD(o,Me)))return;let i=Ir(Me),s={producer:e,consumer:Me,nextProducer:n,prevConsumer:o,lastReadVersion:e.version,nextConsumer:void 0};Me.producersTail=s,t!==void 0?t.nextProducer=s:Me.producers=s,i&&Bf(e,s)}function Lf(){Yc++}function Ln(e){if(!(Ir(e)&&!e.dirty)&&!(!e.dirty&&e.lastCleanEpoch===Yc)){if(!e.producerMustRecompute(e)&&!wo(e)){wr(e);return}e.producerRecomputeValue(e),wr(e)}}function Kc(e){if(e.consumers===void 0)return;let t=Xi;Xi=!0;try{for(let n=e.consumers;n!==void 0;n=n.nextConsumer){let r=n.consumer;r.dirty||Xv(r)}}finally{Xi=t}}function Qc(){return Me?.consumerAllowSignalWrites!==!1}function Xv(e){e.dirty=!0,Kc(e),e.consumerMarkedDirty?.(e)}function wr(e){e.dirty=!1,e.lastCleanEpoch=Yc}function dn(e){return e&&jf(e),M(e)}function jf(e){e.producersTail=void 0,e.recomputing=!0}function jn(e,t){M(t),e&&Vf(e)}function Vf(e){e.recomputing=!1;let t=e.producersTail,n=t!==void 0?t.nextProducer:e.producers;if(n!==void 0){if(Ir(e))do n=Jc(n);while(n!==void 0);t!==void 0?t.nextProducer=void 0:e.producers=void 0}}function wo(e){for(let t=e.producers;t!==void 0;t=t.nextProducer){let n=t.producer,r=t.lastReadVersion;if(r!==n.version||(Ln(n),r!==n.version))return!0}return!1}function Vn(e){if(Ir(e)){let t=e.producers;for(;t!==void 0;)t=Jc(t)}e.producers=void 0,e.producersTail=void 0,e.consumers=void 0,e.consumersTail=void 0}function Bf(e,t){let n=e.consumersTail,r=Ir(e);if(n!==void 0?(t.nextConsumer=n.nextConsumer,n.nextConsumer=t):(t.nextConsumer=void 0,e.consumers=t),t.prevConsumer=n,e.consumersTail=t,!r)for(let o=e.producers;o!==void 0;o=o.nextProducer)Bf(o.producer,o)}function Jc(e){let t=e.producer,n=e.nextProducer,r=e.nextConsumer,o=e.prevConsumer;if(e.nextConsumer=void 0,e.prevConsumer=void 0,r!==void 0?r.prevConsumer=o:t.consumersTail=o,o!==void 0)o.nextConsumer=r;else if(t.consumers=r,!Ir(t)){let i=t.producers;for(;i!==void 0;)i=Jc(i)}return n}function Ir(e){return e.consumerIsAlwaysLive||e.consumers!==void 0}function Io(e){Jv?.(e)}function eD(e,t){let n=t.producersTail;if(n!==void 0){let r=t.producers;do{if(r===e)return!0;if(r===n)break;r=r.nextProducer}while(r!==void 0)}return!1}function So(e,t){return Object.is(e,t)}function ts(e,t){let n=Object.create(tD);n.computation=e,t!==void 0&&(n.equal=t);let r=()=>{if(Ln(n),Fn(n),n.value===bt)throw n.error;return n.value};return r[ye]=n,Io(n),r}var ln=Symbol("UNSET"),kn=Symbol("COMPUTING"),bt=Symbol("ERRORED"),tD=A(y({},un),{value:ln,dirty:!0,error:null,equal:So,kind:"computed",producerMustRecompute(e){return e.value===ln||e.value===kn},producerRecomputeValue(e){if(e.value===kn)throw new Error("");let t=e.value;e.value=kn;let n=dn(e),r,o=!1;try{r=e.computation(),M(null),o=t!==ln&&t!==bt&&r!==bt&&e.equal(t,r)}catch(i){r=bt,e.error=i}finally{jn(e,n)}if(o){e.value=t;return}e.value=r,e.version++}});function nD(){throw new Error}var Uf=nD;function Hf(e){Uf(e)}function Xc(e){Uf=e}var rD=null;function el(e,t){let n=Object.create(rs);n.value=e,t!==void 0&&(n.equal=t);let r=()=>$f(n);return r[ye]=n,Io(n),[r,s=>Bn(n,s),s=>ns(n,s)]}function $f(e){return Fn(e),e.value}function Bn(e,t){Qc()||Hf(e),e.equal(e.value,t)||(e.value=t,oD(e))}function ns(e,t){Qc()||Hf(e),Bn(e,t(e.value))}var rs=A(y({},un),{equal:So,value:void 0,kind:"signal"});function oD(e){e.version++,Lf(),Kc(e),rD?.(e)}var tl=A(y({},un),{consumerIsAlwaysLive:!0,consumerAllowSignalWrites:!0,dirty:!0,kind:"effect"});function nl(e){if(e.dirty=!1,e.version>0&&!wo(e))return;e.version++;let t=dn(e);try{e.cleanup(),e.fn()}finally{jn(e,t)}}function P(e){return typeof e=="function"}function Sr(e){let n=e(r=>{Error.call(r),r.stack=new Error().stack});return n.prototype=Object.create(Error.prototype),n.prototype.constructor=n,n}var os=Sr(e=>function(n){e(this),this.message=n?`${n.length} errors occurred during unsubscription: +${n.map((r,o)=>`${o+1}) ${r.toString()}`).join(` + `)}`:"",this.name="UnsubscriptionError",this.errors=n});function Mo(e,t){if(e){let n=e.indexOf(t);0<=n&&e.splice(n,1)}}var _e=class e{constructor(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}unsubscribe(){let t;if(!this.closed){this.closed=!0;let{_parentage:n}=this;if(n)if(this._parentage=null,Array.isArray(n))for(let i of n)i.remove(this);else n.remove(this);let{initialTeardown:r}=this;if(P(r))try{r()}catch(i){t=i instanceof os?i.errors:[i]}let{_finalizers:o}=this;if(o){this._finalizers=null;for(let i of o)try{zf(i)}catch(s){t=t??[],s instanceof os?t=[...t,...s.errors]:t.push(s)}}if(t)throw new os(t)}}add(t){var n;if(t&&t!==this)if(this.closed)zf(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(n=this._finalizers)!==null&&n!==void 0?n:[]).push(t)}}_hasParent(t){let{_parentage:n}=this;return n===t||Array.isArray(n)&&n.includes(t)}_addParent(t){let{_parentage:n}=this;this._parentage=Array.isArray(n)?(n.push(t),n):n?[n,t]:t}_removeParent(t){let{_parentage:n}=this;n===t?this._parentage=null:Array.isArray(n)&&Mo(n,t)}remove(t){let{_finalizers:n}=this;n&&Mo(n,t),t instanceof e&&t._removeParent(this)}};_e.EMPTY=(()=>{let e=new _e;return e.closed=!0,e})();var rl=_e.EMPTY;function is(e){return e instanceof _e||e&&"closed"in e&&P(e.remove)&&P(e.add)&&P(e.unsubscribe)}function zf(e){P(e)?e():e.unsubscribe()}var ht={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var Mr={setTimeout(e,t,...n){let{delegate:r}=Mr;return r?.setTimeout?r.setTimeout(e,t,...n):setTimeout(e,t,...n)},clearTimeout(e){let{delegate:t}=Mr;return(t?.clearTimeout||clearTimeout)(e)},delegate:void 0};function ss(e){Mr.setTimeout(()=>{let{onUnhandledError:t}=ht;if(t)t(e);else throw e})}function To(){}var Gf=ol("C",void 0,void 0);function Wf(e){return ol("E",void 0,e)}function qf(e){return ol("N",e,void 0)}function ol(e,t,n){return{kind:e,value:t,error:n}}var Un=null;function Tr(e){if(ht.useDeprecatedSynchronousErrorHandling){let t=!Un;if(t&&(Un={errorThrown:!1,error:null}),e(),t){let{errorThrown:n,error:r}=Un;if(Un=null,n)throw r}}else e()}function Zf(e){ht.useDeprecatedSynchronousErrorHandling&&Un&&(Un.errorThrown=!0,Un.error=e)}var Hn=class extends _e{constructor(t){super(),this.isStopped=!1,t?(this.destination=t,is(t)&&t.add(this)):this.destination=aD}static create(t,n,r){return new fn(t,n,r)}next(t){this.isStopped?sl(qf(t),this):this._next(t)}error(t){this.isStopped?sl(Wf(t),this):(this.isStopped=!0,this._error(t))}complete(){this.isStopped?sl(Gf,this):(this.isStopped=!0,this._complete())}unsubscribe(){this.closed||(this.isStopped=!0,super.unsubscribe(),this.destination=null)}_next(t){this.destination.next(t)}_error(t){try{this.destination.error(t)}finally{this.unsubscribe()}}_complete(){try{this.destination.complete()}finally{this.unsubscribe()}}},iD=Function.prototype.bind;function il(e,t){return iD.call(e,t)}var al=class{constructor(t){this.partialObserver=t}next(t){let{partialObserver:n}=this;if(n.next)try{n.next(t)}catch(r){as(r)}}error(t){let{partialObserver:n}=this;if(n.error)try{n.error(t)}catch(r){as(r)}else as(t)}complete(){let{partialObserver:t}=this;if(t.complete)try{t.complete()}catch(n){as(n)}}},fn=class extends Hn{constructor(t,n,r){super();let o;if(P(t)||!t)o={next:t??void 0,error:n??void 0,complete:r??void 0};else{let i;this&&ht.useDeprecatedNextContext?(i=Object.create(t),i.unsubscribe=()=>this.unsubscribe(),o={next:t.next&&il(t.next,i),error:t.error&&il(t.error,i),complete:t.complete&&il(t.complete,i)}):o=t}this.destination=new al(o)}};function as(e){ht.useDeprecatedSynchronousErrorHandling?Zf(e):ss(e)}function sD(e){throw e}function sl(e,t){let{onStoppedNotification:n}=ht;n&&Mr.setTimeout(()=>n(e,t))}var aD={closed:!0,next:To,error:sD,complete:To};var Ar=typeof Symbol=="function"&&Symbol.observable||"@@observable";function pt(e){return e}function cl(...e){return ll(e)}function ll(e){return e.length===0?pt:e.length===1?e[0]:function(n){return e.reduce((r,o)=>o(r),n)}}var j=(()=>{class e{constructor(n){n&&(this._subscribe=n)}lift(n){let r=new e;return r.source=this,r.operator=n,r}subscribe(n,r,o){let i=lD(n)?n:new fn(n,r,o);return Tr(()=>{let{operator:s,source:a}=this;i.add(s?s.call(i,a):a?this._subscribe(i):this._trySubscribe(i))}),i}_trySubscribe(n){try{return this._subscribe(n)}catch(r){n.error(r)}}forEach(n,r){return r=Yf(r),new r((o,i)=>{let s=new fn({next:a=>{try{n(a)}catch(c){i(c),s.unsubscribe()}},error:i,complete:o});this.subscribe(s)})}_subscribe(n){var r;return(r=this.source)===null||r===void 0?void 0:r.subscribe(n)}[Ar](){return this}pipe(...n){return ll(n)(this)}toPromise(n){return n=Yf(n),new n((r,o)=>{let i;this.subscribe(s=>i=s,s=>o(s),()=>r(i))})}}return e.create=t=>new e(t),e})();function Yf(e){var t;return(t=e??ht.Promise)!==null&&t!==void 0?t:Promise}function cD(e){return e&&P(e.next)&&P(e.error)&&P(e.complete)}function lD(e){return e&&e instanceof Hn||cD(e)&&is(e)}function uD(e){return P(e?.lift)}function $(e){return t=>{if(uD(t))return t.lift(function(n){try{return e(n,this)}catch(r){this.error(r)}});throw new TypeError("Unable to lift unknown Observable type")}}function z(e,t,n,r,o){return new ul(e,t,n,r,o)}var ul=class extends Hn{constructor(t,n,r,o,i,s){super(t),this.onFinalize=i,this.shouldUnsubscribe=s,this._next=n?function(a){try{n(a)}catch(c){t.error(c)}}:super._next,this._error=o?function(a){try{o(a)}catch(c){t.error(c)}finally{this.unsubscribe()}}:super._error,this._complete=r?function(){try{r()}catch(a){t.error(a)}finally{this.unsubscribe()}}:super._complete}unsubscribe(){var t;if(!this.shouldUnsubscribe||this.shouldUnsubscribe()){let{closed:n}=this;super.unsubscribe(),!n&&((t=this.onFinalize)===null||t===void 0||t.call(this))}}};var Kf=Sr(e=>function(){e(this),this.name="ObjectUnsubscribedError",this.message="object unsubscribed"});var me=(()=>{class e extends j{constructor(){super(),this.closed=!1,this.currentObservers=null,this.observers=[],this.isStopped=!1,this.hasError=!1,this.thrownError=null}lift(n){let r=new cs(this,this);return r.operator=n,r}_throwIfClosed(){if(this.closed)throw new Kf}next(n){Tr(()=>{if(this._throwIfClosed(),!this.isStopped){this.currentObservers||(this.currentObservers=Array.from(this.observers));for(let r of this.currentObservers)r.next(n)}})}error(n){Tr(()=>{if(this._throwIfClosed(),!this.isStopped){this.hasError=this.isStopped=!0,this.thrownError=n;let{observers:r}=this;for(;r.length;)r.shift().error(n)}})}complete(){Tr(()=>{if(this._throwIfClosed(),!this.isStopped){this.isStopped=!0;let{observers:n}=this;for(;n.length;)n.shift().complete()}})}unsubscribe(){this.isStopped=this.closed=!0,this.observers=this.currentObservers=null}get observed(){var n;return((n=this.observers)===null||n===void 0?void 0:n.length)>0}_trySubscribe(n){return this._throwIfClosed(),super._trySubscribe(n)}_subscribe(n){return this._throwIfClosed(),this._checkFinalizedStatuses(n),this._innerSubscribe(n)}_innerSubscribe(n){let{hasError:r,isStopped:o,observers:i}=this;return r||o?rl:(this.currentObservers=null,i.push(n),new _e(()=>{this.currentObservers=null,Mo(i,n)}))}_checkFinalizedStatuses(n){let{hasError:r,thrownError:o,isStopped:i}=this;r?n.error(o):i&&n.complete()}asObservable(){let n=new j;return n.source=this,n}}return e.create=(t,n)=>new cs(t,n),e})(),cs=class extends me{constructor(t,n){super(),this.destination=t,this.source=n}next(t){var n,r;(r=(n=this.destination)===null||n===void 0?void 0:n.next)===null||r===void 0||r.call(n,t)}error(t){var n,r;(r=(n=this.destination)===null||n===void 0?void 0:n.error)===null||r===void 0||r.call(n,t)}complete(){var t,n;(n=(t=this.destination)===null||t===void 0?void 0:t.complete)===null||n===void 0||n.call(t)}_subscribe(t){var n,r;return(r=(n=this.source)===null||n===void 0?void 0:n.subscribe(t))!==null&&r!==void 0?r:rl}};var be=class extends me{constructor(t){super(),this._value=t}get value(){return this.getValue()}_subscribe(t){let n=super._subscribe(t);return!n.closed&&t.next(this._value),n}getValue(){let{hasError:t,thrownError:n,_value:r}=this;if(t)throw n;return this._throwIfClosed(),r}next(t){super.next(this._value=t)}};var we=new j(e=>e.complete());function Qf(e){return e&&P(e.schedule)}function Jf(e){return e[e.length-1]}function ls(e){return P(Jf(e))?e.pop():void 0}function hn(e){return Qf(Jf(e))?e.pop():void 0}function eh(e,t,n,r){function o(i){return i instanceof n?i:new n(function(s){s(i)})}return new(n||(n=Promise))(function(i,s){function a(u){try{l(r.next(u))}catch(d){s(d)}}function c(u){try{l(r.throw(u))}catch(d){s(d)}}function l(u){u.done?i(u.value):o(u.value).then(a,c)}l((r=r.apply(e,t||[])).next())})}function Xf(e){var t=typeof Symbol=="function"&&Symbol.iterator,n=t&&e[t],r=0;if(n)return n.call(e);if(e&&typeof e.length=="number")return{next:function(){return e&&r>=e.length&&(e=void 0),{value:e&&e[r++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function $n(e){return this instanceof $n?(this.v=e,this):new $n(e)}function th(e,t,n){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var r=n.apply(e,t||[]),o,i=[];return o=Object.create((typeof AsyncIterator=="function"?AsyncIterator:Object).prototype),a("next"),a("throw"),a("return",s),o[Symbol.asyncIterator]=function(){return this},o;function s(f){return function(v){return Promise.resolve(v).then(f,d)}}function a(f,v){r[f]&&(o[f]=function(_){return new Promise(function(b,w){i.push([f,_,b,w])>1||c(f,_)})},v&&(o[f]=v(o[f])))}function c(f,v){try{l(r[f](v))}catch(_){h(i[0][3],_)}}function l(f){f.value instanceof $n?Promise.resolve(f.value.v).then(u,d):h(i[0][2],f)}function u(f){c("next",f)}function d(f){c("throw",f)}function h(f,v){f(v),i.shift(),i.length&&c(i[0][0],i[0][1])}}function nh(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],n;return t?t.call(e):(e=typeof Xf=="function"?Xf(e):e[Symbol.iterator](),n={},r("next"),r("throw"),r("return"),n[Symbol.asyncIterator]=function(){return this},n);function r(i){n[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),o(a,c,s.done,s.value)})}}function o(i,s,a,c){Promise.resolve(c).then(function(l){i({value:l,done:a})},s)}}var us=e=>e&&typeof e.length=="number"&&typeof e!="function";function ds(e){return P(e?.then)}function fs(e){return P(e[Ar])}function hs(e){return Symbol.asyncIterator&&P(e?.[Symbol.asyncIterator])}function ps(e){return new TypeError(`You provided ${e!==null&&typeof e=="object"?"an invalid object":`'${e}'`} where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`)}function dD(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var gs=dD();function ms(e){return P(e?.[gs])}function ys(e){return th(this,arguments,function*(){let n=e.getReader();try{for(;;){let{value:r,done:o}=yield $n(n.read());if(o)return yield $n(void 0);yield yield $n(r)}}finally{n.releaseLock()}})}function vs(e){return P(e?.getReader)}function fe(e){if(e instanceof j)return e;if(e!=null){if(fs(e))return fD(e);if(us(e))return hD(e);if(ds(e))return pD(e);if(hs(e))return rh(e);if(ms(e))return gD(e);if(vs(e))return mD(e)}throw ps(e)}function fD(e){return new j(t=>{let n=e[Ar]();if(P(n.subscribe))return n.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function hD(e){return new j(t=>{for(let n=0;n{e.then(n=>{t.closed||(t.next(n),t.complete())},n=>t.error(n)).then(null,ss)})}function gD(e){return new j(t=>{for(let n of e)if(t.next(n),t.closed)return;t.complete()})}function rh(e){return new j(t=>{yD(e,t).catch(n=>t.error(n))})}function mD(e){return rh(ys(e))}function yD(e,t){var n,r,o,i;return eh(this,void 0,void 0,function*(){try{for(n=nh(e);r=yield n.next(),!r.done;){let s=r.value;if(t.next(s),t.closed)return}}catch(s){o={error:s}}finally{try{r&&!r.done&&(i=n.return)&&(yield i.call(n))}finally{if(o)throw o.error}}t.complete()})}function Fe(e,t,n,r=0,o=!1){let i=t.schedule(function(){n(),o?e.add(this.schedule(null,r)):this.unsubscribe()},r);if(e.add(i),!o)return i}function Ds(e,t=0){return $((n,r)=>{n.subscribe(z(r,o=>Fe(r,e,()=>r.next(o),t),()=>Fe(r,e,()=>r.complete(),t),o=>Fe(r,e,()=>r.error(o),t)))})}function Cs(e,t=0){return $((n,r)=>{r.add(e.schedule(()=>n.subscribe(r),t))})}function oh(e,t){return fe(e).pipe(Cs(t),Ds(t))}function ih(e,t){return fe(e).pipe(Cs(t),Ds(t))}function sh(e,t){return new j(n=>{let r=0;return t.schedule(function(){r===e.length?n.complete():(n.next(e[r++]),n.closed||this.schedule())})})}function ah(e,t){return new j(n=>{let r;return Fe(n,t,()=>{r=e[gs](),Fe(n,t,()=>{let o,i;try{({value:o,done:i}=r.next())}catch(s){n.error(s);return}i?n.complete():n.next(o)},0,!0)}),()=>P(r?.return)&&r.return()})}function Es(e,t){if(!e)throw new Error("Iterable cannot be null");return new j(n=>{Fe(n,t,()=>{let r=e[Symbol.asyncIterator]();Fe(n,t,()=>{r.next().then(o=>{o.done?n.complete():n.next(o.value)})},0,!0)})})}function ch(e,t){return Es(ys(e),t)}function lh(e,t){if(e!=null){if(fs(e))return oh(e,t);if(us(e))return sh(e,t);if(ds(e))return ih(e,t);if(hs(e))return Es(e,t);if(ms(e))return ah(e,t);if(vs(e))return ch(e,t)}throw ps(e)}function ae(e,t){return t?lh(e,t):fe(e)}function k(...e){let t=hn(e);return ae(e,t)}function dl(e,t){let n=P(e)?e:()=>e,r=o=>o.error(n());return new j(t?o=>t.schedule(r,0,o):r)}function _s(e){return!!e&&(e instanceof j||P(e.lift)&&P(e.subscribe))}var $t=Sr(e=>function(){e(this),this.name="EmptyError",this.message="no elements in sequence"});function wt(e,t){let n=typeof t=="object";return new Promise((r,o)=>{let i=new fn({next:s=>{r(s),i.unsubscribe()},error:o,complete:()=>{n?r(t.defaultValue):o(new $t)}});e.subscribe(i)})}function W(e,t){return $((n,r)=>{let o=0;n.subscribe(z(r,i=>{r.next(e.call(t,i,o++))}))})}var{isArray:vD}=Array;function DD(e,t){return vD(t)?e(...t):e(t)}function bs(e){return W(t=>DD(e,t))}var{isArray:CD}=Array,{getPrototypeOf:ED,prototype:_D,keys:bD}=Object;function ws(e){if(e.length===1){let t=e[0];if(CD(t))return{args:t,keys:null};if(wD(t)){let n=bD(t);return{args:n.map(r=>t[r]),keys:n}}}return{args:e,keys:null}}function wD(e){return e&&typeof e=="object"&&ED(e)===_D}function Is(e,t){return e.reduce((n,r,o)=>(n[r]=t[o],n),{})}function fl(...e){let t=hn(e),n=ls(e),{args:r,keys:o}=ws(e);if(r.length===0)return ae([],t);let i=new j(ID(r,t,o?s=>Is(o,s):pt));return n?i.pipe(bs(n)):i}function ID(e,t,n=pt){return r=>{uh(t,()=>{let{length:o}=e,i=new Array(o),s=o,a=o;for(let c=0;c{let l=ae(e[c],t),u=!1;l.subscribe(z(r,d=>{i[c]=d,u||(u=!0,a--),a||r.next(n(i.slice()))},()=>{--s||r.complete()}))},r)},r)}}function uh(e,t,n){e?Fe(n,e,t):t()}function dh(e,t,n,r,o,i,s,a){let c=[],l=0,u=0,d=!1,h=()=>{d&&!c.length&&!l&&t.complete()},f=_=>l{i&&t.next(_),l++;let b=!1;fe(n(_,u++)).subscribe(z(t,w=>{o?.(w),i?f(w):t.next(w)},()=>{b=!0},void 0,()=>{if(b)try{for(l--;c.length&&lv(w)):v(w)}h()}catch(w){t.error(w)}}))};return e.subscribe(z(t,f,()=>{d=!0,h()})),()=>{a?.()}}function xe(e,t,n=1/0){return P(t)?xe((r,o)=>W((i,s)=>t(r,i,o,s))(fe(e(r,o))),n):(typeof t=="number"&&(n=t),$((r,o)=>dh(r,o,e,n)))}function fh(e=1/0){return xe(pt,e)}function hh(){return fh(1)}function Nr(...e){return hh()(ae(e,hn(e)))}function Ao(e){return new j(t=>{fe(e()).subscribe(t)})}function hl(...e){let t=ls(e),{args:n,keys:r}=ws(e),o=new j(i=>{let{length:s}=n;if(!s){i.complete();return}let a=new Array(s),c=s,l=s;for(let u=0;u{d||(d=!0,l--),a[u]=h},()=>c--,void 0,()=>{(!c||!d)&&(l||i.next(r?Is(r,a):a),i.complete())}))}});return t?o.pipe(bs(t)):o}function gt(e,t){return $((n,r)=>{let o=0;n.subscribe(z(r,i=>e.call(t,i,o++)&&r.next(i)))})}function No(e){return $((t,n)=>{let r=null,o=!1,i;r=t.subscribe(z(n,void 0,void 0,s=>{i=fe(e(s,No(e)(t))),r?(r.unsubscribe(),r=null,i.subscribe(n)):o=!0})),o&&(r.unsubscribe(),r=null,i.subscribe(n))})}function xr(e,t){return P(t)?xe(e,t,1):xe(e,1)}function ph(e){return $((t,n)=>{let r=!1;t.subscribe(z(n,o=>{r=!0,n.next(o)},()=>{r||n.next(e),n.complete()}))})}function zt(e){return e<=0?()=>we:$((t,n)=>{let r=0;t.subscribe(z(n,o=>{++r<=e&&(n.next(o),e<=r&&n.complete())}))})}function gh(e=SD){return $((t,n)=>{let r=!1;t.subscribe(z(n,o=>{r=!0,n.next(o)},()=>r?n.complete():n.error(e())))})}function SD(){return new $t}function xo(e){return $((t,n)=>{try{t.subscribe(n)}finally{n.add(e)}})}function Gt(e,t){let n=arguments.length>=2;return r=>r.pipe(e?gt((o,i)=>e(o,i,r)):pt,zt(1),n?ph(t):gh(()=>new $t))}function Ss(e){return e<=0?()=>we:$((t,n)=>{let r=[];t.subscribe(z(n,o=>{r.push(o),e{for(let o of r)n.next(o);n.complete()},void 0,()=>{r=null}))})}function pl(...e){let t=hn(e);return $((n,r)=>{(t?Nr(e,n,t):Nr(e,n)).subscribe(r)})}function Ue(e,t){return $((n,r)=>{let o=null,i=0,s=!1,a=()=>s&&!o&&r.complete();n.subscribe(z(r,c=>{o?.unsubscribe();let l=0,u=i++;fe(e(c,u)).subscribe(o=z(r,d=>r.next(t?t(c,d,u,l++):d),()=>{o=null,a()}))},()=>{s=!0,a()}))})}function Ro(e){return $((t,n)=>{fe(e).subscribe(z(n,()=>n.complete(),To)),!n.closed&&t.subscribe(n)})}function tt(e,t,n){let r=P(e)||t||n?{next:e,error:t,complete:n}:e;return r?$((o,i)=>{var s;(s=r.subscribe)===null||s===void 0||s.call(r);let a=!0;o.subscribe(z(i,c=>{var l;(l=r.next)===null||l===void 0||l.call(r,c),i.next(c)},()=>{var c;a=!1,(c=r.complete)===null||c===void 0||c.call(r),i.complete()},c=>{var l;a=!1,(l=r.error)===null||l===void 0||l.call(r,c),i.error(c)},()=>{var c,l;a&&((c=r.unsubscribe)===null||c===void 0||c.call(r)),(l=r.finalize)===null||l===void 0||l.call(r)}))}):pt}var gl;function Ms(){return gl}function It(e){let t=gl;return gl=e,t}var mh=Symbol("NotFound");function Rr(e){return e===mh||e?.name==="\u0275NotFound"}function ml(e,t,n){let r=Object.create(MD);r.source=e,r.computation=t,n!=null&&(r.equal=n);let i=()=>{if(Ln(r),Fn(r),r.value===bt)throw r.error;return r.value};return i[ye]=r,Io(r),i}function yh(e,t){Ln(e),Bn(e,t),wr(e)}function vh(e,t){if(Ln(e),e.value===bt)throw e.error;ns(e,t),wr(e)}var MD=A(y({},un),{value:ln,dirty:!0,error:null,equal:So,kind:"linkedSignal",producerMustRecompute(e){return e.value===ln||e.value===kn},producerRecomputeValue(e){if(e.value===kn)throw new Error("");let t=e.value;e.value=kn;let n=dn(e),r;try{let o=e.source(),i=t===ln||t===bt?void 0:{source:e.sourceValue,value:t};r=e.computation(o,i),e.sourceValue=o}catch(o){r=bt,e.error=o}finally{jn(e,n)}if(t!==ln&&r!==bt&&e.equal(t,r)){e.value=t;return}e.value=r,e.version++}});function Dh(e){let t=M(null);try{return e()}finally{M(t)}}var Ps="https://angular.dev/best-practices/security#preventing-cross-site-scripting-xss",E=class extends Error{code;constructor(t,n){super(vn(t,n)),this.code=t}};function TD(e){return`NG0${Math.abs(e)}`}function vn(e,t){return`${TD(e)}${t?": "+t:""}`}var qt=globalThis;function G(e){for(let t in e)if(e[t]===G)return t;throw Error("")}function wh(e,t){for(let n in t)t.hasOwnProperty(n)&&!e.hasOwnProperty(n)&&(e[n]=t[n])}function Vo(e){if(typeof e=="string")return e;if(Array.isArray(e))return`[${e.map(Vo).join(", ")}]`;if(e==null)return""+e;let t=e.overriddenName||e.name;if(t)return`${t}`;let n=e.toString();if(n==null)return""+n;let r=n.indexOf(` +`);return r>=0?n.slice(0,r):n}function Al(e,t){return e?t?`${e} ${t}`:e:t||""}var AD=G({__forward_ref__:G});function Dn(e){return e.__forward_ref__=Dn,e}function Ie(e){return Nl(e)?e():e}function Nl(e){return typeof e=="function"&&e.hasOwnProperty(AD)&&e.__forward_ref__===Dn}function S(e){return{token:e.token,providedIn:e.providedIn||null,factory:e.factory,value:void 0}}function mt(e){return{providers:e.providers||[],imports:e.imports||[]}}function Bo(e){return ND(e,ks)}function xl(e){return Bo(e)!==null}function ND(e,t){return e.hasOwnProperty(t)&&e[t]||null}function xD(e){let t=e?.[ks]??null;return t||null}function vl(e){return e&&e.hasOwnProperty(As)?e[As]:null}var ks=G({\u0275prov:G}),As=G({\u0275inj:G}),I=class{_desc;ngMetadataName="InjectionToken";\u0275prov;constructor(t,n){this._desc=t,this.\u0275prov=void 0,typeof n=="number"?this.__NG_ELEMENT_ID__=n:n!==void 0&&(this.\u0275prov=S({token:this,providedIn:n.providedIn||"root",factory:n.factory}))}get multi(){return this}toString(){return`InjectionToken ${this._desc}`}};function Rl(e){return e&&!!e.\u0275providers}var Ol=G({\u0275cmp:G}),Pl=G({\u0275dir:G}),kl=G({\u0275pipe:G}),Fl=G({\u0275mod:G}),Po=G({\u0275fac:G}),Zn=G({__NG_ELEMENT_ID__:G}),Ch=G({__NG_ENV_ID__:G});function Ll(e){return Fs(e,"@NgModule"),e[Fl]||null}function Cn(e){return Fs(e,"@Component"),e[Ol]||null}function jl(e){return Fs(e,"@Directive"),e[Pl]||null}function Ih(e){return Fs(e,"@Pipe"),e[kl]||null}function Fs(e,t){if(e==null)throw new E(-919,!1)}function Pr(e){return typeof e=="string"?e:e==null?"":String(e)}var Sh=G({ngErrorCode:G}),RD=G({ngErrorMessage:G}),OD=G({ngTokenPath:G});function Vl(e,t){return Mh("",-200,t)}function Ls(e,t){throw new E(-201,!1)}function Mh(e,t,n){let r=new E(t,e);return r[Sh]=t,r[RD]=e,n&&(r[OD]=n),r}function PD(e){return e[Sh]}var Dl;function Th(){return Dl}function Re(e){let t=Dl;return Dl=e,t}function Bl(e,t,n){let r=Bo(e);if(r&&r.providedIn=="root")return r.value===void 0?r.value=r.factory():r.value;if(n&8)return null;if(t!==void 0)return t;Ls(e,"")}var kD={},zn=kD,FD="__NG_DI_FLAG__",Cl=class{injector;constructor(t){this.injector=t}retrieve(t,n){let r=Gn(n)||0;try{return this.injector.get(t,r&8?null:zn,r)}catch(o){if(Rr(o))return o;throw o}}};function LD(e,t=0){let n=Ms();if(n===void 0)throw new E(-203,!1);if(n===null)return Bl(e,void 0,t);{let r=jD(t),o=n.retrieve(e,r);if(Rr(o)){if(r.optional)return null;throw o}return o}}function T(e,t=0){return(Th()||LD)(Ie(e),t)}function p(e,t){return T(e,Gn(t))}function Gn(e){return typeof e>"u"||typeof e=="number"?e:0|(e.optional&&8)|(e.host&&1)|(e.self&&2)|(e.skipSelf&&4)}function jD(e){return{optional:!!(e&8),host:!!(e&1),self:!!(e&2),skipSelf:!!(e&4)}}function El(e){let t=[];for(let n=0;nArray.isArray(n)?js(n,t):t(n))}function Ul(e,t,n){t>=e.length?e.push(n):e.splice(t,0,n)}function Uo(e,t){return t>=e.length-1?e.pop():e.splice(t,1)[0]}function Ah(e,t,n,r){let o=e.length;if(o==t)e.push(n,r);else if(o===1)e.push(r,e[0]),e[0]=n;else{for(o--,e.push(e[o-1],e[o]);o>t;){let i=o-2;e[o]=e[i],o--}e[t]=n,e[t+1]=r}}function Nh(e,t,n){let r=kr(e,t);return r>=0?e[r|1]=n:(r=~r,Ah(e,r,t,n)),r}function Vs(e,t){let n=kr(e,t);if(n>=0)return e[n|1]}function kr(e,t){return BD(e,t,1)}function BD(e,t,n){let r=0,o=e.length>>n;for(;o!==r;){let i=r+(o-r>>1),s=e[i<t?o=i:r=i+1}return~(o<{n.push(s)};return js(t,s=>{let a=s;Ns(a,i,[],r)&&(o||=[],o.push(a))}),o!==void 0&&Oh(o,i),n}function Oh(e,t){for(let n=0;n{t(i,r)})}}function Ns(e,t,n,r){if(e=Ie(e),!e)return!1;let o=null,i=vl(e),s=!i&&Cn(e);if(!i&&!s){let c=e.ngModule;if(i=vl(c),i)o=c;else return!1}else{if(s&&!s.standalone)return!1;o=e}let a=r.has(o);if(s){if(a)return!1;if(r.add(o),s.dependencies){let c=typeof s.dependencies=="function"?s.dependencies():s.dependencies;for(let l of c)Ns(l,t,n,r)}}else if(i){if(i.imports!=null&&!a){r.add(o);let l;js(i.imports,u=>{Ns(u,t,n,r)&&(l||=[],l.push(u))}),l!==void 0&&Oh(l,t)}if(!a){let l=pn(o)||(()=>new o);t({provide:o,useFactory:l,deps:He},o),t({provide:Hl,useValue:o,multi:!0},o),t({provide:Yn,useValue:()=>T(o),multi:!0},o)}let c=i.providers;if(c!=null&&!a){let l=e;zl(c,u=>{t(u,l)})}}else return!1;return o!==e&&e.providers!==void 0}function zl(e,t){for(let n of e)Rl(n)&&(n=n.\u0275providers),Array.isArray(n)?zl(n,t):t(n)}var UD=G({provide:String,useValue:G});function Ph(e){return e!==null&&typeof e=="object"&&UD in e}function HD(e){return!!(e&&e.useExisting)}function $D(e){return!!(e&&e.useFactory)}function Wn(e){return typeof e=="function"}function kh(e){return!!e.useClass}var $o=new I(""),Ts={},Eh={},yl;function zo(){return yl===void 0&&(yl=new ko),yl}var ne=class{},qn=class extends ne{parent;source;scopes;records=new Map;_ngOnDestroyHooks=new Set;_onDestroyHooks=[];get destroyed(){return this._destroyed}_destroyed=!1;injectorDefTypes;constructor(t,n,r,o){super(),this.parent=n,this.source=r,this.scopes=o,bl(t,s=>this.processProvider(s)),this.records.set(Ho,Or(void 0,this)),o.has("environment")&&this.records.set(ne,Or(void 0,this));let i=this.records.get($o);i!=null&&typeof i.value=="string"&&this.scopes.add(i.value),this.injectorDefTypes=new Set(this.get(Hl,He,{self:!0}))}retrieve(t,n){let r=Gn(n)||0;try{return this.get(t,zn,r)}catch(o){if(Rr(o))return o;throw o}}destroy(){Oo(this),this._destroyed=!0;let t=M(null);try{for(let r of this._ngOnDestroyHooks)r.ngOnDestroy();let n=this._onDestroyHooks;this._onDestroyHooks=[];for(let r of n)r()}finally{this.records.clear(),this._ngOnDestroyHooks.clear(),this.injectorDefTypes.clear(),M(t)}}onDestroy(t){return Oo(this),this._onDestroyHooks.push(t),()=>this.removeOnDestroy(t)}runInContext(t){Oo(this);let n=It(this),r=Re(void 0),o;try{return t()}finally{It(n),Re(r)}}get(t,n=zn,r){if(Oo(this),t.hasOwnProperty(Ch))return t[Ch](this);let o=Gn(r),i,s=It(this),a=Re(void 0);try{if(!(o&4)){let l=this.records.get(t);if(l===void 0){let u=ZD(t)&&Bo(t);u&&this.injectableDefInScope(u)?l=Or(_l(t),Ts):l=null,this.records.set(t,l)}if(l!=null)return this.hydrate(t,l,o)}let c=o&2?zo():this.parent;return n=o&8&&n===zn?null:n,c.get(t,n)}catch(c){let l=PD(c);throw l===-200||l===-201?new E(l,null):c}finally{Re(a),It(s)}}resolveInjectorInitializers(){let t=M(null),n=It(this),r=Re(void 0),o;try{let i=this.get(Yn,He,{self:!0});for(let s of i)s()}finally{It(n),Re(r),M(t)}}toString(){return"R3Injector[...]"}processProvider(t){t=Ie(t);let n=Wn(t)?t:Ie(t&&t.provide),r=GD(t);if(!Wn(t)&&t.multi===!0){let o=this.records.get(n);o||(o=Or(void 0,Ts,!0),o.factory=()=>El(o.multi),this.records.set(n,o)),n=t,o.multi.push(t)}this.records.set(n,r)}hydrate(t,n,r){let o=M(null);try{if(n.value===Eh)throw Vl("");return n.value===Ts&&(n.value=Eh,n.value=n.factory(void 0,r)),typeof n.value=="object"&&n.value&&qD(n.value)&&this._ngOnDestroyHooks.add(n.value),n.value}finally{M(o)}}injectableDefInScope(t){if(!t.providedIn)return!1;let n=Ie(t.providedIn);return typeof n=="string"?n==="any"||this.scopes.has(n):this.injectorDefTypes.has(n)}removeOnDestroy(t){let n=this._onDestroyHooks.indexOf(t);n!==-1&&this._onDestroyHooks.splice(n,1)}};function _l(e){let t=Bo(e),n=t!==null?t.factory:pn(e);if(n!==null)return n;if(e instanceof I)throw new E(-204,!1);if(e instanceof Function)return zD(e);throw new E(-204,!1)}function zD(e){if(e.length>0)throw new E(-204,!1);let n=xD(e);return n!==null?()=>n.factory(e):()=>new e}function GD(e){if(Ph(e))return Or(void 0,e.useValue);{let t=Gl(e);return Or(t,Ts)}}function Gl(e,t,n){let r;if(Wn(e)){let o=Ie(e);return pn(o)||_l(o)}else if(Ph(e))r=()=>Ie(e.useValue);else if($D(e))r=()=>e.useFactory(...El(e.deps||[]));else if(HD(e))r=(o,i)=>T(Ie(e.useExisting),i!==void 0&&i&8?8:void 0);else{let o=Ie(e&&(e.useClass||e.provide));if(WD(e))r=()=>new o(...El(e.deps));else return pn(o)||_l(o)}return r}function Oo(e){if(e.destroyed)throw new E(-205,!1)}function Or(e,t,n=!1){return{factory:e,value:t,multi:n?[]:void 0}}function WD(e){return!!e.deps}function qD(e){return e!==null&&typeof e=="object"&&typeof e.ngOnDestroy=="function"}function ZD(e){return typeof e=="function"||typeof e=="object"&&e.ngMetadataName==="InjectionToken"}function bl(e,t){for(let n of e)Array.isArray(n)?bl(n,t):n&&Rl(n)?bl(n.\u0275providers,t):t(n)}function De(e,t){let n;e instanceof qn?(Oo(e),n=e):n=new Cl(e);let r,o=It(n),i=Re(void 0);try{return t()}finally{It(o),Re(i)}}function Fh(){return Th()!==void 0||Ms()!=null}var yt=0,N=1,x=2,ve=3,nt=4,rt=5,Fr=6,Lr=7,le=8,Zt=9,Mt=10,re=11,jr=12,Wl=13,Kn=14,$e=15,Qn=16,Jn=17,Xn=18,Tt=19,ql=20,Wt=21,Bs=22,gn=23,ze=24,Us=25,At=26,pe=27,Lh=1,Zl=6,bn=7,Go=8,Wo=9,ce=10;function Nt(e){return Array.isArray(e)&&typeof e[Lh]=="object"}function ot(e){return Array.isArray(e)&&e[Lh]===!0}function Yl(e){return(e.flags&4)!==0}function Yt(e){return e.componentOffset>-1}function Hs(e){return(e.flags&1)===1}function xt(e){return!!e.template}function Vr(e){return(e[x]&512)!==0}function er(e){return(e[x]&256)===256}var jh="svg",Vh="math";function it(e){for(;Array.isArray(e);)e=e[yt];return e}function Kl(e,t){return it(t[e])}function vt(e,t){return it(t[e.index])}function qo(e,t){return e.data[t]}function $s(e,t){return e[t]}function Ql(e,t,n,r){n>=e.data.length&&(e.data[n]=null,e.blueprint[n]=null),t[n]=r}function Ge(e,t){let n=t[e];return Nt(n)?n:n[yt]}function zs(e){return(e[x]&128)===128}function Bh(e){return ot(e[ve])}function wn(e,t){return t==null?null:e[t]}function Jl(e){e[Jn]=0}function Xl(e){e[x]&1024||(e[x]|=1024,zs(e)&&Br(e))}function Uh(e,t){for(;e>0;)t=t[Kn],e--;return t}function Zo(e){return!!(e[x]&9216||e[ze]?.dirty)}function Gs(e){e[Mt].changeDetectionScheduler?.notify(8),e[x]&64&&(e[x]|=1024),Zo(e)&&Br(e)}function Br(e){e[Mt].changeDetectionScheduler?.notify(0);let t=mn(e);for(;t!==null&&!(t[x]&8192||(t[x]|=8192,!zs(t)));)t=mn(t)}function eu(e,t){if(er(e))throw new E(911,!1);e[Wt]===null&&(e[Wt]=[]),e[Wt].push(t)}function Hh(e,t){if(e[Wt]===null)return;let n=e[Wt].indexOf(t);n!==-1&&e[Wt].splice(n,1)}function mn(e){let t=e[ve];return ot(t)?t[ve]:t}function $h(e){return e[Lr]??=[]}function zh(e){return e.cleanup??=[]}var F={lFrame:cp(null),bindingsEnabled:!0,skipHydrationRootTNode:null};var wl=!1;function Gh(){return F.lFrame.elementDepthCount}function Wh(){F.lFrame.elementDepthCount++}function qh(){F.lFrame.elementDepthCount--}function Zh(){return F.bindingsEnabled}function Yh(){return F.skipHydrationRootTNode!==null}function Kh(e){return F.skipHydrationRootTNode===e}function Qh(){F.skipHydrationRootTNode=null}function V(){return F.lFrame.lView}function Te(){return F.lFrame.tView}function Q(e){return F.lFrame.contextLView=e,e[le]}function J(e){return F.lFrame.contextLView=null,e}function je(){let e=tu();for(;e!==null&&e.type===64;)e=e.parent;return e}function tu(){return F.lFrame.currentTNode}function Jh(){let e=F.lFrame,t=e.currentTNode;return e.isParent?t:t.parent}function Ur(e,t){let n=F.lFrame;n.currentTNode=e,n.isParent=t}function nu(){return F.lFrame.isParent}function Xh(){F.lFrame.isParent=!1}function ep(){return F.lFrame.contextLView}function ru(){return wl}function Fo(e){let t=wl;return wl=e,t}function Ws(){let e=F.lFrame,t=e.bindingRootIndex;return t===-1&&(t=e.bindingRootIndex=e.tView.bindingStartIndex),t}function tp(){return F.lFrame.bindingIndex}function np(e){return F.lFrame.bindingIndex=e}function tr(){return F.lFrame.bindingIndex++}function ou(e){let t=F.lFrame,n=t.bindingIndex;return t.bindingIndex=t.bindingIndex+e,n}function rp(){return F.lFrame.inI18n}function op(e,t){let n=F.lFrame;n.bindingIndex=n.bindingRootIndex=e,qs(t)}function ip(){return F.lFrame.currentDirectiveIndex}function qs(e){F.lFrame.currentDirectiveIndex=e}function sp(e){let t=F.lFrame.currentDirectiveIndex;return t===-1?null:e[t]}function iu(e){F.lFrame.currentQueryIndex=e}function YD(e){let t=e[N];return t.type===2?t.declTNode:t.type===1?e[rt]:null}function su(e,t,n){if(n&4){let o=t,i=e;for(;o=o.parent,o===null&&!(n&1);)if(o=YD(i),o===null||(i=i[Kn],o.type&10))break;if(o===null)return!1;t=o,e=i}let r=F.lFrame=ap();return r.currentTNode=t,r.lView=e,!0}function Zs(e){let t=ap(),n=e[N];F.lFrame=t,t.currentTNode=n.firstChild,t.lView=e,t.tView=n,t.contextLView=e,t.bindingIndex=n.bindingStartIndex,t.inI18n=!1}function ap(){let e=F.lFrame,t=e===null?null:e.child;return t===null?cp(e):t}function cp(e){let t={currentTNode:null,isParent:!0,lView:null,tView:null,selectedIndex:-1,contextLView:null,elementDepthCount:0,currentNamespace:null,currentDirectiveIndex:-1,bindingRootIndex:-1,bindingIndex:-1,currentQueryIndex:0,parent:e,child:null,inI18n:!1};return e!==null&&(e.child=t),t}function lp(){let e=F.lFrame;return F.lFrame=e.parent,e.currentTNode=null,e.lView=null,e}var au=lp;function Ys(){let e=lp();e.isParent=!0,e.tView=null,e.selectedIndex=-1,e.contextLView=null,e.elementDepthCount=0,e.currentDirectiveIndex=-1,e.currentNamespace=null,e.bindingRootIndex=-1,e.bindingIndex=-1,e.currentQueryIndex=0}function up(e){return(F.lFrame.contextLView=Uh(e,F.lFrame.contextLView))[le]}function Kt(){return F.lFrame.selectedIndex}function In(e){F.lFrame.selectedIndex=e}function Ks(){let e=F.lFrame;return qo(e.tView,e.selectedIndex)}function dp(){return F.lFrame.currentNamespace}var fp=!0;function Qs(){return fp}function Js(e){fp=e}function Il(e,t=null,n=null,r){let o=cu(e,t,n,r);return o.resolveInjectorInitializers(),o}function cu(e,t=null,n=null,r,o=new Set){let i=[n||He,Rh(e)],s;return new qn(i,t||zo(),s||null,o)}var Le=class e{static THROW_IF_NOT_FOUND=zn;static NULL=new ko;static create(t,n){if(Array.isArray(t))return Il({name:""},n,t,"");{let r=t.name??"";return Il({name:r},t.parent,t.providers,r)}}static \u0275prov=S({token:e,providedIn:"any",factory:()=>T(Ho)});static __NG_ELEMENT_ID__=-1},ue=new I(""),We=(()=>{class e{static __NG_ELEMENT_ID__=KD;static __NG_ENV_ID__=n=>n}return e})(),xs=class extends We{_lView;constructor(t){super(),this._lView=t}get destroyed(){return er(this._lView)}onDestroy(t){let n=this._lView;return eu(n,t),()=>Hh(n,t)}};function KD(){return new xs(V())}var hp=!1,pp=new I(""),Qt=(()=>{class e{taskId=0;pendingTasks=new Set;destroyed=!1;pendingTask=new be(!1);debugTaskTracker=p(pp,{optional:!0});get hasPendingTasks(){return this.destroyed?!1:this.pendingTask.value}get hasPendingTasksObservable(){return this.destroyed?new j(n=>{n.next(!1),n.complete()}):this.pendingTask}add(){!this.hasPendingTasks&&!this.destroyed&&this.pendingTask.next(!0);let n=this.taskId++;return this.pendingTasks.add(n),this.debugTaskTracker?.add(n),n}has(n){return this.pendingTasks.has(n)}remove(n){this.pendingTasks.delete(n),this.debugTaskTracker?.remove(n),this.pendingTasks.size===0&&this.hasPendingTasks&&this.pendingTask.next(!1)}ngOnDestroy(){this.pendingTasks.clear(),this.hasPendingTasks&&this.pendingTask.next(!1),this.destroyed=!0,this.pendingTask.unsubscribe()}static \u0275prov=S({token:e,providedIn:"root",factory:()=>new e})}return e})(),Sl=class extends me{__isAsync;destroyRef=void 0;pendingTasks=void 0;constructor(t=!1){super(),this.__isAsync=t,Fh()&&(this.destroyRef=p(We,{optional:!0})??void 0,this.pendingTasks=p(Qt,{optional:!0})??void 0)}emit(t){let n=M(null);try{super.next(t)}finally{M(n)}}subscribe(t,n,r){let o=t,i=n||(()=>null),s=r;if(t&&typeof t=="object"){let c=t;o=c.next?.bind(c),i=c.error?.bind(c),s=c.complete?.bind(c)}this.__isAsync&&(i=this.wrapInTimeout(i),o&&(o=this.wrapInTimeout(o)),s&&(s=this.wrapInTimeout(s)));let a=super.subscribe({next:o,error:i,complete:s});return t instanceof _e&&t.add(a),a}wrapInTimeout(t){return n=>{let r=this.pendingTasks?.add();setTimeout(()=>{try{t(n)}finally{r!==void 0&&this.pendingTasks?.remove(r)}})}}},he=Sl;function Rs(...e){}function lu(e){let t,n;function r(){e=Rs;try{n!==void 0&&typeof cancelAnimationFrame=="function"&&cancelAnimationFrame(n),t!==void 0&&clearTimeout(t)}catch{}}return t=setTimeout(()=>{e(),r()}),typeof requestAnimationFrame=="function"&&(n=requestAnimationFrame(()=>{e(),r()})),()=>r()}function gp(e){return queueMicrotask(()=>e()),()=>{e=Rs}}var uu="isAngularZone",Lo=uu+"_ID",QD=0,Oe=class e{hasPendingMacrotasks=!1;hasPendingMicrotasks=!1;isStable=!0;onUnstable=new he(!1);onMicrotaskEmpty=new he(!1);onStable=new he(!1);onError=new he(!1);constructor(t){let{enableLongStackTrace:n=!1,shouldCoalesceEventChangeDetection:r=!1,shouldCoalesceRunChangeDetection:o=!1,scheduleInRootZone:i=hp}=t;if(typeof Zone>"u")throw new E(908,!1);Zone.assertZonePatched();let s=this;s._nesting=0,s._outer=s._inner=Zone.current,Zone.TaskTrackingZoneSpec&&(s._inner=s._inner.fork(new Zone.TaskTrackingZoneSpec)),n&&Zone.longStackTraceZoneSpec&&(s._inner=s._inner.fork(Zone.longStackTraceZoneSpec)),s.shouldCoalesceEventChangeDetection=!o&&r,s.shouldCoalesceRunChangeDetection=o,s.callbackScheduled=!1,s.scheduleInRootZone=i,eC(s)}static isInAngularZone(){return typeof Zone<"u"&&Zone.current.get(uu)===!0}static assertInAngularZone(){if(!e.isInAngularZone())throw new E(909,!1)}static assertNotInAngularZone(){if(e.isInAngularZone())throw new E(909,!1)}run(t,n,r){return this._inner.run(t,n,r)}runTask(t,n,r,o){let i=this._inner,s=i.scheduleEventTask("NgZoneEvent: "+o,t,JD,Rs,Rs);try{return i.runTask(s,n,r)}finally{i.cancelTask(s)}}runGuarded(t,n,r){return this._inner.runGuarded(t,n,r)}runOutsideAngular(t){return this._outer.run(t)}},JD={};function du(e){if(e._nesting==0&&!e.hasPendingMicrotasks&&!e.isStable)try{e._nesting++,e.onMicrotaskEmpty.emit(null)}finally{if(e._nesting--,!e.hasPendingMicrotasks)try{e.runOutsideAngular(()=>e.onStable.emit(null))}finally{e.isStable=!0}}}function XD(e){if(e.isCheckStableRunning||e.callbackScheduled)return;e.callbackScheduled=!0;function t(){lu(()=>{e.callbackScheduled=!1,Ml(e),e.isCheckStableRunning=!0,du(e),e.isCheckStableRunning=!1})}e.scheduleInRootZone?Zone.root.run(()=>{t()}):e._outer.run(()=>{t()}),Ml(e)}function eC(e){let t=()=>{XD(e)},n=QD++;e._inner=e._inner.fork({name:"angular",properties:{[uu]:!0,[Lo]:n,[Lo+n]:!0},onInvokeTask:(r,o,i,s,a,c)=>{if(tC(c))return r.invokeTask(i,s,a,c);try{return _h(e),r.invokeTask(i,s,a,c)}finally{(e.shouldCoalesceEventChangeDetection&&s.type==="eventTask"||e.shouldCoalesceRunChangeDetection)&&t(),bh(e)}},onInvoke:(r,o,i,s,a,c,l)=>{try{return _h(e),r.invoke(i,s,a,c,l)}finally{e.shouldCoalesceRunChangeDetection&&!e.callbackScheduled&&!nC(c)&&t(),bh(e)}},onHasTask:(r,o,i,s)=>{r.hasTask(i,s),o===i&&(s.change=="microTask"?(e._hasPendingMicrotasks=s.microTask,Ml(e),du(e)):s.change=="macroTask"&&(e.hasPendingMacrotasks=s.macroTask))},onHandleError:(r,o,i,s)=>(r.handleError(i,s),e.runOutsideAngular(()=>e.onError.emit(s)),!1)})}function Ml(e){e._hasPendingMicrotasks||(e.shouldCoalesceEventChangeDetection||e.shouldCoalesceRunChangeDetection)&&e.callbackScheduled===!0?e.hasPendingMicrotasks=!0:e.hasPendingMicrotasks=!1}function _h(e){e._nesting++,e.isStable&&(e.isStable=!1,e.onUnstable.emit(null))}function bh(e){e._nesting--,du(e)}var jo=class{hasPendingMicrotasks=!1;hasPendingMacrotasks=!1;isStable=!0;onUnstable=new he;onMicrotaskEmpty=new he;onStable=new he;onError=new he;run(t,n,r){return t.apply(n,r)}runGuarded(t,n,r){return t.apply(n,r)}runOutsideAngular(t){return t()}runTask(t,n,r,o){return t.apply(n,r)}};function tC(e){return mp(e,"__ignore_ng_zone__")}function nC(e){return mp(e,"__scheduler_tick__")}function mp(e,t){return!Array.isArray(e)||e.length!==1?!1:e[0]?.data?.[t]===!0}var St=class{_console=console;handleError(t){this._console.error("ERROR",t)}},qe=new I("",{factory:()=>{let e=p(Oe),t=p(ne),n;return r=>{e.runOutsideAngular(()=>{t.destroyed&&!n?setTimeout(()=>{throw r}):(n??=t.get(St),n.handleError(r))})}}}),yp={provide:Yn,useValue:()=>{let e=p(St,{optional:!0})},multi:!0},rC=new I("",{factory:()=>{let e=p(ue).defaultView;if(!e)return;let t=p(qe),n=i=>{t(i.reason),i.preventDefault()},r=i=>{i.error?t(i.error):t(new Error(i.message,{cause:i})),i.preventDefault()},o=()=>{e.addEventListener("unhandledrejection",n),e.addEventListener("error",r)};typeof Zone<"u"?Zone.root.run(o):o(),p(We).onDestroy(()=>{e.removeEventListener("error",r),e.removeEventListener("unhandledrejection",n)})}});function fu(){return _n([xh(()=>{p(rC)})])}function L(e,t){let[n,r,o]=el(e,t?.equal),i=n,s=i[ye];return i.set=r,i.update=o,i.asReadonly=Xs.bind(i),i}function Xs(){let e=this[ye];if(e.readonlyFn===void 0){let t=()=>this();t[ye]=e,e.readonlyFn=t}return e.readonlyFn}var ea=(()=>{class e{view;node;constructor(n,r){this.view=n,this.node=r}static __NG_ELEMENT_ID__=oC}return e})();function oC(){return new ea(V(),je())}var yn=class{},Yo=new I("",{factory:()=>!0});var hu=new I(""),Ko=(()=>{class e{internalPendingTasks=p(Qt);scheduler=p(yn);errorHandler=p(qe);add(){let n=this.internalPendingTasks.add();return()=>{this.internalPendingTasks.has(n)&&(this.scheduler.notify(11),this.internalPendingTasks.remove(n))}}run(n){let r=this.add();n().catch(this.errorHandler).finally(r)}static \u0275prov=S({token:e,providedIn:"root",factory:()=>new e})}return e})(),ta=(()=>{class e{static \u0275prov=S({token:e,providedIn:"root",factory:()=>new Tl})}return e})(),Tl=class{dirtyEffectCount=0;queues=new Map;add(t){this.enqueue(t),this.schedule(t)}schedule(t){t.dirty&&this.dirtyEffectCount++}remove(t){let n=t.zone,r=this.queues.get(n);r.has(t)&&(r.delete(t),t.dirty&&this.dirtyEffectCount--)}enqueue(t){let n=t.zone;this.queues.has(n)||this.queues.set(n,new Set);let r=this.queues.get(n);r.has(t)||r.add(t)}flush(){for(;this.dirtyEffectCount>0;){let t=!1;for(let[n,r]of this.queues)n===null?t||=this.flushQueue(r):t||=n.run(()=>this.flushQueue(r));t||(this.dirtyEffectCount=0)}}flushQueue(t){let n=!1;for(let r of t)r.dirty&&(this.dirtyEffectCount--,n=!0,r.run());return n}},Os=class{[ye];constructor(t){this[ye]=t}destroy(){this[ye].destroy()}};function na(e,t){let n=t?.injector??p(Le),r=t?.manualCleanup!==!0?n.get(We):null,o,i=n.get(ea,null,{optional:!0}),s=n.get(yn);return i!==null?(o=aC(i.view,s,e),r instanceof xs&&r._lView===i.view&&(r=null)):o=cC(e,n.get(ta),s),o.injector=n,r!==null&&(o.onDestroyFns=[r.onDestroy(()=>o.destroy())]),new Os(o)}var vp=A(y({},tl),{cleanupFns:void 0,zone:null,onDestroyFns:null,run(){let e=Fo(!1);try{nl(this)}finally{Fo(e)}},cleanup(){if(!this.cleanupFns?.length)return;let e=M(null);try{for(;this.cleanupFns.length;)this.cleanupFns.pop()()}finally{this.cleanupFns=[],M(e)}}}),iC=A(y({},vp),{consumerMarkedDirty(){this.scheduler.schedule(this),this.notifier.notify(12)},destroy(){if(Vn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.scheduler.remove(this)}}),sC=A(y({},vp),{consumerMarkedDirty(){this.view[x]|=8192,Br(this.view),this.notifier.notify(13)},destroy(){if(Vn(this),this.onDestroyFns!==null)for(let e of this.onDestroyFns)e();this.cleanup(),this.view[gn]?.delete(this)}});function aC(e,t,n){let r=Object.create(sC);return r.view=e,r.zone=typeof Zone<"u"?Zone.current:null,r.notifier=t,r.fn=Dp(r,n),e[gn]??=new Set,e[gn].add(r),r.consumerMarkedDirty(r),r}function cC(e,t,n){let r=Object.create(iC);return r.fn=Dp(r,e),r.scheduler=t,r.notifier=n,r.zone=typeof Zone<"u"?Zone.current:null,r.scheduler.add(r),r.notifier.notify(12),r}function Dp(e,t){return()=>{t(n=>(e.cleanupFns??=[]).push(n))}}function si(e){return{toString:e}.toString()}function mC(e){return typeof e=="function"}function Qp(e,t,n,r){t!==null?t.applyValueToInputSignal(t,r):e[n]=r}var ca=class{previousValue;currentValue;firstChange;constructor(t,n,r){this.previousValue=t,this.currentValue=n,this.firstChange=r}isFirstChange(){return this.firstChange}},Mn=(()=>{let e=()=>Jp;return e.ngInherit=!0,e})();function Jp(e){return e.type.prototype.ngOnChanges&&(e.setInput=vC),yC}function yC(){let e=eg(this),t=e?.current;if(t){let n=e.previous;if(n===En)e.previous=t;else for(let r in t)n[r]=t[r];e.current=null,this.ngOnChanges(t)}}function vC(e,t,n,r,o){let i=this.declaredInputs[r],s=eg(e)||DC(e,{previous:En,current:null}),a=s.current||(s.current={}),c=s.previous,l=c[i];a[i]=new ca(l&&l.currentValue,n,c===En),Qp(e,t,o,n)}var Xp="__ngSimpleChanges__";function eg(e){return e[Xp]||null}function DC(e,t){return e[Xp]=t}var Cp=[];var Z=function(e,t=null,n){for(let r=0;r=r)break}else t[c]<0&&(e[Jn]+=65536),(a>14>16&&(e[x]&3)===t&&(e[x]+=16384,Ep(a,i)):Ep(a,i)}var $r=-1,rr=class{factory;name;injectImpl;resolving=!1;canSeeViewProviders;multi;componentProviders;index;providerFactory;constructor(t,n,r,o){this.factory=t,this.name=o,this.canSeeViewProviders=n,this.injectImpl=r}};function bC(e){return(e.flags&8)!==0}function wC(e){return(e.flags&16)!==0}function IC(e,t,n){let r=0;for(;rt){s=i-1;break}}}for(;i>16}function ua(e,t){let n=MC(e),r=t;for(;n>0;)r=r[Kn],n--;return r}var Su=!0;function da(e){let t=Su;return Su=e,t}var TC=256,og=TC-1,ig=5,AC=0,Rt={};function NC(e,t,n){let r;typeof n=="string"?r=n.charCodeAt(0)||0:n.hasOwnProperty(Zn)&&(r=n[Zn]),r==null&&(r=n[Zn]=AC++);let o=r&og,i=1<>ig)]|=i}function fa(e,t){let n=sg(e,t);if(n!==-1)return n;let r=t[N];r.firstCreatePass&&(e.injectorIndex=t.length,gu(r.data,e),gu(t,null),gu(r.blueprint,null));let o=Yu(e,t),i=e.injectorIndex;if(rg(o)){let s=la(o),a=ua(o,t),c=a[N].data;for(let l=0;l<8;l++)t[i+l]=a[s+l]|c[s+l]}return t[i+8]=o,i}function gu(e,t){e.push(0,0,0,0,0,0,0,0,t)}function sg(e,t){return e.injectorIndex===-1||e.parent&&e.parent.injectorIndex===e.injectorIndex||t[e.injectorIndex+8]===null?-1:e.injectorIndex}function Yu(e,t){if(e.parent&&e.parent.injectorIndex!==-1)return e.parent.injectorIndex;let n=0,r=null,o=t;for(;o!==null;){if(r=dg(o),r===null)return $r;if(n++,o=o[Kn],r.injectorIndex!==-1)return r.injectorIndex|n<<16}return $r}function Mu(e,t,n){NC(e,t,n)}function xC(e,t){if(t==="class")return e.classes;if(t==="style")return e.styles;let n=e.attrs;if(n){let r=n.length,o=0;for(;o>20,d=r?a:a+u,h=o?a+u:l;for(let f=d;f=c&&v.type===n)return f}if(o){let f=s[c];if(f&&xt(f)&&f.type===n)return c}return null}function ha(e,t,n,r,o){let i=e[n],s=t.data;if(i instanceof rr){let a=i;if(a.resolving)throw Vl("");let c=da(a.canSeeViewProviders);a.resolving=!0;let l=s[n].type||s[n],u,d=a.injectImpl?Re(a.injectImpl):null,h=su(e,r,0);try{i=e[n]=a.factory(void 0,o,s,e,r),t.firstCreatePass&&n>=r.directiveStart&&CC(n,s[n],t)}finally{d!==null&&Re(d),da(c),a.resolving=!1,au()}}return i}function PC(e){if(typeof e=="string")return e.charCodeAt(0)||0;let t=e.hasOwnProperty(Zn)?e[Zn]:void 0;return typeof t=="number"?t>=0?t&og:kC:t}function bp(e,t,n){let r=1<>ig)]&r)}function wp(e,t){return!(e&2)&&!(e&1&&t)}var nr=class{_tNode;_lView;constructor(t,n){this._tNode=t,this._lView=n}get(t,n,r){return lg(this._tNode,this._lView,t,Gn(r),n)}};function kC(){return new nr(je(),V())}function cr(e){return si(()=>{let t=e.prototype.constructor,n=t[Po]||Tu(t),r=Object.prototype,o=Object.getPrototypeOf(e.prototype).constructor;for(;o&&o!==r;){let i=o[Po]||Tu(o);if(i&&i!==n)return i;o=Object.getPrototypeOf(o)}return i=>new i})}function Tu(e){return Nl(e)?()=>{let t=Tu(Ie(e));return t&&t()}:pn(e)}function FC(e,t,n,r,o){let i=e,s=t;for(;i!==null&&s!==null&&s[x]&2048&&!Vr(s);){let a=ug(i,s,n,r|2,Rt);if(a!==Rt)return a;let c=i.parent;if(!c){let l=s[ql];if(l){let u=l.get(n,Rt,r&-5);if(u!==Rt)return u}c=dg(s),s=s[Kn]}i=c}return o}function dg(e){let t=e[N],n=t.type;return n===2?t.declTNode:n===1?e[rt]:null}function ai(e){return xC(je(),e)}function LC(){return Ku(je(),V())}function Ku(e,t){return new Tn(vt(e,t))}var Tn=(()=>{class e{nativeElement;constructor(n){this.nativeElement=n}static __NG_ELEMENT_ID__=LC}return e})();function fg(e){return(e.flags&128)===128}var Qu=(function(e){return e[e.OnPush=0]="OnPush",e[e.Eager=1]="Eager",e[e.Default=1]="Default",e})(Qu||{}),hg=new Map,jC=0;function VC(){return jC++}function BC(e){hg.set(e[Tt],e)}function Au(e){hg.delete(e[Tt])}var Ip="__ngContext__";function zr(e,t){Nt(t)?(e[Ip]=t[Tt],BC(t)):e[Ip]=t}function pg(e){return mg(e[jr])}function gg(e){return mg(e[nt])}function mg(e){for(;e!==null&&!ot(e);)e=e[nt];return e}var UC;function Ju(e){UC=e}var Ia=new I("",{factory:()=>HC}),HC="ng";var Sa=new I(""),ci=new I("",{providedIn:"platform",factory:()=>"unknown"});var Ma=new I("",{factory:()=>p(ue).body?.querySelector("[ngCspNonce]")?.getAttribute("ngCspNonce")||null});var yg="r";var vg="di";var Dg=!1,Cg=new I("",{factory:()=>Dg});var $C=(e,t,n,r)=>{};function zC(e,t,n,r){$C(e,t,n,r)}function Xu(e){return(e.flags&32)===32}var GC=()=>null;function Eg(e,t,n=!1){return GC(e,t,n)}function _g(e,t){let n=e.contentQueries;if(n!==null){let r=M(null);try{for(let o=0;oe,createScript:e=>e,createScriptURL:e=>e})}catch{}return ra}function Sp(e){return WC()?.createScriptURL(e)||e}var pa=class{changingThisBreaksApplicationSecurity;constructor(t){this.changingThisBreaksApplicationSecurity=t}toString(){return`SafeValue must use [property]=binding: ${this.changingThisBreaksApplicationSecurity} (see ${Ps})`}};function Ta(e){return e instanceof pa?e.changingThisBreaksApplicationSecurity:e}function ed(e,t){let n=wg(e);if(n!=null&&n!==t){if(n==="ResourceURL"&&t==="URL")return!0;throw new Error(`Required a safe ${t}, got a ${n} (see ${Ps})`)}return n===t}function wg(e){return e instanceof pa&&e.getTypeName()||null}var qC=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:\/?#]*(?:[\/?#]|$))/i;function Ig(e){return e=String(e),e.match(qC)?e:"unsafe:"+e}function ZC(e,t){return e.createText(t)}function YC(e,t,n){e.setValue(t,n)}function Sg(e,t,n){return e.createElement(t,n)}function ga(e,t,n,r,o){e.insertBefore(t,n,r,o)}function Mg(e,t,n){e.appendChild(t,n)}function Mp(e,t,n,r,o){r!==null?ga(e,t,n,r,o):Mg(e,t,n)}function Tg(e,t,n,r){e.removeChild(null,t,n,r)}function KC(e,t,n){e.setAttribute(t,"style",n)}function QC(e,t,n){n===""?e.removeAttribute(t,"class"):e.setAttribute(t,"class",n)}function Ag(e,t,n){let{mergedAttrs:r,classes:o,styles:i}=n;r!==null&&IC(e,t,r),o!==null&&QC(e,t,o),i!==null&&KC(e,t,i)}var Aa=(function(e){return e[e.NONE=0]="NONE",e[e.HTML=1]="HTML",e[e.STYLE=2]="STYLE",e[e.SCRIPT=3]="SCRIPT",e[e.URL=4]="URL",e[e.RESOURCE_URL=5]="RESOURCE_URL",e})(Aa||{});function Na(e){let t=xg();return t?t.sanitize(Aa.URL,e)||"":ed(e,"URL")?Ta(e):Ig(Pr(e))}function Ng(e){let t=xg();if(t)return Sp(t.sanitize(Aa.RESOURCE_URL,e)||"");if(ed(e,"ResourceURL"))return Sp(Ta(e));throw new E(904,!1)}var JC=new Set(["embed","frame","iframe","media","script"]),XC=new Set(["base","link","script"]);function eE(e,t){return t==="src"&&JC.has(e)||t==="href"&&XC.has(e)||t==="xlink:href"&&e==="script"?Ng:Na}function td(e,t,n){return eE(t,n)(e)}function xg(){let e=V();return e&&e[Mt].sanitizer}function Rg(e){return e instanceof Function?e():e}function tE(e,t,n){let r=e.length;for(;;){let o=e.indexOf(t,n);if(o===-1)return o;if(o===0||e.charCodeAt(o-1)<=32){let i=t.length;if(o+i===r||e.charCodeAt(o+i)<=32)return o}n=o+1}}var Og="ng-template";function nE(e,t,n,r){let o=0;if(r){for(;o-1){let i;for(;++oi?d="":d=o[u+1].toLowerCase(),r&2&&l!==d){if(Dt(r))return!1;s=!0}}}}return Dt(r)||s}function Dt(e){return(e&1)===0}function iE(e,t,n,r){if(t===null)return-1;let o=0;if(r||!n){let i=!1;for(;o-1)for(n++;n0?'="'+a+'"':"")+"]"}else r&8?o+="."+s:r&4&&(o+=" "+s);else o!==""&&!Dt(s)&&(t+=Tp(i,o),o=""),r=s,i=i||!Dt(r);n++}return o!==""&&(t+=Tp(i,o)),t}function uE(e){return e.map(lE).join(",")}function dE(e){let t=[],n=[],r=1,o=2;for(;r=0;i--){let s=n[i],a=s.parentNode;s===t?(n.splice(i,1),Ou.add(s),s.dispatchEvent(new CustomEvent("animationend",{detail:{cancel:!0}}))):(o&&s===o||a&&r&&a!==r)&&(n.splice(i,1),s.dispatchEvent(new CustomEvent("animationend",{detail:{cancel:!0}})),s.parentNode?.removeChild(s))}}function yE(e,t){let n=Ru.get(e);n?n.includes(t)||n.push(t):Ru.set(e,[t])}var Sn=new Set,ad=(function(e){return e[e.CHANGE_DETECTION=0]="CHANGE_DETECTION",e[e.AFTER_NEXT_RENDER=1]="AFTER_NEXT_RENDER",e})(ad||{}),lr=new I(""),Ap=new Set;function ur(e){Ap.has(e)||(Ap.add(e),performance?.mark?.("mark_feature_usage",{detail:{feature:e}}))}var Lg=(()=>{class e{impl=null;execute(){this.impl?.execute()}static \u0275prov=S({token:e,providedIn:"root",factory:()=>new e})}return e})();var jg=new I("",{factory:()=>{let e=p(ne),t=new Set;return e.onDestroy(()=>t.clear()),{queue:t,isScheduled:!1,scheduler:null,injector:e}}});function Vg(e,t,n){let r=e.get(jg);if(Array.isArray(t))for(let o of t)r.queue.add(o),n?.detachedLeaveAnimationFns?.push(o);else r.queue.add(t),n?.detachedLeaveAnimationFns?.push(t);r.scheduler&&r.scheduler(e)}function vE(e,t){let n=e.get(jg);if(t.detachedLeaveAnimationFns){for(let r of t.detachedLeaveAnimationFns)n.queue.delete(r);t.detachedLeaveAnimationFns=void 0}}function DE(e,t){for(let[n,r]of t)Vg(e,r.animateFns)}function Np(e,t,n,r){let o=e?.[At]?.enter;t!==null&&o&&o.has(n.index)&&DE(r,o)}function xp(e,t,n,r){try{n.get(Ho)}catch{return r(!1)}let o=e?.[At],i=CE(e,t,o);if(i.size===0){let s=!1;if(e){let a=[];Ra(e,t,a),s=a.length>0}if(!s)return r(!1)}e&&Sn.add(e[Tt]),Vg(n,()=>EE(e,t,o||void 0,i,r),o||void 0)}function CE(e,t,n){let r=new Map,o=n?.leave;if(o&&o.has(t.index)&&r.set(t.index,o.get(t.index)),e&&o)for(let[i,s]of o){if(r.has(i))continue;let c=e[N].data[i].parent;for(;c;){if(c===t){r.set(i,s);break}c=c.parent}}return r}function EE(e,t,n,r,o){let i=[];if(n&&n.leave)for(let[s]of r){if(!n.leave.has(s))continue;let a=n.leave.get(s);for(let c of a.animateFns){let{promise:l}=c();i.push(l)}n.detachedLeaveAnimationFns=void 0}if(e&&Ra(e,t,i),i.length>0){let s=n||e?.[At];if(s){let a=s.running;a&&i.push(a),s.running=Promise.allSettled(i),_E(e,s.running,o)}else Promise.allSettled(i).then(()=>{e&&Sn.delete(e[Tt]),o(!0)})}else e&&Sn.delete(e[Tt]),o(!1)}function Ra(e,t,n){if(Yt(t)){let o=Ge(t.index,e);Rp(o,n)}else if(t.type&12){let o=e[t.index];if(ot(o))for(let i=ce;i{e[At]?.running===t&&(e[At].running=void 0,Sn.delete(e[Tt])),n(!0)})}function Hr(e,t,n,r,o,i,s,a){if(o!=null){let c,l=!1;ot(o)?c=o:Nt(o)&&(l=!0,o=o[yt]);let u=it(o);e===0&&r!==null?(Np(a,r,i,n),s==null?Mg(t,r,u):ga(t,r,u,s||null,!0)):e===1&&r!==null?(Np(a,r,i,n),ga(t,r,u,s||null,!0),mE(i,u)):e===2?(a?.[At]?.leave?.has(i.index)&&yE(i,u),xp(a,i,n,d=>{if(Ou.has(u)){Ou.delete(u);return}Tg(t,u,l,d)})):e===3&&xp(a,i,n,()=>{t.destroyNode(u)}),c!=null&&PE(t,e,n,c,i,r,s)}}function bE(e,t){Bg(e,t),t[yt]=null,t[rt]=null}function wE(e,t,n,r,o,i){r[yt]=o,r[rt]=t,Pa(e,r,n,1,o,i)}function Bg(e,t){t[Mt].changeDetectionScheduler?.notify(9),Pa(e,t,t[re],2,null,null)}function IE(e){let t=e[jr];if(!t)return mu(e[N],e);for(;t;){let n=null;if(Nt(t))n=t[jr];else{let r=t[ce];r&&(n=r)}if(!n){for(;t&&!t[nt]&&t!==e;)Nt(t)&&mu(t[N],t),t=t[ve];t===null&&(t=e),Nt(t)&&mu(t[N],t),n=t&&t[nt]}t=n}}function cd(e,t){let n=e[Wo],r=n.indexOf(t);n.splice(r,1)}function Oa(e,t){if(er(t))return;let n=t[re];n.destroyNode&&Pa(e,t,n,3,null,null),IE(t)}function mu(e,t){if(er(t))return;let n=M(null);try{t[x]&=-129,t[x]|=256,t[ze]&&Vn(t[ze]),ME(e,t),SE(e,t),t[N].type===1&&t[re].destroy();let r=t[Qn];if(r!==null&&ot(t[ve])){r!==t[ve]&&cd(r,t);let o=t[Xn];o!==null&&o.detachView(e)}Au(t)}finally{M(n)}}function SE(e,t){let n=e.cleanup,r=t[Lr];if(n!==null)for(let s=0;s=0?r[a]():r[-a].unsubscribe(),s+=2}else{let a=r[n[s+1]];n[s].call(a)}r!==null&&(t[Lr]=null);let o=t[Wt];if(o!==null){t[Wt]=null;for(let s=0;spe&&Fg(e,t,pe,!1);let a=s?U.TemplateUpdateStart:U.TemplateCreateStart;Z(a,o,n),n(r,o)}finally{In(i);let a=s?U.TemplateUpdateEnd:U.TemplateCreateEnd;Z(a,o,n)}}function $g(e,t,n){HE(e,t,n),(n.flags&64)===64&&$E(e,t,n)}function zg(e,t,n=vt){let r=t.localNames;if(r!==null){let o=t.index+1;for(let i=0;inull;function VE(e){return e==="class"?"className":e==="for"?"htmlFor":e==="formaction"?"formAction":e==="innerHtml"?"innerHTML":e==="readonly"?"readOnly":e==="tabindex"?"tabIndex":e}function Gg(e,t,n,r,o,i){let s=t[N];if(dd(e,s,t,n,r)){Yt(e)&&UE(t,e.index);return}e.type&3&&(n=VE(n)),BE(e,t,n,r,o,i)}function BE(e,t,n,r,o,i){if(e.type&3){let s=vt(e,t);r=i!=null?i(r,e.value||"",n):r,o.setProperty(s,n,r)}else e.type&12}function UE(e,t){let n=Ge(t,e);n[x]&16||(n[x]|=64)}function HE(e,t,n){let r=n.directiveStart,o=n.directiveEnd;Yt(n)&&pE(t,n,e.data[r+n.componentOffset]),e.firstCreatePass||fa(n,t);let i=n.initialInputs;for(let s=r;s{Br(e.lView)},consumerOnSignalRead(){this.lView[ze]=this}});function i_(e){let t=e[ze]??Object.create(s_);return t.lView=e,t}var s_=A(y({},un),{consumerIsAlwaysLive:!0,kind:"template",consumerMarkedDirty:e=>{let t=mn(e.lView);for(;t&&!Yg(t[N]);)t=mn(t);t&&Xl(t)},consumerOnSignalRead(){this.lView[ze]=this}});function Yg(e){return e.type!==2}function Kg(e){if(e[gn]===null)return;let t=!0;for(;t;){let n=!1;for(let r of e[gn])r.dirty&&(n=!0,r.zone===null||Zone.current===r.zone?r.run():r.zone.run(()=>r.run()));t=n&&!!(e[x]&8192)}}var a_=100;function Qg(e,t=0){let r=e[Mt].rendererFactory,o=!1;o||r.begin?.();try{c_(e,t)}finally{o||r.end?.()}}function c_(e,t){let n=ru();try{Fo(!0),ku(e,t);let r=0;for(;Zo(e);){if(r===a_)throw new E(103,!1);r++,ku(e,1)}}finally{Fo(n)}}function l_(e,t,n,r){if(er(t))return;let o=t[x],i=!1,s=!1;Zs(t);let a=!0,c=null,l=null;i||(Yg(e)?(l=t_(t),c=dn(l)):es()===null?(a=!1,l=i_(t),c=dn(l)):t[ze]&&(Vn(t[ze]),t[ze]=null));try{Jl(t),np(e.bindingStartIndex),n!==null&&Hg(e,t,n,2,r);let u=(o&3)===3;if(!i)if(u){let f=e.preOrderCheckHooks;f!==null&&ia(t,f,null)}else{let f=e.preOrderHooks;f!==null&&sa(t,f,0,null),pu(t,0)}if(s||u_(t),Kg(t),Jg(t,0),e.contentQueries!==null&&_g(e,t),!i)if(u){let f=e.contentCheckHooks;f!==null&&ia(t,f)}else{let f=e.contentHooks;f!==null&&sa(t,f,1),pu(t,1)}f_(e,t);let d=e.components;d!==null&&em(t,d,0);let h=e.viewQuery;if(h!==null&&Nu(2,h,r),!i)if(u){let f=e.viewCheckHooks;f!==null&&ia(t,f)}else{let f=e.viewHooks;f!==null&&sa(t,f,2),pu(t,2)}if(e.firstUpdatePass===!0&&(e.firstUpdatePass=!1),t[Bs]){for(let f of t[Bs])f();t[Bs]=null}i||(qg(t),t[x]&=-73)}catch(u){throw i||Br(t),u}finally{l!==null&&(jn(l,c),a&&r_(l)),Ys()}}function Jg(e,t){for(let n=pg(e);n!==null;n=gg(n))for(let r=ce;r0&&(e[n-1][nt]=r[nt]);let i=Uo(e,ce+t);bE(r[N],r);let s=i[Xn];s!==null&&s.detachView(i[N]),r[ve]=null,r[nt]=null,r[x]&=-129}return r}function h_(e,t,n,r){let o=ce+r,i=n.length;r>0&&(n[o-1][nt]=t),r-1&&(ri(t,r),Uo(n,r))}this._attachedToViewContainer=!1}Oa(this._lView[N],this._lView)}onDestroy(t){eu(this._lView,t)}markForCheck(){pd(this._cdRefInjectingView||this._lView,4)}detach(){this._lView[x]&=-129}reattach(){Gs(this._lView),this._lView[x]|=128}detectChanges(){this._lView[x]|=1024,Qg(this._lView)}checkNoChanges(){}attachToViewContainerRef(){if(this._appRef)throw new E(902,!1);this._attachedToViewContainer=!0}detachFromAppRef(){this._appRef=null;let t=Vr(this._lView),n=this._lView[Qn];n!==null&&!t&&cd(n,this._lView),Bg(this._lView[N],this._lView)}attachToAppRef(t){if(this._attachedToViewContainer)throw new E(902,!1);this._appRef=t;let n=Vr(this._lView),r=this._lView[Qn];r!==null&&!n&&om(r,this._lView),Gs(this._lView)}};function gd(e,t,n,r,o){let i=e.data[t];if(i===null)i=p_(e,t,n,r,o),rp()&&(i.flags|=32);else if(i.type&64){i.type=n,i.value=r,i.attrs=o;let s=Jh();i.injectorIndex=s===null?-1:s.injectorIndex}return Ur(i,!0),i}function p_(e,t,n,r,o){let i=tu(),s=nu(),a=s?i:i&&i.parent,c=e.data[t]=m_(e,a,n,t,r,o);return g_(e,c,i,s),c}function g_(e,t,n,r){e.firstChild===null&&(e.firstChild=t),n!==null&&(r?n.child==null&&t.parent!==null&&(n.child=t):n.next===null&&(n.next=t,t.prev=n))}function m_(e,t,n,r,o,i){let s=t?t.injectorIndex:-1,a=0;return Yh()&&(a|=128),{type:n,index:r,insertBeforeIndex:null,injectorIndex:s,directiveStart:-1,directiveEnd:-1,directiveStylingLast:-1,componentOffset:-1,controlDirectiveIndex:-1,customControlIndex:-1,propertyBindings:null,flags:a,providerIndexes:0,value:o,attrs:i,mergedAttrs:null,localNames:null,initialInputs:null,inputs:null,hostDirectiveInputs:null,outputs:null,hostDirectiveOutputs:null,directiveToIndex:null,tView:null,next:null,prev:null,projectionNext:null,child:null,parent:t,projection:null,styles:null,stylesWithoutHost:null,residualStyles:void 0,classes:null,classesWithoutHost:null,residualClasses:void 0,classBindings:0,styleBindings:0}}function y_(e){let t=e[Zl]??[],r=e[ve][re],o=[];for(let i of t)i.data[vg]!==void 0?o.push(i):v_(i,r);e[Zl]=o}function v_(e,t){let n=0,r=e.firstChild;if(r){let o=e.data[yg];for(;nnull,C_=()=>null;function Fu(e,t){return D_(e,t)}function im(e,t,n){return C_(e,t,n)}var sm=class{},Fa=class{},Lu=class{resolveComponentFactory(t){throw new E(917,!1)}},li=class{static NULL=new Lu},ir=class{},dr=(()=>{class e{destroyNode=null;static __NG_ELEMENT_ID__=()=>E_()}return e})();function E_(){let e=V(),t=je(),n=Ge(t.index,e);return(Nt(n)?n:e)[re]}var am=(()=>{class e{static \u0275prov=S({token:e,providedIn:"root",factory:()=>null})}return e})();var aa={},ju=class{injector;parentInjector;constructor(t,n){this.injector=t,this.parentInjector=n}get(t,n,r){let o=this.injector.get(t,aa,r);return o!==aa||n===aa?o:this.parentInjector.get(t,n,r)}};function Pp(e,t,n){let r=n?e.styles:null,o=n?e.classes:null,i=0;if(t!==null)for(let s=0;s0&&(n.directiveToIndex=new Map);for(let h=0;h0;){let n=e[--t];if(typeof n=="number"&&n<0)return n}return 0}function N_(e,t,n){if(n){if(t.exportAs)for(let r=0;rr(it(_[e.index])):e.index;hm(v,t,n,i,a,f,!1)}}return l}function O_(e){return e.startsWith("animation")||e.startsWith("transition")}function P_(e,t,n,r){let o=e.cleanup;if(o!=null)for(let i=0;ic?a[c]:null}typeof s=="string"&&(i+=2)}return null}function hm(e,t,n,r,o,i,s){let a=t.firstCreatePass?zh(t):null,c=$h(n),l=c.length;c.push(o,i),a&&a.push(r,e,l,(l+1)*(s?-1:1))}function Vp(e,t,n,r,o,i){let s=t[n],a=t[N],l=a.data[n].outputs[r],d=s[l].subscribe(i);hm(e.index,a,t,o,i,d,!0)}var Vu=Symbol("BINDING");var ma=class extends li{ngModule;constructor(t){super(),this.ngModule=t}resolveComponentFactory(t){let n=Cn(t);return new Gr(n,this.ngModule)}};function k_(e){return Object.keys(e).map(t=>{let[n,r,o]=e[t],i={propName:n,templateName:t,isSignal:(r&xa.SignalBased)!==0};return o&&(i.transform=o),i})}function F_(e){return Object.keys(e).map(t=>({propName:e[t],templateName:t}))}function L_(e,t,n){let r=t instanceof ne?t:t?.injector;return r&&e.getStandaloneInjector!==null&&(r=e.getStandaloneInjector(r)||r),r?new ju(n,r):n}function j_(e){let t=e.get(ir,null);if(t===null)throw new E(407,!1);let n=e.get(am,null),r=e.get(yn,null);return{rendererFactory:t,sanitizer:n,changeDetectionScheduler:r,ngReflect:!1}}function V_(e,t){let n=pm(e);return Sg(t,n,n==="svg"?jh:n==="math"?Vh:null)}function pm(e){return(e.selectors[0][0]||"div").toLowerCase()}var Gr=class extends Fa{componentDef;ngModule;selector;componentType;ngContentSelectors;isBoundToModule;cachedInputs=null;cachedOutputs=null;get inputs(){return this.cachedInputs??=k_(this.componentDef.inputs),this.cachedInputs}get outputs(){return this.cachedOutputs??=F_(this.componentDef.outputs),this.cachedOutputs}constructor(t,n){super(),this.componentDef=t,this.ngModule=n,this.componentType=t.type,this.selector=uE(t.selectors),this.ngContentSelectors=t.ngContentSelectors??[],this.isBoundToModule=!!n}create(t,n,r,o,i,s){Z(U.DynamicComponentStart);let a=M(null);try{let c=this.componentDef,l=B_(r,c,s,i),u=L_(c,o||this.ngModule,t),d=j_(u),h=d.rendererFactory.createRenderer(null,c),f=r?FE(h,r,c.encapsulation,u):V_(c,h),v=s?.some(Bp)||i?.some(w=>typeof w!="function"&&w.bindings.some(Bp)),_=od(null,l,null,512|Pg(c),null,null,d,h,u,null,Eg(f,u,!0));_[pe]=f,Zs(_);let b=null;try{let w=lm(pe,_,2,"#host",()=>l.directiveRegistry,!0,0);Ag(h,f,w),zr(f,_),$g(l,_,w),bg(l,w,_),um(l,w),n!==void 0&&H_(w,this.ngContentSelectors,n),b=Ge(w.index,_),_[le]=b[le],fd(l,_,null)}catch(w){throw b!==null&&Au(b),Au(_),w}finally{Z(U.DynamicComponentEnd),Ys()}return new ya(this.componentType,_,!!v)}finally{M(a)}}};function B_(e,t,n,r){let o=e?["ng-version","21.2.1"]:dE(t.selectors[0]),i=null,s=null,a=0;if(n)for(let u of n)a+=u[Vu].requiredVars,u.create&&(u.targetIdx=0,(i??=[]).push(u)),u.update&&(u.targetIdx=0,(s??=[]).push(u));if(r)for(let u=0;u{if(n&1&&e)for(let r of e)r.create();if(n&2&&t)for(let r of t)r.update()}}function Bp(e){let t=e[Vu].kind;return t==="input"||t==="twoWay"}var ya=class extends sm{_rootLView;_hasInputBindings;instance;hostView;changeDetectorRef;componentType;location;previousInputValues=null;_tNode;constructor(t,n,r){super(),this._rootLView=n,this._hasInputBindings=r,this._tNode=qo(n[N],pe),this.location=Ku(this._tNode,n),this.instance=Ge(this._tNode.index,n)[le],this.hostView=this.changeDetectorRef=new or(n,void 0),this.componentType=t}setInput(t,n){this._hasInputBindings;let r=this._tNode;if(this.previousInputValues??=new Map,this.previousInputValues.has(t)&&Object.is(this.previousInputValues.get(t),n))return;let o=this._rootLView,i=dd(r,o[N],o,t,n);this.previousInputValues.set(t,n);let s=Ge(r.index,o);pd(s,1)}get injector(){return new nr(this._tNode,this._rootLView)}destroy(){this.hostView.destroy()}onDestroy(t){this.hostView.onDestroy(t)}};function H_(e,t,n){let r=e.projection=[];for(let o=0;o{class e{static __NG_ELEMENT_ID__=$_}return e})();function $_(){let e=je();return G_(e,V())}var z_=ui,gm=class extends z_{_lContainer;_hostTNode;_hostLView;constructor(t,n,r){super(),this._lContainer=t,this._hostTNode=n,this._hostLView=r}get element(){return Ku(this._hostTNode,this._hostLView)}get injector(){return new nr(this._hostTNode,this._hostLView)}get parentInjector(){let t=Yu(this._hostTNode,this._hostLView);if(rg(t)){let n=ua(t,this._hostLView),r=la(t),o=n[N].data[r+8];return new nr(o,n)}else return new nr(null,this._hostLView)}clear(){for(;this.length>0;)this.remove(this.length-1)}get(t){let n=Up(this._lContainer);return n!==null&&n[t]||null}get length(){return this._lContainer.length-ce}createEmbeddedView(t,n,r){let o,i;typeof r=="number"?o=r:r!=null&&(o=r.index,i=r.injector);let s=Fu(this._lContainer,t.ssrId),a=t.createEmbeddedViewImpl(n||{},i,s);return this.insertImpl(a,o,ti(this._hostTNode,s)),a}createComponent(t,n,r,o,i,s,a){let c=t&&!mC(t),l;if(c)l=n;else{let b=n||{};l=b.index,r=b.injector,o=b.projectableNodes,i=b.environmentInjector||b.ngModuleRef,s=b.directives,a=b.bindings}let u=c?t:new Gr(Cn(t)),d=r||this.parentInjector;if(!i&&u.ngModule==null){let w=(c?d:this.parentInjector).get(ne,null);w&&(i=w)}let h=Cn(u.componentType??{}),f=Fu(this._lContainer,h?.id??null),v=f?.firstChild??null,_=u.create(d,o,v,i,s,a);return this.insertImpl(_.hostView,l,ti(this._hostTNode,f)),_}insert(t,n){return this.insertImpl(t,n,!0)}insertImpl(t,n,r){let o=t._lView;if(Bh(o)){let a=this.indexOf(t);if(a!==-1)this.detach(a);else{let c=o[ve],l=new gm(c,c[rt],c[ve]);l.detach(l.indexOf(t))}}let i=this._adjustIndex(n),s=this._lContainer;return ka(s,o,i,r),t.attachToViewContainerRef(),Ul(vu(s),i,t),t}move(t,n){return this.insert(t,n)}indexOf(t){let n=Up(this._lContainer);return n!==null?n.indexOf(t):-1}remove(t){let n=this._adjustIndex(t,-1),r=ri(this._lContainer,n);r&&(Uo(vu(this._lContainer),n),Oa(r[N],r))}detach(t){let n=this._adjustIndex(t,-1),r=ri(this._lContainer,n);return r&&Uo(vu(this._lContainer),n)!=null?new or(r):null}_adjustIndex(t,n=0){return t??this.length+n}};function Up(e){return e[Go]}function vu(e){return e[Go]||(e[Go]=[])}function G_(e,t){let n,r=t[e.index];return ot(r)?n=r:(n=tm(r,t,null,e),t[e.index]=n,id(t,n)),q_(n,t,e,r),new gm(n,e,t)}function W_(e,t){let n=e[re],r=n.createComment(""),o=vt(t,e),i=n.parentNode(o);return ga(n,i,r,n.nextSibling(o),!1),r}var q_=K_,Z_=()=>!1;function Y_(e,t,n){return Z_(e,t,n)}function K_(e,t,n,r){if(e[bn])return;let o;n.type&8?o=it(r):o=W_(t,n),e[bn]=o}var sr=class{},La=class{};var va=class extends sr{ngModuleType;_parent;_bootstrapComponents=[];_r3Injector;instance;destroyCbs=[];componentFactoryResolver=new ma(this);constructor(t,n,r,o=!0){super(),this.ngModuleType=t,this._parent=n;let i=Ll(t);this._bootstrapComponents=Rg(i.bootstrap),this._r3Injector=cu(t,n,[{provide:sr,useValue:this},{provide:li,useValue:this.componentFactoryResolver},...r],Vo(t),new Set(["environment"])),o&&this.resolveInjectorInitializers()}resolveInjectorInitializers(){this._r3Injector.resolveInjectorInitializers(),this.instance=this._r3Injector.get(this.ngModuleType)}get injector(){return this._r3Injector}destroy(){let t=this._r3Injector;!t.destroyed&&t.destroy(),this.destroyCbs.forEach(n=>n()),this.destroyCbs=null}onDestroy(t){this.destroyCbs.push(t)}},Da=class extends La{moduleType;constructor(t){super(),this.moduleType=t}create(t){return new va(this.moduleType,t,[])}};var oi=class extends sr{injector;componentFactoryResolver=new ma(this);instance=null;constructor(t){super();let n=new qn([...t.providers,{provide:sr,useValue:this},{provide:li,useValue:this.componentFactoryResolver}],t.parent||zo(),t.debugName,new Set(["environment"]));this.injector=n,t.runEnvironmentInitializers&&n.resolveInjectorInitializers()}destroy(){this.injector.destroy()}onDestroy(t){this.injector.onDestroy(t)}};function di(e,t,n=null){return new oi({providers:e,parent:t,debugName:n,runEnvironmentInitializers:!0}).injector}var Q_=(()=>{class e{_injector;cachedInjectors=new Map;constructor(n){this._injector=n}getOrCreateStandaloneInjector(n){if(!n.standalone)return null;if(!this.cachedInjectors.has(n)){let r=$l(!1,n.type),o=r.length>0?di([r],this._injector,""):null;this.cachedInjectors.set(n,o)}return this.cachedInjectors.get(n)}ngOnDestroy(){try{for(let n of this.cachedInjectors.values())n!==null&&n.destroy()}finally{this.cachedInjectors.clear()}}static \u0275prov=S({token:e,providedIn:"environment",factory:()=>new e(T(ne))})}return e})();function Jt(e){return si(()=>{let t=mm(e),n=A(y({},t),{decls:e.decls,vars:e.vars,template:e.template,consts:e.consts||null,ngContentSelectors:e.ngContentSelectors,onPush:e.changeDetection===Qu.OnPush,directiveDefs:null,pipeDefs:null,dependencies:t.standalone&&e.dependencies||null,getStandaloneInjector:t.standalone?o=>o.get(Q_).getOrCreateStandaloneInjector(n):null,getExternalStyles:null,signals:e.signals??!1,data:e.data||{},encapsulation:e.encapsulation||Ct.Emulated,styles:e.styles||He,_:null,schemas:e.schemas||null,tView:null,id:""});t.standalone&&ur("NgStandalone"),ym(n);let r=e.dependencies;return n.directiveDefs=Hp(r,J_),n.pipeDefs=Hp(r,Ih),n.id=tb(n),n})}function J_(e){return Cn(e)||jl(e)}function kt(e){return si(()=>({type:e.type,bootstrap:e.bootstrap||He,declarations:e.declarations||He,imports:e.imports||He,exports:e.exports||He,transitiveCompileScopes:null,schemas:e.schemas||null,id:e.id||null}))}function X_(e,t){if(e==null)return En;let n={};for(let r in e)if(e.hasOwnProperty(r)){let o=e[r],i,s,a,c;Array.isArray(o)?(a=o[0],i=o[1],s=o[2]??i,c=o[3]||null):(i=o,s=o,a=xa.None,c=null),n[i]=[r,a,c],t[i]=s}return n}function eb(e){if(e==null)return En;let t={};for(let n in e)e.hasOwnProperty(n)&&(t[e[n]]=n);return t}function Pe(e){return si(()=>{let t=mm(e);return ym(t),t})}function ja(e){return{type:e.type,name:e.name,factory:null,pure:e.pure!==!1,standalone:e.standalone??!0,onDestroy:e.type.prototype.ngOnDestroy||null}}function mm(e){let t={};return{type:e.type,providersResolver:null,viewProvidersResolver:null,factory:null,hostBindings:e.hostBindings||null,hostVars:e.hostVars||0,hostAttrs:e.hostAttrs||null,contentQueries:e.contentQueries||null,declaredInputs:t,inputConfig:e.inputs||En,exportAs:e.exportAs||null,standalone:e.standalone??!0,signals:e.signals===!0,selectors:e.selectors||He,viewQuery:e.viewQuery||null,features:e.features||null,setInput:null,resolveHostDirectives:null,hostDirectives:null,controlDef:null,inputs:X_(e.inputs,t),outputs:eb(e.outputs),debugInfo:null}}function ym(e){e.features?.forEach(t=>t(e))}function Hp(e,t){return e?()=>{let n=typeof e=="function"?e():e,r=[];for(let o of n){let i=t(o);i!==null&&r.push(i)}return r}:null}function tb(e){let t=0,n=typeof e.consts=="function"?"":e.consts,r=[e.selectors,e.ngContentSelectors,e.hostVars,e.hostAttrs,n,e.vars,e.decls,e.encapsulation,e.standalone,e.signals,e.exportAs,JSON.stringify(e.inputs),JSON.stringify(e.outputs),Object.getOwnPropertyNames(e.type.prototype),!!e.contentQueries,!!e.viewQuery];for(let i of r.join("|"))t=Math.imul(31,t)+i.charCodeAt(0)<<0;return t+=2147483648,"c"+t}function nb(e){return Object.getPrototypeOf(e.prototype).constructor}function Xt(e){let t=nb(e.type),n=!0,r=[e];for(;t;){let o;if(xt(e))o=t.\u0275cmp||t.\u0275dir;else{if(t.\u0275cmp)throw new E(903,!1);o=t.\u0275dir}if(o){if(n){r.push(o);let s=e;s.inputs=Du(e.inputs),s.declaredInputs=Du(e.declaredInputs),s.outputs=Du(e.outputs);let a=o.hostBindings;a&&ab(e,a);let c=o.viewQuery,l=o.contentQueries;if(c&&ib(e,c),l&&sb(e,l),rb(e,o),wh(e.outputs,o.outputs),xt(o)&&o.data.animation){let u=e.data;u.animation=(u.animation||[]).concat(o.data.animation)}}let i=o.features;if(i)for(let s=0;s=0;r--){let o=e[r];o.hostVars=t+=o.hostVars,o.hostAttrs=ei(o.hostAttrs,n=ei(n,o.hostAttrs))}}function Du(e){return e===En?{}:e===He?[]:e}function ib(e,t){let n=e.viewQuery;n?e.viewQuery=(r,o)=>{t(r,o),n(r,o)}:e.viewQuery=t}function sb(e,t){let n=e.contentQueries;n?e.contentQueries=(r,o,i)=>{t(r,o,i),n(r,o,i)}:e.contentQueries=t}function ab(e,t){let n=e.hostBindings;n?e.hostBindings=(r,o)=>{t(r,o),n(r,o)}:e.hostBindings=t}function cb(e,t,n,r,o,i,s,a){if(n.firstCreatePass){e.mergedAttrs=ei(e.mergedAttrs,e.attrs);let u=e.tView=rd(2,e,o,i,s,n.directiveRegistry,n.pipeRegistry,null,n.schemas,n.consts,null);n.queries!==null&&(n.queries.template(n,e),u.queries=n.queries.embeddedTView(e))}a&&(e.flags|=a),Ur(e,!1);let c=lb(n,t,e,r);Qs()&&ld(n,t,c,e),zr(c,t);let l=tm(c,t,c,e);t[r+pe]=l,id(t,l),Y_(l,e,t)}function Ca(e,t,n,r,o,i,s,a,c,l,u){let d=n+pe,h;if(t.firstCreatePass){if(h=gd(t,d,4,s||null,a||null),l!=null){let f=wn(t.consts,l);h.localNames=[];for(let v=0;v{class e{log(n){console.log(n)}warn(n){console.warn(n)}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"platform"})}return e})();function yd(e){return typeof e=="function"&&e[ye]!==void 0}function vd(e){return yd(e)&&typeof e.set=="function"}var Dd=new I("");function An(e){return!!e&&typeof e.then=="function"}function Cd(e){return!!e&&typeof e.subscribe=="function"}var vm=new I("");var Ed=(()=>{class e{resolve;reject;initialized=!1;done=!1;donePromise=new Promise((n,r)=>{this.resolve=n,this.reject=r});appInits=p(vm,{optional:!0})??[];injector=p(Le);constructor(){}runInitializers(){if(this.initialized)return;let n=[];for(let o of this.appInits){let i=De(this.injector,o);if(An(i))n.push(i);else if(Cd(i)){let s=new Promise((a,c)=>{i.subscribe({complete:a,error:c})});n.push(s)}}let r=()=>{this.done=!0,this.resolve()};Promise.all(n).then(()=>{r()}).catch(o=>{this.reject(o)}),n.length===0&&r(),this.initialized=!0}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Va=new I("");function Dm(){Xc(()=>{let e="";throw new E(600,e)})}function Cm(e){return e.isBoundToModule}var db=10;var fr=(()=>{class e{_runningTick=!1;_destroyed=!1;_destroyListeners=[];_views=[];internalErrorHandler=p(qe);afterRenderManager=p(Lg);zonelessEnabled=p(Yo);rootEffectScheduler=p(ta);dirtyFlags=0;tracingSnapshot=null;allTestViews=new Set;autoDetectTestViews=new Set;includeAllTestViews=!1;afterTick=new me;get allViews(){return[...(this.includeAllTestViews?this.allTestViews:this.autoDetectTestViews).keys(),...this._views]}get destroyed(){return this._destroyed}componentTypes=[];components=[];internalPendingTask=p(Qt);get isStable(){return this.internalPendingTask.hasPendingTasksObservable.pipe(W(n=>!n))}constructor(){p(lr,{optional:!0})}whenStable(){let n;return new Promise(r=>{n=this.isStable.subscribe({next:o=>{o&&r()}})}).finally(()=>{n.unsubscribe()})}_injector=p(ne);_rendererFactory=null;get injector(){return this._injector}bootstrap(n,r){return this.bootstrapImpl(n,r)}bootstrapImpl(n,r,o=Le.NULL){return this._injector.get(Oe).run(()=>{Z(U.BootstrapComponentStart);let s=n instanceof Fa;if(!this._injector.get(Ed).done){let v="";throw new E(405,v)}let c;s?c=n:c=this._injector.get(li).resolveComponentFactory(n),this.componentTypes.push(c.componentType);let l=Cm(c)?void 0:this._injector.get(sr),u=r||c.selector,d=c.create(o,[],u,l),h=d.location.nativeElement,f=d.injector.get(Dd,null);return f?.registerApplication(h),d.onDestroy(()=>{this.detachView(d.hostView),Xo(this.components,d),f?.unregisterApplication(h)}),this._loadComponent(d),Z(U.BootstrapComponentEnd,d),d})}tick(){this.zonelessEnabled||(this.dirtyFlags|=1),this._tick()}_tick(){Z(U.ChangeDetectionStart),this.tracingSnapshot!==null?this.tracingSnapshot.run(ad.CHANGE_DETECTION,this.tickImpl):this.tickImpl()}tickImpl=()=>{if(this._runningTick)throw Z(U.ChangeDetectionEnd),new E(101,!1);let n=M(null);try{this._runningTick=!0,this.synchronize()}finally{this._runningTick=!1,this.tracingSnapshot?.dispose(),this.tracingSnapshot=null,M(n),this.afterTick.next(),Z(U.ChangeDetectionEnd)}};synchronize(){this._rendererFactory===null&&!this._injector.destroyed&&(this._rendererFactory=this._injector.get(ir,null,{optional:!0}));let n=0;for(;this.dirtyFlags!==0&&n++Zo(n))){this.dirtyFlags|=2;return}else this.dirtyFlags&=-8}attachView(n){let r=n;this._views.push(r),r.attachToAppRef(this)}detachView(n){let r=n;Xo(this._views,r),r.detachFromAppRef()}_loadComponent(n){this.attachView(n.hostView);try{this.tick()}catch(o){this.internalErrorHandler(o)}this.components.push(n),this._injector.get(Va,[]).forEach(o=>o(n))}ngOnDestroy(){if(!this._destroyed)try{this._destroyListeners.forEach(n=>n()),this._views.slice().forEach(n=>n.destroy())}finally{this._destroyed=!0,this._views=[],this._destroyListeners=[]}}onDestroy(n){return this._destroyListeners.push(n),()=>Xo(this._destroyListeners,n)}destroy(){if(this._destroyed)throw new E(406,!1);let n=this._injector;n.destroy&&!n.destroyed&&n.destroy()}get viewCount(){return this._views.length}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Xo(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function hr(e,t,n,r){let o=V(),i=tr();if(Pt(o,i,t)){let s=Te(),a=Ks();WE(a,o,e,t,n,r)}return hr}var Bu=class{destroy(t){}updateValue(t,n){}swap(t,n){let r=Math.min(t,n),o=Math.max(t,n),i=this.detach(o);if(o-r>1){let s=this.detach(r);this.attach(r,i),this.attach(o,s)}else this.attach(r,i)}move(t,n){this.attach(n,this.detach(t))}};function Cu(e,t,n,r,o){return e===n&&Object.is(t,r)?1:Object.is(o(e,t),o(n,r))?-1:0}function fb(e,t,n,r){let o,i,s=0,a=e.length-1,c=void 0;if(Array.isArray(t)){M(r);let l=t.length-1;for(M(null);s<=a&&s<=l;){let u=e.at(s),d=t[s],h=Cu(s,u,s,d,n);if(h!==0){h<0&&e.updateValue(s,d),s++;continue}let f=e.at(a),v=t[l],_=Cu(a,f,l,v,n);if(_!==0){_<0&&e.updateValue(a,v),a--,l--;continue}let b=n(s,u),w=n(a,f),K=n(s,d);if(Object.is(K,w)){let Ee=n(l,v);Object.is(Ee,b)?(e.swap(s,a),e.updateValue(a,v),l--,a--):e.move(a,s),e.updateValue(s,d),s++;continue}if(o??=new Ea,i??=zp(e,s,a,n),Uu(e,o,s,K))e.updateValue(s,d),s++,a++;else if(i.has(K))o.set(b,e.detach(s)),a--;else{let Ee=e.create(s,t[s]);e.attach(s,Ee),s++,a++}}for(;s<=l;)$p(e,o,n,s,t[s]),s++}else if(t!=null){M(r);let l=t[Symbol.iterator]();M(null);let u=l.next();for(;!u.done&&s<=a;){let d=e.at(s),h=u.value,f=Cu(s,d,s,h,n);if(f!==0)f<0&&e.updateValue(s,h),s++,u=l.next();else{o??=new Ea,i??=zp(e,s,a,n);let v=n(s,h);if(Uu(e,o,s,v))e.updateValue(s,h),s++,a++,u=l.next();else if(!i.has(v))e.attach(s,e.create(s,h)),s++,a++,u=l.next();else{let _=n(s,d);o.set(_,e.detach(s)),a--}}}for(;!u.done;)$p(e,o,n,e.length,u.value),u=l.next()}for(;s<=a;)e.destroy(e.detach(a--));o?.forEach(l=>{e.destroy(l)})}function Uu(e,t,n,r){return t!==void 0&&t.has(r)?(e.attach(n,t.get(r)),t.delete(r),!0):!1}function $p(e,t,n,r,o){if(Uu(e,t,r,n(r,o)))e.updateValue(r,o);else{let i=e.create(r,o);e.attach(r,i)}}function zp(e,t,n,r){let o=new Set;for(let i=t;i<=n;i++)o.add(r(i,e.at(i)));return o}var Ea=class{kvMap=new Map;_vMap=void 0;has(t){return this.kvMap.has(t)}delete(t){if(!this.has(t))return!1;let n=this.kvMap.get(t);return this._vMap!==void 0&&this._vMap.has(n)?(this.kvMap.set(t,this._vMap.get(n)),this._vMap.delete(n)):this.kvMap.delete(t),!0}get(t){return this.kvMap.get(t)}set(t,n){if(this.kvMap.has(t)){let r=this.kvMap.get(t);this._vMap===void 0&&(this._vMap=new Map);let o=this._vMap;for(;o.has(r);)r=o.get(r);o.set(r,n)}else this.kvMap.set(t,n)}forEach(t){for(let[n,r]of this.kvMap)if(t(r,n),this._vMap!==void 0){let o=this._vMap;for(;o.has(r);)r=o.get(r),t(r,n)}}};function oe(e,t,n,r,o,i,s,a){ur("NgControlFlow");let c=V(),l=Te(),u=wn(l.consts,i);return Ca(c,l,e,t,n,r,o,u,256,s,a),_d}function _d(e,t,n,r,o,i,s,a){ur("NgControlFlow");let c=V(),l=Te(),u=wn(l.consts,i);return Ca(c,l,e,t,n,r,o,u,512,s,a),_d}function ie(e,t){ur("NgControlFlow");let n=V(),r=tr(),o=n[r]!==st?n[r]:-1,i=o!==-1?_a(n,pe+o):void 0,s=0;if(Pt(n,r,e)){let a=M(null);try{if(i!==void 0&&rm(i,s),e!==-1){let c=pe+e,l=_a(n,c),u=Gu(n[N],c),d=im(l,u,n),h=hd(n,u,t,{dehydratedView:d});ka(l,h,s,ti(u,d))}}finally{M(a)}}else if(i!==void 0){let a=nm(i,s);a!==void 0&&(a[le]=t)}}var Hu=class{lContainer;$implicit;$index;constructor(t,n,r){this.lContainer=t,this.$implicit=n,this.$index=r}get $count(){return this.lContainer.length-ce}};var $u=class{hasEmptyBlock;trackByFn;liveCollection;constructor(t,n,r){this.hasEmptyBlock=t,this.trackByFn=n,this.liveCollection=r}};function pr(e,t,n,r,o,i,s,a,c,l,u,d,h){ur("NgControlFlow");let f=V(),v=Te(),_=c!==void 0,b=V(),w=a?s.bind(b[$e][le]):s,K=new $u(_,w);b[pe+e]=K,Ca(f,v,e+1,t,n,r,o,wn(v.consts,i),256),_&&Ca(f,v,e+2,c,l,u,d,wn(v.consts,h),512)}var zu=class extends Bu{lContainer;hostLView;templateTNode;operationsCounter=void 0;needsIndexUpdate=!1;constructor(t,n,r){super(),this.lContainer=t,this.hostLView=n,this.templateTNode=r}get length(){return this.lContainer.length-ce}at(t){return this.getLView(t)[le].$implicit}attach(t,n){let r=n[Fr];this.needsIndexUpdate||=t!==this.length,ka(this.lContainer,n,t,ti(this.templateTNode,r)),hb(this.lContainer,t)}detach(t){return this.needsIndexUpdate||=t!==this.length-1,pb(this.lContainer,t),gb(this.lContainer,t)}create(t,n){let r=Fu(this.lContainer,this.templateTNode.tView.ssrId);return hd(this.hostLView,this.templateTNode,new Hu(this.lContainer,n,t),{dehydratedView:r})}destroy(t){Oa(t[N],t)}updateValue(t,n){this.getLView(t)[le].$implicit=n}reset(){this.needsIndexUpdate=!1}updateIndexes(){if(this.needsIndexUpdate)for(let t=0;t0){let i=r[Zt];vE(i,o),Sn.delete(r[Tt]),o.detachedLeaveAnimationFns=void 0}}function pb(e,t){if(e.length<=ce)return;let n=ce+t,r=e[n],o=r?r[At]:void 0;o&&o.leave&&o.leave.size>0&&(o.detachedLeaveAnimationFns=[])}function gb(e,t){return ri(e,t)}function mb(e,t){return nm(e,t)}function Gu(e,t){return qo(e,t)}function ke(e,t,n){let r=V(),o=tr();if(Pt(r,o,t)){let i=Te(),s=Ks();Gg(s,r,e,t,r[re],n)}return ke}function Gp(e,t,n,r,o){dd(t,e,n,o?"class":"style",r)}function m(e,t,n,r){let o=V(),i=o[N],s=e+pe,a=i.firstCreatePass?lm(s,o,2,t,GE,Zh(),n,r):i.data[s];if(YE(a,o,e,t,yb),Hs(a)){let c=o[N];$g(c,o,a),bg(c,a,o)}return r!=null&&zg(o,a),m}function g(){let e=Te(),t=je(),n=KE(t);return e.firstCreatePass&&um(e,n),Kh(n)&&Qh(),qh(),n.classesWithoutHost!=null&&bC(n)&&Gp(e,n,V(),n.classesWithoutHost,!0),n.stylesWithoutHost!=null&&wC(n)&&Gp(e,n,V(),n.stylesWithoutHost,!1),g}function qr(e,t,n,r){return m(e,t,n,r),g(),qr}var yb=(e,t,n,r,o)=>(Js(!0),Sg(t[re],r,dp()));function at(){return V()}var Qo=void 0;function vb(e){let t=Math.floor(Math.abs(e)),n=e.toString().replace(/^[^.]*\.?/,"").length;return t===1&&n===0?1:5}var Db=["en",[["a","p"],["AM","PM"]],[["AM","PM"]],[["S","M","T","W","T","F","S"],["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],["Su","Mo","Tu","We","Th","Fr","Sa"]],Qo,[["J","F","M","A","M","J","J","A","S","O","N","D"],["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],["January","February","March","April","May","June","July","August","September","October","November","December"]],Qo,[["B","A"],["BC","AD"],["Before Christ","Anno Domini"]],0,[6,0],["M/d/yy","MMM d, y","MMMM d, y","EEEE, MMMM d, y"],["h:mm\u202Fa","h:mm:ss\u202Fa","h:mm:ss\u202Fa z","h:mm:ss\u202Fa zzzz"],["{1}, {0}",Qo,Qo,Qo],[".",",",";","%","+","-","E","\xD7","\u2030","\u221E","NaN",":"],["#,##0.###","#,##0%","\xA4#,##0.00","#E0"],"USD","$","US Dollar",{},"ltr",vb],Eu={};function Ze(e){let t=Cb(e),n=Wp(t);if(n)return n;let r=t.split("-")[0];if(n=Wp(r),n)return n;if(r==="en")return Db;throw new E(701,!1)}function Wp(e){return e in Eu||(Eu[e]=qt.ng&&qt.ng.common&&qt.ng.common.locales&&qt.ng.common.locales[e]),Eu[e]}var de=(function(e){return e[e.LocaleId=0]="LocaleId",e[e.DayPeriodsFormat=1]="DayPeriodsFormat",e[e.DayPeriodsStandalone=2]="DayPeriodsStandalone",e[e.DaysFormat=3]="DaysFormat",e[e.DaysStandalone=4]="DaysStandalone",e[e.MonthsFormat=5]="MonthsFormat",e[e.MonthsStandalone=6]="MonthsStandalone",e[e.Eras=7]="Eras",e[e.FirstDayOfWeek=8]="FirstDayOfWeek",e[e.WeekendRange=9]="WeekendRange",e[e.DateFormat=10]="DateFormat",e[e.TimeFormat=11]="TimeFormat",e[e.DateTimeFormat=12]="DateTimeFormat",e[e.NumberSymbols=13]="NumberSymbols",e[e.NumberFormats=14]="NumberFormats",e[e.CurrencyCode=15]="CurrencyCode",e[e.CurrencySymbol=16]="CurrencySymbol",e[e.CurrencyName=17]="CurrencyName",e[e.Currencies=18]="Currencies",e[e.Directionality=19]="Directionality",e[e.PluralCase=20]="PluralCase",e[e.ExtraData=21]="ExtraData",e})(de||{});function Cb(e){return e.toLowerCase().replace(/_/g,"-")}var fi="en-US";var Eb=fi;function Em(e){typeof e=="string"&&(Eb=e.toLowerCase().replace(/_/g,"-"))}function te(e,t,n){let r=V(),o=Te(),i=je();return _m(o,r,r[re],i,e,t,n),te}function _m(e,t,n,r,o,i,s){let a=!0,c=null;if((r.type&3||s)&&(c??=yu(r,t,i),R_(r,e,t,s,n,o,i,c)&&(a=!1)),a){let l=r.outputs?.[o],u=r.hostDirectiveOutputs?.[o];if(u&&u.length)for(let d=0;d>17&32767}function _b(e){return(e&2)==2}function bb(e,t){return e&131071|t<<17}function Wu(e){return e|2}function Wr(e){return(e&131068)>>2}function _u(e,t){return e&-131069|t<<2}function wb(e){return(e&1)===1}function qu(e){return e|1}function Ib(e,t,n,r,o,i){let s=i?t.classBindings:t.styleBindings,a=ar(s),c=Wr(s);e[r]=n;let l=!1,u;if(Array.isArray(n)){let d=n;u=d[1],(u===null||kr(d,u)>0)&&(l=!0)}else u=n;if(o)if(c!==0){let h=ar(e[a+1]);e[r+1]=oa(h,a),h!==0&&(e[h+1]=_u(e[h+1],r)),e[a+1]=bb(e[a+1],r)}else e[r+1]=oa(a,0),a!==0&&(e[a+1]=_u(e[a+1],r)),a=r;else e[r+1]=oa(c,0),a===0?a=r:e[c+1]=_u(e[c+1],r),c=r;l&&(e[r+1]=Wu(e[r+1])),qp(e,u,r,!0),qp(e,u,r,!1),Sb(t,u,e,r,i),s=oa(a,c),i?t.classBindings=s:t.styleBindings=s}function Sb(e,t,n,r,o){let i=o?e.residualClasses:e.residualStyles;i!=null&&typeof t=="string"&&kr(i,t)>=0&&(n[r+1]=qu(n[r+1]))}function qp(e,t,n,r){let o=e[n+1],i=t===null,s=r?ar(o):Wr(o),a=!1;for(;s!==0&&(a===!1||i);){let c=e[s],l=e[s+1];Mb(c,t)&&(a=!0,e[s+1]=r?qu(l):Wu(l)),s=r?ar(l):Wr(l)}a&&(e[n+1]=r?Wu(o):qu(o))}function Mb(e,t){return e===null||t==null||(Array.isArray(e)?e[1]:e)===t?!0:Array.isArray(e)&&typeof t=="string"?kr(e,t)>=0:!1}function Ye(e,t){return Tb(e,t,null,!0),Ye}function Tb(e,t,n,r){let o=V(),i=Te(),s=ou(2);if(i.firstUpdatePass&&Nb(i,e,s,r),t!==st&&Pt(o,s,t)){let a=i.data[Kt()];kb(i,a,o,o[re],e,o[s+1]=Fb(t,n),r,s)}}function Ab(e,t){return t>=e.expandoStartIndex}function Nb(e,t,n,r){let o=e.data;if(o[n+1]===null){let i=o[Kt()],s=Ab(e,n);Lb(i,r)&&t===null&&!s&&(t=!1),t=xb(o,i,t,r),Ib(o,i,t,n,s,r)}}function xb(e,t,n,r){let o=sp(e),i=r?t.residualClasses:t.residualStyles;if(o===null)(r?t.classBindings:t.styleBindings)===0&&(n=bu(null,e,t,n,r),n=ii(n,t.attrs,r),i=null);else{let s=t.directiveStylingLast;if(s===-1||e[s]!==o)if(n=bu(o,e,t,n,r),i===null){let c=Rb(e,t,r);c!==void 0&&Array.isArray(c)&&(c=bu(null,e,t,c[1],r),c=ii(c,t.attrs,r),Ob(e,t,r,c))}else i=Pb(e,t,r)}return i!==void 0&&(r?t.residualClasses=i:t.residualStyles=i),n}function Rb(e,t,n){let r=n?t.classBindings:t.styleBindings;if(Wr(r)!==0)return e[ar(r)]}function Ob(e,t,n,r){let o=n?t.classBindings:t.styleBindings;e[ar(o)]=r}function Pb(e,t,n){let r,o=t.directiveEnd;for(let i=1+t.directiveStylingLast;i0;){let c=e[o],l=Array.isArray(c),u=l?c[1]:c,d=u===null,h=n[o+1];h===st&&(h=d?He:void 0);let f=d?Vs(h,r):u===r?h:void 0;if(l&&!ba(f)&&(f=Vs(c,r)),ba(f)&&(a=f,s))return a;let v=e[o+1];o=s?ar(v):Wr(v)}if(t!==null){let c=i?t.residualClasses:t.residualStyles;c!=null&&(a=Vs(c,r))}return a}function ba(e){return e!==void 0}function Fb(e,t){return e==null||e===""||(typeof t=="string"?e=e+t:typeof e=="object"&&(e=Vo(Ta(e)))),e}function Lb(e,t){return(e.flags&(t?8:16))!==0}function D(e,t=""){let n=V(),r=Te(),o=e+pe,i=r.firstCreatePass?gd(r,o,1,t,null):r.data[o],s=jb(r,n,i,t);n[o]=s,Qs()&&ld(r,n,s,i),Ur(i,!1)}var jb=(e,t,n,r)=>(Js(!0),ZC(t[re],r));function Vb(e,t,n,r=""){return Pt(e,tr(),n)?t+Pr(n)+r:st}function Bb(e,t,n,r,o,i=""){let s=tp(),a=fm(e,s,n,o);return ou(2),a?t+Pr(n)+r+Pr(o)+i:st}function X(e){return ct("",e),X}function ct(e,t,n){let r=V(),o=Vb(r,e,t,n);return o!==st&&bm(r,Kt(),o),ct}function mr(e,t,n,r,o){let i=V(),s=Bb(i,e,t,n,r,o);return s!==st&&bm(i,Kt(),s),mr}function bm(e,t,n){let r=Kl(t,e);YC(e[re],r,n)}function Ke(e,t,n){vd(t)&&(t=t());let r=V(),o=tr();if(Pt(r,o,t)){let i=Te(),s=Ks();Gg(s,r,e,t,r[re],n)}return Ke}function lt(e,t){let n=vd(e);return n&&e.set(t),n}function Qe(e,t){let n=V(),r=Te(),o=je();return _m(r,n,n[re],o,e,t),Qe}function Yp(e,t,n){let r=Te();r.firstCreatePass&&wm(t,r.data,r.blueprint,xt(e),n)}function wm(e,t,n,r,o){if(e=Ie(e),Array.isArray(e))for(let i=0;i>20;if(Wn(e)||!e.multi){let f=new rr(l,o,B,null),v=Iu(c,t,o?u:u+h,d);v===-1?(Mu(fa(a,s),i,c),wu(i,e,t.length),t.push(c),a.directiveStart++,a.directiveEnd++,o&&(a.providerIndexes+=1048576),n.push(f),s.push(f)):(n[v]=f,s[v]=f)}else{let f=Iu(c,t,u+h,d),v=Iu(c,t,u,u+h),_=f>=0&&n[f],b=v>=0&&n[v];if(o&&!b||!o&&!_){Mu(fa(a,s),i,c);let w=$b(o?Hb:Ub,n.length,o,r,l,e);!o&&b&&(n[v].providerFactory=w),wu(i,e,t.length,0),t.push(c),a.directiveStart++,a.directiveEnd++,o&&(a.providerIndexes+=1048576),n.push(w),s.push(w)}else{let w=Im(n[o?v:f],l,!o&&r);wu(i,e,f>-1?f:v,w)}!o&&r&&b&&n[v].componentProviders++}}}function wu(e,t,n,r){let o=Wn(t),i=kh(t);if(o||i){let c=(i?Ie(t.useClass):t).prototype.ngOnDestroy;if(c){let l=e.destroyHooks||(e.destroyHooks=[]);if(!o&&t.multi){let u=l.indexOf(n);u===-1?l.push(n,[r,c]):l[u+1].push(r,c)}else l.push(n,c)}}}function Im(e,t,n){return n&&e.componentProviders++,e.multi.push(t)-1}function Iu(e,t,n,r){for(let o=n;o{n.providersResolver=(r,o)=>Yp(r,o?o(e):e,!1),t&&(n.viewProvidersResolver=(r,o)=>Yp(r,o?o(t):t,!0))}}function wd(e,t,n){return Mm(V(),Ws(),e,t,n)}function Sm(e,t){let n=e[t];return n===st?void 0:n}function Mm(e,t,n,r,o,i){let s=t+n;return Pt(e,s,o)?dm(e,s+1,i?r.call(i,o):r(o)):Sm(e,s+1)}function zb(e,t,n,r,o,i,s){let a=t+n;return fm(e,a,o,i)?dm(e,a+2,s?r.call(s,o,i):r(o,i)):Sm(e,a+2)}function yr(e,t){let n=Te(),r,o=e+pe;n.firstCreatePass?(r=Gb(t,n.pipeRegistry),n.data[o]=r,r.onDestroy&&(n.destroyHooks??=[]).push(o,r.onDestroy)):r=n.data[o];let i=r.factory||(r.factory=pn(r.type,!0)),s,a=Re(B);try{let c=da(!1),l=i();return da(c),Ql(n,V(),o,l),l}finally{Re(a)}}function Gb(e,t){if(t)for(let n=t.length-1;n>=0;n--){let r=t[n];if(e===r.name)return r}}function Id(e,t,n){let r=e+pe,o=V(),i=$s(o,r);return Tm(o,r)?Mm(o,Ws(),t,i.transform,n,i):i.transform(n)}function Zr(e,t,n,r){let o=e+pe,i=V(),s=$s(i,o);return Tm(i,o)?zb(i,Ws(),t,s.transform,n,r,s):s.transform(n,r)}function Tm(e,t){return e[N].data[t].pure}var wa=class{ngModuleFactory;componentFactories;constructor(t,n){this.ngModuleFactory=t,this.componentFactories=n}},Sd=(()=>{class e{compileModuleSync(n){return new Da(n)}compileModuleAsync(n){return Promise.resolve(this.compileModuleSync(n))}compileModuleAndAllComponentsSync(n){let r=this.compileModuleSync(n),o=Ll(n),i=Rg(o.declarations).reduce((s,a)=>{let c=Cn(a);return c&&s.push(new Gr(c)),s},[]);return new wa(r,i)}compileModuleAndAllComponentsAsync(n){return Promise.resolve(this.compileModuleAndAllComponentsSync(n))}clearCache(){}clearCacheFor(n){}getModuleId(n){}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();var Am=(()=>{class e{applicationErrorHandler=p(qe);appRef=p(fr);taskService=p(Qt);ngZone=p(Oe);zonelessEnabled=p(Yo);tracing=p(lr,{optional:!0});zoneIsDefined=typeof Zone<"u"&&!!Zone.root.run;schedulerTickApplyArgs=[{data:{__scheduler_tick__:!0}}];subscriptions=new _e;angularZoneId=this.zoneIsDefined?this.ngZone._inner?.get(Lo):null;scheduleInRootZone=!this.zonelessEnabled&&this.zoneIsDefined&&(p(hu,{optional:!0})??!1);cancelScheduledCallback=null;useMicrotaskScheduler=!1;runningTick=!1;pendingRenderTaskId=null;constructor(){this.subscriptions.add(this.appRef.afterTick.subscribe(()=>{let n=this.taskService.add();if(!this.runningTick&&(this.cleanup(),!this.zonelessEnabled||this.appRef.includeAllTestViews)){this.taskService.remove(n);return}this.switchToMicrotaskScheduler(),this.taskService.remove(n)})),this.subscriptions.add(this.ngZone.onUnstable.subscribe(()=>{this.runningTick||this.cleanup()}))}switchToMicrotaskScheduler(){this.ngZone.runOutsideAngular(()=>{let n=this.taskService.add();this.useMicrotaskScheduler=!0,queueMicrotask(()=>{this.useMicrotaskScheduler=!1,this.taskService.remove(n)})})}notify(n){if(!this.zonelessEnabled&&n===5)return;switch(n){case 0:{this.appRef.dirtyFlags|=2;break}case 3:case 2:case 4:case 5:case 1:{this.appRef.dirtyFlags|=4;break}case 6:{this.appRef.dirtyFlags|=2;break}case 12:{this.appRef.dirtyFlags|=16;break}case 13:{this.appRef.dirtyFlags|=2;break}case 11:break;default:this.appRef.dirtyFlags|=8}if(this.appRef.tracingSnapshot=this.tracing?.snapshot(this.appRef.tracingSnapshot)??null,!this.shouldScheduleTick())return;let r=this.useMicrotaskScheduler?gp:lu;this.pendingRenderTaskId=this.taskService.add(),this.scheduleInRootZone?this.cancelScheduledCallback=Zone.root.run(()=>r(()=>this.tick())):this.cancelScheduledCallback=this.ngZone.runOutsideAngular(()=>r(()=>this.tick()))}shouldScheduleTick(){return!(this.appRef.destroyed||this.pendingRenderTaskId!==null||this.runningTick||this.appRef._runningTick||!this.zonelessEnabled&&this.zoneIsDefined&&Zone.current.get(Lo+this.angularZoneId))}tick(){if(this.runningTick||this.appRef.destroyed)return;if(this.appRef.dirtyFlags===0){this.cleanup();return}!this.zonelessEnabled&&this.appRef.dirtyFlags&7&&(this.appRef.dirtyFlags|=1);let n=this.taskService.add();try{this.ngZone.run(()=>{this.runningTick=!0,this.appRef._tick()},void 0,this.schedulerTickApplyArgs)}catch(r){this.applicationErrorHandler(r)}finally{this.taskService.remove(n),this.cleanup()}}ngOnDestroy(){this.subscriptions.unsubscribe(),this.cleanup()}cleanup(){if(this.runningTick=!1,this.cancelScheduledCallback?.(),this.cancelScheduledCallback=null,this.pendingRenderTaskId!==null){let n=this.pendingRenderTaskId;this.pendingRenderTaskId=null,this.taskService.remove(n)}}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function Nm(){return[{provide:yn,useExisting:Am},{provide:Oe,useClass:jo},{provide:Yo,useValue:!0}]}function Wb(){return typeof $localize<"u"&&$localize.locale||fi}var pi=new I("",{factory:()=>p(pi,{optional:!0,skipSelf:!0})||Wb()});function q(e){return Dh(e)}function Se(e,t){return ts(e,t?.equal)}var qb=e=>e;function Md(e,t){if(typeof e=="function"){let n=ml(e,qb,t?.equal);return xm(n,t?.debugName)}else{let n=ml(e.source,e.computation,e.equal);return xm(n,e.debugName)}}function xm(e,t){let n=e[ye],r=e;return r.set=o=>yh(n,o),r.update=o=>vh(n,o),r.asReadonly=Xs.bind(e),r}var Om=Symbol("InputSignalNode#UNSET"),hw=A(y({},rs),{transformFn:void 0,applyValueToInputSignal(e,t){Bn(e,t)}});function Pm(e,t){let n=Object.create(hw);n.value=e,n.transformFn=t?.transform;function r(){if(Fn(n),n.value===Om){let o=null;throw new E(-950,o)}return n.value}return r[ye]=n,r}var Ua=class{attributeName;constructor(t){this.attributeName=t}__NG_ELEMENT_ID__=()=>ai(this.attributeName);toString(){return`HostAttributeToken ${this.attributeName}`}};function Rm(e,t){return Pm(e,t)}function pw(e){return Pm(Om,e)}var km=(Rm.required=pw,Rm);var Td=new I(""),gw=new I("");function gi(e){return!e.moduleRef}function mw(e){let t=gi(e)?e.r3Injector:e.moduleRef.injector,n=t.get(Oe);return n.run(()=>{gi(e)?e.r3Injector.resolveInjectorInitializers():e.moduleRef.resolveInjectorInitializers();let r=t.get(qe),o;if(n.runOutsideAngular(()=>{o=n.onError.subscribe({next:r})}),gi(e)){let i=()=>t.destroy(),s=e.platformInjector.get(Td);s.add(i),t.onDestroy(()=>{o.unsubscribe(),s.delete(i)})}else{let i=()=>e.moduleRef.destroy(),s=e.platformInjector.get(Td);s.add(i),e.moduleRef.onDestroy(()=>{Xo(e.allPlatformModules,e.moduleRef),o.unsubscribe(),s.delete(i)})}return vw(r,n,()=>{let i=t.get(Qt),s=i.add(),a=t.get(Ed);return a.runInitializers(),a.donePromise.then(()=>{let c=t.get(pi,fi);if(Em(c||fi),!t.get(gw,!0))return gi(e)?t.get(fr):(e.allPlatformModules.push(e.moduleRef),e.moduleRef);if(gi(e)){let u=t.get(fr);return e.rootComponent!==void 0&&u.bootstrap(e.rootComponent),u}else return yw?.(e.moduleRef,e.allPlatformModules),e.moduleRef}).finally(()=>{i.remove(s)})})})}var yw;function vw(e,t,n){try{let r=n();return An(r)?r.catch(o=>{throw t.runOutsideAngular(()=>e(o)),o}):r}catch(r){throw t.runOutsideAngular(()=>e(r)),r}}var Ba=null;function Dw(e=[],t){return Le.create({name:t,providers:[{provide:$o,useValue:"platform"},{provide:Td,useValue:new Set([()=>Ba=null])},...e]})}function Cw(e=[]){if(Ba)return Ba;let t=Dw(e);return Ba=t,Dm(),Ew(t),t}function Ew(e){let t=e.get(Sa,null);De(e,()=>{t?.forEach(n=>n())})}var _w=1e4;var QV=_w-1e3;var Yr=(()=>{class e{static __NG_ELEMENT_ID__=bw}return e})();function bw(e){return ww(je(),V(),(e&16)===16)}function ww(e,t,n){if(Yt(e)&&!n){let r=Ge(e.index,t);return new or(r,r)}else if(e.type&175){let r=t[$e];return new or(r,t)}return null}function Fm(e){let{rootComponent:t,appProviders:n,platformProviders:r,platformRef:o}=e;Z(U.BootstrapApplicationStart);try{let i=o?.injector??Cw(r),s=[Nm(),yp,...n||[]],a=new oi({providers:s,parent:i,debugName:"",runEnvironmentInitializers:!1});return mw({r3Injector:a.injector,platformInjector:i,rootComponent:t})}catch(i){return Promise.reject(i)}finally{Z(U.BootstrapApplicationEnd)}}function Kr(e){return typeof e=="boolean"?e:e!=null&&e!=="false"}var Lm=null;function ut(){return Lm}function xd(e){Lm??=e}var mi=class{},Qr=(()=>{class e{historyGo(n){throw new Error("")}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(jm),providedIn:"platform"})}return e})();var jm=(()=>{class e extends Qr{_location;_history;_doc=p(ue);constructor(){super(),this._location=window.location,this._history=window.history}getBaseHrefFromDOM(){return ut().getBaseHref(this._doc)}onPopState(n){let r=ut().getGlobalEventTarget(this._doc,"window");return r.addEventListener("popstate",n,!1),()=>r.removeEventListener("popstate",n)}onHashChange(n){let r=ut().getGlobalEventTarget(this._doc,"window");return r.addEventListener("hashchange",n,!1),()=>r.removeEventListener("hashchange",n)}get href(){return this._location.href}get protocol(){return this._location.protocol}get hostname(){return this._location.hostname}get port(){return this._location.port}get pathname(){return this._location.pathname}get search(){return this._location.search}get hash(){return this._location.hash}set pathname(n){this._location.pathname=n}pushState(n,r,o){this._history.pushState(n,r,o)}replaceState(n,r,o){this._history.replaceState(n,r,o)}forward(){this._history.forward()}back(){this._history.back()}historyGo(n=0){this._history.go(n)}getState(){return this._history.state}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>new e,providedIn:"platform"})}return e})();function Um(e,t){return e?t?e.endsWith("/")?t.startsWith("/")?e+t.slice(1):e+t:t.startsWith("/")?e+t:`${e}/${t}`:e:t}function Vm(e){let t=e.search(/#|\?|$/);return e[t-1]==="/"?e.slice(0,t-1)+e.slice(t):e}function Nn(e){return e&&e[0]!=="?"?`?${e}`:e}var Jr=(()=>{class e{historyGo(n){throw new Error("")}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(Sw),providedIn:"root"})}return e})(),Iw=new I(""),Sw=(()=>{class e extends Jr{_platformLocation;_baseHref;_removeListenerFns=[];constructor(n,r){super(),this._platformLocation=n,this._baseHref=r??this._platformLocation.getBaseHrefFromDOM()??p(ue).location?.origin??""}ngOnDestroy(){for(;this._removeListenerFns.length;)this._removeListenerFns.pop()()}onPopState(n){this._removeListenerFns.push(this._platformLocation.onPopState(n),this._platformLocation.onHashChange(n))}getBaseHref(){return this._baseHref}prepareExternalUrl(n){return Um(this._baseHref,n)}path(n=!1){let r=this._platformLocation.pathname+Nn(this._platformLocation.search),o=this._platformLocation.hash;return o&&n?`${r}${o}`:r}pushState(n,r,o,i){let s=this.prepareExternalUrl(o+Nn(i));this._platformLocation.pushState(n,r,s)}replaceState(n,r,o,i){let s=this.prepareExternalUrl(o+Nn(i));this._platformLocation.replaceState(n,r,s)}forward(){this._platformLocation.forward()}back(){this._platformLocation.back()}getState(){return this._platformLocation.getState()}historyGo(n=0){this._platformLocation.historyGo?.(n)}static \u0275fac=function(r){return new(r||e)(T(Qr),T(Iw,8))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();var Xr=(()=>{class e{_subject=new me;_basePath;_locationStrategy;_urlChangeListeners=[];_urlChangeSubscription=null;constructor(n){this._locationStrategy=n;let r=this._locationStrategy.getBaseHref();this._basePath=Aw(Vm(Bm(r))),this._locationStrategy.onPopState(o=>{this._subject.next({url:this.path(!0),pop:!0,state:o.state,type:o.type})})}ngOnDestroy(){this._urlChangeSubscription?.unsubscribe(),this._urlChangeListeners=[]}path(n=!1){return this.normalize(this._locationStrategy.path(n))}getState(){return this._locationStrategy.getState()}isCurrentPathEqualTo(n,r=""){return this.path()==this.normalize(n+Nn(r))}normalize(n){return e.stripTrailingSlash(Tw(this._basePath,Bm(n)))}prepareExternalUrl(n){return n&&n[0]!=="/"&&(n="/"+n),this._locationStrategy.prepareExternalUrl(n)}go(n,r="",o=null){this._locationStrategy.pushState(o,"",n,r),this._notifyUrlChangeListeners(this.prepareExternalUrl(n+Nn(r)),o)}replaceState(n,r="",o=null){this._locationStrategy.replaceState(o,"",n,r),this._notifyUrlChangeListeners(this.prepareExternalUrl(n+Nn(r)),o)}forward(){this._locationStrategy.forward()}back(){this._locationStrategy.back()}historyGo(n=0){this._locationStrategy.historyGo?.(n)}onUrlChange(n){return this._urlChangeListeners.push(n),this._urlChangeSubscription??=this.subscribe(r=>{this._notifyUrlChangeListeners(r.url,r.state)}),()=>{let r=this._urlChangeListeners.indexOf(n);this._urlChangeListeners.splice(r,1),this._urlChangeListeners.length===0&&(this._urlChangeSubscription?.unsubscribe(),this._urlChangeSubscription=null)}}_notifyUrlChangeListeners(n="",r){this._urlChangeListeners.forEach(o=>o(n,r))}subscribe(n,r,o){return this._subject.subscribe({next:n,error:r??void 0,complete:o??void 0})}static normalizeQueryParams=Nn;static joinWithSlash=Um;static stripTrailingSlash=Vm;static \u0275fac=function(r){return new(r||e)(T(Jr))};static \u0275prov=S({token:e,factory:()=>Mw(),providedIn:"root"})}return e})();function Mw(){return new Xr(T(Jr))}function Tw(e,t){if(!e||!t.startsWith(e))return t;let n=t.substring(e.length);return n===""||["/",";","?","#"].includes(n[0])?n:t}function Bm(e){return e.replace(/\/index.html$/,"")}function Aw(e){if(new RegExp("^(https?:)?//").test(e)){let[,n]=e.split(/\/\/[^\/]+/);return n}return e}var Ae=(function(e){return e[e.Format=0]="Format",e[e.Standalone=1]="Standalone",e})(Ae||{}),Y=(function(e){return e[e.Narrow=0]="Narrow",e[e.Abbreviated=1]="Abbreviated",e[e.Wide=2]="Wide",e[e.Short=3]="Short",e})(Y||{}),Be=(function(e){return e[e.Short=0]="Short",e[e.Medium=1]="Medium",e[e.Long=2]="Long",e[e.Full=3]="Full",e})(Be||{}),tn={Decimal:0,Group:1,List:2,PercentSign:3,PlusSign:4,MinusSign:5,Exponential:6,SuperscriptingExponent:7,PerMille:8,Infinity:9,NaN:10,TimeSeparator:11,CurrencyDecimal:12,CurrencyGroup:13};function $m(e){return Ze(e)[de.LocaleId]}function zm(e,t,n){let r=Ze(e),o=[r[de.DayPeriodsFormat],r[de.DayPeriodsStandalone]],i=dt(o,t);return dt(i,n)}function Gm(e,t,n){let r=Ze(e),o=[r[de.DaysFormat],r[de.DaysStandalone]],i=dt(o,t);return dt(i,n)}function Wm(e,t,n){let r=Ze(e),o=[r[de.MonthsFormat],r[de.MonthsStandalone]],i=dt(o,t);return dt(i,n)}function qm(e,t){let r=Ze(e)[de.Eras];return dt(r,t)}function yi(e,t){let n=Ze(e);return dt(n[de.DateFormat],t)}function vi(e,t){let n=Ze(e);return dt(n[de.TimeFormat],t)}function Di(e,t){let r=Ze(e)[de.DateTimeFormat];return dt(r,t)}function Ci(e,t){let n=Ze(e),r=n[de.NumberSymbols][t];if(typeof r>"u"){if(t===tn.CurrencyDecimal)return n[de.NumberSymbols][tn.Decimal];if(t===tn.CurrencyGroup)return n[de.NumberSymbols][tn.Group]}return r}function Zm(e){if(!e[de.ExtraData])throw new E(2303,!1)}function Ym(e){let t=Ze(e);return Zm(t),(t[de.ExtraData][2]||[]).map(r=>typeof r=="string"?Rd(r):[Rd(r[0]),Rd(r[1])])}function Km(e,t,n){let r=Ze(e);Zm(r);let o=[r[de.ExtraData][0],r[de.ExtraData][1]],i=dt(o,t)||[];return dt(i,n)||[]}function dt(e,t){for(let n=t;n>-1;n--)if(typeof e[n]<"u")return e[n];throw new E(2304,!1)}function Rd(e){let[t,n]=e.split(":");return{hours:+t,minutes:+n}}var Nw=/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/,Ha={},xw=/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;function Qm(e,t,n,r){let o=Bw(e);t=en(n,t)||t;let s=[],a;for(;t;)if(a=xw.exec(t),a){s=s.concat(a.slice(1));let u=s.pop();if(!u)break;t=u}else{s.push(t);break}let c=o.getTimezoneOffset();r&&(c=Xm(r,c),o=Vw(o,r));let l="";return s.forEach(u=>{let d=Lw(u);l+=d?d(o,n,c):u==="''"?"'":u.replace(/(^'|'$)/g,"").replace(/''/g,"'")}),l}function qa(e,t,n){let r=new Date(0);return r.setFullYear(e,t,n),r.setHours(0,0,0),r}function en(e,t){let n=$m(e);if(Ha[n]??={},Ha[n][t])return Ha[n][t];let r="";switch(t){case"shortDate":r=yi(e,Be.Short);break;case"mediumDate":r=yi(e,Be.Medium);break;case"longDate":r=yi(e,Be.Long);break;case"fullDate":r=yi(e,Be.Full);break;case"shortTime":r=vi(e,Be.Short);break;case"mediumTime":r=vi(e,Be.Medium);break;case"longTime":r=vi(e,Be.Long);break;case"fullTime":r=vi(e,Be.Full);break;case"short":let o=en(e,"shortTime"),i=en(e,"shortDate");r=$a(Di(e,Be.Short),[o,i]);break;case"medium":let s=en(e,"mediumTime"),a=en(e,"mediumDate");r=$a(Di(e,Be.Medium),[s,a]);break;case"long":let c=en(e,"longTime"),l=en(e,"longDate");r=$a(Di(e,Be.Long),[c,l]);break;case"full":let u=en(e,"fullTime"),d=en(e,"fullDate");r=$a(Di(e,Be.Full),[u,d]);break}return r&&(Ha[n][t]=r),r}function $a(e,t){return t&&(e=e.replace(/\{([^}]+)}/g,function(n,r){return t!=null&&r in t?t[r]:n})),e}function Et(e,t,n="-",r,o){let i="";(e<0||o&&e<=0)&&(o?e=-e+1:(e=-e,i=n));let s=String(e);for(;s.length0||a>-n)&&(a+=n),e===3)a===0&&n===-12&&(a=12);else if(e===6)return Rw(a,t);let c=Ci(s,tn.MinusSign);return Et(a,t,c,r,o)}}function Ow(e,t){switch(e){case 0:return t.getFullYear();case 1:return t.getMonth();case 2:return t.getDate();case 3:return t.getHours();case 4:return t.getMinutes();case 5:return t.getSeconds();case 6:return t.getMilliseconds();case 7:return t.getDay();default:throw new E(2301,!1)}}function ee(e,t,n=Ae.Format,r=!1){return function(o,i){return Pw(o,i,e,t,n,r)}}function Pw(e,t,n,r,o,i){switch(n){case 2:return Wm(t,o,r)[e.getMonth()];case 1:return Gm(t,o,r)[e.getDay()];case 0:let s=e.getHours(),a=e.getMinutes();if(i){let l=Ym(t),u=Km(t,o,r),d=l.findIndex(h=>{if(Array.isArray(h)){let[f,v]=h,_=s>=f.hours&&a>=f.minutes,b=s0?Math.floor(o/60):Math.ceil(o/60);switch(e){case 0:return(o>=0?"+":"")+Et(s,2,i)+Et(Math.abs(o%60),2,i);case 1:return"GMT"+(o>=0?"+":"")+Et(s,1,i);case 2:return"GMT"+(o>=0?"+":"")+Et(s,2,i)+":"+Et(Math.abs(o%60),2,i);case 3:return r===0?"Z":(o>=0?"+":"")+Et(s,2,i)+":"+Et(Math.abs(o%60),2,i);default:throw new E(2310,!1)}}}var kw=0,Wa=4;function Fw(e){let t=qa(e,kw,1).getDay();return qa(e,0,1+(t<=Wa?Wa:Wa+7)-t)}function Jm(e){let t=e.getDay(),n=t===0?-3:Wa-t;return qa(e.getFullYear(),e.getMonth(),e.getDate()+n)}function Od(e,t=!1){return function(n,r){let o;if(t){let i=new Date(n.getFullYear(),n.getMonth(),1).getDay()-1,s=n.getDate();o=1+Math.floor((s+i)/7)}else{let i=Jm(n),s=Fw(i.getFullYear()),a=i.getTime()-s.getTime();o=1+Math.round(a/6048e5)}return Et(o,e,Ci(r,tn.MinusSign))}}function Ga(e,t=!1){return function(n,r){let i=Jm(n).getFullYear();return Et(i,e,Ci(r,tn.MinusSign),t)}}var Pd={};function Lw(e){if(Pd[e])return Pd[e];let t;switch(e){case"G":case"GG":case"GGG":t=ee(3,Y.Abbreviated);break;case"GGGG":t=ee(3,Y.Wide);break;case"GGGGG":t=ee(3,Y.Narrow);break;case"y":t=ge(0,1,0,!1,!0);break;case"yy":t=ge(0,2,0,!0,!0);break;case"yyy":t=ge(0,3,0,!1,!0);break;case"yyyy":t=ge(0,4,0,!1,!0);break;case"Y":t=Ga(1);break;case"YY":t=Ga(2,!0);break;case"YYY":t=Ga(3);break;case"YYYY":t=Ga(4);break;case"M":case"L":t=ge(1,1,1);break;case"MM":case"LL":t=ge(1,2,1);break;case"MMM":t=ee(2,Y.Abbreviated);break;case"MMMM":t=ee(2,Y.Wide);break;case"MMMMM":t=ee(2,Y.Narrow);break;case"LLL":t=ee(2,Y.Abbreviated,Ae.Standalone);break;case"LLLL":t=ee(2,Y.Wide,Ae.Standalone);break;case"LLLLL":t=ee(2,Y.Narrow,Ae.Standalone);break;case"w":t=Od(1);break;case"ww":t=Od(2);break;case"W":t=Od(1,!0);break;case"d":t=ge(2,1);break;case"dd":t=ge(2,2);break;case"c":case"cc":t=ge(7,1);break;case"ccc":t=ee(1,Y.Abbreviated,Ae.Standalone);break;case"cccc":t=ee(1,Y.Wide,Ae.Standalone);break;case"ccccc":t=ee(1,Y.Narrow,Ae.Standalone);break;case"cccccc":t=ee(1,Y.Short,Ae.Standalone);break;case"E":case"EE":case"EEE":t=ee(1,Y.Abbreviated);break;case"EEEE":t=ee(1,Y.Wide);break;case"EEEEE":t=ee(1,Y.Narrow);break;case"EEEEEE":t=ee(1,Y.Short);break;case"a":case"aa":case"aaa":t=ee(0,Y.Abbreviated);break;case"aaaa":t=ee(0,Y.Wide);break;case"aaaaa":t=ee(0,Y.Narrow);break;case"b":case"bb":case"bbb":t=ee(0,Y.Abbreviated,Ae.Standalone,!0);break;case"bbbb":t=ee(0,Y.Wide,Ae.Standalone,!0);break;case"bbbbb":t=ee(0,Y.Narrow,Ae.Standalone,!0);break;case"B":case"BB":case"BBB":t=ee(0,Y.Abbreviated,Ae.Format,!0);break;case"BBBB":t=ee(0,Y.Wide,Ae.Format,!0);break;case"BBBBB":t=ee(0,Y.Narrow,Ae.Format,!0);break;case"h":t=ge(3,1,-12);break;case"hh":t=ge(3,2,-12);break;case"H":t=ge(3,1);break;case"HH":t=ge(3,2);break;case"m":t=ge(4,1);break;case"mm":t=ge(4,2);break;case"s":t=ge(5,1);break;case"ss":t=ge(5,2);break;case"S":t=ge(6,1);break;case"SS":t=ge(6,2);break;case"SSS":t=ge(6,3);break;case"Z":case"ZZ":case"ZZZ":t=za(0);break;case"ZZZZZ":t=za(3);break;case"O":case"OO":case"OOO":case"z":case"zz":case"zzz":t=za(1);break;case"OOOO":case"ZZZZ":case"zzzz":t=za(2);break;default:return null}return Pd[e]=t,t}function Xm(e,t){e=e.replace(/:/g,"");let n=Date.parse("Jan 01, 1970 00:00:00 "+e)/6e4;return isNaN(n)?t:n}function jw(e,t){return e=new Date(e.getTime()),e.setMinutes(e.getMinutes()+t),e}function Vw(e,t,n){let o=e.getTimezoneOffset(),i=Xm(t,o);return jw(e,-1*(i-o))}function Bw(e){if(Hm(e))return e;if(typeof e=="number"&&!isNaN(e))return new Date(e);if(typeof e=="string"){if(e=e.trim(),/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(e)){let[o,i=1,s=1]=e.split("-").map(a=>+a);return qa(o,i-1,s)}let n=parseFloat(e);if(!isNaN(e-n))return new Date(n);let r;if(r=e.match(Nw))return Uw(r)}let t=new Date(e);if(!Hm(t))throw new E(2311,!1);return t}function Uw(e){let t=new Date(0),n=0,r=0,o=e[8]?t.setUTCFullYear:t.setFullYear,i=e[8]?t.setUTCHours:t.setHours;e[9]&&(n=Number(e[9]+e[10]),r=Number(e[9]+e[11])),o.call(t,Number(e[1]),Number(e[2])-1,Number(e[3]));let s=Number(e[4]||0)-n,a=Number(e[5]||0)-r,c=Number(e[6]||0),l=Math.floor(parseFloat("0."+(e[7]||0))*1e3);return i.call(t,s,a,c,l),t}function Hm(e){return e instanceof Date&&!isNaN(e.valueOf())}function Hw(e,t){return new E(2100,!1)}var $w="mediumDate",ey=new I(""),ty=new I(""),Ei=(()=>{class e{locale;defaultTimezone;defaultOptions;constructor(n,r,o){this.locale=n,this.defaultTimezone=r,this.defaultOptions=o}transform(n,r,o,i){if(n==null||n===""||n!==n)return null;try{let s=r??this.defaultOptions?.dateFormat??$w,a=o??this.defaultOptions?.timezone??this.defaultTimezone??void 0;return Qm(n,s,i||this.locale,a)}catch(s){throw Hw(e,s.message)}}static \u0275fac=function(r){return new(r||e)(B(pi,16),B(ey,24),B(ty,24))};static \u0275pipe=ja({name:"date",type:e,pure:!0})}return e})();var kd=(()=>{class e{transform(n){return JSON.stringify(n,null,2)}static \u0275fac=function(r){return new(r||e)};static \u0275pipe=ja({name:"json",type:e,pure:!1})}return e})();var eo=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=kt({type:e});static \u0275inj=mt({})}return e})();function _i(e,t){t=encodeURIComponent(t);for(let n of e.split(";")){let r=n.indexOf("="),[o,i]=r==-1?[n,""]:[n.slice(0,r),n.slice(r+1)];if(o.trim()===t)return decodeURIComponent(i)}return null}var vr=class{};var ny="browser";var bi=class{_doc;constructor(t){this._doc=t}manager},Za=(()=>{class e extends bi{constructor(n){super(n)}supports(n){return!0}addEventListener(n,r,o,i){return n.addEventListener(r,o,i),()=>this.removeEventListener(n,r,o,i)}removeEventListener(n,r,o,i){return n.removeEventListener(r,o,i)}static \u0275fac=function(r){return new(r||e)(T(ue))};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),Qa=new I(""),Bd=(()=>{class e{_zone;_plugins;_eventNameToPlugin=new Map;constructor(n,r){this._zone=r,n.forEach(s=>{s.manager=this});let o=n.filter(s=>!(s instanceof Za));this._plugins=o.slice().reverse();let i=n.find(s=>s instanceof Za);i&&this._plugins.push(i)}addEventListener(n,r,o,i){return this._findPluginFor(r).addEventListener(n,r,o,i)}getZone(){return this._zone}_findPluginFor(n){let r=this._eventNameToPlugin.get(n);if(r)return r;if(r=this._plugins.find(i=>i.supports(n)),!r)throw new E(5101,!1);return this._eventNameToPlugin.set(n,r),r}static \u0275fac=function(r){return new(r||e)(T(Qa),T(Oe))};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),Ld="ng-app-id";function ry(e){for(let t of e)t.remove()}function oy(e,t){let n=t.createElement("style");return n.textContent=e,n}function Gw(e,t,n,r){let o=e.head?.querySelectorAll(`style[${Ld}="${t}"],link[${Ld}="${t}"]`);if(o)for(let i of o)i.removeAttribute(Ld),i instanceof HTMLLinkElement?r.set(i.href.slice(i.href.lastIndexOf("/")+1),{usage:0,elements:[i]}):i.textContent&&n.set(i.textContent,{usage:0,elements:[i]})}function Vd(e,t){let n=t.createElement("link");return n.setAttribute("rel","stylesheet"),n.setAttribute("href",e),n}var Ud=(()=>{class e{doc;appId;nonce;inline=new Map;external=new Map;hosts=new Set;constructor(n,r,o,i={}){this.doc=n,this.appId=r,this.nonce=o,Gw(n,r,this.inline,this.external),this.hosts.add(n.head)}addStyles(n,r){for(let o of n)this.addUsage(o,this.inline,oy);r?.forEach(o=>this.addUsage(o,this.external,Vd))}removeStyles(n,r){for(let o of n)this.removeUsage(o,this.inline);r?.forEach(o=>this.removeUsage(o,this.external))}addUsage(n,r,o){let i=r.get(n);i?i.usage++:r.set(n,{usage:1,elements:[...this.hosts].map(s=>this.addElement(s,o(n,this.doc)))})}removeUsage(n,r){let o=r.get(n);o&&(o.usage--,o.usage<=0&&(ry(o.elements),r.delete(n)))}ngOnDestroy(){for(let[,{elements:n}]of[...this.inline,...this.external])ry(n);this.hosts.clear()}addHost(n){this.hosts.add(n);for(let[r,{elements:o}]of this.inline)o.push(this.addElement(n,oy(r,this.doc)));for(let[r,{elements:o}]of this.external)o.push(this.addElement(n,Vd(r,this.doc)))}removeHost(n){this.hosts.delete(n)}addElement(n,r){return this.nonce&&r.setAttribute("nonce",this.nonce),n.appendChild(r)}static \u0275fac=function(r){return new(r||e)(T(ue),T(Ia),T(Ma,8),T(ci))};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),jd={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/",math:"http://www.w3.org/1998/Math/MathML"},Hd=/%COMP%/g;var sy="%COMP%",Ww=`_nghost-${sy}`,qw=`_ngcontent-${sy}`,Zw=!0,Yw=new I("",{factory:()=>Zw});function Kw(e){return qw.replace(Hd,e)}function Qw(e){return Ww.replace(Hd,e)}function ay(e,t){return t.map(n=>n.replace(Hd,e))}var $d=(()=>{class e{eventManager;sharedStylesHost;appId;removeStylesOnCompDestroy;doc;ngZone;nonce;tracingService;rendererByCompId=new Map;defaultRenderer;constructor(n,r,o,i,s,a,c=null,l=null){this.eventManager=n,this.sharedStylesHost=r,this.appId=o,this.removeStylesOnCompDestroy=i,this.doc=s,this.ngZone=a,this.nonce=c,this.tracingService=l,this.defaultRenderer=new wi(n,s,a,this.tracingService)}createRenderer(n,r){if(!n||!r)return this.defaultRenderer;let o=this.getOrCreateRenderer(n,r);return o instanceof Ka?o.applyToHost(n):o instanceof Ii&&o.applyStyles(),o}getOrCreateRenderer(n,r){let o=this.rendererByCompId,i=o.get(r.id);if(!i){let s=this.doc,a=this.ngZone,c=this.eventManager,l=this.sharedStylesHost,u=this.removeStylesOnCompDestroy,d=this.tracingService;switch(r.encapsulation){case Ct.Emulated:i=new Ka(c,l,r,this.appId,u,s,a,d);break;case Ct.ShadowDom:return new Ya(c,n,r,s,a,this.nonce,d,l);case Ct.ExperimentalIsolatedShadowDom:return new Ya(c,n,r,s,a,this.nonce,d);default:i=new Ii(c,l,r,u,s,a,d);break}o.set(r.id,i)}return i}ngOnDestroy(){this.rendererByCompId.clear()}componentReplaced(n){this.rendererByCompId.delete(n)}static \u0275fac=function(r){return new(r||e)(T(Bd),T(Ud),T(Ia),T(Yw),T(ue),T(Oe),T(Ma),T(lr,8))};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),wi=class{eventManager;doc;ngZone;tracingService;data=Object.create(null);throwOnSyntheticProps=!0;constructor(t,n,r,o){this.eventManager=t,this.doc=n,this.ngZone=r,this.tracingService=o}destroy(){}destroyNode=null;createElement(t,n){return n?this.doc.createElementNS(jd[n]||n,t):this.doc.createElement(t)}createComment(t){return this.doc.createComment(t)}createText(t){return this.doc.createTextNode(t)}appendChild(t,n){(iy(t)?t.content:t).appendChild(n)}insertBefore(t,n,r){t&&(iy(t)?t.content:t).insertBefore(n,r)}removeChild(t,n){n.remove()}selectRootElement(t,n){let r=typeof t=="string"?this.doc.querySelector(t):t;if(!r)throw new E(-5104,!1);return n||(r.textContent=""),r}parentNode(t){return t.parentNode}nextSibling(t){return t.nextSibling}setAttribute(t,n,r,o){if(o){n=o+":"+n;let i=jd[o];i?t.setAttributeNS(i,n,r):t.setAttribute(n,r)}else t.setAttribute(n,r)}removeAttribute(t,n,r){if(r){let o=jd[r];o?t.removeAttributeNS(o,n):t.removeAttribute(`${r}:${n}`)}else t.removeAttribute(n)}addClass(t,n){t.classList.add(n)}removeClass(t,n){t.classList.remove(n)}setStyle(t,n,r,o){o&(Ot.DashCase|Ot.Important)?t.style.setProperty(n,r,o&Ot.Important?"important":""):t.style[n]=r}removeStyle(t,n,r){r&Ot.DashCase?t.style.removeProperty(n):t.style[n]=""}setProperty(t,n,r){t!=null&&(t[n]=r)}setValue(t,n){t.nodeValue=n}listen(t,n,r,o){if(typeof t=="string"&&(t=ut().getGlobalEventTarget(this.doc,t),!t))throw new E(5102,!1);let i=this.decoratePreventDefault(r);return this.tracingService?.wrapEventListener&&(i=this.tracingService.wrapEventListener(t,n,i)),this.eventManager.addEventListener(t,n,i,o)}decoratePreventDefault(t){return n=>{if(n==="__ngUnwrap__")return t;t(n)===!1&&n.preventDefault()}}};function iy(e){return e.tagName==="TEMPLATE"&&e.content!==void 0}var Ya=class extends wi{hostEl;sharedStylesHost;shadowRoot;constructor(t,n,r,o,i,s,a,c){super(t,o,i,a),this.hostEl=n,this.sharedStylesHost=c,this.shadowRoot=n.attachShadow({mode:"open"}),this.sharedStylesHost&&this.sharedStylesHost.addHost(this.shadowRoot);let l=r.styles;l=ay(r.id,l);for(let d of l){let h=document.createElement("style");s&&h.setAttribute("nonce",s),h.textContent=d,this.shadowRoot.appendChild(h)}let u=r.getExternalStyles?.();if(u)for(let d of u){let h=Vd(d,o);s&&h.setAttribute("nonce",s),this.shadowRoot.appendChild(h)}}nodeOrShadowRoot(t){return t===this.hostEl?this.shadowRoot:t}appendChild(t,n){return super.appendChild(this.nodeOrShadowRoot(t),n)}insertBefore(t,n,r){return super.insertBefore(this.nodeOrShadowRoot(t),n,r)}removeChild(t,n){return super.removeChild(null,n)}parentNode(t){return this.nodeOrShadowRoot(super.parentNode(this.nodeOrShadowRoot(t)))}destroy(){this.sharedStylesHost&&this.sharedStylesHost.removeHost(this.shadowRoot)}},Ii=class extends wi{sharedStylesHost;removeStylesOnCompDestroy;styles;styleUrls;constructor(t,n,r,o,i,s,a,c){super(t,i,s,a),this.sharedStylesHost=n,this.removeStylesOnCompDestroy=o;let l=r.styles;this.styles=c?ay(c,l):l,this.styleUrls=r.getExternalStyles?.(c)}applyStyles(){this.sharedStylesHost.addStyles(this.styles,this.styleUrls)}destroy(){this.removeStylesOnCompDestroy&&Sn.size===0&&this.sharedStylesHost.removeStyles(this.styles,this.styleUrls)}},Ka=class extends Ii{contentAttr;hostAttr;constructor(t,n,r,o,i,s,a,c){let l=o+"-"+r.id;super(t,n,r,i,s,a,c,l),this.contentAttr=Kw(l),this.hostAttr=Qw(l)}applyToHost(t){this.applyStyles(),this.setAttribute(t,this.hostAttr,"")}createElement(t,n){let r=super.createElement(t,n);return super.setAttribute(r,this.contentAttr,""),r}};var Ja=class e extends mi{supportsDOMEvents=!0;static makeCurrent(){xd(new e)}onAndCancel(t,n,r,o){return t.addEventListener(n,r,o),()=>{t.removeEventListener(n,r,o)}}dispatchEvent(t,n){t.dispatchEvent(n)}remove(t){t.remove()}createElement(t,n){return n=n||this.getDefaultDocument(),n.createElement(t)}createHtmlDocument(){return document.implementation.createHTMLDocument("fakeTitle")}getDefaultDocument(){return document}isElementNode(t){return t.nodeType===Node.ELEMENT_NODE}isShadowRoot(t){return t instanceof DocumentFragment}getGlobalEventTarget(t,n){return n==="window"?window:n==="document"?t:n==="body"?t.body:null}getBaseHref(t){let n=Jw();return n==null?null:Xw(n)}resetBaseElement(){Si=null}getUserAgent(){return window.navigator.userAgent}getCookie(t){return _i(document.cookie,t)}},Si=null;function Jw(){return Si=Si||document.head.querySelector("base"),Si?Si.getAttribute("href"):null}function Xw(e){return new URL(e,document.baseURI).pathname}var eI=(()=>{class e{build(){return new XMLHttpRequest}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),cy=["alt","control","meta","shift"],tI={"\b":"Backspace"," ":"Tab","\x7F":"Delete","\x1B":"Escape",Del:"Delete",Esc:"Escape",Left:"ArrowLeft",Right:"ArrowRight",Up:"ArrowUp",Down:"ArrowDown",Menu:"ContextMenu",Scroll:"ScrollLock",Win:"OS"},nI={alt:e=>e.altKey,control:e=>e.ctrlKey,meta:e=>e.metaKey,shift:e=>e.shiftKey},ly=(()=>{class e extends bi{constructor(n){super(n)}supports(n){return e.parseEventName(n)!=null}addEventListener(n,r,o,i){let s=e.parseEventName(r),a=e.eventCallback(s.fullKey,o,this.manager.getZone());return this.manager.getZone().runOutsideAngular(()=>ut().onAndCancel(n,s.domEventName,a,i))}static parseEventName(n){let r=n.toLowerCase().split("."),o=r.shift();if(r.length===0||!(o==="keydown"||o==="keyup"))return null;let i=e._normalizeKey(r.pop()),s="",a=r.indexOf("code");if(a>-1&&(r.splice(a,1),s="code."),cy.forEach(l=>{let u=r.indexOf(l);u>-1&&(r.splice(u,1),s+=l+".")}),s+=i,r.length!=0||i.length===0)return null;let c={};return c.domEventName=o,c.fullKey=s,c}static matchEventFullKeyCode(n,r){let o=tI[n.key]||n.key,i="";return r.indexOf("code.")>-1&&(o=n.code,i="code."),o==null||!o?!1:(o=o.toLowerCase(),o===" "?o="space":o==="."&&(o="dot"),cy.forEach(s=>{if(s!==o){let a=nI[s];a(n)&&(i+=s+".")}}),i+=o,i===r)}static eventCallback(n,r,o){return i=>{e.matchEventFullKeyCode(i,n)&&o.runGuarded(()=>r(i))}}static _normalizeKey(n){return n==="esc"?"escape":n}static \u0275fac=function(r){return new(r||e)(T(ue))};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})();async function zd(e,t,n){let r=y({rootComponent:e},rI(t,n));return Fm(r)}function rI(e,t){return{platformRef:t?.platformRef,appProviders:[...cI,...e?.providers??[]],platformProviders:aI}}function oI(){Ja.makeCurrent()}function iI(){return new St}function sI(){return Ju(document),document}var aI=[{provide:ci,useValue:ny},{provide:Sa,useValue:oI,multi:!0},{provide:ue,useFactory:sI}];var cI=[{provide:$o,useValue:"root"},{provide:St,useFactory:iI},{provide:Qa,useClass:Za,multi:!0},{provide:Qa,useClass:ly,multi:!0},$d,Ud,Bd,{provide:ir,useExisting:$d},{provide:vr,useClass:eI},[]];var Lt=class e{headers;normalizedNames=new Map;lazyInit;lazyUpdate=null;constructor(t){t?typeof t=="string"?this.lazyInit=()=>{this.headers=new Map,t.split(` +`).forEach(n=>{let r=n.indexOf(":");if(r>0){let o=n.slice(0,r),i=n.slice(r+1).trim();this.addHeaderEntry(o,i)}})}:typeof Headers<"u"&&t instanceof Headers?(this.headers=new Map,t.forEach((n,r)=>{this.addHeaderEntry(r,n)})):this.lazyInit=()=>{this.headers=new Map,Object.entries(t).forEach(([n,r])=>{this.setHeaderEntries(n,r)})}:this.headers=new Map}has(t){return this.init(),this.headers.has(t.toLowerCase())}get(t){this.init();let n=this.headers.get(t.toLowerCase());return n&&n.length>0?n[0]:null}keys(){return this.init(),Array.from(this.normalizedNames.values())}getAll(t){return this.init(),this.headers.get(t.toLowerCase())||null}append(t,n){return this.clone({name:t,value:n,op:"a"})}set(t,n){return this.clone({name:t,value:n,op:"s"})}delete(t,n){return this.clone({name:t,value:n,op:"d"})}maybeSetNormalizedName(t,n){this.normalizedNames.has(n)||this.normalizedNames.set(n,t)}init(){this.lazyInit&&(this.lazyInit instanceof e?this.copyFrom(this.lazyInit):this.lazyInit(),this.lazyInit=null,this.lazyUpdate&&(this.lazyUpdate.forEach(t=>this.applyUpdate(t)),this.lazyUpdate=null))}copyFrom(t){t.init(),Array.from(t.headers.keys()).forEach(n=>{this.headers.set(n,t.headers.get(n)),this.normalizedNames.set(n,t.normalizedNames.get(n))})}clone(t){let n=new e;return n.lazyInit=this.lazyInit&&this.lazyInit instanceof e?this.lazyInit:this,n.lazyUpdate=(this.lazyUpdate||[]).concat([t]),n}applyUpdate(t){let n=t.name.toLowerCase();switch(t.op){case"a":case"s":let r=t.value;if(typeof r=="string"&&(r=[r]),r.length===0)return;this.maybeSetNormalizedName(t.name,n);let o=(t.op==="a"?this.headers.get(n):void 0)||[];o.push(...r),this.headers.set(n,o);break;case"d":let i=t.value;if(!i)this.headers.delete(n),this.normalizedNames.delete(n);else{let s=this.headers.get(n);if(!s)return;s=s.filter(a=>i.indexOf(a)===-1),s.length===0?(this.headers.delete(n),this.normalizedNames.delete(n)):this.headers.set(n,s)}break}}addHeaderEntry(t,n){let r=t.toLowerCase();this.maybeSetNormalizedName(t,r),this.headers.has(r)?this.headers.get(r).push(n):this.headers.set(r,[n])}setHeaderEntries(t,n){let r=(Array.isArray(n)?n:[n]).map(i=>i.toString()),o=t.toLowerCase();this.headers.set(o,r),this.maybeSetNormalizedName(t,o)}forEach(t){this.init(),Array.from(this.normalizedNames.keys()).forEach(n=>t(this.normalizedNames.get(n),this.headers.get(n)))}};var tc=class{map=new Map;set(t,n){return this.map.set(t,n),this}get(t){return this.map.has(t)||this.map.set(t,t.defaultValue()),this.map.get(t)}delete(t){return this.map.delete(t),this}has(t){return this.map.has(t)}keys(){return this.map.keys()}},nc=class{encodeKey(t){return uy(t)}encodeValue(t){return uy(t)}decodeKey(t){return decodeURIComponent(t)}decodeValue(t){return decodeURIComponent(t)}};function lI(e,t){let n=new Map;return e.length>0&&e.replace(/^\?/,"").split("&").forEach(o=>{let i=o.indexOf("="),[s,a]=i==-1?[t.decodeKey(o),""]:[t.decodeKey(o.slice(0,i)),t.decodeValue(o.slice(i+1))],c=n.get(s)||[];c.push(a),n.set(s,c)}),n}var uI=/%(\d[a-f0-9])/gi,dI={40:"@","3A":":",24:"$","2C":",","3B":";","3D":"=","3F":"?","2F":"/"};function uy(e){return encodeURIComponent(e).replace(uI,(t,n)=>dI[n]??t)}function Xa(e){return`${e}`}var nn=class e{map;encoder;updates=null;cloneFrom=null;constructor(t={}){if(this.encoder=t.encoder||new nc,t.fromString){if(t.fromObject)throw new E(2805,!1);this.map=lI(t.fromString,this.encoder)}else t.fromObject?(this.map=new Map,Object.keys(t.fromObject).forEach(n=>{let r=t.fromObject[n],o=Array.isArray(r)?r.map(Xa):[Xa(r)];this.map.set(n,o)})):this.map=null}has(t){return this.init(),this.map.has(t)}get(t){this.init();let n=this.map.get(t);return n?n[0]:null}getAll(t){return this.init(),this.map.get(t)||null}keys(){return this.init(),Array.from(this.map.keys())}append(t,n){return this.clone({param:t,value:n,op:"a"})}appendAll(t){let n=[];return Object.keys(t).forEach(r=>{let o=t[r];Array.isArray(o)?o.forEach(i=>{n.push({param:r,value:i,op:"a"})}):n.push({param:r,value:o,op:"a"})}),this.clone(n)}set(t,n){return this.clone({param:t,value:n,op:"s"})}delete(t,n){return this.clone({param:t,value:n,op:"d"})}toString(){return this.init(),this.keys().map(t=>{let n=this.encoder.encodeKey(t);return this.map.get(t).map(r=>n+"="+this.encoder.encodeValue(r)).join("&")}).filter(t=>t!=="").join("&")}clone(t){let n=new e({encoder:this.encoder});return n.cloneFrom=this.cloneFrom||this,n.updates=(this.updates||[]).concat(t),n}init(){this.map===null&&(this.map=new Map),this.cloneFrom!==null&&(this.cloneFrom.init(),this.cloneFrom.keys().forEach(t=>this.map.set(t,this.cloneFrom.map.get(t))),this.updates.forEach(t=>{switch(t.op){case"a":case"s":let n=(t.op==="a"?this.map.get(t.param):void 0)||[];n.push(Xa(t.value)),this.map.set(t.param,n);break;case"d":if(t.value!==void 0){let r=this.map.get(t.param)||[],o=r.indexOf(Xa(t.value));o!==-1&&r.splice(o,1),r.length>0?this.map.set(t.param,r):this.map.delete(t.param)}else{this.map.delete(t.param);break}}}),this.cloneFrom=this.updates=null)}};function fI(e){switch(e){case"DELETE":case"GET":case"HEAD":case"OPTIONS":case"JSONP":return!1;default:return!0}}function dy(e){return typeof ArrayBuffer<"u"&&e instanceof ArrayBuffer}function fy(e){return typeof Blob<"u"&&e instanceof Blob}function hy(e){return typeof FormData<"u"&&e instanceof FormData}function hI(e){return typeof URLSearchParams<"u"&&e instanceof URLSearchParams}var Mi="Content-Type",rc="Accept",py="text/plain",gy="application/json",my=`${gy}, ${py}, */*`,to=class e{url;body=null;headers;context;reportProgress=!1;withCredentials=!1;credentials;keepalive=!1;cache;priority;mode;redirect;referrer;integrity;referrerPolicy;responseType="json";method;params;urlWithParams;transferCache;timeout;constructor(t,n,r,o){this.url=n,this.method=t.toUpperCase();let i;if(fI(this.method)||o?(this.body=r!==void 0?r:null,i=o):i=r,i){if(this.reportProgress=!!i.reportProgress,this.withCredentials=!!i.withCredentials,this.keepalive=!!i.keepalive,i.responseType&&(this.responseType=i.responseType),i.headers&&(this.headers=i.headers),i.context&&(this.context=i.context),i.params&&(this.params=i.params),i.priority&&(this.priority=i.priority),i.cache&&(this.cache=i.cache),i.credentials&&(this.credentials=i.credentials),typeof i.timeout=="number"){if(i.timeout<1||!Number.isInteger(i.timeout))throw new E(2822,"");this.timeout=i.timeout}i.mode&&(this.mode=i.mode),i.redirect&&(this.redirect=i.redirect),i.integrity&&(this.integrity=i.integrity),i.referrer&&(this.referrer=i.referrer),i.referrerPolicy&&(this.referrerPolicy=i.referrerPolicy),this.transferCache=i.transferCache}if(this.headers??=new Lt,this.context??=new tc,!this.params)this.params=new nn,this.urlWithParams=n;else{let s=this.params.toString();if(s.length===0)this.urlWithParams=n;else{let a=n.indexOf("?"),c=a===-1?"?":acn.set(Ht,t.setHeaders[Ht]),Ee)),t.setParams&&(se=Object.keys(t.setParams).reduce((cn,Ht)=>cn.set(Ht,t.setParams[Ht]),se)),new e(n,r,b,{params:se,headers:Ee,context:an,reportProgress:K,responseType:o,withCredentials:w,transferCache:v,keepalive:i,cache:a,priority:s,timeout:_,mode:c,redirect:l,credentials:u,referrer:d,integrity:h,referrerPolicy:f})}},rn=(function(e){return e[e.Sent=0]="Sent",e[e.UploadProgress=1]="UploadProgress",e[e.ResponseHeader=2]="ResponseHeader",e[e.DownloadProgress=3]="DownloadProgress",e[e.Response=4]="Response",e[e.User=5]="User",e})(rn||{}),no=class{headers;status;statusText;url;ok;type;redirected;responseType;constructor(t,n=200,r="OK"){this.headers=t.headers||new Lt,this.status=t.status!==void 0?t.status:n,this.statusText=t.statusText||r,this.url=t.url||null,this.redirected=t.redirected,this.responseType=t.responseType,this.ok=this.status>=200&&this.status<300}},Ti=class e extends no{constructor(t={}){super(t)}type=rn.ResponseHeader;clone(t={}){return new e({headers:t.headers||this.headers,status:t.status!==void 0?t.status:this.status,statusText:t.statusText||this.statusText,url:t.url||this.url||void 0})}},ro=class e extends no{body;constructor(t={}){super(t),this.body=t.body!==void 0?t.body:null}type=rn.Response;clone(t={}){return new e({body:t.body!==void 0?t.body:this.body,headers:t.headers||this.headers,status:t.status!==void 0?t.status:this.status,statusText:t.statusText||this.statusText,url:t.url||this.url||void 0,redirected:t.redirected??this.redirected,responseType:t.responseType??this.responseType})}},Ft=class extends no{name="HttpErrorResponse";message;error;ok=!1;constructor(t){super(t,0,"Unknown Error"),this.status>=200&&this.status<300?this.message=`Http failure during parsing for ${t.url||"(unknown url)"}`:this.message=`Http failure response for ${t.url||"(unknown url)"}: ${t.status} ${t.statusText}`,this.error=t.error||null}},yy=200,pI=204;var gI=/^\)\]\}',?\n/,vy=new I(""),ec=(()=>{class e{fetchImpl=p(Wd,{optional:!0})?.fetch??((...n)=>globalThis.fetch(...n));ngZone=p(Oe);destroyRef=p(We);handle(n){return new j(r=>{let o=new AbortController;this.doRequest(n,o.signal,r).then(qd,s=>r.error(new Ft({error:s})));let i;return n.timeout&&(i=this.ngZone.runOutsideAngular(()=>setTimeout(()=>{o.signal.aborted||o.abort(new DOMException("signal timed out","TimeoutError"))},n.timeout))),()=>{i!==void 0&&clearTimeout(i),o.abort()}})}async doRequest(n,r,o){let i=this.createRequestInit(n),s;try{let _=this.ngZone.runOutsideAngular(()=>this.fetchImpl(n.urlWithParams,y({signal:r},i)));mI(_),o.next({type:rn.Sent}),s=await _}catch(_){o.error(new Ft({error:_,status:_.status??0,statusText:_.statusText,url:n.urlWithParams,headers:_.headers}));return}let a=new Lt(s.headers),c=s.statusText,l=s.url||n.urlWithParams,u=s.status,d=null;if(n.reportProgress&&o.next(new Ti({headers:a,status:u,statusText:c,url:l})),s.body){let _=s.headers.get("content-length"),b=[],w=s.body.getReader(),K=0,Ee,se,an=typeof Zone<"u"&&Zone.current,cn=!1;if(await this.ngZone.runOutsideAngular(async()=>{for(;;){if(this.destroyRef.destroyed){await w.cancel(),cn=!0;break}let{done:bo,value:Zc}=await w.read();if(bo)break;if(b.push(Zc),K+=Zc.length,n.reportProgress){se=n.responseType==="text"?(se??"")+(Ee??=new TextDecoder).decode(Zc,{stream:!0}):void 0;let Pf=()=>o.next({type:rn.DownloadProgress,total:_?+_:void 0,loaded:K,partialText:se});an?an.run(Pf):Pf()}}}),cn){o.complete();return}let Ht=this.concatChunks(b,K);try{let bo=s.headers.get(Mi)??"";d=this.parseBody(n,Ht,bo,u)}catch(bo){o.error(new Ft({error:bo,headers:new Lt(s.headers),status:s.status,statusText:s.statusText,url:s.url||n.urlWithParams}));return}}u===0&&(u=d?yy:0);let h=u>=200&&u<300,f=s.redirected,v=s.type;h?(o.next(new ro({body:d,headers:a,status:u,statusText:c,url:l,redirected:f,responseType:v})),o.complete()):o.error(new Ft({error:d,headers:a,status:u,statusText:c,url:l,redirected:f,responseType:v}))}parseBody(n,r,o,i){switch(n.responseType){case"json":let s=new TextDecoder().decode(r).replace(gI,"");if(s==="")return null;try{return JSON.parse(s)}catch(a){if(i<200||i>=300)return s;throw a}case"text":return new TextDecoder().decode(r);case"blob":return new Blob([r],{type:o});case"arraybuffer":return r.buffer}}createRequestInit(n){let r={},o;if(o=n.credentials,n.withCredentials&&(o="include"),n.headers.forEach((i,s)=>r[i]=s.join(",")),n.headers.has(rc)||(r[rc]=my),!n.headers.has(Mi)){let i=n.detectContentTypeHeader();i!==null&&(r[Mi]=i)}return{body:n.serializeBody(),method:n.method,headers:r,credentials:o,keepalive:n.keepalive,cache:n.cache,priority:n.priority,mode:n.mode,redirect:n.redirect,referrer:n.referrer,integrity:n.integrity,referrerPolicy:n.referrerPolicy}}concatChunks(n,r){let o=new Uint8Array(r),i=0;for(let s of n)o.set(s,i),i+=s.length;return o}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac})}return e})(),Wd=class{};function qd(){}function mI(e){e.then(qd,qd)}var yI=/^\)\]\}',?\n/;var Zd=(()=>{class e{xhrFactory;tracingService=p(lr,{optional:!0});constructor(n){this.xhrFactory=n}maybePropagateTrace(n){return this.tracingService?.propagate?this.tracingService.propagate(n):n}handle(n){if(n.method==="JSONP")throw new E(-2800,!1);let r=this.xhrFactory;return k(null).pipe(Ue(()=>new j(i=>{let s=r.build();if(s.open(n.method,n.urlWithParams),n.withCredentials&&(s.withCredentials=!0),n.headers.forEach((b,w)=>s.setRequestHeader(b,w.join(","))),n.headers.has(rc)||s.setRequestHeader(rc,my),!n.headers.has(Mi)){let b=n.detectContentTypeHeader();b!==null&&s.setRequestHeader(Mi,b)}if(n.timeout&&(s.timeout=n.timeout),n.responseType){let b=n.responseType.toLowerCase();s.responseType=b!=="json"?b:"text"}let a=n.serializeBody(),c=null,l=()=>{if(c!==null)return c;let b=s.statusText||"OK",w=new Lt(s.getAllResponseHeaders()),K=s.responseURL||n.url;return c=new Ti({headers:w,status:s.status,statusText:b,url:K}),c},u=this.maybePropagateTrace(()=>{let{headers:b,status:w,statusText:K,url:Ee}=l(),se=null;w!==pI&&(se=typeof s.response>"u"?s.responseText:s.response),w===0&&(w=se?yy:0);let an=w>=200&&w<300;if(n.responseType==="json"&&typeof se=="string"){let cn=se;se=se.replace(yI,"");try{se=se!==""?JSON.parse(se):null}catch(Ht){se=cn,an&&(an=!1,se={error:Ht,text:se})}}an?(i.next(new ro({body:se,headers:b,status:w,statusText:K,url:Ee||void 0})),i.complete()):i.error(new Ft({error:se,headers:b,status:w,statusText:K,url:Ee||void 0}))}),d=this.maybePropagateTrace(b=>{let{url:w}=l(),K=new Ft({error:b,status:s.status||0,statusText:s.statusText||"Unknown Error",url:w||void 0});i.error(K)}),h=d;n.timeout&&(h=this.maybePropagateTrace(b=>{let{url:w}=l(),K=new Ft({error:new DOMException("Request timed out","TimeoutError"),status:s.status||0,statusText:s.statusText||"Request timeout",url:w||void 0});i.error(K)}));let f=!1,v=this.maybePropagateTrace(b=>{f||(i.next(l()),f=!0);let w={type:rn.DownloadProgress,loaded:b.loaded};b.lengthComputable&&(w.total=b.total),n.responseType==="text"&&s.responseText&&(w.partialText=s.responseText),i.next(w)}),_=this.maybePropagateTrace(b=>{let w={type:rn.UploadProgress,loaded:b.loaded};b.lengthComputable&&(w.total=b.total),i.next(w)});return s.addEventListener("load",u),s.addEventListener("error",d),s.addEventListener("timeout",h),s.addEventListener("abort",d),n.reportProgress&&(s.addEventListener("progress",v),a!==null&&s.upload&&s.upload.addEventListener("progress",_)),s.send(a),i.next({type:rn.Sent}),()=>{s.removeEventListener("error",d),s.removeEventListener("abort",d),s.removeEventListener("load",u),s.removeEventListener("timeout",h),n.reportProgress&&(s.removeEventListener("progress",v),a!==null&&s.upload&&s.upload.removeEventListener("progress",_)),s.readyState!==s.DONE&&s.abort()}})))}static \u0275fac=function(r){return new(r||e)(T(vr))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function vI(e,t){return t(e)}function DI(e,t,n){return(r,o)=>De(n,()=>t(r,i=>e(i,o)))}var Dy=new I("",{factory:()=>[]}),Cy=new I(""),Ey=new I("",{factory:()=>!0});var ic=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:function(r){let o=null;return r?o=new(r||e):o=T(Zd),o},providedIn:"root"})}return e})();var oc=(()=>{class e{backend;injector;chain=null;pendingTasks=p(Ko);contributeToStability=p(Ey);constructor(n,r){this.backend=n,this.injector=r}handle(n){if(this.chain===null){let r=Array.from(new Set([...this.injector.get(Dy),...this.injector.get(Cy,[])]));this.chain=r.reduceRight((o,i)=>DI(o,i,this.injector),vI)}if(this.contributeToStability){let r=this.pendingTasks.add();return this.chain(n,o=>this.backend.handle(o)).pipe(xo(r))}else return this.chain(n,r=>this.backend.handle(r))}static \u0275fac=function(r){return new(r||e)(T(ic),T(ne))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Yd=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:function(r){let o=null;return r?o=new(r||e):o=T(oc),o},providedIn:"root"})}return e})();function Gd(e,t){return{body:t,headers:e.headers,context:e.context,observe:e.observe,params:e.params,reportProgress:e.reportProgress,responseType:e.responseType,withCredentials:e.withCredentials,credentials:e.credentials,transferCache:e.transferCache,timeout:e.timeout,keepalive:e.keepalive,priority:e.priority,cache:e.cache,mode:e.mode,redirect:e.redirect,integrity:e.integrity,referrer:e.referrer,referrerPolicy:e.referrerPolicy}}var sc=(()=>{class e{handler;constructor(n){this.handler=n}request(n,r,o={}){let i;if(n instanceof to)i=n;else{let c;o.headers instanceof Lt?c=o.headers:c=new Lt(o.headers);let l;o.params&&(o.params instanceof nn?l=o.params:l=new nn({fromObject:o.params})),i=new to(n,r,o.body!==void 0?o.body:null,{headers:c,context:o.context,params:l,reportProgress:o.reportProgress,responseType:o.responseType||"json",withCredentials:o.withCredentials,transferCache:o.transferCache,keepalive:o.keepalive,priority:o.priority,cache:o.cache,mode:o.mode,redirect:o.redirect,credentials:o.credentials,referrer:o.referrer,referrerPolicy:o.referrerPolicy,integrity:o.integrity,timeout:o.timeout})}let s=k(i).pipe(xr(c=>this.handler.handle(c)));if(n instanceof to||o.observe==="events")return s;let a=s.pipe(gt(c=>c instanceof ro));switch(o.observe||"body"){case"body":switch(i.responseType){case"arraybuffer":return a.pipe(W(c=>{if(c.body!==null&&!(c.body instanceof ArrayBuffer))throw new E(2806,!1);return c.body}));case"blob":return a.pipe(W(c=>{if(c.body!==null&&!(c.body instanceof Blob))throw new E(2807,!1);return c.body}));case"text":return a.pipe(W(c=>{if(c.body!==null&&typeof c.body!="string")throw new E(2808,!1);return c.body}));default:return a.pipe(W(c=>c.body))}case"response":return a;default:throw new E(2809,!1)}}delete(n,r={}){return this.request("DELETE",n,r)}get(n,r={}){return this.request("GET",n,r)}head(n,r={}){return this.request("HEAD",n,r)}jsonp(n,r){return this.request("JSONP",n,{params:new nn().append(r,"JSONP_CALLBACK"),observe:"body",responseType:"json"})}options(n,r={}){return this.request("OPTIONS",n,r)}patch(n,r,o={}){return this.request("PATCH",n,Gd(o,r))}post(n,r,o={}){return this.request("POST",n,Gd(o,r))}put(n,r,o={}){return this.request("PUT",n,Gd(o,r))}static \u0275fac=function(r){return new(r||e)(T(Yd))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();var CI=new I("",{factory:()=>!0}),EI="XSRF-TOKEN",_I=new I("",{factory:()=>EI}),bI="X-XSRF-TOKEN",wI=new I("",{factory:()=>bI}),II=(()=>{class e{cookieName=p(_I);doc=p(ue);lastCookieString="";lastToken=null;parseCount=0;getToken(){let n=this.doc.cookie||"";return n!==this.lastCookieString&&(this.parseCount++,this.lastToken=_i(n,this.cookieName),this.lastCookieString=n),this.lastToken}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),_y=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:function(r){let o=null;return r?o=new(r||e):o=T(II),o},providedIn:"root"})}return e})();function SI(e,t){if(!p(CI)||e.method==="GET"||e.method==="HEAD")return t(e);try{let o=p(Qr).href,{origin:i}=new URL(o),{origin:s}=new URL(e.url,i);if(i!==s)return t(e)}catch{return t(e)}let n=p(_y).getToken(),r=p(wI);return n!=null&&!e.headers.has(r)&&(e=e.clone({headers:e.headers.set(r,n)})),t(e)}var Kd=(function(e){return e[e.Interceptors=0]="Interceptors",e[e.LegacyInterceptors=1]="LegacyInterceptors",e[e.CustomXsrfConfiguration=2]="CustomXsrfConfiguration",e[e.NoXsrfProtection=3]="NoXsrfProtection",e[e.JsonpSupport=4]="JsonpSupport",e[e.RequestsMadeViaParent=5]="RequestsMadeViaParent",e[e.Fetch=6]="Fetch",e})(Kd||{});function MI(e,t){return{\u0275kind:e,\u0275providers:t}}function Qd(...e){let t=[sc,oc,{provide:Yd,useExisting:oc},{provide:ic,useFactory:()=>p(vy,{optional:!0})??p(Zd)},{provide:Dy,useValue:SI,multi:!0}];for(let n of e)t.push(...n.\u0275providers);return _n(t)}function Jd(){return MI(Kd.Fetch,[ec,{provide:vy,useExisting:ec},{provide:ic,useExisting:ec}])}var by=(()=>{class e{_doc;constructor(n){this._doc=n}getTitle(){return this._doc.title}setTitle(n){this._doc.title=n||""}static \u0275fac=function(r){return new(r||e)(T(ue))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();var O="primary",Hi=Symbol("RouteTitle"),rf=class{params;constructor(t){this.params=t||{}}has(t){return Object.prototype.hasOwnProperty.call(this.params,t)}get(t){if(this.has(t)){let n=this.params[t];return Array.isArray(n)?n[0]:n}return null}getAll(t){if(this.has(t)){let n=this.params[t];return Array.isArray(n)?n:[n]}return[]}get keys(){return Object.keys(this.params)}};function Cr(e){return new rf(e)}function Xd(e,t,n){for(let r=0;re.length||n.pathMatch==="full"&&(t.hasChildren()||r.lengthe.length||n.pathMatch==="full"&&t.hasChildren()&&n.path!=="**")return null;let a={};return!Xd(i,e.slice(0,i.length),a)||!Xd(s,e.slice(e.length-s.length),a)?null:{consumed:e,posParams:a}}function fc(e){return new Promise((t,n)=>{e.pipe(Gt()).subscribe({next:r=>t(r),error:r=>n(r)})})}function NI(e,t){if(e.length!==t.length)return!1;for(let n=0;nr[i]===o)}else return e===t}function xI(e){return e.length>0?e[e.length-1]:null}function br(e){return _s(e)?e:An(e)?ae(Promise.resolve(e)):k(e)}function Oy(e){return _s(e)?fc(e):Promise.resolve(e)}var RI={exact:Fy,subset:Ly},Py={exact:OI,subset:PI,ignored:()=>!0},ky={paths:"exact",fragment:"ignored",matrixParams:"ignored",queryParams:"exact"},sf={paths:"subset",fragment:"ignored",matrixParams:"ignored",queryParams:"subset"};function wy(e,t,n){return RI[n.paths](e.root,t.root,n.matrixParams)&&Py[n.queryParams](e.queryParams,t.queryParams)&&!(n.fragment==="exact"&&e.fragment!==t.fragment)}function OI(e,t){return jt(e,t)}function Fy(e,t,n){if(!Dr(e.segments,t.segments)||!lc(e.segments,t.segments,n)||e.numberOfChildren!==t.numberOfChildren)return!1;for(let r in t.children)if(!e.children[r]||!Fy(e.children[r],t.children[r],n))return!1;return!0}function PI(e,t){return Object.keys(t).length<=Object.keys(e).length&&Object.keys(t).every(n=>Ry(e[n],t[n]))}function Ly(e,t,n){return jy(e,t,t.segments,n)}function jy(e,t,n,r){if(e.segments.length>n.length){let o=e.segments.slice(0,n.length);return!(!Dr(o,n)||t.hasChildren()||!lc(o,n,r))}else if(e.segments.length===n.length){if(!Dr(e.segments,n)||!lc(e.segments,n,r))return!1;for(let o in t.children)if(!e.children[o]||!Ly(e.children[o],t.children[o],r))return!1;return!0}else{let o=n.slice(0,e.segments.length),i=n.slice(e.segments.length);return!Dr(e.segments,o)||!lc(e.segments,o,r)||!e.children[O]?!1:jy(e.children[O],t,i,r)}}function lc(e,t,n){return t.every((r,o)=>Py[n](e[o].parameters,r.parameters))}var Xe=class{root;queryParams;fragment;_queryParamMap;constructor(t=new H([],{}),n={},r=null){this.root=t,this.queryParams=n,this.fragment=r}get queryParamMap(){return this._queryParamMap??=Cr(this.queryParams),this._queryParamMap}toString(){return LI.serialize(this)}},H=class{segments;children;parent=null;constructor(t,n){this.segments=t,this.children=n,Object.values(n).forEach(r=>r.parent=this)}hasChildren(){return this.numberOfChildren>0}get numberOfChildren(){return Object.keys(this.children).length}toString(){return uc(this)}},xn=class{path;parameters;_parameterMap;constructor(t,n){this.path=t,this.parameters=n}get parameterMap(){return this._parameterMap??=Cr(this.parameters),this._parameterMap}toString(){return By(this)}};function kI(e,t){return Dr(e,t)&&e.every((n,r)=>jt(n.parameters,t[r].parameters))}function Dr(e,t){return e.length!==t.length?!1:e.every((n,r)=>n.path===t[r].path)}function FI(e,t){let n=[];return Object.entries(e.children).forEach(([r,o])=>{r===O&&(n=n.concat(t(o,r)))}),Object.entries(e.children).forEach(([r,o])=>{r!==O&&(n=n.concat(t(o,r)))}),n}var ho=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>new Rn,providedIn:"root"})}return e})(),Rn=class{parse(t){let n=new cf(t);return new Xe(n.parseRootSegment(),n.parseQueryParams(),n.parseFragment())}serialize(t){let n=`/${Ai(t.root,!0)}`,r=BI(t.queryParams),o=typeof t.fragment=="string"?`#${jI(t.fragment)}`:"";return`${n}${r}${o}`}},LI=new Rn;function uc(e){return e.segments.map(t=>By(t)).join("/")}function Ai(e,t){if(!e.hasChildren())return uc(e);if(t){let n=e.children[O]?Ai(e.children[O],!1):"",r=[];return Object.entries(e.children).forEach(([o,i])=>{o!==O&&r.push(`${o}:${Ai(i,!1)}`)}),r.length>0?`${n}(${r.join("//")})`:n}else{let n=FI(e,(r,o)=>o===O?[Ai(e.children[O],!1)]:[`${o}:${Ai(r,!1)}`]);return Object.keys(e.children).length===1&&e.children[O]!=null?`${uc(e)}/${n[0]}`:`${uc(e)}/(${n.join("//")})`}}function Vy(e){return encodeURIComponent(e).replace(/%40/g,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",")}function ac(e){return Vy(e).replace(/%3B/gi,";")}function jI(e){return encodeURI(e)}function af(e){return Vy(e).replace(/\(/g,"%28").replace(/\)/g,"%29").replace(/%26/gi,"&")}function dc(e){return decodeURIComponent(e)}function Iy(e){return dc(e.replace(/\+/g,"%20"))}function By(e){return`${af(e.path)}${VI(e.parameters)}`}function VI(e){return Object.entries(e).map(([t,n])=>`;${af(t)}=${af(n)}`).join("")}function BI(e){let t=Object.entries(e).map(([n,r])=>Array.isArray(r)?r.map(o=>`${ac(n)}=${ac(o)}`).join("&"):`${ac(n)}=${ac(r)}`).filter(n=>n);return t.length?`?${t.join("&")}`:""}var UI=/^[^\/()?;#]+/;function ef(e){let t=e.match(UI);return t?t[0]:""}var HI=/^[^\/()?;=#]+/;function $I(e){let t=e.match(HI);return t?t[0]:""}var zI=/^[^=?&#]+/;function GI(e){let t=e.match(zI);return t?t[0]:""}var WI=/^[^&#]+/;function qI(e){let t=e.match(WI);return t?t[0]:""}var cf=class{url;remaining;constructor(t){this.url=t,this.remaining=t}parseRootSegment(){return this.consumeOptional("/"),this.remaining===""||this.peekStartsWith("?")||this.peekStartsWith("#")?new H([],{}):new H([],this.parseChildren())}parseQueryParams(){let t={};if(this.consumeOptional("?"))do this.parseQueryParam(t);while(this.consumeOptional("&"));return t}parseFragment(){return this.consumeOptional("#")?decodeURIComponent(this.remaining):null}parseChildren(t=0){if(t>50)throw new E(4010,!1);if(this.remaining==="")return{};this.consumeOptional("/");let n=[];for(this.peekStartsWith("(")||n.push(this.parseSegment());this.peekStartsWith("/")&&!this.peekStartsWith("//")&&!this.peekStartsWith("/(");)this.capture("/"),n.push(this.parseSegment());let r={};this.peekStartsWith("/(")&&(this.capture("/"),r=this.parseParens(!0,t));let o={};return this.peekStartsWith("(")&&(o=this.parseParens(!1,t)),(n.length>0||Object.keys(r).length>0)&&(o[O]=new H(n,r)),o}parseSegment(){let t=ef(this.remaining);if(t===""&&this.peekStartsWith(";"))throw new E(4009,!1);return this.capture(t),new xn(dc(t),this.parseMatrixParams())}parseMatrixParams(){let t={};for(;this.consumeOptional(";");)this.parseParam(t);return t}parseParam(t){let n=$I(this.remaining);if(!n)return;this.capture(n);let r="";if(this.consumeOptional("=")){let o=ef(this.remaining);o&&(r=o,this.capture(r))}t[dc(n)]=dc(r)}parseQueryParam(t){let n=GI(this.remaining);if(!n)return;this.capture(n);let r="";if(this.consumeOptional("=")){let s=qI(this.remaining);s&&(r=s,this.capture(r))}let o=Iy(n),i=Iy(r);if(t.hasOwnProperty(o)){let s=t[o];Array.isArray(s)||(s=[s],t[o]=s),s.push(i)}else t[o]=i}parseParens(t,n){let r={};for(this.capture("(");!this.consumeOptional(")")&&this.remaining.length>0;){let o=ef(this.remaining),i=this.remaining[o.length];if(i!=="/"&&i!==")"&&i!==";")throw new E(4010,!1);let s;o.indexOf(":")>-1?(s=o.slice(0,o.indexOf(":")),this.capture(s),this.capture(":")):t&&(s=O);let a=this.parseChildren(n+1);r[s??O]=Object.keys(a).length===1&&a[O]?a[O]:new H([],a),this.consumeOptional("//")}return r}peekStartsWith(t){return this.remaining.startsWith(t)}consumeOptional(t){return this.peekStartsWith(t)?(this.remaining=this.remaining.substring(t.length),!0):!1}capture(t){if(!this.consumeOptional(t))throw new E(4011,!1)}};function Uy(e){return e.segments.length>0?new H([],{[O]:e}):e}function Hy(e){let t={};for(let[r,o]of Object.entries(e.children)){let i=Hy(o);if(r===O&&i.segments.length===0&&i.hasChildren())for(let[s,a]of Object.entries(i.children))t[s]=a;else(i.segments.length>0||i.hasChildren())&&(t[r]=i)}let n=new H(e.segments,t);return ZI(n)}function ZI(e){if(e.numberOfChildren===1&&e.children[O]){let t=e.children[O];return new H(e.segments.concat(t.segments),t.children)}return e}function On(e){return e instanceof Xe}function $y(e,t,n=null,r=null,o=new Rn){let i=zy(e);return Gy(i,t,n,r,o)}function zy(e){let t;function n(i){let s={};for(let c of i.children){let l=n(c);s[c.outlet]=l}let a=new H(i.url,s);return i===e&&(t=a),a}let r=n(e.root),o=Uy(r);return t??o}function Gy(e,t,n,r,o){let i=e;for(;i.parent;)i=i.parent;if(t.length===0)return tf(i,i,i,n,r,o);let s=YI(t);if(s.toRoot())return tf(i,i,new H([],{}),n,r,o);let a=KI(s,i,e),c=a.processChildren?xi(a.segmentGroup,a.index,s.commands):qy(a.segmentGroup,a.index,s.commands);return tf(i,a.segmentGroup,c,n,r,o)}function hc(e){return typeof e=="object"&&e!=null&&!e.outlets&&!e.segmentPath}function Pi(e){return typeof e=="object"&&e!=null&&e.outlets}function Sy(e,t,n){e||="\u0275";let r=new Xe;return r.queryParams={[e]:t},n.parse(n.serialize(r)).queryParams[e]}function tf(e,t,n,r,o,i){let s={};for(let[l,u]of Object.entries(r??{}))s[l]=Array.isArray(u)?u.map(d=>Sy(l,d,i)):Sy(l,u,i);let a;e===t?a=n:a=Wy(e,t,n);let c=Uy(Hy(a));return new Xe(c,s,o)}function Wy(e,t,n){let r={};return Object.entries(e.children).forEach(([o,i])=>{i===t?r[o]=n:r[o]=Wy(i,t,n)}),new H(e.segments,r)}var pc=class{isAbsolute;numberOfDoubleDots;commands;constructor(t,n,r){if(this.isAbsolute=t,this.numberOfDoubleDots=n,this.commands=r,t&&r.length>0&&hc(r[0]))throw new E(4003,!1);let o=r.find(Pi);if(o&&o!==xI(r))throw new E(4004,!1)}toRoot(){return this.isAbsolute&&this.commands.length===1&&this.commands[0]=="/"}};function YI(e){if(typeof e[0]=="string"&&e.length===1&&e[0]==="/")return new pc(!0,0,e);let t=0,n=!1,r=e.reduce((o,i,s)=>{if(typeof i=="object"&&i!=null){if(i.outlets){let a={};return Object.entries(i.outlets).forEach(([c,l])=>{a[c]=typeof l=="string"?l.split("/"):l}),[...o,{outlets:a}]}if(i.segmentPath)return[...o,i.segmentPath]}return typeof i!="string"?[...o,i]:s===0?(i.split("/").forEach((a,c)=>{c==0&&a==="."||(c==0&&a===""?n=!0:a===".."?t++:a!=""&&o.push(a))}),o):[...o,i]},[]);return new pc(n,t,r)}var io=class{segmentGroup;processChildren;index;constructor(t,n,r){this.segmentGroup=t,this.processChildren=n,this.index=r}};function KI(e,t,n){if(e.isAbsolute)return new io(t,!0,0);if(!n)return new io(t,!1,NaN);if(n.parent===null)return new io(n,!0,0);let r=hc(e.commands[0])?0:1,o=n.segments.length-1+r;return QI(n,o,e.numberOfDoubleDots)}function QI(e,t,n){let r=e,o=t,i=n;for(;i>o;){if(i-=o,r=r.parent,!r)throw new E(4005,!1);o=r.segments.length}return new io(r,!1,o-i)}function JI(e){return Pi(e[0])?e[0].outlets:{[O]:e}}function qy(e,t,n){if(e??=new H([],{}),e.segments.length===0&&e.hasChildren())return xi(e,t,n);let r=XI(e,t,n),o=n.slice(r.commandIndex);if(r.match&&r.pathIndexi!==O)&&e.children[O]&&e.numberOfChildren===1&&e.children[O].segments.length===0){let i=xi(e.children[O],t,n);return new H(e.segments,i.children)}return Object.entries(r).forEach(([i,s])=>{typeof s=="string"&&(s=[s]),s!==null&&(o[i]=qy(e.children[i],t,s))}),Object.entries(e.children).forEach(([i,s])=>{r[i]===void 0&&(o[i]=s)}),new H(e.segments,o)}}function XI(e,t,n){let r=0,o=t,i={match:!1,pathIndex:0,commandIndex:0};for(;o=n.length)return i;let s=e.segments[o],a=n[r];if(Pi(a))break;let c=`${a}`,l=r0&&c===void 0)break;if(c&&l&&typeof l=="object"&&l.outlets===void 0){if(!Ty(c,l,s))return i;r+=2}else{if(!Ty(c,{},s))return i;r++}o++}return{match:!0,pathIndex:o,commandIndex:r}}function lf(e,t,n){let r=e.segments.slice(0,t),o=0;for(;o{typeof r=="string"&&(r=[r]),r!==null&&(t[n]=lf(new H([],{}),0,r))}),t}function My(e){let t={};return Object.entries(e).forEach(([n,r])=>t[n]=`${r}`),t}function Ty(e,t,n){return e==n.path&&jt(t,n.parameters)}var Ri="imperative",Ce=(function(e){return e[e.NavigationStart=0]="NavigationStart",e[e.NavigationEnd=1]="NavigationEnd",e[e.NavigationCancel=2]="NavigationCancel",e[e.NavigationError=3]="NavigationError",e[e.RoutesRecognized=4]="RoutesRecognized",e[e.ResolveStart=5]="ResolveStart",e[e.ResolveEnd=6]="ResolveEnd",e[e.GuardsCheckStart=7]="GuardsCheckStart",e[e.GuardsCheckEnd=8]="GuardsCheckEnd",e[e.RouteConfigLoadStart=9]="RouteConfigLoadStart",e[e.RouteConfigLoadEnd=10]="RouteConfigLoadEnd",e[e.ChildActivationStart=11]="ChildActivationStart",e[e.ChildActivationEnd=12]="ChildActivationEnd",e[e.ActivationStart=13]="ActivationStart",e[e.ActivationEnd=14]="ActivationEnd",e[e.Scroll=15]="Scroll",e[e.NavigationSkipped=16]="NavigationSkipped",e})(Ce||{}),et=class{id;url;constructor(t,n){this.id=t,this.url=n}},Er=class extends et{type=Ce.NavigationStart;navigationTrigger;restoredState;constructor(t,n,r="imperative",o=null){super(t,n),this.navigationTrigger=r,this.restoredState=o}toString(){return`NavigationStart(id: ${this.id}, url: '${this.url}')`}},Bt=class extends et{urlAfterRedirects;type=Ce.NavigationEnd;constructor(t,n,r){super(t,n),this.urlAfterRedirects=r}toString(){return`NavigationEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}')`}},Ne=(function(e){return e[e.Redirect=0]="Redirect",e[e.SupersededByNewNavigation=1]="SupersededByNewNavigation",e[e.NoDataFromResolver=2]="NoDataFromResolver",e[e.GuardRejected=3]="GuardRejected",e[e.Aborted=4]="Aborted",e})(Ne||{}),ki=(function(e){return e[e.IgnoredSameUrlNavigation=0]="IgnoredSameUrlNavigation",e[e.IgnoredByUrlHandlingStrategy=1]="IgnoredByUrlHandlingStrategy",e})(ki||{}),ft=class extends et{reason;code;type=Ce.NavigationCancel;constructor(t,n,r,o){super(t,n),this.reason=r,this.code=o}toString(){return`NavigationCancel(id: ${this.id}, url: '${this.url}')`}};function Zy(e){return e instanceof ft&&(e.code===Ne.Redirect||e.code===Ne.SupersededByNewNavigation)}var sn=class extends et{reason;code;type=Ce.NavigationSkipped;constructor(t,n,r,o){super(t,n),this.reason=r,this.code=o}},_r=class extends et{error;target;type=Ce.NavigationError;constructor(t,n,r,o){super(t,n),this.error=r,this.target=o}toString(){return`NavigationError(id: ${this.id}, url: '${this.url}', error: ${this.error})`}},Fi=class extends et{urlAfterRedirects;state;type=Ce.RoutesRecognized;constructor(t,n,r,o){super(t,n),this.urlAfterRedirects=r,this.state=o}toString(){return`RoutesRecognized(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}},gc=class extends et{urlAfterRedirects;state;type=Ce.GuardsCheckStart;constructor(t,n,r,o){super(t,n),this.urlAfterRedirects=r,this.state=o}toString(){return`GuardsCheckStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}},mc=class extends et{urlAfterRedirects;state;shouldActivate;type=Ce.GuardsCheckEnd;constructor(t,n,r,o,i){super(t,n),this.urlAfterRedirects=r,this.state=o,this.shouldActivate=i}toString(){return`GuardsCheckEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state}, shouldActivate: ${this.shouldActivate})`}},yc=class extends et{urlAfterRedirects;state;type=Ce.ResolveStart;constructor(t,n,r,o){super(t,n),this.urlAfterRedirects=r,this.state=o}toString(){return`ResolveStart(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}},vc=class extends et{urlAfterRedirects;state;type=Ce.ResolveEnd;constructor(t,n,r,o){super(t,n),this.urlAfterRedirects=r,this.state=o}toString(){return`ResolveEnd(id: ${this.id}, url: '${this.url}', urlAfterRedirects: '${this.urlAfterRedirects}', state: ${this.state})`}},Dc=class{route;type=Ce.RouteConfigLoadStart;constructor(t){this.route=t}toString(){return`RouteConfigLoadStart(path: ${this.route.path})`}},Cc=class{route;type=Ce.RouteConfigLoadEnd;constructor(t){this.route=t}toString(){return`RouteConfigLoadEnd(path: ${this.route.path})`}},Ec=class{snapshot;type=Ce.ChildActivationStart;constructor(t){this.snapshot=t}toString(){return`ChildActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}},_c=class{snapshot;type=Ce.ChildActivationEnd;constructor(t){this.snapshot=t}toString(){return`ChildActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}},bc=class{snapshot;type=Ce.ActivationStart;constructor(t){this.snapshot=t}toString(){return`ActivationStart(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}},wc=class{snapshot;type=Ce.ActivationEnd;constructor(t){this.snapshot=t}toString(){return`ActivationEnd(path: '${this.snapshot.routeConfig&&this.snapshot.routeConfig.path||""}')`}};var ao=class{},Li=class{},co=class{url;navigationBehaviorOptions;constructor(t,n){this.url=t,this.navigationBehaviorOptions=n}};function t0(e){return!(e instanceof ao)&&!(e instanceof co)&&!(e instanceof Li)}var Ic=class{rootInjector;outlet=null;route=null;children;attachRef=null;get injector(){return this.route?.snapshot._environmentInjector??this.rootInjector}constructor(t){this.rootInjector=t,this.children=new po(this.rootInjector)}},po=(()=>{class e{rootInjector;contexts=new Map;constructor(n){this.rootInjector=n}onChildOutletCreated(n,r){let o=this.getOrCreateContext(n);o.outlet=r,this.contexts.set(n,o)}onChildOutletDestroyed(n){let r=this.getContext(n);r&&(r.outlet=null,r.attachRef=null)}onOutletDeactivated(){let n=this.contexts;return this.contexts=new Map,n}onOutletReAttached(n){this.contexts=n}getOrCreateContext(n){let r=this.getContext(n);return r||(r=new Ic(this.rootInjector),this.contexts.set(n,r)),r}getContext(n){return this.contexts.get(n)||null}static \u0275fac=function(r){return new(r||e)(T(ne))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Sc=class{_root;constructor(t){this._root=t}get root(){return this._root.value}parent(t){let n=this.pathFromRoot(t);return n.length>1?n[n.length-2]:null}children(t){let n=uf(t,this._root);return n?n.children.map(r=>r.value):[]}firstChild(t){let n=uf(t,this._root);return n&&n.children.length>0?n.children[0].value:null}siblings(t){let n=df(t,this._root);return n.length<2?[]:n[n.length-2].children.map(o=>o.value).filter(o=>o!==t)}pathFromRoot(t){return df(t,this._root).map(n=>n.value)}};function uf(e,t){if(e===t.value)return t;for(let n of t.children){let r=uf(e,n);if(r)return r}return null}function df(e,t){if(e===t.value)return[t];for(let n of t.children){let r=df(e,n);if(r.length)return r.unshift(t),r}return[]}var Je=class{value;children;constructor(t,n){this.value=t,this.children=n}toString(){return`TreeNode(${this.value})`}};function oo(e){let t={};return e&&e.children.forEach(n=>t[n.value.outlet]=n),t}var ji=class extends Sc{snapshot;constructor(t,n){super(t),this.snapshot=n,Cf(this,t)}toString(){return this.snapshot.toString()}};function Yy(e,t){let n=n0(e,t),r=new be([new xn("",{})]),o=new be({}),i=new be({}),s=new be({}),a=new be(""),c=new _t(r,o,s,a,i,O,e,n.root);return c.snapshot=n.root,new ji(new Je(c,[]),n)}function n0(e,t){let n={},r={},o={},s=new lo([],n,o,"",r,O,e,null,{},t);return new Vi("",new Je(s,[]))}var _t=class{urlSubject;paramsSubject;queryParamsSubject;fragmentSubject;dataSubject;outlet;component;snapshot;_futureSnapshot;_routerState;_paramMap;_queryParamMap;title;url;params;queryParams;fragment;data;constructor(t,n,r,o,i,s,a,c){this.urlSubject=t,this.paramsSubject=n,this.queryParamsSubject=r,this.fragmentSubject=o,this.dataSubject=i,this.outlet=s,this.component=a,this._futureSnapshot=c,this.title=this.dataSubject?.pipe(W(l=>l[Hi]))??k(void 0),this.url=t,this.params=n,this.queryParams=r,this.fragment=o,this.data=i}get routeConfig(){return this._futureSnapshot.routeConfig}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap??=this.params.pipe(W(t=>Cr(t))),this._paramMap}get queryParamMap(){return this._queryParamMap??=this.queryParams.pipe(W(t=>Cr(t))),this._queryParamMap}toString(){return this.snapshot?this.snapshot.toString():`Future(${this._futureSnapshot})`}};function Df(e,t,n="emptyOnly"){let r,{routeConfig:o}=e;return t!==null&&(n==="always"||o?.path===""||!t.component&&!t.routeConfig?.loadComponent)?r={params:y(y({},t.params),e.params),data:y(y({},t.data),e.data),resolve:y(y(y(y({},e.data),t.data),o?.data),e._resolvedData)}:r={params:y({},e.params),data:y({},e.data),resolve:y(y({},e.data),e._resolvedData??{})},o&&Qy(o)&&(r.resolve[Hi]=o.title),r}var lo=class{url;params;queryParams;fragment;data;outlet;component;routeConfig;_resolve;_resolvedData;_routerState;_paramMap;_queryParamMap;_environmentInjector;get title(){return this.data?.[Hi]}constructor(t,n,r,o,i,s,a,c,l,u){this.url=t,this.params=n,this.queryParams=r,this.fragment=o,this.data=i,this.outlet=s,this.component=a,this.routeConfig=c,this._resolve=l,this._environmentInjector=u}get root(){return this._routerState.root}get parent(){return this._routerState.parent(this)}get firstChild(){return this._routerState.firstChild(this)}get children(){return this._routerState.children(this)}get pathFromRoot(){return this._routerState.pathFromRoot(this)}get paramMap(){return this._paramMap??=Cr(this.params),this._paramMap}get queryParamMap(){return this._queryParamMap??=Cr(this.queryParams),this._queryParamMap}toString(){let t=this.url.map(r=>r.toString()).join("/"),n=this.routeConfig?this.routeConfig.path:"";return`Route(url:'${t}', path:'${n}')`}},Vi=class extends Sc{url;constructor(t,n){super(n),this.url=t,Cf(this,n)}toString(){return Ky(this._root)}};function Cf(e,t){t.value._routerState=e,t.children.forEach(n=>Cf(e,n))}function Ky(e){let t=e.children.length>0?` { ${e.children.map(Ky).join(", ")} } `:"";return`${e.value}${t}`}function nf(e){if(e.snapshot){let t=e.snapshot,n=e._futureSnapshot;e.snapshot=n,jt(t.queryParams,n.queryParams)||e.queryParamsSubject.next(n.queryParams),t.fragment!==n.fragment&&e.fragmentSubject.next(n.fragment),jt(t.params,n.params)||e.paramsSubject.next(n.params),NI(t.url,n.url)||e.urlSubject.next(n.url),jt(t.data,n.data)||e.dataSubject.next(n.data)}else e.snapshot=e._futureSnapshot,e.dataSubject.next(e._futureSnapshot.data)}function ff(e,t){let n=jt(e.params,t.params)&&kI(e.url,t.url),r=!e.parent!=!t.parent;return n&&!r&&(!e.parent||ff(e.parent,t.parent))}function Qy(e){return typeof e.title=="string"||e.title===null}var Jy=new I(""),$i=(()=>{class e{activated=null;get activatedComponentRef(){return this.activated}_activatedRoute=null;name=O;activateEvents=new he;deactivateEvents=new he;attachEvents=new he;detachEvents=new he;routerOutletData=km();parentContexts=p(po);location=p(ui);changeDetector=p(Yr);inputBinder=p(Nc,{optional:!0});supportsBindingToComponentInputs=!0;ngOnChanges(n){if(n.name){let{firstChange:r,previousValue:o}=n.name;if(r)return;this.isTrackedInParentContexts(o)&&(this.deactivate(),this.parentContexts.onChildOutletDestroyed(o)),this.initializeOutletWithName()}}ngOnDestroy(){this.isTrackedInParentContexts(this.name)&&this.parentContexts.onChildOutletDestroyed(this.name),this.inputBinder?.unsubscribeFromRouteData(this)}isTrackedInParentContexts(n){return this.parentContexts.getContext(n)?.outlet===this}ngOnInit(){this.initializeOutletWithName()}initializeOutletWithName(){if(this.parentContexts.onChildOutletCreated(this.name,this),this.activated)return;let n=this.parentContexts.getContext(this.name);n?.route&&(n.attachRef?this.attach(n.attachRef,n.route):this.activateWith(n.route,n.injector))}get isActivated(){return!!this.activated}get component(){if(!this.activated)throw new E(4012,!1);return this.activated.instance}get activatedRoute(){if(!this.activated)throw new E(4012,!1);return this._activatedRoute}get activatedRouteData(){return this._activatedRoute?this._activatedRoute.snapshot.data:{}}detach(){if(!this.activated)throw new E(4012,!1);this.location.detach();let n=this.activated;return this.activated=null,this._activatedRoute=null,this.detachEvents.emit(n.instance),n}attach(n,r){this.activated=n,this._activatedRoute=r,this.location.insert(n.hostView),this.inputBinder?.bindActivatedRouteToOutletComponent(this),this.attachEvents.emit(n.instance)}deactivate(){if(this.activated){let n=this.component;this.activated.destroy(),this.activated=null,this._activatedRoute=null,this.deactivateEvents.emit(n)}}activateWith(n,r){if(this.isActivated)throw new E(4013,!1);this._activatedRoute=n;let o=this.location,s=n.snapshot.component,a=this.parentContexts.getOrCreateContext(this.name).children,c=new hf(n,a,o.injector,this.routerOutletData);this.activated=o.createComponent(s,{index:o.length,injector:c,environmentInjector:r}),this.changeDetector.markForCheck(),this.inputBinder?.bindActivatedRouteToOutletComponent(this),this.activateEvents.emit(this.activated.instance)}static \u0275fac=function(r){return new(r||e)};static \u0275dir=Pe({type:e,selectors:[["router-outlet"]],inputs:{name:"name",routerOutletData:[1,"routerOutletData"]},outputs:{activateEvents:"activate",deactivateEvents:"deactivate",attachEvents:"attach",detachEvents:"detach"},exportAs:["outlet"],features:[Mn]})}return e})(),hf=class{route;childContexts;parent;outletData;constructor(t,n,r,o){this.route=t,this.childContexts=n,this.parent=r,this.outletData=o}get(t,n){return t===_t?this.route:t===po?this.childContexts:t===Jy?this.outletData:this.parent.get(t,n)}},Nc=new I("");var Ef=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275cmp=Jt({type:e,selectors:[["ng-component"]],exportAs:["emptyRouterOutlet"],decls:1,vars:0,template:function(r,o){r&1&&qr(0,"router-outlet")},dependencies:[$i],encapsulation:2})}return e})();function _f(e){let t=e.children&&e.children.map(_f),n=t?A(y({},e),{children:t}):y({},e);return!n.component&&!n.loadComponent&&(t||n.loadChildren)&&n.outlet&&n.outlet!==O&&(n.component=Ef),n}function r0(e,t,n){let r=Bi(e,t._root,n?n._root:void 0);return new ji(r,t)}function Bi(e,t,n){if(n&&e.shouldReuseRoute(t.value,n.value.snapshot)){let r=n.value;r._futureSnapshot=t.value;let o=o0(e,t,n);return new Je(r,o)}else{if(e.shouldAttach(t.value)){let i=e.retrieve(t.value);if(i!==null){let s=i.route;return s.value._futureSnapshot=t.value,s.children=t.children.map(a=>Bi(e,a)),s}}let r=i0(t.value),o=t.children.map(i=>Bi(e,i));return new Je(r,o)}}function o0(e,t,n){return t.children.map(r=>{for(let o of n.children)if(e.shouldReuseRoute(r.value,o.value.snapshot))return Bi(e,r,o);return Bi(e,r)})}function i0(e){return new _t(new be(e.url),new be(e.params),new be(e.queryParams),new be(e.fragment),new be(e.data),e.outlet,e.component,e)}var uo=class{redirectTo;navigationBehaviorOptions;constructor(t,n){this.redirectTo=t,this.navigationBehaviorOptions=n}},Xy="ngNavigationCancelingError";function Mc(e,t){let{redirectTo:n,navigationBehaviorOptions:r}=On(t)?{redirectTo:t,navigationBehaviorOptions:void 0}:t,o=ev(!1,Ne.Redirect);return o.url=n,o.navigationBehaviorOptions=r,o}function ev(e,t){let n=new Error(`NavigationCancelingError: ${e||""}`);return n[Xy]=!0,n.cancellationCode=t,n}function s0(e){return tv(e)&&On(e.url)}function tv(e){return!!e&&e[Xy]}var pf=class{routeReuseStrategy;futureState;currState;forwardEvent;inputBindingEnabled;constructor(t,n,r,o,i){this.routeReuseStrategy=t,this.futureState=n,this.currState=r,this.forwardEvent=o,this.inputBindingEnabled=i}activate(t){let n=this.futureState._root,r=this.currState?this.currState._root:null;this.deactivateChildRoutes(n,r,t),nf(this.futureState.root),this.activateChildRoutes(n,r,t)}deactivateChildRoutes(t,n,r){let o=oo(n);t.children.forEach(i=>{let s=i.value.outlet;this.deactivateRoutes(i,o[s],r),delete o[s]}),Object.values(o).forEach(i=>{this.deactivateRouteAndItsChildren(i,r)})}deactivateRoutes(t,n,r){let o=t.value,i=n?n.value:null;if(o===i)if(o.component){let s=r.getContext(o.outlet);s&&this.deactivateChildRoutes(t,n,s.children)}else this.deactivateChildRoutes(t,n,r);else i&&this.deactivateRouteAndItsChildren(n,r)}deactivateRouteAndItsChildren(t,n){t.value.component&&this.routeReuseStrategy.shouldDetach(t.value.snapshot)?this.detachAndStoreRouteSubtree(t,n):this.deactivateRouteAndOutlet(t,n)}detachAndStoreRouteSubtree(t,n){let r=n.getContext(t.value.outlet),o=r&&t.value.component?r.children:n,i=oo(t);for(let s of Object.values(i))this.deactivateRouteAndItsChildren(s,o);if(r&&r.outlet){let s=r.outlet.detach(),a=r.children.onOutletDeactivated();this.routeReuseStrategy.store(t.value.snapshot,{componentRef:s,route:t,contexts:a})}}deactivateRouteAndOutlet(t,n){let r=n.getContext(t.value.outlet),o=r&&t.value.component?r.children:n,i=oo(t);for(let s of Object.values(i))this.deactivateRouteAndItsChildren(s,o);r&&(r.outlet&&(r.outlet.deactivate(),r.children.onOutletDeactivated()),r.attachRef=null,r.route=null)}activateChildRoutes(t,n,r){let o=oo(n);t.children.forEach(i=>{this.activateRoutes(i,o[i.value.outlet],r),this.forwardEvent(new wc(i.value.snapshot))}),t.children.length&&this.forwardEvent(new _c(t.value.snapshot))}activateRoutes(t,n,r){let o=t.value,i=n?n.value:null;if(nf(o),o===i)if(o.component){let s=r.getOrCreateContext(o.outlet);this.activateChildRoutes(t,n,s.children)}else this.activateChildRoutes(t,n,r);else if(o.component){let s=r.getOrCreateContext(o.outlet);if(this.routeReuseStrategy.shouldAttach(o.snapshot)){let a=this.routeReuseStrategy.retrieve(o.snapshot);this.routeReuseStrategy.store(o.snapshot,null),s.children.onOutletReAttached(a.contexts),s.attachRef=a.componentRef,s.route=a.route.value,s.outlet&&s.outlet.attach(a.componentRef,a.route.value),nf(a.route.value),this.activateChildRoutes(t,null,s.children)}else s.attachRef=null,s.route=o,s.outlet&&s.outlet.activateWith(o,s.injector),this.activateChildRoutes(t,null,s.children)}else this.activateChildRoutes(t,null,r)}},Tc=class{path;route;constructor(t){this.path=t,this.route=this.path[this.path.length-1]}},so=class{component;route;constructor(t,n){this.component=t,this.route=n}};function a0(e,t,n){let r=e._root,o=t?t._root:null;return Ni(r,o,n,[r.value])}function c0(e){let t=e.routeConfig?e.routeConfig.canActivateChild:null;return!t||t.length===0?null:{node:e,guards:t}}function go(e,t){let n=Symbol(),r=t.get(e,n);return r===n?typeof e=="function"&&!xl(e)?e:t.get(e):r}function Ni(e,t,n,r,o={canDeactivateChecks:[],canActivateChecks:[]}){let i=oo(t);return e.children.forEach(s=>{l0(s,i[s.value.outlet],n,r.concat([s.value]),o),delete i[s.value.outlet]}),Object.entries(i).forEach(([s,a])=>Oi(a,n.getContext(s),o)),o}function l0(e,t,n,r,o={canDeactivateChecks:[],canActivateChecks:[]}){let i=e.value,s=t?t.value:null,a=n?n.getContext(e.value.outlet):null;if(s&&i.routeConfig===s.routeConfig){let c=u0(s,i,i.routeConfig.runGuardsAndResolvers);c?o.canActivateChecks.push(new Tc(r)):(i.data=s.data,i._resolvedData=s._resolvedData),i.component?Ni(e,t,a?a.children:null,r,o):Ni(e,t,n,r,o),c&&a&&a.outlet&&a.outlet.isActivated&&o.canDeactivateChecks.push(new so(a.outlet.component,s))}else s&&Oi(t,a,o),o.canActivateChecks.push(new Tc(r)),i.component?Ni(e,null,a?a.children:null,r,o):Ni(e,null,n,r,o);return o}function u0(e,t,n){if(typeof n=="function")return De(t._environmentInjector,()=>n(e,t));switch(n){case"pathParamsChange":return!Dr(e.url,t.url);case"pathParamsOrQueryParamsChange":return!Dr(e.url,t.url)||!jt(e.queryParams,t.queryParams);case"always":return!0;case"paramsOrQueryParamsChange":return!ff(e,t)||!jt(e.queryParams,t.queryParams);default:return!ff(e,t)}}function Oi(e,t,n){let r=oo(e),o=e.value;Object.entries(r).forEach(([i,s])=>{o.component?t?Oi(s,t.children.getContext(i),n):Oi(s,null,n):Oi(s,t,n)}),o.component?t&&t.outlet&&t.outlet.isActivated?n.canDeactivateChecks.push(new so(t.outlet.component,o)):n.canDeactivateChecks.push(new so(null,o)):n.canDeactivateChecks.push(new so(null,o))}function zi(e){return typeof e=="function"}function d0(e){return typeof e=="boolean"}function f0(e){return e&&zi(e.canLoad)}function h0(e){return e&&zi(e.canActivate)}function p0(e){return e&&zi(e.canActivateChild)}function g0(e){return e&&zi(e.canDeactivate)}function m0(e){return e&&zi(e.canMatch)}function nv(e){return e instanceof $t||e?.name==="EmptyError"}var cc=Symbol("INITIAL_VALUE");function fo(){return Ue(e=>fl(e.map(t=>t.pipe(zt(1),pl(cc)))).pipe(W(t=>{for(let n of t)if(n!==!0){if(n===cc)return cc;if(n===!1||y0(n))return n}return!0}),gt(t=>t!==cc),zt(1)))}function y0(e){return On(e)||e instanceof uo}function rv(e){return e.aborted?k(void 0).pipe(zt(1)):new j(t=>{let n=()=>{t.next(),t.complete()};return e.addEventListener("abort",n),()=>e.removeEventListener("abort",n)})}function ov(e){return Ro(rv(e))}function v0(e){return xe(t=>{let{targetSnapshot:n,currentSnapshot:r,guards:{canActivateChecks:o,canDeactivateChecks:i}}=t;return i.length===0&&o.length===0?k(A(y({},t),{guardsResult:!0})):D0(i,n,r).pipe(xe(s=>s&&d0(s)?C0(n,o,e):k(s)),W(s=>A(y({},t),{guardsResult:s})))})}function D0(e,t,n){return ae(e).pipe(xe(r=>I0(r.component,r.route,n,t)),Gt(r=>r!==!0,!0))}function C0(e,t,n){return ae(t).pipe(xr(r=>Nr(_0(r.route.parent,n),E0(r.route,n),w0(e,r.path),b0(e,r.route))),Gt(r=>r!==!0,!0))}function E0(e,t){return e!==null&&t&&t(new bc(e)),k(!0)}function _0(e,t){return e!==null&&t&&t(new Ec(e)),k(!0)}function b0(e,t){let n=t.routeConfig?t.routeConfig.canActivate:null;if(!n||n.length===0)return k(!0);let r=n.map(o=>Ao(()=>{let i=t._environmentInjector,s=go(o,i),a=h0(s)?s.canActivate(t,e):De(i,()=>s(t,e));return br(a).pipe(Gt())}));return k(r).pipe(fo())}function w0(e,t){let n=t[t.length-1],o=t.slice(0,t.length-1).reverse().map(i=>c0(i)).filter(i=>i!==null).map(i=>Ao(()=>{let s=i.guards.map(a=>{let c=i.node._environmentInjector,l=go(a,c),u=p0(l)?l.canActivateChild(n,e):De(c,()=>l(n,e));return br(u).pipe(Gt())});return k(s).pipe(fo())}));return k(o).pipe(fo())}function I0(e,t,n,r){let o=t&&t.routeConfig?t.routeConfig.canDeactivate:null;if(!o||o.length===0)return k(!0);let i=o.map(s=>{let a=t._environmentInjector,c=go(s,a),l=g0(c)?c.canDeactivate(e,t,n,r):De(a,()=>c(e,t,n,r));return br(l).pipe(Gt())});return k(i).pipe(fo())}function S0(e,t,n,r,o){let i=t.canLoad;if(i===void 0||i.length===0)return k(!0);let s=i.map(a=>{let c=go(a,e),l=f0(c)?c.canLoad(t,n):De(e,()=>c(t,n)),u=br(l);return o?u.pipe(ov(o)):u});return k(s).pipe(fo(),iv(r))}function iv(e){return cl(tt(t=>{if(typeof t!="boolean")throw Mc(e,t)}),W(t=>t===!0))}function M0(e,t,n,r,o,i){let s=t.canMatch;if(!s||s.length===0)return k(!0);let a=s.map(c=>{let l=go(c,e),u=m0(l)?l.canMatch(t,n,o):De(e,()=>l(t,n,o));return br(u).pipe(ov(i))});return k(a).pipe(fo(),iv(r))}var on=class e extends Error{segmentGroup;constructor(t){super(),this.segmentGroup=t||null,Object.setPrototypeOf(this,e.prototype)}},Ui=class e extends Error{urlTree;constructor(t){super(),this.urlTree=t,Object.setPrototypeOf(this,e.prototype)}};function T0(e){throw new E(4e3,!1)}function A0(e){throw ev(!1,Ne.GuardRejected)}var gf=class{urlSerializer;urlTree;constructor(t,n){this.urlSerializer=t,this.urlTree=n}async lineralizeSegments(t,n){let r=[],o=n.root;for(;;){if(r=r.concat(o.segments),o.numberOfChildren===0)return r;if(o.numberOfChildren>1||!o.children[O])throw T0(`${t.redirectTo}`);o=o.children[O]}}async applyRedirectCommands(t,n,r,o,i){let s=await N0(n,o,i);if(s instanceof Xe)throw new Ui(s);let a=this.applyRedirectCreateUrlTree(s,this.urlSerializer.parse(s),t,r);if(s[0]==="/")throw new Ui(a);return a}applyRedirectCreateUrlTree(t,n,r,o){let i=this.createSegmentGroup(t,n.root,r,o);return new Xe(i,this.createQueryParams(n.queryParams,this.urlTree.queryParams),n.fragment)}createQueryParams(t,n){let r={};return Object.entries(t).forEach(([o,i])=>{if(typeof i=="string"&&i[0]===":"){let a=i.substring(1);r[o]=n[a]}else r[o]=i}),r}createSegmentGroup(t,n,r,o){let i=this.createSegments(t,n.segments,r,o),s={};return Object.entries(n.children).forEach(([a,c])=>{s[a]=this.createSegmentGroup(t,c,r,o)}),new H(i,s)}createSegments(t,n,r,o){return n.map(i=>i.path[0]===":"?this.findPosParam(t,i,o):this.findOrReturn(i,r))}findPosParam(t,n,r){let o=r[n.path.substring(1)];if(!o)throw new E(4001,!1);return o}findOrReturn(t,n){let r=0;for(let o of n){if(o.path===t.path)return n.splice(r),o;r++}return t}};function N0(e,t,n){if(typeof e=="string")return Promise.resolve(e);let r=e;return fc(br(De(n,()=>r(t))))}function x0(e,t){return e.providers&&!e._injector&&(e._injector=di(e.providers,t,`Route: ${e.path}`)),e._injector??t}function Vt(e){return e.outlet||O}function R0(e,t){let n=e.filter(r=>Vt(r)===t);return n.push(...e.filter(r=>Vt(r)!==t)),n}var mf={matched:!1,consumedSegments:[],remainingSegments:[],parameters:{},positionalParamSegments:{}};function sv(e){return{routeConfig:e.routeConfig,url:e.url,params:e.params,queryParams:e.queryParams,fragment:e.fragment,data:e.data,outlet:e.outlet,title:e.title,paramMap:e.paramMap,queryParamMap:e.queryParamMap}}function O0(e,t,n,r,o,i,s){let a=av(e,t,n);if(!a.matched)return k(a);let c=sv(i(a));return r=x0(t,r),M0(r,t,n,o,c,s).pipe(W(l=>l===!0?a:y({},mf)))}function av(e,t,n){if(t.path==="")return t.pathMatch==="full"&&(e.hasChildren()||n.length>0)?y({},mf):{matched:!0,consumedSegments:[],remainingSegments:n,parameters:{},positionalParamSegments:{}};let o=(t.matcher||xy)(n,e,t);if(!o)return y({},mf);let i={};Object.entries(o.posParams??{}).forEach(([a,c])=>{i[a]=c.path});let s=o.consumed.length>0?y(y({},i),o.consumed[o.consumed.length-1].parameters):i;return{matched:!0,consumedSegments:o.consumed,remainingSegments:n.slice(o.consumed.length),parameters:s,positionalParamSegments:o.posParams??{}}}function Ay(e,t,n,r){return n.length>0&&F0(e,n,r)?{segmentGroup:new H(t,k0(r,new H(n,e.children))),slicedSegments:[]}:n.length===0&&L0(e,n,r)?{segmentGroup:new H(e.segments,P0(e,n,r,e.children)),slicedSegments:n}:{segmentGroup:new H(e.segments,e.children),slicedSegments:n}}function P0(e,t,n,r){let o={};for(let i of n)if(xc(e,t,i)&&!r[Vt(i)]){let s=new H([],{});o[Vt(i)]=s}return y(y({},r),o)}function k0(e,t){let n={};n[O]=t;for(let r of e)if(r.path===""&&Vt(r)!==O){let o=new H([],{});n[Vt(r)]=o}return n}function F0(e,t,n){return n.some(r=>xc(e,t,r)&&Vt(r)!==O)}function L0(e,t,n){return n.some(r=>xc(e,t,r))}function xc(e,t,n){return(e.hasChildren()||t.length>0)&&n.pathMatch==="full"?!1:n.path===""}function j0(e,t,n){return t.length===0&&!e.children[n]}var yf=class{};async function V0(e,t,n,r,o,i,s="emptyOnly",a){return new vf(e,t,n,r,o,s,i,a).recognize()}var B0=31,vf=class{injector;configLoader;rootComponentType;config;urlTree;paramsInheritanceStrategy;urlSerializer;abortSignal;applyRedirects;absoluteRedirectCount=0;allowRedirects=!0;constructor(t,n,r,o,i,s,a,c){this.injector=t,this.configLoader=n,this.rootComponentType=r,this.config=o,this.urlTree=i,this.paramsInheritanceStrategy=s,this.urlSerializer=a,this.abortSignal=c,this.applyRedirects=new gf(this.urlSerializer,this.urlTree)}noMatchError(t){return new E(4002,`'${t.segmentGroup}'`)}async recognize(){let t=Ay(this.urlTree.root,[],[],this.config).segmentGroup,{children:n,rootSnapshot:r}=await this.match(t),o=new Je(r,n),i=new Vi("",o),s=$y(r,[],this.urlTree.queryParams,this.urlTree.fragment);return s.queryParams=this.urlTree.queryParams,i.url=this.urlSerializer.serialize(s),{state:i,tree:s}}async match(t){let n=new lo([],Object.freeze({}),Object.freeze(y({},this.urlTree.queryParams)),this.urlTree.fragment,Object.freeze({}),O,this.rootComponentType,null,{},this.injector);try{return{children:await this.processSegmentGroup(this.injector,this.config,t,O,n),rootSnapshot:n}}catch(r){if(r instanceof Ui)return this.urlTree=r.urlTree,this.match(r.urlTree.root);throw r instanceof on?this.noMatchError(r):r}}async processSegmentGroup(t,n,r,o,i){if(r.segments.length===0&&r.hasChildren())return this.processChildren(t,n,r,i);let s=await this.processSegment(t,n,r,r.segments,o,!0,i);return s instanceof Je?[s]:[]}async processChildren(t,n,r,o){let i=[];for(let c of Object.keys(r.children))c==="primary"?i.unshift(c):i.push(c);let s=[];for(let c of i){let l=r.children[c],u=R0(n,c),d=await this.processSegmentGroup(t,u,l,c,o);s.push(...d)}let a=cv(s);return U0(a),a}async processSegment(t,n,r,o,i,s,a){for(let c of n)try{return await this.processSegmentAgainstRoute(c._injector??t,n,c,r,o,i,s,a)}catch(l){if(l instanceof on||nv(l))continue;throw l}if(j0(r,o,i))return new yf;throw new on(r)}async processSegmentAgainstRoute(t,n,r,o,i,s,a,c){if(Vt(r)!==s&&(s===O||!xc(o,i,r)))throw new on(o);if(r.redirectTo===void 0)return this.matchSegmentAgainstRoute(t,o,r,i,s,c);if(this.allowRedirects&&a)return this.expandSegmentAgainstRouteUsingRedirect(t,o,n,r,i,s,c);throw new on(o)}async expandSegmentAgainstRouteUsingRedirect(t,n,r,o,i,s,a){let{matched:c,parameters:l,consumedSegments:u,positionalParamSegments:d,remainingSegments:h}=av(n,o,i);if(!c)throw new on(n);typeof o.redirectTo=="string"&&o.redirectTo[0]==="/"&&(this.absoluteRedirectCount++,this.absoluteRedirectCount>B0&&(this.allowRedirects=!1));let f=this.createSnapshot(t,o,i,l,a);if(this.abortSignal.aborted)throw new Error(this.abortSignal.reason);let v=await this.applyRedirects.applyRedirectCommands(u,o.redirectTo,d,sv(f),t),_=await this.applyRedirects.lineralizeSegments(o,v);return this.processSegment(t,r,n,_.concat(h),s,!1,a)}createSnapshot(t,n,r,o,i){let s=new lo(r,o,Object.freeze(y({},this.urlTree.queryParams)),this.urlTree.fragment,$0(n),Vt(n),n.component??n._loadedComponent??null,n,z0(n),t),a=Df(s,i,this.paramsInheritanceStrategy);return s.params=Object.freeze(a.params),s.data=Object.freeze(a.data),s}async matchSegmentAgainstRoute(t,n,r,o,i,s){if(this.abortSignal.aborted)throw new Error(this.abortSignal.reason);let a=Ee=>this.createSnapshot(t,r,Ee.consumedSegments,Ee.parameters,s),c=await fc(O0(n,r,o,t,this.urlSerializer,a,this.abortSignal));if(r.path==="**"&&(n.children={}),!c?.matched)throw new on(n);t=r._injector??t;let{routes:l}=await this.getChildConfig(t,r,o),u=r._loadedInjector??t,{parameters:d,consumedSegments:h,remainingSegments:f}=c,v=this.createSnapshot(t,r,h,d,s),{segmentGroup:_,slicedSegments:b}=Ay(n,h,f,l);if(b.length===0&&_.hasChildren()){let Ee=await this.processChildren(u,l,_,v);return new Je(v,Ee)}if(l.length===0&&b.length===0)return new Je(v,[]);let w=Vt(r)===i,K=await this.processSegment(u,l,_,b,w?O:i,!0,v);return new Je(v,K instanceof Je?[K]:[])}async getChildConfig(t,n,r){if(n.children)return{routes:n.children,injector:t};if(n.loadChildren){if(n._loadedRoutes!==void 0){let i=n._loadedNgModuleFactory;return i&&!n._loadedInjector&&(n._loadedInjector=i.create(t).injector),{routes:n._loadedRoutes,injector:n._loadedInjector}}if(this.abortSignal.aborted)throw new Error(this.abortSignal.reason);if(await fc(S0(t,n,r,this.urlSerializer,this.abortSignal))){let i=await this.configLoader.loadChildren(t,n);return n._loadedRoutes=i.routes,n._loadedInjector=i.injector,n._loadedNgModuleFactory=i.factory,i}throw A0(n)}return{routes:[],injector:t}}};function U0(e){e.sort((t,n)=>t.value.outlet===O?-1:n.value.outlet===O?1:t.value.outlet.localeCompare(n.value.outlet))}function H0(e){let t=e.value.routeConfig;return t&&t.path===""}function cv(e){let t=[],n=new Set;for(let r of e){if(!H0(r)){t.push(r);continue}let o=t.find(i=>r.value.routeConfig===i.value.routeConfig);o!==void 0?(o.children.push(...r.children),n.add(o)):t.push(r)}for(let r of n){let o=cv(r.children);t.push(new Je(r.value,o))}return t.filter(r=>!n.has(r))}function $0(e){return e.data||{}}function z0(e){return e.resolve||{}}function G0(e,t,n,r,o,i,s){return xe(async a=>{let{state:c,tree:l}=await V0(e,t,n,r,a.extractedUrl,o,i,s);return A(y({},a),{targetSnapshot:c,urlAfterRedirects:l})})}function W0(e){return xe(t=>{let{targetSnapshot:n,guards:{canActivateChecks:r}}=t;if(!r.length)return k(t);let o=new Set(r.map(a=>a.route)),i=new Set;for(let a of o)if(!i.has(a))for(let c of lv(a))i.add(c);let s=0;return ae(i).pipe(xr(a=>o.has(a)?q0(a,n,e):(a.data=Df(a,a.parent,e).resolve,k(void 0))),tt(()=>s++),Ss(1),xe(a=>s===i.size?k(t):we))})}function lv(e){let t=e.children.map(n=>lv(n)).flat();return[e,...t]}function q0(e,t,n){let r=e.routeConfig,o=e._resolve;return r?.title!==void 0&&!Qy(r)&&(o[Hi]=r.title),Ao(()=>(e.data=Df(e,e.parent,n).resolve,Z0(o,e,t).pipe(W(i=>(e._resolvedData=i,e.data=y(y({},e.data),i),null)))))}function Z0(e,t,n){let r=of(e);if(r.length===0)return k({});let o={};return ae(r).pipe(xe(i=>Y0(e[i],t,n).pipe(Gt(),tt(s=>{if(s instanceof uo)throw Mc(new Rn,s);o[i]=s}))),Ss(1),W(()=>o),No(i=>nv(i)?we:dl(i)))}function Y0(e,t,n){let r=t._environmentInjector,o=go(e,r),i=o.resolve?o.resolve(t,n):De(r,()=>o(t,n));return br(i)}function Ny(e){return Ue(t=>{let n=e(t);return n?ae(n).pipe(W(()=>t)):k(t)})}var bf=(()=>{class e{buildTitle(n){let r,o=n.root;for(;o!==void 0;)r=this.getResolvedTitleForRoute(o)??r,o=o.children.find(i=>i.outlet===O);return r}getResolvedTitleForRoute(n){return n.data[Hi]}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(uv),providedIn:"root"})}return e})(),uv=(()=>{class e extends bf{title;constructor(n){super(),this.title=n}updateTitle(n){let r=this.buildTitle(n);r!==void 0&&this.title.setTitle(r)}static \u0275fac=function(r){return new(r||e)(T(by))};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),mo=new I("",{factory:()=>({})}),Gi=new I(""),dv=(()=>{class e{componentLoaders=new WeakMap;childrenLoaders=new WeakMap;onLoadStartListener;onLoadEndListener;compiler=p(Sd);async loadComponent(n,r){if(this.componentLoaders.get(r))return this.componentLoaders.get(r);if(r._loadedComponent)return Promise.resolve(r._loadedComponent);this.onLoadStartListener&&this.onLoadStartListener(r);let o=(async()=>{try{let i=await Oy(De(n,()=>r.loadComponent())),s=await pv(hv(i));return this.onLoadEndListener&&this.onLoadEndListener(r),r._loadedComponent=s,s}finally{this.componentLoaders.delete(r)}})();return this.componentLoaders.set(r,o),o}loadChildren(n,r){if(this.childrenLoaders.get(r))return this.childrenLoaders.get(r);if(r._loadedRoutes)return Promise.resolve({routes:r._loadedRoutes,injector:r._loadedInjector});this.onLoadStartListener&&this.onLoadStartListener(r);let o=(async()=>{try{let i=await fv(r,this.compiler,n,this.onLoadEndListener);return r._loadedRoutes=i.routes,r._loadedInjector=i.injector,r._loadedNgModuleFactory=i.factory,i}finally{this.childrenLoaders.delete(r)}})();return this.childrenLoaders.set(r,o),o}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();async function fv(e,t,n,r){let o=await Oy(De(n,()=>e.loadChildren())),i=await pv(hv(o)),s;i instanceof La||Array.isArray(i)?s=i:s=await t.compileModuleAsync(i),r&&r(e);let a,c,l=!1,u;return Array.isArray(s)?(c=s,l=!0):(a=s.create(n).injector,u=s,c=a.get(Gi,[],{optional:!0,self:!0}).flat()),{routes:c.map(_f),injector:a,factory:u}}function K0(e){return e&&typeof e=="object"&&"default"in e}function hv(e){return K0(e)?e.default:e}async function pv(e){return e}var Rc=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(Q0),providedIn:"root"})}return e})(),Q0=(()=>{class e{shouldProcessUrl(n){return!0}extract(n){return n}merge(n,r){return n}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),gv=new I("");var J0=()=>{},mv=new I(""),yv=(()=>{class e{currentNavigation=L(null,{equal:()=>!1});currentTransition=null;lastSuccessfulNavigation=L(null);events=new me;transitionAbortWithErrorSubject=new me;configLoader=p(dv);environmentInjector=p(ne);destroyRef=p(We);urlSerializer=p(ho);rootContexts=p(po);location=p(Xr);inputBindingEnabled=p(Nc,{optional:!0})!==null;titleStrategy=p(bf);options=p(mo,{optional:!0})||{};paramsInheritanceStrategy=this.options.paramsInheritanceStrategy||"emptyOnly";urlHandlingStrategy=p(Rc);createViewTransition=p(gv,{optional:!0});navigationErrorHandler=p(mv,{optional:!0});navigationId=0;get hasRequestedNavigation(){return this.navigationId!==0}transitions;afterPreactivation=()=>k(void 0);rootComponentType=null;destroyed=!1;constructor(){let n=o=>this.events.next(new Dc(o)),r=o=>this.events.next(new Cc(o));this.configLoader.onLoadEndListener=r,this.configLoader.onLoadStartListener=n,this.destroyRef.onDestroy(()=>{this.destroyed=!0})}complete(){this.transitions?.complete()}handleNavigationRequest(n){let r=++this.navigationId;q(()=>{this.transitions?.next(A(y({},n),{extractedUrl:this.urlHandlingStrategy.extract(n.rawUrl),targetSnapshot:null,targetRouterState:null,guards:{canActivateChecks:[],canDeactivateChecks:[]},guardsResult:null,id:r,routesRecognizeHandler:{},beforeActivateHandler:{}}))})}setupNavigations(n){return this.transitions=new be(null),this.transitions.pipe(gt(r=>r!==null),Ue(r=>{let o=!1,i=new AbortController,s=()=>!o&&this.currentTransition?.id===r.id;return k(r).pipe(Ue(a=>{if(this.navigationId>r.id)return this.cancelNavigationTransition(r,"",Ne.SupersededByNewNavigation),we;this.currentTransition=r;let c=this.lastSuccessfulNavigation();this.currentNavigation.set({id:a.id,initialUrl:a.rawUrl,extractedUrl:a.extractedUrl,targetBrowserUrl:typeof a.extras.browserUrl=="string"?this.urlSerializer.parse(a.extras.browserUrl):a.extras.browserUrl,trigger:a.source,extras:a.extras,previousNavigation:c?A(y({},c),{previousNavigation:null}):null,abort:()=>i.abort(),routesRecognizeHandler:a.routesRecognizeHandler,beforeActivateHandler:a.beforeActivateHandler});let l=!n.navigated||this.isUpdatingInternalState()||this.isUpdatedBrowserUrl(),u=a.extras.onSameUrlNavigation??n.onSameUrlNavigation;if(!l&&u!=="reload")return this.events.next(new sn(a.id,this.urlSerializer.serialize(a.rawUrl),"",ki.IgnoredSameUrlNavigation)),a.resolve(!1),we;if(this.urlHandlingStrategy.shouldProcessUrl(a.rawUrl))return k(a).pipe(Ue(d=>(this.events.next(new Er(d.id,this.urlSerializer.serialize(d.extractedUrl),d.source,d.restoredState)),d.id!==this.navigationId?we:Promise.resolve(d))),G0(this.environmentInjector,this.configLoader,this.rootComponentType,n.config,this.urlSerializer,this.paramsInheritanceStrategy,i.signal),tt(d=>{r.targetSnapshot=d.targetSnapshot,r.urlAfterRedirects=d.urlAfterRedirects,this.currentNavigation.update(h=>(h.finalUrl=d.urlAfterRedirects,h)),this.events.next(new Li)}),Ue(d=>ae(r.routesRecognizeHandler.deferredHandle??k(void 0)).pipe(W(()=>d))),tt(()=>{let d=new Fi(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects),a.targetSnapshot);this.events.next(d)}));if(l&&this.urlHandlingStrategy.shouldProcessUrl(a.currentRawUrl)){let{id:d,extractedUrl:h,source:f,restoredState:v,extras:_}=a,b=new Er(d,this.urlSerializer.serialize(h),f,v);this.events.next(b);let w=Yy(this.rootComponentType,this.environmentInjector).snapshot;return this.currentTransition=r=A(y({},a),{targetSnapshot:w,urlAfterRedirects:h,extras:A(y({},_),{skipLocationChange:!1,replaceUrl:!1})}),this.currentNavigation.update(K=>(K.finalUrl=h,K)),k(r)}else return this.events.next(new sn(a.id,this.urlSerializer.serialize(a.extractedUrl),"",ki.IgnoredByUrlHandlingStrategy)),a.resolve(!1),we}),W(a=>{let c=new gc(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects),a.targetSnapshot);return this.events.next(c),this.currentTransition=r=A(y({},a),{guards:a0(a.targetSnapshot,a.currentSnapshot,this.rootContexts)}),r}),v0(a=>this.events.next(a)),Ue(a=>{if(r.guardsResult=a.guardsResult,a.guardsResult&&typeof a.guardsResult!="boolean")throw Mc(this.urlSerializer,a.guardsResult);let c=new mc(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects),a.targetSnapshot,!!a.guardsResult);if(this.events.next(c),!s())return we;if(!a.guardsResult)return this.cancelNavigationTransition(a,"",Ne.GuardRejected),we;if(a.guards.canActivateChecks.length===0)return k(a);let l=new yc(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects),a.targetSnapshot);if(this.events.next(l),!s())return we;let u=!1;return k(a).pipe(W0(this.paramsInheritanceStrategy),tt({next:()=>{u=!0;let d=new vc(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects),a.targetSnapshot);this.events.next(d)},complete:()=>{u||this.cancelNavigationTransition(a,"",Ne.NoDataFromResolver)}}))}),Ny(a=>{let c=u=>{let d=[];if(u.routeConfig?._loadedComponent)u.component=u.routeConfig?._loadedComponent;else if(u.routeConfig?.loadComponent){let h=u._environmentInjector;d.push(this.configLoader.loadComponent(h,u.routeConfig).then(f=>{u.component=f}))}for(let h of u.children)d.push(...c(h));return d},l=c(a.targetSnapshot.root);return l.length===0?k(a):ae(Promise.all(l).then(()=>a))}),Ny(()=>this.afterPreactivation()),Ue(()=>{let{currentSnapshot:a,targetSnapshot:c}=r,l=this.createViewTransition?.(this.environmentInjector,a.root,c.root);return l?ae(l).pipe(W(()=>r)):k(r)}),zt(1),Ue(a=>{let c=r0(n.routeReuseStrategy,a.targetSnapshot,a.currentRouterState);this.currentTransition=r=a=A(y({},a),{targetRouterState:c}),this.currentNavigation.update(u=>(u.targetRouterState=c,u)),this.events.next(new ao);let l=r.beforeActivateHandler.deferredHandle;return l?ae(l.then(()=>a)):k(a)}),tt(a=>{new pf(n.routeReuseStrategy,r.targetRouterState,r.currentRouterState,c=>this.events.next(c),this.inputBindingEnabled).activate(this.rootContexts),s()&&(o=!0,this.currentNavigation.update(c=>(c.abort=J0,c)),this.lastSuccessfulNavigation.set(q(this.currentNavigation)),this.events.next(new Bt(a.id,this.urlSerializer.serialize(a.extractedUrl),this.urlSerializer.serialize(a.urlAfterRedirects))),this.titleStrategy?.updateTitle(a.targetRouterState.snapshot),a.resolve(!0))}),Ro(rv(i.signal).pipe(gt(()=>!o&&!r.targetRouterState),tt(()=>{this.cancelNavigationTransition(r,i.signal.reason+"",Ne.Aborted)}))),tt({complete:()=>{o=!0}}),Ro(this.transitionAbortWithErrorSubject.pipe(tt(a=>{throw a}))),xo(()=>{i.abort(),o||this.cancelNavigationTransition(r,"",Ne.SupersededByNewNavigation),this.currentTransition?.id===r.id&&(this.currentNavigation.set(null),this.currentTransition=null)}),No(a=>{if(o=!0,this.destroyed)return r.resolve(!1),we;if(tv(a))this.events.next(new ft(r.id,this.urlSerializer.serialize(r.extractedUrl),a.message,a.cancellationCode)),s0(a)?this.events.next(new co(a.url,a.navigationBehaviorOptions)):r.resolve(!1);else{let c=new _r(r.id,this.urlSerializer.serialize(r.extractedUrl),a,r.targetSnapshot??void 0);try{let l=De(this.environmentInjector,()=>this.navigationErrorHandler?.(c));if(l instanceof uo){let{message:u,cancellationCode:d}=Mc(this.urlSerializer,l);this.events.next(new ft(r.id,this.urlSerializer.serialize(r.extractedUrl),u,d)),this.events.next(new co(l.redirectTo,l.navigationBehaviorOptions))}else throw this.events.next(c),a}catch(l){this.options.resolveNavigationPromiseOnError?r.resolve(!1):r.reject(l)}}return we}))}))}cancelNavigationTransition(n,r,o){let i=new ft(n.id,this.urlSerializer.serialize(n.extractedUrl),r,o);this.events.next(i),n.resolve(!1)}isUpdatingInternalState(){return this.currentTransition?.extractedUrl.toString()!==this.currentTransition?.currentUrlTree.toString()}isUpdatedBrowserUrl(){let n=this.urlHandlingStrategy.extract(this.urlSerializer.parse(this.location.path(!0))),r=q(this.currentNavigation),o=r?.targetBrowserUrl??r?.extractedUrl;return n.toString()!==o?.toString()&&!r?.extras.skipLocationChange}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function X0(e){return e!==Ri}var vv=new I("");var Dv=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(eS),providedIn:"root"})}return e})(),Ac=class{shouldDetach(t){return!1}store(t,n){}shouldAttach(t){return!1}retrieve(t){return null}shouldReuseRoute(t,n){return t.routeConfig===n.routeConfig}shouldDestroyInjector(t){return!0}},eS=(()=>{class e extends Ac{static \u0275fac=(()=>{let n;return function(o){return(n||(n=cr(e)))(o||e)}})();static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),Oc=(()=>{class e{urlSerializer=p(ho);options=p(mo,{optional:!0})||{};canceledNavigationResolution=this.options.canceledNavigationResolution||"replace";location=p(Xr);urlHandlingStrategy=p(Rc);urlUpdateStrategy=this.options.urlUpdateStrategy||"deferred";currentUrlTree=new Xe;getCurrentUrlTree(){return this.currentUrlTree}rawUrlTree=this.currentUrlTree;getRawUrlTree(){return this.rawUrlTree}createBrowserPath({finalUrl:n,initialUrl:r,targetBrowserUrl:o}){let i=n!==void 0?this.urlHandlingStrategy.merge(n,r):r,s=o??i;return s instanceof Xe?this.urlSerializer.serialize(s):s}commitTransition({targetRouterState:n,finalUrl:r,initialUrl:o}){r&&n?(this.currentUrlTree=r,this.rawUrlTree=this.urlHandlingStrategy.merge(r,o),this.routerState=n):this.rawUrlTree=o}routerState=Yy(null,p(ne));getRouterState(){return this.routerState}_stateMemento=this.createStateMemento();get stateMemento(){return this._stateMemento}updateStateMemento(){this._stateMemento=this.createStateMemento()}createStateMemento(){return{rawUrlTree:this.rawUrlTree,currentUrlTree:this.currentUrlTree,routerState:this.routerState}}restoredState(){return this.location.getState()}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:()=>p(tS),providedIn:"root"})}return e})(),tS=(()=>{class e extends Oc{currentPageId=0;lastSuccessfulId=-1;get browserPageId(){return this.canceledNavigationResolution!=="computed"?this.currentPageId:this.restoredState()?.\u0275routerPageId??this.currentPageId}registerNonRouterCurrentEntryChangeListener(n){return this.location.subscribe(r=>{r.type==="popstate"&&setTimeout(()=>{n(r.url,r.state,"popstate",{replaceUrl:!0})})})}handleRouterEvent(n,r){n instanceof Er?this.updateStateMemento():n instanceof sn?this.commitTransition(r):n instanceof Fi?this.urlUpdateStrategy==="eager"&&(r.extras.skipLocationChange||this.setBrowserUrl(this.createBrowserPath(r),r)):n instanceof ao?(this.commitTransition(r),this.urlUpdateStrategy==="deferred"&&!r.extras.skipLocationChange&&this.setBrowserUrl(this.createBrowserPath(r),r)):n instanceof ft&&!Zy(n)?this.restoreHistory(r):n instanceof _r?this.restoreHistory(r,!0):n instanceof Bt&&(this.lastSuccessfulId=n.id,this.currentPageId=this.browserPageId)}setBrowserUrl(n,{extras:r,id:o}){let{replaceUrl:i,state:s}=r;if(this.location.isCurrentPathEqualTo(n)||i){let a=this.browserPageId,c=y(y({},s),this.generateNgRouterState(o,a));this.location.replaceState(n,"",c)}else{let a=y(y({},s),this.generateNgRouterState(o,this.browserPageId+1));this.location.go(n,"",a)}}restoreHistory(n,r=!1){if(this.canceledNavigationResolution==="computed"){let o=this.browserPageId,i=this.currentPageId-o;i!==0?this.location.historyGo(i):this.getCurrentUrlTree()===n.finalUrl&&i===0&&(this.resetInternalState(n),this.resetUrlToCurrentUrlTree())}else this.canceledNavigationResolution==="replace"&&(r&&this.resetInternalState(n),this.resetUrlToCurrentUrlTree())}resetInternalState({finalUrl:n}){this.routerState=this.stateMemento.routerState,this.currentUrlTree=this.stateMemento.currentUrlTree,this.rawUrlTree=this.urlHandlingStrategy.merge(this.currentUrlTree,n??this.rawUrlTree)}resetUrlToCurrentUrlTree(){this.location.replaceState(this.urlSerializer.serialize(this.getRawUrlTree()),"",this.generateNgRouterState(this.lastSuccessfulId,this.currentPageId))}generateNgRouterState(n,r){return this.canceledNavigationResolution==="computed"?{navigationId:n,\u0275routerPageId:r}:{navigationId:n}}static \u0275fac=(()=>{let n;return function(o){return(n||(n=cr(e)))(o||e)}})();static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function wf(e,t){e.events.pipe(gt(n=>n instanceof Bt||n instanceof ft||n instanceof _r||n instanceof sn),W(n=>n instanceof Bt||n instanceof sn?0:(n instanceof ft?n.code===Ne.Redirect||n.code===Ne.SupersededByNewNavigation:!1)?2:1),gt(n=>n!==2),zt(1)).subscribe(()=>{t()})}var Ut=(()=>{class e{get currentUrlTree(){return this.stateManager.getCurrentUrlTree()}get rawUrlTree(){return this.stateManager.getRawUrlTree()}disposed=!1;nonRouterCurrentEntryChangeSubscription;console=p(md);stateManager=p(Oc);options=p(mo,{optional:!0})||{};pendingTasks=p(Qt);urlUpdateStrategy=this.options.urlUpdateStrategy||"deferred";navigationTransitions=p(yv);urlSerializer=p(ho);location=p(Xr);urlHandlingStrategy=p(Rc);injector=p(ne);_events=new me;get events(){return this._events}get routerState(){return this.stateManager.getRouterState()}navigated=!1;routeReuseStrategy=p(Dv);injectorCleanup=p(vv,{optional:!0});onSameUrlNavigation=this.options.onSameUrlNavigation||"ignore";config=p(Gi,{optional:!0})?.flat()??[];componentInputBindingEnabled=!!p(Nc,{optional:!0});currentNavigation=this.navigationTransitions.currentNavigation.asReadonly();constructor(){this.resetConfig(this.config),this.navigationTransitions.setupNavigations(this).subscribe({error:n=>{}}),this.subscribeToNavigationEvents()}eventsSubscription=new _e;subscribeToNavigationEvents(){let n=this.navigationTransitions.events.subscribe(r=>{try{let o=this.navigationTransitions.currentTransition,i=q(this.navigationTransitions.currentNavigation);if(o!==null&&i!==null){if(this.stateManager.handleRouterEvent(r,i),r instanceof ft&&r.code!==Ne.Redirect&&r.code!==Ne.SupersededByNewNavigation)this.navigated=!0;else if(r instanceof Bt)this.navigated=!0,this.injectorCleanup?.(this.routeReuseStrategy,this.routerState,this.config);else if(r instanceof co){let s=r.navigationBehaviorOptions,a=this.urlHandlingStrategy.merge(r.url,o.currentRawUrl),c=y({scroll:o.extras.scroll,browserUrl:o.extras.browserUrl,info:o.extras.info,skipLocationChange:o.extras.skipLocationChange,replaceUrl:o.extras.replaceUrl||this.urlUpdateStrategy==="eager"||X0(o.source)},s);this.scheduleNavigation(a,Ri,null,c,{resolve:o.resolve,reject:o.reject,promise:o.promise})}}t0(r)&&this._events.next(r)}catch(o){this.navigationTransitions.transitionAbortWithErrorSubject.next(o)}});this.eventsSubscription.add(n)}resetRootComponentType(n){this.routerState.root.component=n,this.navigationTransitions.rootComponentType=n}initialNavigation(){this.setUpLocationChangeListener(),this.navigationTransitions.hasRequestedNavigation||this.navigateToSyncWithBrowser(this.location.path(!0),Ri,this.stateManager.restoredState(),{replaceUrl:!0})}setUpLocationChangeListener(){this.nonRouterCurrentEntryChangeSubscription??=this.stateManager.registerNonRouterCurrentEntryChangeListener((n,r,o,i)=>{this.navigateToSyncWithBrowser(n,o,r,i)})}navigateToSyncWithBrowser(n,r,o,i){let s=o?.navigationId?o:null;if(o){let c=y({},o);delete c.navigationId,delete c.\u0275routerPageId,Object.keys(c).length!==0&&(i.state=c)}let a=this.parseUrl(n);this.scheduleNavigation(a,r,s,i).catch(c=>{this.disposed||this.injector.get(qe)(c)})}get url(){return this.serializeUrl(this.currentUrlTree)}getCurrentNavigation(){return q(this.navigationTransitions.currentNavigation)}get lastSuccessfulNavigation(){return this.navigationTransitions.lastSuccessfulNavigation}resetConfig(n){this.config=n.map(_f),this.navigated=!1}ngOnDestroy(){this.dispose()}dispose(){this._events.unsubscribe(),this.navigationTransitions.complete(),this.nonRouterCurrentEntryChangeSubscription?.unsubscribe(),this.nonRouterCurrentEntryChangeSubscription=void 0,this.disposed=!0,this.eventsSubscription.unsubscribe()}createUrlTree(n,r={}){let{relativeTo:o,queryParams:i,fragment:s,queryParamsHandling:a,preserveFragment:c}=r,l=c?this.currentUrlTree.fragment:s,u=null;switch(a??this.options.defaultQueryParamsHandling){case"merge":u=y(y({},this.currentUrlTree.queryParams),i);break;case"preserve":u=this.currentUrlTree.queryParams;break;default:u=i||null}u!==null&&(u=this.removeEmptyProps(u));let d;try{let h=o?o.snapshot:this.routerState.snapshot.root;d=zy(h)}catch{(typeof n[0]!="string"||n[0][0]!=="/")&&(n=[]),d=this.currentUrlTree.root}return Gy(d,n,u,l??null,this.urlSerializer)}navigateByUrl(n,r={skipLocationChange:!1}){let o=On(n)?n:this.parseUrl(n),i=this.urlHandlingStrategy.merge(o,this.rawUrlTree);return this.scheduleNavigation(i,Ri,null,r)}navigate(n,r={skipLocationChange:!1}){return nS(n),this.navigateByUrl(this.createUrlTree(n,r),r)}serializeUrl(n){return this.urlSerializer.serialize(n)}parseUrl(n){try{return this.urlSerializer.parse(n)}catch{return this.console.warn(vn(4018,!1)),this.urlSerializer.parse("/")}}isActive(n,r){let o;if(r===!0?o=y({},ky):r===!1?o=y({},sf):o=y(y({},sf),r),On(n))return wy(this.currentUrlTree,n,o);let i=this.parseUrl(n);return wy(this.currentUrlTree,i,o)}removeEmptyProps(n){return Object.entries(n).reduce((r,[o,i])=>(i!=null&&(r[o]=i),r),{})}scheduleNavigation(n,r,o,i,s){if(this.disposed)return Promise.resolve(!1);let a,c,l;s?(a=s.resolve,c=s.reject,l=s.promise):l=new Promise((d,h)=>{a=d,c=h});let u=this.pendingTasks.add();return wf(this,()=>{queueMicrotask(()=>this.pendingTasks.remove(u))}),this.navigationTransitions.handleNavigationRequest({source:r,restoredState:o,currentUrlTree:this.currentUrlTree,currentRawUrl:this.currentUrlTree,rawUrl:n,extras:i,resolve:a,reject:c,promise:l,currentSnapshot:this.routerState.snapshot,currentRouterState:this.routerState}),l.catch(Promise.reject.bind(Promise))}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})();function nS(e){for(let t=0;t{class e{router=p(Ut);stateManager=p(Oc);fragment=L("");queryParams=L({});path=L("");serializer=p(ho);constructor(){this.updateState(),this.router.events?.subscribe(n=>{n instanceof Bt&&this.updateState()})}updateState(){let{fragment:n,root:r,queryParams:o}=this.stateManager.getCurrentUrlTree();this.fragment.set(n),this.queryParams.set(o),this.path.set(this.serializer.serialize(new Xe(r)))}static \u0275fac=function(r){return new(r||e)};static \u0275prov=S({token:e,factory:e.\u0275fac,providedIn:"root"})}return e})(),yo=(()=>{class e{router;route;tabIndexAttribute;renderer;el;locationStrategy;hrefAttributeValue=p(new Ua("href"),{optional:!0});reactiveHref=Md(()=>this.isAnchorElement?this.computeHref(this._urlTree()):this.hrefAttributeValue);get href(){return q(this.reactiveHref)}set href(n){this.reactiveHref.set(n)}set target(n){this._target.set(n)}get target(){return q(this._target)}_target=L(void 0);set queryParams(n){this._queryParams.set(n)}get queryParams(){return q(this._queryParams)}_queryParams=L(void 0,{equal:()=>!1});set fragment(n){this._fragment.set(n)}get fragment(){return q(this._fragment)}_fragment=L(void 0);set queryParamsHandling(n){this._queryParamsHandling.set(n)}get queryParamsHandling(){return q(this._queryParamsHandling)}_queryParamsHandling=L(void 0);set state(n){this._state.set(n)}get state(){return q(this._state)}_state=L(void 0,{equal:()=>!1});set info(n){this._info.set(n)}get info(){return q(this._info)}_info=L(void 0,{equal:()=>!1});set relativeTo(n){this._relativeTo.set(n)}get relativeTo(){return q(this._relativeTo)}_relativeTo=L(void 0);set preserveFragment(n){this._preserveFragment.set(n)}get preserveFragment(){return q(this._preserveFragment)}_preserveFragment=L(!1);set skipLocationChange(n){this._skipLocationChange.set(n)}get skipLocationChange(){return q(this._skipLocationChange)}_skipLocationChange=L(!1);set replaceUrl(n){this._replaceUrl.set(n)}get replaceUrl(){return q(this._replaceUrl)}_replaceUrl=L(!1);isAnchorElement;onChanges=new me;applicationErrorHandler=p(qe);options=p(mo,{optional:!0});reactiveRouterState=p(iS);constructor(n,r,o,i,s,a){this.router=n,this.route=r,this.tabIndexAttribute=o,this.renderer=i,this.el=s,this.locationStrategy=a;let c=s.nativeElement.tagName?.toLowerCase();this.isAnchorElement=c==="a"||c==="area"||!!(typeof customElements=="object"&&customElements.get(c)?.observedAttributes?.includes?.("href"))}setTabIndexIfNotOnNativeEl(n){this.tabIndexAttribute!=null||this.isAnchorElement||this.applyAttributeValue("tabindex",n)}ngOnChanges(n){this.onChanges.next(this)}routerLinkInput=L(null);set routerLink(n){n==null?(this.routerLinkInput.set(null),this.setTabIndexIfNotOnNativeEl(null)):(On(n)?this.routerLinkInput.set(n):this.routerLinkInput.set(Array.isArray(n)?n:[n]),this.setTabIndexIfNotOnNativeEl("0"))}onClick(n,r,o,i,s){let a=this._urlTree();if(a===null||this.isAnchorElement&&(n!==0||r||o||i||s||typeof this.target=="string"&&this.target!="_self"))return!0;let c={skipLocationChange:this.skipLocationChange,replaceUrl:this.replaceUrl,state:this.state,info:this.info};return this.router.navigateByUrl(a,c)?.catch(l=>{this.applicationErrorHandler(l)}),!this.isAnchorElement}ngOnDestroy(){}applyAttributeValue(n,r){let o=this.renderer,i=this.el.nativeElement;r!==null?o.setAttribute(i,n,r):o.removeAttribute(i,n)}_urlTree=Se(()=>{this.reactiveRouterState.path(),this._preserveFragment()&&this.reactiveRouterState.fragment();let n=o=>o==="preserve"||o==="merge";(n(this._queryParamsHandling())||n(this.options?.defaultQueryParamsHandling))&&this.reactiveRouterState.queryParams();let r=this.routerLinkInput();return r===null||!this.router.createUrlTree?null:On(r)?r:this.router.createUrlTree(r,{relativeTo:this._relativeTo()!==void 0?this._relativeTo():this.route,queryParams:this._queryParams(),fragment:this._fragment(),queryParamsHandling:this._queryParamsHandling(),preserveFragment:this._preserveFragment()})},{equal:(n,r)=>this.computeHref(n)===this.computeHref(r)});get urlTree(){return q(this._urlTree)}computeHref(n){return n!==null&&this.locationStrategy?this.locationStrategy?.prepareExternalUrl(this.router.serializeUrl(n))??"":null}static \u0275fac=function(r){return new(r||e)(B(Ut),B(_t),ai("tabindex"),B(dr),B(Tn),B(Jr))};static \u0275dir=Pe({type:e,selectors:[["","routerLink",""]],hostVars:2,hostBindings:function(r,o){r&1&&te("click",function(s){return o.onClick(s.button,s.ctrlKey,s.shiftKey,s.altKey,s.metaKey)}),r&2&&hr("href",o.reactiveHref(),td)("target",o._target())},inputs:{target:"target",queryParams:"queryParams",fragment:"fragment",queryParamsHandling:"queryParamsHandling",state:"state",info:"info",relativeTo:"relativeTo",preserveFragment:[2,"preserveFragment","preserveFragment",Kr],skipLocationChange:[2,"skipLocationChange","skipLocationChange",Kr],replaceUrl:[2,"replaceUrl","replaceUrl",Kr],routerLink:"routerLink"},features:[Mn]})}return e})();var sS=new I("");function If(e,...t){return _n([{provide:Gi,multi:!0,useValue:e},[],{provide:_t,useFactory:aS},{provide:Va,multi:!0,useFactory:cS},t.map(n=>n.\u0275providers)])}function aS(){return p(Ut).routerState.root}function cS(){let e=p(Le);return t=>{let n=e.get(fr);if(t!==n.components[0])return;let r=e.get(Ut),o=e.get(lS);e.get(uS)===1&&r.initialNavigation(),e.get(dS,null,{optional:!0})?.setUpPreloading(),e.get(sS,null,{optional:!0})?.init(),r.resetRootComponentType(n.componentTypes[0]),o.closed||(o.next(),o.complete(),o.unsubscribe())}}var lS=new I("",{factory:()=>new me}),uS=new I("",{factory:()=>1});var dS=new I("");var Mv=(()=>{class e{_renderer;_elementRef;onChange=n=>{};onTouched=()=>{};constructor(n,r){this._renderer=n,this._elementRef=r}setProperty(n,r){this._renderer.setProperty(this._elementRef.nativeElement,n,r)}registerOnTouched(n){this.onTouched=n}registerOnChange(n){this.onChange=n}setDisabledState(n){this.setProperty("disabled",n)}static \u0275fac=function(r){return new(r||e)(B(dr),B(Tn))};static \u0275dir=Pe({type:e})}return e})(),fS=(()=>{class e extends Mv{static \u0275fac=(()=>{let n;return function(o){return(n||(n=cr(e)))(o||e)}})();static \u0275dir=Pe({type:e,features:[Xt]})}return e})(),Tv=new I("");var hS={provide:Tv,useExisting:Dn(()=>Eo),multi:!0};function pS(){let e=ut()?ut().getUserAgent():"";return/android (\d+)/.test(e.toLowerCase())}var gS=new I(""),Eo=(()=>{class e extends Mv{_compositionMode;_composing=!1;constructor(n,r,o){super(n,r),this._compositionMode=o,this._compositionMode==null&&(this._compositionMode=!pS())}writeValue(n){let r=n??"";this.setProperty("value",r)}_handleInput(n){(!this._compositionMode||this._compositionMode&&!this._composing)&&this.onChange(n)}_compositionStart(){this._composing=!0}_compositionEnd(n){this._composing=!1,this._compositionMode&&this.onChange(n)}static \u0275fac=function(r){return new(r||e)(B(dr),B(Tn),B(gS,8))};static \u0275dir=Pe({type:e,selectors:[["input","formControlName","",3,"type","checkbox"],["textarea","formControlName",""],["input","formControl","",3,"type","checkbox"],["textarea","formControl",""],["input","ngModel","",3,"type","checkbox"],["textarea","ngModel",""],["","ngDefaultControl",""]],hostBindings:function(r,o){r&1&&te("input",function(s){return o._handleInput(s.target.value)})("blur",function(){return o.onTouched()})("compositionstart",function(){return o._compositionStart()})("compositionend",function(s){return o._compositionEnd(s.target.value)})},standalone:!1,features:[hi([hS]),Xt]})}return e})();var Av=new I(""),Nv=new I("");function xv(e){return e!=null}function Rv(e){return An(e)?ae(e):e}function Ov(e){let t={};return e.forEach(n=>{t=n!=null?y(y({},t),n):t}),Object.keys(t).length===0?null:t}function Pv(e,t){return t.map(n=>n(e))}function mS(e){return!e.validate}function kv(e){return e.map(t=>mS(t)?t:n=>t.validate(n))}function yS(e){if(!e)return null;let t=e.filter(xv);return t.length==0?null:function(n){return Ov(Pv(n,t))}}function Tf(e){return e!=null?yS(kv(e)):null}function vS(e){if(!e)return null;let t=e.filter(xv);return t.length==0?null:function(n){let r=Pv(n,t).map(Rv);return hl(r).pipe(W(Ov))}}function Af(e){return e!=null?vS(kv(e)):null}function Cv(e,t){return e===null?[t]:Array.isArray(e)?[...e,t]:[e,t]}function DS(e){return e._rawValidators}function CS(e){return e._rawAsyncValidators}function Sf(e){return e?Array.isArray(e)?e:[e]:[]}function kc(e,t){return Array.isArray(e)?e.includes(t):e===t}function Ev(e,t){let n=Sf(t);return Sf(e).forEach(o=>{kc(n,o)||n.push(o)}),n}function _v(e,t){return Sf(t).filter(n=>!kc(e,n))}var Fc=class{get value(){return this.control?this.control.value:null}get valid(){return this.control?this.control.valid:null}get invalid(){return this.control?this.control.invalid:null}get pending(){return this.control?this.control.pending:null}get disabled(){return this.control?this.control.disabled:null}get enabled(){return this.control?this.control.enabled:null}get errors(){return this.control?this.control.errors:null}get pristine(){return this.control?this.control.pristine:null}get dirty(){return this.control?this.control.dirty:null}get touched(){return this.control?this.control.touched:null}get status(){return this.control?this.control.status:null}get untouched(){return this.control?this.control.untouched:null}get statusChanges(){return this.control?this.control.statusChanges:null}get valueChanges(){return this.control?this.control.valueChanges:null}get path(){return null}_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators=[];_rawAsyncValidators=[];_setValidators(t){this._rawValidators=t||[],this._composedValidatorFn=Tf(this._rawValidators)}_setAsyncValidators(t){this._rawAsyncValidators=t||[],this._composedAsyncValidatorFn=Af(this._rawAsyncValidators)}get validator(){return this._composedValidatorFn||null}get asyncValidator(){return this._composedAsyncValidatorFn||null}_onDestroyCallbacks=[];_registerOnDestroy(t){this._onDestroyCallbacks.push(t)}_invokeOnDestroyCallbacks(){this._onDestroyCallbacks.forEach(t=>t()),this._onDestroyCallbacks=[]}reset(t=void 0){this.control?.reset(t)}hasError(t,n){return this.control?this.control.hasError(t,n):!1}getError(t,n){return this.control?this.control.getError(t,n):null}},Co=class extends Fc{name;get formDirective(){return null}get path(){return null}},Qi=class extends Fc{_parent=null;name=null;valueAccessor=null},Lc=class{_cd;constructor(t){this._cd=t}get isTouched(){return this._cd?.control?._touched?.(),!!this._cd?.control?.touched}get isUntouched(){return!!this._cd?.control?.untouched}get isPristine(){return this._cd?.control?._pristine?.(),!!this._cd?.control?.pristine}get isDirty(){return!!this._cd?.control?.dirty}get isValid(){return this._cd?.control?._status?.(),!!this._cd?.control?.valid}get isInvalid(){return!!this._cd?.control?.invalid}get isPending(){return!!this._cd?.control?.pending}get isSubmitted(){return this._cd?._submitted?.(),!!this._cd?.submitted}};var Hc=(()=>{class e extends Lc{constructor(n){super(n)}static \u0275fac=function(r){return new(r||e)(B(Qi,2))};static \u0275dir=Pe({type:e,selectors:[["","formControlName",""],["","ngModel",""],["","formControl",""]],hostVars:14,hostBindings:function(r,o){r&2&&Ye("ng-untouched",o.isUntouched)("ng-touched",o.isTouched)("ng-pristine",o.isPristine)("ng-dirty",o.isDirty)("ng-valid",o.isValid)("ng-invalid",o.isInvalid)("ng-pending",o.isPending)},standalone:!1,features:[Xt]})}return e})(),Fv=(()=>{class e extends Lc{constructor(n){super(n)}static \u0275fac=function(r){return new(r||e)(B(Co,10))};static \u0275dir=Pe({type:e,selectors:[["","formGroupName",""],["","formArrayName",""],["","ngModelGroup",""],["","formGroup",""],["","formArray",""],["form",3,"ngNoForm",""],["","ngForm",""]],hostVars:16,hostBindings:function(r,o){r&2&&Ye("ng-untouched",o.isUntouched)("ng-touched",o.isTouched)("ng-pristine",o.isPristine)("ng-dirty",o.isDirty)("ng-valid",o.isValid)("ng-invalid",o.isInvalid)("ng-pending",o.isPending)("ng-submitted",o.isSubmitted)},standalone:!1,features:[Xt]})}return e})();var Wi="VALID",Pc="INVALID",vo="PENDING",qi="DISABLED",Pn=class{},jc=class extends Pn{value;source;constructor(t,n){super(),this.value=t,this.source=n}},Yi=class extends Pn{pristine;source;constructor(t,n){super(),this.pristine=t,this.source=n}},Ki=class extends Pn{touched;source;constructor(t,n){super(),this.touched=t,this.source=n}},Do=class extends Pn{status;source;constructor(t,n){super(),this.status=t,this.source=n}},Mf=class extends Pn{source;constructor(t){super(),this.source=t}},Vc=class extends Pn{source;constructor(t){super(),this.source=t}};function Lv(e){return($c(e)?e.validators:e)||null}function ES(e){return Array.isArray(e)?Tf(e):e||null}function jv(e,t){return($c(t)?t.asyncValidators:e)||null}function _S(e){return Array.isArray(e)?Af(e):e||null}function $c(e){return e!=null&&!Array.isArray(e)&&typeof e=="object"}function bS(e,t,n){let r=e.controls;if(!(t?Object.keys(r):r).length)throw new E(1e3,"");if(!r[n])throw new E(1001,"")}function wS(e,t,n){e._forEachChild((r,o)=>{if(n[o]===void 0)throw new E(1002,"")})}var Bc=class{_pendingDirty=!1;_hasOwnPendingAsyncValidator=null;_pendingTouched=!1;_onCollectionChange=()=>{};_updateOn;_parent=null;_asyncValidationSubscription;_composedValidatorFn;_composedAsyncValidatorFn;_rawValidators;_rawAsyncValidators;value;constructor(t,n){this._assignValidators(t),this._assignAsyncValidators(n)}get validator(){return this._composedValidatorFn}set validator(t){this._rawValidators=this._composedValidatorFn=t}get asyncValidator(){return this._composedAsyncValidatorFn}set asyncValidator(t){this._rawAsyncValidators=this._composedAsyncValidatorFn=t}get parent(){return this._parent}get status(){return q(this.statusReactive)}set status(t){q(()=>this.statusReactive.set(t))}_status=Se(()=>this.statusReactive());statusReactive=L(void 0);get valid(){return this.status===Wi}get invalid(){return this.status===Pc}get pending(){return this.status==vo}get disabled(){return this.status===qi}get enabled(){return this.status!==qi}errors;get pristine(){return q(this.pristineReactive)}set pristine(t){q(()=>this.pristineReactive.set(t))}_pristine=Se(()=>this.pristineReactive());pristineReactive=L(!0);get dirty(){return!this.pristine}get touched(){return q(this.touchedReactive)}set touched(t){q(()=>this.touchedReactive.set(t))}_touched=Se(()=>this.touchedReactive());touchedReactive=L(!1);get untouched(){return!this.touched}_events=new me;events=this._events.asObservable();valueChanges;statusChanges;get updateOn(){return this._updateOn?this._updateOn:this.parent?this.parent.updateOn:"change"}setValidators(t){this._assignValidators(t)}setAsyncValidators(t){this._assignAsyncValidators(t)}addValidators(t){this.setValidators(Ev(t,this._rawValidators))}addAsyncValidators(t){this.setAsyncValidators(Ev(t,this._rawAsyncValidators))}removeValidators(t){this.setValidators(_v(t,this._rawValidators))}removeAsyncValidators(t){this.setAsyncValidators(_v(t,this._rawAsyncValidators))}hasValidator(t){return kc(this._rawValidators,t)}hasAsyncValidator(t){return kc(this._rawAsyncValidators,t)}clearValidators(){this.validator=null}clearAsyncValidators(){this.asyncValidator=null}markAsTouched(t={}){let n=this.touched===!1;this.touched=!0;let r=t.sourceControl??this;t.onlySelf||this._parent?.markAsTouched(A(y({},t),{sourceControl:r})),n&&t.emitEvent!==!1&&this._events.next(new Ki(!0,r))}markAllAsDirty(t={}){this.markAsDirty({onlySelf:!0,emitEvent:t.emitEvent,sourceControl:this}),this._forEachChild(n=>n.markAllAsDirty(t))}markAllAsTouched(t={}){this.markAsTouched({onlySelf:!0,emitEvent:t.emitEvent,sourceControl:this}),this._forEachChild(n=>n.markAllAsTouched(t))}markAsUntouched(t={}){let n=this.touched===!0;this.touched=!1,this._pendingTouched=!1;let r=t.sourceControl??this;this._forEachChild(o=>{o.markAsUntouched({onlySelf:!0,emitEvent:t.emitEvent,sourceControl:r})}),t.onlySelf||this._parent?._updateTouched(t,r),n&&t.emitEvent!==!1&&this._events.next(new Ki(!1,r))}markAsDirty(t={}){let n=this.pristine===!0;this.pristine=!1;let r=t.sourceControl??this;t.onlySelf||this._parent?.markAsDirty(A(y({},t),{sourceControl:r})),n&&t.emitEvent!==!1&&this._events.next(new Yi(!1,r))}markAsPristine(t={}){let n=this.pristine===!1;this.pristine=!0,this._pendingDirty=!1;let r=t.sourceControl??this;this._forEachChild(o=>{o.markAsPristine({onlySelf:!0,emitEvent:t.emitEvent})}),t.onlySelf||this._parent?._updatePristine(t,r),n&&t.emitEvent!==!1&&this._events.next(new Yi(!0,r))}markAsPending(t={}){this.status=vo;let n=t.sourceControl??this;t.emitEvent!==!1&&(this._events.next(new Do(this.status,n)),this.statusChanges.emit(this.status)),t.onlySelf||this._parent?.markAsPending(A(y({},t),{sourceControl:n}))}disable(t={}){let n=this._parentMarkedDirty(t.onlySelf);this.status=qi,this.errors=null,this._forEachChild(o=>{o.disable(A(y({},t),{onlySelf:!0}))}),this._updateValue();let r=t.sourceControl??this;t.emitEvent!==!1&&(this._events.next(new jc(this.value,r)),this._events.next(new Do(this.status,r)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),this._updateAncestors(A(y({},t),{skipPristineCheck:n}),this),this._onDisabledChange.forEach(o=>o(!0))}enable(t={}){let n=this._parentMarkedDirty(t.onlySelf);this.status=Wi,this._forEachChild(r=>{r.enable(A(y({},t),{onlySelf:!0}))}),this.updateValueAndValidity({onlySelf:!0,emitEvent:t.emitEvent}),this._updateAncestors(A(y({},t),{skipPristineCheck:n}),this),this._onDisabledChange.forEach(r=>r(!1))}_updateAncestors(t,n){t.onlySelf||(this._parent?.updateValueAndValidity(t),t.skipPristineCheck||this._parent?._updatePristine({},n),this._parent?._updateTouched({},n))}setParent(t){this._parent=t}getRawValue(){return this.value}updateValueAndValidity(t={}){if(this._setInitialStatus(),this._updateValue(),this.enabled){let r=this._cancelExistingSubscription();this.errors=this._runValidator(),this.status=this._calculateStatus(),(this.status===Wi||this.status===vo)&&this._runAsyncValidator(r,t.emitEvent)}let n=t.sourceControl??this;t.emitEvent!==!1&&(this._events.next(new jc(this.value,n)),this._events.next(new Do(this.status,n)),this.valueChanges.emit(this.value),this.statusChanges.emit(this.status)),t.onlySelf||this._parent?.updateValueAndValidity(A(y({},t),{sourceControl:n}))}_updateTreeValidity(t={emitEvent:!0}){this._forEachChild(n=>n._updateTreeValidity(t)),this.updateValueAndValidity({onlySelf:!0,emitEvent:t.emitEvent})}_setInitialStatus(){this.status=this._allControlsDisabled()?qi:Wi}_runValidator(){return this.validator?this.validator(this):null}_runAsyncValidator(t,n){if(this.asyncValidator){this.status=vo,this._hasOwnPendingAsyncValidator={emitEvent:n!==!1,shouldHaveEmitted:t!==!1};let r=Rv(this.asyncValidator(this));this._asyncValidationSubscription=r.subscribe(o=>{this._hasOwnPendingAsyncValidator=null,this.setErrors(o,{emitEvent:n,shouldHaveEmitted:t})})}}_cancelExistingSubscription(){if(this._asyncValidationSubscription){this._asyncValidationSubscription.unsubscribe();let t=(this._hasOwnPendingAsyncValidator?.emitEvent||this._hasOwnPendingAsyncValidator?.shouldHaveEmitted)??!1;return this._hasOwnPendingAsyncValidator=null,t}return!1}setErrors(t,n={}){this.errors=t,this._updateControlsErrors(n.emitEvent!==!1,this,n.shouldHaveEmitted)}get(t){let n=t;return n==null||(Array.isArray(n)||(n=n.split(".")),n.length===0)?null:n.reduce((r,o)=>r&&r._find(o),this)}getError(t,n){let r=n?this.get(n):this;return r?.errors?r.errors[t]:null}hasError(t,n){return!!this.getError(t,n)}get root(){let t=this;for(;t._parent;)t=t._parent;return t}_updateControlsErrors(t,n,r){this.status=this._calculateStatus(),t&&this.statusChanges.emit(this.status),(t||r)&&this._events.next(new Do(this.status,n)),this._parent&&this._parent._updateControlsErrors(t,n,r)}_initObservables(){this.valueChanges=new he,this.statusChanges=new he}_calculateStatus(){return this._allControlsDisabled()?qi:this.errors?Pc:this._hasOwnPendingAsyncValidator||this._anyControlsHaveStatus(vo)?vo:this._anyControlsHaveStatus(Pc)?Pc:Wi}_anyControlsHaveStatus(t){return this._anyControls(n=>n.status===t)}_anyControlsDirty(){return this._anyControls(t=>t.dirty)}_anyControlsTouched(){return this._anyControls(t=>t.touched)}_updatePristine(t,n){let r=!this._anyControlsDirty(),o=this.pristine!==r;this.pristine=r,t.onlySelf||this._parent?._updatePristine(t,n),o&&this._events.next(new Yi(this.pristine,n))}_updateTouched(t={},n){this.touched=this._anyControlsTouched(),this._events.next(new Ki(this.touched,n)),t.onlySelf||this._parent?._updateTouched(t,n)}_onDisabledChange=[];_registerOnCollectionChange(t){this._onCollectionChange=t}_setUpdateStrategy(t){$c(t)&&t.updateOn!=null&&(this._updateOn=t.updateOn)}_parentMarkedDirty(t){return!t&&!!this._parent?.dirty&&!this._parent._anyControlsDirty()}_find(t){return null}_assignValidators(t){this._rawValidators=Array.isArray(t)?t.slice():t,this._composedValidatorFn=ES(this._rawValidators)}_assignAsyncValidators(t){this._rawAsyncValidators=Array.isArray(t)?t.slice():t,this._composedAsyncValidatorFn=_S(this._rawAsyncValidators)}},Uc=class extends Bc{constructor(t,n,r){super(Lv(n),jv(r,n)),this.controls=t,this._initObservables(),this._setUpdateStrategy(n),this._setUpControls(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator})}controls;registerControl(t,n){return this.controls[t]?this.controls[t]:(this.controls[t]=n,n.setParent(this),n._registerOnCollectionChange(this._onCollectionChange),n)}addControl(t,n,r={}){this.registerControl(t,n),this.updateValueAndValidity({emitEvent:r.emitEvent}),this._onCollectionChange()}removeControl(t,n={}){this.controls[t]&&this.controls[t]._registerOnCollectionChange(()=>{}),delete this.controls[t],this.updateValueAndValidity({emitEvent:n.emitEvent}),this._onCollectionChange()}setControl(t,n,r={}){this.controls[t]&&this.controls[t]._registerOnCollectionChange(()=>{}),delete this.controls[t],n&&this.registerControl(t,n),this.updateValueAndValidity({emitEvent:r.emitEvent}),this._onCollectionChange()}contains(t){return this.controls.hasOwnProperty(t)&&this.controls[t].enabled}setValue(t,n={}){wS(this,!0,t),Object.keys(t).forEach(r=>{bS(this,!0,r),this.controls[r].setValue(t[r],{onlySelf:!0,emitEvent:n.emitEvent})}),this.updateValueAndValidity(n)}patchValue(t,n={}){t!=null&&(Object.keys(t).forEach(r=>{let o=this.controls[r];o&&o.patchValue(t[r],{onlySelf:!0,emitEvent:n.emitEvent})}),this.updateValueAndValidity(n))}reset(t={},n={}){this._forEachChild((r,o)=>{r.reset(t?t[o]:null,A(y({},n),{onlySelf:!0}))}),this._updatePristine(n,this),this._updateTouched(n,this),this.updateValueAndValidity(n),n?.emitEvent!==!1&&this._events.next(new Vc(this))}getRawValue(){return this._reduceChildren({},(t,n,r)=>(t[r]=n.getRawValue(),t))}_syncPendingControls(){let t=this._reduceChildren(!1,(n,r)=>r._syncPendingControls()?!0:n);return t&&this.updateValueAndValidity({onlySelf:!0}),t}_forEachChild(t){Object.keys(this.controls).forEach(n=>{let r=this.controls[n];r&&t(r,n)})}_setUpControls(){this._forEachChild(t=>{t.setParent(this),t._registerOnCollectionChange(this._onCollectionChange)})}_updateValue(){this.value=this._reduceValue()}_anyControls(t){for(let[n,r]of Object.entries(this.controls))if(this.contains(n)&&t(r))return!0;return!1}_reduceValue(){let t={};return this._reduceChildren(t,(n,r,o)=>((r.enabled||this.disabled)&&(n[o]=r.value),n))}_reduceChildren(t,n){let r=t;return this._forEachChild((o,i)=>{r=n(r,o,i)}),r}_allControlsDisabled(){for(let t of Object.keys(this.controls))if(this.controls[t].enabled)return!1;return Object.keys(this.controls).length>0||this.disabled}_find(t){return this.controls.hasOwnProperty(t)?this.controls[t]:null}};var Nf=new I("",{factory:()=>xf}),xf="always";function IS(e,t){return[...t.path,e]}function Vv(e,t,n=xf){Bv(e,t),t.valueAccessor.writeValue(e.value),(e.disabled||n==="always")&&t.valueAccessor.setDisabledState?.(e.disabled),MS(e,t),AS(e,t),TS(e,t),SS(e,t)}function bv(e,t){e.forEach(n=>{n.registerOnValidatorChange&&n.registerOnValidatorChange(t)})}function SS(e,t){if(t.valueAccessor.setDisabledState){let n=r=>{t.valueAccessor.setDisabledState(r)};e.registerOnDisabledChange(n),t._registerOnDestroy(()=>{e._unregisterOnDisabledChange(n)})}}function Bv(e,t){let n=DS(e);t.validator!==null?e.setValidators(Cv(n,t.validator)):typeof n=="function"&&e.setValidators([n]);let r=CS(e);t.asyncValidator!==null?e.setAsyncValidators(Cv(r,t.asyncValidator)):typeof r=="function"&&e.setAsyncValidators([r]);let o=()=>e.updateValueAndValidity();bv(t._rawValidators,o),bv(t._rawAsyncValidators,o)}function MS(e,t){t.valueAccessor.registerOnChange(n=>{e._pendingValue=n,e._pendingChange=!0,e._pendingDirty=!0,e.updateOn==="change"&&Uv(e,t)})}function TS(e,t){t.valueAccessor.registerOnTouched(()=>{e._pendingTouched=!0,e.updateOn==="blur"&&e._pendingChange&&Uv(e,t),e.updateOn!=="submit"&&e.markAsTouched()})}function Uv(e,t){e._pendingDirty&&e.markAsDirty(),e.setValue(e._pendingValue,{emitModelToViewChange:!1}),t.viewToModelUpdate(e._pendingValue),e._pendingChange=!1}function AS(e,t){let n=(r,o)=>{t.valueAccessor.writeValue(r),o&&t.viewToModelUpdate(r)};e.registerOnChange(n),t._registerOnDestroy(()=>{e._unregisterOnChange(n)})}function NS(e,t){e==null,Bv(e,t)}function xS(e,t){if(!e.hasOwnProperty("model"))return!1;let n=e.model;return n.isFirstChange()?!0:!Object.is(t,n.currentValue)}function RS(e){return Object.getPrototypeOf(e.constructor)===fS}function OS(e,t){e._syncPendingControls(),t.forEach(n=>{let r=n.control;r.updateOn==="submit"&&r._pendingChange&&(n.viewToModelUpdate(r._pendingValue),r._pendingChange=!1)})}function PS(e,t){if(!t)return null;Array.isArray(t);let n,r,o;return t.forEach(i=>{i.constructor===Eo?n=i:RS(i)?r=i:o=i}),o||r||n||null}var kS={provide:Co,useExisting:Dn(()=>Rf)},Zi=Promise.resolve(),Rf=(()=>{class e extends Co{callSetDisabledState;get submitted(){return q(this.submittedReactive)}_submitted=Se(()=>this.submittedReactive());submittedReactive=L(!1);_directives=new Set;form;ngSubmit=new he;options;constructor(n,r,o){super(),this.callSetDisabledState=o,this.form=new Uc({},Tf(n),Af(r))}ngAfterViewInit(){this._setUpdateStrategy()}get formDirective(){return this}get control(){return this.form}get path(){return[]}get controls(){return this.form.controls}addControl(n){Zi.then(()=>{let r=this._findContainer(n.path);n.control=r.registerControl(n.name,n.control),Vv(n.control,n,this.callSetDisabledState),n.control.updateValueAndValidity({emitEvent:!1}),this._directives.add(n)})}getControl(n){return this.form.get(n.path)}removeControl(n){Zi.then(()=>{this._findContainer(n.path)?.removeControl(n.name),this._directives.delete(n)})}addFormGroup(n){Zi.then(()=>{let r=this._findContainer(n.path),o=new Uc({});NS(o,n),r.registerControl(n.name,o),o.updateValueAndValidity({emitEvent:!1})})}removeFormGroup(n){Zi.then(()=>{this._findContainer(n.path)?.removeControl?.(n.name)})}getFormGroup(n){return this.form.get(n.path)}updateModel(n,r){Zi.then(()=>{this.form.get(n.path).setValue(r)})}setValue(n){this.control.setValue(n)}onSubmit(n){return this.submittedReactive.set(!0),OS(this.form,this._directives),this.ngSubmit.emit(n),this.form._events.next(new Mf(this.control)),n?.target?.method==="dialog"}onReset(){this.resetForm()}resetForm(n=void 0){this.form.reset(n),this.submittedReactive.set(!1)}_setUpdateStrategy(){this.options&&this.options.updateOn!=null&&(this.form._updateOn=this.options.updateOn)}_findContainer(n){return n.pop(),n.length?this.form.get(n):this.form}static \u0275fac=function(r){return new(r||e)(B(Av,10),B(Nv,10),B(Nf,8))};static \u0275dir=Pe({type:e,selectors:[["form",3,"ngNoForm","",3,"formGroup","",3,"formArray",""],["ng-form"],["","ngForm",""]],hostBindings:function(r,o){r&1&&te("submit",function(s){return o.onSubmit(s)})("reset",function(){return o.onReset()})},inputs:{options:[0,"ngFormOptions","options"]},outputs:{ngSubmit:"ngSubmit"},exportAs:["ngForm"],standalone:!1,features:[hi([kS]),Xt]})}return e})();function wv(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}function Iv(e){return typeof e=="object"&&e!==null&&Object.keys(e).length===2&&"value"in e&&"disabled"in e}var FS=class extends Bc{defaultValue=null;_onChange=[];_pendingValue;_pendingChange=!1;constructor(t=null,n,r){super(Lv(n),jv(r,n)),this._applyFormState(t),this._setUpdateStrategy(n),this._initObservables(),this.updateValueAndValidity({onlySelf:!0,emitEvent:!!this.asyncValidator}),$c(n)&&(n.nonNullable||n.initialValueIsDefault)&&(Iv(t)?this.defaultValue=t.value:this.defaultValue=t)}setValue(t,n={}){this.value=this._pendingValue=t,this._onChange.length&&n.emitModelToViewChange!==!1&&this._onChange.forEach(r=>r(this.value,n.emitViewToModelChange!==!1)),this.updateValueAndValidity(n)}patchValue(t,n={}){this.setValue(t,n)}reset(t=this.defaultValue,n={}){this._applyFormState(t),this.markAsPristine(n),this.markAsUntouched(n),this.setValue(this.value,n),n.overwriteDefaultValue&&(this.defaultValue=this.value),this._pendingChange=!1,n?.emitEvent!==!1&&this._events.next(new Vc(this))}_updateValue(){}_anyControls(t){return!1}_allControlsDisabled(){return this.disabled}registerOnChange(t){this._onChange.push(t)}_unregisterOnChange(t){wv(this._onChange,t)}registerOnDisabledChange(t){this._onDisabledChange.push(t)}_unregisterOnDisabledChange(t){wv(this._onDisabledChange,t)}_forEachChild(t){}_syncPendingControls(){return this.updateOn==="submit"&&(this._pendingDirty&&this.markAsDirty(),this._pendingTouched&&this.markAsTouched(),this._pendingChange)?(this.setValue(this._pendingValue,{onlySelf:!0,emitModelToViewChange:!1}),!0):!1}_applyFormState(t){Iv(t)?(this.value=this._pendingValue=t.value,t.disabled?this.disable({onlySelf:!0,emitEvent:!1}):this.enable({onlySelf:!0,emitEvent:!1})):this.value=this._pendingValue=t}};var LS={provide:Qi,useExisting:Dn(()=>Ji)},Sv=Promise.resolve(),Ji=(()=>{class e extends Qi{_changeDetectorRef;callSetDisabledState;control=new FS;static ngAcceptInputType_isDisabled;_registered=!1;viewModel;name="";isDisabled;model;options;update=new he;constructor(n,r,o,i,s,a){super(),this._changeDetectorRef=s,this.callSetDisabledState=a,this._parent=n,this._setValidators(r),this._setAsyncValidators(o),this.valueAccessor=PS(this,i)}ngOnChanges(n){if(this._checkForErrors(),!this._registered||"name"in n){if(this._registered&&(this._checkName(),this.formDirective)){let r=n.name.previousValue;this.formDirective.removeControl({name:r,path:this._getPath(r)})}this._setUpControl()}"isDisabled"in n&&this._updateDisabled(n),xS(n,this.viewModel)&&(this._updateValue(this.model),this.viewModel=this.model)}ngOnDestroy(){this.formDirective?.removeControl(this)}get path(){return this._getPath(this.name)}get formDirective(){return this._parent?this._parent.formDirective:null}viewToModelUpdate(n){this.viewModel=n,this.update.emit(n)}_setUpControl(){this._setUpdateStrategy(),this._isStandalone()?this._setUpStandalone():this.formDirective.addControl(this),this._registered=!0}_setUpdateStrategy(){this.options&&this.options.updateOn!=null&&(this.control._updateOn=this.options.updateOn)}_isStandalone(){return!this._parent||!!(this.options&&this.options.standalone)}_setUpStandalone(){Vv(this.control,this,this.callSetDisabledState),this.control.updateValueAndValidity({emitEvent:!1})}_checkForErrors(){this._checkName()}_checkName(){this.options&&this.options.name&&(this.name=this.options.name),!this._isStandalone()&&this.name}_updateValue(n){Sv.then(()=>{this.control.setValue(n,{emitViewToModelChange:!1}),this._changeDetectorRef?.markForCheck()})}_updateDisabled(n){let r=n.isDisabled.currentValue,o=r!==0&&Kr(r);Sv.then(()=>{o&&!this.control.disabled?this.control.disable():!o&&this.control.disabled&&this.control.enable(),this._changeDetectorRef?.markForCheck()})}_getPath(n){return this._parent?IS(n,this._parent):[n]}static \u0275fac=function(r){return new(r||e)(B(Co,9),B(Av,10),B(Nv,10),B(Tv,10),B(Yr,8),B(Nf,8))};static \u0275dir=Pe({type:e,selectors:[["","ngModel","",3,"formControlName","",3,"formControl",""]],inputs:{name:"name",isDisabled:[0,"disabled","isDisabled"],model:[0,"ngModel","model"],options:[0,"ngModelOptions","options"]},outputs:{update:"ngModelChange"},exportAs:["ngModel"],standalone:!1,features:[hi([LS]),Xt,Mn]})}return e})();var Hv=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275dir=Pe({type:e,selectors:[["form",3,"ngNoForm","",3,"ngNativeValidate",""]],hostAttrs:["novalidate",""],standalone:!1})}return e})();var jS=(()=>{class e{static \u0275fac=function(r){return new(r||e)};static \u0275mod=kt({type:e});static \u0275inj=mt({})}return e})();var zc=(()=>{class e{static withConfig(n){return{ngModule:e,providers:[{provide:Nf,useValue:n.callSetDisabledState??xf}]}}static \u0275fac=function(r){return new(r||e)};static \u0275mod=kt({type:e});static \u0275inj=mt({imports:[jS]})}return e})();var _o=class e{constructor(t){this.http=t;this.token()&&this.currentUser()&&queueMicrotask(()=>{this.restoreSession()})}serverUrl=L(this.readStorage("privatechat.serverUrl")??"http://localhost:3000");currentUser=L(this.readUserStorage());accessKeys=L([]);peers=L([]);activePeerId=L(null);messages=L([]);status=L("Disconnected from signaling server.");error=L(null);webAuthnSupported=L(typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials?.create=="function"&&typeof navigator.credentials?.get=="function");selectedPeer=Se(()=>this.peers().find(t=>t.id===this.activePeerId())??null);conversation=Se(()=>{let t=this.activePeerId();return t?this.messages().filter(n=>n.peerId===t):[]});isSelectedPeerReady=Se(()=>this.selectedPeer()?.channelState==="open");token=L(this.readStorage("privatechat.token"));peerBundles=new Map;incomingFiles=new Map;websocket=null;async register(t,n,r){await this.authenticate("/api/auth/register",{username:t,password:n,displayName:r.trim()||void 0})}async login(t,n){await this.authenticate("/api/auth/login",{username:t,password:n})}async loginWithAccessKey(t){if(!this.webAuthnSupported()){this.error.set("This browser does not support WebAuthn access keys.");return}this.error.set(null);try{let n=await wt(this.http.post(`${this.serverUrl()}/api/webauthn/authenticate/options`,{username:t.trim()||void 0})),r=await navigator.credentials.get({publicKey:this.toPublicKeyRequestOptions(n)});if(!(r instanceof PublicKeyCredential)){this.error.set("The browser did not return a valid access key credential.");return}let o=await wt(this.http.post(`${this.serverUrl()}/api/webauthn/authenticate/verify`,{attemptId:n.attemptId,credential:this.serializeAuthenticationCredential(r)}));await this.applyAuthenticatedSession(o)}catch(n){this.error.set(this.extractErrorMessage(n,"Access key login failed or was cancelled."))}}async logout(){let t=this.token();try{t&&await wt(this.http.post(`${this.serverUrl()}/api/auth/logout`,{},{headers:{Authorization:`Bearer ${t}`}}))}catch{}finally{this.clearLocalAuth("Logged out.")}}setServerUrl(t){let n=t.trim().replace(/\/+$/,"");n&&(this.serverUrl.set(n),this.writeStorage("privatechat.serverUrl",n),this.currentUser()&&this.connectWebSocket())}selectPeer(t){this.activePeerId.set(t)}async connectToPeer(t){if(!this.websocket||this.websocket.readyState!==WebSocket.OPEN){this.error.set("You must be connected to signaling before opening a peer session.");return}let n=this.ensurePeerBundle(t,!0);if(n.channel?.readyState==="open"||n.pc.signalingState!=="stable")return;this.patchPeer(t,{connectionState:"connecting",channelState:"connecting"}),this.addSystemMessage(t,"Opening WebRTC data channel.");let r=await n.pc.createOffer();await n.pc.setLocalDescription(r),this.sendSignal(t,{type:"sdp",description:n.pc.localDescription.toJSON()})}async registerAccessKey(t){if(!this.webAuthnSupported()){this.error.set("This browser does not support WebAuthn access keys.");return}let n=this.token();if(!n){this.error.set("Sign in before registering an access key.");return}this.error.set(null);try{let r=await wt(this.http.post(`${this.serverUrl()}/api/webauthn/register/options`,{label:t.trim()||void 0},{headers:{Authorization:`Bearer ${n}`}})),o=await navigator.credentials.create({publicKey:this.toPublicKeyCreationOptions(r)});if(!(o instanceof PublicKeyCredential)){this.error.set("The browser did not return a valid access key credential.");return}await wt(this.http.post(`${this.serverUrl()}/api/webauthn/register/verify`,{credential:this.serializeRegistrationCredential(o)},{headers:{Authorization:`Bearer ${n}`}})),await this.loadAccessKeys(),this.status.set("Access key registered.")}catch(r){this.error.set(this.extractErrorMessage(r,"Access key registration failed or was cancelled."))}}async sendText(t,n){let r=n.trim();if(!r)return;let o=this.requireOpenChannel(t);if(!o)return;let i={type:"text",id:crypto.randomUUID(),body:r,authorId:this.currentUser().id,authorName:this.currentUser().displayName,sentAt:Date.now()};o.send(JSON.stringify(i)),this.pushMessage({id:i.id,peerId:t,direction:"outgoing",kind:"text",createdAt:i.sentAt,authorLabel:"You",text:r})}async sendJson(t,n){if(!n.trim())return;let r=this.requireOpenChannel(t);if(!r)return;let o;try{o=JSON.parse(n)}catch{this.error.set("JSON payload is not valid.");return}let i={type:"json",id:crypto.randomUUID(),body:o,authorId:this.currentUser().id,authorName:this.currentUser().displayName,sentAt:Date.now()};r.send(JSON.stringify(i)),this.pushMessage({id:i.id,peerId:t,direction:"outgoing",kind:"json",createdAt:i.sentAt,authorLabel:"You",payload:o})}async sendFile(t,n){let r=this.requireOpenChannel(t);if(!r)return;let o=crypto.randomUUID(),i=Date.now(),s=await n.arrayBuffer(),a=16*1024;r.send(JSON.stringify({type:"file-meta",id:o,name:n.name,mimeType:n.type||"application/octet-stream",size:n.size,authorId:this.currentUser().id,authorName:this.currentUser().displayName,sentAt:i}));for(let c=0;c{this.status.set("Connected to signaling server.")},n.onmessage=r=>{let o=JSON.parse(r.data);this.handleServerEvent(o)},n.onerror=()=>{this.error.set("The signaling socket encountered an error.")},n.onclose=()=>{this.status.set("Signaling connection closed."),this.websocket=null,this.peers.update(r=>r.map(o=>A(y({},o),{connectionState:"disconnected",channelState:"closed"})))}}disconnectWebSocket(){this.websocket&&(this.websocket.close(),this.websocket=null)}async handleServerEvent(t){switch(t.type){case"presence":this.mergePresence(t.peers);break;case"peer-joined":this.mergePresence([...this.peers().map(n=>n),A(y({},t.peer),{connectionState:"disconnected",channelState:"closed"})]);break;case"peer-left":this.releasePeerBundle(t.peerId,!1),this.peers.update(n=>n.filter(r=>r.id!==t.peerId)),this.activePeerId()===t.peerId&&this.activePeerId.set(this.peers()[0]?.id??null),this.addSystemMessage(t.peerId,"Peer disconnected from signaling.");break;case"signal":await this.handleSignal(t.from,t.signal);break;case"error":this.error.set(t.message),/auth|session/i.test(t.message)&&this.clearLocalAuth("Session expired. Sign in again.");break}}async restoreSession(){let t=this.token();if(t){this.status.set("Restoring saved session."),this.error.set(null);try{let n=await wt(this.http.get(`${this.serverUrl()}/api/auth/session`,{headers:{Authorization:`Bearer ${t}`}}));this.currentUser.set(n.user),this.writeStorage("privatechat.user",JSON.stringify(n.user)),await this.loadAccessKeys(),await this.connectWebSocket()}catch{this.clearLocalAuth("Saved session expired. Sign in again.")}}}mergePresence(t){let n=new Map(this.peers().map(o=>[o.id,o])),r=t.map(o=>{let i=n.get(o.id);return{id:o.id,username:o.username,displayName:o.displayName,connectionState:i?.connectionState??"disconnected",channelState:i?.channelState??"closed"}}).filter((o,i,s)=>s.findIndex(a=>a.id===o.id)===i).sort((o,i)=>o.displayName.localeCompare(i.displayName));this.peers.set(r),!this.activePeerId()&&r.length>0&&this.activePeerId.set(r[0].id)}async handleSignal(t,n){if(n.type==="ice-candidate"){let i=this.ensurePeerBundle(t,!1);i.pc.remoteDescription?await i.pc.addIceCandidate(n.candidate):i.pendingCandidates.push(n.candidate);return}let r=this.ensurePeerBundle(t,!1),o=n.description;if(o.type==="offer"){let i=r.pc.signalingState!=="stable",s=this.isPolitePeer(t);if(i){if(!s)return;await r.pc.setLocalDescription({type:"rollback"})}await r.pc.setRemoteDescription(o),await this.flushPendingCandidates(r);let a=await r.pc.createAnswer();await r.pc.setLocalDescription(a),this.sendSignal(t,{type:"sdp",description:r.pc.localDescription.toJSON()});return}await r.pc.setRemoteDescription(o),await this.flushPendingCandidates(r)}ensurePeerBundle(t,n){let r=this.peerBundles.get(t);if(r&&r.pc.connectionState!=="closed"&&r.pc.connectionState!=="failed"){if(n&&!r.channel){let i=r.pc.createDataChannel("privatechat");this.attachDataChannel(t,i,r)}return r}this.releasePeerBundle(t,!1);let o={pc:new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]}),pendingCandidates:[]};if(o.pc.onicecandidate=i=>{i.candidate&&this.sendSignal(t,{type:"ice-candidate",candidate:i.candidate.toJSON()})},o.pc.onconnectionstatechange=()=>{let i=this.mapConnectionState(o.pc.connectionState);this.patchPeer(t,{connectionState:i}),i==="connected"&&this.addSystemMessage(t,"Peer connection established."),(o.pc.connectionState==="closed"||o.pc.connectionState==="failed")&&this.releasePeerBundle(t,!0)},o.pc.ondatachannel=i=>{this.attachDataChannel(t,i.channel,o)},n){let i=o.pc.createDataChannel("privatechat");this.attachDataChannel(t,i,o)}return this.peerBundles.set(t,o),this.patchPeer(t,{connectionState:"connecting"}),o}attachDataChannel(t,n,r){n.binaryType="arraybuffer",r.channel=n,this.patchPeer(t,{channelState:n.readyState==="open"?"open":"connecting"}),n.onopen=()=>{this.patchPeer(t,{connectionState:"connected",channelState:"open"}),this.addSystemMessage(t,"Secure data channel is open.")},n.onclose=()=>{this.patchPeer(t,{channelState:"closed"})},n.onerror=()=>{this.patchPeer(t,{channelState:"closed",connectionState:"failed"}),this.error.set("A peer data channel failed.")},n.onmessage=o=>{if(typeof o.data=="string"){this.handleChannelEnvelope(t,JSON.parse(o.data));return}this.handleBinaryChunk(t,o.data)}}handleChannelEnvelope(t,n){switch(n.type){case"text":this.pushMessage({id:n.id,peerId:t,direction:"incoming",kind:"text",createdAt:n.sentAt,authorLabel:n.authorName,text:n.body});break;case"json":this.pushMessage({id:n.id,peerId:t,direction:"incoming",kind:"json",createdAt:n.sentAt,authorLabel:n.authorName,payload:n.body});break;case"file-meta":this.incomingFiles.set(t,{id:n.id,name:n.name,mimeType:n.mimeType,size:n.size,sentAt:n.sentAt,authorName:n.authorName,chunks:[],receivedBytes:0}),this.addSystemMessage(t,`Receiving file ${n.name}.`);break;case"file-complete":this.finalizeIncomingFile(t,n.id);break}}async handleBinaryChunk(t,n){let r=this.incomingFiles.get(t);if(!r)return;let o=n instanceof Blob?await n.arrayBuffer():n;r.chunks.push(o),r.receivedBytes+=o.byteLength}finalizeIncomingFile(t,n){let r=this.incomingFiles.get(t);if(!r||r.id!==n)return;let o=new Blob(r.chunks,{type:r.mimeType}),i=URL.createObjectURL(o);this.pushMessage({id:r.id,peerId:t,direction:"incoming",kind:"file",createdAt:r.sentAt,authorLabel:r.authorName,fileName:r.name,fileSize:r.size,downloadUrl:i}),this.incomingFiles.delete(t)}async flushPendingCandidates(t){for(;t.pendingCandidates.length>0;){let n=t.pendingCandidates.shift();n&&await t.pc.addIceCandidate(n)}}sendSignal(t,n){!this.websocket||this.websocket.readyState!==WebSocket.OPEN||this.websocket.send(JSON.stringify({type:"signal",to:t,signal:n}))}requireOpenChannel(t){let n=this.peerBundles.get(t)?.channel;return!n||n.readyState!=="open"?(this.error.set("Open a peer connection before sending data."),null):n}async waitForBufferedAmount(t,n){for(;t.bufferedAmount>n;)await new Promise(r=>window.setTimeout(r,25))}releasePeerBundle(t,n){let r=this.peerBundles.get(t);r&&(r.channel?.close(),r.pc.close(),this.peerBundles.delete(t),this.incomingFiles.delete(t),n&&this.patchPeer(t,{connectionState:"disconnected",channelState:"closed"}))}resetPeerConnections(){for(let t of this.peerBundles.keys())this.releasePeerBundle(t,!0)}patchPeer(t,n){this.peers.update(r=>r.map(o=>o.id===t?y(y({},o),n):o))}pushMessage(t){this.messages.update(n=>[...n,t].sort((r,o)=>r.createdAt-o.createdAt))}addSystemMessage(t,n){this.pushMessage({id:crypto.randomUUID(),peerId:t,direction:"system",kind:"system",createdAt:Date.now(),authorLabel:"System",text:n})}isPolitePeer(t){return(this.currentUser()?.id??"")>t}mapConnectionState(t){switch(t){case"connected":return"connected";case"connecting":case"new":return"connecting";case"failed":return"failed";default:return"disconnected"}}clearLocalAuth(t){this.disconnectWebSocket(),this.resetPeerConnections(),this.currentUser.set(null),this.token.set(null),this.peers.set([]),this.accessKeys.set([]),this.activePeerId.set(null),this.messages.set([]),this.error.set(null),this.status.set(t),this.removeStorage("privatechat.token"),this.removeStorage("privatechat.user")}toWebSocketUrl(t,n){let r=new URL(t);return r.protocol=r.protocol==="https:"?"wss:":"ws:",r.pathname="/ws",r.search=`token=${encodeURIComponent(n)}`,r.toString()}toPublicKeyCreationOptions(t){return A(y({},t),{challenge:this.base64UrlToBuffer(t.challenge),user:A(y({},t.user),{id:this.base64UrlToBuffer(t.user.id)}),excludeCredentials:t.excludeCredentials?.map(n=>A(y({},n),{id:this.base64UrlToBuffer(n.id),transports:n.transports}))})}toPublicKeyRequestOptions(t){return{challenge:this.base64UrlToBuffer(t.challenge),timeout:t.timeout,rpId:t.rpId,userVerification:t.userVerification,allowCredentials:t.allowCredentials?.map(n=>A(y({},n),{id:this.base64UrlToBuffer(n.id),transports:n.transports})),extensions:t.extensions}}serializeRegistrationCredential(t){let n=t.response;return{id:t.id,rawId:this.bufferToBase64Url(t.rawId),response:{clientDataJSON:this.bufferToBase64Url(n.clientDataJSON),attestationObject:this.bufferToBase64Url(n.attestationObject),transports:n.getTransports?.()},clientExtensionResults:t.getClientExtensionResults(),type:t.type,authenticatorAttachment:t.authenticatorAttachment??void 0}}serializeAuthenticationCredential(t){let n=t.response;return{id:t.id,rawId:this.bufferToBase64Url(t.rawId),response:{clientDataJSON:this.bufferToBase64Url(n.clientDataJSON),authenticatorData:this.bufferToBase64Url(n.authenticatorData),signature:this.bufferToBase64Url(n.signature),userHandle:n.userHandle?this.bufferToBase64Url(n.userHandle):void 0},clientExtensionResults:t.getClientExtensionResults(),type:t.type,authenticatorAttachment:t.authenticatorAttachment??void 0}}base64UrlToBuffer(t){let n="=".repeat((4-t.length%4)%4),r=(t+n).replace(/-/g,"+").replace(/_/g,"/"),o=atob(r),i=new Uint8Array(o.length);for(let s=0;st.id;function BS(e,t){if(e&1&&(m(0,"h1",12),D(1),g(),m(2,"p",13),D(3),g()),e&2){let n=t;C(),X(n.displayName),C(2),mr(" Text chat. Connection: ",n.connectionState,". Channel: ",n.channelState,". ")}}function US(e,t){e&1&&(m(0,"h1",12),D(1,"Peer not available"),g(),m(2,"p",13),D(3,"Return to the dashboard and select another peer."),g())}function HS(e,t){if(e&1){let n=at();m(0,"button",14),te("click",function(){Q(n);let o=R();return J(o.ensureConnection())}),D(1),g()}if(e&2){let n=t;ke("disabled",n.channelState==="open"),C(),ct(" ",n.channelState==="open"?"Connected":"Open channel"," ")}}function $S(e,t){e&1&&(m(0,"div",7),D(1," No text messages yet. The chat page is ready as soon as the peer channel opens. "),g())}function zS(e,t){if(e&1&&(m(0,"article",15)(1,"div",16)(2,"span"),D(3),g(),m(4,"time"),D(5),yr(6,"date"),g()(),m(7,"p",17),D(8),g()()),e&2){let n=t.$implicit;Ye("bubble-incoming",n.direction==="incoming")("bubble-outgoing",n.direction==="outgoing")("bubble-system",n.direction==="system"),C(3),X(n.authorLabel),C(2),X(Zr(6,9,n.createdAt,"shortTime")),C(3),X(n.text)}}var Gc=class e{constructor(t){this.session=t;let n=this.peerId();n&&(this.session.selectPeer(n),this.session.connectToPeer(n)),this.session.currentUser()||this.router.navigateByUrl("/")}route=p(_t);router=p(Ut);messageText="";peerId=Se(()=>this.route.snapshot.paramMap.get("peerId")??"");peer=Se(()=>this.session.peers().find(t=>t.id===this.peerId())??null);textConversation=Se(()=>this.session.messages().filter(t=>t.peerId===this.peerId()&&(t.kind==="text"||t.kind==="system")));async ensureConnection(){let t=this.peerId();t&&(this.session.selectPeer(t),await this.session.connectToPeer(t))}async sendMessage(){let t=this.peerId();t&&(await this.session.sendText(t,this.messageText),this.messageText="")}static \u0275fac=function(n){return new(n||e)(B(_o))};static \u0275cmp=Jt({type:e,selectors:[["app-chat-page"]],decls:18,vars:6,consts:[[1,"chat-shell","py-4"],[1,"container-lg"],[1,"chat-page","panel","p-3","p-lg-4"],[1,"chat-header","d-flex","flex-column","flex-lg-row","justify-content-between","align-items-start","align-items-lg-center","gap-3","mb-4"],["routerLink","/",1,"back-link"],["type","button",1,"btn","btn-outline-light",3,"disabled"],[1,"conversation"],[1,"empty-chat"],[1,"bubble",3,"bubble-incoming","bubble-outgoing","bubble-system"],[1,"composer"],["rows","3","placeholder","Write a text message to your peer",1,"form-control","composer-textarea",3,"ngModelChange","ngModel","disabled"],["type","button","title","Send message","aria-label","Send message",1,"send-emoji",3,"click","disabled"],[1,"h3","mb-1","mt-2"],[1,"small","text-secondary","mb-0"],["type","button",1,"btn","btn-outline-light",3,"click","disabled"],[1,"bubble"],[1,"bubble-meta"],[1,"mb-0"]],template:function(n,r){if(n&1&&(m(0,"main",0)(1,"div",1)(2,"section",2)(3,"div",3)(4,"div")(5,"a",4),D(6,"\u2190 Back to dashboard"),g(),oe(7,BS,4,3)(8,US,4,0),g(),oe(9,HS,2,2,"button",5),g(),m(10,"div",6),oe(11,$S,2,0,"div",7),pr(12,zS,9,12,"article",8,VS),g(),m(14,"div",9)(15,"textarea",10),Qe("ngModelChange",function(i){return lt(r.messageText,i)||(r.messageText=i),i}),g(),m(16,"button",11),te("click",function(){return r.sendMessage()}),D(17," \u2705 "),g()()()()()),n&2){let o,i;C(7),ie((o=r.peer())?7:8,o),C(2),ie((i=r.peer())?9:-1,i),C(2),ie(r.textConversation().length===0?11:-1),C(),gr(r.textConversation()),C(3),Ke("ngModel",r.messageText),ke("disabled",!r.session.isSelectedPeerReady()),C(),ke("disabled",!r.session.isSelectedPeerReady())}},dependencies:[eo,zc,Eo,Hc,Ji,yo,Ei],styles:["[_nghost-%COMP%]{display:block;min-height:100dvh;color:#eff3ff}.chat-shell[_ngcontent-%COMP%]{min-height:100dvh}.panel[_ngcontent-%COMP%]{border:1px solid rgba(255,255,255,.12);border-radius:1.75rem;background:#09101ccc;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);box-shadow:0 20px 60px #00000047}.back-link[_ngcontent-%COMP%]{color:#9bd5ff;text-decoration:none}.conversation[_ngcontent-%COMP%]{display:grid;gap:.85rem;min-height:24rem;max-height:calc(100dvh - 22rem);overflow:auto;padding:.5rem 0}.bubble[_ngcontent-%COMP%]{max-width:min(75%,34rem);padding:.9rem 1rem;border-radius:1.2rem;box-shadow:0 12px 30px #00000024}.bubble-incoming[_ngcontent-%COMP%]{justify-self:start;color:#0f2540;background:#dcefff}.bubble-outgoing[_ngcontent-%COMP%]{justify-self:end;color:#153420;background:#def7dd}.bubble-system[_ngcontent-%COMP%]{justify-self:center;max-width:90%;color:#eff3ffd6;background:#ffffff14}.bubble-meta[_ngcontent-%COMP%]{display:flex;justify-content:space-between;gap:1rem;margin-bottom:.35rem;font-size:.78rem;opacity:.7}.composer[_ngcontent-%COMP%]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.9rem;align-items:end;padding-top:1rem;margin-top:1rem;border-top:1px solid rgba(255,255,255,.08)}.composer-textarea[_ngcontent-%COMP%], .composer-textarea[_ngcontent-%COMP%]:focus{color:#eff3ff;background-color:#ffffff0f;border-color:#ffffff29;box-shadow:none}.composer-textarea[_ngcontent-%COMP%]::placeholder{color:#eff3ff80}.send-emoji[_ngcontent-%COMP%]{width:3.25rem;height:3.25rem;border:0;border-radius:999px;font-size:1.35rem;background:linear-gradient(135deg,#def7dd,#9bd5ff)}.empty-chat[_ngcontent-%COMP%]{padding:1.25rem;border:1px dashed rgba(255,255,255,.16);border-radius:1rem;color:#e7eef9b8;text-align:center}.h3[_ngcontent-%COMP%], .small[_ngcontent-%COMP%]{color:#eff3ff}@media(max-width:767.98px){.bubble[_ngcontent-%COMP%]{max-width:88%}}"]})};var GS=e=>["/chat",e],Of=(e,t)=>t.id;function WS(e,t){if(e&1){let n=at();m(0,"div",10)(1,"div",11),D(2,"Signed in"),g(),m(3,"div",12),D(4),g(),m(5,"div",13),D(6),g(),m(7,"div",14),D(8),g(),m(9,"button",15),te("click",function(){Q(n);let o=R(2);return J(o.logout())}),D(10,"Log out"),g()()}if(e&2){let n=t,r=R(2);C(4),X(n.displayName),C(2),X(n.username),C(2),X(r.session.status())}}function qS(e,t){if(e&1&&(m(0,"section",3)(1,"div",5)(2,"div",6)(3,"span",7),D(4,"WebRTC Private Chat"),g(),m(5,"h1",8),D(6,"Authenticated peer messaging without routing chat payloads through the server."),g(),m(7,"p",9),D(8," Fastify handles identity and signaling. After discovery, peers exchange text, JSON, and files over a direct WebRTC data channel. "),g()(),oe(9,WS,11,3,"div",10),g()()),e&2){let n,r=R();C(9),ie((n=r.session.currentUser())?9:-1,n)}}function ZS(e,t){e&1&&(m(0,"section",16)(1,"h2",18),D(2,"Open Settings to sign in"),g(),m(3,"p",19),D(4," This embedded client expects authentication and backend configuration from the native app settings. "),g()())}function YS(e,t){if(e&1){let n=at();m(0,"div")(1,"label",41),D(2,"Display name"),g(),m(3,"input",42),Qe("ngModelChange",function(o){Q(n);let i=R(3);return lt(i.displayName,o)||(i.displayName=o),J(o)}),g()()}if(e&2){let n=R(3);C(3),Ke("ngModel",n.displayName)}}function KS(e,t){if(e&1){let n=at();m(0,"div",43),D(1,"or"),g(),m(2,"button",44),te("click",function(){Q(n);let o=R(3);return J(o.loginWithAccessKey())}),D(3," \u{1F511} Use access key "),g(),m(4,"div",45),D(5," Leave the username blank to choose from discoverable passkeys, or enter it to target one account. "),g()}}function QS(e,t){if(e&1&&(m(0,"div",36),D(1),g()),e&2){let n=R(3);C(),X(n.session.error())}}function JS(e,t){if(e&1){let n=at();m(0,"section",17)(1,"div",20)(2,"div",21)(3,"div",22)(4,"div")(5,"h2",23),D(6,"Connect to the signaling backend"),g(),m(7,"p",19),D(8,"Use the Fastify server for authentication and peer discovery."),g()(),m(9,"span",24),D(10,"Angular + Bootstrap"),g()(),m(11,"div",25)(12,"label",26),D(13,"Backend URL"),g(),m(14,"input",27),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.serverUrl,o)||(i.serverUrl=o),J(o)}),g()(),m(15,"div",28)(16,"button",29),te("click",function(){Q(n);let o=R(2);return J(o.authMode="login")}),D(17," Log in "),g(),m(18,"button",29),te("click",function(){Q(n);let o=R(2);return J(o.authMode="register")}),D(19," Register "),g()(),m(20,"form",30),te("ngSubmit",function(){Q(n);let o=R(2);return J(o.submitAuth())}),oe(21,YS,4,1,"div"),m(22,"div")(23,"label",31),D(24,"Username"),g(),m(25,"input",32),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.username,o)||(i.username=o),J(o)}),g()(),m(26,"div")(27,"label",33),D(28,"Password"),g(),m(29,"input",34),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.password,o)||(i.password=o),J(o)}),g()(),m(30,"button",35),D(31),g(),oe(32,KS,6,0),g(),oe(33,QS,2,1,"div",36),g()(),m(34,"div",20)(35,"div",37)(36,"h2",18),D(37,"Transport model"),g(),m(38,"div",38)(39,"article")(40,"div",39),D(41,"1. Authenticate"),g(),m(42,"p",40),D(43,"Register or log in against the Fastify API to receive a JWT."),g()(),m(44,"article")(45,"div",39),D(46,"2. Discover peers"),g(),m(47,"p",40),D(48,"Open the WebSocket signaling session and receive the online peer list."),g()(),m(49,"article")(50,"div",39),D(51,"3. Exchange data directly"),g(),m(52,"p",40),D(53,"Create a WebRTC data channel and send text, JSON, or files peer-to-peer."),g()()()()()()}if(e&2){let n=R(2);C(14),Ke("ngModel",n.serverUrl),C(2),Ye("btn-primary",n.authMode==="login")("btn-outline-primary",n.authMode!=="login"),C(2),Ye("btn-primary",n.authMode==="register")("btn-outline-primary",n.authMode!=="register"),C(3),ie(n.authMode==="register"?21:-1),C(4),Ke("ngModel",n.username),hr("autocomplete",n.authMode==="login"?"username webauthn":"username"),C(4),Ke("ngModel",n.password),C(2),ct(" ",n.authMode==="login"?"Enter chat":"Create account"," "),C(),ie(n.authMode==="login"&&n.session.webAuthnSupported()?32:-1),C(),ie(n.session.error()?33:-1)}}function XS(e,t){if(e&1&&oe(0,ZS,5,0,"section",16)(1,JS,54,16,"section",17),e&2){let n=R();ie(n.embeddedMode?0:1)}}function eM(e,t){if(e&1){let n=at();m(0,"label",57),D(1,"Backend URL"),g(),m(2,"div",58)(3,"input",59),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.serverUrl,o)||(i.serverUrl=o),J(o)}),te("blur",function(){Q(n);let o=R(2);return J(o.applyServerUrl())}),g(),m(4,"button",60),te("click",function(){Q(n);let o=R(2);return J(o.applyServerUrl())}),D(5,"Apply"),g()()}if(e&2){let n=R(2);C(3),Ke("ngModel",n.serverUrl)}}function tM(e,t){e&1&&(m(0,"div",51),D(1," No other authenticated users are online yet. "),g())}function nM(e,t){if(e&1){let n=at();m(0,"article",61)(1,"button",62),te("click",function(){let o=Q(n).$implicit,i=R(2);return J(i.selectPeer(o.id))}),m(2,"div",63)(3,"div")(4,"div",64),D(5),g(),m(6,"div",45),D(7),g()(),m(8,"span",65),D(9),g()(),m(10,"div",66),D(11),g()(),m(12,"a",67),te("click",function(o){return o.stopPropagation()}),D(13," \u{1F4AC} "),g()()}if(e&2){let n=t.$implicit,r=R(2);Ye("peer-tile-active",r.session.activePeerId()===n.id),C(5),X(n.displayName),C(2),X(n.username),C(),Ye("text-bg-success",n.channelState==="open")("text-bg-warning",n.channelState==="connecting")("text-bg-secondary",n.channelState==="closed"),C(),ct(" ",n.channelState," "),C(2),ct("Peer connection: ",n.connectionState),C(),ke("routerLink",wd(13,GS,n.id))}}function rM(e,t){if(e&1){let n=at();m(0,"div",58)(1,"input",74),Qe("ngModelChange",function(o){Q(n);let i=R(3);return lt(i.accessKeyLabel,o)||(i.accessKeyLabel=o),J(o)}),g(),m(2,"button",75),te("click",function(){Q(n);let o=R(3);return J(o.registerAccessKey())}),D(3,"Add key"),g()()}if(e&2){let n=R(3);C(),Ke("ngModel",n.accessKeyLabel)}}function oM(e,t){e&1&&(m(0,"div",70),D(1,"This browser does not expose WebAuthn registration APIs."),g())}function iM(e,t){e&1&&(m(0,"div",72),D(1,"No access keys registered yet."),g())}function sM(e,t){if(e&1&&(m(0,"article",73)(1,"div",64),D(2),g(),m(3,"div",45),D(4),g(),m(5,"div",45),D(6),g(),m(7,"div",45),D(8),yr(9,"date"),g()()),e&2){let n=t.$implicit;C(2),X(n.label),C(2),mr("Device: ",n.deviceType,"",n.backedUp?" / backed up":""),C(2),ct("Transports: ",n.transports.length>0?n.transports.join(", "):"unspecified"),C(2),ct("Added: ",Zr(9,5,n.createdAt,"medium"))}}function aM(e,t){if(e&1&&(m(0,"section",53)(1,"div",48)(2,"div")(3,"h3",68),D(4,"Access keys"),g(),m(5,"p",69),D(6,"Register one or more WebAuthn credentials for this account."),g()(),m(7,"span",24),D(8),g()(),oe(9,rM,4,1,"div",58)(10,oM,2,0,"div",70),m(11,"div",71),oe(12,iM,2,0,"div",72),pr(13,sM,10,8,"article",73,Of),g()()),e&2){let n=R(2);C(8),X(n.session.accessKeys().length),C(),ie(n.session.webAuthnSupported()?9:10),C(3),ie(n.session.accessKeys().length===0?12:-1),C(),gr(n.session.accessKeys())}}function cM(e,t){if(e&1&&(m(0,"div",54),D(1),g()),e&2){let n=R(2);C(),X(n.session.error())}}function lM(e,t){e&1&&(m(0,"div",51),D(1," No messages yet. Open a direct channel to start exchanging data. "),g())}function uM(e,t){if(e&1&&(m(0,"p",40),D(1),g()),e&2){let n=R().$implicit;C(),X(n.text)}}function dM(e,t){if(e&1&&(m(0,"pre",93),D(1),yr(2,"json"),g()),e&2){let n=R().$implicit;C(),X(Id(2,1,n.payload))}}function fM(e,t){if(e&1&&(m(0,"a",95),D(1,"Download"),g()),e&2){let n=R(2).$implicit;ke("href",n.downloadUrl,Na)("download",n.fileName)}}function hM(e,t){if(e&1&&(m(0,"div",94)(1,"div")(2,"div",64),D(3),g(),m(4,"div",45),D(5),g()(),oe(6,fM,2,2,"a",95),g()),e&2){let n=R().$implicit,r=R(3);C(3),X(n.fileName),C(2),X(r.formatBytes(n.fileSize??0)),C(),ie(n.downloadUrl?6:-1)}}function pM(e,t){if(e&1&&(m(0,"p",40),D(1),g()),e&2){let n=R().$implicit;C(),X(n.text)}}function gM(e,t){if(e&1&&(m(0,"article",91)(1,"div",92)(2,"span",64),D(3),g(),m(4,"time",45),D(5),yr(6,"date"),g()(),oe(7,uM,2,1,"p",40)(8,dM,3,3,"pre",93)(9,hM,7,3,"div",94)(10,pM,2,1,"p",40),g()),e&2){let n,r=t.$implicit;Ye("message-card-outgoing",r.direction==="outgoing")("message-card-system",r.direction==="system"),C(3),X(r.authorLabel),C(2),X(Zr(6,7,r.createdAt,"shortTime")),C(2),ie((n=r.kind)==="text"?7:n==="json"?8:n==="file"?9:10)}}function mM(e,t){if(e&1){let n=at();m(0,"div",76)(1,"div")(2,"h2",23),D(3),g(),m(4,"p",19),D(5),g()(),m(6,"button",77),te("click",function(){let o=Q(n),i=R(2);return J(i.openPeerConnection(o.id))}),D(7),g()(),m(8,"div",78),oe(9,lM,2,0,"div",51),pr(10,gM,11,10,"article",79,Of),g(),m(12,"div",80)(13,"section",81)(14,"label",82),D(15,"Text message"),g(),m(16,"textarea",83),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.textMessage,o)||(i.textMessage=o),J(o)}),g(),m(17,"button",84),te("click",function(){let o=Q(n),i=R(2);return J(i.sendText(o.id))}),D(18," Send text "),g()(),m(19,"section",81)(20,"label",85),D(21,"JSON payload"),g(),m(22,"textarea",86),Qe("ngModelChange",function(o){Q(n);let i=R(2);return lt(i.jsonPayload,o)||(i.jsonPayload=o),J(o)}),g(),m(23,"button",87),te("click",function(){let o=Q(n),i=R(2);return J(i.sendJson(o.id))}),D(24," Send JSON "),g()(),m(25,"section",81)(26,"label",88),D(27,"File transfer"),g(),m(28,"input",89,0),te("change",function(){let o=Q(n),i=bd(29),s=R(2);return J(s.sendFile(o.id,i))}),g(),m(30,"p",90),D(31,"Files are chunked over the data channel and never stored on the signaling server."),g()()()}if(e&2){let n=t,r=R(2);C(3),X(n.displayName),C(2),mr(" Signal state: ",n.connectionState,". Data channel: ",n.channelState,". "),C(),ke("disabled",n.channelState==="open"),C(),ct(" ",n.channelState==="open"?"Channel ready":"Open direct channel"," "),C(2),ie(r.session.conversation().length===0?9:-1),C(),gr(r.session.conversation()),C(6),Ke("ngModel",r.textMessage),ke("disabled",!r.session.isSelectedPeerReady()),C(),ke("disabled",!r.session.isSelectedPeerReady()),C(5),Ke("ngModel",r.jsonPayload),ke("disabled",!r.session.isSelectedPeerReady()),C(),ke("disabled",!r.session.isSelectedPeerReady()),C(5),ke("disabled",!r.session.isSelectedPeerReady())}}function yM(e,t){e&1&&(m(0,"div",56),D(1," Choose an online peer to start a direct session. "),g())}function vM(e,t){if(e&1&&(m(0,"section",4)(1,"div",46)(2,"div",47)(3,"div")(4,"div",48)(5,"div")(6,"h2",23),D(7,"Peers"),g(),m(8,"p",19),D(9,"Direct sessions available through signaling."),g()(),m(10,"span",49),D(11),g()(),oe(12,eM,6,1),g(),m(13,"div",50),oe(14,tM,2,0,"div",51),pr(15,nM,14,15,"article",52,Of),g(),oe(17,aM,15,3,"section",53),oe(18,cM,2,1,"div",54),g()(),m(19,"div",55)(20,"div",47),oe(21,mM,32,13)(22,yM,2,0,"div",56),g()()()),e&2){let n,r=R();C(11),X(r.session.status()),C(),ie(r.embeddedMode?-1:12),C(2),ie(r.session.peers().length===0?14:-1),C(),gr(r.session.peers()),C(2),ie(r.embeddedMode?-1:17),C(),ie(r.session.error()?18:-1),C(3),ie((n=r.session.selectedPeer())?21:22,n)}}var Wc=class e{constructor(t){this.session=t;this.serverUrl=t.serverUrl(),this.embeddedMode&&na(()=>{let n=this.session.currentUser(),r=this.session.activePeerId();!n||!r||this.router.navigate(["/chat",r],{replaceUrl:!0})})}router=p(Ut);authMode="login";embeddedMode=typeof window<"u"&&window.localStorage.getItem("privatechat.embeddedMode")==="1";serverUrl="";displayName="";username="";password="";accessKeyLabel="";textMessage="";jsonPayload=`{ + "kind": "example", + "sentAt": "now" +}`;async submitAuth(){if(this.applyServerUrl(),this.authMode==="register"){await this.session.register(this.username,this.password,this.displayName);return}await this.session.login(this.username,this.password)}applyServerUrl(){this.session.setServerUrl(this.serverUrl)}async logout(){await this.session.logout(),this.authMode="login",this.displayName="",this.password="",this.textMessage=""}async loginWithAccessKey(){this.applyServerUrl(),await this.session.loginWithAccessKey(this.username),this.password=""}async registerAccessKey(){await this.session.registerAccessKey(this.accessKeyLabel),this.accessKeyLabel=""}selectPeer(t){this.session.selectPeer(t)}async openPeerConnection(t){await this.session.connectToPeer(t)}async sendText(t){await this.session.sendText(t,this.textMessage),this.textMessage=""}async sendJson(t){await this.session.sendJson(t,this.jsonPayload)}async sendFile(t,n){let r=n.files?.item(0);r&&(await this.session.sendFile(t,r),n.value="")}formatBytes(t){return t<1024?`${t} B`:t<1024*1024?`${(t/1024).toFixed(1)} KB`:`${(t/(1024*1024)).toFixed(1)} MB`}static \u0275fac=function(n){return new(n||e)(B(_o))};static \u0275cmp=Jt({type:e,selectors:[["app-home-page"]],decls:5,vars:2,consts:[["fileInput",""],[1,"shell","py-4","py-lg-5"],[1,"container-xl"],[1,"hero-panel","mb-4","mb-lg-5","p-4","p-lg-5"],[1,"row","g-4","app-grid"],[1,"d-flex","flex-column","flex-lg-row","align-items-start","align-items-lg-center","justify-content-between","gap-4"],[1,"hero-copy"],[1,"eyebrow"],[1,"display-5","fw-semibold","mb-3"],[1,"lead","mb-0","text-body-secondary"],[1,"session-card","p-3","p-lg-4"],[1,"text-uppercase","small","text-secondary","mb-2"],[1,"h4","mb-1"],[1,"text-secondary","mb-3"],[1,"small","status-pill","mb-3"],["type","button",1,"btn","btn-outline-light","w-100",3,"click"],[1,"panel","p-4","p-lg-5","text-center"],[1,"row","g-4","align-items-stretch"],[1,"h3","mb-3"],[1,"text-secondary","mb-0"],[1,"col-lg-6"],[1,"panel","p-4","h-100"],[1,"d-flex","justify-content-between","align-items-center","mb-4"],[1,"h3","mb-1"],[1,"badge","rounded-pill","text-bg-dark"],[1,"mb-3"],["for","serverUrl",1,"form-label"],["id","serverUrl","name","serverUrl","placeholder","http://localhost:3000",1,"form-control","form-control-lg",3,"ngModelChange","ngModel"],["role","group","aria-label","Authentication mode",1,"btn-group","mb-4","w-100"],["type","button",1,"btn",3,"click"],[1,"d-grid","gap-3",3,"ngSubmit"],["for","username",1,"form-label"],["id","username","name","username","placeholder","alice",1,"form-control","form-control-lg",3,"ngModelChange","ngModel"],["for","password",1,"form-label"],["id","password","name","password","type","password","placeholder","At least 8 characters","autocomplete","current-password",1,"form-control","form-control-lg",3,"ngModelChange","ngModel"],["type","submit",1,"btn","btn-accent","btn-lg","mt-2"],[1,"alert","alert-danger","mt-4","mb-0"],[1,"panel","panel-muted","p-4","h-100"],[1,"info-rail","d-grid","gap-3"],[1,"small","text-uppercase","text-secondary","mb-2"],[1,"mb-0"],["for","displayName",1,"form-label"],["id","displayName","name","displayName","placeholder","Operator One",1,"form-control","form-control-lg",3,"ngModelChange","ngModel"],[1,"text-center","small","text-secondary","mt-1"],["type","button",1,"btn","btn-outline-light","btn-lg",3,"click"],[1,"small","text-secondary"],[1,"col-xl-4"],[1,"panel","p-4","h-100","d-flex","flex-column","gap-4"],[1,"d-flex","justify-content-between","align-items-start","gap-3","mb-3"],[1,"small","status-pill"],[1,"peer-list","d-grid","gap-2"],[1,"empty-state","p-4","text-center","text-secondary"],[1,"peer-tile",3,"peer-tile-active"],[1,"access-key-panel"],[1,"alert","alert-danger","mb-0"],[1,"col-xl-8"],[1,"empty-state","h-100","d-flex","align-items-center","justify-content-center","text-center","text-secondary","p-5"],["for","connectedServerUrl",1,"form-label"],[1,"input-group","mb-3"],["id","connectedServerUrl",1,"form-control",3,"ngModelChange","blur","ngModel"],["type","button",1,"btn","btn-outline-secondary",3,"click"],[1,"peer-tile"],["type","button",1,"peer-tile-main","text-start",3,"click"],[1,"d-flex","justify-content-between","align-items-start","gap-3"],[1,"fw-semibold"],[1,"badge","rounded-pill"],[1,"small","text-secondary","mt-2"],["title","Open text chat","aria-label","Open text chat",1,"chat-emoji",3,"click","routerLink"],[1,"h5","mb-1"],[1,"small","text-secondary","mb-0"],[1,"alert","alert-warning","mb-3"],[1,"d-grid","gap-2"],[1,"empty-state","p-3","text-center","text-secondary"],[1,"access-key-card","p-3"],["placeholder","Laptop passkey",1,"form-control",3,"ngModelChange","ngModel"],["type","button",1,"btn","btn-outline-light",3,"click"],[1,"d-flex","flex-column","flex-lg-row","justify-content-between","align-items-start","align-items-lg-center","gap-3"],["type","button",1,"btn","btn-accent",3,"click","disabled"],[1,"chat-log","flex-grow-1"],[1,"message-card",3,"message-card-outgoing","message-card-system"],[1,"composer-grid"],[1,"composer-card","p-3"],["for","messageText",1,"form-label"],["id","messageText","rows","3","placeholder","Send a direct text message over WebRTC",1,"form-control",3,"ngModelChange","ngModel","disabled"],["type","button",1,"btn","btn-accent","mt-3",3,"click","disabled"],["for","jsonPayload",1,"form-label"],["id","jsonPayload","rows","3","placeholder",'{"kind":"note","value":42}',1,"form-control","font-monospace",3,"ngModelChange","ngModel","disabled"],["type","button",1,"btn","btn-outline-light","mt-3",3,"click","disabled"],["for","fileInput",1,"form-label"],["id","fileInput","type","file",1,"form-control",3,"change","disabled"],[1,"small","text-secondary","mt-3","mb-0"],[1,"message-card"],[1,"d-flex","justify-content-between","align-items-center","gap-3","mb-2"],[1,"json-block","mb-0"],[1,"d-flex","flex-column","gap-2"],[1,"btn","btn-sm","btn-outline-light","align-self-start",3,"href","download"]],template:function(n,r){n&1&&(m(0,"main",1)(1,"div",2),oe(2,qS,10,1,"section",3),oe(3,XS,2,1)(4,vM,23,6,"section",4),g()()),n&2&&(C(2),ie(r.embeddedMode?-1:2),C(),ie(r.session.currentUser()?4:3))},dependencies:[eo,zc,Hv,Eo,Hc,Fv,Ji,Rf,yo,kd,Ei],styles:["[_nghost-%COMP%]{display:block;min-height:100dvh;color:#eff3ff}.shell[_ngcontent-%COMP%]{min-height:100dvh}.hero-panel[_ngcontent-%COMP%], .panel[_ngcontent-%COMP%], .session-card[_ngcontent-%COMP%], .peer-tile[_ngcontent-%COMP%], .message-card[_ngcontent-%COMP%], .composer-card[_ngcontent-%COMP%], .empty-state[_ngcontent-%COMP%]{border:1px solid rgba(255,255,255,.12);background:#09101cc7;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px);box-shadow:0 20px 60px #00000047}.hero-panel[_ngcontent-%COMP%]{border-radius:2rem}.panel[_ngcontent-%COMP%]{border-radius:1.5rem}.panel-muted[_ngcontent-%COMP%]{background:#0f1b2cc7}.hero-copy[_ngcontent-%COMP%]{max-width:52rem}.eyebrow[_ngcontent-%COMP%]{display:inline-flex;align-items:center;gap:.5rem;padding:.45rem .85rem;border-radius:999px;margin-bottom:1rem;letter-spacing:.14em;text-transform:uppercase;font-size:.72rem;font-weight:700;color:#81f4d7;background:#81f4d71a}.session-card[_ngcontent-%COMP%]{min-width:min(100%,18rem);border-radius:1.5rem}.status-pill[_ngcontent-%COMP%]{display:inline-flex;padding:.45rem .8rem;border-radius:999px;background:#ffffff14}.btn-accent[_ngcontent-%COMP%]{color:#06111d;border:0;background:linear-gradient(135deg,#81f4d7,#55a8ff)}.btn-accent[_ngcontent-%COMP%]:hover, .btn-accent[_ngcontent-%COMP%]:focus-visible{color:#06111d;background:linear-gradient(135deg,#9bf7e0,#7abaff)}.peer-list[_ngcontent-%COMP%]{max-height:30rem;overflow:auto}.access-key-panel[_ngcontent-%COMP%]{padding:1rem;border-radius:1rem;background:#ffffff0a}.access-key-card[_ngcontent-%COMP%]{border-radius:.9rem;border:1px solid rgba(255,255,255,.08);background:#080e17b3}.peer-tile[_ngcontent-%COMP%]{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.75rem;align-items:center;padding:1rem;border-radius:1rem;transition:transform .16s ease,border-color .16s ease,background .16s ease}.peer-tile[_ngcontent-%COMP%]:hover, .peer-tile[_ngcontent-%COMP%]:focus-within, .peer-tile-active[_ngcontent-%COMP%]{transform:translateY(-1px);border-color:#81f4d766;background:#101e31f2}.peer-tile-main[_ngcontent-%COMP%]{width:100%;padding:0;border:0;color:inherit;background:transparent}.chat-emoji[_ngcontent-%COMP%]{display:inline-flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;border-radius:999px;font-size:1.2rem;text-decoration:none;background:#81f4d724;box-shadow:inset 0 0 0 1px #81f4d733}.chat-log[_ngcontent-%COMP%]{display:grid;gap:.9rem;min-height:20rem;max-height:32rem;overflow:auto;padding-right:.25rem}.message-card[_ngcontent-%COMP%]{padding:1rem;border-radius:1rem}.message-card-outgoing[_ngcontent-%COMP%]{background:linear-gradient(135deg,#55a8ff47,#81f4d72e)}.message-card-system[_ngcontent-%COMP%]{border-style:dashed;background:#ffffff0a}.composer-grid[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1rem}.composer-card[_ngcontent-%COMP%], .empty-state[_ngcontent-%COMP%]{border-radius:1.25rem}.json-block[_ngcontent-%COMP%]{padding:.9rem;border-radius:.85rem;margin:0;color:#d7e7ff;background:#050b14b8}.info-rail[_ngcontent-%COMP%] article[_ngcontent-%COMP%]{padding:1rem 1.1rem;border-radius:1rem;background:#ffffff0d}.form-control[_ngcontent-%COMP%], .form-control[_ngcontent-%COMP%]:focus{color:#eff3ff;background-color:#ffffff0f;border-color:#ffffff29;box-shadow:none}.form-control[_ngcontent-%COMP%]::placeholder{color:#eff3ff80}.form-label[_ngcontent-%COMP%], .h3[_ngcontent-%COMP%], .h4[_ngcontent-%COMP%], .display-5[_ngcontent-%COMP%], .fw-semibold[_ngcontent-%COMP%], .fw-bold[_ngcontent-%COMP%]{color:#f8fbff}.text-secondary[_ngcontent-%COMP%], .lead[_ngcontent-%COMP%], .small[_ngcontent-%COMP%]{color:#e7eef9b8!important}@media(max-width:1199.98px){.composer-grid[_ngcontent-%COMP%]{grid-template-columns:1fr}}"]})};var Gv=[{path:"",component:Wc},{path:"chat/:peerId",component:Gc},{path:"**",redirectTo:""}];var Wv={providers:[fu(),Qd(Jd()),If(Gv)]};var qc=class e{static \u0275fac=function(n){return new(n||e)};static \u0275cmp=Jt({type:e,selectors:[["app-root"]],decls:1,vars:0,template:function(n,r){n&1&&qr(0,"router-outlet")},dependencies:[$i],styles:["[_nghost-%COMP%]{display:block;min-height:100dvh}"]})};zd(qc,Wv).catch(e=>console.error(e)); diff --git a/apple-client/WebApp/browser/styles-YLPXNZVT.css b/apple-client/WebApp/browser/styles-YLPXNZVT.css new file mode 100644 index 0000000..0665203 --- /dev/null +++ b/apple-client/WebApp/browser/styles-YLPXNZVT.css @@ -0,0 +1 @@ +@charset "UTF-8";:root,[data-bs-theme=light]{--bs-blue: #0d6efd;--bs-indigo: #6610f2;--bs-purple: #6f42c1;--bs-pink: #d63384;--bs-red: #dc3545;--bs-orange: #fd7e14;--bs-yellow: #ffc107;--bs-green: #198754;--bs-teal: #20c997;--bs-cyan: #0dcaf0;--bs-black: #000;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #343a40;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #343a40;--bs-gray-900: #212529;--bs-primary: #0d6efd;--bs-secondary: #6c757d;--bs-success: #198754;--bs-info: #0dcaf0;--bs-warning: #ffc107;--bs-danger: #dc3545;--bs-light: #f8f9fa;--bs-dark: #212529;--bs-primary-rgb: 13, 110, 253;--bs-secondary-rgb: 108, 117, 125;--bs-success-rgb: 25, 135, 84;--bs-info-rgb: 13, 202, 240;--bs-warning-rgb: 255, 193, 7;--bs-danger-rgb: 220, 53, 69;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 33, 37, 41;--bs-primary-text-emphasis: rgb(5.2, 44, 101.2);--bs-secondary-text-emphasis: rgb(43.2, 46.8, 50);--bs-success-text-emphasis: rgb(10, 54, 33.6);--bs-info-text-emphasis: rgb(5.2, 80.8, 96);--bs-warning-text-emphasis: rgb(102, 77.2, 2.8);--bs-danger-text-emphasis: rgb(88, 21.2, 27.6);--bs-light-text-emphasis: #495057;--bs-dark-text-emphasis: #495057;--bs-primary-bg-subtle: rgb(206.6, 226, 254.6);--bs-secondary-bg-subtle: rgb(225.6, 227.4, 229);--bs-success-bg-subtle: rgb(209, 231, 220.8);--bs-info-bg-subtle: rgb(206.6, 244.4, 252);--bs-warning-bg-subtle: rgb(255, 242.6, 205.4);--bs-danger-bg-subtle: rgb(248, 214.6, 217.8);--bs-light-bg-subtle: rgb(251.5, 252, 252.5);--bs-dark-bg-subtle: #ced4da;--bs-primary-border-subtle: rgb(158.2, 197, 254.2);--bs-secondary-border-subtle: rgb(196.2, 199.8, 203);--bs-success-border-subtle: rgb(163, 207, 186.6);--bs-info-border-subtle: rgb(158.2, 233.8, 249);--bs-warning-border-subtle: rgb(255, 230.2, 155.8);--bs-danger-border-subtle: rgb(241, 174.2, 180.6);--bs-light-border-subtle: #e9ecef;--bs-dark-border-subtle: #adb5bd;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, .15), rgba(255, 255, 255, 0));--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.5;--bs-body-color: #212529;--bs-body-color-rgb: 33, 37, 41;--bs-body-bg: #fff;--bs-body-bg-rgb: 255, 255, 255;--bs-emphasis-color: #000;--bs-emphasis-color-rgb: 0, 0, 0;--bs-secondary-color: rgba(33, 37, 41, .75);--bs-secondary-color-rgb: 33, 37, 41;--bs-secondary-bg: #e9ecef;--bs-secondary-bg-rgb: 233, 236, 239;--bs-tertiary-color: rgba(33, 37, 41, .5);--bs-tertiary-color-rgb: 33, 37, 41;--bs-tertiary-bg: #f8f9fa;--bs-tertiary-bg-rgb: 248, 249, 250;--bs-heading-color: inherit;--bs-link-color: #0d6efd;--bs-link-color-rgb: 13, 110, 253;--bs-link-decoration: underline;--bs-link-hover-color: rgb(10.4, 88, 202.4);--bs-link-hover-color-rgb: 10, 88, 202;--bs-code-color: #d63384;--bs-highlight-color: #212529;--bs-highlight-bg: rgb(255, 242.6, 205.4);--bs-border-width: 1px;--bs-border-style: solid;--bs-border-color: #dee2e6;--bs-border-color-translucent: rgba(0, 0, 0, .175);--bs-border-radius: .375rem;--bs-border-radius-sm: .25rem;--bs-border-radius-lg: .5rem;--bs-border-radius-xl: 1rem;--bs-border-radius-xxl: 2rem;--bs-border-radius-2xl: var(--bs-border-radius-xxl);--bs-border-radius-pill: 50rem;--bs-box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .15);--bs-box-shadow-sm: 0 .125rem .25rem rgba(0, 0, 0, .075);--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, .175);--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, .075);--bs-focus-ring-width: .25rem;--bs-focus-ring-opacity: .25;--bs-focus-ring-color: rgba(13, 110, 253, .25);--bs-form-valid-color: #198754;--bs-form-valid-border-color: #198754;--bs-form-invalid-color: #dc3545;--bs-form-invalid-border-color: #dc3545}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color: #dee2e6;--bs-body-color-rgb: 222, 226, 230;--bs-body-bg: #212529;--bs-body-bg-rgb: 33, 37, 41;--bs-emphasis-color: #fff;--bs-emphasis-color-rgb: 255, 255, 255;--bs-secondary-color: rgba(222, 226, 230, .75);--bs-secondary-color-rgb: 222, 226, 230;--bs-secondary-bg: #343a40;--bs-secondary-bg-rgb: 52, 58, 64;--bs-tertiary-color: rgba(222, 226, 230, .5);--bs-tertiary-color-rgb: 222, 226, 230;--bs-tertiary-bg: rgb(42.5, 47.5, 52.5);--bs-tertiary-bg-rgb: 43, 48, 53;--bs-primary-text-emphasis: rgb(109.8, 168, 253.8);--bs-secondary-text-emphasis: rgb(166.8, 172.2, 177);--bs-success-text-emphasis: rgb(117, 183, 152.4);--bs-info-text-emphasis: rgb(109.8, 223.2, 246);--bs-warning-text-emphasis: rgb(255, 217.8, 106.2);--bs-danger-text-emphasis: rgb(234, 133.8, 143.4);--bs-light-text-emphasis: #f8f9fa;--bs-dark-text-emphasis: #dee2e6;--bs-primary-bg-subtle: rgb(2.6, 22, 50.6);--bs-secondary-bg-subtle: rgb(21.6, 23.4, 25);--bs-success-bg-subtle: rgb(5, 27, 16.8);--bs-info-bg-subtle: rgb(2.6, 40.4, 48);--bs-warning-bg-subtle: rgb(51, 38.6, 1.4);--bs-danger-bg-subtle: rgb(44, 10.6, 13.8);--bs-light-bg-subtle: #343a40;--bs-dark-bg-subtle: #1a1d20;--bs-primary-border-subtle: rgb(7.8, 66, 151.8);--bs-secondary-border-subtle: rgb(64.8, 70.2, 75);--bs-success-border-subtle: rgb(15, 81, 50.4);--bs-info-border-subtle: rgb(7.8, 121.2, 144);--bs-warning-border-subtle: rgb(153, 115.8, 4.2);--bs-danger-border-subtle: rgb(132, 31.8, 41.4);--bs-light-border-subtle: #495057;--bs-dark-border-subtle: #343a40;--bs-heading-color: inherit;--bs-link-color: rgb(109.8, 168, 253.8);--bs-link-hover-color: rgb(138.84, 185.4, 254.04);--bs-link-color-rgb: 110, 168, 254;--bs-link-hover-color-rgb: 139, 185, 254;--bs-code-color: rgb(230.4, 132.6, 181.2);--bs-highlight-color: #dee2e6;--bs-highlight-bg: rgb(102, 77.2, 2.8);--bs-border-color: #495057;--bs-border-color-translucent: rgba(255, 255, 255, .15);--bs-form-valid-color: rgb(117, 183, 152.4);--bs-form-valid-border-color: rgb(117, 183, 152.4);--bs-form-invalid-color: rgb(234, 133.8, 143.4);--bs-form-invalid-border-color: rgb(234, 133.8, 143.4)}*,*:before,*:after{box-sizing:border-box}@media(prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2;color:var(--bs-heading-color)}h1,.h1{font-size:calc(1.375rem + 1.5vw)}@media(min-width:1200px){h1,.h1{font-size:2.5rem}}h2,.h2{font-size:calc(1.325rem + .9vw)}@media(min-width:1200px){h2,.h2{font-size:2rem}}h3,.h3{font-size:calc(1.3rem + .6vw)}@media(min-width:1200px){h3,.h3{font-size:1.75rem}}h4,.h4{font-size:calc(1.275rem + .3vw)}@media(min-width:1200px){h4,.h4{font-size:1.5rem}}h5,.h5{font-size:1.25rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small,.small{font-size:.875em}mark,.mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity, 1));text-decoration:underline}a:hover{--bs-link-color-rgb: var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color);border-radius:.25rem}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;line-height:inherit;font-size:calc(1.275rem + .3vw)}@media(min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button{cursor:pointer;filter:grayscale(1)}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-weight:300;line-height:1.2;font-size:calc(1.625rem + 4.5vw)}@media(min-width:1200px){.display-1{font-size:5rem}}.display-2{font-weight:300;line-height:1.2;font-size:calc(1.575rem + 3.9vw)}@media(min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-weight:300;line-height:1.2;font-size:calc(1.525rem + 3.3vw)}@media(min-width:1200px){.display-3{font-size:4rem}}.display-4{font-weight:300;line-height:1.2;font-size:calc(1.475rem + 2.7vw)}@media(min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-weight:300;line-height:1.2;font-size:calc(1.425rem + 2.1vw)}@media(min-width:1200px){.display-5{font-size:3rem}}.display-6{font-weight:300;line-height:1.2;font-size:calc(1.375rem + 1.5vw)}@media(min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled,.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#6c757d}.blockquote-footer:before{content:"\2014\a0"}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-xxl,.container-xl,.container-lg,.container-md,.container-sm{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media(min-width:576px){.container-sm,.container{max-width:540px}}@media(min-width:768px){.container-md,.container-sm,.container{max-width:720px}}@media(min-width:992px){.container-lg,.container-md,.container-sm,.container{max-width:960px}}@media(min-width:1200px){.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1140px}}@media(min-width:1400px){.container-xxl,.container-xl,.container-lg,.container-md,.container-sm,.container{max-width:1320px}}:root{--bs-breakpoint-xs: 0;--bs-breakpoint-sm: 576px;--bs-breakpoint-md: 768px;--bs-breakpoint-lg: 992px;--bs-breakpoint-xl: 1200px;--bs-breakpoint-xxl: 1400px}.row{--bs-gutter-x: 1.5rem;--bs-gutter-y: 0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x: 0}.g-0,.gy-0{--bs-gutter-y: 0}.g-1,.gx-1{--bs-gutter-x: .25rem}.g-1,.gy-1{--bs-gutter-y: .25rem}.g-2,.gx-2{--bs-gutter-x: .5rem}.g-2,.gy-2{--bs-gutter-y: .5rem}.g-3,.gx-3{--bs-gutter-x: 1rem}.g-3,.gy-3{--bs-gutter-y: 1rem}.g-4,.gx-4{--bs-gutter-x: 1.5rem}.g-4,.gy-4{--bs-gutter-y: 1.5rem}.g-5,.gx-5{--bs-gutter-x: 3rem}.g-5,.gy-5{--bs-gutter-y: 3rem}@media(min-width:576px){.col-sm{flex:1 0 0}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x: 0}.g-sm-0,.gy-sm-0{--bs-gutter-y: 0}.g-sm-1,.gx-sm-1{--bs-gutter-x: .25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y: .25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x: .5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y: .5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x: 1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y: 1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x: 1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y: 1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x: 3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y: 3rem}}@media(min-width:768px){.col-md{flex:1 0 0}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x: 0}.g-md-0,.gy-md-0{--bs-gutter-y: 0}.g-md-1,.gx-md-1{--bs-gutter-x: .25rem}.g-md-1,.gy-md-1{--bs-gutter-y: .25rem}.g-md-2,.gx-md-2{--bs-gutter-x: .5rem}.g-md-2,.gy-md-2{--bs-gutter-y: .5rem}.g-md-3,.gx-md-3{--bs-gutter-x: 1rem}.g-md-3,.gy-md-3{--bs-gutter-y: 1rem}.g-md-4,.gx-md-4{--bs-gutter-x: 1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y: 1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x: 3rem}.g-md-5,.gy-md-5{--bs-gutter-y: 3rem}}@media(min-width:992px){.col-lg{flex:1 0 0}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x: 0}.g-lg-0,.gy-lg-0{--bs-gutter-y: 0}.g-lg-1,.gx-lg-1{--bs-gutter-x: .25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y: .25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x: .5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y: .5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x: 1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y: 1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x: 1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y: 1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x: 3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y: 3rem}}@media(min-width:1200px){.col-xl{flex:1 0 0}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x: 0}.g-xl-0,.gy-xl-0{--bs-gutter-y: 0}.g-xl-1,.gx-xl-1{--bs-gutter-x: .25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y: .25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x: .5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y: .5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x: 1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y: 1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x: 1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y: 1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x: 3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y: 3rem}}@media(min-width:1400px){.col-xxl{flex:1 0 0}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x: 0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y: 0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x: .25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y: .25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x: .5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y: .5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x: 1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y: 1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x: 1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y: 1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x: 3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y: 3rem}}.table{--bs-table-color-type: initial;--bs-table-bg-type: initial;--bs-table-color-state: initial;--bs-table-bg-state: initial;--bs-table-color: var(--bs-emphasis-color);--bs-table-bg: var(--bs-body-bg);--bs-table-border-color: var(--bs-border-color);--bs-table-accent-bg: transparent;--bs-table-striped-color: var(--bs-emphasis-color);--bs-table-striped-bg: rgba(var(--bs-emphasis-color-rgb), .05);--bs-table-active-color: var(--bs-emphasis-color);--bs-table-active-bg: rgba(var(--bs-emphasis-color-rgb), .1);--bs-table-hover-color: var(--bs-emphasis-color);--bs-table-hover-bg: rgba(var(--bs-emphasis-color-rgb), .075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem;color:var(--bs-table-color-state, var(--bs-table-color-type, var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state, var(--bs-table-bg-type, var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type: var(--bs-table-striped-color);--bs-table-bg-type: var(--bs-table-striped-bg)}.table-active{--bs-table-color-state: var(--bs-table-active-color);--bs-table-bg-state: var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state: var(--bs-table-hover-color);--bs-table-bg-state: var(--bs-table-hover-bg)}.table-primary{--bs-table-color: #000;--bs-table-bg: rgb(206.6, 226, 254.6);--bs-table-border-color: rgb(165.28, 180.8, 203.68);--bs-table-striped-bg: rgb(196.27, 214.7, 241.87);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(185.94, 203.4, 229.14);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(191.105, 209.05, 235.505);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color: #000;--bs-table-bg: rgb(225.6, 227.4, 229);--bs-table-border-color: rgb(180.48, 181.92, 183.2);--bs-table-striped-bg: rgb(214.32, 216.03, 217.55);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(203.04, 204.66, 206.1);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(208.68, 210.345, 211.825);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color: #000;--bs-table-bg: rgb(209, 231, 220.8);--bs-table-border-color: rgb(167.2, 184.8, 176.64);--bs-table-striped-bg: rgb(198.55, 219.45, 209.76);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(188.1, 207.9, 198.72);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(193.325, 213.675, 204.24);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color: #000;--bs-table-bg: rgb(206.6, 244.4, 252);--bs-table-border-color: rgb(165.28, 195.52, 201.6);--bs-table-striped-bg: rgb(196.27, 232.18, 239.4);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(185.94, 219.96, 226.8);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(191.105, 226.07, 233.1);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color: #000;--bs-table-bg: rgb(255, 242.6, 205.4);--bs-table-border-color: rgb(204, 194.08, 164.32);--bs-table-striped-bg: rgb(242.25, 230.47, 195.13);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(229.5, 218.34, 184.86);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(235.875, 224.405, 189.995);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color: #000;--bs-table-bg: rgb(248, 214.6, 217.8);--bs-table-border-color: rgb(198.4, 171.68, 174.24);--bs-table-striped-bg: rgb(235.6, 203.87, 206.91);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(223.2, 193.14, 196.02);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(229.4, 198.505, 201.465);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color: #000;--bs-table-bg: #f8f9fa;--bs-table-border-color: rgb(198.4, 199.2, 200);--bs-table-striped-bg: rgb(235.6, 236.55, 237.5);--bs-table-striped-color: #000;--bs-table-active-bg: rgb(223.2, 224.1, 225);--bs-table-active-color: #000;--bs-table-hover-bg: rgb(229.4, 230.325, 231.25);--bs-table-hover-color: #000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color: #fff;--bs-table-bg: #212529;--bs-table-border-color: rgb(77.4, 80.6, 83.8);--bs-table-striped-bg: rgb(44.1, 47.9, 51.7);--bs-table-striped-color: #fff;--bs-table-active-bg: rgb(55.2, 58.8, 62.4);--bs-table-active-color: #fff;--bs-table-hover-bg: rgb(49.65, 53.35, 57.05);--bs-table-hover-color: #fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(.375rem + var(--bs-border-width));padding-bottom:calc(.375rem + var(--bs-border-width));margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(.5rem + var(--bs-border-width));padding-bottom:calc(.5rem + var(--bs-border-width));font-size:1.25rem}.col-form-label-sm{padding-top:calc(.25rem + var(--bs-border-width));padding-bottom:calc(.25rem + var(--bs-border-width));font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);appearance:none;background-color:var(--bs-body-bg);background-clip:padding-box;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:var(--bs-body-bg);border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:var(--bs-secondary-bg);opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-.375rem -.75rem;margin-inline-end:.75rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:var(--bs-border-width);border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:var(--bs-border-width) 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2));padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-.25rem -.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2));padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2))}textarea.form-control-sm{min-height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}textarea.form-control-lg{min-height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-control-color{width:3rem;height:calc(1.5em + .75rem + calc(var(--bs-border-width) * 2));padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color::-webkit-color-swatch{border:0!important;border-radius:var(--bs-border-radius)}.form-control-color.form-control-sm{height:calc(1.5em + .5rem + calc(var(--bs-border-width) * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 1rem + calc(var(--bs-border-width) * 2))}.form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);appearance:none;background-color:var(--bs-body-bg);background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon, none);background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius);transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:var(--bs-secondary-bg)}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23dee2e6' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg: var(--bs-body-bg);flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;print-color-adjust:exact}.form-check-input[type=checkbox]{border-radius:.25em}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#86b7fe;outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.form-check-input:checked{background-color:#0d6efd;border-color:#0d6efd}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#0d6efd;border-color:#0d6efd;--bs-form-check-bg-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input:disabled~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:2em;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgb%28134, 182.5, 254%29'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem #0d6efd40}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#b6d4fe}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range::-moz-range-thumb{width:1rem;height:1rem;appearance:none;background-color:#0d6efd;border:0;border-radius:1rem;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#b6d4fe}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent;border-radius:1rem}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(var(--bs-border-width) * 2));min-height:calc(3.5rem + calc(var(--bs-border-width) * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;max-width:100%;height:100%;padding:1rem .75rem;overflow:hidden;color:rgba(var(--bs-body-color-rgb),.65);text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:var(--bs-border-width) solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem .75rem}.form-floating>.form-control::placeholder,.form-floating>.form-control-plaintext::placeholder{color:transparent}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown),.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill,.form-floating>.form-control-plaintext:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem;padding-left:.75rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-control-plaintext~label,.form-floating>.form-select~label{transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>.form-control:-webkit-autofill~label{transform:scale(.85) translateY(-.5rem) translate(.15rem)}.form-floating>textarea:focus~label:after,.form-floating>textarea:not(:placeholder-shown)~label:after{position:absolute;inset:1rem .375rem;z-index:-1;height:1.5em;content:"";background-color:var(--bs-body-bg);border-radius:var(--bs-border-radius)}.form-floating>textarea:disabled~label:after{background-color:var(--bs-secondary-bg)}.form-floating>.form-control-plaintext~label{border-width:var(--bs-border-width) 0}.form-floating>:disabled~label,.form-floating>.form-control:disabled~label{color:#6c757d}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select,.input-group>.form-floating{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus,.input-group>.form-floating:focus-within{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:var(--bs-tertiary-bg);border:var(--bs-border-width) solid var(--bs-border-color);border-radius:var(--bs-border-radius)}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:var(--bs-border-radius-lg)}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:.875rem;border-radius:var(--bs-border-radius-sm)}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-control,.input-group:not(.has-validation)>.form-floating:not(:last-child)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-control,.input-group.has-validation>.form-floating:nth-last-child(n+3)>.form-select{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(-1 * var(--bs-border-width));border-top-left-radius:0;border-bottom-left-radius:0}.input-group>.form-floating:not(:first-child)>.form-control,.input-group>.form-floating:not(:first-child)>.form-select{border-top-left-radius:0;border-bottom-left-radius:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success);border-radius:var(--bs-border-radius)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23198754' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated .form-control-color:valid,.form-control-color.is-valid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:var(--bs-form-valid-border-color)}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:var(--bs-form-valid-color)}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):valid,.input-group>.form-control:not(:focus).is-valid,.was-validated .input-group>.form-select:not(:focus):valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.input-group>.form-floating:not(:focus-within).is-valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger);border-radius:var(--bs-border-radius)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + .75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .1875rem) center;background-size:calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + .75rem);background-position:top calc(.375em + .1875rem) right calc(.375em + .1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23dc3545'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23dc3545' stroke='none'/%3e%3c/svg%3e");padding-right:4.125rem;background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(.75em + .375rem) calc(.75em + .375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated .form-control-color:invalid,.form-control-color.is-invalid{width:calc(3.75rem + 1.5em)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:var(--bs-form-invalid-border-color)}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:var(--bs-form-invalid-color)}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group>.form-control:not(:focus):invalid,.input-group>.form-control:not(:focus).is-invalid,.was-validated .input-group>.form-select:not(:focus):invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.input-group>.form-floating:not(:focus-within).is-invalid{z-index:4}.btn{--bs-btn-padding-x: .75rem;--bs-btn-padding-y: .375rem;--bs-btn-font-family: ;--bs-btn-font-size: 1rem;--bs-btn-font-weight: 400;--bs-btn-line-height: 1.5;--bs-btn-color: var(--bs-body-color);--bs-btn-bg: transparent;--bs-btn-border-width: var(--bs-border-width);--bs-btn-border-color: transparent;--bs-btn-border-radius: var(--bs-border-radius);--bs-btn-hover-border-color: transparent;--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);--bs-btn-disabled-opacity: .65;--bs-btn-focus-box-shadow: 0 0 0 .25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);border-radius:var(--bs-btn-border-radius);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,:not(.btn-check)+.btn:active,.btn:first-child:active,.btn.active,.btn.show{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,:not(.btn-check)+.btn:active:focus-visible,.btn:first-child:active:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color: #fff;--bs-btn-bg: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(11.05, 93.5, 215.05);--bs-btn-hover-border-color: rgb(10.4, 88, 202.4);--bs-btn-focus-shadow-rgb: 49, 132, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(10.4, 88, 202.4);--bs-btn-active-border-color: rgb(9.75, 82.5, 189.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #0d6efd;--bs-btn-disabled-border-color: #0d6efd}.btn-secondary{--bs-btn-color: #fff;--bs-btn-bg: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(91.8, 99.45, 106.25);--bs-btn-hover-border-color: rgb(86.4, 93.6, 100);--bs-btn-focus-shadow-rgb: 130, 138, 145;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(86.4, 93.6, 100);--bs-btn-active-border-color: rgb(81, 87.75, 93.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #6c757d;--bs-btn-disabled-border-color: #6c757d}.btn-success{--bs-btn-color: #fff;--bs-btn-bg: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(21.25, 114.75, 71.4);--bs-btn-hover-border-color: rgb(20, 108, 67.2);--bs-btn-focus-shadow-rgb: 60, 153, 110;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(20, 108, 67.2);--bs-btn-active-border-color: rgb(18.75, 101.25, 63);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #198754;--bs-btn-disabled-border-color: #198754}.btn-info{--bs-btn-color: #000;--bs-btn-bg: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(49.3, 209.95, 242.25);--bs-btn-hover-border-color: rgb(37.2, 207.3, 241.5);--bs-btn-focus-shadow-rgb: 11, 172, 204;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(61.4, 212.6, 243);--bs-btn-active-border-color: rgb(37.2, 207.3, 241.5);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #0dcaf0;--bs-btn-disabled-border-color: #0dcaf0}.btn-warning{--bs-btn-color: #000;--bs-btn-bg: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(255, 202.3, 44.2);--bs-btn-hover-border-color: rgb(255, 199.2, 31.8);--bs-btn-focus-shadow-rgb: 217, 164, 6;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(255, 205.4, 56.6);--bs-btn-active-border-color: rgb(255, 199.2, 31.8);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #ffc107;--bs-btn-disabled-border-color: #ffc107}.btn-danger{--bs-btn-color: #fff;--bs-btn-bg: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(187, 45.05, 58.65);--bs-btn-hover-border-color: rgb(176, 42.4, 55.2);--bs-btn-focus-shadow-rgb: 225, 83, 97;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(176, 42.4, 55.2);--bs-btn-active-border-color: rgb(165, 39.75, 51.75);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #dc3545;--bs-btn-disabled-border-color: #dc3545}.btn-light{--bs-btn-color: #000;--bs-btn-bg: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: rgb(210.8, 211.65, 212.5);--bs-btn-hover-border-color: rgb(198.4, 199.2, 200);--bs-btn-focus-shadow-rgb: 211, 212, 213;--bs-btn-active-color: #000;--bs-btn-active-bg: rgb(198.4, 199.2, 200);--bs-btn-active-border-color: rgb(186, 186.75, 187.5);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #000;--bs-btn-disabled-bg: #f8f9fa;--bs-btn-disabled-border-color: #f8f9fa}.btn-dark{--bs-btn-color: #fff;--bs-btn-bg: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: rgb(66.3, 69.7, 73.1);--bs-btn-hover-border-color: rgb(55.2, 58.8, 62.4);--bs-btn-focus-shadow-rgb: 66, 70, 73;--bs-btn-active-color: #fff;--bs-btn-active-bg: rgb(77.4, 80.6, 83.8);--bs-btn-active-border-color: rgb(55.2, 58.8, 62.4);--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #fff;--bs-btn-disabled-bg: #212529;--bs-btn-disabled-border-color: #212529}.btn-outline-primary{--bs-btn-color: #0d6efd;--bs-btn-border-color: #0d6efd;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #0d6efd;--bs-btn-hover-border-color: #0d6efd;--bs-btn-focus-shadow-rgb: 13, 110, 253;--bs-btn-active-color: #fff;--bs-btn-active-bg: #0d6efd;--bs-btn-active-border-color: #0d6efd;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0d6efd;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0d6efd;--bs-gradient: none}.btn-outline-secondary{--bs-btn-color: #6c757d;--bs-btn-border-color: #6c757d;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #6c757d;--bs-btn-hover-border-color: #6c757d;--bs-btn-focus-shadow-rgb: 108, 117, 125;--bs-btn-active-color: #fff;--bs-btn-active-bg: #6c757d;--bs-btn-active-border-color: #6c757d;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #6c757d;--bs-gradient: none}.btn-outline-success{--bs-btn-color: #198754;--bs-btn-border-color: #198754;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #198754;--bs-btn-hover-border-color: #198754;--bs-btn-focus-shadow-rgb: 25, 135, 84;--bs-btn-active-color: #fff;--bs-btn-active-bg: #198754;--bs-btn-active-border-color: #198754;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #198754;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #198754;--bs-gradient: none}.btn-outline-info{--bs-btn-color: #0dcaf0;--bs-btn-border-color: #0dcaf0;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #0dcaf0;--bs-btn-hover-border-color: #0dcaf0;--bs-btn-focus-shadow-rgb: 13, 202, 240;--bs-btn-active-color: #000;--bs-btn-active-bg: #0dcaf0;--bs-btn-active-border-color: #0dcaf0;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #0dcaf0;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #0dcaf0;--bs-gradient: none}.btn-outline-warning{--bs-btn-color: #ffc107;--bs-btn-border-color: #ffc107;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #ffc107;--bs-btn-hover-border-color: #ffc107;--bs-btn-focus-shadow-rgb: 255, 193, 7;--bs-btn-active-color: #000;--bs-btn-active-bg: #ffc107;--bs-btn-active-border-color: #ffc107;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #ffc107;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #ffc107;--bs-gradient: none}.btn-outline-danger{--bs-btn-color: #dc3545;--bs-btn-border-color: #dc3545;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #dc3545;--bs-btn-hover-border-color: #dc3545;--bs-btn-focus-shadow-rgb: 220, 53, 69;--bs-btn-active-color: #fff;--bs-btn-active-bg: #dc3545;--bs-btn-active-border-color: #dc3545;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #dc3545;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #dc3545;--bs-gradient: none}.btn-outline-light{--bs-btn-color: #f8f9fa;--bs-btn-border-color: #f8f9fa;--bs-btn-hover-color: #000;--bs-btn-hover-bg: #f8f9fa;--bs-btn-hover-border-color: #f8f9fa;--bs-btn-focus-shadow-rgb: 248, 249, 250;--bs-btn-active-color: #000;--bs-btn-active-bg: #f8f9fa;--bs-btn-active-border-color: #f8f9fa;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #f8f9fa;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #f8f9fa;--bs-gradient: none}.btn-outline-dark{--bs-btn-color: #212529;--bs-btn-border-color: #212529;--bs-btn-hover-color: #fff;--bs-btn-hover-bg: #212529;--bs-btn-hover-border-color: #212529;--bs-btn-focus-shadow-rgb: 33, 37, 41;--bs-btn-active-color: #fff;--bs-btn-active-bg: #212529;--bs-btn-active-border-color: #212529;--bs-btn-active-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);--bs-btn-disabled-color: #212529;--bs-btn-disabled-bg: transparent;--bs-btn-disabled-border-color: #212529;--bs-gradient: none}.btn-link{--bs-btn-font-weight: 400;--bs-btn-color: var(--bs-link-color);--bs-btn-bg: transparent;--bs-btn-border-color: transparent;--bs-btn-hover-color: var(--bs-link-hover-color);--bs-btn-hover-border-color: transparent;--bs-btn-active-color: var(--bs-link-hover-color);--bs-btn-active-border-color: transparent;--bs-btn-disabled-color: #6c757d;--bs-btn-disabled-border-color: transparent;--bs-btn-box-shadow: 0 0 0 #000;--bs-btn-focus-shadow-rgb: 49, 132, 253;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-lg,.btn-group-lg>.btn{--bs-btn-padding-y: .5rem;--bs-btn-padding-x: 1rem;--bs-btn-font-size: 1.25rem;--bs-btn-border-radius: var(--bs-border-radius-lg)}.btn-sm,.btn-group-sm>.btn{--bs-btn-padding-y: .25rem;--bs-btn-padding-x: .5rem;--bs-btn-font-size: .875rem;--bs-btn-border-radius: var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media(prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart,.dropup-center,.dropdown-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex: 1000;--bs-dropdown-min-width: 10rem;--bs-dropdown-padding-x: 0;--bs-dropdown-padding-y: .5rem;--bs-dropdown-spacer: .125rem;--bs-dropdown-font-size: 1rem;--bs-dropdown-color: var(--bs-body-color);--bs-dropdown-bg: var(--bs-body-bg);--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-border-radius: var(--bs-border-radius);--bs-dropdown-border-width: var(--bs-border-width);--bs-dropdown-inner-border-radius: calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y: .5rem;--bs-dropdown-box-shadow: var(--bs-box-shadow);--bs-dropdown-link-color: var(--bs-body-color);--bs-dropdown-link-hover-color: var(--bs-body-color);--bs-dropdown-link-hover-bg: var(--bs-tertiary-bg);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: var(--bs-tertiary-color);--bs-dropdown-item-padding-x: 1rem;--bs-dropdown-item-padding-y: .25rem;--bs-dropdown-header-color: #6c757d;--bs-dropdown-header-padding-x: 1rem;--bs-dropdown-header-padding-y: .5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);border-radius:var(--bs-dropdown-border-radius)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width:576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width:768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width:992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width:1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width:1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle:after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle:after{display:none}.dropstart .dropdown-toggle:before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty:after{margin-left:0}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:400;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0;border-radius:var(--bs-dropdown-item-border-radius, 0)}.dropdown-item:hover,.dropdown-item:focus{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color: #dee2e6;--bs-dropdown-bg: #343a40;--bs-dropdown-border-color: var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color: #dee2e6;--bs-dropdown-link-hover-color: #fff;--bs-dropdown-divider-bg: var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg: rgba(255, 255, 255, .15);--bs-dropdown-link-active-color: #fff;--bs-dropdown-link-active-bg: #0d6efd;--bs-dropdown-link-disabled-color: #adb5bd;--bs-dropdown-header-color: #adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group{border-radius:var(--bs-border-radius)}.btn-group>:not(.btn-check:first-child)+.btn,.btn-group>.btn-group:not(:first-child){margin-left:calc(-1 * var(--bs-border-width))}.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.btn-group>.btn.dropdown-toggle-split:first-child,.btn-group>.btn-group:not(:last-child)>.btn{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn,.btn-group>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after,.dropend .dropdown-toggle-split:after{margin-left:0}.dropstart .dropdown-toggle-split:before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:calc(-1 * var(--bs-border-width))}.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle),.btn-group-vertical>.btn-group:not(:last-child)>.btn{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:nth-child(n+3),.btn-group-vertical>:not(.btn-check)+.btn,.btn-group-vertical>.btn-group:not(:first-child)>.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{--bs-nav-link-padding-x: 1rem;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-link-color);--bs-nav-link-hover-color: var(--bs-link-hover-color);--bs-nav-link-disabled-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:none;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem #0d6efd40}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width: var(--bs-border-width);--bs-nav-tabs-border-color: var(--bs-border-color);--bs-nav-tabs-border-radius: var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color: var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color: var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg: var(--bs-body-bg);--bs-nav-tabs-link-active-border-color: var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent;border-top-left-radius:var(--bs-nav-tabs-border-radius);border-top-right-radius:var(--bs-nav-tabs-border-radius)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width));border-top-left-radius:0;border-top-right-radius:0}.nav-pills{--bs-nav-pills-border-radius: var(--bs-border-radius);--bs-nav-pills-link-active-color: #fff;--bs-nav-pills-link-active-bg: #0d6efd}.nav-pills .nav-link{border-radius:var(--bs-nav-pills-border-radius)}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap: 1rem;--bs-nav-underline-border-width: .125rem;--bs-nav-underline-link-active-color: var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:hover,.nav-underline .nav-link:focus{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:700;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-grow:1;flex-basis:0;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x: 0;--bs-navbar-padding-y: .5rem;--bs-navbar-color: rgba(var(--bs-emphasis-color-rgb), .65);--bs-navbar-hover-color: rgba(var(--bs-emphasis-color-rgb), .8);--bs-navbar-disabled-color: rgba(var(--bs-emphasis-color-rgb), .3);--bs-navbar-active-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-padding-y: .3125rem;--bs-navbar-brand-margin-end: 1rem;--bs-navbar-brand-font-size: 1.25rem;--bs-navbar-brand-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-brand-hover-color: rgba(var(--bs-emphasis-color-rgb), 1);--bs-navbar-nav-link-padding-x: .5rem;--bs-navbar-toggler-padding-y: .25rem;--bs-navbar-toggler-padding-x: .75rem;--bs-navbar-toggler-font-size: 1.25rem;--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2833, 37, 41, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color: rgba(var(--bs-emphasis-color-rgb), .15);--bs-navbar-toggler-border-radius: var(--bs-border-radius);--bs-navbar-toggler-focus-width: .25rem;--bs-navbar-toggler-transition: box-shadow .15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-sm,.navbar>.container-md,.navbar>.container-lg,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:hover,.navbar-brand:focus{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x: 0;--bs-nav-link-padding-y: .5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color: var(--bs-navbar-color);--bs-nav-link-hover-color: var(--bs-navbar-hover-color);--bs-nav-link-disabled-color: var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:hover,.navbar-text a:focus{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-grow:1;flex-basis:100%;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);border-radius:var(--bs-navbar-toggler-border-radius);transition:var(--bs-navbar-toggler-transition)}@media(prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media(min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color: rgba(255, 255, 255, .55);--bs-navbar-hover-color: rgba(255, 255, 255, .75);--bs-navbar-disabled-color: rgba(255, 255, 255, .25);--bs-navbar-active-color: #fff;--bs-navbar-brand-color: #fff;--bs-navbar-brand-hover-color: #fff;--bs-navbar-toggler-border-color: rgba(255, 255, 255, .1);--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y: 1rem;--bs-card-spacer-x: 1rem;--bs-card-title-spacer-y: .5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width: var(--bs-border-width);--bs-card-border-color: var(--bs-border-color-translucent);--bs-card-border-radius: var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y: .5rem;--bs-card-cap-padding-x: 1rem;--bs-card-cap-bg: rgba(var(--bs-body-color-rgb), .03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg: var(--bs-body-bg);--bs-card-img-overlay-padding: 1rem;--bs-card-group-margin: .75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color);border-radius:var(--bs-card-border-radius)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0;border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card>.list-group:last-child{border-bottom-width:0;border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header:first-child{border-radius:var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius) 0 0}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer:last-child{border-radius:0 0 var(--bs-card-inner-border-radius) var(--bs-card-inner-border-radius)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;inset:0;padding:var(--bs-card-img-overlay-padding);border-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-img,.card-img-top{border-top-left-radius:var(--bs-card-inner-border-radius);border-top-right-radius:var(--bs-card-inner-border-radius)}.card-img,.card-img-bottom{border-bottom-right-radius:var(--bs-card-inner-border-radius);border-bottom-left-radius:var(--bs-card-inner-border-radius)}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media(min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:not(:last-child)>.card-img-top,.card-group>.card:not(:last-child)>.card-header{border-top-right-radius:0}.card-group>.card:not(:last-child)>.card-img-bottom,.card-group>.card:not(:last-child)>.card-footer{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:not(:first-child)>.card-img-top,.card-group>.card:not(:first-child)>.card-header{border-top-left-radius:0}.card-group>.card:not(:first-child)>.card-img-bottom,.card-group>.card:not(:first-child)>.card-footer{border-bottom-left-radius:0}}.accordion{--bs-accordion-color: var(--bs-body-color);--bs-accordion-bg: var(--bs-body-bg);--bs-accordion-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out, border-radius .15s ease;--bs-accordion-border-color: var(--bs-border-color);--bs-accordion-border-width: var(--bs-border-width);--bs-accordion-border-radius: var(--bs-border-radius);--bs-accordion-inner-border-radius: calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x: 1.25rem;--bs-accordion-btn-padding-y: 1rem;--bs-accordion-btn-color: var(--bs-body-color);--bs-accordion-btn-bg: var(--bs-accordion-bg);--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23212529' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width: 1.25rem;--bs-accordion-btn-icon-transform: rotate(-180deg);--bs-accordion-btn-icon-transition: transform .2s ease-in-out;--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='rgb%285.2, 44, 101.2%29' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='m2 5 6 6 6-6'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-accordion-body-padding-x: 1.25rem;--bs-accordion-body-padding-y: 1rem;--bs-accordion-active-color: var(--bs-primary-text-emphasis);--bs-accordion-active-bg: var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;border-radius:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media(prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed):after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button:after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media(prefers-reduced-motion:reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:first-of-type{border-top-left-radius:var(--bs-accordion-border-radius);border-top-right-radius:var(--bs-accordion-border-radius)}.accordion-item:first-of-type>.accordion-header .accordion-button{border-top-left-radius:var(--bs-accordion-inner-border-radius);border-top-right-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-item:last-of-type>.accordion-header .accordion-button.collapsed{border-bottom-right-radius:var(--bs-accordion-inner-border-radius);border-bottom-left-radius:var(--bs-accordion-inner-border-radius)}.accordion-item:last-of-type>.accordion-collapse{border-bottom-right-radius:var(--bs-accordion-border-radius);border-bottom-left-radius:var(--bs-accordion-border-radius)}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0;border-radius:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}.accordion-flush>.accordion-item>.accordion-collapse,.accordion-flush>.accordion-item>.accordion-header .accordion-button,.accordion-flush>.accordion-item>.accordion-header .accordion-button.collapsed{border-radius:0}[data-bs-theme=dark] .accordion-button:after{--bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='rgb%28109.8, 168, 253.8%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='rgb%28109.8, 168, 253.8%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x: 0;--bs-breadcrumb-padding-y: 0;--bs-breadcrumb-margin-bottom: 1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color: var(--bs-secondary-color);--bs-breadcrumb-item-padding-x: .5rem;--bs-breadcrumb-item-active-color: var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg);border-radius:var(--bs-breadcrumb-border-radius)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item:before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x: .75rem;--bs-pagination-padding-y: .375rem;--bs-pagination-font-size: 1rem;--bs-pagination-color: var(--bs-link-color);--bs-pagination-bg: var(--bs-body-bg);--bs-pagination-border-width: var(--bs-border-width);--bs-pagination-border-color: var(--bs-border-color);--bs-pagination-border-radius: var(--bs-border-radius);--bs-pagination-hover-color: var(--bs-link-hover-color);--bs-pagination-hover-bg: var(--bs-tertiary-bg);--bs-pagination-hover-border-color: var(--bs-border-color);--bs-pagination-focus-color: var(--bs-link-hover-color);--bs-pagination-focus-bg: var(--bs-secondary-bg);--bs-pagination-focus-box-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-pagination-active-color: #fff;--bs-pagination-active-bg: #0d6efd;--bs-pagination-active-border-color: #0d6efd;--bs-pagination-disabled-color: var(--bs-secondary-color);--bs-pagination-disabled-bg: var(--bs-secondary-bg);--bs-pagination-disabled-border-color: var(--bs-border-color);display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.page-link.active,.active>.page-link{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.page-link.disabled,.disabled>.page-link{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(-1 * var(--bs-border-width))}.page-item:first-child .page-link{border-top-left-radius:var(--bs-pagination-border-radius);border-bottom-left-radius:var(--bs-pagination-border-radius)}.page-item:last-child .page-link{border-top-right-radius:var(--bs-pagination-border-radius);border-bottom-right-radius:var(--bs-pagination-border-radius)}.pagination-lg{--bs-pagination-padding-x: 1.5rem;--bs-pagination-padding-y: .75rem;--bs-pagination-font-size: 1.25rem;--bs-pagination-border-radius: var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x: .5rem;--bs-pagination-padding-y: .25rem;--bs-pagination-font-size: .875rem;--bs-pagination-border-radius: var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x: .65em;--bs-badge-padding-y: .35em;--bs-badge-font-size: .75em;--bs-badge-font-weight: 700;--bs-badge-color: #fff;--bs-badge-border-radius: var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:var(--bs-badge-border-radius)}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg: transparent;--bs-alert-padding-x: 1rem;--bs-alert-padding-y: 1rem;--bs-alert-margin-bottom: 1rem;--bs-alert-color: inherit;--bs-alert-border-color: transparent;--bs-alert-border: var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius: var(--bs-border-radius);--bs-alert-link-color: inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border);border-radius:var(--bs-alert-border-radius)}.alert-heading{color:inherit}.alert-link{font-weight:700;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color: var(--bs-primary-text-emphasis);--bs-alert-bg: var(--bs-primary-bg-subtle);--bs-alert-border-color: var(--bs-primary-border-subtle);--bs-alert-link-color: var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color: var(--bs-secondary-text-emphasis);--bs-alert-bg: var(--bs-secondary-bg-subtle);--bs-alert-border-color: var(--bs-secondary-border-subtle);--bs-alert-link-color: var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color: var(--bs-success-text-emphasis);--bs-alert-bg: var(--bs-success-bg-subtle);--bs-alert-border-color: var(--bs-success-border-subtle);--bs-alert-link-color: var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color: var(--bs-info-text-emphasis);--bs-alert-bg: var(--bs-info-bg-subtle);--bs-alert-border-color: var(--bs-info-border-subtle);--bs-alert-link-color: var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color: var(--bs-warning-text-emphasis);--bs-alert-bg: var(--bs-warning-bg-subtle);--bs-alert-border-color: var(--bs-warning-border-subtle);--bs-alert-link-color: var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color: var(--bs-danger-text-emphasis);--bs-alert-bg: var(--bs-danger-bg-subtle);--bs-alert-border-color: var(--bs-danger-border-subtle);--bs-alert-link-color: var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color: var(--bs-light-text-emphasis);--bs-alert-bg: var(--bs-light-bg-subtle);--bs-alert-border-color: var(--bs-light-border-subtle);--bs-alert-link-color: var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color: var(--bs-dark-text-emphasis);--bs-alert-bg: var(--bs-dark-bg-subtle);--bs-alert-border-color: var(--bs-dark-border-subtle);--bs-alert-link-color: var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:var(--bs-progress-height)}}.progress,.progress-stacked{--bs-progress-height: 1rem;--bs-progress-font-size: .75rem;--bs-progress-bg: var(--bs-secondary-bg);--bs-progress-border-radius: var(--bs-border-radius);--bs-progress-box-shadow: var(--bs-box-shadow-inset);--bs-progress-bar-color: #fff;--bs-progress-bar-bg: #0d6efd;--bs-progress-bar-transition: width .6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg);border-radius:var(--bs-progress-border-radius)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media(prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color: var(--bs-body-color);--bs-list-group-bg: var(--bs-body-bg);--bs-list-group-border-color: var(--bs-border-color);--bs-list-group-border-width: var(--bs-border-width);--bs-list-group-border-radius: var(--bs-border-radius);--bs-list-group-item-padding-x: 1rem;--bs-list-group-item-padding-y: .5rem;--bs-list-group-action-color: var(--bs-secondary-color);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-tertiary-bg);--bs-list-group-action-active-color: var(--bs-body-color);--bs-list-group-action-active-bg: var(--bs-secondary-bg);--bs-list-group-disabled-color: var(--bs-secondary-color);--bs-list-group-disabled-bg: var(--bs-body-bg);--bs-list-group-active-color: #fff;--bs-list-group-active-bg: #0d6efd;--bs-list-group-active-border-color: #0d6efd;display:flex;flex-direction:column;padding-left:0;margin-bottom:0;border-radius:var(--bs-list-group-border-radius)}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-right-radius:inherit;border-bottom-left-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:not(.active):hover,.list-group-item-action:not(.active):focus{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:not(.active):active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media(min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media(min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child:not(:last-child){border-bottom-left-radius:var(--bs-list-group-border-radius);border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child:not(:first-child){border-top-right-radius:var(--bs-list-group-border-radius);border-bottom-left-radius:0}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color: var(--bs-primary-text-emphasis);--bs-list-group-bg: var(--bs-primary-bg-subtle);--bs-list-group-border-color: var(--bs-primary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-primary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-primary-border-subtle);--bs-list-group-active-color: var(--bs-primary-bg-subtle);--bs-list-group-active-bg: var(--bs-primary-text-emphasis);--bs-list-group-active-border-color: var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color: var(--bs-secondary-text-emphasis);--bs-list-group-bg: var(--bs-secondary-bg-subtle);--bs-list-group-border-color: var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-secondary-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-secondary-border-subtle);--bs-list-group-active-color: var(--bs-secondary-bg-subtle);--bs-list-group-active-bg: var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color: var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color: var(--bs-success-text-emphasis);--bs-list-group-bg: var(--bs-success-bg-subtle);--bs-list-group-border-color: var(--bs-success-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-success-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-success-border-subtle);--bs-list-group-active-color: var(--bs-success-bg-subtle);--bs-list-group-active-bg: var(--bs-success-text-emphasis);--bs-list-group-active-border-color: var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color: var(--bs-info-text-emphasis);--bs-list-group-bg: var(--bs-info-bg-subtle);--bs-list-group-border-color: var(--bs-info-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-info-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-info-border-subtle);--bs-list-group-active-color: var(--bs-info-bg-subtle);--bs-list-group-active-bg: var(--bs-info-text-emphasis);--bs-list-group-active-border-color: var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color: var(--bs-warning-text-emphasis);--bs-list-group-bg: var(--bs-warning-bg-subtle);--bs-list-group-border-color: var(--bs-warning-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-warning-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-warning-border-subtle);--bs-list-group-active-color: var(--bs-warning-bg-subtle);--bs-list-group-active-bg: var(--bs-warning-text-emphasis);--bs-list-group-active-border-color: var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color: var(--bs-danger-text-emphasis);--bs-list-group-bg: var(--bs-danger-bg-subtle);--bs-list-group-border-color: var(--bs-danger-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-danger-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-danger-border-subtle);--bs-list-group-active-color: var(--bs-danger-bg-subtle);--bs-list-group-active-bg: var(--bs-danger-text-emphasis);--bs-list-group-active-border-color: var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color: var(--bs-light-text-emphasis);--bs-list-group-bg: var(--bs-light-bg-subtle);--bs-list-group-border-color: var(--bs-light-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-light-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-light-border-subtle);--bs-list-group-active-color: var(--bs-light-bg-subtle);--bs-list-group-active-bg: var(--bs-light-text-emphasis);--bs-list-group-active-border-color: var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color: var(--bs-dark-text-emphasis);--bs-list-group-bg: var(--bs-dark-bg-subtle);--bs-list-group-border-color: var(--bs-dark-border-subtle);--bs-list-group-action-hover-color: var(--bs-emphasis-color);--bs-list-group-action-hover-bg: var(--bs-dark-border-subtle);--bs-list-group-action-active-color: var(--bs-emphasis-color);--bs-list-group-action-active-bg: var(--bs-dark-border-subtle);--bs-list-group-active-color: var(--bs-dark-bg-subtle);--bs-list-group-active-bg: var(--bs-dark-text-emphasis);--bs-list-group-active-border-color: var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color: #000;--bs-btn-close-bg: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/%3e%3c/svg%3e");--bs-btn-close-opacity: .5;--bs-btn-close-hover-opacity: .75;--bs-btn-close-focus-shadow: 0 0 0 .25rem rgba(13, 110, 253, .25);--bs-btn-close-focus-opacity: 1;--bs-btn-close-disabled-opacity: .25;box-sizing:content-box;width:1em;height:1em;padding:.25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;filter:var(--bs-btn-close-filter);border:0;border-radius:.375rem;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close:disabled,.btn-close.disabled{pointer-events:none;-webkit-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{--bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%)}:root,[data-bs-theme=light]{--bs-btn-close-filter: }[data-bs-theme=dark]{--bs-btn-close-filter: invert(1) grayscale(100%) brightness(200%)}.toast{--bs-toast-zindex: 1090;--bs-toast-padding-x: .75rem;--bs-toast-padding-y: .5rem;--bs-toast-spacing: 1.5rem;--bs-toast-max-width: 350px;--bs-toast-font-size: .875rem;--bs-toast-color: ;--bs-toast-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-border-width: var(--bs-border-width);--bs-toast-border-color: var(--bs-border-color-translucent);--bs-toast-border-radius: var(--bs-border-radius);--bs-toast-box-shadow: var(--bs-box-shadow);--bs-toast-header-color: var(--bs-secondary-color);--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), .85);--bs-toast-header-border-color: var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow);border-radius:var(--bs-toast-border-radius)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex: 1090;position:absolute;z-index:var(--bs-toast-zindex);width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color);border-top-left-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));border-top-right-radius:calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width))}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex: 1055;--bs-modal-width: 500px;--bs-modal-padding: 1rem;--bs-modal-margin: .5rem;--bs-modal-color: var(--bs-body-color);--bs-modal-bg: var(--bs-body-bg);--bs-modal-border-color: var(--bs-border-color-translucent);--bs-modal-border-width: var(--bs-border-width);--bs-modal-border-radius: var(--bs-border-radius-lg);--bs-modal-box-shadow: var(--bs-box-shadow-sm);--bs-modal-inner-border-radius: calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x: 1rem;--bs-modal-header-padding-y: 1rem;--bs-modal-header-padding: 1rem 1rem;--bs-modal-header-border-color: var(--bs-border-color);--bs-modal-header-border-width: var(--bs-border-width);--bs-modal-title-line-height: 1.5;--bs-modal-footer-gap: .5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color: var(--bs-border-color);--bs-modal-footer-border-width: var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transform:translateY(-50px);transition:transform .3s ease-out}@media(prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);border-radius:var(--bs-modal-border-radius);outline:0}.modal-backdrop{--bs-backdrop-zindex: 1050;--bs-backdrop-bg: #000;--bs-backdrop-opacity: .5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color);border-top-left-radius:var(--bs-modal-inner-border-radius);border-top-right-radius:var(--bs-modal-inner-border-radius)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin-top:calc(-.5 * var(--bs-modal-header-padding-y));margin-right:calc(-.5 * var(--bs-modal-header-padding-x));margin-bottom:calc(-.5 * var(--bs-modal-header-padding-y));margin-left:auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color);border-bottom-right-radius:var(--bs-modal-inner-border-radius);border-bottom-left-radius:var(--bs-modal-inner-border-radius)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media(min-width:576px){.modal{--bs-modal-margin: 1.75rem;--bs-modal-box-shadow: var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width: 300px}}@media(min-width:992px){.modal-lg,.modal-xl{--bs-modal-width: 800px}}@media(min-width:1200px){.modal-xl{--bs-modal-width: 1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen .modal-header,.modal-fullscreen .modal-footer{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-sm-down .modal-header,.modal-fullscreen-sm-down .modal-footer{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-md-down .modal-header,.modal-fullscreen-md-down .modal-footer{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-lg-down .modal-header,.modal-fullscreen-lg-down .modal-footer{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xl-down .modal-header,.modal-fullscreen-xl-down .modal-footer{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0;border-radius:0}.modal-fullscreen-xxl-down .modal-header,.modal-fullscreen-xxl-down .modal-footer{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex: 1080;--bs-tooltip-max-width: 200px;--bs-tooltip-padding-x: .5rem;--bs-tooltip-padding-y: .25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size: .875rem;--bs-tooltip-color: var(--bs-body-bg);--bs-tooltip-bg: var(--bs-emphasis-color);--bs-tooltip-border-radius: var(--bs-border-radius);--bs-tooltip-opacity: .9;--bs-tooltip-arrow-width: .8rem;--bs-tooltip-arrow-height: .4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow:before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-top .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-end .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-bottom .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-start .tooltip-arrow:before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg);border-radius:var(--bs-tooltip-border-radius)}.popover{--bs-popover-zindex: 1070;--bs-popover-max-width: 276px;--bs-popover-font-size: .875rem;--bs-popover-bg: var(--bs-body-bg);--bs-popover-border-width: var(--bs-border-width);--bs-popover-border-color: var(--bs-border-color-translucent);--bs-popover-border-radius: var(--bs-border-radius-lg);--bs-popover-inner-border-radius: calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow: var(--bs-box-shadow);--bs-popover-header-padding-x: 1rem;--bs-popover-header-padding-y: .5rem;--bs-popover-header-font-size: 1rem;--bs-popover-header-color: inherit;--bs-popover-header-bg: var(--bs-secondary-bg);--bs-popover-body-padding-x: 1rem;--bs-popover-body-padding-y: 1rem;--bs-popover-body-color: var(--bs-body-color);--bs-popover-arrow-width: 1rem;--bs-popover-arrow-height: .5rem;--bs-popover-arrow-border: var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-radius:var(--bs-popover-border-radius)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow:before,.popover .popover-arrow:after{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-top>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-top>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-end>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-end>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-bottom>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-bottom>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-bottom .popover-header:before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-start>.popover-arrow:before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-start>.popover-arrow:after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color);border-top-left-radius:var(--bs-popover-inner-border-radius);border-top-right-radius:var(--bs-popover-inner-border-radius)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner:after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translate(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translate(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;filter:var(--bs-carousel-control-icon-filter);border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion:reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:var(--bs-carousel-indicator-active-bg);background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:var(--bs-carousel-caption-color);text-align:center}.carousel-dark{--bs-carousel-indicator-active-bg: #000;--bs-carousel-caption-color: #000;--bs-carousel-control-icon-filter: invert(1) grayscale(100)}:root,[data-bs-theme=light]{--bs-carousel-indicator-active-bg: #fff;--bs-carousel-caption-color: #fff;--bs-carousel-control-icon-filter: }[data-bs-theme=dark]{--bs-carousel-indicator-active-bg: #000;--bs-carousel-caption-color: #000;--bs-carousel-control-icon-filter: invert(1) grayscale(100)}.spinner-grow,.spinner-border{display:inline-block;flex-shrink:0;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-border-width: .25em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem;--bs-spinner-border-width: .2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width: 2rem;--bs-spinner-height: 2rem;--bs-spinner-vertical-align: -.125em;--bs-spinner-animation-speed: .75s;--bs-spinner-animation-name: spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width: 1rem;--bs-spinner-height: 1rem}@media(prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed: 1.5s}}.offcanvas,.offcanvas-xxl,.offcanvas-xl,.offcanvas-lg,.offcanvas-md,.offcanvas-sm{--bs-offcanvas-zindex: 1045;--bs-offcanvas-width: 400px;--bs-offcanvas-height: 30vh;--bs-offcanvas-padding-x: 1rem;--bs-offcanvas-padding-y: 1rem;--bs-offcanvas-color: var(--bs-body-color);--bs-offcanvas-bg: var(--bs-body-bg);--bs-offcanvas-border-width: var(--bs-border-width);--bs-offcanvas-border-color: var(--bs-border-color-translucent);--bs-offcanvas-box-shadow: var(--bs-box-shadow-sm);--bs-offcanvas-transition: transform .3s ease-in-out;--bs-offcanvas-title-line-height: 1.5}@media(max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width:575.98px)and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media(max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.showing,.offcanvas-sm.show:not(.hiding){transform:none}.offcanvas-sm.showing,.offcanvas-sm.hiding,.offcanvas-sm.show{visibility:visible}}@media(min-width:576px){.offcanvas-sm{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media(max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width:767.98px)and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media(max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.showing,.offcanvas-md.show:not(.hiding){transform:none}.offcanvas-md.showing,.offcanvas-md.hiding,.offcanvas-md.show{visibility:visible}}@media(min-width:768px){.offcanvas-md{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media(max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width:991.98px)and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media(max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.showing,.offcanvas-lg.show:not(.hiding){transform:none}.offcanvas-lg.showing,.offcanvas-lg.hiding,.offcanvas-lg.show{visibility:visible}}@media(min-width:992px){.offcanvas-lg{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media(max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width:1199.98px)and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media(max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.showing,.offcanvas-xl.show:not(.hiding){transform:none}.offcanvas-xl.showing,.offcanvas-xl.hiding,.offcanvas-xl.show{visibility:visible}}@media(min-width:1200px){.offcanvas-xl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media(max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media(max-width:1399.98px)and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media(max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.showing,.offcanvas-xxl.show:not(.hiding){transform:none}.offcanvas-xxl.showing,.offcanvas-xxl.hiding,.offcanvas-xxl.show{visibility:visible}}@media(min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height: auto;--bs-offcanvas-border-width: 0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media(prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translate(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.showing,.offcanvas.show:not(.hiding){transform:none}.offcanvas.showing,.offcanvas.hiding,.offcanvas.show{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin-top:calc(-.5 * var(--bs-offcanvas-padding-y));margin-right:calc(-.5 * var(--bs-offcanvas-padding-x));margin-bottom:calc(-.5 * var(--bs-offcanvas-padding-y));margin-left:auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn:before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,#000c,#000 95%);mask-image:linear-gradient(130deg,#000 55%,#000c,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{to{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix:after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-secondary{color:#fff!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-info{color:#000!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity, 1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity, 1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-primary:hover,.link-primary:focus{color:RGBA(10,88,202,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(10,88,202,var(--bs-link-underline-opacity, 1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity, 1))!important}.link-secondary:hover,.link-secondary:focus{color:RGBA(86,94,100,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(86,94,100,var(--bs-link-underline-opacity, 1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity, 1))!important}.link-success:hover,.link-success:focus{color:RGBA(20,108,67,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(20,108,67,var(--bs-link-underline-opacity, 1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity, 1))!important}.link-info:hover,.link-info:focus{color:RGBA(61,213,243,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(61,213,243,var(--bs-link-underline-opacity, 1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity, 1))!important}.link-warning:hover,.link-warning:focus{color:RGBA(255,205,57,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(255,205,57,var(--bs-link-underline-opacity, 1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity, 1))!important}.link-danger:hover,.link-danger:focus{color:RGBA(176,42,55,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(176,42,55,var(--bs-link-underline-opacity, 1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity, 1))!important}.link-light:hover,.link-light:focus{color:RGBA(249,250,251,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(249,250,251,var(--bs-link-underline-opacity, 1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity, 1))!important}.link-dark:hover,.link-dark:focus{color:RGBA(26,30,33,var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(26,30,33,var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, 1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-body-emphasis:hover,.link-body-emphasis:focus{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity, .75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity, .75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x, 0) var(--bs-focus-ring-y, 0) var(--bs-focus-ring-blur, 0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity, .5));text-underline-offset:.25em;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media(prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:hover>.bi,.icon-link-hover:focus-visible>.bi{transform:var(--bs-icon-link-transform, translate3d(.25em, 0, 0))}.ratio{position:relative;width:100%}.ratio:before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}.sticky-bottom{position:sticky;bottom:0;z-index:1020}@media(min-width:576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width:768px){.sticky-md-top{position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width:992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width:1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:sticky;bottom:0;z-index:1020}}@media(min-width:1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden:not(caption),.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption){position:absolute!important}.visually-hidden *,.visually-hidden-focusable:not(:focus):not(:focus-within) *{overflow:hidden!important}.stretched-link:after{position:absolute;inset:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{object-fit:contain!important}.object-fit-cover{object-fit:cover!important}.object-fit-fill{object-fit:fill!important}.object-fit-scale{object-fit:scale-down!important}.object-fit-none{object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color: rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color: rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color: rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color: rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color: rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color: rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color: rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color: rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translate(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity: 1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity: 1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity: 1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity: 1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity: 1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity: 1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity: 1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity: 1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity: 1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity: 1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity: .1}.border-opacity-25{--bs-border-opacity: .25}.border-opacity-50{--bs-border-opacity: .5}.border-opacity-75{--bs-border-opacity: .75}.border-opacity-100{--bs-border-opacity: 1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{column-gap:0!important}.column-gap-1{column-gap:.25rem!important}.column-gap-2{column-gap:.5rem!important}.column-gap-3{column-gap:1rem!important}.column-gap-4{column-gap:1.5rem!important}.column-gap-5{column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.375rem + 1.5vw)!important}.fs-2{font-size:calc(1.325rem + .9vw)!important}.fs-3{font-size:calc(1.3rem + .6vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:300!important}.fw-normal{font-weight:400!important}.fw-medium{font-weight:500!important}.fw-semibold{font-weight:600!important}.fw-bold{font-weight:700!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity: 1;color:#00000080!important}.text-white-50{--bs-text-opacity: 1;color:#ffffff80!important}.text-body-secondary{--bs-text-opacity: 1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity: 1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity: 1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity: 1;color:inherit!important}.text-opacity-25{--bs-text-opacity: .25}.text-opacity-50{--bs-text-opacity: .5}.text-opacity-75{--bs-text-opacity: .75}.text-opacity-100{--bs-text-opacity: 1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10,.link-opacity-10-hover:hover{--bs-link-opacity: .1}.link-opacity-25,.link-opacity-25-hover:hover{--bs-link-opacity: .25}.link-opacity-50,.link-opacity-50-hover:hover{--bs-link-opacity: .5}.link-opacity-75,.link-opacity-75-hover:hover{--bs-link-opacity: .75}.link-opacity-100,.link-opacity-100-hover:hover{--bs-link-opacity: 1}.link-offset-1,.link-offset-1-hover:hover{text-underline-offset:.125em!important}.link-offset-2,.link-offset-2-hover:hover{text-underline-offset:.25em!important}.link-offset-3,.link-offset-3-hover:hover{text-underline-offset:.375em!important}.link-underline-primary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity: 1;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity, 1))!important}.link-underline-opacity-0,.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity: 0}.link-underline-opacity-10,.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity: .1}.link-underline-opacity-25,.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity: .25}.link-underline-opacity-50,.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity: .5}.link-underline-opacity-75,.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity: .75}.link-underline-opacity-100,.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity: 1}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity: 1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity: .1}.bg-opacity-25{--bs-bg-opacity: .25}.bg-opacity-50{--bs-bg-opacity: .5}.bg-opacity-75{--bs-bg-opacity: .75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media(min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{object-fit:contain!important}.object-fit-sm-cover{object-fit:cover!important}.object-fit-sm-fill{object-fit:fill!important}.object-fit-sm-scale{object-fit:scale-down!important}.object-fit-sm-none{object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{column-gap:0!important}.column-gap-sm-1{column-gap:.25rem!important}.column-gap-sm-2{column-gap:.5rem!important}.column-gap-sm-3{column-gap:1rem!important}.column-gap-sm-4{column-gap:1.5rem!important}.column-gap-sm-5{column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media(min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{object-fit:contain!important}.object-fit-md-cover{object-fit:cover!important}.object-fit-md-fill{object-fit:fill!important}.object-fit-md-scale{object-fit:scale-down!important}.object-fit-md-none{object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{column-gap:0!important}.column-gap-md-1{column-gap:.25rem!important}.column-gap-md-2{column-gap:.5rem!important}.column-gap-md-3{column-gap:1rem!important}.column-gap-md-4{column-gap:1.5rem!important}.column-gap-md-5{column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media(min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{object-fit:contain!important}.object-fit-lg-cover{object-fit:cover!important}.object-fit-lg-fill{object-fit:fill!important}.object-fit-lg-scale{object-fit:scale-down!important}.object-fit-lg-none{object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{column-gap:0!important}.column-gap-lg-1{column-gap:.25rem!important}.column-gap-lg-2{column-gap:.5rem!important}.column-gap-lg-3{column-gap:1rem!important}.column-gap-lg-4{column-gap:1.5rem!important}.column-gap-lg-5{column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media(min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{object-fit:contain!important}.object-fit-xl-cover{object-fit:cover!important}.object-fit-xl-fill{object-fit:fill!important}.object-fit-xl-scale{object-fit:scale-down!important}.object-fit-xl-none{object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{column-gap:0!important}.column-gap-xl-1{column-gap:.25rem!important}.column-gap-xl-2{column-gap:.5rem!important}.column-gap-xl-3{column-gap:1rem!important}.column-gap-xl-4{column-gap:1.5rem!important}.column-gap-xl-5{column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media(min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{object-fit:contain!important}.object-fit-xxl-cover{object-fit:cover!important}.object-fit-xxl-fill{object-fit:fill!important}.object-fit-xxl-scale{object-fit:scale-down!important}.object-fit-xxl-none{object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{column-gap:0!important}.column-gap-xxl-1{column-gap:.25rem!important}.column-gap-xxl-2{column-gap:.5rem!important}.column-gap-xxl-3{column-gap:1rem!important}.column-gap-xxl-4{column-gap:1.5rem!important}.column-gap-xxl-5{column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media(min-width:1200px){.fs-1{font-size:2.5rem!important}.fs-2{font-size:2rem!important}.fs-3{font-size:1.75rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}}:root{color-scheme:dark}html,body{min-height:100%}body{margin:0;font-family:Space Grotesk,system-ui,sans-serif;background:radial-gradient(circle at top left,rgba(85,168,255,.3),transparent 32%),radial-gradient(circle at top right,rgba(129,244,215,.18),transparent 24%),linear-gradient(160deg,#06111d,#0d1b2c 48%,#02060b)}button,input,textarea{font:inherit} diff --git a/apple-client/WebApp/prerendered-routes.json b/apple-client/WebApp/prerendered-routes.json new file mode 100644 index 0000000..3226541 --- /dev/null +++ b/apple-client/WebApp/prerendered-routes.json @@ -0,0 +1,3 @@ +{ + "routes": {} +} \ No newline at end of file diff --git a/apple-client/project.yml b/apple-client/project.yml new file mode 100644 index 0000000..4ed08a4 --- /dev/null +++ b/apple-client/project.yml @@ -0,0 +1,44 @@ +name: PrivateChatApple +options: + bundleIdPrefix: com.privatechat +settings: + base: + SWIFT_VERSION: 6.0 + PRODUCT_BUNDLE_IDENTIFIER: com.privatechat.apple + MARKETING_VERSION: 1.0 + CURRENT_PROJECT_VERSION: 1 + GENERATE_INFOPLIST_FILE: YES + IPHONEOS_DEPLOYMENT_TARGET: 17.4 + MACOSX_DEPLOYMENT_TARGET: 14.4 + CODE_SIGN_STYLE: Automatic +targets: + PrivateChatApple: + type: application + supportedDestinations: + - iOS + - macOS + sources: + - path: Sources/App + settings: + base: + PRODUCT_NAME: PrivateChatApple + INFOPLIST_KEY_CFBundleDisplayName: PrivateChat + INFOPLIST_KEY_LSApplicationCategoryType: public.app-category.social-networking + INFOPLIST_KEY_ITSAppUsesNonExemptEncryption: NO + CODE_SIGNING_ALLOWED: NO + CODE_SIGNING_REQUIRED: NO + preBuildScripts: + - name: Build Embedded Angular Client + script: | + set -euo pipefail + cd "$SRCROOT/.." + mkdir -p "$SRCROOT/WebApp" + npm run build --prefix client -- --base-href ./ --output-path "$SRCROOT/WebApp" + postBuildScripts: + - name: Copy Embedded Angular Client + script: | + set -euo pipefail + DESTINATION="$TARGET_BUILD_DIR/$UNLOCALIZED_RESOURCES_FOLDER_PATH/WebApp" + rm -rf "$DESTINATION" + mkdir -p "$DESTINATION" + cp -R "$SRCROOT/WebApp/." "$DESTINATION" diff --git a/client/.editorconfig b/client/.editorconfig new file mode 100644 index 0000000..f166060 --- /dev/null +++ b/client/.editorconfig @@ -0,0 +1,17 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single +ij_typescript_use_double_quotes = false + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/client/.prettierrc b/client/.prettierrc new file mode 100644 index 0000000..d6c16d7 --- /dev/null +++ b/client/.prettierrc @@ -0,0 +1,12 @@ +{ + "printWidth": 100, + "singleQuote": true, + "overrides": [ + { + "files": "*.html", + "options": { + "parser": "angular" + } + } + ] +} diff --git a/client/.vscode/extensions.json b/client/.vscode/extensions.json new file mode 100644 index 0000000..77b3745 --- /dev/null +++ b/client/.vscode/extensions.json @@ -0,0 +1,4 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 + "recommendations": ["angular.ng-template"] +} diff --git a/client/.vscode/launch.json b/client/.vscode/launch.json new file mode 100644 index 0000000..925af83 --- /dev/null +++ b/client/.vscode/launch.json @@ -0,0 +1,20 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "ng serve", + "type": "chrome", + "request": "launch", + "preLaunchTask": "npm: start", + "url": "http://localhost:4200/" + }, + { + "name": "ng test", + "type": "chrome", + "request": "launch", + "preLaunchTask": "npm: test", + "url": "http://localhost:9876/debug.html" + } + ] +} diff --git a/client/.vscode/mcp.json b/client/.vscode/mcp.json new file mode 100644 index 0000000..956af8c --- /dev/null +++ b/client/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + // For more information, visit: https://angular.dev/ai/mcp + "servers": { + "angular-cli": { + "command": "npx", + "args": ["-y", "@angular/cli", "mcp"] + } + } +} diff --git a/client/.vscode/tasks.json b/client/.vscode/tasks.json new file mode 100644 index 0000000..244306f --- /dev/null +++ b/client/.vscode/tasks.json @@ -0,0 +1,42 @@ +{ + // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "start", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "Changes detected" + }, + "endsPattern": { + "regexp": "bundle generation (complete|failed)" + } + } + } + }, + { + "type": "npm", + "script": "test", + "isBackground": true, + "problemMatcher": { + "owner": "typescript", + "pattern": "$tsc", + "background": { + "activeOnStart": true, + "beginsPattern": { + "regexp": "Changes detected" + }, + "endsPattern": { + "regexp": "bundle generation (complete|failed)" + } + } + } + } + ] +} diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..c997e1f --- /dev/null +++ b/client/README.md @@ -0,0 +1,59 @@ +# Client + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 21.2.1. + +## Development server + +To start a local development server, run: + +```bash +ng serve +``` + +Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the project run: + +```bash +ng build +``` + +This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed. + +## Running unit tests + +To execute unit tests with the [Vitest](https://vitest.dev/) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/client/angular.json b/client/angular.json new file mode 100644 index 0000000..7d7e545 --- /dev/null +++ b/client/angular.json @@ -0,0 +1,97 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "cli": { + "packageManager": "npm" + }, + "newProjectRoot": "projects", + "projects": { + "client": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss", + "skipTests": true + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:interceptor": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:resolver": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "src/main.ts", + "tsConfig": "tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "public" + } + ], + "styles": [ + "src/styles.scss" + ] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "700kB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "client:build:production" + }, + "development": { + "buildTarget": "client:build:development" + } + }, + "defaultConfiguration": "development" + } + } + } + } +} diff --git a/client/package-lock.json b/client/package-lock.json new file mode 100644 index 0000000..e921101 --- /dev/null +++ b/client/package-lock.json @@ -0,0 +1,7784 @@ +{ + "name": "client", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "client", + "version": "0.0.0", + "dependencies": { + "@angular/common": "^21.2.0", + "@angular/compiler": "^21.2.0", + "@angular/core": "^21.2.0", + "@angular/forms": "^21.2.0", + "@angular/platform-browser": "^21.2.0", + "@angular/router": "^21.2.0", + "bootstrap": "^5.3.8", + "rxjs": "~7.8.0", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^21.2.1", + "@angular/cli": "^21.2.1", + "@angular/compiler-cli": "^21.2.0", + "dotenv": "^17.3.1", + "prettier": "^3.8.1", + "typescript": "~5.9.2" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", + "integrity": "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.1.tgz", + "integrity": "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.1.tgz", + "integrity": "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.1.tgz", + "integrity": "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.1.tgz", + "integrity": "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.1.tgz", + "integrity": "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.1.tgz", + "integrity": "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.1.tgz", + "integrity": "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.1.tgz", + "integrity": "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.48.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.1.tgz", + "integrity": "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.1.tgz", + "integrity": "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.1.tgz", + "integrity": "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.1.tgz", + "integrity": "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.1.tgz", + "integrity": "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/client-common": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.2102.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.1.tgz", + "integrity": "sha512-x2Qqz6oLYvEh9UBUG0AP1A4zROO/VP+k+zM9+4c2uZw1uqoBQFmutqgzncjVU7cR9R0RApgx9JRZHDFtQru68w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.1", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.1.tgz", + "integrity": "sha512-TpXGjERqVPN8EPt7LdmWAwh0oNQ/6uWFutzGZiXhJy81n1zb1O1XrqhRAmvP1cAo5O+na6IV2JkkCmxL6F8GUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.18.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.3", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.1.tgz", + "integrity": "sha512-CWoamHaasAHMjHcYqxbj0tMnoXxdGotcAz2SpiuWtH28Lnf5xfbTaJn/lwdMP8Wdh4tgA+uYh2l45A5auCwmkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.1", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.21", + "ora": "9.3.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/build": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.1.tgz", + "integrity": "sha512-cUpLNHJp9taII/FOcJHHfQYlMcZSRaf6eIxgSNS6Xfx1CeGoJNDN+J8+GFk+H1CPJt1EvbfyZ+dE5DbsgTD/QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.2102.1", + "@babel/core": "7.29.0", + "@babel/helper-annotate-as-pure": "7.27.3", + "@babel/helper-split-export-declaration": "7.24.7", + "@inquirer/confirm": "5.1.21", + "@vitejs/plugin-basic-ssl": "2.1.4", + "beasties": "0.4.1", + "browserslist": "^4.26.0", + "esbuild": "0.27.3", + "https-proxy-agent": "7.0.6", + "istanbul-lib-instrument": "6.0.3", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "magic-string": "0.30.21", + "mrmime": "2.0.1", + "parse5-html-rewriting-stream": "8.0.0", + "picomatch": "4.0.3", + "piscina": "5.1.4", + "rolldown": "1.0.0-rc.4", + "sass": "1.97.3", + "semver": "7.7.4", + "source-map-support": "0.5.21", + "tinyglobby": "0.2.15", + "undici": "7.22.0", + "vite": "7.3.1", + "watchpack": "2.5.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "lmdb": "3.5.1" + }, + "peerDependencies": { + "@angular/compiler": "^21.0.0", + "@angular/compiler-cli": "^21.0.0", + "@angular/core": "^21.0.0", + "@angular/localize": "^21.0.0", + "@angular/platform-browser": "^21.0.0", + "@angular/platform-server": "^21.0.0", + "@angular/service-worker": "^21.0.0", + "@angular/ssr": "^21.2.1", + "karma": "^6.4.0", + "less": "^4.2.0", + "ng-packagr": "^21.0.0", + "postcss": "^8.4.0", + "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "tslib": "^2.3.0", + "typescript": ">=5.9 <6.0", + "vitest": "^4.0.8" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + }, + "@angular/localize": { + "optional": true + }, + "@angular/platform-browser": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@angular/ssr": { + "optional": true + }, + "karma": { + "optional": true + }, + "less": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tailwindcss": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@angular/cli": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.1.tgz", + "integrity": "sha512-5SRfMTgwFj1zXOpfeZWHsxZBni0J4Xz7/CbewG47D6DmbstOrSdgt6eNzJ62R650t0G9dpri2YvToZgImtbjOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/architect": "0.2102.1", + "@angular-devkit/core": "21.2.1", + "@angular-devkit/schematics": "21.2.1", + "@inquirer/prompts": "7.10.1", + "@listr2/prompt-adapter-inquirer": "3.0.5", + "@modelcontextprotocol/sdk": "1.26.0", + "@schematics/angular": "21.2.1", + "@yarnpkg/lockfile": "1.1.0", + "algoliasearch": "5.48.1", + "ini": "6.0.0", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "npm-package-arg": "13.0.2", + "pacote": "21.3.1", + "parse5-html-rewriting-stream": "8.0.0", + "semver": "7.7.4", + "yargs": "18.0.0", + "zod": "4.3.6" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/common": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.1.tgz", + "integrity": "sha512-xhv2i1Q9s1kpGbGsfj+o36+XUC/TQLcZyRuRxn3GwaN7Rv34FabC88ycpvoE+sW/txj4JRx9yPA0dRSZjwZ+Gg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/core": "21.2.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.1.tgz", + "integrity": "sha512-FxWaSaii1vfHIFA+JksqQ8NGB2frfqCrs7Ju50a44kbwR4fmanfn/VsiS/CbwBp9vcyT/Br9X/jAG4RuK/U2nw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@angular/compiler-cli": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.1.tgz", + "integrity": "sha512-qYCWLGtEju4cDtYLi4ZzbwKoF0lcGs+Lc31kuESvAzYvWNgk2EUOtwWo8kbgpAzAwSYodtxW6Q90iWEwfU6elw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "7.29.0", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^5.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^18.0.0" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "21.2.1", + "typescript": ">=5.9 <6.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@angular/core": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.1.tgz", + "integrity": "sha512-pFTbg03s2ZI5cHNT+eWsGjwIIKiYkeAnodFbCAHjwFi9KCEYlTykFLjr9lcpGrBddfmAH7GE08Q73vgmsdcNHw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/compiler": "21.2.1", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0 || ~0.16.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } + } + }, + "node_modules/@angular/forms": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.1.tgz", + "integrity": "sha512-6aqOPk9xoa0dfeUDeEbhaiPhmt6MQrdn59qbGAomn9RMXA925TrHbJhSIkp9tXc2Fr4aJRi8zkD/cdXEc1IYeA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/common": "21.2.1", + "@angular/core": "21.2.1", + "@angular/platform-browser": "21.2.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.1.tgz", + "integrity": "sha512-k4SJLxIaLT26vLjLuFL+ho0BiG5PrdxEsjsXFC7w5iUhomeouzkHVTZ4t7gaLNKrdRD7QNtU4Faw0nL0yx0ZPQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/animations": "21.2.1", + "@angular/common": "21.2.1", + "@angular/core": "21.2.1" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/router": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.1.tgz", + "integrity": "sha512-FUKG+8ImQYxmlDUdAs7+VeS/VrBNrbo0zGiKkzVNU/bbcCyroKXJLXFtkFI3qmROiJNyIta2IMBCHJvIjLIMig==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@angular/common": "21.2.1", + "@angular/core": "21.2.1", + "@angular/platform-browser": "21.2.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.8.1.tgz", + "integrity": "sha512-AvT9QFpxK0Zd8J0jopedNm+w/2fIzvtPKPjqyw9jwvBaReTTqPBk9Hixaz7KbjimP+QNz605/XnjFcDAL2pqBg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.1.0", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz", + "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz", + "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@gar/promise-retry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.2.tgz", + "integrity": "sha512-Lm/ZLhDZcBECta3TmCQSngiQykFdfw+QtI1/GYMsZd4l3nG+P8WLB16XuS7WaBGLQ+9E+cOcWQsth9cayuGt8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "retry": "^0.13.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", + "dev": true, + "license": "Apache-2.0", + "optional": true + }, + "node_modules/@hono/node-server": { + "version": "1.19.11", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.11.tgz", + "integrity": "sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", + "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.5" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", + "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", + "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", + "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", + "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", + "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", + "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", + "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1", + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@npmcli/agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", + "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@npmcli/fs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/git": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", + "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", + "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", + "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", + "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", + "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", + "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", + "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "license": "MIT", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", + "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", + "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", + "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "21.2.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.1.tgz", + "integrity": "sha512-DjrHRMoILhbZ6tc7aNZWuHA1wCm1iU/JN1TxAwNEyIBgyU3Fx8Z5baK4w0TCpOIPt0RLWVgP2L7kka9aXWCUFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "21.2.1", + "@angular-devkit/schematics": "21.2.1", + "jsonc-parser": "3.3.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sigstore/bundle": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", + "integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@sigstore/core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.1.0.tgz", + "integrity": "sha512-o5cw1QYhNQ9IroioJxpzexmPjfCe7gzafd2RY3qnMpxr4ZEja+Jad/U8sgFpaue6bOaF+z7RVkyKVV44FN+N8A==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.0.tgz", + "integrity": "sha512-MM8XIwUjN2bwvCg1QvrMtbBmpcSHrkhFSCu1D11NyPvDQ25HEc4oG5/OcQfd/Tlf/OxmKWERDj0zGE23jQaMwA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.0.tgz", + "integrity": "sha512-Vx1RmLxLGnSUqx/o5/VsCjkuN5L7y+vxEEwawvc7u+6WtX2W4GNa7b9HEjmcRWohw/d6BpATXmvOwc78m+Swdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.3", + "proc-log": "^6.1.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.1.tgz", + "integrity": "sha512-OPZBg8y5Vc9yZjmWCHrlWPMBqW5yd8+wFNl+thMdtcWz3vjVSoJQutF8YkrzI0SLGnkuFof4HSsWUhXrf219Lw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz", + "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz", + "integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", + "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", + "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^6.0.0 || ^7.0.0" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/algoliasearch": { + "version": "5.48.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.1.tgz", + "integrity": "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@algolia/abtesting": "1.14.1", + "@algolia/client-abtesting": "5.48.1", + "@algolia/client-analytics": "5.48.1", + "@algolia/client-common": "5.48.1", + "@algolia/client-insights": "5.48.1", + "@algolia/client-personalization": "5.48.1", + "@algolia/client-query-suggestions": "5.48.1", + "@algolia/client-search": "5.48.1", + "@algolia/ingestion": "1.48.1", + "@algolia/monitoring": "1.48.1", + "@algolia/recommend": "5.48.1", + "@algolia/requester-browser-xhr": "5.48.1", + "@algolia/requester-fetch": "5.48.1", + "@algolia/requester-node-http": "5.48.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/beasties": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", + "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "css-select": "^6.0.0", + "css-what": "^7.0.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "htmlparser2": "^10.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.49", + "postcss-media-query-parser": "^0.2.3", + "postcss-safe-parser": "^7.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/body-parser": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/bootstrap": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz", + "integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "license": "MIT", + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "20.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.3.tgz", + "integrity": "sha512-3pUp4e8hv07k1QlijZu6Kn7c9+ZpWWk4j3F8N3xPuCExULobqJydKYOTj1FTq58srkJsXvO7LbGAH4C0ZU3WGw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", + "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-3.4.0.tgz", + "integrity": "sha512-bXfOC4QcT1tKXGorxL3wbJm6XJPDqEnij2gQ2m7ESQuE+/z9YFIWnl/5RpTiKWbMq3EVKR4fRLJGn6DVfu0mpw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-6.0.0.tgz", + "integrity": "sha512-rZZVSLle8v0+EY8QAkDWrKhpgt6SA5OtHsgBnsj6ZaLb5dmDVOWUDtQitd9ydxxvEjhewNudS6eTVU7uOyzvXw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^7.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "nth-check": "^2.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", + "integrity": "sha512-wD5oz5xibMOPHzy13CyGmogB3phdvcDaB5t0W/Nr5Z2O/agcB8YwOz6e2Lsp10pNDzBoDO9nVa3RGs/2BttpHQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.6.tgz", + "integrity": "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.3.0.tgz", + "integrity": "sha512-KJzBawY6fB9FiZGdE/0aftepZ91YlaGIrV8vgblRM3J8X+dHx/aiowJWwkx6LIGyuqGiANsjSwwrbb8mifOJ4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "10.1.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.5.tgz", + "integrity": "sha512-3qq+FUBtlTHhtYxbxheZgY8NIFnkkC/MR8u5TTsr7YZ3wixryQ3cCwn3iZbg8p8B88iDBBAYSfZDS75t8MN7Vg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/hosted-git-info": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.2.tgz", + "integrity": "sha512-M422h7o/BR3rmCQ8UHi7cyyMqKltdP9Uo+J2fXK+RSAY+wTcKOIRyhTuKv4qn+DJf3g+PL890AzId5KZpX+CBg==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ignore-walk": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz", + "integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/immutable": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/ip-address": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", + "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jose": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.0.tgz", + "integrity": "sha512-xsfE1TcSCbUdo6U07tR0mvhg0flGxU8tPLbF03mirl2ukGQENhUg4ubGYQnhVH0b5stLlPM+WOqDkEl1R1y5sQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", + "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "license": "MIT" + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lmdb": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", + "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@harperfast/extended-iterable": "^1.0.3", + "msgpackr": "^1.11.2", + "node-addon-api": "^6.1.0", + "node-gyp-build-optional-packages": "5.2.2", + "ordered-binary": "^1.5.3", + "weak-lru-cache": "^1.2.2" + }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@lmdb/lmdb-darwin-arm64": "3.5.1", + "@lmdb/lmdb-darwin-x64": "3.5.1", + "@lmdb/lmdb-linux-arm": "3.5.1", + "@lmdb/lmdb-linux-arm64": "3.5.1", + "@lmdb/lmdb-linux-x64": "3.5.1", + "@lmdb/lmdb-win32-arm64": "3.5.1", + "@lmdb/lmdb-win32-x64": "3.5.1" + } + }, + "node_modules/log-symbols": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-7.0.1.tgz", + "integrity": "sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/make-fetch-happen": { + "version": "15.0.4", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.4.tgz", + "integrity": "sha512-vM2sG+wbVeVGYcCm16mM3d5fuem9oC28n436HjsGO3LcxoTI8LNVa4rwZDn3f76+cWyT4GGJDxjTYU1I2nr6zw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz", + "integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minipass-sized": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz", + "integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/msgpackr": { + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.8.tgz", + "integrity": "sha512-bC4UGzHhVvgDNS7kn9tV8fAucIYUBuGojcaLiz7v+P63Lmtm0Xeji8B/8tYKddALXxJLpwIeBmUN3u64C4YkRA==", + "dev": true, + "license": "MIT", + "optional": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.2" + } + }, + "node_modules/msgpackr-extract": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build-optional-packages": "5.2.2" + }, + "bin": { + "download-msgpackr-prebuilds": "bin/download-prebuilds.js" + }, + "optionalDependencies": { + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + } + }, + "node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-gyp": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.2.0.tgz", + "integrity": "sha512-q23WdzrQv48KozXlr0U1v9dwO/k59NHeSzn6loGcasyf0UnSrtzs8kRxM+mfwJSf0DkX0s43hcqgnSO4/VNthQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^15.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-gyp-build-optional-packages": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-bundled": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", + "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-install-checks": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", + "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-package-arg": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-packlist": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", + "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", + "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", + "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", + "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.1", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ordered-binary": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", + "integrity": "sha512-QkCdPooczexPLiXIrbVOPYkR3VO3T6v2OyKRkR1Xbhpy7/LAVXwahnRCgRp78Oe/Ehf0C/HATAxfSr6eA1oX+w==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pacote": { + "version": "21.3.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", + "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/parse5": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", + "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", + "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0", + "parse5": "^8.0.0", + "parse5-sax-parser": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-8.0.0.tgz", + "integrity": "sha512-/dQ8UzHZwnrzs3EvDj6IkKrD/jIZyTlB+8XrHJvcjNgRdmWruNdN9i9RK/JtxakmlUdPwKubKPTCqvbTgzGhrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-to-regexp": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", + "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/piscina": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", + "integrity": "sha512-7uU4ZnKeQq22t9AsmHGD2w4OYQGonwFnTypDypaWi7Qr2EvQIFVtG8J5D/3bE7W123Wdc9+v4CZDu5hJXVCtBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.x" + }, + "optionalDependencies": { + "@napi-rs/nice": "^1.0.4" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true, + "license": "MIT" + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/prettier": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", + "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", + "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.113.0", + "@rolldown/pluginutils": "1.0.0-rc.4" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", + "@rolldown/binding-darwin-x64": "1.0.0-rc.4", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + }, + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz", + "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.0", + "@sigstore/tuf": "^4.0.1", + "@sigstore/verify": "^3.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/slice-ansi": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.7", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", + "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.0.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/ssri": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", + "integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/stdin-discarder": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.1.tgz", + "integrity": "sha512-reExS1kSGoElkextOcPkel4NE99S0BWxjUHQeDFnR8S993JxpPX7KU4MNmO19NXhlJp+8dmdCbKQVNgLJh2teA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", + "integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/tar": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.10.tgz", + "integrity": "sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tuf-js": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz", + "integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.22.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", + "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/unique-filename": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-5.0.0.tgz", + "integrity": "sha512-2RaJTAvAb4owyjllTfXzFClJ7WsGxlykkPvCr9pA//LD9goVq+m4PPAeBgNodGZ7nSrntT/auWpJ6Y5IFXcfjg==", + "dev": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/unique-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-6.0.0.tgz", + "integrity": "sha512-4Lup7Ezn8W3d52/xBhZBVdx323ckxa7DEvd9kPQHppTkLoJXw6ltrBCyj5pnrxj0qKDxYMJ56CoxNuFCscdTiw==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", + "integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/weak-lru-cache": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/weak-lru-cache/-/weak-lru-cache-1.2.2.tgz", + "integrity": "sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", + "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", + "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", + "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25 || ^4" + } + } + } +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..21f8a5a --- /dev/null +++ b/client/package.json @@ -0,0 +1,33 @@ +{ + "name": "client", + "version": "0.0.0", + "scripts": { + "prepare-env": "node scripts/write-env.js", + "ng": "node node_modules/@angular/cli/bin/ng.js", + "start": "npm run prepare-env && node node_modules/@angular/cli/bin/ng.js serve", + "build": "npm run prepare-env && node node_modules/@angular/cli/bin/ng.js build", + "watch": "npm run prepare-env && node node_modules/@angular/cli/bin/ng.js build --watch --configuration development", + "test": "node node_modules/@angular/cli/bin/ng.js test" + }, + "private": true, + "packageManager": "npm@11.10.1", + "dependencies": { + "@angular/common": "^21.2.0", + "@angular/compiler": "^21.2.0", + "@angular/core": "^21.2.0", + "@angular/forms": "^21.2.0", + "@angular/platform-browser": "^21.2.0", + "@angular/router": "^21.2.0", + "bootstrap": "^5.3.8", + "rxjs": "~7.8.0", + "tslib": "^2.3.0" + }, + "devDependencies": { + "@angular/build": "^21.2.1", + "@angular/cli": "^21.2.1", + "@angular/compiler-cli": "^21.2.0", + "dotenv": "^17.3.1", + "prettier": "^3.8.1", + "typescript": "~5.9.2" + } +} diff --git a/client/public/env.js b/client/public/env.js new file mode 100644 index 0000000..67bc94b --- /dev/null +++ b/client/public/env.js @@ -0,0 +1,3 @@ +window.__PRIVATECHAT_ENV__ = { + "PRIVATECHAT_CLIENT_SERVER_URL": "http://chatter.dubertrand.fr" +}; diff --git a/client/public/favicon.ico b/client/public/favicon.ico new file mode 100644 index 0000000..57614f9 Binary files /dev/null and b/client/public/favicon.ico differ diff --git a/client/scripts/write-env.js b/client/scripts/write-env.js new file mode 100644 index 0000000..b9bf61a --- /dev/null +++ b/client/scripts/write-env.js @@ -0,0 +1,17 @@ +const fs = require('node:fs'); +const path = require('node:path'); +const dotenv = require('dotenv'); + +const rootEnvPath = path.resolve(__dirname, '../../.env'); +const outputPath = path.resolve(__dirname, '../public/env.js'); + +dotenv.config({ path: rootEnvPath }); + +const runtimeEnv = { + PRIVATECHAT_CLIENT_SERVER_URL: process.env.PRIVATECHAT_CLIENT_SERVER_URL ?? 'http://localhost:3000', +}; + +const fileContents = `window.__PRIVATECHAT_ENV__ = ${JSON.stringify(runtimeEnv, null, 2)};\n`; + +fs.mkdirSync(path.dirname(outputPath), { recursive: true }); +fs.writeFileSync(outputPath, fileContents, 'utf8'); diff --git a/client/src/app/app.config.ts b/client/src/app/app.config.ts new file mode 100644 index 0000000..65e6679 --- /dev/null +++ b/client/src/app/app.config.ts @@ -0,0 +1,13 @@ +import { provideHttpClient, withFetch } from '@angular/common/http'; +import { ApplicationConfig, provideBrowserGlobalErrorListeners } from '@angular/core'; +import { provideRouter } from '@angular/router'; + +import { routes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideBrowserGlobalErrorListeners(), + provideHttpClient(withFetch()), + provideRouter(routes) + ] +}; diff --git a/client/src/app/app.html b/client/src/app/app.html new file mode 100644 index 0000000..67e7bd4 --- /dev/null +++ b/client/src/app/app.html @@ -0,0 +1 @@ + diff --git a/client/src/app/app.routes.ts b/client/src/app/app.routes.ts new file mode 100644 index 0000000..6b19fd8 --- /dev/null +++ b/client/src/app/app.routes.ts @@ -0,0 +1,24 @@ +import { Routes } from '@angular/router'; + +import { ApprovalPageComponent } from './approval-page.component'; +import { ChatPageComponent } from './chat-page.component'; +import { HomePageComponent } from './home-page.component'; + +export const routes: Routes = [ + { + path: '', + component: HomePageComponent, + }, + { + path: 'chat/:peerId', + component: ChatPageComponent, + }, + { + path: 'approvals', + component: ApprovalPageComponent, + }, + { + path: '**', + redirectTo: '', + }, +]; diff --git a/client/src/app/app.scss b/client/src/app/app.scss new file mode 100644 index 0000000..76169cc --- /dev/null +++ b/client/src/app/app.scss @@ -0,0 +1,4 @@ +:host { + display: block; + min-height: 100dvh; +} diff --git a/client/src/app/app.ts b/client/src/app/app.ts new file mode 100644 index 0000000..3dc1cc4 --- /dev/null +++ b/client/src/app/app.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { RouterOutlet } from '@angular/router'; + +import { ThemeService } from './theme.service'; + +@Component({ + selector: 'app-root', + imports: [RouterOutlet], + templateUrl: './app.html', + styleUrl: './app.scss', +}) +export class App { + constructor(_: ThemeService) {} +} diff --git a/client/src/app/approval-page.component.html b/client/src/app/approval-page.component.html new file mode 100644 index 0000000..6904c23 --- /dev/null +++ b/client/src/app/approval-page.component.html @@ -0,0 +1,45 @@ +
+
+
+
+
+ ← Back to dashboard +

Account approvals

+

Only ladparis can activate newly registered accounts.

+
+ {{ pendingUsers().length }} pending +
+ + @if (errorMessage()) { +
{{ errorMessage() }}
+ } + + @if (loading()) { +
Loading pending accounts...
+ } @else if (pendingUsers().length === 0) { +
No accounts are waiting for approval.
+ } @else { +
+ @for (user of pendingUsers(); track user.id) { +
+
+
{{ user.displayName }}
+
{{ user.username }}
+
Registered {{ user.createdAt | date: 'medium' }}
+
+ + +
+ } +
+ } +
+
+
diff --git a/client/src/app/approval-page.component.scss b/client/src/app/approval-page.component.scss new file mode 100644 index 0000000..e5310bb --- /dev/null +++ b/client/src/app/approval-page.component.scss @@ -0,0 +1,5 @@ +.approval-card { + border: 1px solid var(--surface-border-soft); + border-radius: 1rem; + background: var(--panel-soft-background); +} diff --git a/client/src/app/approval-page.component.ts b/client/src/app/approval-page.component.ts new file mode 100644 index 0000000..e948e08 --- /dev/null +++ b/client/src/app/approval-page.component.ts @@ -0,0 +1,61 @@ +import { CommonModule } from '@angular/common'; +import { Component, inject, signal } from '@angular/core'; +import { Router, RouterLink } from '@angular/router'; + +import { ChatSessionService } from './chat-session.service'; +import type { PendingApprovalUser } from './models'; + +@Component({ + selector: 'app-approval-page', + imports: [CommonModule, RouterLink], + templateUrl: './approval-page.component.html', + styleUrl: './approval-page.component.scss', +}) +export class ApprovalPageComponent { + private readonly router = inject(Router); + + readonly pendingUsers = signal([]); + readonly loading = signal(true); + readonly errorMessage = signal(null); + readonly approvingUserId = signal(null); + + constructor(readonly session: ChatSessionService) { + if (!this.session.isApprovalAdmin()) { + void this.router.navigateByUrl('/'); + return; + } + + void this.loadPendingUsers(); + } + + async approve(userId: string): Promise { + this.errorMessage.set(null); + this.approvingUserId.set(userId); + + try { + await this.session.approvePendingUser(userId); + this.pendingUsers.update((users) => users.filter((user) => user.id !== userId)); + } catch (error) { + this.errorMessage.set( + error instanceof Error ? error.message : 'Could not approve that account.', + ); + } finally { + this.approvingUserId.set(null); + } + } + + private async loadPendingUsers(): Promise { + this.loading.set(true); + this.errorMessage.set(null); + + try { + this.pendingUsers.set(await this.session.loadPendingApprovalUsers()); + } catch (error) { + this.errorMessage.set( + error instanceof Error ? error.message : 'Could not load pending account approvals.', + ); + } finally { + this.loading.set(false); + } + } +} diff --git a/client/src/app/chat-page.component.html b/client/src/app/chat-page.component.html new file mode 100644 index 0000000..d78cd39 --- /dev/null +++ b/client/src/app/chat-page.component.html @@ -0,0 +1,199 @@ +
+
+
+
+
+ ← Back to dashboard + @if (currentUser(); as connectedUser) { +

{{ connectedUser.displayName }}

+
+
+ + Signaling +
+
+ + WebRTC +
+
+ } @else { +

Not signed in

+

Return to the dashboard and sign in again.

+ } +
+ + @if (peer(); as selectedPeer) { + + } +
+ +
+ + +
+
+ @if (conversation().length === 0) { +
+ No text messages yet. The chat page is ready as soon as the peer channel opens. +
+ } + + @for (entry of conversation(); track entry.id) { +
+ +
+ {{ entry.authorLabel }} + +
+ + @switch (entry.kind) { + @case ('text') { +

{{ entry.text }}

+ } + @case ('json') { +
{{ entry.payload | json }}
+ } + @case ('file') { +
+ @if (isImageEntry(entry)) { + + } + +
+
{{ entry.fileName }}
+ @if (entry.fileSize) { +
{{ entry.fileSize | number }} bytes
+ } +
+ + @if (entry.downloadUrl) { + Download + } +
+ } + @default { +

{{ entry.text }}

+ } + } +
+ } +
+ +
+ @if (peer(); as selectedPeer) { + + + } + + + +
+
+
+
+
+
diff --git a/client/src/app/chat-page.component.scss b/client/src/app/chat-page.component.scss new file mode 100644 index 0000000..2921303 --- /dev/null +++ b/client/src/app/chat-page.component.scss @@ -0,0 +1,316 @@ +:host { + display: block; + min-height: 100dvh; + color: var(--page-text); +} + +.chat-shell { + min-height: 100dvh; +} + +.panel { + border: 1px solid var(--surface-border); + border-radius: 1.75rem; + background: var(--panel-background); + backdrop-filter: blur(18px); + box-shadow: 0 20px 60px var(--shadow-color); +} + +.back-link { + color: var(--link-color); + text-decoration: none; +} + +.status-indicators { + display: flex; + flex-wrap: wrap; + gap: 0.9rem; +} + +.status-indicator { + display: inline-flex; + align-items: center; + gap: 0.45rem; + font-size: 0.9rem; + color: var(--page-text-soft); +} + +.status-led { + width: 0.8rem; + height: 0.8rem; + border-radius: 999px; + box-shadow: 0 0 0 1px var(--input-border); +} + +.status-led-ok { + background: #59d66f; +} + +.status-led-connecting { + background: #f3ad3d; +} + +.status-led-offline { + background: #eb5d64; +} + +.chat-layout { + display: grid; + grid-template-columns: minmax(15rem, 19rem) minmax(0, 1fr); + gap: 1.25rem; +} + +.peer-sidebar { + padding: 1rem; + border-radius: 1.3rem; + border: 1px solid var(--surface-border-soft); + background: var(--panel-soft-background); +} + +.peer-count { + display: inline-flex; + min-width: 2rem; + justify-content: center; + padding: 0.35rem 0.65rem; + border-radius: 999px; + font-size: 0.85rem; + background: var(--badge-background); +} + +.peer-list { + display: grid; + gap: 0.75rem; + max-height: calc(100dvh - 17rem); + overflow: auto; +} + +.peer-tile { + width: 100%; + padding: 0.95rem 1rem; + border: 1px solid var(--surface-border); + border-radius: 1rem; + color: inherit; + background: var(--surface-background); + transition: transform 160ms ease, border-color 160ms ease, background 160ms ease; +} + +.peer-tile:hover, +.peer-tile:focus-visible, +.peer-tile-active { + transform: translateY(-1px); + border-color: color-mix(in srgb, var(--accent-color) 35%, transparent); + background: var(--surface-hover-background); +} + +.peer-tile-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 0.75rem; +} + +.peer-tile-title { + display: inline-flex; + align-items: center; + gap: 0.45rem; + min-width: 0; +} + +.peer-typing-dots { + display: inline-flex; + align-items: center; + gap: 0.2rem; + min-height: 0.9rem; +} + +.peer-typing-dots span { + width: 0.38rem; + height: 0.38rem; + border-radius: 999px; + background: var(--page-text); + opacity: 0.28; + animation: peer-typing-pulse 900ms infinite ease-in-out; +} + +.peer-typing-dots span:nth-child(2) { + animation-delay: 120ms; +} + +.peer-typing-dots span:nth-child(3) { + animation-delay: 240ms; +} + +.peer-tile-status { + flex: 0 0 auto; +} + +.chat-main { + min-width: 0; +} + +.conversation { + display: grid; + gap: 0.85rem; + min-height: 24rem; + max-height: calc(100dvh - 20rem); + overflow: auto; + padding: 0.5rem 0; +} + +.bubble { + position: relative; + max-width: min(75%, 34rem); + padding: 0.9rem 1rem; + border-radius: 1.2rem; + box-shadow: 0 12px 30px rgba(0, 0, 0, 0.14); +} + +.bubble-delete { + position: absolute; + top: 0.45rem; + right: 0.55rem; + width: 1.5rem; + height: 1.5rem; + border: 0; + border-radius: 999px; + color: #fff; + background: var(--danger-background); + line-height: 1; + font-size: 1rem; +} + +.bubble-incoming { + justify-self: start; + color: var(--incoming-bubble-text); + background: var(--incoming-bubble-background); +} + +.bubble-outgoing { + justify-self: end; + color: var(--outgoing-bubble-text); + background: var(--outgoing-bubble-background); +} + +.bubble-system { + justify-self: center; + max-width: 90%; + color: var(--page-text-soft); + background: var(--badge-background); +} + +.bubble-meta { + display: flex; + justify-content: space-between; + gap: 1rem; + margin-bottom: 0.35rem; + font-size: 0.78rem; + opacity: 0.7; +} + +.composer { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + gap: 0.9rem; + align-items: end; + padding-top: 1rem; + margin-top: 1rem; + border-top: 1px solid var(--surface-border-soft); +} + +.composer-file-input { + display: none; +} + +.composer-plus, +.send-emoji { + width: 3.25rem; + height: 3.25rem; + border: 0; + border-radius: 999px; + font-size: 1.35rem; +} + +.composer-textarea, +.composer-textarea:focus { + color: var(--page-text); + background-color: var(--input-background); + border-color: var(--input-border); + box-shadow: none; +} + +.composer-textarea::placeholder { + color: var(--placeholder-color); +} + +.composer-plus { + color: var(--page-text); + background: var(--badge-background); +} + +.send-emoji { + background: linear-gradient(135deg, #def7dd, #9bd5ff); +} + +.bubble-image { + width: 200px; + max-width: 100%; + height: auto; + border-radius: 1rem; + display: block; +} + +.bubble-download { + color: inherit; + font-weight: 600; +} + +.bubble-json { + white-space: pre-wrap; + word-break: break-word; + margin: 0; +} + +.empty-chat { + padding: 1.25rem; + border: 1px dashed var(--input-border); + border-radius: 1rem; + color: var(--page-text-muted); + text-align: center; +} + +.empty-peers { + min-height: 10rem; +} + +.h3, +.small { + color: var(--page-text); +} + +@keyframes peer-typing-pulse { + 0%, + 80%, + 100% { + opacity: 0.28; + transform: translateY(0); + } + + 40% { + opacity: 1; + transform: translateY(-1px); + } +} + +@media (max-width: 767.98px) { + .chat-layout { + grid-template-columns: 1fr; + } + + .peer-list { + max-height: 16rem; + } + + .bubble { + max-width: 88%; + } +} diff --git a/client/src/app/chat-page.component.ts b/client/src/app/chat-page.component.ts new file mode 100644 index 0000000..fdce636 --- /dev/null +++ b/client/src/app/chat-page.component.ts @@ -0,0 +1,151 @@ +import { CommonModule } from '@angular/common'; +import { Component, computed, effect, inject } from '@angular/core'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { FormsModule } from '@angular/forms'; +import { ActivatedRoute, Router, RouterLink } from '@angular/router'; + +import { ChatSessionService } from './chat-session.service'; +import type { ChatEntry, ConnectionState } from './models'; + +@Component({ + selector: 'app-chat-page', + imports: [CommonModule, FormsModule, RouterLink], + templateUrl: './chat-page.component.html', + styleUrl: './chat-page.component.scss', +}) +export class ChatPageComponent { + private readonly route = inject(ActivatedRoute); + private readonly router = inject(Router); + private readonly routeParamMap = toSignal(this.route.paramMap, { + initialValue: this.route.snapshot.paramMap, + }); + + messageText = ''; + readonly peerId = computed(() => this.routeParamMap().get('peerId') ?? ''); + readonly peer = computed(() => this.session.peers().find((item) => item.id === this.peerId()) ?? null); + readonly currentUser = computed(() => this.session.currentUser()); + readonly conversation = computed(() => + this.session + .messages() + .filter((entry) => entry.peerId === this.peerId()), + ); + readonly webRtcState = computed(() => { + const selectedPeer = this.peer(); + + if (!selectedPeer) { + return 'disconnected'; + } + + if (selectedPeer.channelState === 'open' || selectedPeer.connectionState === 'connected') { + return 'connected'; + } + + if (selectedPeer.channelState === 'connecting' || selectedPeer.connectionState === 'connecting') { + return 'connecting'; + } + + return 'disconnected'; + }); + + constructor(readonly session: ChatSessionService) { + if (!this.session.currentUser()) { + void this.router.navigateByUrl('/'); + } + + effect(() => { + const peerId = this.peerId(); + + if (!peerId) { + return; + } + + this.session.selectPeer(peerId); + void this.session.connectToPeer(peerId); + }); + } + + async ensureConnection(): Promise { + const peerId = this.peerId(); + + if (!peerId) { + return; + } + + this.session.selectPeer(peerId); + await this.session.connectToPeer(peerId); + } + + async sendMessage(): Promise { + const peerId = this.peerId(); + + if (!peerId) { + return; + } + + await this.session.sendText(peerId, this.messageText); + this.messageText = ''; + } + + handleComposerEnter(event: Event): void { + if (!(event instanceof KeyboardEvent) || event.shiftKey) { + return; + } + + event.preventDefault(); + void this.sendMessage(); + } + + handleMessageTextChange(text: string): void { + const peerId = this.peerId(); + + if (!peerId) { + return; + } + + this.session.notifyTypingActivity(peerId, text); + } + + async sendFile(peerId: string, input: HTMLInputElement): Promise { + const file = input.files?.item(0); + + if (!file) { + return; + } + + await this.session.sendFile(peerId, file); + input.value = ''; + } + + async deleteMessage(entry: ChatEntry): Promise { + await this.session.deleteMessage(entry); + } + + isImageEntry(entry: ChatEntry): boolean { + return entry.kind === 'file' && !!entry.downloadUrl && (entry.fileMimeType?.startsWith('image/') ?? false); + } + + isPeerTyping(peerId: string): boolean { + return this.session.typingPeerIds().includes(peerId); + } + + indicatorTone(state: ConnectionState): 'ok' | 'connecting' | 'offline' { + if (state === 'connected') { + return 'ok'; + } + + if (state === 'connecting') { + return 'connecting'; + } + + return 'offline'; + } + + async switchPeer(peerId: string): Promise { + if (!peerId || peerId === this.peerId()) { + return; + } + + this.session.selectPeer(peerId); + await this.router.navigate(['/chat', peerId]); + } +} diff --git a/client/src/app/chat-session.service.ts b/client/src/app/chat-session.service.ts new file mode 100644 index 0000000..a8a45b8 --- /dev/null +++ b/client/src/app/chat-session.service.ts @@ -0,0 +1,1799 @@ +import { HttpClient } from '@angular/common/http'; +import { computed, Injectable, signal } from '@angular/core'; +import type { HttpErrorResponse } from '@angular/common/http'; +import { firstValueFrom } from 'rxjs'; + +import { + AccessKeySummary, + AuthenticationOptionsResponse, + AuthResponse, + ChatEntry, + ConnectionState, + DataEnvelope, + PendingApprovalResponse, + PendingApprovalUser, + PeerSummary, + RegistrationOptionsResponse, + SessionResponse, + ServerEvent, + SignalPayload, + UserProfile, +} from './models'; + +type PeerBundle = { + pc: RTCPeerConnection; + channel?: RTCDataChannel; + pendingCandidates: RTCIceCandidateInit[]; +}; + +type IncomingFileTransfer = { + id: string; + name: string; + mimeType: string; + size: number; + sentAt: number; + authorName: string; + chunks: ArrayBuffer[]; + receivedBytes: number; +}; + +type PersistedBinary = string | ArrayBuffer; + +type LegacyPersistedChatEntry = { + storageKey: string; + ownerUserId: string; + conversationKey: string; + id: string; + peerId: string; + direction: ChatEntry['direction']; + kind: Exclude; + createdAt: number; + authorLabel: string; + text?: string; + payload?: unknown; + fileName?: string; + fileSize?: number; + fileMimeType?: string; + fileBlob?: Blob; +}; + +type EncryptedPersistedChatEntry = { + storageKey: string; + ownerUserId: string; + conversationKey: string; + id: string; + peerId: string; + direction: ChatEntry['direction']; + kind: Exclude; + createdAt: number; + encryptedPayload: PersistedBinary; + payloadIv: number[]; + encryptedFileBlob?: PersistedBinary; + fileIv?: number[]; +}; + +type PersistedChatEntry = LegacyPersistedChatEntry | EncryptedPersistedChatEntry; + +type PersistedChatEntryContent = { + authorLabel: string; + text?: string; + payload?: unknown; + fileName?: string; + fileSize?: number; + fileMimeType?: string; +}; + +type RuntimeEnv = { + PRIVATECHAT_CLIENT_SERVER_URL?: string; +}; + +function readDefaultServerUrl(): string { + const runtimeWindow = typeof window === 'undefined' + ? undefined + : (window as Window & typeof globalThis & { __PRIVATECHAT_ENV__?: RuntimeEnv }); + const configuredUrl = runtimeWindow?.__PRIVATECHAT_ENV__?.PRIVATECHAT_CLIENT_SERVER_URL?.trim(); + + return configuredUrl?.replace(/\/+$/, '') || 'http://localhost:3000'; +} + +@Injectable({ providedIn: 'root' }) +export class ChatSessionService { + private static readonly messageDatabaseName = 'privatechat'; + private static readonly messageStoreName = 'conversation_messages'; + private static readonly messageRetentionLimit = 256; + private static readonly systemMessageLifetimeMs = 5000; + private static readonly typingIndicatorLifetimeMs = 1800; + private static readonly typingIdleMs = 1200; + private static readonly typingHeartbeatMs = 900; + + readonly serverUrl = signal(this.readStorage('privatechat.serverUrl') ?? readDefaultServerUrl()); + readonly currentUser = signal(this.readUserStorage()); + readonly accessKeys = signal([]); + readonly peers = signal([]); + readonly activePeerId = signal(null); + readonly messages = signal([]); + readonly unreadPeerIds = signal([]); + readonly typingPeerIds = signal([]); + readonly signalingState = signal('disconnected'); + readonly status = signal('Disconnected from signaling server.'); + readonly error = signal(null); + readonly notice = signal(null); + readonly webAuthnSupported = signal( + typeof window !== 'undefined' && + typeof window.PublicKeyCredential !== 'undefined' && + typeof navigator !== 'undefined' && + typeof navigator.credentials?.create === 'function' && + typeof navigator.credentials?.get === 'function', + ); + + readonly selectedPeer = computed(() => this.peers().find((peer) => peer.id === this.activePeerId()) ?? null); + readonly conversation = computed(() => { + const peerId = this.activePeerId(); + + if (!peerId) { + return []; + } + + return this.messages().filter((entry) => entry.peerId === peerId); + }); + + readonly isSelectedPeerReady = computed(() => this.selectedPeer()?.channelState === 'open'); + readonly isApprovalAdmin = computed(() => this.currentUser()?.username === 'ladparis'); + + private readonly token = signal(this.readStorage('privatechat.token')); + private readonly peerBundles = new Map(); + private readonly incomingFiles = new Map(); + private readonly systemMessageTimeouts = new Map(); + private readonly typingIndicatorTimeouts = new Map(); + private readonly outgoingTypingIdleTimeouts = new Map(); + private readonly outgoingTypingStates = new Map(); + private readonly messageStoreOperations = new Map>(); + private messageEncryptionKey: CryptoKey | null = null; + private messageDatabasePromise: Promise | null = null; + private websocket: WebSocket | null = null; + + constructor(private readonly http: HttpClient) { + if (this.token() && this.currentUser()) { + queueMicrotask(() => { + void this.restoreSession(); + }); + } + } + + async register(username: string, password: string, displayName: string): Promise { + this.error.set(null); + this.notice.set(null); + + try { + const response = await firstValueFrom( + this.http.post(`${this.serverUrl()}/api/auth/register`, { + username, + password, + displayName: displayName.trim() || undefined, + }), + ); + + if ('token' in response) { + await this.applyAuthenticatedSession(response); + return true; + } + + this.notice.set(response.message); + this.status.set(response.message); + return false; + } catch (error) { + this.error.set( + this.extractErrorMessage(error, 'Registration failed. Check the backend URL and your credentials.'), + ); + return false; + } + } + + async login(username: string, password: string): Promise { + await this.authenticate('/api/auth/login', { username, password }); + } + + async loginWithAccessKey(username: string): Promise { + if (!this.webAuthnSupported()) { + this.error.set('This browser does not support WebAuthn access keys.'); + return; + } + + this.error.set(null); + this.notice.set(null); + + try { + const options = await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/webauthn/authenticate/options`, + { username: username.trim() || undefined }, + ), + ); + + const credential = await navigator.credentials.get({ + publicKey: this.toPublicKeyRequestOptions(options), + }); + + if (!(credential instanceof PublicKeyCredential)) { + this.error.set('The browser did not return a valid access key credential.'); + return; + } + + const response = await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/webauthn/authenticate/verify`, + { + attemptId: options.attemptId, + credential: this.serializeAuthenticationCredential(credential), + }, + ), + ); + + await this.applyAuthenticatedSession(response); + } catch (error) { + this.error.set(this.extractErrorMessage(error, 'Access key login failed or was cancelled.')); + } + } + + async logout(): Promise { + const token = this.token(); + + try { + if (token) { + await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/auth/logout`, + {}, + { headers: { Authorization: `Bearer ${token}` } }, + ), + ); + } + } catch { + // Local cleanup still needs to happen even if the backend is unavailable. + } finally { + this.clearLocalAuth('Logged out.'); + } + } + + setServerUrl(url: string): void { + const normalized = url.trim().replace(/\/+$/, ''); + + if (!normalized) { + return; + } + + this.serverUrl.set(normalized); + this.writeStorage('privatechat.serverUrl', normalized); + + if (this.currentUser()) { + void this.connectWebSocket(); + } + } + + selectPeer(peerId: string): void { + this.activePeerId.set(peerId); + this.clearUnreadPeer(peerId); + } + + notifyTypingActivity(peerId: string, rawText: string): void { + if (!peerId) { + return; + } + + const trimmed = rawText.trim(); + + if (!trimmed) { + this.sendTypingState(peerId, false); + return; + } + + const now = Date.now(); + const currentState = this.outgoingTypingStates.get(peerId); + + if (!currentState?.active || now - currentState.lastSentAt >= ChatSessionService.typingHeartbeatMs) { + this.sendTypingState(peerId, true, true); + } + + const existingTimeoutId = this.outgoingTypingIdleTimeouts.get(peerId); + + if (typeof existingTimeoutId !== 'undefined') { + window.clearTimeout(existingTimeoutId); + } + + const timeoutId = window.setTimeout(() => { + this.sendTypingState(peerId, false); + }, ChatSessionService.typingIdleMs); + + this.outgoingTypingIdleTimeouts.set(peerId, timeoutId); + } + + async connectToPeer(peerId: string): Promise { + if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) { + this.error.set('You must be connected to signaling before opening a peer session.'); + return; + } + + const bundle = this.ensurePeerBundle(peerId, true); + + if (bundle.channel?.readyState === 'open') { + return; + } + + if (bundle.pc.signalingState !== 'stable') { + return; + } + + this.patchPeer(peerId, { connectionState: 'connecting', channelState: 'connecting' }); + this.addSystemMessage(peerId, 'Opening WebRTC data channel.'); + + const offer = await bundle.pc.createOffer(); + await bundle.pc.setLocalDescription(offer); + + this.sendSignal(peerId, { + type: 'sdp', + description: bundle.pc.localDescription!.toJSON(), + }); + } + + async registerAccessKey(label: string): Promise { + if (!this.webAuthnSupported()) { + this.error.set('This browser does not support WebAuthn access keys.'); + return; + } + + const token = this.token(); + + if (!token) { + this.error.set('Sign in before registering an access key.'); + return; + } + + this.error.set(null); + this.notice.set(null); + + try { + const options = await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/webauthn/register/options`, + { label: label.trim() || undefined }, + { headers: { Authorization: `Bearer ${token}` } }, + ), + ); + + const credential = await navigator.credentials.create({ + publicKey: this.toPublicKeyCreationOptions(options), + }); + + if (!(credential instanceof PublicKeyCredential)) { + this.error.set('The browser did not return a valid access key credential.'); + return; + } + + await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/webauthn/register/verify`, + { credential: this.serializeRegistrationCredential(credential) }, + { headers: { Authorization: `Bearer ${token}` } }, + ), + ); + + await this.loadAccessKeys(); + this.status.set('Access key registered.'); + } catch (error) { + this.error.set(this.extractErrorMessage(error, 'Access key registration failed or was cancelled.')); + } + } + + async sendText(peerId: string, text: string): Promise { + const trimmed = text.trim(); + + if (!trimmed) { + return; + } + + const channel = this.requireOpenChannel(peerId); + + if (!channel) { + return; + } + + const envelope: DataEnvelope = { + type: 'text', + id: crypto.randomUUID(), + body: trimmed, + authorId: this.currentUser()!.id, + authorName: this.currentUser()!.displayName, + sentAt: Date.now(), + }; + + channel.send(JSON.stringify(envelope)); + this.sendTypingState(peerId, false); + this.pushMessage({ + id: envelope.id, + peerId, + direction: 'outgoing', + kind: 'text', + createdAt: envelope.sentAt, + authorLabel: 'You', + text: trimmed, + }); + } + + async sendJson(peerId: string, rawPayload: string): Promise { + if (!rawPayload.trim()) { + return; + } + + const channel = this.requireOpenChannel(peerId); + + if (!channel) { + return; + } + + let parsedPayload: unknown; + + try { + parsedPayload = JSON.parse(rawPayload); + } catch { + this.error.set('JSON payload is not valid.'); + return; + } + + const envelope: DataEnvelope = { + type: 'json', + id: crypto.randomUUID(), + body: parsedPayload, + authorId: this.currentUser()!.id, + authorName: this.currentUser()!.displayName, + sentAt: Date.now(), + }; + + channel.send(JSON.stringify(envelope)); + this.pushMessage({ + id: envelope.id, + peerId, + direction: 'outgoing', + kind: 'json', + createdAt: envelope.sentAt, + authorLabel: 'You', + payload: parsedPayload, + }); + } + + async sendFile(peerId: string, file: File): Promise { + const channel = this.requireOpenChannel(peerId); + + if (!channel) { + return; + } + + this.sendTypingState(peerId, false); + + const transferId = crypto.randomUUID(); + const sentAt = Date.now(); + const arrayBuffer = await file.arrayBuffer(); + const chunkSize = 16 * 1024; + + channel.send(JSON.stringify({ + type: 'file-meta', + id: transferId, + name: file.name, + mimeType: file.type || 'application/octet-stream', + size: file.size, + authorId: this.currentUser()!.id, + authorName: this.currentUser()!.displayName, + sentAt, + } satisfies DataEnvelope)); + + for (let offset = 0; offset < arrayBuffer.byteLength; offset += chunkSize) { + await this.waitForBufferedAmount(channel, chunkSize * 2); + channel.send(arrayBuffer.slice(offset, Math.min(offset + chunkSize, arrayBuffer.byteLength))); + } + + channel.send(JSON.stringify({ type: 'file-complete', id: transferId } satisfies DataEnvelope)); + + this.pushMessage({ + id: transferId, + peerId, + direction: 'outgoing', + kind: 'file', + createdAt: sentAt, + authorLabel: 'You', + fileName: file.name, + fileSize: file.size, + fileMimeType: file.type || 'application/octet-stream', + downloadUrl: URL.createObjectURL(file), + }, file); + } + + private async authenticate(path: string, payload: Record): Promise { + this.error.set(null); + this.notice.set(null); + + try { + const response = await firstValueFrom( + this.http.post(`${this.serverUrl()}${path}`, payload), + ); + + await this.applyAuthenticatedSession(response); + } catch (error) { + this.error.set( + this.extractErrorMessage(error, 'Authentication failed. Check the backend URL and your credentials.'), + ); + } + } + + private async applyAuthenticatedSession(response: AuthResponse): Promise { + this.token.set(response.token); + this.currentUser.set(response.user); + this.messageEncryptionKey = await this.importMessageEncryptionKey(response.messageEncryptionKey); + this.writeStorage('privatechat.token', response.token); + this.writeStorage('privatechat.user', JSON.stringify(response.user)); + this.notice.set(null); + this.status.set(`Authenticated as ${response.user.displayName}.`); + await this.loadPersistedMessages(response.user.id); + await this.loadAccessKeys(); + await this.connectWebSocket(); + } + + async loadPendingApprovalUsers(): Promise { + const token = this.token(); + + if (!token) { + throw new Error('Authentication required.'); + } + + const response = await firstValueFrom( + this.http.get<{ users: PendingApprovalUser[] }>(`${this.serverUrl()}/api/admin/pending-users`, { + headers: { Authorization: `Bearer ${token}` }, + }), + ); + + return response.users; + } + + async approvePendingUser(userId: string): Promise { + const token = this.token(); + + if (!token) { + throw new Error('Authentication required.'); + } + + await firstValueFrom( + this.http.post( + `${this.serverUrl()}/api/admin/pending-users/${encodeURIComponent(userId)}/approve`, + {}, + { headers: { Authorization: `Bearer ${token}` } }, + ), + ); + } + + private async loadAccessKeys(): Promise { + const token = this.token(); + + if (!token) { + this.accessKeys.set([]); + return; + } + + try { + const response = await firstValueFrom( + this.http.get<{ credentials: AccessKeySummary[] }>(`${this.serverUrl()}/api/webauthn/credentials`, { + headers: { Authorization: `Bearer ${token}` }, + }), + ); + + this.accessKeys.set(response.credentials); + } catch { + this.error.set('Could not load registered access keys.'); + } + } + + private async connectWebSocket(): Promise { + const token = this.token(); + + if (!token) { + return; + } + + this.disconnectWebSocket(); + this.resetPeerConnections(); + + this.error.set(null); + this.signalingState.set('connecting'); + this.status.set('Connecting to signaling server.'); + + const websocket = new WebSocket(this.toWebSocketUrl(this.serverUrl(), token)); + this.websocket = websocket; + + websocket.onopen = () => { + this.signalingState.set('connected'); + this.status.set('Connected to signaling server.'); + }; + + websocket.onmessage = (event) => { + const message = JSON.parse(event.data) as ServerEvent; + void this.handleServerEvent(message); + }; + + websocket.onerror = () => { + this.signalingState.set('failed'); + this.error.set('The signaling socket encountered an error.'); + }; + + websocket.onclose = () => { + this.signalingState.set('disconnected'); + this.status.set('Signaling connection closed.'); + this.websocket = null; + this.peers.update((peers) => + peers.map((peer) => ({ ...peer, connectionState: 'disconnected', channelState: 'closed' })), + ); + }; + } + + private disconnectWebSocket(): void { + if (this.websocket) { + this.websocket.close(); + this.websocket = null; + } + } + + private async handleServerEvent(event: ServerEvent): Promise { + switch (event.type) { + case 'presence': + this.mergePresence(event.peers); + break; + case 'peer-joined': + this.mergePresence([ + ...this.peers().map((peer) => peer), + { ...event.peer, connectionState: 'disconnected', channelState: 'closed' }, + ]); + break; + case 'peer-left': + this.releasePeerBundle(event.peerId, false); + this.peers.update((peers) => peers.filter((peer) => peer.id !== event.peerId)); + this.clearUnreadPeer(event.peerId); + this.clearPeerTyping(event.peerId); + if (this.activePeerId() === event.peerId) { + this.activePeerId.set(this.peers()[0]?.id ?? null); + } + this.addSystemMessage(event.peerId, 'Peer disconnected from signaling.'); + break; + case 'signal': + await this.handleSignal(event.from, event.signal); + break; + case 'error': + this.error.set(event.message); + if (/auth|session/i.test(event.message)) { + this.clearLocalAuth('Session expired. Sign in again.'); + } + break; + } + } + + private async restoreSession(): Promise { + const token = this.token(); + + if (!token) { + return; + } + + this.status.set('Restoring saved session.'); + this.error.set(null); + this.notice.set(null); + + try { + const response = await firstValueFrom( + this.http.get(`${this.serverUrl()}/api/auth/session`, { + headers: { Authorization: `Bearer ${token}` }, + }), + ); + + this.currentUser.set(response.user); + this.messageEncryptionKey = await this.importMessageEncryptionKey(response.messageEncryptionKey); + this.writeStorage('privatechat.user', JSON.stringify(response.user)); + await this.loadPersistedMessages(response.user.id); + await this.loadAccessKeys(); + await this.connectWebSocket(); + } catch { + this.clearLocalAuth('Saved session expired. Sign in again.'); + } + } + + private mergePresence(peers: Array): void { + const previous = new Map(this.peers().map((peer) => [peer.id, peer])); + + const nextPeers = peers + .map((peer) => { + const existing = previous.get(peer.id); + + return { + id: peer.id, + username: peer.username, + displayName: peer.displayName, + connectionState: existing?.connectionState ?? 'disconnected', + channelState: existing?.channelState ?? 'closed', + } satisfies PeerSummary; + }) + .filter((peer, index, values) => values.findIndex((candidate) => candidate.id === peer.id) === index) + .sort((left, right) => left.displayName.localeCompare(right.displayName)); + + this.peers.set(nextPeers); + this.unreadPeerIds.update((peerIds) => peerIds.filter((peerId) => nextPeers.some((peer) => peer.id === peerId))); + this.typingPeerIds.update((peerIds) => peerIds.filter((peerId) => nextPeers.some((peer) => peer.id === peerId))); + + if (!this.activePeerId() && nextPeers.length > 0) { + this.activePeerId.set(nextPeers[0].id); + } + } + + private async handleSignal(peerId: string, signal: SignalPayload): Promise { + if (signal.type === 'ice-candidate') { + const bundle = this.ensurePeerBundle(peerId, false); + + if (bundle.pc.remoteDescription) { + await bundle.pc.addIceCandidate(signal.candidate); + } else { + bundle.pendingCandidates.push(signal.candidate); + } + + return; + } + + const bundle = this.ensurePeerBundle(peerId, false); + const description = signal.description; + + if (description.type === 'offer') { + const offerCollision = bundle.pc.signalingState !== 'stable'; + const polite = this.isPolitePeer(peerId); + + if (offerCollision) { + if (!polite) { + return; + } + + await bundle.pc.setLocalDescription({ type: 'rollback' }); + } + + await bundle.pc.setRemoteDescription(description); + await this.flushPendingCandidates(bundle); + + const answer = await bundle.pc.createAnswer(); + await bundle.pc.setLocalDescription(answer); + + this.sendSignal(peerId, { + type: 'sdp', + description: bundle.pc.localDescription!.toJSON(), + }); + + return; + } + + await bundle.pc.setRemoteDescription(description); + await this.flushPendingCandidates(bundle); + } + + private ensurePeerBundle(peerId: string, initiator: boolean): PeerBundle { + const existing = this.peerBundles.get(peerId); + + if (existing && existing.pc.connectionState !== 'closed' && existing.pc.connectionState !== 'failed') { + if (initiator && !existing.channel) { + const channel = existing.pc.createDataChannel('privatechat'); + this.attachDataChannel(peerId, channel, existing); + } + + return existing; + } + + this.releasePeerBundle(peerId, false); + + const bundle: PeerBundle = { + pc: new RTCPeerConnection({ + iceServers: [{ urls: 'stun:stun.l.google.com:19302' }], + }), + pendingCandidates: [], + }; + + bundle.pc.onicecandidate = (event) => { + if (event.candidate) { + this.sendSignal(peerId, { + type: 'ice-candidate', + candidate: event.candidate.toJSON(), + }); + } + }; + + bundle.pc.onconnectionstatechange = () => { + const state = this.mapConnectionState(bundle.pc.connectionState); + this.patchPeer(peerId, { connectionState: state }); + + if (state === 'connected') { + this.addSystemMessage(peerId, 'Peer connection established.'); + } + + if (bundle.pc.connectionState === 'closed' || bundle.pc.connectionState === 'failed') { + this.releasePeerBundle(peerId, true); + } + }; + + bundle.pc.ondatachannel = (event) => { + this.attachDataChannel(peerId, event.channel, bundle); + }; + + if (initiator) { + const channel = bundle.pc.createDataChannel('privatechat'); + this.attachDataChannel(peerId, channel, bundle); + } + + this.peerBundles.set(peerId, bundle); + this.patchPeer(peerId, { connectionState: 'connecting' }); + + return bundle; + } + + private attachDataChannel(peerId: string, channel: RTCDataChannel, bundle: PeerBundle): void { + channel.binaryType = 'arraybuffer'; + bundle.channel = channel; + + this.patchPeer(peerId, { channelState: channel.readyState === 'open' ? 'open' : 'connecting' }); + + channel.onopen = () => { + this.patchPeer(peerId, { connectionState: 'connected', channelState: 'open' }); + this.addSystemMessage(peerId, 'Secure data channel is open.'); + }; + + channel.onclose = () => { + this.patchPeer(peerId, { channelState: 'closed' }); + }; + + channel.onerror = () => { + this.patchPeer(peerId, { channelState: 'closed', connectionState: 'failed' }); + this.error.set('A peer data channel failed.'); + }; + + channel.onmessage = (event) => { + if (typeof event.data === 'string') { + this.handleChannelEnvelope(peerId, JSON.parse(event.data) as DataEnvelope); + return; + } + + void this.handleBinaryChunk(peerId, event.data); + }; + } + + private handleChannelEnvelope(peerId: string, envelope: DataEnvelope): void { + switch (envelope.type) { + case 'text': + this.pushMessage({ + id: envelope.id, + peerId, + direction: 'incoming', + kind: 'text', + createdAt: envelope.sentAt, + authorLabel: envelope.authorName, + text: envelope.body, + }); + break; + case 'json': + this.pushMessage({ + id: envelope.id, + peerId, + direction: 'incoming', + kind: 'json', + createdAt: envelope.sentAt, + authorLabel: envelope.authorName, + payload: envelope.body, + }); + break; + case 'file-meta': + this.incomingFiles.set(peerId, { + id: envelope.id, + name: envelope.name, + mimeType: envelope.mimeType, + size: envelope.size, + sentAt: envelope.sentAt, + authorName: envelope.authorName, + chunks: [], + receivedBytes: 0, + }); + this.addSystemMessage(peerId, `Receiving file ${envelope.name}.`); + break; + case 'file-complete': + this.finalizeIncomingFile(peerId, envelope.id); + break; + case 'typing': + this.setPeerTyping(peerId, envelope.active); + break; + } + } + + private async handleBinaryChunk(peerId: string, chunk: Blob | ArrayBuffer): Promise { + const transfer = this.incomingFiles.get(peerId); + + if (!transfer) { + return; + } + + const arrayBuffer = chunk instanceof Blob ? await chunk.arrayBuffer() : chunk; + + transfer.chunks.push(arrayBuffer); + transfer.receivedBytes += arrayBuffer.byteLength; + } + + private finalizeIncomingFile(peerId: string, transferId: string): void { + const transfer = this.incomingFiles.get(peerId); + + if (!transfer || transfer.id !== transferId) { + return; + } + + const blob = new Blob(transfer.chunks, { type: transfer.mimeType }); + const downloadUrl = URL.createObjectURL(blob); + + this.pushMessage({ + id: transfer.id, + peerId, + direction: 'incoming', + kind: 'file', + createdAt: transfer.sentAt, + authorLabel: transfer.authorName, + fileName: transfer.name, + fileSize: transfer.size, + fileMimeType: transfer.mimeType, + downloadUrl, + }, blob); + + this.incomingFiles.delete(peerId); + } + + private async flushPendingCandidates(bundle: PeerBundle): Promise { + while (bundle.pendingCandidates.length > 0) { + const candidate = bundle.pendingCandidates.shift(); + + if (candidate) { + await bundle.pc.addIceCandidate(candidate); + } + } + } + + private sendSignal(peerId: string, signal: SignalPayload): void { + if (!this.websocket || this.websocket.readyState !== WebSocket.OPEN) { + return; + } + + this.websocket.send(JSON.stringify({ type: 'signal', to: peerId, signal })); + } + + private requireOpenChannel(peerId: string): RTCDataChannel | null { + const channel = this.peerBundles.get(peerId)?.channel; + + if (!channel || channel.readyState !== 'open') { + this.error.set('Open a peer connection before sending data.'); + return null; + } + + return channel; + } + + private async waitForBufferedAmount(channel: RTCDataChannel, threshold: number): Promise { + while (channel.bufferedAmount > threshold) { + await new Promise((resolve) => window.setTimeout(resolve, 25)); + } + } + + private releasePeerBundle(peerId: string, preservePeerState: boolean): void { + const bundle = this.peerBundles.get(peerId); + + this.clearPeerTyping(peerId); + this.clearOutgoingTyping(peerId); + + if (!bundle) { + return; + } + + bundle.channel?.close(); + bundle.pc.close(); + this.peerBundles.delete(peerId); + this.incomingFiles.delete(peerId); + + if (preservePeerState) { + this.patchPeer(peerId, { connectionState: 'disconnected', channelState: 'closed' }); + } + } + + private resetPeerConnections(): void { + for (const peerId of this.peerBundles.keys()) { + this.releasePeerBundle(peerId, true); + } + } + + private patchPeer( + peerId: string, + patch: Partial>, + ): void { + this.peers.update((peers) => + peers.map((peer) => (peer.id === peerId ? { ...peer, ...patch } : peer)), + ); + } + + private pushMessage(entry: ChatEntry, fileBlob?: Blob): void { + this.messages.update((messages) => [...messages, entry].sort((left, right) => left.createdAt - right.createdAt)); + + if (entry.direction === 'incoming' && entry.kind !== 'system' && this.activePeerId() !== entry.peerId) { + this.markPeerUnread(entry.peerId); + } + + if (entry.kind !== 'system') { + void this.persistMessage(entry, fileBlob); + } + } + + async deleteMessage(entry: ChatEntry): Promise { + this.removeMessageById(entry.id); + + if (entry.kind === 'system') { + return; + } + + const currentUserId = this.currentUser()?.id; + + if (!currentUserId) { + return; + } + + try { + const storageKey = this.messageStorageKey(currentUserId, entry.peerId, entry.id); + await this.queueMessageStoreOperation(storageKey, async () => { + const database = await this.openMessageDatabase(); + + if (!database) { + return; + } + + const transaction = database.transaction(ChatSessionService.messageStoreName, 'readwrite'); + const store = transaction.objectStore(ChatSessionService.messageStoreName); + store.delete(storageKey); + await this.waitForTransaction(transaction); + }); + } catch (error) { + console.warn('Could not delete chat message.', error); + } + } + + private addSystemMessage(peerId: string, text: string): void { + const id = crypto.randomUUID(); + + this.pushMessage({ + id, + peerId, + direction: 'system', + kind: 'system', + createdAt: Date.now(), + authorLabel: 'System', + text, + }); + + const timeoutId = window.setTimeout(() => { + this.removeMessageById(id); + }, ChatSessionService.systemMessageLifetimeMs); + this.systemMessageTimeouts.set(id, timeoutId); + } + + private isPolitePeer(peerId: string): boolean { + return (this.currentUser()?.id ?? '') > peerId; + } + + private mapConnectionState(state: RTCPeerConnectionState): ConnectionState { + switch (state) { + case 'connected': + return 'connected'; + case 'connecting': + case 'new': + return 'connecting'; + case 'failed': + return 'failed'; + default: + return 'disconnected'; + } + } + + private clearLocalAuth(statusMessage: string): void { + this.disconnectWebSocket(); + this.resetPeerConnections(); + this.clearSystemMessageTimeouts(); + this.clearTypingTimeouts(); + this.messageEncryptionKey = null; + this.revokeMessageDownloads(this.messages()); + this.currentUser.set(null); + this.token.set(null); + this.peers.set([]); + this.accessKeys.set([]); + this.activePeerId.set(null); + this.unreadPeerIds.set([]); + this.typingPeerIds.set([]); + this.messages.set([]); + this.signalingState.set('disconnected'); + this.error.set(null); + this.notice.set(null); + this.status.set(statusMessage); + this.removeStorage('privatechat.token'); + this.removeStorage('privatechat.user'); + } + + private async loadPersistedMessages(userId: string): Promise { + const messageEncryptionKey = this.messageEncryptionKey; + + if (!messageEncryptionKey) { + this.revokeMessageDownloads(this.messages()); + this.messages.set([]); + return; + } + + try { + const database = await this.openMessageDatabase(); + + if (!database) { + this.revokeMessageDownloads(this.messages()); + this.messages.set([]); + return; + } + + const transaction = database.transaction(ChatSessionService.messageStoreName, 'readonly'); + const store = transaction.objectStore(ChatSessionService.messageStoreName); + const ownerIndex = store.index('ownerUserId'); + const rows = await this.waitForRequest( + ownerIndex.getAll(IDBKeyRange.only(userId)), + ) as PersistedChatEntry[]; + + await this.waitForTransaction(transaction); + + const nextMessages = ( + await Promise.all(rows.map((row) => this.hydratePersistedMessage(row, messageEncryptionKey))) + ) + .filter((entry): entry is ChatEntry => entry !== null) + .sort((left, right) => left.createdAt - right.createdAt); + + this.revokeMessageDownloads(this.messages()); + this.messages.set(nextMessages); + + const legacyRows = rows.filter((row): row is LegacyPersistedChatEntry => this.isLegacyPersistedChatEntry(row)); + const encryptedRows = rows.filter( + (row): row is EncryptedPersistedChatEntry => !this.isLegacyPersistedChatEntry(row), + ); + + if (legacyRows.length > 0) { + await Promise.all(legacyRows.map((row) => this.migrateLegacyPersistedMessage(row))); + } + + const encryptedRowsToMigrate = encryptedRows.filter((row) => this.hasLegacyEncryptedBinaryStorage(row)); + + if (encryptedRowsToMigrate.length > 0) { + await Promise.all(encryptedRowsToMigrate.map((row) => this.migrateEncryptedPersistedMessage(row))); + } + } catch (error) { + console.warn('Could not restore persisted chat messages.', error); + } + } + + private async persistMessage(entry: ChatEntry, fileBlob?: Blob): Promise { + const currentUserId = this.currentUser()?.id; + const messageEncryptionKey = this.messageEncryptionKey; + + if (!currentUserId || !messageEncryptionKey || entry.kind === 'system') { + return; + } + + try { + const conversationKey = this.conversationStorageKey(currentUserId, entry.peerId); + const storageKey = this.messageStorageKey(currentUserId, entry.peerId, entry.id); + const encryptedPayload = await this.encryptPersistedMessageContent(messageEncryptionKey, { + authorLabel: entry.authorLabel, + text: entry.text, + payload: entry.payload, + fileName: entry.fileName, + fileSize: entry.fileSize, + fileMimeType: entry.fileMimeType, + }); + const encryptedFileBlob = fileBlob + ? await this.encryptBinary(messageEncryptionKey, await fileBlob.arrayBuffer()) + : null; + const persistedEntry: EncryptedPersistedChatEntry = { + storageKey, + ownerUserId: currentUserId, + conversationKey, + id: entry.id, + peerId: entry.peerId, + direction: entry.direction, + kind: entry.kind, + createdAt: entry.createdAt, + encryptedPayload: this.serializePersistedBinary(encryptedPayload.ciphertext), + payloadIv: Array.from(encryptedPayload.iv), + encryptedFileBlob: encryptedFileBlob + ? this.serializePersistedBinary(encryptedFileBlob.ciphertext) + : undefined, + fileIv: encryptedFileBlob ? Array.from(encryptedFileBlob.iv) : undefined, + }; + + await this.queueMessageStoreOperation(storageKey, async () => { + const database = await this.openMessageDatabase(); + + if (!database) { + return; + } + + const transaction = database.transaction(ChatSessionService.messageStoreName, 'readwrite'); + const store = transaction.objectStore(ChatSessionService.messageStoreName); + store.put(persistedEntry); + + const conversationIndex = store.index('conversationKeyCreatedAt'); + const rows = await this.waitForRequest( + conversationIndex.getAll( + IDBKeyRange.bound([conversationKey, 0], [conversationKey, Number.MAX_SAFE_INTEGER]), + ), + ) as PersistedChatEntry[]; + + const overflow = rows.length - ChatSessionService.messageRetentionLimit; + + if (overflow > 0) { + for (const staleEntry of rows.slice(0, overflow)) { + store.delete(staleEntry.storageKey); + } + } + + await this.waitForTransaction(transaction); + }); + } catch (error) { + console.warn('Could not persist chat message.', error); + } + } + + private async hydratePersistedMessage( + entry: PersistedChatEntry, + messageEncryptionKey: CryptoKey, + ): Promise { + if (this.isLegacyPersistedChatEntry(entry)) { + return this.hydrateLegacyPersistedMessage(entry); + } + + try { + const content = await this.decryptPersistedMessageContent(messageEncryptionKey, entry); + let downloadUrl: string | undefined; + + if (entry.encryptedFileBlob && entry.fileIv) { + const decryptedFile = await this.decryptBinary( + messageEncryptionKey, + this.deserializePersistedBinary(entry.encryptedFileBlob), + Uint8Array.from(entry.fileIv).buffer, + ); + const fileBlob = new Blob([decryptedFile], { + type: content.fileMimeType || 'application/octet-stream', + }); + downloadUrl = URL.createObjectURL(fileBlob); + } + + return { + id: entry.id, + peerId: entry.peerId, + direction: entry.direction, + kind: entry.kind, + createdAt: entry.createdAt, + authorLabel: content.authorLabel, + text: content.text, + payload: content.payload, + fileName: content.fileName, + fileSize: content.fileSize, + fileMimeType: content.fileMimeType, + downloadUrl, + }; + } catch (error) { + console.warn('Could not decrypt persisted chat message.', error); + return null; + } + } + + private hydrateLegacyPersistedMessage(entry: LegacyPersistedChatEntry): ChatEntry { + return { + id: entry.id, + peerId: entry.peerId, + direction: entry.direction, + kind: entry.kind, + createdAt: entry.createdAt, + authorLabel: entry.authorLabel, + text: entry.text, + payload: entry.payload, + fileName: entry.fileName, + fileSize: entry.fileSize, + fileMimeType: entry.fileMimeType, + downloadUrl: entry.fileBlob ? URL.createObjectURL(entry.fileBlob) : undefined, + }; + } + + private async migrateLegacyPersistedMessage(entry: LegacyPersistedChatEntry): Promise { + const hydratedEntry = this.hydrateLegacyPersistedMessage(entry); + const fileBlob = entry.fileBlob + ? new Blob([await entry.fileBlob.arrayBuffer()], { + type: entry.fileMimeType || 'application/octet-stream', + }) + : undefined; + + await this.persistMessage(hydratedEntry, fileBlob); + } + + private async migrateEncryptedPersistedMessage(entry: EncryptedPersistedChatEntry): Promise { + const migratedEntry: EncryptedPersistedChatEntry = { + ...entry, + encryptedPayload: this.serializePersistedBinary(this.deserializePersistedBinary(entry.encryptedPayload)), + encryptedFileBlob: entry.encryptedFileBlob + ? this.serializePersistedBinary(this.deserializePersistedBinary(entry.encryptedFileBlob)) + : undefined, + }; + + await this.queueMessageStoreOperation(entry.storageKey, async () => { + const database = await this.openMessageDatabase(); + + if (!database) { + return; + } + + const transaction = database.transaction(ChatSessionService.messageStoreName, 'readwrite'); + const store = transaction.objectStore(ChatSessionService.messageStoreName); + store.put(migratedEntry); + await this.waitForTransaction(transaction); + }); + } + + private revokeMessageDownloads(entries: ChatEntry[]): void { + for (const entry of entries) { + if (entry.downloadUrl?.startsWith('blob:')) { + URL.revokeObjectURL(entry.downloadUrl); + } + } + } + + private conversationStorageKey(currentUserId: string, peerId: string): string { + return `${currentUserId}:${peerId}`; + } + + private messageStorageKey(currentUserId: string, peerId: string, messageId: string): string { + return `${this.conversationStorageKey(currentUserId, peerId)}:${messageId}`; + } + + private queueMessageStoreOperation(storageKey: string, operation: () => Promise): Promise { + const previous = this.messageStoreOperations.get(storageKey) ?? Promise.resolve(); + const next = previous + .catch(() => { + // Keep the queue moving after a failed operation for the same message. + }) + .then(operation); + + this.messageStoreOperations.set(storageKey, next); + + return next.finally(() => { + if (this.messageStoreOperations.get(storageKey) === next) { + this.messageStoreOperations.delete(storageKey); + } + }); + } + + private async importMessageEncryptionKey(rawKey: string): Promise { + if (!globalThis.crypto?.subtle) { + throw new Error('This browser does not support message encryption.'); + } + + return crypto.subtle.importKey( + 'raw', + this.base64UrlToBuffer(rawKey), + { name: 'AES-GCM' }, + false, + ['encrypt', 'decrypt'], + ); + } + + private isLegacyPersistedChatEntry(entry: PersistedChatEntry): entry is LegacyPersistedChatEntry { + return !('encryptedPayload' in entry); + } + + private async encryptPersistedMessageContent( + messageEncryptionKey: CryptoKey, + content: PersistedChatEntryContent, + ): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array }> { + const encoded = new TextEncoder().encode(JSON.stringify(content)); + return this.encryptBinary(messageEncryptionKey, encoded.buffer); + } + + private async decryptPersistedMessageContent( + messageEncryptionKey: CryptoKey, + entry: EncryptedPersistedChatEntry, + ): Promise { + const decrypted = await this.decryptBinary( + messageEncryptionKey, + this.deserializePersistedBinary(entry.encryptedPayload), + Uint8Array.from(entry.payloadIv).buffer, + ); + + return JSON.parse(new TextDecoder().decode(decrypted)) as PersistedChatEntryContent; + } + + private async encryptBinary( + messageEncryptionKey: CryptoKey, + value: ArrayBuffer, + ): Promise<{ ciphertext: ArrayBuffer; iv: Uint8Array }> { + const ivBuffer = new ArrayBuffer(12); + const iv = new Uint8Array(ivBuffer); + crypto.getRandomValues(iv); + const ciphertext = await crypto.subtle.encrypt( + { name: 'AES-GCM', iv: ivBuffer }, + messageEncryptionKey, + value, + ); + + return { ciphertext, iv }; + } + + private async decryptBinary( + messageEncryptionKey: CryptoKey, + value: ArrayBuffer, + iv: ArrayBuffer, + ): Promise { + return crypto.subtle.decrypt( + { name: 'AES-GCM', iv }, + messageEncryptionKey, + value, + ); + } + + private hasLegacyEncryptedBinaryStorage(entry: EncryptedPersistedChatEntry): boolean { + return typeof entry.encryptedPayload !== 'string' + || (!!entry.encryptedFileBlob && typeof entry.encryptedFileBlob !== 'string'); + } + + private serializePersistedBinary(value: ArrayBuffer): string { + return this.bufferToBase64Url(value); + } + + private deserializePersistedBinary(value: PersistedBinary): ArrayBuffer { + return typeof value === 'string' ? this.base64UrlToBuffer(value) : value; + } + + private sendTypingState(peerId: string, active: boolean, force = false): void { + const existingIdleTimeoutId = this.outgoingTypingIdleTimeouts.get(peerId); + + if (typeof existingIdleTimeoutId !== 'undefined') { + window.clearTimeout(existingIdleTimeoutId); + this.outgoingTypingIdleTimeouts.delete(peerId); + } + + const currentState = this.outgoingTypingStates.get(peerId); + + if (!force && currentState?.active === active) { + if (!active) { + this.outgoingTypingStates.delete(peerId); + } + + return; + } + + const channel = this.peerBundles.get(peerId)?.channel; + + if (!channel || channel.readyState !== 'open') { + if (active) { + this.outgoingTypingStates.set(peerId, { active: true, lastSentAt: Date.now() }); + } else { + this.outgoingTypingStates.delete(peerId); + } + return; + } + + channel.send(JSON.stringify({ type: 'typing', active } satisfies DataEnvelope)); + + if (active) { + this.outgoingTypingStates.set(peerId, { active: true, lastSentAt: Date.now() }); + return; + } + + this.outgoingTypingStates.delete(peerId); + } + + private removeMessageById(messageId: string): void { + const message = this.messages().find((entry) => entry.id === messageId); + + if (!message) { + return; + } + + if (message.downloadUrl?.startsWith('blob:')) { + URL.revokeObjectURL(message.downloadUrl); + } + + const timeoutId = this.systemMessageTimeouts.get(messageId); + + if (typeof timeoutId !== 'undefined') { + window.clearTimeout(timeoutId); + this.systemMessageTimeouts.delete(messageId); + } + + this.messages.update((messages) => messages.filter((entry) => entry.id !== messageId)); + } + + private clearSystemMessageTimeouts(): void { + for (const timeoutId of this.systemMessageTimeouts.values()) { + window.clearTimeout(timeoutId); + } + + this.systemMessageTimeouts.clear(); + } + + private markPeerUnread(peerId: string): void { + this.unreadPeerIds.update((peerIds) => (peerIds.includes(peerId) ? peerIds : [...peerIds, peerId])); + } + + private clearUnreadPeer(peerId: string): void { + this.unreadPeerIds.update((peerIds) => peerIds.filter((id) => id !== peerId)); + } + + private setPeerTyping(peerId: string, active: boolean): void { + const existingTimeoutId = this.typingIndicatorTimeouts.get(peerId); + + if (typeof existingTimeoutId !== 'undefined') { + window.clearTimeout(existingTimeoutId); + this.typingIndicatorTimeouts.delete(peerId); + } + + if (!active) { + this.clearPeerTyping(peerId); + return; + } + + this.typingPeerIds.update((peerIds) => (peerIds.includes(peerId) ? peerIds : [...peerIds, peerId])); + + const timeoutId = window.setTimeout(() => { + this.clearPeerTyping(peerId); + }, ChatSessionService.typingIndicatorLifetimeMs); + + this.typingIndicatorTimeouts.set(peerId, timeoutId); + } + + private clearPeerTyping(peerId: string): void { + const timeoutId = this.typingIndicatorTimeouts.get(peerId); + + if (typeof timeoutId !== 'undefined') { + window.clearTimeout(timeoutId); + this.typingIndicatorTimeouts.delete(peerId); + } + + this.typingPeerIds.update((peerIds) => peerIds.filter((id) => id !== peerId)); + } + + private clearOutgoingTyping(peerId: string): void { + const idleTimeoutId = this.outgoingTypingIdleTimeouts.get(peerId); + + if (typeof idleTimeoutId !== 'undefined') { + window.clearTimeout(idleTimeoutId); + this.outgoingTypingIdleTimeouts.delete(peerId); + } + + this.outgoingTypingStates.delete(peerId); + } + + private clearTypingTimeouts(): void { + for (const timeoutId of this.typingIndicatorTimeouts.values()) { + window.clearTimeout(timeoutId); + } + + for (const timeoutId of this.outgoingTypingIdleTimeouts.values()) { + window.clearTimeout(timeoutId); + } + + this.typingIndicatorTimeouts.clear(); + this.outgoingTypingIdleTimeouts.clear(); + this.outgoingTypingStates.clear(); + } + + private async openMessageDatabase(): Promise { + if (this.messageDatabasePromise) { + return this.messageDatabasePromise; + } + + if (typeof indexedDB === 'undefined') { + this.messageDatabasePromise = Promise.resolve(null); + return this.messageDatabasePromise; + } + + this.messageDatabasePromise = new Promise((resolve, reject) => { + const request = indexedDB.open(ChatSessionService.messageDatabaseName, 2); + + request.onupgradeneeded = () => { + const database = request.result; + const store = database.objectStoreNames.contains(ChatSessionService.messageStoreName) + ? request.transaction!.objectStore(ChatSessionService.messageStoreName) + : database.createObjectStore(ChatSessionService.messageStoreName, { keyPath: 'storageKey' }); + + if (!store.indexNames.contains('ownerUserId')) { + store.createIndex('ownerUserId', 'ownerUserId', { unique: false }); + } + + if (!store.indexNames.contains('conversationKeyCreatedAt')) { + store.createIndex('conversationKeyCreatedAt', ['conversationKey', 'createdAt'], { unique: false }); + } + }; + + request.onsuccess = () => { + const database = request.result; + database.onversionchange = () => { + database.close(); + this.messageDatabasePromise = null; + }; + resolve(database); + }; + + request.onerror = () => { + reject(request.error ?? new Error('Could not open IndexedDB.')); + }; + }); + + return this.messageDatabasePromise; + } + + private waitForRequest(request: IDBRequest): Promise { + return new Promise((resolve, reject) => { + request.onsuccess = () => resolve(request.result); + request.onerror = () => reject(request.error ?? new Error('IndexedDB request failed.')); + }); + } + + private waitForTransaction(transaction: IDBTransaction): Promise { + return new Promise((resolve, reject) => { + transaction.oncomplete = () => resolve(); + transaction.onabort = () => reject(transaction.error ?? new Error('IndexedDB transaction aborted.')); + transaction.onerror = () => reject(transaction.error ?? new Error('IndexedDB transaction failed.')); + }); + } + + private toWebSocketUrl(httpUrl: string, token: string): string { + const normalized = new URL(httpUrl); + normalized.protocol = normalized.protocol === 'https:' ? 'wss:' : 'ws:'; + normalized.pathname = '/ws'; + normalized.search = `token=${encodeURIComponent(token)}`; + + return normalized.toString(); + } + + private toPublicKeyCreationOptions(options: RegistrationOptionsResponse): PublicKeyCredentialCreationOptions { + return { + ...options, + challenge: this.base64UrlToBuffer(options.challenge), + user: { + ...options.user, + id: this.base64UrlToBuffer(options.user.id), + }, + excludeCredentials: options.excludeCredentials?.map((credential) => ({ + ...credential, + id: this.base64UrlToBuffer(credential.id), + transports: credential.transports as AuthenticatorTransport[] | undefined, + })), + }; + } + + private toPublicKeyRequestOptions(options: AuthenticationOptionsResponse): PublicKeyCredentialRequestOptions { + return { + challenge: this.base64UrlToBuffer(options.challenge), + timeout: options.timeout, + rpId: options.rpId, + userVerification: options.userVerification, + allowCredentials: options.allowCredentials?.map((credential) => ({ + ...credential, + id: this.base64UrlToBuffer(credential.id), + transports: credential.transports as AuthenticatorTransport[] | undefined, + })), + extensions: options.extensions, + }; + } + + private serializeRegistrationCredential(credential: PublicKeyCredential) { + const response = credential.response as AuthenticatorAttestationResponse & { + getTransports?: () => string[]; + }; + + return { + id: credential.id, + rawId: this.bufferToBase64Url(credential.rawId), + response: { + clientDataJSON: this.bufferToBase64Url(response.clientDataJSON), + attestationObject: this.bufferToBase64Url(response.attestationObject), + transports: response.getTransports?.(), + }, + clientExtensionResults: credential.getClientExtensionResults(), + type: credential.type, + authenticatorAttachment: credential.authenticatorAttachment ?? undefined, + }; + } + + private serializeAuthenticationCredential(credential: PublicKeyCredential) { + const response = credential.response as AuthenticatorAssertionResponse; + + return { + id: credential.id, + rawId: this.bufferToBase64Url(credential.rawId), + response: { + clientDataJSON: this.bufferToBase64Url(response.clientDataJSON), + authenticatorData: this.bufferToBase64Url(response.authenticatorData), + signature: this.bufferToBase64Url(response.signature), + userHandle: response.userHandle ? this.bufferToBase64Url(response.userHandle) : undefined, + }, + clientExtensionResults: credential.getClientExtensionResults(), + type: credential.type, + authenticatorAttachment: credential.authenticatorAttachment ?? undefined, + }; + } + + private base64UrlToBuffer(value: string): ArrayBuffer { + const padding = '='.repeat((4 - (value.length % 4)) % 4); + const normalized = (value + padding).replace(/-/g, '+').replace(/_/g, '/'); + const binary = atob(normalized); + const bytes = new Uint8Array(binary.length); + + for (let index = 0; index < binary.length; index += 1) { + bytes[index] = binary.charCodeAt(index); + } + + return bytes.buffer.slice(0); + } + + private bufferToBase64Url(value: ArrayBuffer): string { + let binary = ''; + const bytes = new Uint8Array(value); + + for (const byte of bytes) { + binary += String.fromCharCode(byte); + } + + return btoa(binary).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); + } + + private readUserStorage(): UserProfile | null { + const value = this.readStorage('privatechat.user'); + + if (!value) { + return null; + } + + try { + return JSON.parse(value) as UserProfile; + } catch { + return null; + } + } + + private readStorage(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } + } + + private writeStorage(key: string, value: string): void { + try { + localStorage.setItem(key, value); + } catch { + // Ignore storage errors in private browsing modes. + } + } + + private removeStorage(key: string): void { + try { + localStorage.removeItem(key); + } catch { + // Ignore storage errors in private browsing modes. + } + } + + private extractErrorMessage(error: unknown, fallback: string): string { + const httpError = error as HttpErrorResponse | undefined; + const responseMessage = + typeof httpError?.error?.message === 'string' ? httpError.error.message : undefined; + const thrownMessage = error instanceof Error ? error.message : undefined; + + return responseMessage ?? thrownMessage ?? fallback; + } +} diff --git a/client/src/app/home-page.component.html b/client/src/app/home-page.component.html new file mode 100644 index 0000000..6254448 --- /dev/null +++ b/client/src/app/home-page.component.html @@ -0,0 +1,269 @@ +
+
+ @if (!embeddedMode) { +
+
+
+
+ WebRTC Private Chat + +
+
+ + @if (session.currentUser(); as user) { +
+
Signed in
+
{{ user.displayName }}
+
{{ user.username }}
+
{{ session.status() }}
+ + @if (session.isApprovalAdmin()) { + Approve accounts + } + +
+ } +
+
+ } + + @if (!session.currentUser()) { + @if (embeddedMode) { +
+

Open Settings to sign in

+

+ This embedded client expects authentication and backend configuration from the native app settings. +

+
+ } @else { +
+
+
+
+
+

Connect to the signaling backend

+

Use the Fastify server for authentication and peer discovery.

+
+ Angular + Bootstrap +
+ +
+ + +
+ +
+ + +
+ +
+ @if (authMode === 'register') { +
+ + +
+ } + +
+ + +
+ +
+ + +
+ + + + @if (authMode === 'login' && session.webAuthnSupported()) { +
or
+ +
+ Leave the username blank to choose from discoverable passkeys, or enter it to target one account. +
+ } +
+ + @if (session.error()) { +
{{ session.error() }}
+ } + + @if (session.notice()) { +
{{ session.notice() }}
+ } +
+
+ +
+
+

Transport model

+
+
+
1. Authenticate
+

Register or log in against the Fastify API to receive a JWT.

+
+
+
2. Discover peers
+

Open the WebSocket signaling session and receive the online peer list.

+
+
+
3. Exchange data directly
+

Create a WebRTC data channel and send text, JSON, or files peer-to-peer.

+
+
+
+
+
+ } + } @else { +
+
+
+
+
+

Connection settings

+

Manage the backend endpoint used for auth and signaling.

+
+ @if (session.isApprovalAdmin()) { + Approvals + } +
+ + @if (!embeddedMode) { + +
+ + +
+ } @else { +
+ Backend settings are managed by the native app in embedded mode. +
+ } + +
{{ session.status() }}
+ + @if (session.error()) { +
{{ session.error() }}
+ } + + @if (session.notice()) { +
{{ session.notice() }}
+ } +
+
+ +
+
+
+
+
+

Access keys

+

Register one or more WebAuthn credentials for this account.

+
+ {{ session.accessKeys().length }} +
+ + @if (!embeddedMode && session.webAuthnSupported()) { +
+ + +
+ } @else if (!embeddedMode) { +
This browser does not expose WebAuthn registration APIs.
+ } @else { +
+ Access keys are managed through the native app in embedded mode. +
+ } + +
+ @if (session.accessKeys().length === 0) { +
No access keys registered yet.
+ } + + @for (key of session.accessKeys(); track key.id) { +
+
{{ key.label }}
+
Device: {{ key.deviceType }}{{ key.backedUp ? ' / backed up' : '' }}
+
Transports: {{ key.transports.length > 0 ? key.transports.join(', ') : 'unspecified' }}
+
Added: {{ key.createdAt | date: 'medium' }}
+
+ } +
+
+
+
+
+ } +
+
diff --git a/client/src/app/home-page.component.scss b/client/src/app/home-page.component.scss new file mode 100644 index 0000000..7d32ada --- /dev/null +++ b/client/src/app/home-page.component.scss @@ -0,0 +1,156 @@ +:host { + display: block; + min-height: 100dvh; + color: var(--page-text); +} + +.shell { + min-height: 100dvh; +} + +.hero-panel, +.panel, +.session-card, +.empty-state { + border: 1px solid var(--surface-border); + background: var(--panel-background); + backdrop-filter: blur(18px); + box-shadow: 0 20px 60px var(--shadow-color); +} + +.hero-panel { + border-radius: 2rem; +} + +.panel { + border-radius: 1.5rem; +} + +.panel-muted { + background: var(--panel-alt-background); +} + +.hero-copy { + max-width: 52rem; +} + +.eyebrow { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.45rem 0.85rem; + border-radius: 999px; + margin-bottom: 1rem; + letter-spacing: 0.14em; + text-transform: uppercase; + font-size: 0.72rem; + font-weight: 700; + color: var(--accent-color); + background: var(--accent-color-soft); +} + +.theme-toggle { + display: inline-flex; + align-items: center; + gap: 0.55rem; + min-width: 7.5rem; + height: 3rem; + padding: 0 0.95rem; + border: 1px solid var(--surface-border); + border-radius: 999px; + color: var(--page-text); + background: var(--panel-soft-background); + font-size: 0.95rem; + font-weight: 700; + text-transform: capitalize; + line-height: 1; + transition: transform 160ms ease, background 160ms ease, border-color 160ms ease; +} + +.theme-toggle-icon { + font-size: 1.25rem; +} + +.theme-toggle-label { + letter-spacing: 0.03em; +} + +.theme-toggle:hover, +.theme-toggle:focus-visible { + transform: translateY(-1px); + border-color: color-mix(in srgb, var(--accent-color) 35%, var(--surface-border)); + background: var(--surface-hover-background); +} + +.session-card { + min-width: min(100%, 18rem); + border-radius: 1.5rem; +} + +.status-pill { + display: inline-flex; + padding: 0.45rem 0.8rem; + border-radius: 999px; + background: var(--badge-background); +} + +.btn-accent { + color: #06111d; + border: 0; + background: var(--accent-gradient); +} + +.btn-accent:hover, +.btn-accent:focus-visible { + color: #06111d; + background: var(--accent-gradient-hover); +} + +.access-key-panel { + padding: 1rem; + border-radius: 1rem; + background: var(--panel-soft-background); +} + +.access-key-card { + border-radius: 0.9rem; + border: 1px solid var(--surface-border-soft); + background: var(--surface-background); +} + +.empty-state { + border-radius: 1.25rem; +} + +.info-rail article { + padding: 1rem 1.1rem; + border-radius: 1rem; + background: var(--panel-soft-background); +} + +.form-control, +.form-control:focus { + color: var(--page-text); + background-color: var(--input-background); + border-color: var(--input-border); + box-shadow: none; +} + +.form-control::placeholder { + color: var(--placeholder-color); +} + +.form-label, +.h3, +.h4, +.display-5, +.fw-semibold, +.fw-bold { + color: var(--page-text); +} + +.text-secondary, +.lead, +.small { + color: var(--page-text-muted) !important; +} diff --git a/client/src/app/home-page.component.ts b/client/src/app/home-page.component.ts new file mode 100644 index 0000000..ddcab09 --- /dev/null +++ b/client/src/app/home-page.component.ts @@ -0,0 +1,102 @@ +import { CommonModule } from '@angular/common'; +import { Component, effect, inject } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { Router, RouterLink } from '@angular/router'; + +import { ChatSessionService } from './chat-session.service'; +import { ThemeService } from './theme.service'; + +@Component({ + selector: 'app-home-page', + imports: [CommonModule, FormsModule, RouterLink], + templateUrl: './home-page.component.html', + styleUrl: './home-page.component.scss', +}) +export class HomePageComponent { + private readonly router = inject(Router); + readonly theme = inject(ThemeService); + authMode: 'login' | 'register' = 'login'; + readonly embeddedMode = + typeof window !== 'undefined' && window.localStorage.getItem('privatechat.embeddedMode') === '1'; + serverUrl = ''; + displayName = ''; + username = ''; + password = ''; + accessKeyLabel = ''; + + constructor(readonly session: ChatSessionService) { + this.serverUrl = session.serverUrl(); + + if (this.embeddedMode) { + effect(() => { + const currentUser = this.session.currentUser(); + const activePeerId = this.session.activePeerId(); + + if (!currentUser || !activePeerId) { + return; + } + + void this.router.navigate(['/chat', activePeerId], { replaceUrl: true }); + }); + } + } + + async submitAuth(): Promise { + this.applyServerUrl(); + + if (this.authMode === 'register') { + const authenticated = await this.session.register(this.username, this.password, this.displayName); + this.password = ''; + + if (!authenticated) { + this.authMode = 'login'; + } + + return; + } + + await this.session.login(this.username, this.password); + } + + applyServerUrl(): void { + this.session.setServerUrl(this.serverUrl); + } + + async logout(): Promise { + await this.session.logout(); + this.authMode = 'login'; + this.displayName = ''; + this.password = ''; + } + + async loginWithAccessKey(): Promise { + this.applyServerUrl(); + await this.session.loginWithAccessKey(this.username); + this.password = ''; + } + + async registerAccessKey(): Promise { + await this.session.registerAccessKey(this.accessKeyLabel); + this.accessKeyLabel = ''; + } + + canOpenChatUi(): boolean { + return this.session.peers().length > 0; + } + + async openChatUi(): Promise { + const peerId = this.session.activePeerId() ?? this.session.peers()[0]?.id; + + if (!peerId) { + this.session.error.set('No connected peers are available yet.'); + return; + } + + this.session.selectPeer(peerId); + await this.router.navigate(['/chat', peerId]); + } + + cycleTheme(): void { + this.theme.cycleMode(); + } +} diff --git a/client/src/app/models.ts b/client/src/app/models.ts new file mode 100644 index 0000000..862ac08 --- /dev/null +++ b/client/src/app/models.ts @@ -0,0 +1,144 @@ +export type ConnectionState = 'disconnected' | 'connecting' | 'connected' | 'failed'; +export type ChannelState = 'closed' | 'connecting' | 'open'; + +export interface UserProfile { + id: string; + username: string; + displayName: string; +} + +export interface PeerSummary extends UserProfile { + connectionState: ConnectionState; + channelState: ChannelState; +} + +export interface AuthResponse { + token: string; + user: UserProfile; + messageEncryptionKey: string; +} + +export interface SessionResponse { + user: UserProfile; + messageEncryptionKey: string; +} + +export interface PendingApprovalResponse { + pendingApproval: true; + message: string; +} + +export interface PendingApprovalUser { + id: string; + username: string; + displayName: string; + createdAt: string; +} + +export interface AccessKeySummary { + id: string; + credentialId: string; + label: string; + transports: string[]; + deviceType: string; + backedUp: boolean; + aaguid: string; + createdAt: string; +} + +export interface RegistrationOptionsResponse { + rp: PublicKeyCredentialRpEntity; + user: { + id: string; + name: string; + displayName: string; + }; + challenge: string; + pubKeyCredParams: PublicKeyCredentialParameters[]; + timeout?: number; + excludeCredentials?: Array<{ + id: string; + type: PublicKeyCredentialType; + transports?: string[]; + }>; + authenticatorSelection?: AuthenticatorSelectionCriteria; + attestation?: AttestationConveyancePreference; + extensions?: AuthenticationExtensionsClientInputs; +} + +export interface AuthenticationOptionsResponse { + attemptId: string; + challenge: string; + timeout?: number; + rpId?: string; + allowCredentials?: Array<{ + id: string; + type: PublicKeyCredentialType; + transports?: string[]; + }>; + userVerification?: UserVerificationRequirement; + hints?: string[]; + extensions?: AuthenticationExtensionsClientInputs; +} + +export interface ChatEntry { + id: string; + peerId: string; + direction: 'incoming' | 'outgoing' | 'system'; + kind: 'text' | 'json' | 'file' | 'system'; + createdAt: number; + authorLabel: string; + text?: string; + payload?: unknown; + fileName?: string; + fileSize?: number; + fileMimeType?: string; + downloadUrl?: string; +} + +export type SignalPayload = + | { type: 'sdp'; description: RTCSessionDescriptionInit } + | { type: 'ice-candidate'; candidate: RTCIceCandidateInit }; + +export type ServerEvent = + | { type: 'presence'; self: UserProfile; peers: UserProfile[] } + | { type: 'peer-joined'; peer: UserProfile } + | { type: 'peer-left'; peerId: string } + | { type: 'signal'; from: string; signal: SignalPayload } + | { type: 'error'; message: string }; + +export type DataEnvelope = + | { + type: 'text'; + id: string; + body: string; + authorId: string; + authorName: string; + sentAt: number; + } + | { + type: 'json'; + id: string; + body: unknown; + authorId: string; + authorName: string; + sentAt: number; + } + | { + type: 'file-meta'; + id: string; + name: string; + mimeType: string; + size: number; + authorId: string; + authorName: string; + sentAt: number; + } + | { + type: 'file-complete'; + id: string; + } + | { + type: 'typing'; + active: boolean; + }; diff --git a/client/src/app/theme.service.ts b/client/src/app/theme.service.ts new file mode 100644 index 0000000..619224b --- /dev/null +++ b/client/src/app/theme.service.ts @@ -0,0 +1,110 @@ +import { Injectable, computed, signal } from '@angular/core'; + +export type ThemeMode = 'light' | 'dark' | 'system'; +type ResolvedTheme = 'light' | 'dark'; + +@Injectable({ providedIn: 'root' }) +export class ThemeService { + private readonly storageKey = 'privatechat.themeMode'; + private readonly mediaQuery = + typeof window !== 'undefined' ? window.matchMedia('(prefers-color-scheme: dark)') : null; + + readonly mode = signal(this.readStoredMode()); + readonly resolvedTheme = computed(() => { + const mode = this.mode(); + + if (mode === 'system') { + return this.mediaQuery?.matches ? 'dark' : 'light'; + } + + return mode === 'dark' ? 'dark' : 'light'; + }); + + readonly emoji = computed(() => { + switch (this.mode()) { + case 'light': + return '🌞'; + case 'dark': + return '🌙'; + default: + return '🖥️'; + } + }); + + readonly nextMode = computed(() => { + switch (this.mode()) { + case 'light': + return 'dark'; + case 'dark': + return 'system'; + default: + return 'light'; + } + }); + + constructor() { + this.applyTheme(); + const mediaQuery = this.mediaQuery as + | (MediaQueryList & { + addListener?: (listener: () => void) => void; + }) + | null; + + if (mediaQuery) { + try { + mediaQuery.addEventListener('change', this.handleSystemThemeChange); + } catch { + mediaQuery.addListener?.(this.handleSystemThemeChange); + } + } + } + + cycleMode(): void { + this.setMode(this.nextMode()); + } + + setMode(mode: ThemeMode): void { + this.mode.set(mode); + this.writeStoredMode(mode); + this.applyTheme(); + } + + private readonly handleSystemThemeChange = (): void => { + if (this.mode() === 'system') { + this.applyTheme(); + } + }; + + private applyTheme(): void { + if (typeof document === 'undefined') { + return; + } + + document.documentElement.dataset['themeMode'] = this.mode(); + document.documentElement.dataset['theme'] = this.resolvedTheme(); + document.documentElement.dataset['bsTheme'] = this.resolvedTheme(); + document.documentElement.style.colorScheme = this.resolvedTheme(); + } + + private readStoredMode(): ThemeMode { + try { + const value = localStorage.getItem(this.storageKey); + + if (value === 'light' || value === 'dark' || value === 'system') { + return value; + } + } catch { + // Ignore storage access issues. + } + + return 'system'; + } + + private writeStoredMode(mode: ThemeMode): void { + try { + localStorage.setItem(this.storageKey, mode); + } catch { + // Ignore storage access issues. + } + } +} diff --git a/client/src/index.html b/client/src/index.html new file mode 100644 index 0000000..574cb26 --- /dev/null +++ b/client/src/index.html @@ -0,0 +1,17 @@ + + + + + PrivateChat + + + + + + + + + + + + diff --git a/client/src/main.ts b/client/src/main.ts new file mode 100644 index 0000000..5df75f9 --- /dev/null +++ b/client/src/main.ts @@ -0,0 +1,6 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { App } from './app/app'; + +bootstrapApplication(App, appConfig) + .catch((err) => console.error(err)); diff --git a/client/src/styles.scss b/client/src/styles.scss new file mode 100644 index 0000000..e4a9816 --- /dev/null +++ b/client/src/styles.scss @@ -0,0 +1,179 @@ +@use 'bootstrap/scss/bootstrap'; + +:root { + --page-text: #142236; + --page-text-muted: rgba(39, 63, 91, 0.72); + --page-text-soft: rgba(39, 63, 91, 0.82); + --page-background: + radial-gradient(circle at top left, rgba(81, 168, 255, 0.2), transparent 30%), + radial-gradient(circle at top right, rgba(129, 244, 215, 0.22), transparent 24%), + linear-gradient(180deg, #f6fbff 0%, #e8f1fb 100%); + --panel-background: rgba(255, 255, 255, 0.82); + --panel-alt-background: rgba(241, 247, 255, 0.9); + --panel-soft-background: rgba(20, 34, 54, 0.04); + --surface-background: rgba(255, 255, 255, 0.82); + --surface-hover-background: rgba(235, 244, 255, 0.98); + --surface-border: rgba(33, 62, 94, 0.12); + --surface-border-soft: rgba(33, 62, 94, 0.08); + --input-background: rgba(255, 255, 255, 0.92); + --input-border: rgba(77, 114, 154, 0.26); + --placeholder-color: rgba(55, 83, 118, 0.52); + --accent-color: #138a7b; + --accent-color-soft: rgba(19, 138, 123, 0.1); + --accent-gradient: linear-gradient(135deg, #8df0df, #6cb6ff); + --accent-gradient-hover: linear-gradient(135deg, #a6f5e8, #86c4ff); + --link-color: #2f7cd6; + --badge-background: rgba(20, 34, 54, 0.08); + --incoming-bubble-background: #d9ebff; + --incoming-bubble-text: #183759; + --outgoing-bubble-background: #d9f5df; + --outgoing-bubble-text: #1e4d2f; + --danger-background: #d94b53; + --shadow-color: rgba(41, 73, 110, 0.14); + color-scheme: light; +} + +@media (prefers-color-scheme: dark) { + :root:not([data-theme]) { + --page-text: #eff3ff; + --page-text-muted: rgba(231, 238, 249, 0.72); + --page-text-soft: rgba(231, 238, 249, 0.84); + --page-background: + radial-gradient(circle at top left, rgba(129, 244, 215, 0.18), transparent 28%), + radial-gradient(circle at top right, rgba(85, 168, 255, 0.18), transparent 24%), + linear-gradient(180deg, #08111d 0%, #101d31 100%); + --panel-background: rgba(9, 16, 28, 0.78); + --panel-alt-background: rgba(15, 27, 44, 0.78); + --panel-soft-background: rgba(255, 255, 255, 0.04); + --surface-background: rgba(8, 14, 23, 0.7); + --surface-hover-background: rgba(16, 30, 49, 0.92); + --surface-border: rgba(255, 255, 255, 0.12); + --surface-border-soft: rgba(255, 255, 255, 0.08); + --input-background: rgba(255, 255, 255, 0.06); + --input-border: rgba(255, 255, 255, 0.16); + --placeholder-color: rgba(239, 243, 255, 0.5); + --accent-color: #81f4d7; + --accent-color-soft: rgba(129, 244, 215, 0.1); + --accent-gradient: linear-gradient(135deg, #81f4d7, #55a8ff); + --accent-gradient-hover: linear-gradient(135deg, #9bf7e0, #7abaff); + --link-color: #9bd5ff; + --badge-background: rgba(255, 255, 255, 0.08); + --incoming-bubble-background: #dcefff; + --incoming-bubble-text: #0f2540; + --outgoing-bubble-background: #def7dd; + --outgoing-bubble-text: #153420; + --danger-background: #d94b53; + --shadow-color: rgba(0, 0, 0, 0.28); + color-scheme: dark; + } +} + +:root[data-theme='dark'] { + --page-text: #eff3ff; + --page-text-muted: rgba(231, 238, 249, 0.72); + --page-text-soft: rgba(231, 238, 249, 0.84); + --page-background: + radial-gradient(circle at top left, rgba(129, 244, 215, 0.18), transparent 28%), + radial-gradient(circle at top right, rgba(85, 168, 255, 0.18), transparent 24%), + linear-gradient(180deg, #08111d 0%, #101d31 100%); + --panel-background: rgba(9, 16, 28, 0.78); + --panel-alt-background: rgba(15, 27, 44, 0.78); + --panel-soft-background: rgba(255, 255, 255, 0.04); + --surface-background: rgba(8, 14, 23, 0.7); + --surface-hover-background: rgba(16, 30, 49, 0.92); + --surface-border: rgba(255, 255, 255, 0.12); + --surface-border-soft: rgba(255, 255, 255, 0.08); + --input-background: rgba(255, 255, 255, 0.06); + --input-border: rgba(255, 255, 255, 0.16); + --placeholder-color: rgba(239, 243, 255, 0.5); + --accent-color: #81f4d7; + --accent-color-soft: rgba(129, 244, 215, 0.1); + --accent-gradient: linear-gradient(135deg, #81f4d7, #55a8ff); + --accent-gradient-hover: linear-gradient(135deg, #9bf7e0, #7abaff); + --link-color: #9bd5ff; + --badge-background: rgba(255, 255, 255, 0.08); + --incoming-bubble-background: #dcefff; + --incoming-bubble-text: #0f2540; + --outgoing-bubble-background: #def7dd; + --outgoing-bubble-text: #153420; + --danger-background: #d94b53; + --shadow-color: rgba(0, 0, 0, 0.28); + color-scheme: dark; +} + +:root[data-theme='light'] { + color-scheme: light; +} + +html, +body { + min-height: 100dvh; +} + +body { + margin: 0; + color: var(--page-text); + font-family: 'Space Grotesk', system-ui, sans-serif; + background: var(--page-background); + background-attachment: fixed; + transition: + background 180ms ease, + color 180ms ease, + border-color 180ms ease, + box-shadow 180ms ease; +} + +button, +input, +textarea { + font: inherit; +} + +.text-secondary { + color: var(--page-text-muted) !important; +} + +.text-bg-dark { + color: var(--page-text) !important; + background: var(--badge-background) !important; +} + +.btn-outline-light { + color: var(--page-text); + border-color: var(--surface-border); +} + +.btn-outline-light:hover, +.btn-outline-light:focus-visible { + color: var(--page-text); + border-color: var(--surface-border); + background: var(--panel-soft-background); +} + +.btn-outline-secondary { + color: var(--page-text-muted); + border-color: var(--surface-border); +} + +.btn-outline-secondary:hover, +.btn-outline-secondary:focus-visible { + color: var(--page-text); + border-color: var(--surface-border); + background: var(--panel-soft-background); +} + +.btn-outline-primary { + color: var(--link-color); + border-color: color-mix(in srgb, var(--link-color) 32%, transparent); +} + +.btn-primary { + border-color: transparent; + background: var(--accent-gradient); +} + +.alert-danger, +.alert-success, +.alert-warning { + border: 1px solid var(--surface-border); +} diff --git a/client/tsconfig.app.json b/client/tsconfig.app.json new file mode 100644 index 0000000..264f459 --- /dev/null +++ b/client/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "include": [ + "src/**/*.ts" + ], + "exclude": [ + "src/**/*.spec.ts" + ] +} diff --git a/client/tsconfig.json b/client/tsconfig.json new file mode 100644 index 0000000..ad457fa --- /dev/null +++ b/client/tsconfig.json @@ -0,0 +1,30 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "compileOnSave": false, + "compilerOptions": { + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "ES2022", + "module": "preserve" + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + }, + "files": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/client/tsconfig.spec.json b/client/tsconfig.spec.json new file mode 100644 index 0000000..d383706 --- /dev/null +++ b/client/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "vitest/globals" + ] + }, + "include": [ + "src/**/*.d.ts", + "src/**/*.spec.ts" + ] +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..a9af35b --- /dev/null +++ b/package-lock.json @@ -0,0 +1,329 @@ +{ + "name": "private-chat", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "private-chat", + "version": "1.0.0", + "devDependencies": { + "concurrently": "^9.2.1" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..19f0111 --- /dev/null +++ b/package.json @@ -0,0 +1,15 @@ +{ + "name": "private-chat", + "version": "1.0.0", + "private": true, + "scripts": { + "dev": "node node_modules/concurrently/dist/bin/concurrently.js -k -n server,client -c green,blue \"npm run dev --prefix server\" \"npm run start --prefix client\"", + "dev:server": "npm run dev --prefix server", + "dev:client": "npm run start --prefix client", + "build": "npm run build --prefix server && npm run build --prefix client", + "start": "npm run build && npm run start --prefix server" + }, + "devDependencies": { + "concurrently": "^9.2.1" + } +} diff --git a/server/dist/index.js b/server/dist/index.js new file mode 100644 index 0000000..2ec0580 --- /dev/null +++ b/server/dist/index.js @@ -0,0 +1,1026 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { TextEncoder } from 'node:util'; +import { DatabaseSync } from 'node:sqlite'; +import cors from '@fastify/cors'; +import jwt from '@fastify/jwt'; +import fastifyStatic from '@fastify/static'; +import websocket from '@fastify/websocket'; +import dotenv from 'dotenv'; +import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse, } from '@simplewebauthn/server'; +import Fastify from 'fastify'; +import { Redis } from 'ioredis'; +import { z } from 'zod'; +dotenv.config({ path: fileURLToPath(new URL('../../.env', import.meta.url)) }); +const projectRootPath = fileURLToPath(new URL('../../', import.meta.url)); +const registerSchema = z.object({ + username: z.string().trim().min(3).max(32).regex(/^[a-zA-Z0-9_-]+$/), + displayName: z.string().trim().min(2).max(48).optional(), + password: z.string().min(8).max(128), +}); +const loginSchema = z.object({ + username: z.string().trim().min(3).max(32), + password: z.string().min(8).max(128), +}); +const accessKeyLabelSchema = z.object({ + label: z.string().trim().min(1).max(64).optional(), +}); +const verifyAccessKeySchema = z.object({ + credential: z.custom(), +}); +const accessKeyAuthenticationSchema = z.object({ + username: z.string().trim().min(3).max(32).optional(), +}); +const verifyAccessKeyAuthenticationSchema = z.object({ + attemptId: z.string().min(1), + credential: z.custom(), +}); +const approvePendingUserParamsSchema = z.object({ + userId: z.string().min(1), +}); +const wsQuerySchema = z.object({ + token: z.string().min(1), +}); +const signalMessageSchema = z.discriminatedUnion('type', [ + z.object({ + type: z.literal('signal'), + to: z.string().min(1), + signal: z.discriminatedUnion('type', [ + z.object({ + type: z.literal('sdp'), + description: z.object({ + type: z.enum(['offer', 'answer', 'pranswer', 'rollback']), + sdp: z.string().optional(), + }), + }), + z.object({ + type: z.literal('ice-candidate'), + candidate: z.object({ + candidate: z.string().optional(), + sdpMid: z.string().nullable().optional(), + sdpMLineIndex: z.number().nullable().optional(), + usernameFragment: z.string().nullable().optional(), + }), + }), + ]), + }), +]); +const app = Fastify({ logger: true }); +const approvalAdminUsername = 'ladparis'; +const dataDirectory = resolveStoragePath(process.env.PRIVATECHAT_DATA_DIR ?? 'server/data'); +const sqlitePath = resolveStoragePath(process.env.SQLITE_PATH ?? path.join(dataDirectory, 'privatechat.sqlite')); +const masterKeyPath = resolveStoragePath(process.env.PRIVATECHAT_MASTER_KEY_PATH ?? path.join(dataDirectory, 'master.key')); +const frontendDistPath = resolveProjectPath(process.env.PRIVATECHAT_WEB_DIST_DIR ?? 'client/dist/client/browser'); +const sessionTtlSeconds = Number(process.env.SESSION_TTL_SECONDS ?? 60 * 60 * 12); +const webAuthnChallengeTtlSeconds = Number(process.env.WEBAUTHN_CHALLENGE_TTL_SECONDS ?? 5 * 60); +const webAuthnOrigin = process.env.WEBAUTHN_ORIGIN ?? 'http://localhost:4200'; +const webAuthnRpName = process.env.WEBAUTHN_RP_NAME ?? 'PrivateChat'; +const webAuthnUserVerification = resolveWebAuthnUserVerification(process.env.WEBAUTHN_USER_VERIFICATION); +const frontendIndexPath = path.join(frontendDistPath, 'index.html'); +const hasFrontendBuild = fs.existsSync(frontendIndexPath); +fs.mkdirSync(path.dirname(sqlitePath), { recursive: true }); +fs.mkdirSync(path.dirname(masterKeyPath), { recursive: true }); +const encryptionKey = deriveEncryptionKey(loadOrCreateMasterKey(masterKeyPath)); +const database = new DatabaseSync(sqlitePath); +database.exec(` + PRAGMA journal_mode = WAL; + + CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + display_name TEXT NOT NULL, + encrypted_credentials TEXT NOT NULL, + is_active INTEGER NOT NULL DEFAULT 1, + approved_at TEXT, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS app_secrets ( + name TEXT PRIMARY KEY, + encrypted_value TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS webauthn_credentials ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + credential_id TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + encrypted_registration TEXT NOT NULL, + created_at TEXT NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + ); +`); +ensureUserApprovalColumns(); +const createUserStatement = database.prepare(` + INSERT INTO users (id, username, display_name, encrypted_credentials, is_active, approved_at, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?) +`); +const selectUserByUsernameStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE username = ? +`); +const selectUserByIdStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE id = ? +`); +const selectPendingUsersStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE is_active = 0 + ORDER BY created_at ASC +`); +const approveUserStatement = database.prepare(` + UPDATE users + SET is_active = 1, approved_at = ? + WHERE id = ? AND is_active = 0 +`); +const updateUserCredentialsStatement = database.prepare(` + UPDATE users + SET encrypted_credentials = ? + WHERE id = ? +`); +const insertSecretStatement = database.prepare(` + INSERT INTO app_secrets (name, encrypted_value, created_at) + VALUES (?, ?, ?) +`); +const selectSecretStatement = database.prepare(` + SELECT encrypted_value + FROM app_secrets + WHERE name = ? +`); +const createAccessKeyStatement = database.prepare(` + INSERT INTO webauthn_credentials (id, user_id, credential_id, label, encrypted_registration, created_at) + VALUES (?, ?, ?, ?, ?, ?) +`); +const selectAccessKeysByUserStatement = database.prepare(` + SELECT id, user_id, credential_id, label, encrypted_registration, created_at + FROM webauthn_credentials + WHERE user_id = ? + ORDER BY created_at DESC +`); +const selectAccessKeyByCredentialIdStatement = database.prepare(` + SELECT id, user_id, credential_id, label, encrypted_registration, created_at + FROM webauthn_credentials + WHERE credential_id = ? +`); +const updateAccessKeyStatement = database.prepare(` + UPDATE webauthn_credentials + SET encrypted_registration = ? + WHERE credential_id = ? +`); +const jwtSecret = loadOrCreateSecret('jwt-secret', () => crypto.randomBytes(64).toString('hex')); +const redis = new Redis(process.env.REDIS_URL ?? 'redis://127.0.0.1:6379/0'); +const socketsByUserId = new Map(); +await redis.ping(); +await app.register(cors, { + origin: process.env.CORS_ORIGIN ? [process.env.CORS_ORIGIN] : true, + credentials: false, +}); +await app.register(jwt, { + secret: jwtSecret, +}); +await app.register(websocket); +if (hasFrontendBuild) { + await app.register(fastifyStatic, { + root: frontendDistPath, + prefix: '/', + }); + app.setNotFoundHandler((request, reply) => { + const requestPath = request.raw.url?.split('?')[0] ?? '/'; + if (request.method !== 'GET' || + requestPath === '/ws' || + requestPath === '/api' || + requestPath.startsWith('/api/')) { + return reply.code(404).send({ message: 'Not found.' }); + } + return reply.type('text/html; charset=utf-8').send(fs.createReadStream(frontendIndexPath)); + }); +} +else { + app.log.warn({ frontendDistPath }, 'Angular frontend build not found. Build the client before serving it from the backend.'); +} +app.get('/api/health', async () => ({ ok: true })); +app.post('/api/auth/register', async (request, reply) => { + const parsed = registerSchema.safeParse(request.body); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid registration payload.', + issues: parsed.error.flatten(), + }); + } + const username = parsed.data.username.toLowerCase(); + if (findUserByUsername(username)) { + return reply.code(409).send({ message: 'Username is already taken.' }); + } + const user = createUser({ + username, + displayName: parsed.data.displayName?.trim() || parsed.data.username, + password: parsed.data.password, + isActive: username === approvalAdminUsername, + }); + if (!user.isActive) { + return reply.code(202).send({ + pendingApproval: true, + message: `Account created. It must be approved by ${approvalAdminUsername} before you can sign in.`, + }); + } + const session = await createSession(user.id); + return createAuthReply(user, session.sessionId); +}); +app.post('/api/auth/login', async (request, reply) => { + const parsed = loginSchema.safeParse(request.body); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid login payload.', + issues: parsed.error.flatten(), + }); + } + const user = findUserByUsername(parsed.data.username.toLowerCase()); + if (!user || !verifyPassword(parsed.data.password, user.passwordHash)) { + return reply.code(401).send({ message: 'Invalid credentials.' }); + } + if (!user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + const session = await createSession(user.id); + return createAuthReply(user, session.sessionId); +}); +app.post('/api/webauthn/authenticate/options', async (request, reply) => { + const parsed = accessKeyAuthenticationSchema.safeParse(request.body ?? {}); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key sign-in payload.', + issues: parsed.error.flatten(), + }); + } + const expectedOrigin = resolveWebAuthnOrigin(request); + const expectedRpId = process.env.WEBAUTHN_RP_ID ?? new URL(expectedOrigin).hostname; + const username = parsed.data.username?.trim().toLowerCase(); + const user = username ? findUserByUsername(username) : null; + if (username && !user) { + return reply.code(400).send({ message: 'No access key is registered for that username.' }); + } + if (user && !user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + const storedCredentials = user ? listStoredAccessKeys(user.id) : []; + if (username && storedCredentials.length === 0) { + return reply.code(400).send({ message: 'No access key is registered for that username.' }); + } + const attemptId = crypto.randomUUID(); + const options = await generateAuthenticationOptions({ + rpID: expectedRpId, + userVerification: webAuthnUserVerification, + allowCredentials: storedCredentials.length > 0 + ? storedCredentials.map((credential) => ({ + id: credential.credentialId, + transports: credential.transports, + })) + : undefined, + }); + await redis.set(webAuthnAuthenticationKey(attemptId), JSON.stringify({ + challenge: options.challenge, + expectedOrigin, + expectedRpId, + expectedUserId: user?.id ?? null, + }), 'EX', webAuthnChallengeTtlSeconds); + return { + attemptId, + expectedOrigin, + ...options, + }; +}); +app.post('/api/webauthn/authenticate/verify', async (request, reply) => { + const parsed = verifyAccessKeyAuthenticationSchema.safeParse(request.body); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key sign-in verification payload.', + issues: parsed.error.flatten(), + }); + } + const pending = await getPendingAuthentication(parsed.data.attemptId); + if (!pending) { + return reply.code(400).send({ message: 'Access key sign-in challenge expired.' }); + } + try { + const storedAccessKey = findStoredAccessKeyByCredentialId(parsed.data.credential.id); + if (!storedAccessKey) { + return reply.code(401).send({ message: 'This access key is not registered.' }); + } + if (!storedAccessKey.user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + if (pending.expectedUserId && storedAccessKey.user.id !== pending.expectedUserId) { + return reply.code(401).send({ message: 'This access key does not match the requested username.' }); + } + const verification = await verifyAuthenticationResponse({ + response: parsed.data.credential, + expectedChallenge: pending.challenge, + expectedOrigin: pending.expectedOrigin, + expectedRPID: pending.expectedRpId, + credential: { + id: storedAccessKey.registration.credentialId, + publicKey: Buffer.from(storedAccessKey.registration.publicKey, 'base64url'), + counter: storedAccessKey.registration.counter, + transports: storedAccessKey.registration.transports, + }, + requireUserVerification: webAuthnUserVerification === 'required', + }); + if (!verification.verified) { + return reply.code(401).send({ message: 'Access key sign-in could not be verified.' }); + } + updateStoredAccessKey(storedAccessKey, { + counter: verification.authenticationInfo.newCounter, + deviceType: verification.authenticationInfo.credentialDeviceType, + backedUp: verification.authenticationInfo.credentialBackedUp, + }); + const session = await createSession(storedAccessKey.user.id); + return createAuthReply(storedAccessKey.user, session.sessionId); + } + catch (error) { + app.log.warn({ err: error }, 'WebAuthn authentication verification failed'); + return reply.code(400).send({ + message: error instanceof Error + ? `Access key sign-in could not be verified: ${error.message}` + : 'Access key sign-in could not be verified.', + }); + } + finally { + await clearPendingAuthentication(parsed.data.attemptId); + } +}); +app.get('/api/auth/session', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + return { + user: toPublicUser(authContext.user), + messageEncryptionKey: authContext.user.messageEncryptionKey, + }; +}); +app.get('/api/admin/pending-users', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + if (!isApprovalAdmin(authContext.user)) { + return reply.code(403).send({ message: 'Only ladparis can approve accounts.' }); + } + return { + users: listPendingApprovalUsers(), + }; +}); +app.post('/api/admin/pending-users/:userId/approve', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + if (!isApprovalAdmin(authContext.user)) { + return reply.code(403).send({ message: 'Only ladparis can approve accounts.' }); + } + const parsed = approvePendingUserParamsSchema.safeParse(request.params); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid user approval request.', + issues: parsed.error.flatten(), + }); + } + const approvedUser = approveUser(parsed.data.userId); + if (!approvedUser) { + return reply.code(404).send({ message: 'Pending user not found.' }); + } + return { + user: toPublicUser(approvedUser), + }; +}); +app.post('/api/auth/logout', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + await destroySession(authContext.session.sessionId); + await clearPendingRegistration(authContext.session.sessionId); + closeSocketSession(authContext.user.id, authContext.session.sessionId); + return { ok: true }; +}); +app.get('/api/webauthn/credentials', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + return { + credentials: listAccessKeys(authContext.user.id), + }; +}); +app.post('/api/webauthn/register/options', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + const parsed = accessKeyLabelSchema.safeParse(request.body ?? {}); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key request payload.', + issues: parsed.error.flatten(), + }); + } + const label = parsed.data.label?.trim() || defaultAccessKeyLabel(); + const storedCredentials = listStoredAccessKeys(authContext.user.id); + const expectedOrigin = resolveWebAuthnOrigin(request); + const expectedRpId = process.env.WEBAUTHN_RP_ID ?? new URL(expectedOrigin).hostname; + const options = await generateRegistrationOptions({ + rpName: webAuthnRpName, + rpID: expectedRpId, + userName: authContext.user.username, + userDisplayName: authContext.user.displayName, + userID: new TextEncoder().encode(authContext.user.id), + attestationType: 'none', + authenticatorSelection: { + residentKey: 'preferred', + userVerification: webAuthnUserVerification, + }, + excludeCredentials: storedCredentials.map((credential) => ({ + id: credential.credentialId, + transports: credential.transports, + })), + }); + await redis.set(webAuthnRegistrationKey(authContext.session.sessionId), JSON.stringify({ + challenge: options.challenge, + label, + expectedOrigin, + expectedRpId, + }), 'EX', webAuthnChallengeTtlSeconds); + return { + expectedOrigin, + ...options, + }; +}); +app.post('/api/webauthn/register/verify', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + if (!authContext) { + return; + } + const parsed = verifyAccessKeySchema.safeParse(request.body); + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key verification payload.', + issues: parsed.error.flatten(), + }); + } + const pending = await getPendingRegistration(authContext.session.sessionId); + if (!pending) { + return reply.code(400).send({ message: 'Access key registration challenge expired.' }); + } + try { + const verification = await verifyRegistrationResponse({ + response: parsed.data.credential, + expectedChallenge: pending.challenge, + expectedOrigin: pending.expectedOrigin, + expectedRPID: pending.expectedRpId, + requireUserVerification: webAuthnUserVerification === 'required', + }); + if (!verification.verified || !verification.registrationInfo) { + return reply.code(400).send({ message: 'Access key registration could not be verified.' }); + } + const registrationInfo = verification.registrationInfo; + persistAccessKey(authContext.user.id, { + credentialId: registrationInfo.credential.id, + label: pending.label, + publicKey: bytesToBase64Url(registrationInfo.credential.publicKey), + counter: registrationInfo.credential.counter, + transports: registrationInfo.credential.transports ?? [], + deviceType: registrationInfo.credentialDeviceType, + backedUp: registrationInfo.credentialBackedUp, + aaguid: registrationInfo.aaguid, + }); + await clearPendingRegistration(authContext.session.sessionId); + return { + credential: listAccessKeys(authContext.user.id)[0], + }; + } + catch (error) { + app.log.warn({ err: error }, 'WebAuthn registration verification failed'); + return reply.code(400).send({ + message: error instanceof Error + ? `Access key registration could not be verified: ${error.message}` + : 'Access key registration could not be verified.', + }); + } +}); +app.get('/ws', { websocket: true }, (socket, request) => { + void openSocket(socket, request); +}); +const port = Number(process.env.PORT ?? 16990); +await app.listen({ port, host: '0.0.0.0' }); +app.log.info(`PrivateChat signaling server listening on http://localhost:${port}`); +async function openSocket(socket, request) { + const query = wsQuerySchema.safeParse(request.query); + if (!query.success) { + send(socket, { type: 'error', message: 'Missing token.' }); + socket.close(); + return; + } + const authContext = await authenticateToken(query.data.token); + if (!authContext) { + send(socket, { type: 'error', message: 'Authentication required.' }); + socket.close(); + return; + } + const userSockets = socketsByUserId.get(authContext.user.id) ?? new Map(); + const isFirstConnection = userSockets.size === 0; + userSockets.set(authContext.session.sessionId, socket); + socketsByUserId.set(authContext.user.id, userSockets); + send(socket, { + type: 'presence', + self: toPublicUser(authContext.user), + peers: listOnlinePeers(authContext.user.id), + }); + if (isFirstConnection) { + broadcastExcept(authContext.user.id, { + type: 'peer-joined', + peer: toPublicUser(authContext.user), + }); + } + socket.on('message', (rawMessage) => { + void handleSocketMessage(authContext.user.id, authContext.session.sessionId, socket, rawMessage.toString()); + }); + socket.on('close', () => { + if (detachSocket(authContext.user.id, authContext.session.sessionId)) { + broadcastExcept(authContext.user.id, { type: 'peer-left', peerId: authContext.user.id }); + } + }); +} +async function handleSocketMessage(userId, sessionId, socket, rawMessage) { + const authContext = await authenticateTokenFromSession(userId, sessionId); + if (!authContext) { + send(socket, { type: 'error', message: 'Session expired.' }); + socket.close(); + return; + } + const parsed = parseClientMessage(rawMessage); + if (!parsed) { + send(socket, { type: 'error', message: 'Unsupported signaling message.' }); + return; + } + let delivered = 0; + const recipientSockets = socketsByUserId.get(parsed.to); + if (recipientSockets) { + for (const [recipientSessionId, recipientSocket] of recipientSockets.entries()) { + const recipientContext = await authenticateTokenFromSession(parsed.to, recipientSessionId); + if (!recipientContext) { + recipientSocket.close(); + continue; + } + send(recipientSocket, { + type: 'signal', + from: authContext.user.id, + signal: parsed.signal, + }); + delivered += 1; + } + } + if (delivered === 0) { + send(socket, { type: 'error', message: 'Peer is offline or not authenticated.' }); + } +} +function createAuthReply(user, sessionId) { + return { + token: app.jwt.sign({ + sub: user.id, + username: user.username, + displayName: user.displayName, + sid: sessionId, + }), + user: toPublicUser(user), + messageEncryptionKey: user.messageEncryptionKey, + }; +} +async function authenticateRequest(request, reply) { + const token = extractBearerToken(request.headers.authorization); + if (!token) { + reply.code(401).send({ message: 'Authentication required.' }); + return null; + } + const authContext = await authenticateToken(token); + if (!authContext) { + reply.code(401).send({ message: 'Invalid or expired session.' }); + return null; + } + return authContext; +} +async function authenticateToken(token) { + let decoded; + try { + decoded = app.jwt.verify(token); + } + catch { + return null; + } + return authenticateTokenFromSession(decoded.sub, decoded.sid, decoded); +} +async function authenticateTokenFromSession(userId, sessionId, decoded) { + const session = await getSession(sessionId); + if (!session || session.userId !== userId) { + return null; + } + const user = findUserById(userId); + if (!user) { + await destroySession(sessionId); + return null; + } + if (!user.isActive) { + await destroySession(sessionId); + return null; + } + await redis.expire(sessionKey(sessionId), sessionTtlSeconds); + return { + user, + session, + token: decoded ?? { + sub: user.id, + username: user.username, + displayName: user.displayName, + sid: sessionId, + }, + }; +} +function createUser(input) { + const createdAt = new Date().toISOString(); + const user = { + id: crypto.randomUUID(), + username: input.username, + displayName: input.displayName, + passwordHash: hashPassword(input.password), + messageEncryptionKey: generateUserMessageEncryptionKey(), + isActive: input.isActive, + createdAt, + approvedAt: input.isActive ? createdAt : null, + }; + createUserStatement.run(user.id, user.username, user.displayName, encryptJson({ + passwordHash: user.passwordHash, + messageEncryptionKey: user.messageEncryptionKey, + }), user.isActive ? 1 : 0, user.approvedAt, user.createdAt); + return user; +} +function listPendingApprovalUsers() { + const rows = selectPendingUsersStatement.all(); + return rows.map((row) => ({ + id: row.id, + username: row.username, + displayName: row.display_name, + createdAt: row.created_at, + })); +} +function approveUser(userId) { + const approvedAt = new Date().toISOString(); + const result = approveUserStatement.run(approvedAt, userId); + if (result.changes === 0) { + return null; + } + return findUserById(userId); +} +function persistAccessKey(userId, input) { + createAccessKeyStatement.run(crypto.randomUUID(), userId, input.credentialId, input.label, encryptJson({ + credentialId: input.credentialId, + publicKey: input.publicKey, + counter: input.counter, + transports: input.transports, + deviceType: input.deviceType, + backedUp: input.backedUp, + aaguid: input.aaguid, + }), new Date().toISOString()); +} +function updateStoredAccessKey(storedAccessKey, changes) { + const nextRegistration = { + ...storedAccessKey.registration, + counter: changes.counter, + deviceType: changes.deviceType, + backedUp: changes.backedUp, + }; + updateAccessKeyStatement.run(encryptJson(nextRegistration), storedAccessKey.row.credential_id); +} +function findUserByUsername(username) { + const row = selectUserByUsernameStatement.get(username); + return row ? hydrateUser(row) : null; +} +function findUserById(userId) { + const row = selectUserByIdStatement.get(userId); + return row ? hydrateUser(row) : null; +} +function hydrateUser(row) { + const credentials = decryptJson(row.encrypted_credentials); + const messageEncryptionKey = credentials.messageEncryptionKey ?? generateUserMessageEncryptionKey(); + if (!credentials.messageEncryptionKey) { + updateUserCredentialsStatement.run(encryptJson({ + passwordHash: credentials.passwordHash, + messageEncryptionKey, + }), row.id); + } + return { + id: row.id, + username: row.username, + displayName: row.display_name, + passwordHash: credentials.passwordHash, + messageEncryptionKey, + isActive: row.is_active === 1, + createdAt: row.created_at, + approvedAt: row.approved_at, + }; +} +function listStoredAccessKeys(userId) { + const rows = selectAccessKeysByUserStatement.all(userId); + return rows.map((row) => decryptJson(row.encrypted_registration)); +} +function findStoredAccessKeyByCredentialId(credentialId) { + const row = selectAccessKeyByCredentialIdStatement.get(credentialId); + if (!row) { + return null; + } + const user = findUserById(row.user_id); + if (!user) { + return null; + } + return { + row, + user, + registration: decryptJson(row.encrypted_registration), + }; +} +function listAccessKeys(userId) { + const rows = selectAccessKeysByUserStatement.all(userId); + return rows.map((row) => { + const registration = decryptJson(row.encrypted_registration); + return { + id: row.id, + credentialId: row.credential_id, + label: row.label, + transports: registration.transports, + deviceType: registration.deviceType, + backedUp: registration.backedUp, + aaguid: registration.aaguid, + createdAt: row.created_at, + }; + }); +} +function loadOrCreateSecret(name, createValue) { + const row = selectSecretStatement.get(name); + if (row) { + return decryptText(row.encrypted_value); + } + const value = createValue(); + insertSecretStatement.run(name, encryptText(value), new Date().toISOString()); + return value; +} +async function createSession(userId) { + const session = { + sessionId: crypto.randomUUID(), + userId, + createdAt: new Date().toISOString(), + }; + await redis.set(sessionKey(session.sessionId), JSON.stringify(session), 'EX', sessionTtlSeconds); + return session; +} +async function getSession(sessionId) { + const payload = await redis.get(sessionKey(sessionId)); + if (!payload) { + return null; + } + return JSON.parse(payload); +} +async function destroySession(sessionId) { + await redis.del(sessionKey(sessionId)); +} +function sessionKey(sessionId) { + return `privatechat:session:${sessionId}`; +} +function webAuthnRegistrationKey(sessionId) { + return `privatechat:webauthn-registration:${sessionId}`; +} +function webAuthnAuthenticationKey(attemptId) { + return `privatechat:webauthn-authentication:${attemptId}`; +} +async function getPendingRegistration(sessionId) { + const payload = await redis.get(webAuthnRegistrationKey(sessionId)); + if (!payload) { + return null; + } + return JSON.parse(payload); +} +async function clearPendingRegistration(sessionId) { + await redis.del(webAuthnRegistrationKey(sessionId)); +} +async function getPendingAuthentication(attemptId) { + const payload = await redis.get(webAuthnAuthenticationKey(attemptId)); + if (!payload) { + return null; + } + return JSON.parse(payload); +} +async function clearPendingAuthentication(attemptId) { + await redis.del(webAuthnAuthenticationKey(attemptId)); +} +function closeSocketSession(userId, sessionId) { + const socket = socketsByUserId.get(userId)?.get(sessionId); + if (socket && socket.readyState < 2) { + socket.close(); + } +} +function detachSocket(userId, sessionId) { + const userSockets = socketsByUserId.get(userId); + if (!userSockets) { + return false; + } + userSockets.delete(sessionId); + if (userSockets.size === 0) { + socketsByUserId.delete(userId); + return true; + } + return false; +} +function listOnlinePeers(currentUserId) { + const peers = []; + for (const [userId, sockets] of socketsByUserId.entries()) { + if (userId === currentUserId || sockets.size === 0) { + continue; + } + const user = findUserById(userId); + if (user) { + peers.push(toPublicUser(user)); + } + } + return peers.sort((left, right) => left.displayName.localeCompare(right.displayName)); +} +function broadcastExcept(userId, payload) { + for (const [peerId, sockets] of socketsByUserId.entries()) { + if (peerId === userId) { + continue; + } + for (const socket of sockets.values()) { + send(socket, payload); + } + } +} +function send(socket, payload) { + if (socket.readyState === 1) { + socket.send(JSON.stringify(payload)); + } +} +function parseClientMessage(rawMessage) { + let payload; + try { + payload = JSON.parse(rawMessage); + } + catch { + return null; + } + const parsed = signalMessageSchema.safeParse(payload); + if (!parsed.success) { + return null; + } + return { + type: 'signal', + to: parsed.data.to, + signal: normalizeSignal(parsed.data.signal), + }; +} +function normalizeSignal(signal) { + if (signal.type === 'sdp') { + return { + type: 'sdp', + description: signal.description, + }; + } + return { + type: 'ice-candidate', + candidate: signal.candidate, + }; +} +function extractBearerToken(authorizationHeader) { + if (!authorizationHeader?.startsWith('Bearer ')) { + return null; + } + return authorizationHeader.slice('Bearer '.length).trim(); +} +function toPublicUser(user) { + return { + id: user.id, + username: user.username, + displayName: user.displayName, + }; +} +function isApprovalAdmin(user) { + return user.username === approvalAdminUsername; +} +function hashPassword(password) { + const salt = crypto.randomBytes(16).toString('hex'); + const derived = crypto.scryptSync(password, salt, 64).toString('hex'); + return `${salt}:${derived}`; +} +function verifyPassword(password, storedHash) { + const [salt, stored] = storedHash.split(':'); + if (!salt || !stored) { + return false; + } + const incoming = crypto.scryptSync(password, salt, 64); + const saved = Buffer.from(stored, 'hex'); + return incoming.length === saved.length && crypto.timingSafeEqual(incoming, saved); +} +function generateUserMessageEncryptionKey() { + return crypto.randomBytes(32).toString('base64url'); +} +function encryptJson(value) { + return encryptText(JSON.stringify(value)); +} +function decryptJson(payload) { + return JSON.parse(decryptText(payload)); +} +function encryptText(value) { + const iv = crypto.randomBytes(12); + const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, iv); + const encrypted = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()]); + const authTag = cipher.getAuthTag(); + return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`; +} +function decryptText(payload) { + const [ivHex, authTagHex, encryptedHex] = payload.split(':'); + if (!ivHex || !authTagHex || !encryptedHex) { + throw new Error('Encrypted payload is malformed.'); + } + const decipher = crypto.createDecipheriv('aes-256-gcm', encryptionKey, Buffer.from(ivHex, 'hex')); + decipher.setAuthTag(Buffer.from(authTagHex, 'hex')); + const decrypted = Buffer.concat([ + decipher.update(Buffer.from(encryptedHex, 'hex')), + decipher.final(), + ]); + return decrypted.toString('utf8'); +} +function loadOrCreateMasterKey(masterKeyFilePath) { + if (process.env.PRIVATECHAT_MASTER_KEY) { + return process.env.PRIVATECHAT_MASTER_KEY; + } + if (fs.existsSync(masterKeyFilePath)) { + return fs.readFileSync(masterKeyFilePath, 'utf8').trim(); + } + const generatedKey = crypto.randomBytes(32).toString('hex'); + fs.writeFileSync(masterKeyFilePath, generatedKey, { mode: 0o600 }); + return generatedKey; +} +function ensureUserApprovalColumns() { + const rows = database.prepare('PRAGMA table_info(users)').all(); + const columnNames = new Set(rows.map((row) => row.name)); + if (!columnNames.has('is_active')) { + database.exec('ALTER TABLE users ADD COLUMN is_active INTEGER NOT NULL DEFAULT 1'); + } + if (!columnNames.has('approved_at')) { + database.exec('ALTER TABLE users ADD COLUMN approved_at TEXT'); + } + database.exec(` + UPDATE users + SET approved_at = COALESCE(approved_at, created_at) + WHERE is_active = 1 + `); +} +function deriveEncryptionKey(masterKeyMaterial) { + return crypto.createHash('sha256').update(masterKeyMaterial).digest(); +} +function resolveStoragePath(targetPath) { + return path.isAbsolute(targetPath) ? targetPath : path.resolve(process.cwd(), targetPath); +} +function resolveProjectPath(targetPath) { + return path.isAbsolute(targetPath) ? targetPath : path.resolve(projectRootPath, targetPath); +} +function resolveWebAuthnOrigin(request) { + const originHeader = request.headers.origin; + if (typeof originHeader === 'string' && originHeader.length > 0) { + return originHeader; + } + return webAuthnOrigin; +} +function resolveWebAuthnUserVerification(value) { + switch (value?.toLowerCase()) { + case 'discouraged': + return 'discouraged'; + case 'required': + return 'required'; + default: + return 'preferred'; + } +} +function bytesToBase64Url(value) { + return Buffer.from(value).toString('base64url'); +} +function defaultAccessKeyLabel() { + return `Access key ${new Date().toISOString().replace('T', ' ').slice(0, 16)}`; +} diff --git a/server/package-lock.json b/server/package-lock.json new file mode 100644 index 0000000..d9af003 --- /dev/null +++ b/server/package-lock.json @@ -0,0 +1,2166 @@ +{ + "name": "private-chat-server", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "private-chat-server", + "version": "1.0.0", + "dependencies": { + "@fastify/cors": "^11.2.0", + "@fastify/jwt": "^10.0.0", + "@fastify/static": "^9.0.0", + "@fastify/websocket": "^11.2.0", + "@simplewebauthn/server": "^13.2.3", + "dotenv": "^17.3.1", + "fastify": "^5.8.2", + "ioredis": "^5.10.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@types/node": "^25.3.5", + "@types/ws": "^8.18.1", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@fastify/accept-negotiator": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@fastify/accept-negotiator/-/accept-negotiator-2.0.1.tgz", + "integrity": "sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/ajv-compiler": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@fastify/ajv-compiler/-/ajv-compiler-4.0.5.tgz", + "integrity": "sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0" + } + }, + "node_modules/@fastify/cors": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@fastify/cors/-/cors-11.2.0.tgz", + "integrity": "sha512-LbLHBuSAdGdSFZYTLVA3+Ch2t+sA6nq3Ejc6XLAKiQ6ViS2qFnvicpj0htsx03FyYeLs04HfRNBsz/a8SvbcUw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fastify-plugin": "^5.0.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/@fastify/error": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@fastify/error/-/error-4.2.0.tgz", + "integrity": "sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/fast-json-stringify-compiler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@fastify/fast-json-stringify-compiler/-/fast-json-stringify-compiler-5.0.3.tgz", + "integrity": "sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "fast-json-stringify": "^6.0.0" + } + }, + "node_modules/@fastify/forwarded": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@fastify/forwarded/-/forwarded-3.0.1.tgz", + "integrity": "sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/@fastify/jwt": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@fastify/jwt/-/jwt-10.0.0.tgz", + "integrity": "sha512-2Qka3NiyNNcsfejMUvyzot1T4UYIzzcbkFGDdVyrl344fRZ/WkD6VFXOoXhxe2Pzf3LpJNkoSxUM4Ru4DVgkYA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/error": "^4.2.0", + "@lukeed/ms": "^2.0.2", + "fast-jwt": "^6.0.2", + "fastify-plugin": "^5.0.1", + "steed": "^1.1.3" + } + }, + "node_modules/@fastify/merge-json-schemas": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@fastify/merge-json-schemas/-/merge-json-schemas-0.2.1.tgz", + "integrity": "sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@fastify/proxy-addr": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@fastify/proxy-addr/-/proxy-addr-5.1.0.tgz", + "integrity": "sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/forwarded": "^3.0.0", + "ipaddr.js": "^2.1.0" + } + }, + "node_modules/@fastify/send": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@fastify/send/-/send-4.1.0.tgz", + "integrity": "sha512-TMYeQLCBSy2TOFmV95hQWkiTYgC/SEx7vMdV+wnZVX4tt8VBLKzmH8vV9OzJehV0+XBfg+WxPMt5wp+JBUKsVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@lukeed/ms": "^2.0.2", + "escape-html": "~1.0.3", + "fast-decode-uri-component": "^1.0.1", + "http-errors": "^2.0.0", + "mime": "^3" + } + }, + "node_modules/@fastify/static": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@fastify/static/-/static-9.0.0.tgz", + "integrity": "sha512-r64H8Woe/vfilg5RTy7lwWlE8ZZcTrc3kebYFMEUBrMqlydhQyoiExQXdYAy2REVpST/G35+stAM8WYp1WGmMA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/accept-negotiator": "^2.0.0", + "@fastify/send": "^4.0.0", + "content-disposition": "^1.0.1", + "fastify-plugin": "^5.0.0", + "fastq": "^1.17.1", + "glob": "^13.0.0" + } + }, + "node_modules/@fastify/websocket": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/@fastify/websocket/-/websocket-11.2.0.tgz", + "integrity": "sha512-3HrDPbAG1CzUCqnslgJxppvzaAZffieOVbLp1DAy1huCSynUWPifSvfdEDUR8HlJLp3sp1A36uOM2tJogADS8w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "duplexify": "^4.1.3", + "fastify-plugin": "^5.0.0", + "ws": "^8.16.0" + } + }, + "node_modules/@hexagon/base64": { + "version": "1.1.28", + "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz", + "integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==", + "license": "MIT" + }, + "node_modules/@ioredis/commands": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.5.1.tgz", + "integrity": "sha512-JH8ZL/ywcJyR9MmJ5BNqZllXNZQqQbnVZOqpPQqE1vHiFgAw4NHbvE0FOduNU8IX9babitBT46571OnPTT0Zcw==", + "license": "MIT" + }, + "node_modules/@levischuck/tiny-cbor": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz", + "integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==", + "license": "MIT" + }, + "node_modules/@lukeed/ms": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@lukeed/ms/-/ms-2.0.2.tgz", + "integrity": "sha512-9I2Zn6+NJLfaGoz9jN3lpwDgAYvfGeNYdbAIjJOqzs4Tpc+VU3Jqq4IofSUBKajiDS8k9fZIg18/z13mpk1bsA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@peculiar/asn1-android": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.6.0.tgz", + "integrity": "sha512-cBRCKtYPF7vJGN76/yG8VbxRcHLPF3HnkoHhKOZeHpoVtbMYfY9ROKtH3DtYUY9m8uI1Mh47PRhHf2hSK3xcSQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-cms": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", + "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-csr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", + "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-ecc": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", + "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pfx": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", + "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs8": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", + "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-pkcs9": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", + "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.1", + "@peculiar/asn1-pfx": "^2.6.1", + "@peculiar/asn1-pkcs8": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/asn1-x509-attr": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-rsa": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", + "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-schema": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", + "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", + "license": "MIT", + "dependencies": { + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", + "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "asn1js": "^3.0.6", + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/asn1-x509-attr": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", + "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "asn1js": "^3.0.6", + "tslib": "^2.8.1" + } + }, + "node_modules/@peculiar/x509": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", + "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", + "license": "MIT", + "dependencies": { + "@peculiar/asn1-cms": "^2.6.0", + "@peculiar/asn1-csr": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.0", + "@peculiar/asn1-pkcs9": "^2.6.0", + "@peculiar/asn1-rsa": "^2.6.0", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.0", + "pvtsutils": "^1.3.6", + "reflect-metadata": "^0.2.2", + "tslib": "^2.8.1", + "tsyringe": "^4.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@pinojs/redact": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@pinojs/redact/-/redact-0.4.0.tgz", + "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==", + "license": "MIT" + }, + "node_modules/@simplewebauthn/server": { + "version": "13.2.3", + "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.2.3.tgz", + "integrity": "sha512-ZhcVBOw63birYx9jVfbhK6rTehckVes8PeWV324zpmdxr0BUfylospwMzcrxrdMcOi48MHWj2LCA+S528LnGvg==", + "license": "MIT", + "dependencies": { + "@hexagon/base64": "^1.1.27", + "@levischuck/tiny-cbor": "^0.2.2", + "@peculiar/asn1-android": "^2.6.0", + "@peculiar/asn1-ecc": "^2.6.1", + "@peculiar/asn1-rsa": "^2.6.1", + "@peculiar/asn1-schema": "^2.6.0", + "@peculiar/asn1-x509": "^2.6.1", + "@peculiar/x509": "^1.14.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@types/node": { + "version": "25.3.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.5.tgz", + "integrity": "sha512-oX8xrhvpiyRCQkG1MFchB09f+cXftgIXb3a7UUa4Y3wpmZPw5tyZGTLWhlESOLq1Rq6oDlc8npVU2/9xiCuXMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/abstract-logging": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-2.0.1.tgz", + "integrity": "sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==", + "license": "MIT" + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/avvio": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/avvio/-/avvio-9.2.0.tgz", + "integrity": "sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/error": "^4.0.0", + "fastq": "^1.17.1" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/content-disposition": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", + "integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/dotenv": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.3.1.tgz", + "integrity": "sha512-IO8C/dzEb6O3F9/twg6ZLXz164a2fhTnEWb95H23Dm4OuN+92NmEAlTrupP9VW6Jm3sO26tQlqyvyi4CsnY9GA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/duplexify": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.3.tgz", + "integrity": "sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.2" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-json-stringify": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-6.3.0.tgz", + "integrity": "sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/merge-json-schemas": "^0.2.0", + "ajv": "^8.12.0", + "ajv-formats": "^3.0.1", + "fast-uri": "^3.0.0", + "json-schema-ref-resolver": "^3.0.0", + "rfdc": "^1.2.0" + } + }, + "node_modules/fast-jwt": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/fast-jwt/-/fast-jwt-6.1.0.tgz", + "integrity": "sha512-cGK/TXlud8INL49Iv7yRtZy0PHzNJId1shfqNCqdF0gOlWiy+1FPgjxX+ZHp/CYxFYDaoNnxeYEGzcXSkahUEQ==", + "license": "Apache-2.0", + "dependencies": { + "@lukeed/ms": "^2.0.2", + "asn1.js": "^5.4.1", + "ecdsa-sig-formatter": "^1.0.11", + "mnemonist": "^0.40.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", + "license": "MIT", + "dependencies": { + "fast-decode-uri-component": "^1.0.1" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastfall": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/fastfall/-/fastfall-1.5.1.tgz", + "integrity": "sha512-KH6p+Z8AKPXnmA7+Iz2Lh8ARCMr+8WNPVludm1LGkZoD2MjY6LVnRMtTKhkdzI+jr0RzQWXKzKyBJm1zoHEL4Q==", + "license": "MIT", + "dependencies": { + "reusify": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fastify": { + "version": "5.8.2", + "resolved": "https://registry.npmjs.org/fastify/-/fastify-5.8.2.tgz", + "integrity": "sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "@fastify/ajv-compiler": "^4.0.5", + "@fastify/error": "^4.0.0", + "@fastify/fast-json-stringify-compiler": "^5.0.0", + "@fastify/proxy-addr": "^5.0.0", + "abstract-logging": "^2.0.1", + "avvio": "^9.0.0", + "fast-json-stringify": "^6.0.0", + "find-my-way": "^9.0.0", + "light-my-request": "^6.0.0", + "pino": "^9.14.0 || ^10.1.0", + "process-warning": "^5.0.0", + "rfdc": "^1.3.1", + "secure-json-parse": "^4.0.0", + "semver": "^7.6.0", + "toad-cache": "^3.7.0" + } + }, + "node_modules/fastify-plugin": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-5.1.0.tgz", + "integrity": "sha512-FAIDA8eovSt5qcDgcBvDuX/v0Cjz0ohGhENZ/wpc3y+oZCY2afZ9Baqql3g/lC+OHRnciQol4ww7tuthOb9idw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/fastparallel": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/fastparallel/-/fastparallel-2.4.1.tgz", + "integrity": "sha512-qUmhxPgNHmvRjZKBFUNI0oZuuH9OlSIOXmJ98lhKPxMZZ7zS/Fi0wRHOihDSz0R1YiIOjxzOY4bq65YTcdBi2Q==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4", + "xtend": "^4.0.2" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fastseries": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/fastseries/-/fastseries-1.7.2.tgz", + "integrity": "sha512-dTPFrPGS8SNSzAt7u/CbMKCJ3s01N04s4JFbORHcmyvVfVKmbhMD1VtRbh5enGHxkaQDqWyLefiKOGGmohGDDQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/find-my-way": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.5.0.tgz", + "integrity": "sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^5.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-tsconfig": { + "version": "4.13.6", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz", + "integrity": "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ioredis": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.10.0.tgz", + "integrity": "sha512-HVBe9OFuqs+Z6n64q09PQvP1/R4Bm+30PAyyD4wIEqssh3v9L21QjCVk4kRLucMBcDokJTcLjsGeVRlq/nH6DA==", + "license": "MIT", + "dependencies": { + "@ioredis/commands": "1.5.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" + }, + "engines": { + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ipaddr.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", + "integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/json-schema-ref-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-schema-ref-resolver/-/json-schema-ref-resolver-3.0.0.tgz", + "integrity": "sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/light-my-request": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-6.6.0.tgz", + "integrity": "sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "cookie": "^1.0.1", + "process-warning": "^4.0.0", + "set-cookie-parser": "^2.6.0" + } + }, + "node_modules/light-my-request/node_modules/process-warning": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-4.0.1.tgz", + "integrity": "sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==", + "license": "MIT" + }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mnemonist": { + "version": "0.40.3", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.40.3.tgz", + "integrity": "sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==", + "license": "MIT", + "dependencies": { + "obliterator": "^2.0.4" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/obliterator": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", + "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", + "license": "MIT" + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/pino": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.3.1.tgz", + "integrity": "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==", + "license": "MIT", + "dependencies": { + "@pinojs/redact": "^0.4.0", + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^3.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^4.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz", + "integrity": "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz", + "integrity": "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==", + "license": "MIT" + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "license": "MIT", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", + "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", + "license": "Apache-2.0" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex2": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.0.0.tgz", + "integrity": "sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT", + "dependencies": { + "ret": "~0.5.0" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/secure-json-parse": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-4.1.0.tgz", + "integrity": "sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sonic-boom": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.1.tgz", + "integrity": "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==", + "license": "MIT" + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/steed": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/steed/-/steed-1.1.3.tgz", + "integrity": "sha512-EUkci0FAUiE4IvGTSKcDJIQ/eRUP2JJb56+fvZ4sdnguLTqIdKjSxUe138poW8mkvKWXW2sFPrgTsxqoISnmoA==", + "license": "MIT", + "dependencies": { + "fastfall": "^1.5.0", + "fastparallel": "^2.2.0", + "fastq": "^1.3.0", + "fastseries": "^1.7.0", + "reusify": "^1.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.3.tgz", + "integrity": "sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==", + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/thread-stream": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-4.0.0.tgz", + "integrity": "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/toad-cache": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/toad-cache/-/toad-cache-3.7.0.tgz", + "integrity": "sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.21.0.tgz", + "integrity": "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.27.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsyringe": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", + "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", + "license": "MIT", + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/tsyringe/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/server/package.json b/server/package.json new file mode 100644 index 0000000..85c9a81 --- /dev/null +++ b/server/package.json @@ -0,0 +1,28 @@ +{ + "name": "private-chat-server", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "dev": "node node_modules/tsx/dist/cli.mjs watch src/index.ts", + "build": "node node_modules/typescript/bin/tsc -p tsconfig.json", + "start": "node dist/index.js" + }, + "dependencies": { + "@fastify/cors": "^11.2.0", + "@fastify/jwt": "^10.0.0", + "@fastify/static": "^9.0.0", + "@fastify/websocket": "^11.2.0", + "@simplewebauthn/server": "^13.2.3", + "dotenv": "^17.3.1", + "fastify": "^5.8.2", + "ioredis": "^5.10.0", + "zod": "^4.3.6" + }, + "devDependencies": { + "@types/node": "^25.3.5", + "@types/ws": "^8.18.1", + "tsx": "^4.21.0", + "typescript": "^5.9.3" + } +} diff --git a/server/src/index.ts b/server/src/index.ts new file mode 100644 index 0000000..8372a57 --- /dev/null +++ b/server/src/index.ts @@ -0,0 +1,1540 @@ +import crypto from 'node:crypto'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { TextEncoder } from 'node:util'; +import { DatabaseSync } from 'node:sqlite'; + +import cors from '@fastify/cors'; +import jwt from '@fastify/jwt'; +import fastifyStatic from '@fastify/static'; +import websocket from '@fastify/websocket'; +import dotenv from 'dotenv'; +import { + generateAuthenticationOptions, + generateRegistrationOptions, + verifyAuthenticationResponse, + type AuthenticationResponseJSON, + verifyRegistrationResponse, + type RegistrationResponseJSON, +} from '@simplewebauthn/server'; +import Fastify, { type FastifyReply, type FastifyRequest } from 'fastify'; +import { Redis } from 'ioredis'; +import type WebSocket from 'ws'; +import { z } from 'zod'; + +dotenv.config({ path: fileURLToPath(new URL('../../.env', import.meta.url)) }); + +const projectRootPath = fileURLToPath(new URL('../../', import.meta.url)); + +type UserRecord = { + id: string; + username: string; + displayName: string; + passwordHash: string; + messageEncryptionKey: string; + isActive: boolean; + createdAt: string; + approvedAt: string | null; +}; + +type PublicUser = { + id: string; + username: string; + displayName: string; +}; + +type AuthToken = { + sub: string; + username: string; + displayName: string; + sid: string; +}; + +type SessionRecord = { + sessionId: string; + userId: string; + createdAt: string; +}; + +type AuthContext = { + user: UserRecord; + session: SessionRecord; + token: AuthToken; +}; + +type DatabaseUserRow = { + id: string; + username: string; + display_name: string; + encrypted_credentials: string; + is_active: number; + created_at: string; + approved_at: string | null; +}; + +type DatabaseTableColumnRow = { + name: string; +}; + +type PendingApprovalUser = { + id: string; + username: string; + displayName: string; + createdAt: string; +}; + +type DatabaseAccessKeyRow = { + id: string; + user_id: string; + credential_id: string; + label: string; + encrypted_registration: string; + created_at: string; +}; + +type SignalPayload = + | { type: 'sdp'; description: RTCSessionDescriptionInit } + | { type: 'ice-candidate'; candidate: RTCIceCandidateInit }; + +type ClientMessage = { + type: 'signal'; + to: string; + signal: SignalPayload; +}; + +type ServerMessage = + | { type: 'presence'; self: PublicUser; peers: PublicUser[] } + | { type: 'peer-joined'; peer: PublicUser } + | { type: 'peer-left'; peerId: string } + | { type: 'signal'; from: string; signal: SignalPayload } + | { type: 'error'; message: string }; + +type StoredCredentials = { + passwordHash: string; + messageEncryptionKey?: string; +}; + +type StoredAccessKey = { + credentialId: string; + publicKey: string; + counter: number; + transports: string[]; + deviceType: string; + backedUp: boolean; + aaguid: string; +}; + +type AccessKeySummary = { + id: string; + credentialId: string; + label: string; + transports: string[]; + deviceType: string; + backedUp: boolean; + aaguid: string; + createdAt: string; +}; + +type PendingRegistration = { + challenge: string; + label: string; + expectedOrigin: string; + expectedRpId: string; +}; + +type PendingAuthentication = { + challenge: string; + expectedOrigin: string; + expectedRpId: string; + expectedUserId: string | null; +}; + +type WebRtcCandidate = { + candidate?: string; + sdpMid?: string | null; + sdpMLineIndex?: number | null; + usernameFragment?: string | null; +}; + +type WebRtcDescription = { + type: 'offer' | 'answer' | 'pranswer' | 'rollback'; + sdp?: string; +}; + +const registerSchema = z.object({ + username: z.string().trim().min(3).max(32).regex(/^[a-zA-Z0-9_-]+$/), + displayName: z.string().trim().min(2).max(48).optional(), + password: z.string().min(8).max(128), +}); + +const loginSchema = z.object({ + username: z.string().trim().min(3).max(32), + password: z.string().min(8).max(128), +}); + +const accessKeyLabelSchema = z.object({ + label: z.string().trim().min(1).max(64).optional(), +}); + +const verifyAccessKeySchema = z.object({ + credential: z.custom(), +}); + +const accessKeyAuthenticationSchema = z.object({ + username: z.string().trim().min(3).max(32).optional(), +}); + +const verifyAccessKeyAuthenticationSchema = z.object({ + attemptId: z.string().min(1), + credential: z.custom(), +}); + +const approvePendingUserParamsSchema = z.object({ + userId: z.string().min(1), +}); + +const wsQuerySchema = z.object({ + token: z.string().min(1), +}); + +const signalMessageSchema = z.discriminatedUnion('type', [ + z.object({ + type: z.literal('signal'), + to: z.string().min(1), + signal: z.discriminatedUnion('type', [ + z.object({ + type: z.literal('sdp'), + description: z.object({ + type: z.enum(['offer', 'answer', 'pranswer', 'rollback']), + sdp: z.string().optional(), + }), + }), + z.object({ + type: z.literal('ice-candidate'), + candidate: z.object({ + candidate: z.string().optional(), + sdpMid: z.string().nullable().optional(), + sdpMLineIndex: z.number().nullable().optional(), + usernameFragment: z.string().nullable().optional(), + }), + }), + ]), + }), +]); + +const app = Fastify({ logger: true }); +const approvalAdminUsername = 'ladparis'; + +const dataDirectory = resolveStoragePath(process.env.PRIVATECHAT_DATA_DIR ?? 'server/data'); +const sqlitePath = resolveStoragePath( + process.env.SQLITE_PATH ?? path.join(dataDirectory, 'privatechat.sqlite'), +); +const masterKeyPath = resolveStoragePath( + process.env.PRIVATECHAT_MASTER_KEY_PATH ?? path.join(dataDirectory, 'master.key'), +); +const frontendDistPath = resolveProjectPath( + process.env.PRIVATECHAT_WEB_DIST_DIR ?? 'client/dist/client/browser', +); +const sessionTtlSeconds = Number(process.env.SESSION_TTL_SECONDS ?? 60 * 60 * 12); +const webAuthnChallengeTtlSeconds = Number(process.env.WEBAUTHN_CHALLENGE_TTL_SECONDS ?? 5 * 60); +const webAuthnOrigin = process.env.WEBAUTHN_ORIGIN ?? 'http://localhost:4200'; +const webAuthnRpName = process.env.WEBAUTHN_RP_NAME ?? 'PrivateChat'; +const webAuthnUserVerification = resolveWebAuthnUserVerification( + process.env.WEBAUTHN_USER_VERIFICATION, +); +const frontendIndexPath = path.join(frontendDistPath, 'index.html'); +const hasFrontendBuild = fs.existsSync(frontendIndexPath); + +fs.mkdirSync(path.dirname(sqlitePath), { recursive: true }); +fs.mkdirSync(path.dirname(masterKeyPath), { recursive: true }); + +const encryptionKey = deriveEncryptionKey(loadOrCreateMasterKey(masterKeyPath)); +const database = new DatabaseSync(sqlitePath); + +database.exec(` + PRAGMA journal_mode = WAL; + + CREATE TABLE IF NOT EXISTS users ( + id TEXT PRIMARY KEY, + username TEXT NOT NULL UNIQUE, + display_name TEXT NOT NULL, + encrypted_credentials TEXT NOT NULL, + is_active INTEGER NOT NULL DEFAULT 1, + approved_at TEXT, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS app_secrets ( + name TEXT PRIMARY KEY, + encrypted_value TEXT NOT NULL, + created_at TEXT NOT NULL + ); + + CREATE TABLE IF NOT EXISTS webauthn_credentials ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + credential_id TEXT NOT NULL UNIQUE, + label TEXT NOT NULL, + encrypted_registration TEXT NOT NULL, + created_at TEXT NOT NULL, + FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE + ); +`); + +ensureUserApprovalColumns(); + +const createUserStatement = database.prepare(` + INSERT INTO users (id, username, display_name, encrypted_credentials, is_active, approved_at, created_at) + VALUES (?, ?, ?, ?, ?, ?, ?) +`); +const selectUserByUsernameStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE username = ? +`); +const selectUserByIdStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE id = ? +`); +const selectPendingUsersStatement = database.prepare(` + SELECT id, username, display_name, encrypted_credentials, is_active, created_at, approved_at + FROM users + WHERE is_active = 0 + ORDER BY created_at ASC +`); +const approveUserStatement = database.prepare(` + UPDATE users + SET is_active = 1, approved_at = ? + WHERE id = ? AND is_active = 0 +`); +const updateUserCredentialsStatement = database.prepare(` + UPDATE users + SET encrypted_credentials = ? + WHERE id = ? +`); +const insertSecretStatement = database.prepare(` + INSERT INTO app_secrets (name, encrypted_value, created_at) + VALUES (?, ?, ?) +`); +const selectSecretStatement = database.prepare(` + SELECT encrypted_value + FROM app_secrets + WHERE name = ? +`); +const createAccessKeyStatement = database.prepare(` + INSERT INTO webauthn_credentials (id, user_id, credential_id, label, encrypted_registration, created_at) + VALUES (?, ?, ?, ?, ?, ?) +`); +const selectAccessKeysByUserStatement = database.prepare(` + SELECT id, user_id, credential_id, label, encrypted_registration, created_at + FROM webauthn_credentials + WHERE user_id = ? + ORDER BY created_at DESC +`); +const selectAccessKeyByCredentialIdStatement = database.prepare(` + SELECT id, user_id, credential_id, label, encrypted_registration, created_at + FROM webauthn_credentials + WHERE credential_id = ? +`); +const updateAccessKeyStatement = database.prepare(` + UPDATE webauthn_credentials + SET encrypted_registration = ? + WHERE credential_id = ? +`); + +const jwtSecret = loadOrCreateSecret('jwt-secret', () => crypto.randomBytes(64).toString('hex')); +const redis = new Redis(process.env.REDIS_URL ?? 'redis://127.0.0.1:6379/0'); +const socketsByUserId = new Map>(); + +await redis.ping(); + +await app.register(cors, { + origin: process.env.CORS_ORIGIN ? [process.env.CORS_ORIGIN] : true, + credentials: false, +}); + +await app.register(jwt, { + secret: jwtSecret, +}); + +await app.register(websocket); + +if (hasFrontendBuild) { + await app.register(fastifyStatic, { + root: frontendDistPath, + prefix: '/', + }); + + app.setNotFoundHandler((request, reply) => { + const requestPath = request.raw.url?.split('?')[0] ?? '/'; + + if ( + request.method !== 'GET' || + requestPath === '/ws' || + requestPath === '/api' || + requestPath.startsWith('/api/') + ) { + return reply.code(404).send({ message: 'Not found.' }); + } + + return reply.type('text/html; charset=utf-8').send(fs.createReadStream(frontendIndexPath)); + }); +} else { + app.log.warn( + { frontendDistPath }, + 'Angular frontend build not found. Build the client before serving it from the backend.', + ); +} + +app.get('/api/health', async () => ({ ok: true })); + +app.post('/api/auth/register', async (request, reply) => { + const parsed = registerSchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid registration payload.', + issues: parsed.error.flatten(), + }); + } + + const username = parsed.data.username.toLowerCase(); + + if (findUserByUsername(username)) { + return reply.code(409).send({ message: 'Username is already taken.' }); + } + + const user = createUser({ + username, + displayName: parsed.data.displayName?.trim() || parsed.data.username, + password: parsed.data.password, + isActive: username === approvalAdminUsername, + }); + + if (!user.isActive) { + return reply.code(202).send({ + pendingApproval: true, + message: `Account created. It must be approved by ${approvalAdminUsername} before you can sign in.`, + }); + } + + const session = await createSession(user.id); + + return createAuthReply(user, session.sessionId); +}); + +app.post('/api/auth/login', async (request, reply) => { + const parsed = loginSchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid login payload.', + issues: parsed.error.flatten(), + }); + } + + const user = findUserByUsername(parsed.data.username.toLowerCase()); + + if (!user || !verifyPassword(parsed.data.password, user.passwordHash)) { + return reply.code(401).send({ message: 'Invalid credentials.' }); + } + + if (!user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + + const session = await createSession(user.id); + + return createAuthReply(user, session.sessionId); +}); + +app.post('/api/webauthn/authenticate/options', async (request, reply) => { + const parsed = accessKeyAuthenticationSchema.safeParse(request.body ?? {}); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key sign-in payload.', + issues: parsed.error.flatten(), + }); + } + + const expectedOrigin = resolveWebAuthnOrigin(request); + const expectedRpId = process.env.WEBAUTHN_RP_ID ?? new URL(expectedOrigin).hostname; + const username = parsed.data.username?.trim().toLowerCase(); + const user = username ? findUserByUsername(username) : null; + + if (username && !user) { + return reply.code(400).send({ message: 'No access key is registered for that username.' }); + } + + if (user && !user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + + const storedCredentials = user ? listStoredAccessKeys(user.id) : []; + + if (username && storedCredentials.length === 0) { + return reply.code(400).send({ message: 'No access key is registered for that username.' }); + } + + const attemptId = crypto.randomUUID(); + const options = await generateAuthenticationOptions({ + rpID: expectedRpId, + userVerification: webAuthnUserVerification, + allowCredentials: + storedCredentials.length > 0 + ? storedCredentials.map((credential) => ({ + id: credential.credentialId, + transports: credential.transports as ( + | 'ble' + | 'cable' + | 'hybrid' + | 'internal' + | 'nfc' + | 'smart-card' + | 'usb' + )[], + })) + : undefined, + }); + + await redis.set( + webAuthnAuthenticationKey(attemptId), + JSON.stringify({ + challenge: options.challenge, + expectedOrigin, + expectedRpId, + expectedUserId: user?.id ?? null, + } satisfies PendingAuthentication), + 'EX', + webAuthnChallengeTtlSeconds, + ); + + return { + attemptId, + expectedOrigin, + ...options, + }; +}); + +app.post('/api/webauthn/authenticate/verify', async (request, reply) => { + const parsed = verifyAccessKeyAuthenticationSchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key sign-in verification payload.', + issues: parsed.error.flatten(), + }); + } + + const pending = await getPendingAuthentication(parsed.data.attemptId); + + if (!pending) { + return reply.code(400).send({ message: 'Access key sign-in challenge expired.' }); + } + + try { + const storedAccessKey = findStoredAccessKeyByCredentialId(parsed.data.credential.id); + + if (!storedAccessKey) { + return reply.code(401).send({ message: 'This access key is not registered.' }); + } + + if (!storedAccessKey.user.isActive) { + return reply.code(403).send({ + message: `Your account is awaiting approval from ${approvalAdminUsername}.`, + }); + } + + if (pending.expectedUserId && storedAccessKey.user.id !== pending.expectedUserId) { + return reply.code(401).send({ message: 'This access key does not match the requested username.' }); + } + + const verification = await verifyAuthenticationResponse({ + response: parsed.data.credential, + expectedChallenge: pending.challenge, + expectedOrigin: pending.expectedOrigin, + expectedRPID: pending.expectedRpId, + credential: { + id: storedAccessKey.registration.credentialId, + publicKey: Buffer.from(storedAccessKey.registration.publicKey, 'base64url'), + counter: storedAccessKey.registration.counter, + transports: storedAccessKey.registration.transports as ( + | 'ble' + | 'cable' + | 'hybrid' + | 'internal' + | 'nfc' + | 'smart-card' + | 'usb' + )[], + }, + requireUserVerification: webAuthnUserVerification === 'required', + }); + + if (!verification.verified) { + return reply.code(401).send({ message: 'Access key sign-in could not be verified.' }); + } + + updateStoredAccessKey(storedAccessKey, { + counter: verification.authenticationInfo.newCounter, + deviceType: verification.authenticationInfo.credentialDeviceType, + backedUp: verification.authenticationInfo.credentialBackedUp, + }); + + const session = await createSession(storedAccessKey.user.id); + + return createAuthReply(storedAccessKey.user, session.sessionId); + } catch (error) { + app.log.warn({ err: error }, 'WebAuthn authentication verification failed'); + return reply.code(400).send({ + message: + error instanceof Error + ? `Access key sign-in could not be verified: ${error.message}` + : 'Access key sign-in could not be verified.', + }); + } finally { + await clearPendingAuthentication(parsed.data.attemptId); + } +}); + +app.get('/api/auth/session', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + return { + user: toPublicUser(authContext.user), + messageEncryptionKey: authContext.user.messageEncryptionKey, + }; +}); + +app.get('/api/admin/pending-users', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + if (!isApprovalAdmin(authContext.user)) { + return reply.code(403).send({ message: 'Only ladparis can approve accounts.' }); + } + + return { + users: listPendingApprovalUsers(), + }; +}); + +app.post('/api/admin/pending-users/:userId/approve', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + if (!isApprovalAdmin(authContext.user)) { + return reply.code(403).send({ message: 'Only ladparis can approve accounts.' }); + } + + const parsed = approvePendingUserParamsSchema.safeParse(request.params); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid user approval request.', + issues: parsed.error.flatten(), + }); + } + + const approvedUser = approveUser(parsed.data.userId); + + if (!approvedUser) { + return reply.code(404).send({ message: 'Pending user not found.' }); + } + + return { + user: toPublicUser(approvedUser), + }; +}); + +app.post('/api/auth/logout', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + await destroySession(authContext.session.sessionId); + await clearPendingRegistration(authContext.session.sessionId); + closeSocketSession(authContext.user.id, authContext.session.sessionId); + + return { ok: true }; +}); + +app.get('/api/webauthn/credentials', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + return { + credentials: listAccessKeys(authContext.user.id), + }; +}); + +app.post('/api/webauthn/register/options', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + const parsed = accessKeyLabelSchema.safeParse(request.body ?? {}); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key request payload.', + issues: parsed.error.flatten(), + }); + } + + const label = parsed.data.label?.trim() || defaultAccessKeyLabel(); + const storedCredentials = listStoredAccessKeys(authContext.user.id); + const expectedOrigin = resolveWebAuthnOrigin(request); + const expectedRpId = process.env.WEBAUTHN_RP_ID ?? new URL(expectedOrigin).hostname; + + const options = await generateRegistrationOptions({ + rpName: webAuthnRpName, + rpID: expectedRpId, + userName: authContext.user.username, + userDisplayName: authContext.user.displayName, + userID: new TextEncoder().encode(authContext.user.id), + attestationType: 'none', + authenticatorSelection: { + residentKey: 'preferred', + userVerification: webAuthnUserVerification, + }, + excludeCredentials: storedCredentials.map((credential) => ({ + id: credential.credentialId, + transports: credential.transports as ( + | 'ble' + | 'cable' + | 'hybrid' + | 'internal' + | 'nfc' + | 'smart-card' + | 'usb' + )[], + })), + }); + + await redis.set( + webAuthnRegistrationKey(authContext.session.sessionId), + JSON.stringify({ + challenge: options.challenge, + label, + expectedOrigin, + expectedRpId, + } satisfies PendingRegistration), + 'EX', + webAuthnChallengeTtlSeconds, + ); + + return { + expectedOrigin, + ...options, + }; +}); + +app.post('/api/webauthn/register/verify', async (request, reply) => { + const authContext = await authenticateRequest(request, reply); + + if (!authContext) { + return; + } + + const parsed = verifyAccessKeySchema.safeParse(request.body); + + if (!parsed.success) { + return reply.code(400).send({ + message: 'Invalid access key verification payload.', + issues: parsed.error.flatten(), + }); + } + + const pending = await getPendingRegistration(authContext.session.sessionId); + + if (!pending) { + return reply.code(400).send({ message: 'Access key registration challenge expired.' }); + } + + try { + const verification = await verifyRegistrationResponse({ + response: parsed.data.credential, + expectedChallenge: pending.challenge, + expectedOrigin: pending.expectedOrigin, + expectedRPID: pending.expectedRpId, + requireUserVerification: webAuthnUserVerification === 'required', + }); + + if (!verification.verified || !verification.registrationInfo) { + return reply.code(400).send({ message: 'Access key registration could not be verified.' }); + } + + const registrationInfo = verification.registrationInfo; + + persistAccessKey(authContext.user.id, { + credentialId: registrationInfo.credential.id, + label: pending.label, + publicKey: bytesToBase64Url(registrationInfo.credential.publicKey), + counter: registrationInfo.credential.counter, + transports: registrationInfo.credential.transports ?? [], + deviceType: registrationInfo.credentialDeviceType, + backedUp: registrationInfo.credentialBackedUp, + aaguid: registrationInfo.aaguid, + }); + + await clearPendingRegistration(authContext.session.sessionId); + + return { + credential: listAccessKeys(authContext.user.id)[0], + }; + } catch (error) { + app.log.warn({ err: error }, 'WebAuthn registration verification failed'); + return reply.code(400).send({ + message: + error instanceof Error + ? `Access key registration could not be verified: ${error.message}` + : 'Access key registration could not be verified.', + }); + } +}); + +app.get('/ws', { websocket: true }, (socket, request) => { + void openSocket(socket, request); +}); + +const port = Number(process.env.PORT ?? 16990); + +await app.listen({ port, host: '0.0.0.0' }); + +app.log.info(`PrivateChat signaling server listening on http://localhost:${port}`); + +async function openSocket(socket: WebSocket, request: FastifyRequest): Promise { + const query = wsQuerySchema.safeParse(request.query); + + if (!query.success) { + send(socket, { type: 'error', message: 'Missing token.' }); + socket.close(); + return; + } + + const authContext = await authenticateToken(query.data.token); + + if (!authContext) { + send(socket, { type: 'error', message: 'Authentication required.' }); + socket.close(); + return; + } + + const userSockets = socketsByUserId.get(authContext.user.id) ?? new Map(); + const isFirstConnection = userSockets.size === 0; + + userSockets.set(authContext.session.sessionId, socket); + socketsByUserId.set(authContext.user.id, userSockets); + + send(socket, { + type: 'presence', + self: toPublicUser(authContext.user), + peers: listOnlinePeers(authContext.user.id), + }); + + if (isFirstConnection) { + broadcastExcept(authContext.user.id, { + type: 'peer-joined', + peer: toPublicUser(authContext.user), + }); + } + + socket.on('message', (rawMessage: WebSocket.RawData) => { + void handleSocketMessage( + authContext.user.id, + authContext.session.sessionId, + socket, + rawMessage.toString(), + ); + }); + + socket.on('close', () => { + if (detachSocket(authContext.user.id, authContext.session.sessionId)) { + broadcastExcept(authContext.user.id, { type: 'peer-left', peerId: authContext.user.id }); + } + }); +} + +async function handleSocketMessage( + userId: string, + sessionId: string, + socket: WebSocket, + rawMessage: string, +): Promise { + const authContext = await authenticateTokenFromSession(userId, sessionId); + + if (!authContext) { + send(socket, { type: 'error', message: 'Session expired.' }); + socket.close(); + return; + } + + const parsed = parseClientMessage(rawMessage); + + if (!parsed) { + send(socket, { type: 'error', message: 'Unsupported signaling message.' }); + return; + } + + let delivered = 0; + const recipientSockets = socketsByUserId.get(parsed.to); + + if (recipientSockets) { + for (const [recipientSessionId, recipientSocket] of recipientSockets.entries()) { + const recipientContext = await authenticateTokenFromSession(parsed.to, recipientSessionId); + + if (!recipientContext) { + recipientSocket.close(); + continue; + } + + send(recipientSocket, { + type: 'signal', + from: authContext.user.id, + signal: parsed.signal, + }); + delivered += 1; + } + } + + if (delivered === 0) { + send(socket, { type: 'error', message: 'Peer is offline or not authenticated.' }); + } +} + +function createAuthReply(user: UserRecord, sessionId: string) { + return { + token: app.jwt.sign({ + sub: user.id, + username: user.username, + displayName: user.displayName, + sid: sessionId, + } satisfies AuthToken), + user: toPublicUser(user), + messageEncryptionKey: user.messageEncryptionKey, + }; +} + +async function authenticateRequest( + request: FastifyRequest, + reply: FastifyReply, +): Promise { + const token = extractBearerToken(request.headers.authorization); + + if (!token) { + reply.code(401).send({ message: 'Authentication required.' }); + return null; + } + + const authContext = await authenticateToken(token); + + if (!authContext) { + reply.code(401).send({ message: 'Invalid or expired session.' }); + return null; + } + + return authContext; +} + +async function authenticateToken(token: string): Promise { + let decoded: AuthToken; + + try { + decoded = app.jwt.verify(token); + } catch { + return null; + } + + return authenticateTokenFromSession(decoded.sub, decoded.sid, decoded); +} + +async function authenticateTokenFromSession( + userId: string, + sessionId: string, + decoded?: AuthToken, +): Promise { + const session = await getSession(sessionId); + + if (!session || session.userId !== userId) { + return null; + } + + const user = findUserById(userId); + + if (!user) { + await destroySession(sessionId); + return null; + } + + if (!user.isActive) { + await destroySession(sessionId); + return null; + } + + await redis.expire(sessionKey(sessionId), sessionTtlSeconds); + + return { + user, + session, + token: + decoded ?? { + sub: user.id, + username: user.username, + displayName: user.displayName, + sid: sessionId, + }, + }; +} + +function createUser(input: { + username: string; + displayName: string; + password: string; + isActive: boolean; +}): UserRecord { + const createdAt = new Date().toISOString(); + const user: UserRecord = { + id: crypto.randomUUID(), + username: input.username, + displayName: input.displayName, + passwordHash: hashPassword(input.password), + messageEncryptionKey: generateUserMessageEncryptionKey(), + isActive: input.isActive, + createdAt, + approvedAt: input.isActive ? createdAt : null, + }; + + createUserStatement.run( + user.id, + user.username, + user.displayName, + encryptJson({ + passwordHash: user.passwordHash, + messageEncryptionKey: user.messageEncryptionKey, + }), + user.isActive ? 1 : 0, + user.approvedAt, + user.createdAt, + ); + + return user; +} + +function listPendingApprovalUsers(): PendingApprovalUser[] { + const rows = selectPendingUsersStatement.all() as DatabaseUserRow[]; + + return rows.map((row) => ({ + id: row.id, + username: row.username, + displayName: row.display_name, + createdAt: row.created_at, + })); +} + +function approveUser(userId: string): UserRecord | null { + const approvedAt = new Date().toISOString(); + const result = approveUserStatement.run(approvedAt, userId); + + if (result.changes === 0) { + return null; + } + + return findUserById(userId); +} + +function persistAccessKey( + userId: string, + input: { + credentialId: string; + label: string; + publicKey: string; + counter: number; + transports: string[]; + deviceType: string; + backedUp: boolean; + aaguid: string; + }, +): void { + createAccessKeyStatement.run( + crypto.randomUUID(), + userId, + input.credentialId, + input.label, + encryptJson({ + credentialId: input.credentialId, + publicKey: input.publicKey, + counter: input.counter, + transports: input.transports, + deviceType: input.deviceType, + backedUp: input.backedUp, + aaguid: input.aaguid, + }), + new Date().toISOString(), + ); +} + +function updateStoredAccessKey( + storedAccessKey: { + row: DatabaseAccessKeyRow; + user: UserRecord; + registration: StoredAccessKey; + }, + changes: { + counter: number; + deviceType: string; + backedUp: boolean; + }, +): void { + const nextRegistration: StoredAccessKey = { + ...storedAccessKey.registration, + counter: changes.counter, + deviceType: changes.deviceType, + backedUp: changes.backedUp, + }; + + updateAccessKeyStatement.run( + encryptJson(nextRegistration), + storedAccessKey.row.credential_id, + ); +} + +function findUserByUsername(username: string): UserRecord | null { + const row = selectUserByUsernameStatement.get(username) as DatabaseUserRow | undefined; + + return row ? hydrateUser(row) : null; +} + +function findUserById(userId: string): UserRecord | null { + const row = selectUserByIdStatement.get(userId) as DatabaseUserRow | undefined; + + return row ? hydrateUser(row) : null; +} + +function hydrateUser(row: DatabaseUserRow): UserRecord { + const credentials = decryptJson(row.encrypted_credentials); + const messageEncryptionKey = credentials.messageEncryptionKey ?? generateUserMessageEncryptionKey(); + + if (!credentials.messageEncryptionKey) { + updateUserCredentialsStatement.run( + encryptJson({ + passwordHash: credentials.passwordHash, + messageEncryptionKey, + }), + row.id, + ); + } + + return { + id: row.id, + username: row.username, + displayName: row.display_name, + passwordHash: credentials.passwordHash, + messageEncryptionKey, + isActive: row.is_active === 1, + createdAt: row.created_at, + approvedAt: row.approved_at, + }; +} + +function listStoredAccessKeys(userId: string): StoredAccessKey[] { + const rows = selectAccessKeysByUserStatement.all(userId) as DatabaseAccessKeyRow[]; + + return rows.map((row) => decryptJson(row.encrypted_registration)); +} + +function findStoredAccessKeyByCredentialId(credentialId: string): { + row: DatabaseAccessKeyRow; + user: UserRecord; + registration: StoredAccessKey; +} | null { + const row = selectAccessKeyByCredentialIdStatement.get(credentialId) as DatabaseAccessKeyRow | undefined; + + if (!row) { + return null; + } + + const user = findUserById(row.user_id); + + if (!user) { + return null; + } + + return { + row, + user, + registration: decryptJson(row.encrypted_registration), + }; +} + +function listAccessKeys(userId: string): AccessKeySummary[] { + const rows = selectAccessKeysByUserStatement.all(userId) as DatabaseAccessKeyRow[]; + + return rows.map((row) => { + const registration = decryptJson(row.encrypted_registration); + + return { + id: row.id, + credentialId: row.credential_id, + label: row.label, + transports: registration.transports, + deviceType: registration.deviceType, + backedUp: registration.backedUp, + aaguid: registration.aaguid, + createdAt: row.created_at, + }; + }); +} + +function loadOrCreateSecret(name: string, createValue: () => string): string { + const row = selectSecretStatement.get(name) as { encrypted_value: string } | undefined; + + if (row) { + return decryptText(row.encrypted_value); + } + + const value = createValue(); + insertSecretStatement.run(name, encryptText(value), new Date().toISOString()); + return value; +} + +async function createSession(userId: string): Promise { + const session: SessionRecord = { + sessionId: crypto.randomUUID(), + userId, + createdAt: new Date().toISOString(), + }; + + await redis.set(sessionKey(session.sessionId), JSON.stringify(session), 'EX', sessionTtlSeconds); + + return session; +} + +async function getSession(sessionId: string): Promise { + const payload = await redis.get(sessionKey(sessionId)); + + if (!payload) { + return null; + } + + return JSON.parse(payload) as SessionRecord; +} + +async function destroySession(sessionId: string): Promise { + await redis.del(sessionKey(sessionId)); +} + +function sessionKey(sessionId: string): string { + return `privatechat:session:${sessionId}`; +} + +function webAuthnRegistrationKey(sessionId: string): string { + return `privatechat:webauthn-registration:${sessionId}`; +} + +function webAuthnAuthenticationKey(attemptId: string): string { + return `privatechat:webauthn-authentication:${attemptId}`; +} + +async function getPendingRegistration(sessionId: string): Promise { + const payload = await redis.get(webAuthnRegistrationKey(sessionId)); + + if (!payload) { + return null; + } + + return JSON.parse(payload) as PendingRegistration; +} + +async function clearPendingRegistration(sessionId: string): Promise { + await redis.del(webAuthnRegistrationKey(sessionId)); +} + +async function getPendingAuthentication(attemptId: string): Promise { + const payload = await redis.get(webAuthnAuthenticationKey(attemptId)); + + if (!payload) { + return null; + } + + return JSON.parse(payload) as PendingAuthentication; +} + +async function clearPendingAuthentication(attemptId: string): Promise { + await redis.del(webAuthnAuthenticationKey(attemptId)); +} + +function closeSocketSession(userId: string, sessionId: string): void { + const socket = socketsByUserId.get(userId)?.get(sessionId); + + if (socket && socket.readyState < 2) { + socket.close(); + } +} + +function detachSocket(userId: string, sessionId: string): boolean { + const userSockets = socketsByUserId.get(userId); + + if (!userSockets) { + return false; + } + + userSockets.delete(sessionId); + + if (userSockets.size === 0) { + socketsByUserId.delete(userId); + return true; + } + + return false; +} + +function listOnlinePeers(currentUserId: string): PublicUser[] { + const peers: PublicUser[] = []; + + for (const [userId, sockets] of socketsByUserId.entries()) { + if (userId === currentUserId || sockets.size === 0) { + continue; + } + + const user = findUserById(userId); + + if (user) { + peers.push(toPublicUser(user)); + } + } + + return peers.sort((left, right) => left.displayName.localeCompare(right.displayName)); +} + +function broadcastExcept(userId: string, payload: ServerMessage): void { + for (const [peerId, sockets] of socketsByUserId.entries()) { + if (peerId === userId) { + continue; + } + + for (const socket of sockets.values()) { + send(socket, payload); + } + } +} + +function send(socket: WebSocket, payload: ServerMessage): void { + if (socket.readyState === 1) { + socket.send(JSON.stringify(payload)); + } +} + +function parseClientMessage(rawMessage: string): ClientMessage | null { + let payload: unknown; + + try { + payload = JSON.parse(rawMessage); + } catch { + return null; + } + + const parsed = signalMessageSchema.safeParse(payload); + + if (!parsed.success) { + return null; + } + + return { + type: 'signal', + to: parsed.data.to, + signal: normalizeSignal(parsed.data.signal), + }; +} + +function normalizeSignal(signal: ClientMessage['signal']): SignalPayload { + if (signal.type === 'sdp') { + return { + type: 'sdp', + description: signal.description as WebRtcDescription, + }; + } + + return { + type: 'ice-candidate', + candidate: signal.candidate as WebRtcCandidate, + }; +} + +function extractBearerToken(authorizationHeader?: string): string | null { + if (!authorizationHeader?.startsWith('Bearer ')) { + return null; + } + + return authorizationHeader.slice('Bearer '.length).trim(); +} + +function toPublicUser(user: UserRecord): PublicUser { + return { + id: user.id, + username: user.username, + displayName: user.displayName, + }; +} + +function isApprovalAdmin(user: UserRecord): boolean { + return user.username === approvalAdminUsername; +} + +function hashPassword(password: string): string { + const salt = crypto.randomBytes(16).toString('hex'); + const derived = crypto.scryptSync(password, salt, 64).toString('hex'); + + return `${salt}:${derived}`; +} + +function verifyPassword(password: string, storedHash: string): boolean { + const [salt, stored] = storedHash.split(':'); + + if (!salt || !stored) { + return false; + } + + const incoming = crypto.scryptSync(password, salt, 64); + const saved = Buffer.from(stored, 'hex'); + + return incoming.length === saved.length && crypto.timingSafeEqual(incoming, saved); +} + +function generateUserMessageEncryptionKey(): string { + return crypto.randomBytes(32).toString('base64url'); +} + +function encryptJson(value: T): string { + return encryptText(JSON.stringify(value)); +} + +function decryptJson(payload: string): T { + return JSON.parse(decryptText(payload)) as T; +} + +function encryptText(value: string): string { + const iv = crypto.randomBytes(12); + const cipher = crypto.createCipheriv('aes-256-gcm', encryptionKey, iv); + const encrypted = Buffer.concat([cipher.update(value, 'utf8'), cipher.final()]); + const authTag = cipher.getAuthTag(); + + return `${iv.toString('hex')}:${authTag.toString('hex')}:${encrypted.toString('hex')}`; +} + +function decryptText(payload: string): string { + const [ivHex, authTagHex, encryptedHex] = payload.split(':'); + + if (!ivHex || !authTagHex || !encryptedHex) { + throw new Error('Encrypted payload is malformed.'); + } + + const decipher = crypto.createDecipheriv('aes-256-gcm', encryptionKey, Buffer.from(ivHex, 'hex')); + decipher.setAuthTag(Buffer.from(authTagHex, 'hex')); + const decrypted = Buffer.concat([ + decipher.update(Buffer.from(encryptedHex, 'hex')), + decipher.final(), + ]); + + return decrypted.toString('utf8'); +} + +function loadOrCreateMasterKey(masterKeyFilePath: string): string { + if (process.env.PRIVATECHAT_MASTER_KEY) { + return process.env.PRIVATECHAT_MASTER_KEY; + } + + if (fs.existsSync(masterKeyFilePath)) { + return fs.readFileSync(masterKeyFilePath, 'utf8').trim(); + } + + const generatedKey = crypto.randomBytes(32).toString('hex'); + fs.writeFileSync(masterKeyFilePath, generatedKey, { mode: 0o600 }); + return generatedKey; +} + +function ensureUserApprovalColumns(): void { + const rows = database.prepare('PRAGMA table_info(users)').all() as DatabaseTableColumnRow[]; + const columnNames = new Set(rows.map((row) => row.name)); + + if (!columnNames.has('is_active')) { + database.exec('ALTER TABLE users ADD COLUMN is_active INTEGER NOT NULL DEFAULT 1'); + } + + if (!columnNames.has('approved_at')) { + database.exec('ALTER TABLE users ADD COLUMN approved_at TEXT'); + } + + database.exec(` + UPDATE users + SET approved_at = COALESCE(approved_at, created_at) + WHERE is_active = 1 + `); +} + +function deriveEncryptionKey(masterKeyMaterial: string): Buffer { + return crypto.createHash('sha256').update(masterKeyMaterial).digest(); +} + +function resolveStoragePath(targetPath: string): string { + return path.isAbsolute(targetPath) ? targetPath : path.resolve(process.cwd(), targetPath); +} + +function resolveProjectPath(targetPath: string): string { + return path.isAbsolute(targetPath) ? targetPath : path.resolve(projectRootPath, targetPath); +} + +function resolveWebAuthnOrigin(request: FastifyRequest): string { + const originHeader = request.headers.origin; + + if (typeof originHeader === 'string' && originHeader.length > 0) { + return originHeader; + } + + return webAuthnOrigin; +} + +function resolveWebAuthnUserVerification( + value: string | undefined, +): 'discouraged' | 'preferred' | 'required' { + switch (value?.toLowerCase()) { + case 'discouraged': + return 'discouraged'; + case 'required': + return 'required'; + default: + return 'preferred'; + } +} + +function bytesToBase64Url(value: Uint8Array): string { + return Buffer.from(value).toString('base64url'); +} + +function defaultAccessKeyLabel(): string { + return `Access key ${new Date().toISOString().replace('T', ' ').slice(0, 16)}`; +} diff --git a/server/tsconfig.json b/server/tsconfig.json new file mode 100644 index 0000000..f243d2e --- /dev/null +++ b/server/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "rootDir": "src", + "outDir": "dist", + "strict": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["src/**/*.ts"] +}