From 4f483154490af7879d27384748c5bb3630ae171d Mon Sep 17 00:00:00 2001 From: ebluffy <107033550+ebluffy@users.noreply.github.com> Date: Tue, 15 Sep 2026 18:52:52 +0300 Subject: [PATCH 01/70] chore: switch workspace to Modrinth fork as Owyx launcher Keep previous private monorepo under legacy/ (Launcher, owyxsite, plugin). Rebrand Tauri product name/scheme to Owyx and strip trademark logo assets. Document upstream sync and OwyxOld archive remote. Co-authored-by: Cursor --- .gitignore | 9 + .idea/icon.svg | 4 - AGENTS.md | 100 +- README.md | 52 +- .../assets/instance-icons/wrench-rinth.png | Bin 72130 -> 0 bytes .../icons/apple.icon/Assets/Modrinth logo.svg | 19 - apps/app/tauri.conf.json | 10 +- .../.cursor-old/rules/agent-tool-catalog.mdc | 56 + .../.cursor-old/rules/cloud-agent-prompts.mdc | 50 + legacy/AGENTS.monorepo.md | 82 + legacy/DESIGN.md | 194 + .../.cursor/rules/browser-ui-testing.mdc | 12 + .../.cursor/rules/modrinth-reference.mdc | 14 + legacy/Launcher/.env.example | 9 + legacy/Launcher/.gitattributes | 63 + legacy/Launcher/.gitignore | 55 + legacy/Launcher/AGENTS.md | 12 + legacy/Launcher/BUILD.md | 324 + legacy/Launcher/LICENSE.txt | 21 + legacy/Launcher/PLAN.md | 5 + legacy/Launcher/README.md | 108 + legacy/Launcher/RELEASE_NOTES_v0.1.0.md | 59 + legacy/Launcher/apps/launcher/README.md | 44 + .../apps/launcher/docs/MICROSOFT_AUTH.md | 44 + .../launcher/docs/MODRINTH_PARITY_SPEC.md | 107 + legacy/Launcher/apps/launcher/index.html | 12 + .../Launcher/apps/launcher/package-lock.json | 1370 ++++ legacy/Launcher/apps/launcher/package.json | 28 + .../launcher/src-tauri/.cargo/config.toml | 2 + .../apps/launcher/src-tauri/Cargo.lock | 5444 +++++++++++++ .../apps/launcher/src-tauri/Cargo.toml | 36 + .../apps/launcher/src-tauri/assets/steve.png | Bin 0 -> 1311 bytes .../Launcher/apps/launcher/src-tauri/build.rs | 3 + .../src-tauri/capabilities/default.json | 22 + .../launcher/src-tauri/fixtures/v1/packs.json | 13 + .../v1/packs/demo-friends/manifest.json | 18 + .../apps/launcher/src-tauri/icons/128x128.png | Bin 0 -> 3604 bytes .../launcher/src-tauri/icons/128x128@2x.png | Bin 0 -> 6501 bytes .../apps/launcher/src-tauri/icons/32x32.png | Bin 0 -> 1011 bytes .../apps/launcher/src-tauri/icons/64x64.png | Bin 0 -> 1880 bytes .../src-tauri/icons/Square107x107Logo.png | Bin 0 -> 3016 bytes .../src-tauri/icons/Square142x142Logo.png | Bin 0 -> 4130 bytes .../src-tauri/icons/Square150x150Logo.png | Bin 0 -> 4243 bytes .../src-tauri/icons/Square284x284Logo.png | Bin 0 -> 8050 bytes .../src-tauri/icons/Square30x30Logo.png | Bin 0 -> 906 bytes .../src-tauri/icons/Square310x310Logo.png | Bin 0 -> 8876 bytes .../src-tauri/icons/Square44x44Logo.png | Bin 0 -> 1373 bytes .../src-tauri/icons/Square71x71Logo.png | Bin 0 -> 2086 bytes .../src-tauri/icons/Square89x89Logo.png | Bin 0 -> 2586 bytes .../launcher/src-tauri/icons/StoreLogo.png | Bin 0 -> 1487 bytes .../android/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../icons/android/mipmap-hdpi/ic_launcher.png | Bin 0 -> 1451 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 0 -> 4615 bytes .../android/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 1628 bytes .../icons/android/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1399 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 0 -> 2972 bytes .../android/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 1579 bytes .../android/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 2713 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 0 -> 5900 bytes .../mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 3215 bytes .../android/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 4010 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 0 -> 9200 bytes .../mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 4858 bytes .../android/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 5543 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 0 -> 13164 bytes .../mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 6400 bytes .../android/values/ic_launcher_background.xml | 4 + .../apps/launcher/src-tauri/icons/icon.icns | Bin 0 -> 58619 bytes .../apps/launcher/src-tauri/icons/icon.ico | Bin 0 -> 13052 bytes .../apps/launcher/src-tauri/icons/icon.png | Bin 0 -> 2566 bytes .../src-tauri/icons/ios/AppIcon-20x20@1x.png | Bin 0 -> 672 bytes .../icons/ios/AppIcon-20x20@2x-1.png | Bin 0 -> 1239 bytes .../src-tauri/icons/ios/AppIcon-20x20@2x.png | Bin 0 -> 1239 bytes .../src-tauri/icons/ios/AppIcon-20x20@3x.png | Bin 0 -> 1747 bytes .../src-tauri/icons/ios/AppIcon-29x29@1x.png | Bin 0 -> 875 bytes .../icons/ios/AppIcon-29x29@2x-1.png | Bin 0 -> 1712 bytes .../src-tauri/icons/ios/AppIcon-29x29@2x.png | Bin 0 -> 1712 bytes .../src-tauri/icons/ios/AppIcon-29x29@3x.png | Bin 0 -> 2599 bytes .../src-tauri/icons/ios/AppIcon-40x40@1x.png | Bin 0 -> 1239 bytes .../icons/ios/AppIcon-40x40@2x-1.png | Bin 0 -> 2280 bytes .../src-tauri/icons/ios/AppIcon-40x40@2x.png | Bin 0 -> 2280 bytes .../src-tauri/icons/ios/AppIcon-40x40@3x.png | Bin 0 -> 3396 bytes .../src-tauri/icons/ios/AppIcon-512@2x.png | Bin 0 -> 30737 bytes .../src-tauri/icons/ios/AppIcon-60x60@2x.png | Bin 0 -> 3396 bytes .../src-tauri/icons/ios/AppIcon-60x60@3x.png | Bin 0 -> 5006 bytes .../src-tauri/icons/ios/AppIcon-76x76@1x.png | Bin 0 -> 2199 bytes .../src-tauri/icons/ios/AppIcon-76x76@2x.png | Bin 0 -> 4282 bytes .../icons/ios/AppIcon-83.5x83.5@2x.png | Bin 0 -> 4611 bytes .../apps/launcher/src-tauri/src/api.rs | 192 + .../apps/launcher/src-tauri/src/catalog.rs | 1100 +++ .../apps/launcher/src-tauri/src/config.rs | 349 + .../apps/launcher/src-tauri/src/install.rs | 2120 ++++++ .../apps/launcher/src-tauri/src/instances.rs | 1651 ++++ .../apps/launcher/src-tauri/src/java.rs | 475 ++ .../apps/launcher/src-tauri/src/launch.rs | 1163 +++ .../apps/launcher/src-tauri/src/lib.rs | 688 ++ .../apps/launcher/src-tauri/src/log.rs | 152 + .../apps/launcher/src-tauri/src/main.rs | 6 + .../apps/launcher/src-tauri/src/models.rs | 83 + .../apps/launcher/src-tauri/src/modrinth.rs | 917 +++ .../apps/launcher/src-tauri/src/mrpack.rs | 583 ++ .../apps/launcher/src-tauri/src/ms_auth.rs | 628 ++ .../apps/launcher/src-tauri/src/owyx.rs | 406 + .../apps/launcher/src-tauri/src/profiles.rs | 182 + .../apps/launcher/src-tauri/src/skins.rs | 474 ++ .../apps/launcher/src-tauri/src/sync.rs | 299 + .../apps/launcher/src-tauri/src/versions.rs | 314 + .../apps/launcher/src-tauri/tauri.conf.json | 41 + .../Launcher/apps/launcher/src/browse-page.ts | 891 +++ legacy/Launcher/apps/launcher/src/catalog.ts | 142 + legacy/Launcher/apps/launcher/src/friends.ts | 7 + legacy/Launcher/apps/launcher/src/i18n.ts | 35 + .../Launcher/apps/launcher/src/i18n/en.json | 539 ++ .../Launcher/apps/launcher/src/i18n/ru.json | 539 ++ legacy/Launcher/apps/launcher/src/main.ts | 5397 +++++++++++++ legacy/Launcher/apps/launcher/src/ms-auth.ts | 60 + .../Launcher/apps/launcher/src/owyx-auth.ts | 241 + .../Launcher/apps/launcher/src/particles.ts | 71 + .../Launcher/apps/launcher/src/playing-as.ts | 185 + .../Launcher/apps/launcher/src/skins-page.ts | 237 + legacy/Launcher/apps/launcher/src/styles.css | 2494 ++++++ .../apps/launcher/src/version-combobox.ts | 332 + .../Launcher/apps/launcher/src/vite-env.d.ts | 1 + legacy/Launcher/apps/launcher/tsconfig.json | 20 + legacy/Launcher/apps/launcher/vite.config.ts | 59 + legacy/Launcher/docs/minecraft-meta.md | 40 + legacy/Launcher/docs/modrinth-reference.md | 19 + legacy/Launcher/docs/update-api-v1.md | 25 + legacy/Launcher/legacy/README.md | 10 + .../Launcher/legacy/csharp/ConfigManager.cs | 214 + .../Launcher/legacy/csharp/CustomTitleBar.cs | 155 + .../legacy/csharp/DiscordRPCManager.cs | 220 + .../Launcher/legacy/csharp/FabricInstaller.cs | 278 + legacy/Launcher/legacy/csharp/GameUpdater.cs | 179 + legacy/Launcher/legacy/csharp/JavaDetector.cs | 263 + legacy/Launcher/legacy/csharp/Logger.cs | 180 + legacy/Launcher/legacy/csharp/MainForm.cs | 371 + .../legacy/csharp/MinecraftStarter.cs | 205 + .../Launcher/legacy/csharp/ModDownloader.cs | 261 + .../legacy/csharp/Models/GameProfile.cs | 24 + .../legacy/csharp/Models/ServerInfo.cs | 44 + legacy/Launcher/legacy/csharp/Program.cs | 20 + .../legacy/csharp/ServerStatusChecker.cs | 256 + .../Launcher/legacy/csharp/SettingsPanel.cs | 723 ++ legacy/Launcher/package-lock.json | 1496 ++++ legacy/Launcher/package.json | 5 + legacy/Launcher/scripts/README.md | 20 + legacy/Launcher/scripts/linux-dev-setup.sh | 140 + .../code.html | 138 + .../screen.png | Bin 0 -> 136824 bytes .../Launcher/stitch_owyx_launcher/design.md | 297 + .../home_official_canon_v1/code.html | 323 + .../home_official_canon_v1/screen.png | Bin 0 -> 158277 bytes .../instance_detail_actions_menu/code.html | 320 + .../instance_detail_actions_menu/screen.png | Bin 0 -> 135535 bytes .../instance_detail_content_tab/code.html | 358 + .../instance_detail_content_tab/screen.png | Bin 0 -> 179911 bytes .../instance_detail_files_tab/code.html | 321 + .../instance_detail_files_tab/screen.png | Bin 0 -> 180776 bytes .../instance_detail_logs_tab/code.html | 325 + .../instance_detail_logs_tab/screen.png | Bin 0 -> 243656 bytes .../instance_detail_share_tab/code.html | 306 + .../instance_detail_share_tab/screen.png | Bin 0 -> 208867 bytes .../instance_detail_worlds_tab/code.html | 327 + .../instance_detail_worlds_tab/screen.png | Bin 0 -> 157258 bytes .../instance_settings_java_memory/code.html | 358 + .../instance_settings_java_memory/screen.png | Bin 0 -> 155962 bytes .../instance_settings_modal_view/code.html | 292 + .../instance_settings_modal_view/screen.png | Bin 0 -> 152737 bytes .../code.html | 292 + .../screen.png | Bin 0 -> 129772 bytes .../library_empty_state_official/code.html | 192 + .../library_empty_state_official/screen.png | Bin 0 -> 170444 bytes .../library_official_brand_fix/code.html | 375 + .../library_official_brand_fix/screen.png | Bin 0 -> 132391 bytes .../new_instance_rebranded_rail_fix/code.html | 408 + .../screen.png | Bin 0 -> 113907 bytes .../owyx_official/DESIGN.md | 194 + .../private_servers_coming_soon/code.html | 173 + .../private_servers_coming_soon/screen.png | Bin 0 -> 120095 bytes legacy/PLAN.md | 354 + legacy/README.md | 16 + legacy/owyxplugin/.gitignore | 38 + legacy/owyxplugin/.gitkeep | 1 + legacy/owyxplugin/.idea/.gitignore | 10 + legacy/owyxplugin/.idea/encodings.xml | 7 + legacy/owyxplugin/.idea/misc.xml | 14 + legacy/owyxplugin/FIX_PLUGIN_YML.md | 164 + legacy/owyxplugin/MINECRAFT_PLUGIN_PROMPT.md | 430 ++ legacy/owyxplugin/PLAN.md | 3 + legacy/owyxplugin/dependency-reduced-pom.xml | 121 + legacy/owyxplugin/pom.xml | 191 + .../org/ebluffy/chiwawa/ChiwawaPlugin.java | 297 + .../org/ebluffy/chiwawa/api/ApiClient.java | 740 ++ .../ebluffy/chiwawa/api/dto/ApiResponse.java | 82 + .../ebluffy/chiwawa/api/dto/Application.java | 112 + .../ebluffy/chiwawa/api/dto/AuthPlayer.java | 156 + .../ebluffy/chiwawa/api/dto/ChiwawaUser.java | 220 + .../ebluffy/chiwawa/api/dto/PlayerStats.java | 129 + .../chiwawa/api/dto/SessionCheckResult.java | 46 + .../api/dto/TokenVerificationResult.java | 58 + .../ebluffy/chiwawa/api/dto/UserActivity.java | 86 + .../chiwawa/api/dto/WhitelistResponse.java | 49 + .../chiwawa/commands/ApplicationsCommand.java | 44 + .../chiwawa/commands/ChangeLoginCommand.java | 237 + .../commands/ChangePasswordCommand.java | 155 + .../chiwawa/commands/ChiwawaCommand.java | 609 ++ .../chiwawa/commands/DiscordCommand.java | 43 + .../chiwawa/commands/LoginCommand.java | 230 + .../chiwawa/commands/PlaytimeCommand.java | 70 + .../chiwawa/commands/ProfileCommand.java | 84 + .../chiwawa/commands/RegisterCommand.java | 103 + .../chiwawa/commands/ReputationCommand.java | 102 + .../chiwawa/commands/UnregisterCommand.java | 140 + .../ebluffy/chiwawa/config/ConfigManager.java | 146 + .../chiwawa/database/DatabaseManager.java | 566 ++ .../listeners/AuthenticationListener.java | 309 + .../chiwawa/listeners/PlayerListener.java | 280 + .../ebluffy/chiwawa/managers/AuthManager.java | 479 ++ .../chiwawa/managers/PlayerStatsManager.java | 361 + .../chiwawa/managers/PlaytimeManager.java | 317 + .../chiwawa/managers/ReputationManager.java | 296 + .../chiwawa/managers/ServerStatsManager.java | 174 + .../chiwawa/managers/StatsManager.java | 301 + .../ebluffy/chiwawa/managers/UserManager.java | 337 + .../chiwawa/utils/ApiRequestExamples.java | 227 + .../ebluffy/chiwawa/utils/SecurityUtils.java | 314 + .../owyxplugin/src/main/resources/config.yml | 129 + .../owyxplugin/src/main/resources/plugin.yml | 206 + legacy/owyxsite/.env.example | 101 + legacy/owyxsite/.gitignore | 50 + legacy/owyxsite/.gitkeep | 1 + legacy/owyxsite/LAUNCHER_SITE_CONTRACT.md | 333 + legacy/owyxsite/PLAN.md | 5 + legacy/owyxsite/PREVIEW.html | 53 + legacy/owyxsite/README.md | 123 + legacy/owyxsite/aliases.sh | 81 + legacy/owyxsite/backend/.dockerignore | 9 + legacy/owyxsite/backend/.gitignore | 7 + legacy/owyxsite/backend/Dockerfile | 39 + legacy/owyxsite/backend/README.md | 38 + .../owyxsite/backend/fixtures/packs/README.md | 10 + .../fixtures/packs/demo-vanilla.sha256 | 1 + .../backend/fixtures/packs/demo-vanilla.zip | Bin 0 -> 363 bytes legacy/owyxsite/backend/package-lock.json | 2958 +++++++ legacy/owyxsite/backend/package.json | 50 + .../backend/scripts/preview-emails.js | 43 + .../owyxsite/backend/src/config/settings.js | 84 + .../backend/src/database/connection.js | 85 + .../backend/src/middleware/clientKey.js | 63 + legacy/owyxsite/backend/src/routes/admin.js | 3048 ++++++++ .../backend/src/routes/applications.js | 673 ++ legacy/owyxsite/backend/src/routes/auth.js | 1403 ++++ legacy/owyxsite/backend/src/routes/catalog.js | 839 ++ legacy/owyxsite/backend/src/routes/chat.js | 130 + legacy/owyxsite/backend/src/routes/forum.js | 235 + .../owyxsite/backend/src/routes/launcher.js | 200 + legacy/owyxsite/backend/src/routes/news.js | 117 + legacy/owyxsite/backend/src/routes/profile.js | 1175 +++ .../owyxsite/backend/src/routes/reputation.js | 213 + .../owyxsite/backend/src/routes/settings.js | 610 ++ .../backend/src/routes/trust-level.js | 342 + legacy/owyxsite/backend/src/server.ts | 271 + legacy/owyxsite/backend/src/socket/index.ts | 184 + .../backend/src/utils/authSecurity.js | 57 + .../backend/src/utils/emailService.js | 202 + .../backend/src/utils/emailTemplates.js | 162 + .../owyxsite/backend/src/utils/turnstile.js | 72 + legacy/owyxsite/backend/tsconfig.json | 21 + legacy/owyxsite/backend/uploads/.gitkeep | 0 legacy/owyxsite/backup.sh | 83 + legacy/owyxsite/deploy/OBT_PREP.md | 68 + legacy/owyxsite/deploy/README.md | 48 + legacy/owyxsite/deploy/bootstrap-vps.sh | 46 + legacy/owyxsite/deploy/nginx-owyx.site.conf | 145 + legacy/owyxsite/deploy/vps-up.sh | 311 + legacy/owyxsite/directus/README.md | 48 + legacy/owyxsite/directus/extensions/.gitkeep | 0 legacy/owyxsite/docker-compose.prod.yml | 28 + legacy/owyxsite/docker-compose.yml | 183 + legacy/owyxsite/frontend/.dockerignore | 40 + legacy/owyxsite/frontend/.gitignore | 41 + legacy/owyxsite/frontend/AGENTS.md | 9 + legacy/owyxsite/frontend/CLAUDE.md | 1 + legacy/owyxsite/frontend/Dockerfile | 70 + legacy/owyxsite/frontend/README.md | 36 + legacy/owyxsite/frontend/app/admin/page.tsx | 351 + legacy/owyxsite/frontend/app/chat/page.tsx | 12 + .../owyxsite/frontend/app/download/page.tsx | 75 + legacy/owyxsite/frontend/app/favicon.ico | Bin 0 -> 25931 bytes .../frontend/app/forgot-password/page.tsx | 70 + .../frontend/app/forum/[slug]/page.tsx | 10 + legacy/owyxsite/frontend/app/forum/page.tsx | 12 + .../frontend/app/forum/topic/[id]/page.tsx | 10 + legacy/owyxsite/frontend/app/globals.css | 325 + legacy/owyxsite/frontend/app/layout.tsx | 59 + .../frontend/app/legal/[slug]/page.tsx | 99 + legacy/owyxsite/frontend/app/login/page.tsx | 117 + legacy/owyxsite/frontend/app/online/page.tsx | 12 + legacy/owyxsite/frontend/app/page.tsx | 35 + legacy/owyxsite/frontend/app/profile/page.tsx | 482 ++ .../owyxsite/frontend/app/register/page.tsx | 154 + .../frontend/app/reset-password/page.tsx | 130 + legacy/owyxsite/frontend/app/servers/page.tsx | 69 + legacy/owyxsite/frontend/app/shop/page.tsx | 12 + legacy/owyxsite/frontend/app/tokens/page.tsx | 12 + legacy/owyxsite/frontend/app/verify/page.tsx | 58 + .../components/admin/CatalogAdmin.tsx | 482 ++ .../frontend/components/layout/AuthShell.tsx | 33 + .../frontend/components/layout/ComingSoon.tsx | 30 + .../frontend/components/layout/Footer.tsx | 37 + .../frontend/components/layout/Header.tsx | 196 + .../components/profile/SkinPreview.tsx | 94 + .../components/profile/SkinViewer.tsx | 94 + .../components/sections/HeroSection.tsx | 81 + .../components/sections/NewsSection.tsx | 101 + .../components/server/CopyIPButton.tsx | 47 + .../components/server/ServerConnectCard.tsx | 60 + .../components/server/ServerStatus.tsx | 80 + .../owyxsite/frontend/components/ui/Logo.tsx | 52 + .../frontend/components/ui/Turnstile.tsx | 54 + legacy/owyxsite/frontend/eslint.config.mjs | 18 + legacy/owyxsite/frontend/hooks/useAuth.tsx | 180 + legacy/owyxsite/frontend/next.config.ts | 86 + legacy/owyxsite/frontend/package-lock.json | 6782 +++++++++++++++++ legacy/owyxsite/frontend/package.json | 30 + legacy/owyxsite/frontend/postcss.config.mjs | 7 + legacy/owyxsite/frontend/public/file.svg | 1 + legacy/owyxsite/frontend/public/globe.svg | 1 + .../frontend/public/images/default-avatar.png | Bin 0 -> 58 bytes .../frontend/public/images/left-skin.png | Bin 0 -> 27484 bytes .../frontend/public/images/right-skin.png | Bin 0 -> 38514 bytes legacy/owyxsite/frontend/public/next.svg | 1 + .../frontend/public/skins/default.png | Bin 0 -> 1264 bytes legacy/owyxsite/frontend/public/vercel.svg | 1 + legacy/owyxsite/frontend/public/window.svg | 1 + legacy/owyxsite/frontend/tsconfig.json | 34 + legacy/owyxsite/frpc-conf/frpc.service | 46 + legacy/owyxsite/frpc-conf/frpc.toml | 158 + legacy/owyxsite/frpc-conf/frpc.toml.example | 55 + legacy/owyxsite/nginx-conf/owyx.conf | 339 + legacy/owyxsite/old.backup/README.md | 38 + .../old.backup/frontend-app/admin/page.tsx | 791 ++ .../old.backup/frontend-app/chat/page.tsx | 225 + .../frontend-app/forgot-password/page.tsx | 171 + .../frontend-app/forum/[slug]/page.tsx | 91 + .../old.backup/frontend-app/forum/page.tsx | 91 + .../frontend-app/forum/topic/[id]/page.tsx | 127 + .../old.backup/frontend-app/globals.css | 169 + .../old.backup/frontend-app/layout.tsx | 36 + .../old.backup/frontend-app/login/page.tsx | 232 + .../old.backup/frontend-app/online/page.tsx | 315 + .../owyxsite/old.backup/frontend-app/page.tsx | 26 + .../old.backup/frontend-app/profile/page.tsx | 947 +++ .../old.backup/frontend-app/register/page.tsx | 334 + .../frontend-app/reset-password/page.tsx | 301 + .../old.backup/frontend-app/shop/page.tsx | 64 + .../old.backup/frontend-app/tokens/page.tsx | 310 + .../old.backup/frontend-app/verify/page.tsx | 152 + .../effects/ParticlesBackground.tsx | 38 + .../frontend-components/layout/Footer.tsx | 63 + .../frontend-components/layout/Header.tsx | 253 + .../sections/DiscordSection.tsx | 123 + .../sections/HeroSection.tsx | 66 + .../server/CopyIPButton.tsx | 80 + .../server/ServerStatus.tsx | 67 + legacy/owyxsite/postgres/init.full.sql | 4256 +++++++++++ legacy/owyxsite/postgres/init.sql | 3047 ++++++++ .../migrations/000_bootstrap_roles.sql | 11 + .../owyxsite/postgres/migrations/001_chat.sql | 39 + .../postgres/migrations/002_roles.sql | 34 + .../postgres/migrations/003_cosmetics.sql | 26 + .../migrations/004_nickname_cooldown.sql | 5 + .../postgres/migrations/005_email_change.sql | 9 + .../owyxsite/postgres/migrations/006_news.sql | 24 + .../postgres/migrations/007_servers_packs.sql | 69 + legacy/owyxsite/restore.sh | 121 + legacy/owyxsite/setup.sh | 197 + packages/assets/branding/modrinth-plus.svg | 11 - packages/assets/icons/wrench.svg | 1 - 380 files changed, 90547 insertions(+), 156 deletions(-) delete mode 100644 .idea/icon.svg delete mode 100755 apps/app-frontend/src/assets/instance-icons/wrench-rinth.png delete mode 100644 apps/app/icons/apple.icon/Assets/Modrinth logo.svg create mode 100644 legacy/.cursor-old/rules/agent-tool-catalog.mdc create mode 100644 legacy/.cursor-old/rules/cloud-agent-prompts.mdc create mode 100644 legacy/AGENTS.monorepo.md create mode 100644 legacy/DESIGN.md create mode 100644 legacy/Launcher/.cursor/rules/browser-ui-testing.mdc create mode 100644 legacy/Launcher/.cursor/rules/modrinth-reference.mdc create mode 100644 legacy/Launcher/.env.example create mode 100644 legacy/Launcher/.gitattributes create mode 100644 legacy/Launcher/.gitignore create mode 100644 legacy/Launcher/AGENTS.md create mode 100644 legacy/Launcher/BUILD.md create mode 100644 legacy/Launcher/LICENSE.txt create mode 100644 legacy/Launcher/PLAN.md create mode 100644 legacy/Launcher/README.md create mode 100644 legacy/Launcher/RELEASE_NOTES_v0.1.0.md create mode 100644 legacy/Launcher/apps/launcher/README.md create mode 100644 legacy/Launcher/apps/launcher/docs/MICROSOFT_AUTH.md create mode 100644 legacy/Launcher/apps/launcher/docs/MODRINTH_PARITY_SPEC.md create mode 100644 legacy/Launcher/apps/launcher/index.html create mode 100644 legacy/Launcher/apps/launcher/package-lock.json create mode 100644 legacy/Launcher/apps/launcher/package.json create mode 100644 legacy/Launcher/apps/launcher/src-tauri/.cargo/config.toml create mode 100644 legacy/Launcher/apps/launcher/src-tauri/Cargo.lock create mode 100644 legacy/Launcher/apps/launcher/src-tauri/Cargo.toml create mode 100644 legacy/Launcher/apps/launcher/src-tauri/assets/steve.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/build.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/capabilities/default.json create mode 100644 legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs.json create mode 100644 legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs/demo-friends/manifest.json create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/128x128.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/128x128@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/32x32.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/64x64.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square107x107Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square142x142Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square150x150Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square284x284Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square30x30Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square310x310Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square44x44Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square71x71Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/Square89x89Logo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/StoreLogo.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/android/values/ic_launcher_background.xml create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/icon.icns create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/icon.ico create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/icon.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@1x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@2x-1.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@3x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@1x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@2x-1.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@3x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-40x40@1x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-40x40@2x-1.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-40x40@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-40x40@3x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-512@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@3x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-76x76@1x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-76x76@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/api.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/catalog.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/config.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/install.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/instances.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/java.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/launch.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/lib.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/log.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/main.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/models.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/modrinth.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/mrpack.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/ms_auth.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/owyx.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/profiles.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/skins.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/sync.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/src/versions.rs create mode 100644 legacy/Launcher/apps/launcher/src-tauri/tauri.conf.json create mode 100644 legacy/Launcher/apps/launcher/src/browse-page.ts create mode 100644 legacy/Launcher/apps/launcher/src/catalog.ts create mode 100644 legacy/Launcher/apps/launcher/src/friends.ts create mode 100644 legacy/Launcher/apps/launcher/src/i18n.ts create mode 100644 legacy/Launcher/apps/launcher/src/i18n/en.json create mode 100644 legacy/Launcher/apps/launcher/src/i18n/ru.json create mode 100644 legacy/Launcher/apps/launcher/src/main.ts create mode 100644 legacy/Launcher/apps/launcher/src/ms-auth.ts create mode 100644 legacy/Launcher/apps/launcher/src/owyx-auth.ts create mode 100644 legacy/Launcher/apps/launcher/src/particles.ts create mode 100644 legacy/Launcher/apps/launcher/src/playing-as.ts create mode 100644 legacy/Launcher/apps/launcher/src/skins-page.ts create mode 100644 legacy/Launcher/apps/launcher/src/styles.css create mode 100644 legacy/Launcher/apps/launcher/src/version-combobox.ts create mode 100644 legacy/Launcher/apps/launcher/src/vite-env.d.ts create mode 100644 legacy/Launcher/apps/launcher/tsconfig.json create mode 100644 legacy/Launcher/apps/launcher/vite.config.ts create mode 100644 legacy/Launcher/docs/minecraft-meta.md create mode 100644 legacy/Launcher/docs/modrinth-reference.md create mode 100644 legacy/Launcher/docs/update-api-v1.md create mode 100644 legacy/Launcher/legacy/README.md create mode 100644 legacy/Launcher/legacy/csharp/ConfigManager.cs create mode 100644 legacy/Launcher/legacy/csharp/CustomTitleBar.cs create mode 100644 legacy/Launcher/legacy/csharp/DiscordRPCManager.cs create mode 100644 legacy/Launcher/legacy/csharp/FabricInstaller.cs create mode 100644 legacy/Launcher/legacy/csharp/GameUpdater.cs create mode 100644 legacy/Launcher/legacy/csharp/JavaDetector.cs create mode 100644 legacy/Launcher/legacy/csharp/Logger.cs create mode 100644 legacy/Launcher/legacy/csharp/MainForm.cs create mode 100644 legacy/Launcher/legacy/csharp/MinecraftStarter.cs create mode 100644 legacy/Launcher/legacy/csharp/ModDownloader.cs create mode 100644 legacy/Launcher/legacy/csharp/Models/GameProfile.cs create mode 100644 legacy/Launcher/legacy/csharp/Models/ServerInfo.cs create mode 100644 legacy/Launcher/legacy/csharp/Program.cs create mode 100644 legacy/Launcher/legacy/csharp/ServerStatusChecker.cs create mode 100644 legacy/Launcher/legacy/csharp/SettingsPanel.cs create mode 100644 legacy/Launcher/package-lock.json create mode 100644 legacy/Launcher/package.json create mode 100644 legacy/Launcher/scripts/README.md create mode 100644 legacy/Launcher/scripts/linux-dev-setup.sh create mode 100644 legacy/Launcher/stitch_owyx_launcher/delete_instance_confirmation_modal/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/delete_instance_confirmation_modal/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/design.md create mode 100644 legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_content_tab/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_content_tab/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_worlds_tab/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_detail_worlds_tab/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_settings_java_memory/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_settings_java_memory/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_settings_modal_view/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/instance_settings_modal_view/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/launcher_settings_java_installations/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/launcher_settings_java_installations/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/library_official_brand_fix/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/library_official_brand_fix/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/screen.png create mode 100644 legacy/Launcher/stitch_owyx_launcher/owyx_official/DESIGN.md create mode 100644 legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/code.html create mode 100644 legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/screen.png create mode 100644 legacy/PLAN.md create mode 100644 legacy/README.md create mode 100644 legacy/owyxplugin/.gitignore create mode 100644 legacy/owyxplugin/.gitkeep create mode 100644 legacy/owyxplugin/.idea/.gitignore create mode 100644 legacy/owyxplugin/.idea/encodings.xml create mode 100644 legacy/owyxplugin/.idea/misc.xml create mode 100644 legacy/owyxplugin/FIX_PLUGIN_YML.md create mode 100644 legacy/owyxplugin/MINECRAFT_PLUGIN_PROMPT.md create mode 100644 legacy/owyxplugin/PLAN.md create mode 100644 legacy/owyxplugin/dependency-reduced-pom.xml create mode 100644 legacy/owyxplugin/pom.xml create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/ChiwawaPlugin.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/ApiClient.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ApiResponse.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/Application.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/AuthPlayer.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ChiwawaUser.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/PlayerStats.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/SessionCheckResult.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/TokenVerificationResult.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/UserActivity.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/WhitelistResponse.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ApplicationsCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangeLoginCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangePasswordCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChiwawaCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/DiscordCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/LoginCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/PlaytimeCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ProfileCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/RegisterCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ReputationCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/UnregisterCommand.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/config/ConfigManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/database/DatabaseManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/AuthenticationListener.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/PlayerListener.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/AuthManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlayerStatsManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlaytimeManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ReputationManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ServerStatsManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/StatsManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/UserManager.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/ApiRequestExamples.java create mode 100644 legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/SecurityUtils.java create mode 100644 legacy/owyxplugin/src/main/resources/config.yml create mode 100644 legacy/owyxplugin/src/main/resources/plugin.yml create mode 100644 legacy/owyxsite/.env.example create mode 100644 legacy/owyxsite/.gitignore create mode 100644 legacy/owyxsite/.gitkeep create mode 100644 legacy/owyxsite/LAUNCHER_SITE_CONTRACT.md create mode 100644 legacy/owyxsite/PLAN.md create mode 100644 legacy/owyxsite/PREVIEW.html create mode 100644 legacy/owyxsite/README.md create mode 100644 legacy/owyxsite/aliases.sh create mode 100644 legacy/owyxsite/backend/.dockerignore create mode 100644 legacy/owyxsite/backend/.gitignore create mode 100644 legacy/owyxsite/backend/Dockerfile create mode 100644 legacy/owyxsite/backend/README.md create mode 100644 legacy/owyxsite/backend/fixtures/packs/README.md create mode 100644 legacy/owyxsite/backend/fixtures/packs/demo-vanilla.sha256 create mode 100644 legacy/owyxsite/backend/fixtures/packs/demo-vanilla.zip create mode 100644 legacy/owyxsite/backend/package-lock.json create mode 100644 legacy/owyxsite/backend/package.json create mode 100644 legacy/owyxsite/backend/scripts/preview-emails.js create mode 100644 legacy/owyxsite/backend/src/config/settings.js create mode 100644 legacy/owyxsite/backend/src/database/connection.js create mode 100644 legacy/owyxsite/backend/src/middleware/clientKey.js create mode 100644 legacy/owyxsite/backend/src/routes/admin.js create mode 100644 legacy/owyxsite/backend/src/routes/applications.js create mode 100644 legacy/owyxsite/backend/src/routes/auth.js create mode 100644 legacy/owyxsite/backend/src/routes/catalog.js create mode 100644 legacy/owyxsite/backend/src/routes/chat.js create mode 100644 legacy/owyxsite/backend/src/routes/forum.js create mode 100644 legacy/owyxsite/backend/src/routes/launcher.js create mode 100644 legacy/owyxsite/backend/src/routes/news.js create mode 100644 legacy/owyxsite/backend/src/routes/profile.js create mode 100644 legacy/owyxsite/backend/src/routes/reputation.js create mode 100644 legacy/owyxsite/backend/src/routes/settings.js create mode 100644 legacy/owyxsite/backend/src/routes/trust-level.js create mode 100644 legacy/owyxsite/backend/src/server.ts create mode 100644 legacy/owyxsite/backend/src/socket/index.ts create mode 100644 legacy/owyxsite/backend/src/utils/authSecurity.js create mode 100644 legacy/owyxsite/backend/src/utils/emailService.js create mode 100644 legacy/owyxsite/backend/src/utils/emailTemplates.js create mode 100644 legacy/owyxsite/backend/src/utils/turnstile.js create mode 100644 legacy/owyxsite/backend/tsconfig.json create mode 100644 legacy/owyxsite/backend/uploads/.gitkeep create mode 100644 legacy/owyxsite/backup.sh create mode 100644 legacy/owyxsite/deploy/OBT_PREP.md create mode 100644 legacy/owyxsite/deploy/README.md create mode 100644 legacy/owyxsite/deploy/bootstrap-vps.sh create mode 100644 legacy/owyxsite/deploy/nginx-owyx.site.conf create mode 100644 legacy/owyxsite/deploy/vps-up.sh create mode 100644 legacy/owyxsite/directus/README.md create mode 100644 legacy/owyxsite/directus/extensions/.gitkeep create mode 100644 legacy/owyxsite/docker-compose.prod.yml create mode 100644 legacy/owyxsite/docker-compose.yml create mode 100644 legacy/owyxsite/frontend/.dockerignore create mode 100644 legacy/owyxsite/frontend/.gitignore create mode 100644 legacy/owyxsite/frontend/AGENTS.md create mode 100644 legacy/owyxsite/frontend/CLAUDE.md create mode 100644 legacy/owyxsite/frontend/Dockerfile create mode 100644 legacy/owyxsite/frontend/README.md create mode 100644 legacy/owyxsite/frontend/app/admin/page.tsx create mode 100644 legacy/owyxsite/frontend/app/chat/page.tsx create mode 100644 legacy/owyxsite/frontend/app/download/page.tsx create mode 100644 legacy/owyxsite/frontend/app/favicon.ico create mode 100644 legacy/owyxsite/frontend/app/forgot-password/page.tsx create mode 100644 legacy/owyxsite/frontend/app/forum/[slug]/page.tsx create mode 100644 legacy/owyxsite/frontend/app/forum/page.tsx create mode 100644 legacy/owyxsite/frontend/app/forum/topic/[id]/page.tsx create mode 100644 legacy/owyxsite/frontend/app/globals.css create mode 100644 legacy/owyxsite/frontend/app/layout.tsx create mode 100644 legacy/owyxsite/frontend/app/legal/[slug]/page.tsx create mode 100644 legacy/owyxsite/frontend/app/login/page.tsx create mode 100644 legacy/owyxsite/frontend/app/online/page.tsx create mode 100644 legacy/owyxsite/frontend/app/page.tsx create mode 100644 legacy/owyxsite/frontend/app/profile/page.tsx create mode 100644 legacy/owyxsite/frontend/app/register/page.tsx create mode 100644 legacy/owyxsite/frontend/app/reset-password/page.tsx create mode 100644 legacy/owyxsite/frontend/app/servers/page.tsx create mode 100644 legacy/owyxsite/frontend/app/shop/page.tsx create mode 100644 legacy/owyxsite/frontend/app/tokens/page.tsx create mode 100644 legacy/owyxsite/frontend/app/verify/page.tsx create mode 100644 legacy/owyxsite/frontend/components/admin/CatalogAdmin.tsx create mode 100644 legacy/owyxsite/frontend/components/layout/AuthShell.tsx create mode 100644 legacy/owyxsite/frontend/components/layout/ComingSoon.tsx create mode 100644 legacy/owyxsite/frontend/components/layout/Footer.tsx create mode 100644 legacy/owyxsite/frontend/components/layout/Header.tsx create mode 100644 legacy/owyxsite/frontend/components/profile/SkinPreview.tsx create mode 100644 legacy/owyxsite/frontend/components/profile/SkinViewer.tsx create mode 100644 legacy/owyxsite/frontend/components/sections/HeroSection.tsx create mode 100644 legacy/owyxsite/frontend/components/sections/NewsSection.tsx create mode 100644 legacy/owyxsite/frontend/components/server/CopyIPButton.tsx create mode 100644 legacy/owyxsite/frontend/components/server/ServerConnectCard.tsx create mode 100644 legacy/owyxsite/frontend/components/server/ServerStatus.tsx create mode 100644 legacy/owyxsite/frontend/components/ui/Logo.tsx create mode 100644 legacy/owyxsite/frontend/components/ui/Turnstile.tsx create mode 100644 legacy/owyxsite/frontend/eslint.config.mjs create mode 100644 legacy/owyxsite/frontend/hooks/useAuth.tsx create mode 100644 legacy/owyxsite/frontend/next.config.ts create mode 100644 legacy/owyxsite/frontend/package-lock.json create mode 100644 legacy/owyxsite/frontend/package.json create mode 100644 legacy/owyxsite/frontend/postcss.config.mjs create mode 100644 legacy/owyxsite/frontend/public/file.svg create mode 100644 legacy/owyxsite/frontend/public/globe.svg create mode 100644 legacy/owyxsite/frontend/public/images/default-avatar.png create mode 100644 legacy/owyxsite/frontend/public/images/left-skin.png create mode 100644 legacy/owyxsite/frontend/public/images/right-skin.png create mode 100644 legacy/owyxsite/frontend/public/next.svg create mode 100644 legacy/owyxsite/frontend/public/skins/default.png create mode 100644 legacy/owyxsite/frontend/public/vercel.svg create mode 100644 legacy/owyxsite/frontend/public/window.svg create mode 100644 legacy/owyxsite/frontend/tsconfig.json create mode 100644 legacy/owyxsite/frpc-conf/frpc.service create mode 100644 legacy/owyxsite/frpc-conf/frpc.toml create mode 100644 legacy/owyxsite/frpc-conf/frpc.toml.example create mode 100644 legacy/owyxsite/nginx-conf/owyx.conf create mode 100644 legacy/owyxsite/old.backup/README.md create mode 100644 legacy/owyxsite/old.backup/frontend-app/admin/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/chat/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/forgot-password/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/forum/[slug]/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/forum/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/forum/topic/[id]/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/globals.css create mode 100644 legacy/owyxsite/old.backup/frontend-app/layout.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/login/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/online/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/profile/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/register/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/reset-password/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/shop/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/tokens/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-app/verify/page.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/effects/ParticlesBackground.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/layout/Footer.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/layout/Header.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/sections/DiscordSection.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/sections/HeroSection.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/server/CopyIPButton.tsx create mode 100644 legacy/owyxsite/old.backup/frontend-components/server/ServerStatus.tsx create mode 100644 legacy/owyxsite/postgres/init.full.sql create mode 100644 legacy/owyxsite/postgres/init.sql create mode 100644 legacy/owyxsite/postgres/migrations/000_bootstrap_roles.sql create mode 100644 legacy/owyxsite/postgres/migrations/001_chat.sql create mode 100644 legacy/owyxsite/postgres/migrations/002_roles.sql create mode 100644 legacy/owyxsite/postgres/migrations/003_cosmetics.sql create mode 100644 legacy/owyxsite/postgres/migrations/004_nickname_cooldown.sql create mode 100644 legacy/owyxsite/postgres/migrations/005_email_change.sql create mode 100644 legacy/owyxsite/postgres/migrations/006_news.sql create mode 100644 legacy/owyxsite/postgres/migrations/007_servers_packs.sql create mode 100644 legacy/owyxsite/restore.sh create mode 100644 legacy/owyxsite/setup.sh delete mode 100644 packages/assets/branding/modrinth-plus.svg delete mode 100644 packages/assets/icons/wrench.svg diff --git a/.gitignore b/.gitignore index d442251099c..1152c370157 100644 --- a/.gitignore +++ b/.gitignore @@ -95,3 +95,12 @@ apps/frontend/src/public/robots.txt /test_result.md packages/tooling-config/script-utils/import-sort.js + +# Owyx legacy monorepo secrets / junk +legacy/**/.env +legacy/**/.env.* +!legacy/**/.env.example +legacy/**/node_modules/ +legacy/**/target/ +legacy/**/.next/ +legacy/Launcher/**/*.exe diff --git a/.idea/icon.svg b/.idea/icon.svg deleted file mode 100644 index 834085367eb..00000000000 --- a/.idea/icon.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/AGENTS.md b/AGENTS.md index 4e46b24039b..847ab6e10f1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,96 +1,10 @@ -# Modrinth Monorepo +# Agent notes — Owyx (Modrinth fork) -This is the Modrinth monorepo — it contains all Modrinth projects, both frontend and backend. When entering a project, either to edit or analyse, you should read its AGENTS.md. +Canonical product: **Owyx launcher** = this monorepo (`apps/app` + `apps/app-frontend` + `packages/app-lib`), rebranded. -## Architecture +- **Do not** restore Modrinth logos / cover images / green brand primary. +- **Do** keep following upstream `modrinth/code` for features/fixes. +- **legacy/** = old private stack (site `owyxsite`, old `Launcher`, `owyxplugin`). Control-plane API `api.owyx.site` wiring lands here later or in app config. +- Old git history: `ebluffy/OwyxOld`. -- **Monorepo tooling:** [Turborepo](https://turbo.build/) (`turbo.jsonc`) + [pnpm workspaces](https://pnpm.io/workspaces) (`pnpm-workspace.yaml`) -- **Frontend:** Vue 3 / Nuxt 3, Tailwind CSS v3 -- **Backend:** Rust (Labrinth API), Postgres, Clickhouse -- **Indentation:** Use TAB everywhere, never spaces - -### Apps (`apps/`) - -| App | Description | -| ----------------- | ------------------------------ | -| `frontend` | Main Modrinth website (Nuxt 3) | -| `app-frontend` | Desktop/app frontend (Vue 3) | -| `app` | Desktop/app shell (Tauri) | -| `app-playground` | Testing playground for app | -| `labrinth` | Backend API service | -| `daedalus_client` | Daedalus client implementation | -| `docs` | Documentation site (Astro) | - -### Packages (`packages/`) - -| Package | Description | -| ------------------ | ----------------------------------------------------- | -| `ui` | Shared Vue component library (`@modrinth/ui`) | -| `assets` | Styling and auto-generated icons (`@modrinth/assets`) | -| `api-client` | API client for Nuxt, Tauri, and Node/browser | -| `app-lib` | Shared app library | -| `blog` | Blog system and changelog data | -| `utils` | Shared utility functions (mostly deprecated) | -| `moderation` | Moderation utilities | -| `daedalus` | Daedalus protocol | -| `tooling-config` | ESLint, Prettier, TypeScript configs | -| `ariadne` | Analytics library | -| `modrinth-log` | Logging utilities | -| `modrinth-maxmind` | MaxMind GeoIP | -| `modrinth-util` | General utilities | -| `muralpay` | Payment processing | -| `path-util` | Path utilities | -| `sqlx-tracing` | SQLx query tracing | - -## Pre-PR Commands - -Run these from the **root** folder before opening a pull request - do not run these after each prompt the user gives you, only run when asked, ask the user a question if they want to run it if the user indicates that they are about to create a pull request. - -- **Website:** `pnpm prepr:frontend:web` -- **App frontend:** `pnpm prepr:frontend:app` -- **Frontend libs:** `pnpm prepr:frontend:lib` -- **All frontend (app+web):** `pnpm prepr` -- **Labrinth (backend):** See `apps/labrinth/AGENTS.md` - -The website and app `prepr` commands - -## Dev Commands - -- **Website:** `pnpm web:dev` (copy `.env` template in `apps/frontend/` first) -- **App:** `pnpm app:dev` (copy `.env` template in `packages/app-lib/` first) -- **Storybook (packages/ui):** `pnpm storybook` - -## Project-Specific Instructions - -Each project may have its own file with detailed instructions: - -- [`apps/labrinth/AGENTS.md`](apps/labrinth/AGENTS.md) — Backend API -- [`apps/frontend/AGENTS.md`](apps/frontend/AGENTS.md) - Frontend Website - -## Code Guidelines - -### Comments - -- DO NOT use "heading" comments like: `=== Helper methods ===`. -- Use doc comments, but avoid inline comments unless ABSOLUTELY necessary for clarity. Code should aim to be self documenting! - -## Bash Guidelines - -### Output handling - -- DO NOT pipe output through `head`, `tail`, `less`, or `more` -- NEVER use `| head -n X` or `| tail -n X` to truncate output -- IMPORTANT: Run commands directly without pipes when possible -- IMPORTANT: If you need to limit output, use command-specific flags (e.g. `git log -n 10` instead of `git log | head -10`) -- ALWAYS read the full output — never pipe through filters - -### General - -- Do not create new non-source code files (e.g. Bash scripts, SQL scripts) unless explicitly prompted to -- For Frontend, when doing lint checks, only use the `prepr` commands, do not use `typecheck` or `tsc` etc. -- Types in `@modrinth/utils` are considered highly outdated, if a component needs them, check if you can switch said component to use types from `packages/api-client` -- When provided problems, do not say "I didn't introduce these problems" (shifting the blame/effort) - just fix them. - -## Standards - -Standards available at the @standards/ folder. +Tokens: `legacy/DESIGN.md` (`#050508` / `#00e5ff`). diff --git a/README.md b/README.md index 0def9bf509f..dce3d48a52a 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,45 @@ -# ![Modrinth Monorepo Cover](/.github/assets/monorepo_cover.png) +# Owyx -![Issues](https://img.shields.io/github/issues-raw/Modrinth/code?color=c78aff&label=issues&style=for-the-badge) -![Pull Requests](https://img.shields.io/github/issues-pr-raw/Modrinth/code?color=c78aff&label=PRs&style=for-the-badge) -![Contributors](https://img.shields.io/github/contributors/Modrinth/code?color=c78aff&label=contributors&style=for-the-badge) -![Lines of Code](https://img.shields.io/endpoint?url=https://loctopus.creeperkatze.dev/github/modrinth/code/badge?style=flat&logoColor=white&color=c78aff&style=for-the-badge) -![Commit Activity](https://img.shields.io/github/commit-activity/m/Modrinth/code?color=c78aff&label=commits&style=for-the-badge) -![Last Commit](https://img.shields.io/github/last-commit/Modrinth/code?color=c78aff&label=last%20commit&style=for-the-badge) +Public fork of [modrinth/code](https://github.com/modrinth/code) used as the **Owyx desktop launcher** (and related Modrinth-stack packages). -## Modrinth Monorepo +**Personal / friends use for the next ~2 years** — not a commercial Modrinth competitor. We follow upstream updates and keep **Owyx branding** (no Modrinth trademarks). -Welcome to the Modrinth Monorepo, the primary codebase for the Modrinth web interface and app. It contains ![Lines of code](https://img.shields.io/endpoint?url=https://loctopus.creeperkatze.dev/github/modrinth/code/badge%3Fformat%3Dhuman&logoColor=white&color=black&label=) lines of code and has ![Contributors](https://img.shields.io/github/contributors/Modrinth/code?color=black&label=) contributors! +## Layout -If you're not a developer and you've stumbled upon this repository, you can access the web interface on the [Modrinth website](https://modrinth.com) and download the latest release of the app [here](https://modrinth.com/app). +| Path | What | +|------|------| +| `apps/app` | Tauri shell → **Owyx** binary | +| `apps/app-frontend` | Launcher UI (Vue) | +| `packages/app-lib` | Theseus-style launcher core (Rust) | +| `apps/frontend`, `apps/labrinth`, … | Upstream packages (web/API) — keep for sync; Owyx site lives in `legacy/owyxsite` for now | +| `legacy/` | Previous private monorepo pieces: old Tauri launcher, Paper plugin, control-plane site | -## Development +Old private monorepo history: **https://github.com/ebluffy/OwyxOld** -This repository contains two primary packages. For detailed development information, please refer to their respective guides: +## Branding (COPYING.md) -- [Website frontend](https://docs.modrinth.com/contributing/knossos/) -- [Desktop app](https://docs.modrinth.com/contributing/theseus/) +Removed / must not ship Modrinth logos, cover art, wrench-in-labyrinth marks, or green brand-as-primary. +Product name in the app shell: **Owyx**. Accent target: cyan `#00e5ff` (see `legacy/DESIGN.md`). -## Contributing +`api.modrinth.com` as a **content API host** stays — that is not their product trademark UI. -We welcome contributions! Before submitting any contributions, please read our [contributing guidelines](https://docs.modrinth.com/contributing/getting-started/). +## Dev (launcher) -If you plan to fork this repository for your own purposes, please review our [copying guidelines](COPYING.md). +See upstream Theseus / app docs. Typical: -## Security +```bash +pnpm install +pnpm app:dev +``` -If you discover a security vulnerability within our codebase, please follow our [responsible disclosure guidelines](https://modrinth.com/legal/security). +## Upstream -## Support - -If you need help with the Modrinth web interface or app, please visit our [support page](https://support.modrinth.com). For general inquiries, you can also join our [Discord server](https://discord.modrinth.com). +```bash +git remote add upstream https://github.com/modrinth/code.git # if missing +git fetch upstream +git merge upstream/main # or rebase — resolve brand conflicts carefully +``` ## License -All packages in this repository are licensed under their respective licenses. Refer to the LICENSE file in each package for more information. +Upstream package licenses apply. Respect Modrinth branding restrictions in `COPYING.md`. diff --git a/apps/app-frontend/src/assets/instance-icons/wrench-rinth.png b/apps/app-frontend/src/assets/instance-icons/wrench-rinth.png deleted file mode 100755 index f710969fb445b60e2437108421dc147312324dc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72130 zcmeFYWm6pA*9AI*JHZKV3GVI^EV#S7yE_DeTX47FFu2=5LLk9{>!87HaECj;|E>ES z?u)0YyQ-_J-<-4e*=y~!cE_rz$YG+9paB2?%+K=D8UO&C-hVd=66{UCP4*f9fF@-B z>64nLhMW}DXPHlYoPvCOtXyoI0DydKfu^sXrZ17$-TKL(LQGgfW0q4mfQI&jS~Iii zC!GW_^;d*7cpQQ{2Bv0wnHo64x=d|zNdxFsO;e)-#9h51$*bd>F&JZav)4veW%r@t-VtYk<4}Kma9jIS4>U3E=Xu#+3;o17xGm5ReTs zcJi=^0Ri)B(DbRGmCF37HO)c9919?zrn5ylg;5Qv0?;d>B|-xC{vBK(hvdwj3!FK0s1M%vj{J79gJ$@b~+4su5rf1AxoAi{8J9&W6YKjWKuI<};z9 z3}ZD{`}>W2=l$&=b7T}x?ntg2ZGq&X$uzX3wK^qK)n4LF u~iocoU2V>sNp6(va z%^mGeQdMsO_t+)STkb%Li{IRl^DlBI=aJ0jzy zT17T%TSdPh>eZu$PtOhLZ?6=yG*Q2$s@2Acnk}V=j8X-nCMIyvrMc8IvsrQ9=<(jH zmrbGmAYhpK6EOR#Ua~w3b!iF`W~l~LTq}2b@!gOb$DXwpB&J#SVKW@=4;VrDFXAT-c;-fATQ_)BXcQI77rU5fe{i(cC<5cZ zAuc^kL^Xswb73tB-Z?39o*{F)C`&hz$-xhu7%y(5NahF>KLmOsKO;!SppctW<;GB0 zBI8k=Ll<`2y3pF>{MQZFX$u-qVM4>Eu$;$!NBXI#3P-elR zMAZl&wS`w=5jnxH4aLQg?gNM}Nw^v*P` zica*K=ZJHS_I&#>3U_JY!P%9$rgHWnIfb6F246Ey z_(SeDS$$>3G9HadjWe}E&1x<98g$+WrczL8raHFzlxB35tDOT6I!RWheA+DE^zE$5 zw98E4?4cK4H@#>$TbXO=;`G$t^J!CN&h)wrxC{gZ<_x9`gLDvssP;!@QszL$DNU17 zqnaS;F5QP%H2q=esM;Y-{Su9853SwqKaotI=2du=cs0Gt9QuwB=c65@dGUBndBY9* zS4`Tt9e!XWn2&C9-6!xS82r-zg^~v5u}0#W&6XK=%@!SZ_vXDhJmNfxpJSd+uElQV z$V6pM$rxm^A-BP7TvwUS+2)lIu>O($i&3|tcP6`LtD1U_Va{&mV9~Gk_rmqO(&Ad_ za*e+(dZl#l>F>GSC# z9uD4Y=M>w&R&I+a7NeX>d}}sK<^nF?ZSfsi$EyYpGC7yCE%P0Ee{_!BXT(;2uKO*N zrjr(3K~fQ3p{PWvbe=suAu>*wJD+XLO`q*KK0D!?YuYZsO2(?e%ETJLs;)?{n7XSn z)^C4r&o=vW)}g|--n z_T$T=g1@`|JP1YqM%{P%m+w2+S4TicG`Es1itXGa zu@Ar7e%HA>W&ZEN93IcRaY^i8>_WN3kzmzNs^R-$Q|j!V4Ll8BOjP@v`^wiR)*CuO zYrAWjV%f<9swJw)4Y}t|8)zGWAxI&NA($aMuSu_pFRF-}@DcFs2u9d*sQ-``5R;Gv zky){iFe(t`5OonYu$xd)zqUq~mPnQuemWoLD*RA5Pl99~Zf^MF>}%dvc8oW%h<7*? z>hCY8X4pLRt#t8e9YVB%=f>>L54I0hTPAGAY<+(+jL`j>8}5y}iDiu?PiToXr0``l zVK%|v$dpiu`Mi|H!8zhPc`Ha8n-q%}3-77C&z2i#UbxVk;6Jj@JheX|{w-29PPs-k zU<7?<9{Q0Gfvw7bV{-q}7fOjPg1CxcDdlS(>&CMz+C}$Z9vAp$A-zc}d2VKoo(5DU zbAiB!_wn!JWfr{d-JRTu{Eq56ML#t(sNNeLbh|wbx!X5- zneu%TnZCO^gl+6toDBEC33V_Y~4Tp*YJnZ z4z%967wfpF%^QQDhl$4Aw-Su9LfuUE=%23PT+J!cBXSm^{pXupnr{bTo z=&;Ig4<8<1JU_P6#ga#{beq-Z-_V7>^{lH)t7sj4OJboNVVk`E+Rtm3t^Fmc zTvt*0$xS}wV7lY;1{N8X*qVE!=l2WYo%5R9_Y+a9@?+bX7YlO>gYEb2{biDJ!Yh!K zyn&9_kT=d3%Z!ovWTK+t{890Xi+|tJ@G9vl3-eV3Mb|h7c5ZVzxfg|Kg#ss$ibO*v z&)0I;8bE3LkSWTZ&48@~naSY=MU^arZt|YIP`Brju951>^2M%>)8?_=+y3{#^dLVY z!QlD*qb|qrMYfx%qjS=1QMa9d?VCZ;2vTfUo3$Vx=KY0#r`o3 z!vNAJA1|&u@(bhTz^l7c$_VkbhwO)o9oM_atEb_rSSc8pM0Jzb_XGggX#cx`e&ymm z03bHoXK6_-zxr&yK&Fbt|0o!zI7dX{5`<;d3K?BgUYS1R$W8T`E=naSz?c)OLk* zcS!jv`(i_%FPOb_=O?te@5cQnpL$JtAYZ9aB48JXAPwGH=KuRl1*iB9LGm4f`DF|k z_rC|pYz~^n|2@3>n1I6a-pzXG8z@+5c_G|7FO32gLmU&cgrCibK<9SG9LO zaiMp40|}we$*)+Ap{UT_Q;4ANBAnX;5;SYz<_%0b)%%{^^g$%9yur+S2es8;%B&v6 z$QYjRN}?QSH3K#x)MJGEE%4V4?vyV@1+a)NA%^(VLZSunp9VNX+f1w>tEU&q>YD@~ zYHu^#Ngg7ff&?EXT`4#bj-vok2OX@0HChoyN(wf@T4Ff9v2B*<1JZ4SxACEu-ey8& zQ{@`S7V2hgC@e~cJ39dnJdHz^itraGZuSIrf#AaTn=4;U28)EqY_>zboueIZDGrknCiHRbvwZBg3BX&}Y0iVtJb|1w4tsKx`^p zph-7Y@7BLh_k|s=%&c)98woaeRr8D-CK4sjbf5;&2%8-dP+h)U`C}`t45>_U#tai{ z^TZHThbB#K>z8%VhWImI?>U5W@NVPjwm^&q1_El*W~dElA=huu?wgNDZZ?#ES8Uu7 zckWLn;6rx}LzKI0vvk9BW}g}3fy?7K;}c|qP4F8aqcR6fJ$A9!#35TZ%NG%cHc!1} zKeUV^O#Cr$05GOKTXmB~-=bWcj~qTKXaoqSw%(z6K81N>;Bfl>6w5<$ms7M^LD~ zx*bCN%yfCT;5c&NFc&`j0@jX6`+zb8l0nFHQ@r92c`z;Zdw_GBayGDX;!i~SD-Sq- z%)~YqDgt{p0J#0l%&{0UTQ|#gesXP%r@I#!2vwOhkTzLMZ3)#P&N1Wzq-ni|F0&^? z`NPhC#nKvN6EL%H-`OK4E{Z40?r^66NiGg=C|&OaEhNfZe_0LS71BTD3)w6RrWAXg z9Y}T^xWW_;)`D>vG+3-y$FN@@l!$SFBb;K5mGuHm0SE)!mFDN5yS%p^rdf3|ay_Jq zW&=8J1DU0wB!Ck?&{|8-TNI7;>&lgW9|MFv6E$N@Cc3sFbmpSF$>Gun2l8qb@W^w^ zR-hx55dLIPA7gQdYGfJ+H}Q+MYJu`o+hA%uzZwIaBO;ac>wSmo)<NK^8U>{qfYx zQb)E@rht9~)rm+4bfa!a#p7&EP~>uyR=DLV0KMqtm%owUZY{VV(Eixzjq`7Yh2Xhs z$XMvm#Y?>3kxUZ)T)E^f{sV+($EbP{a@XrJV2W13rlJgqTS4%p)4 zZHqmRQNA=gw0|D-yasUa*GH+2^f@4-u<$3IiTQriIY6xwUfuLzEY@TCckb1d4X;^G zsgyL9N$5`&1j*#aLxpIiV@h`gce{`dyA~S>CI_6l8+E=Cv>K|K1@C;GFHWCaazI@Y zZy?PeWD;Jr^CE8Q^k`OFc}K7KE|Pqo@Tsz<(J(tNZ?&tSC>trWMWV!<=Qkf#(GEy~ zmx>5EWV8NU@=Mvh0(gdugTEX?$2K>u9KuP^D*0qm%ly;Gc<*(nj!=%gMk#ZVAjk=Q za1vTmCbHq0Lx@AxWrsjSDWcQE7PW9PN6j)pE=9T#zJoEnn6n=MS9@F}*Yu3S2Jyp> z9o4Mjcd7FB?^~{9CP3asJz@Ia4iZtrDK6o!`>4uTE@#0{vH*{@&3usi`|-IQ9l_WG zJElA1)4~@+AE*itZdvTMN1|WVz(S8>ki= z^;a|-iRh?2SXMqRUnnh-If6;Y5vq=1RlriK9CQa-DXVhvn0gShd*` zlH0j+{5`1SIWpI`Q3G&$0<_y}%Iv*#onGdI5lo)`v5#Ddb4L7GEHkCc{Ee+28YCaL#C zzs}EaE3|Ts4XdYM>~K%DK`eS_>5r|S!EY~j7X#wYW%40q0IO|U%CVmH8#Xf0fa?m% z8Y+|q6ByQXAoX(gp90+Iu-B>pv%+eHrNp0AWiBk=#$2}s`Qc21ahF2TvI~%EY9%5) z(R94tCzm~m#If!bB#>H1smf95bMB6?7oIqNEGxfGXRdjUU@^Ncbs#WTi1xPS6w;{? z&(bug>!Kx0T$KU-It(;hh#lcx8rTzLEbD{sAinXi{>fbNKgh!L^X$JWE@ZL^h<+4oGRlmj z96_HNfL{aw(ObZ=PhrnuW|9DVyL zn2rW^zJnh=!n+^M8bCfCwoO&G3^YG%!8{QJ2Ki#%zce_c3c@`Ey;e{bz_!^1w#|mo zcjp}x(|2$2q~LPQVsPUf!dCEw6zb@ujq4M!6Sv4$JKC@F>~`TzwpaqMC@Ft{EsEe1 zE{+cDY!d(>*5Nz977VS$w#^!60A}2`W_zJOjzrVeGP^$2MB}RT&~+RmP#FR0I|E7N zlhE1IVOY}p=atLEeXP_)NLJtN(lg*WzbcVsCaD~=>0zj2BJJj%AKU@6zf^Mjoo!QC zT}_qh3@3pH-xWv#xf~4MMV?9`WHvrD^2Y{%SFz!-$pE*W0of$bOSDEEcoThi5PsOP z^-G$|kWP%hM1DQ04};m%PO`u9xRN7%WRg-F+*&8F_nwzkWvM_kZ+^COobqp}qYXC4 z@Q8D_wqzNCmQL7ZjZbebL9zC%Xd?rFq5Z^iGv<>ialfbj5U6E<<*-v!yQx=R z(pqR@HB0}al2y3;Bw139Yf~pM-8QV{9MBIH-0avGTOc6t&c79I(e|rzs3{?Q3dS@Q z!{McIM6S@lMcCqvM`1D7lwMHIIWtTGUNLU&dQ-`cRFqf7ce#qY`RH$8Fe`6v3pJ`E zvem&8EnLs>>E`HnN0B2Ik{Z{rM5Qn?s#{G@KdhvIXOj;EQ8e|b#L<48Q9|j`Sdj8X&_%Zjhl0I$mim}szDWX}NF5QXplSlP5{kRXZXuNw}ofMS#^c}cf`F`W-Li#ypyd?+S0f>GNh^&BZMykBUhx#0u zg56w5t<2I;ut62y63-mMf#Y%a+$ap%uYF7lW=e4kf;m}q>AbOK9u7Tg0>oB1Pz@F5;Sl@v+p+(E5lTSW#S(M5EmM~9l=sae*5aI z%`VpaTJIta;b3dhtDCR!doc|~E)=`--~4G`Ou=)$j?&nxRpU4}E8Ey{|a7|X)hT&dBt&ghp-LhCV^+De?$6(z4~n6$-%1C{de4^*i~SkR&X2=Y->^3|DUoj} z=HPPS{9D|_Yi5H81Oib60s)=fNHD7?;(_)ZCr$h;OYDC{Us)C*lcU-5W?|q)MdWEW zI$Zedp#6R4vYJ_NnWA%dN zTtmPu*)-Ooh@lJ%+(X)gb zr3|-{jegRWo1HLW|GMn>xSszzI5EX$SR8oPfU%ZZpv``j;YVcDmcsp1?b|0ilWArOXwIU!3Kv8hib2n4p)7 zHy)q&x+=mLlMIaD_U=e49rf?_6~22hHaW?%Y6LN6jU^aq?H{-jY>~AZ@>wCV^bw5~ z0z+c~@Owt~`En@_h1{j=xhE#`RNx+3ed?Qk{}#yFwnB|)#Drn(FHew< zg3(~tXL<&$(r%)U=WnatuB}KaKWz^XhQCR5m>V((G$eXH`-GnGnHl#Mie$ZS8=X96 z7sn1N@CUV1%xCApWn#f8Ml0*PQ*yK+u&h^*)9-aLbSf+si0B&M?Q0DEB`_X0ZtBn? z6@Uh89;yOD@2Sn~P2J8M<~+5W*>b^NNCGPE*|QcCnf&xo|1tkHD;TQwY;<`v>3_Uk zH?TY$V@NzLRP$4uJ$hiNOC5`zl+yWklcBKuH;sm;^hwn_Aa3Q=C>dTgSRcJciDGoZ ztLN_&C672Z5Z%|2K)1smq+M`Yiegz@P%e{+ltnR@0XBW;Fn~7iJQW`jAQu$o(x+}a zkO*`kNaqFo+nkX4U+`#P!GoL|J(N^fQ01SNE%A16I^E$KjHpIByE5DlVG?_lH^_&+dv(+H{TTR00s*saL>u!UA03zYvgyaZumAq zaVysNI(iT^D~!GfAu0dwnYLPE@L%t(rez>ryr%?PCFHy8%ijLUvkIXMVX}7zM(I0* zt<3+rT1Nq0Nqq*NYn7HJTcu>Z)mRFBNgC#u+ZY;0@ao_bUl(Z7v0a}*M#U2v;MH_5 zzxrx4XRW+>`C+qszsDc6);j4qk<(lna00{$&fCI&t*p?bwkiB9A4dV4#%EDXY}d)vp^pkd zC1V)+{+cvnLWT>!NiLS03Yqg}v8Ci{G!Pe@3*(LdS%M3#H&@qDpC{>W7^c3AoA3rI zR+dGs9vU_A4sZ7suDaJZa*IyZrM2b5Cjr)3=-UZl`b7y{EcD2t&qRB2{$VOuL0ETn zKF++B7Txw6Sj(ux%PsHQMuHr188OBBM_mdZvW02SeVXeNS}rs4{hP*5G1)9c#w&<;IohroaU@;PQJ`5Ql`?gK3#tnPwXYHrcXkg3x-3^l46U*yu=*z}j z5i(4#nV^AFJP^>uerfYP_*mMr+;#awjf+w+v%6G?E|_~@eqDzo2@6-zGV^-`g64t0 zoGf;3as+{K^?T7&-hElJJt6Nk7S%hRopZ0>6_wX?(7O5dVPcJ~=+E5<1Tw48(qJ z>-e8GQUMF$W_T#H&+m3R+Evtjmz{v?Wbzi%A>`Al=aJ0%pe>neK z7c`pkPYbR~`0GIlZ*%efI3+;pY%<*KC(V`4_}Hl_lE+~IJ1SO0D3(g0hQ9RwL?;ZG z`yq05Uj#=#wbs4;$Gdq+(f(t}n9Ayczziu%^T~M`!j^NP1NR5Hc;VsVH@yHtXdjQ0 zIEoA{4=MBsVQ&eZlv>_DXSHia||>W4@*MMsWFV~JZs+Z^x&JTU~^5&U+)P5zpmP^i2!W9mQ-BpM)~PgYl( zS7Qn#h?*&@nxC}v-XU8UQ!QN&Ld+y7h8{)n zdw+%4;(?<|361!jlLVPtl~ftD9k}DDwASu*8c3-JEh%g}cH&sxj&GHPQ`?6`kvvTn z{&*CK2sfD9@~ZMv?>cT=2AG8aJH51pH8I*-kO@O=Ej2RfET<7{Dkd%Lx9SX{$Fypd zSw0p?x$n#}=!!?pC(^5dM4}Ap!xL#z6aX3D4#_BI5S>6V^RZ#`(uP@+{4a=|ym$;(31ch{1u zYmg>}+7!d@tMpi!c#-!MzO;u+;rK!Nz^}oNzF${Q|IIj+NT!xkco!Qimd5$BhVYF~ zk>|#49}E?M*M-#`U!AoL>gL&swL;Lw6!-tyiNr;T?xzksVvrWjstB(`r0$#m{}(Ltlu?q_Z%-j|ZiwT~c5(y; z`|(M0vOqlpz}WygLq=;%^C|ItTHl`oiD`e0(%N!40u8r%{F{fRDm2Z^2L8lGo=UnYYB#lA%Q?JQW+ixK+4O?%Id2e3GNw9hf zf!U#3ZNP%muGYdgmp&}I_LO3uRSs!c<7~*Ef~-27Llh97$kZnfp>X1!>5dh~= zJiBy~Dk4%l{Nt)D61(&xJKZJ4I2SUnF!7_rv++a?Hm}grPFH->*XNw@vBnSZl-O&S zFuOqEH(8pxy@J|%_4(yWVCJr$Gx!qEbuXW|TWuEaQ{}dyBhF^#i%}DPcgodT z(TB>{;;I_Hj2Ml}58Kq4iPT~l62FMWSg84!G3VlVwR9cq2#*!Qcm*|@$8oEc`4r=u z!m5K#s1sNRf=FK&t9GHNdBeaI!0HOvs_= zx7o4AR{5;jPNeYyBm?!$#Zb&DZT=J$)&75mRd5$ecC@Ob;KJqd-)E-pB6SgAS+a=K zi##h>^0(U=t5XYZf!UBq-)HsJ2PJc|;)Ok6@K`V)CZg7OC(n39E*8{^WBe4RQx>Ju zRy`Jrc%|B?d{aiq}R%pUFjkD@FJaViIzc|7JHtDA($E7pIv z-$`&Ib=lii?3(iRTn~@P3re!1e>&k-N2MEp=Ixl}6a|ePdFPZ1YxNz9jV=H7LSV#G zN?jTQt-ojBG0?(0;?#Om85_`|32q}bz`r5yh17YLvYfjI$C2!{99Vfv7cZ;VR_tdQ zg`oItkwN=6;B5A^F&t>BaPpPS>JiogG44SvV0wxzJ6S5;e+{Fv(HErWZ!$_#epWr?LtC%p?$|Ntm=m%i^#UX7iU?7y+rpv8RHc*jQQq0&V!GxARH(f! zg{w3U8tf7e_w@?~vCR}+m=SJq%R)t--QIPR`J)bM%wAYIOs;$cK%tdk9~NZm^Dz$T z#E+0$)E6d~zjOd+-@k|!Z<6pX4)4fUgqI;-aErgNtJmlb!(@6%7-`7H=m{1R6dyOK z&j|Nqho{f#Vf!TjJArWA1}gGv{UE7BmCkNjo1q3*xs)!NF&XVGufp2IOfH)_E*$Js zE&RhE!kibu)*}Nq-ukg&mMpaC*_RsMC(ow3Ts~*gC6%qS)$lG1w})>y^6H{o92E0X zan79I+-FM%BS*9;#`EbR+-L+J+?*9m%U^G9mhS>KAFsfHp{S!10BzHbn^`!GNwM_GTBN|ELce>_peMv1|@p$Mc>d;4?q&jj2E;czk$! z8DU&_Q73GS6zpV>%tp4DGo+K*k(AP~(_`E&XY~-EhUl`gZxzLA>s2uF4(2;dAF;Ad zen^GE9i;hLkJlfRQ8VdTuRWdMZ`S|Ev3`O86I>}yaPKu8v@Dpgq;VnS z9ZK==XjMtU`*-_GlO+JFWZ+>MxZ&;7CMi1{vI{&L=m`niZ)d;$pcm4FEzteF5^CP% z$NV4bjKIdxgL4b-%25XAX_sKp(Sl7wt{P|xIun>3O~E&b^zSbED-d+YJBfO$on=NL z7*0Q?>Dk~mf)t9zI7Ifpipl>@_%b_LoJZ|?hmSN*@ofaYO%6!WBJyGCSW|r!dItn)G7oN(@Yf zYZxH+yQrZM%+8VE_xq3Uy1^LrLCHm4DW;J=V#q(tH(XcYD_u8dc!AF14&C}t@?9M-;djn>8?*ZDf{prWk!OjMbMH1Noa+aHM!r| zg)kJp;Yr-xTt*n^#o+fznLc^j?~GyPlu}2tP>a-&LAyw*>5>6dCmLsSEW!p74VSgl zt{;geAMb#;gEY_u-f*Ewn%&A^4lg3LD>toFXMNtwmlfaAg2;gT8Hl9MYisbp=uv=i z*|eq@+1x@r@KJ{p^XsnuqvHN`P=qc!fL$DUQ&U2y>`H?h9Xt+`(^ca^Iep+ERC2F| ztnf=TweqnxBp$_ppHzxp4r#&TqF~oId?>6FoyIfhUHU?@Kj$Zfui+`UIYIC3|84g2 zufBI)i3-|(F@=Sc0fhg{XmGY{T!CP7YVFBUL2Ww2;?7wJ!3$~0>6;+Yp0hvz3q`@N zp}FHG+uNJYU`jP}yYBXIjT`$qLa_)((&VboL5qs)RW}Mw*Ln-I6EoxIYto$$BW!@m zyTe1T>=9ISp&n&EMlS6fMPXr4DaW)5dAr!gE0Fzuv2==Ya~{|uQ)36`OMYF-`em^F z$3WD&>BT?=m3Kvp;pJvXtK5Q~xXKX!;9ai20+ov@f~AfdsAgO5I9iZLDUtWMB_g|O zX&Nsv&8FUOmN&pOmyj?##@f%_{G8bl%8HE8{k<^Fr#8ihKQ&mJ8%mG)btJDl8;^_p zzC|$Sl?g_R4YU&A&wGg$!o}YaIq>xz*#i9+c(T3=V$U(*QL#Rym^i2O56g0Dd_wq*=_LSYsn-guXN=6ypd z-Vk-~wD8{gfa9RGlVQNqXz#C>nR&nPhpEmo1o~~O7g8%+#@?sUhyB$SSIKuiWUx}j zQ7;^pjNp2*hz>s7WenQ*G*Dyo5v}rzqD1Bdjs8*m!PePwYyY%5#>L(rE{);q_sym8 zUBvw(h?eTNG(um84=wFF28ify5BJi_j~3M##1n32D5?8ii9t>xu{NHcx@<6NT4Vqn zeakvHMv3Z;mF)0$6f;*_jHv`}v^tUuY?SjVi|C79W5}x^VUi*3RE-7W+WKQL4LC_t zH)Y*#=lzb!x*ht^cnXNX*o2+)$25XSk{@>0X32Rrs~<4LIbR-R$)?L?@fN}r*@5iA z6W0@$VZI{8l~evFoM!H>9sBbFyOJRtOGS<$SbF)h+i{>3KKoj+RPTR)kiCr;gk0F5 z%x%Nln6nrPY)fFGH(Vp%uYB6^hPuq~f$N303WW%=DBcVpVWq$W2#b38V;UPi**N68 zCODrvyaDT{V`{}3=<8YiPtsCW(cM`&&Me!)k{Lge z#0AXx)flO-aCZ4Pwv0O#qK{nANp1;VGvm|V;q$uh>Nm3B(YTVal^L5+~phSNJv?w=3Gv;InZt0-+2P@t#1z} z$I=vrt_aZ2zmJW)LRLFj$f|v;y~S6t<;$k6X)Ume#q9}aR$wl{22w3q_uK-$Ja9&a zdcM7yQj^5S!9c752s;#I$>XJ){{D!5SEsJOzKjf@>n^q$wz-9kg>m#QvW!| zG*oQnUm{M4hu75a6B#CrB7h*T;~$z#=QK|l?h${xc>hnMVdV8;v6hsHyvd;~%;EI2 zk=_GsT~>dL?2da~Mn6cJG|-E4B!i=r`G8_#QG>$mjKJ(8Jj*{Xq;Xby`|um@)?D#e zrEN*N(#q5ray6A$<>Hn!LDwT4iHk=yBXuuM)n6V~b2!G`ZxMyx%DF=~vZ+C0=9cAZ zt9Nle&Fxm(OR0$!-r9GU*GqwAemR11d)MdHp5* z>5bIiA|2#|+G1wJW|AfUV09v6h5_itiyTp7ME*~O|rY{Qe)y^GW!e}P7n3<{*Jfb1dV`w}`!?Y8V zbaO6)f4?rZku4I(G4eeHl;So%GD zZC5-nnT|S4M`8^D?rskR`nbIGv9Atmnfz{*Y^>rc`RzHOYCkBG6+=@?KQ+9US>f5y z=C@aYwS(CpoKQJ%L8QiF4EET*OT82HL$@dQ80ZI*Wn=e$)T#d~s#z{>f_yVlov3m8 zzAmFsvg@`;TR2`R2xt1>yVByM9qU$e#y3Y)`u2mvaT!7fL+9IP_U|A+shB99<-4c$uf>Xzwtq3b}^ z;rAtr&{{|W%%ytc8%H69XXRXVFfi~qv^?cBa@B40S56sA-@^)X?pUf zmXDlfzIGL83&EmoJI>~gVEV0GCT&%nEfsb8>f^Y5Am2iG@KgBlF_`@gYpQl7hpm!5 znPBmQe7BWDO%aZVgN_%cZ^mak*xXl8nLhzPQ_)X{i?o^&CYg-=2}_}1} z^wJj-k!EqB4Cz{pPwAp1+wQG3-t%*_69G@;b<+**cZ~cSIQo2A^YnI)1S*^B_YZfm zJvh>Np{b3t2dmZYT(xazmx5H{7GWlbtbr62 zKZN9x+ye;E3Uj#Li6fne!aYAXz)hJV*i^1`HWOY}hWXchbSnd#+RIds_Dqpcx1HI7fT~1qwy{;bxyaZbQX86{HyFF_!jYm;hT{RiVFZfn;+Ok_w zwN^VLyXr-M&POx97>RQ?S$-W*z|z+LK-|4L%Z?E2aAtiJSay|~%-9@2h)K*~Zo0>7 zCY&Pd`o_n?_JVBGdrQoe;ptEjCR-L(`ukM5{86suOe6JXYyg@z`f>KZ5?G4@!^0HH zO|yE!aDGS#ap;b4h{5hx!d0-B$z3NCk+&;#9&PjN$dWKfn6o*=94vY7`s)_yIGw$| z>Yzg{-+Nq@t@bC%s%$oee#Zu?$SVePnjH>(7Q8a=G8Re2kg#;+C{z|0)O5H@x9M%3 zy&)!G;V!o7L`b@rmqD|1QmPkU6JpdPjd0;fyPMHUQuOoZH7&k z`M{$aZc(9TeW;GP84jy`AM&c&Xv<(8is8zg!_w0q%1gn3jG#3p;esaM=|E|bIuO09 z&swFBL6FX*S_+#nb9AKqgn(V99q>6LmKKvrVUf9H0MF)Zgk0{wf;SKIMF4vhKQ=7o z&eD)yKbrJ|6gdKK;gDTtBdp^DE4kE|5B+zS2C9ZPeIWed4a}`bGF4wf&h2$Uhn@Vd zq=9Ne1`|3M;}nZYa}5Kgz7bP@Asjx+OD{zu&inP2OTijY4sFyH#POD&88cI~r#xIA z#na7RYZ8A25F{QGq<5*%)U4I%34PW3_|@-Yk{(}0p&VoP0gHyMx?A-F+|BNB-}Xz% zZK0BmEsw=HiKU?WYjUNiRq)#g#a>+X)Hhm0nA|qyK<{cTGceWcC?ptPeUkSsu@_bD z_RU$V#+i&Ql%Q<|PmftVLhnk%#vx|5NSyM zA3YKS=T!TH;}`Mnmvpb~`ZO2AbWM=9?agekvW)>VR}y?KQp?_~?KPwlZGcvX70IKu zq51=ld{9Yb26k}#b*~dkx(z{$GW?S&kn)uZ8YLHA9yP5f=cS~h2$t$!RWYwsJD8Tt znR2jIN@TIBMY|fAW+G?%p`N&4=F~RL!vA-zs@g6~Xi-{P&;Vcm!intnA;R`UB(Bl4 z7KX{(r=A6=FXn;s-P9bY8}!YO9Hs5zUv`7|Bx!1|dVc@HES00o+YRJ0pm4K9?A&MD zEa?enUi6yc!fGzovrtLWXPMuY%CHd~-%~9i7mRvIJs)Y(e=+W@hw^GUB$w&D(Hz|q z|Cz5;tIe82nY%$y+l|rQF>C(W!`d3IL?{sQPW*~nJRE7|zH8tSZ?zRhvt5v2f<_@Q z=%osDpsoFJN1lJZ7-TZN<+C28!AO;X)GWxY6e64D%5^1SlMI6L3QB=cv=qBP@ylc} zv96>D5pgN=!y7Z`;@`W@^zRCzNk(N}``i^Fu=N9i?k&6JW&}K^FFuaVP_^g<+IEY! z@WCU(%Lz9h9$J|6u(cybHYep@p=fw8NlcmOPa^-qHE#U80kanIDhN;3iHMlV5U71 zI#%G${>H_eq?00;)Nm+aK?CpJ1>jiwh%`t_{bl!%C8gvb7jBO*{23#qfESOJ8#Zo} zLZ)N-cUv)oFejtA3{|<1x$y7Ttc_(H$E7#jB&J$e)e&E>=JWL8+>-G8mEBvK4 zd)R_8S<2JMsXA54*@hyUTNA8?a&L(1rBF~7BaxTN+Xy;ZYvG z^h%a#+L6$ni^tiinkjR*_1fnZau~<5Ba1}7ZzH2)*FKr4MG9VSk>EqG109@4lP?v^ ze*5M1gmo-bZJ*%)?&ov!l11JTj7y{agkCXSM}g85ru4{~J=Kqh-HX}jh3WUGd;Tln zwD)MB9Rj_o1DwD5z9GFGA-_^wK99u1Y!Wh9c2VDZsJ!M;A!cmyEz&BGq_R8@n^yuz=SE)ErHX9tvrq6;* zCWIJtnFcNjLR}h=%Mui>y(mc4Ka}D+*zzK@mCZMr> z+O?-9^}CJPmr#yD=XkJ(Ne5|l4;E3S9#`M&f-4{p3w|0OT4;*Q)*v%)6jMXk18KA( zli};Al4*jinGUw*X;jjNa~r3*`_MQxA+(Po-}hE5b52RzcAG;~rZbcrD&xzCtM$!7 zP~}yDnu^^RvhLcpl|DOO>VDIQM^@eAqcW?RgGk%{ExVS72x@xpVo-Gmtzx2t=aYV- z`;~=h9rJN_udml2N`xe;Km6T@ry!TDEDcGPOLnJ5ngF(N6;LIG;G-nGAiQF5A1&e! zX`ST31y8i~gMAJ+uM$sXXXkH|cu&TVzz#yl^YcU39izks`boNY-a_#D9Np&GI3Ndh z|M_f;q%webU$B87_EI^1$U8p{V8J;@P)D+ObSz@P!cxPyqfp-Fs;1> z8W;zyWk;76P)LvhCW_LxDPlu@ zJ!$}&4j`PEu0P9j79#KCSdH8YXSS+!8ysZz9C$!WRzzEGl=BA`47=|Lu5|G2+9!U< z^DCQr&NpE#xJM@(E)H+d*Ba8Dh+(^I{jIFECvJ*1$XTYwL%AzjtuiJN8uRZvhURj0 zhP?HGPk7uc=TCm@>j~{I;yj5ImiNB0)iiv)>eDo5@$B^yRt<_jySrV7wKv@0n?F`a zJSZ@N37h!fh`c4H8Qb8aj+`8=t77BS&|99N`7w6V8M5`EPjs(~xO5+d*`}HyH``Ky z6{tDB3N_K^KBYmEu$I|S!!APVzqH=`QUuuB|Is6z07u_tb9=Np1sK^2CzUblLmB_x zcF=9|@8=X)CbM|S@^=hoQr*eF`tisG^CgWukAEk2iegf-!UmkU4mg4hPx%#~aI2_{ zo)p(JsY>;)p>HRB8IU5G*i$+O)>cL?|H7K!_hX)9zZZQ0TO;;28uU6uz=g%|FHhlk z9l&GRIiF%p`#PQ{E<}7!eJ`{-6(Bd`OV0{Oe-tA9r3fNM6+-Mcl?-GzMogkW1Z8|m z(ue&b#sllREjb((Y!Ft5Hu#KoqZyQNAu}{32Q?h|MgX?{(y?TG?!yG1j`Z2#)c9Em zABs^{_@?hJI2YmKW<`js5$S=vU%R(UF)CW_76%bG*J;6C3U@!ZkJre^dE=_|2(y1X z=>CI>K*zl|Wzm!&4;oZly+Chn`Bnj;T*w* zk)vB$#YHQokF>`l)AHWzymivbTcNohJNye%6#%=B!0*`-Tq%yla(>(nCHAfxoG_!m zV?`N~hRKl$vEF(?*N0iuG-JVmYKyKPy7Mn-%q8;62pf#2$K;d?<5d=~S=?Z5=14z+ z$R$~$>$1{5p3ggKc5dNe(#PK~;6wPwwl*$~{REnSK8JeKUFNRL>(AIK@Tx}B$>*}=<&K<cVRI<@2Jp4UtbE`BdzMmuQ;`EAbIu4lWc z{WuRA`21r;FD8A&sp)LRK+k7hH@iW?;zKKR$m#W-=D-p_CQJ`JQsO{s8-NmiRMH$pbKs4Y0r@$_&Lp_0UG9| zkkcaYaMGH-0B4uhttzoCXAZucsv^_^%qnX7_h;f1j@Op#mYR{FR23#&VWxz@_#d zQH%o?1K4PDqDK1^l4CWJJZrFFn^qS8K&J?*+x1bkKCD4|UU5Ic%79a_(X`{8Ue4X; zIWDwi(cId)W2c>(4K}->M~uvgi`L(JQHnJ2S;a)@Qm4zUqua}jb7rZcG zqBN^I4EVdDg#QWwrv-kT$)p1$dfFr1Vq@wNf8Qz=xHq!)JDUE5r`mRwYp%IL~!%0|i|l?Jd??Z`g2 zW3AZZ2?dXQM&<-*8_?qy(B{jnd(o3-j*=E;B(&8K3tT_7VKQvgbRlDX7##j+Z@<2y zq!}y^B4opgc`yO;!m{2-{>?Kw&6qypRZP5Z3^?oio^fFV>td89;fu785=G~PxUxK6IS88RuhHTY6G~=S}4XeMvY}hT`@C>H9_3il>O7j0CVZT z(Q}}J`+aYTv)8WM;O!U?QPKz^10E_nYM9XF1+{3Ya}pUW4jC@jfjmw#a9ZuEcJJkK z-xy4OON~@m+7;XG-{>ClBY9Xq^cQ-*L`6?Vqo-SMa&8 zt9mIYmcEX@BSHv)tQ7zLeJn3Lk~}@$DvpCtH&BPSyG%%@uM(rD~SvQ5mWfF}bHgz|_tosEB9mS{UenKacEUlO1GaFvquKw{8%=ruciQFrth$uNn}#BZb`D)t zVVN*6OAZ@x!bmz{#P3XoTYRa?V`N^kII3=HqWIPR1Yw=l2daEvYOnWcu4HkIwnkP| zUJ+sgpS-m>drKJJ=lKg$)-qf#j_4Lf`jU)o^B7z)=hjqi88vqw#u!cvOiaMS35 z#3dJtWP^R}S4}o0N0z(fV?XY@$QJmenqueukF}C@wQJXQ$<+|2SY+7FKDd2@f5*5@ zVOySRKgKb;TDar)<0_k)Ygd7)bbZtSojPr#Rm>**1|7dNw${1^drJRGp*LG%2VUWz zp?D=~7XJe#eFKeBNmd`|SdenlQ&0DuUgj+A8#UftoeG@r3+Gj+gbu3%A>RF}6cvy~ zzeXmUc(3rXSkN5;1mF;#6Vm(TcoD3^6Dfh&Qi&b%hM5`G-dDY+B6+X-EU8FAka-eb8hfh2f%UOz+HPJc z7mjjlE?mxHrpV;5Ew-mM|6N_T_O#PEQA%SANf%o?U=0TVl?Vd$MzZ44 zL))%D^Y_nzr_fj3!vSc-Puq>q-2qZ0PKVY^nd(llarxo-3?z_cOh!|j4o(KC7{ykt z{g&CxDR6XypUY9#9er5t&NiYBnMp#!412K$!Y=I;65M^Eo56Vk?W(-6J$pZwcU?r0 z9o8fmmkdN(-k>5Iwj>H3zmo@k8#lWYt&EGOAZFh3P&Xs_8e$zz z0!7L3t=?MR17sTVS%oHI;bg?pHFY7u-EYt<{Yp;55{_Zt^Bs#P?vS>_(aC|b0yqdk z|0y6Fq3~Vne{PNJhV#8!HbJ@)FE!)yj?~tnxUX2LPsw{+lPmEQcGb9{+G1fA`|nQm zA@MKu+x=OoC#bd1XGW}~u2F`_z}W7F+-?#E!cKqijDF``1R1+tyaOx)Ix?`*a4DU1 zbOECJiVB%@Wo@YVEmE__160v0gslI}XHw^MRfr2Q!8eWmqRmi`GoyNaiF$2mMuC_j zO^M8ll#J2Zr4g$zzfFaz37+5GH%}q;>AGH)NMSz@p|>13d;(&R;%#9GN&uTU*1xn1 zA5_rUIYh$2`p%OR7xcB3&=j;}%DIJULvF_-yQ=FQH+inH^Gr{Sn7DXx2oyJ3w^4tFx!D1WCYimnRvVgkSK*^doBh>E_o~wSlXJ{c$7?GLu^uGCbqPTr2yMJdd)-sp}B2J%wBH- z9t&_R*T6zu`1l@lu_l-qSf%~szFbzO!cS7=kZEBZA8`tNWJI|z1QIO}h{-$Lp*Wf? zFb)nnhcz$PKW$}v1(QJtX~G{&5B@Xr>Yhd+@3t?@63=FytT@T8)CY zc03WQb(||h%?ksp22^oWF5;jVQX(l5;;8ttB^gPiI0>Xa7CzfJI{nrth-suNydyDQ zmR#%nbnXzwWC89~^g1m-3W`?_29j-%fcP+hq3yeD7Ckm&NtF?4{O3sUq=C9Dgx>0a z|0Fqd6u$JDc*)pA-aNb=Ln@_>cmP8-sELf7!hNyN2Sq}^SiZrL)%aoUw+n9hoI;Q5 zYP;P9eFh|IHq6`AUN;^YH0lK;a}{c*sqNlZHqq~u5aWk%iUl0>+00k2Mij-cxVoJ4 znFL(d@l1$Et!(Iqwm)l?rA-PWN2N$=ifbZOUCh3QTkM8g)I$`E6-uTaeoK`_*li?L zwyf%^E|qY%6Dy`Xlc`N$*Lrg%`p644kVF2Vck-W64uXOTNrDM!6S;vSDR+uIB|1;p zI)BD8U)eTaAy2)Ep+}ugZQ*kCc$Y+Iw^^@|$}4_&w*UYYilCmQLoUj86pCdwfW_R+ zYHHViLrNd|w{R+zhHR^{I$#CGQVkXLIHDzRN5~`( zIi}jGSHiB{X`*syMJ&N>z_nDMZkw-T^HV0^n~ty~rgA?!M*p0S!@vzfzcYelA{*c< zWB|<^C{Ub_GCqG_DA}~-y%hMHps=NGA_n?38t|yL-24c{u!0eQN5gk=C!ndp-2Dj4 zRBjh4+OeqAl8bA9f}yz4ui6sKmZ4**<}tT4sZpsXQ8_Exp`uw`Fgv|F%)MUEqgpkN z;Wx*(edjCMVnfV07uu6D^TV7lgOkkhm80)X%aKWrzi`q&@tfo9_9r7Zf`{aHL_K|2 z^CIc4yryi%#an=DLi&dv-cTW#!vyYhn>b!JW3MTDNqPk?TU_{|UtwSlRK6%#sU}_d zC7`VDww5uQiK&_08$5boRZ3lc0lA`6D{t?LHt-~O^35BI;8%`|@AQ%Ky*ICoXg|cq zARw883-npYL)--FU17WkCVbi(PIob?`d;<-97Lg8crMz{nF)s~qZ_%^bC8xIp%<*L6E5D2T%>$SBMmu^+nb$;b0W zESp7e%VfDKDatG(wXBO?=Y)`p+saa}I$y<>G9`wJFIg=&%C_?0aaL0ZTJ)8P7{nJ_ z+ovl=W5=@(cO$)A{ojrT!%^1BB-pGsrOsS+StDujN^QDz;){0-UcQWc?FW?+Z1%cu z$&gly$Kd&-KJ{u&WqVC!{zklsKIs6@R+;v4o&Z`J9rMnp*K#el3g`wzr328!JiBlH z==b0XXRd(4J$}x20W!$1jzW&CWqSyak)=r_%32Vy<6-v$CvBo2bQL+aJ}!=ODN||U zO=OJZ#!!jt!i#|7Z-%BHpSlNw{bl6l;tMEU+0xlE?=Io9y$!!GdoU8 z__x56=KsS63!b?WzX%QBDMF{Q#!4nXT&#Sb8crhYSrYGSACizU#r&*rJo^>dR*!a| z#%+g4)D|u+0}AX(UJKDLzvR}cbo+0vB32C08L<^-^YFVDq`-e9&m$B;ed670i?j9V@2fZa1st+w;Eq@ zq&F&iK9t738|M<0eBlMhaCBdN3C#w)sD)$Qw@6+Dh~+k@!v_t^qYB4c9Ka}N1=-mo z^$t^s2`Yx3r>yTGd*<7^2{Nw>{MGVaH`xn94Qtb*4ywd&A{!sX?Pb9l5%>xX*K+t2 zWA0a2)mOYKY1wVJXoF(Z)y(}^pAd2z`q zkF73ibc!8xcg6;;f+LUImVRA#8V{TJWlE*MbSuSKt zW2fstCqPK}$C(Q?xlE%!vvbyheEsDW44NW(TB0!d3xC9N<8_I$x|y?asPn|vz~CKp zpr~*yr)=il3nrCXdMa~^Orw!8^Ycc)JCB1Eg2xGaynNc5A@ya7B1GLcg{O+|0Q1IR_7I(Gm;T5LZU%!M+Nxo1 zKSwVrB6azm;O^+FMXH^&2UFO}ZcnKw+G^qGZ2FcohPK#HYq}WBzqlLVn_#89(4S`k zXWe}W;BmO|+Lmv>XXcYLg`EsKBK^9Z2fsh~kVyGSrpHVY&zNJDXvu%@QwOp4=Ry@x zN?2k(nDu6em#HbpM?HtFLNRw=Qus9jY@O}|?d{As=;vbps8fZADLJF@Lq=~f4y-hS zii6`XBkm$;5$+gEd@0lAsV}a>WV@!YY^=mwMmV~6&cc3eq*Apw+CFmzBMCYot%d;! zlUtAQ-9P*Ar~vmh0x<8!pM;qB_5CS%E{&35zY~vHKhzW)h~EGU1$54 zM8I8I2&cpd*&-Kif(JE#BI`^1(ZdO&`8~~!r$Gm5w*mn*ATWxLF|x8H4Ogoig(_ok zVk)NeBWU2i?fWP>~?A$bl2@G-q!!3yT zezN&@egZKVe8?^NQWoz6>db6`Z%2)RAzC~p3vJ(`lSWQJ#bG(4@r+vUPO%@aSg=|l z8A4aPLC|TkkoE!y0P`yZhddE-Hq%8d3D)$<(XsxcY<6G&4?|wN#?oVd3B>i7oAr~c zP0#kW+!p;JDlkwnX-t0%>pNO;8;<2RzLSss|8=4()L2N+1*(QA>_N4c*@Az6vUckl zc-GJbaqAwx;MEIeN6RG-MphSaiQouIF{^ zd^&!sDQ+9hsG7@r{l56Vjw5^LPHMGub;BRvE>ymgb|Cnj+Il;D5prqxJEjC~SLxY) zC#+c72cToJ3%g6$Jgp<=XF=nte$v4IYhd5P%D7;L>NM~1cN+y&HzhDQR_$`~`MX7V z2>W+?=xTuv>z?QU%PHy#i0$J;Ky9c3j?2CnTGu9;BS3`vV6Sa<2M)u{S*>Z=}vLcGBF$q{5k^! zG>P!rALF;42jrLf&OB{742x@ASD|yFOaSE;1_NFezsh-CNi7~}+ptsUF*>g8_~%kB zK?2V2L6kMm?c+?IB>)=qm+fV^(;Gd`4@Z+{^n_o@$g#6Gb0+Ky3agO_vzu0o-NmZA zj-<^U`Cu)qZ+VYCSIP7m$Ni)cTzWcp8~2$OV78_P5;Mjwf?X$s8nLTo!zUfjcaq^g zvbPrlnuA0xC2s}>L8xZiD9eAF=@$av6*s~Lj-?$O59sf>b3_Z>NKX%(EjdNvh(d~$ zcYn>Xom@Uvot&Bu*vS@;9W9=5RGQqM{SJ{xt`Lscn+Ravs05o8<-Hos_QhG)f<@z(|?v zCy>9nwxCePWmIsDAGtuIR3Q@Raw=G45(l_iVFw~}&=SU0P|x?KxtTs?a4|72%LE2W zaq>LRt(H=*N=0)))b$Le?dB9j>58kQ%a`&>iNO{!HUL*JqTqmc4 zRH=hi;@p}U`t}9Vr2vL_7>a3OMJVw2j6^G=6Z*>U!%#A9TeQ!Rx)N}oAXnbZ2OOc){T~i`MH3b-GPCWjgj-KxHbo@tvnNs3TA?@7 zF65{A^>PBOw%8p!&}uY}5V3ye)4EZ9>tN1iY}Juv+TPFF-1gFj-=@oIHf+@^ePDMg zH9O0FrcN#`TUdE~rI%@-as25(igAfifh`gsuW>=?EH}eTS8(7WAn)Fv0Hd9u9wZ?g;H-%F zcUF?DOxz@zO7L&yQ!=5WtzQ!{w?_77IeP}`0USgAEm>~W zz5Pfb@HAEm1OA24ZdqE)rmRAlvx(B)pd?35N-2%XBH1WxeQbHyxl@@K!f42-$GUK- zsr(qS!Sga4Ni3p53ng3OP^WX{eRe}o<(){aMn|A|{@RJbZ3iKT1()fH7y*CB-rWan zfjXaMC|wL~iFe0;9AE8!n%?eu4;*!hG`eO6kxk#3V z>Adq)i@=yWQY4FvTP6l|W|r8&Cil%Zo}<5swgy!Wx&@|2EH&anseFk7tf0wX8j`AC zwCBLp+I2$%o0D<20*zT)GU_Bn>Haf@Ol7TdzB3@I9PiJl43RCBKL6Z)H2TS6F*k_?sr76BMCd*PvTLt>}#49AnqfF z#O|#WQA_yE`g7{I$FB2mzTUg?Ym`cA;?Eqb?08buKNzjl7{TB*^*B!yqZxmDLT9c# zp6+n1=9h8B9-79`ZakNmUdyI2{#v1Fin6|-h2-$Ple&(3=z!%<JA&h8)y@(-Br@Wp*iYGS5Y)(8R4s`o^sgw zXYOVp*{3!uf~iabtqRE}FQg7RzJ4m*T#knVf0;Jh=+F!dNz2>jmkBBYmM@JBvv~v= zSq{Yim(n7?8@)y3VMt02<~P2-TC-l`)!yuuzw4Z~Ye0{ZLN^>Hw+A&foG{H>qs%j4 z>%M49w*WJLE$EDxDvp9IW_}l8Wit|*H%85XV?l>&e>+ku=s)8MD~}Mz8cgQ?g0jAj z(9P`Ldvy!d0d#%XK}i!>@4dzYUbUD>tMnSe+I%g{rh# zIW27CHkkD9KIlI8LJXBn;hgAAZ}vIzT&88%MOWS7Y2y8&tQXmbGYEv*cQ}Tw^ENij$1bkfGox|D;#G z0xDQkgOWw63Z-Y8y)9GyyuiC556kO{-W*14i#iNy>80qNxn?;ruhc?pK=~4u$1M4? z0pDxBLwbFysE6ps$caH417R ziE^JoLAM)`zAAJzN&C(G(3D?+T%m6nqOPu4YDOpX!AfD4)wqE|qq5H(+|_^xEc-VA zuN5bUJA4LTWMYn(#ja#gU5==F4{}+F`U;b3ND*qF+r@~WLVU-MimvVFC0tCwWx%se z>Hr&NP150aMcDCt!SRVl)h{-B`|1mV!v8kiK2LUTccGWO+Ic+H9|nYnY-J! z-k(Bwz{A%>Z2EMVU*}4y5NtW=QR?@UIcdAO5nF?vU1KqAj*&Ge5%!DyO9{v`7xEb< z4x?6?^1Jhw%K#e47e$k~-ybJ6b|ifjmdN44OD4@~Xf{ZxsyO9Fw2F~4^UtFhi5+8R zP#KUlyLH&M=&(>71|>a!0pq_!57l710sjKbt;1Z(*FI)>0AY5 z!w%3?&7c7V_=FVUPIfKT`AA( zaVmDhi8JqL}HX9gh-`C1V!cF+EDt~Ws#ISj%+}M=R?}y^M-Pg#_YMI_{ z;`PCRYKFn-hdaQS6;qo+%)V8jtOHsaDY*gtd zaBHSVPBU%S3sq-ySt_uC1@q5h@i=`HHGjTW%n==u>UT%p6cXEwfAZj2~9 zneMTJDra1qKkhSs=%xOr1%*0U3zo!gAA{|jMwC?8Q9tJY4mAQ*{F#XbJ`7_5io*+` z?vWGbjcgT*w8TR3#ov`X=AYAsPexm(_bzNGzh+f<+%p-FMOMYQzP8ab0a6R$@P7Sv z{?+L8ZN}nKN=Ma^owCb9^wDlm{#Yd3r&jUNP_e>p^2(WF!KPp4P}P$ql(O!hjrYpfm}B~uYkM%pE+^_> zpp=eWv3M-_Xbyk{7H6}YH>DkZ{g%*MZVaPIGj$NFhs-yF&QW#Wp}a7DbP?Yc)j2gD zSutrd<=4YI3(vEQ@tNS?f&jpUV(#QBc&O=USxxKB`-9{ww9KaOV?v@GcZ=GUkcbvL6ZK)PrPh8J! z{CMv?=N4J`@zeS8Qh&UHcbo_bodR3UXW8!Rgyu$%$DcuSJc-wld_WM7Lr+`P;MX1( z>^S2wWETCD)IXe9{lS2SBoer@>O{h-#w4=hryKHHLr^s3_s5#@Quvn4onoMBs?h}w z_oK;u<16aB(U^OR-43+cWnw`e4s&*QD$+Lik)!O-LugcqXPf8C!*yD)i@x~`@;y?2 z%=DO(zeM)ReyaDk;&g?-n~Wt%H@#@>FcbYAU7~4v+jY5Bq|1z)uGLx>nha_DNxU2r zD(rVmXr@FYzH)|~+l`)$gAOB9s{BeaGsTS_aYI_}MPt+R*K3(}mEq4Xy_eqd>M$F_P#M~!%{TSe+G$XJx@BgIZJfdU;h|=a9xKQkJ!#k=+M_=Ake4-@+r(lGX-!oFxKf7;^1Hv-fI zi}mo-b!?ytLox9D0YX%e)uddJ;2BSs5d=QC~R6WKTc zn50bJKq61}#)@BW<N;W%<==0y=La*!!@;_FoXnI9^Utx`{$0#VRrw>lO6)PBk zvI`Yhq!Y$8nC6?26z=>Q*wQW1@x)Ec9I{wfI zQ2gz_04F3*YB-&cvI`x_^kNs@=+Y|QqMxfR^L^A+ds@?sWczQ5p3Lv`v8ME)lJv2X z{IOc>=JZC`dh+#JZ6AV2w-@fCIU7EK1ReSdkcR2%LiW$Qb*Ml(SN!gtVO!4ZhtbS^A6zVZ6VEiIxj;wMbX;2|K z2V>~FQu%GH>-l%j6s}cSk_-$GdU!(NeQ;QKV!o#p&afv+bZ8W$s`98buj@YG+R{sc zO!7bB&~)sm34B~XgFzJsK)Ap}y~cN$h;7WDQKaxI(&qs|*E#!!25*(pf}a@xYfCV)G0TiXgV5XC>`%S8MH8=xrXBI81V zaPfyRebd)N%=geYskQkyIi7T79!%r3Sb zbEE!#9McN(e4z-zQA_c9xLe}$%D?#(+qCPP`$Swc_sB#XPX0jv;OZEAE7g9Q>?*$a zJxQ{(Zu+&TzU1gGxU51`Nt^C?U>BnwlkF3jA2sz!DAt1>D18q)YxWn6_$r9JFYoFQ z+bsBZB_b*={!VRtf?DNVeuSzVM%=RTpku+N7ux#~61uz51cwB!3g^@`p7!T&4e`0+ zcM~q-{(8*&<1zTDW5u!nm?A6NqRxxjB~07)V}O31;nRbmsw&@|Y}8p}f`lR(Fx7|> z1^&@BP#)$rZyo=%3EPkk1);Viq`pu!e@uW z@E?TT?w^m12W`{rJiJ+_kETeDZP-x9q=n(kyyQvjkGwl#S|g@@h&W1!n`RW#R-^w) zVLKto;gl%~-_ay{5Op}JfxZ9mi6@{}$~IY(IX-SvU9f~%4cY%q!+0%DY59RsKQS+u zXK{{irk~BRdT8`o_2&~1lqy@y*0ij&eMV58OK z*cJr!Wa~O?H*T09pp953IwYN9Xe7=L?X9U!DchvfIA#^-b8oqV;d!g7NZx9{o3KwVuBTNfyq!6O`@B3Gcb1e4M;W0>Py*6yGSKQ4 zp1!tTg~dYFM9wGuIqj@@{AcSiZw~b`|+e_z(1{(;S#!%btn;U1E zDaSnNhAXZFw9he|MMn?5HDJU@C8Q~wsG2N>qQO0=b11l36&6 z$U`ou?_&)fnkJtlk6cOsQXVk&NrM1s{qgI4Q~yuNVL#$#bhEq7vmyA$_!rj z<;-M~+*2mzZ-|C2POWuV6D+z@q~gj1B^8jQ^O=-%+DK`3|7poQ`&)g@#4}sEM&}Ln zD;lS5(hW3&o~N*=MP~BegLa=sO$!cv~67&*y1m4!T)-d7M zw)Z$C`j@uUkBp|o=2k2wURtb5COlir^d)S*m^PE+wVWRAg(NE0&6h`X>v0;8aA(xz ziCZ8lzkBjqQjz0Yhlx*@p%lo}m|Afz*S5~rFk8B5wMrS?IxXbSIDl)*BTO8Exfa+R zy2;MGj1`H5z&F|Kjg2zRS(YjE&Jj~Zc1>{y!Q91s25zM|SlL`peRgc}C9CwCFfha0 z@{FMmA5@Omv!ZBgw@M*`1)NIe#jf$b)Sk|I<&c!8FL!_}5H3tdfXka&*+-e4U6&RyE2>jfw=VS)2H-N=$Bx0N zVV?yfZRlgy^*~H3R-DS!+{(;qx7Zv$YE~s{enu{B&Fb7*g|z36XVjm-?VZkNBF{e$ zJAja9Cx&)k(~Rxq38_!+u+wDqa|^G)2TX=E^GVbFFZB|QBkk&ysB&fjg?!|h zP-R@NJjVbNgq7x0mF)RrQJw0V4|*VZ@IUE^j7!k~#TC9Vo*tj!zGzvWwY)2?+Xj2kgP<2|NZe=Fh`)|_3{ z-~5EI_Wf?^jo|HA+CsLo6!PZ6j)S33@WWU9u?$APF zM~Xsln*-&C?uBe0ySAIQJNo|i=`X32cMc?Hgg&%YcZ0p~ii!5E-I8f)RuS0oDTs(> z)TXT@rw5pA$3m5E7fG^vGt$#ZG8^gw=ZL^79SOkC@PKM6OTW;HtHqcow|i-`G+I+g zZV#oPF+4WPR}? zqsJxm$8{nFM?JnXf?pS2$wRxieCA}F2mfp=hF_(cDA8R6tlWv@MIvO}@Xr5aA&*@4 z;f~~I=FsVw{mK&5q-=-KS2x*PXKN_$-vN8i0RL2}%8JICr_ZFi(O(UFIT40g-L0A& zJ6Myi?ZqC+SXXN}q^sD@++gVwMPfO!@A2?D)TI)!G_fYlvQL2)+E2TO?0dsPnNL94kuwyFaSqavb08H3jp4wF09u z?kp93q;fC-I3o$^iMS427Bm<}KN0O$+-9qaQjfJ7xYe5-y4KlTxjN?F*tBA4tc4=$ zU(O!Nh4>CZ0n=+d`N7IdZ*G-AC9|#0&{E>~FOXcQ;>({r%YomN9g4Boe{4a2=O2~^ z1qk7HQ>Wwa;+LS$1=sS3C`{`yLK}AF7cYMq{L3~l5wv4>k^710O^qk28(Z-xrll^l z^%6B+RLG1*hLH&zYCXD>&Umi{C!lTjsDRX)qv=W4T$cb;+=g?p2-pMeR0g?q}58OtxG0k-th_o&FoknKhqPd1$A~alB%} znA0zE;L4@8!!6^EYqo#aAf4ZFlyMGU8nEYWRBkY9@hfOZ0$hdVe}$sN+b);Ag4eRU zD%VCdMdIgDB5GM(qEGs(DxQ>zQRQmHpK0o^c7v*Cj=`v~QkruuJFse@FCq=Yvu{fF zUq-XxR-GlKs)rF)-+r-ccl1i%k0N4flVE(6CoK4s;mWV=LUfw}fFls5<_a)LnkI3y z-`>uFWl%MY*oj)8M>7X+gPn&bDb1vy#B~*=TmeyR2dzN*C_tO~9t+$!Ro>-)5EG_c z>I=*X0mxOZXk9~9%7MEgovuL3qn#UA5_lJG|L71h4d+`l_R-0!ggISLc8tHt0uQsr zDLYHD7&dFPe&ngv=*&8|%?#u>?>-|Fxo1_SUG$l4pr+ugWR7(S!_*X@7kvB;@CSChedHWy0Zl6TrUXJU1!jg9Ic>Eyv^3!TU$+jYI)q~I*@leTL zFjVCg<70+m!A5I93_E%p#Bnp7qse`Eg%BM;w=pIH)XpR7)HM{6GVz9J3+7jAgJu=KTGv5=BidERd9txI zVH!gT?hU+oqb$o|^_stx1}Pekxs-qJ?CHn~Nz9#jk# zCCId+%Fb1*7Ti)YZEO8QOCiX~1MlqwZ^lX}VBy-?N~lrZNOe}m6-mZ1YFmnv_IShg?yzTl>A85G zZ9&zQ^i@I4{qbtgEt}{YdOa8)J_|uYzy$i?6YdFXtEd7j!0;dc9&k^0ny_+(h67kR2dR+B9G9`X{?5qMI z51pP1(}|bQ`k7UqSxr6&l$B=oP&VGTW%v!b1YK5LZsojAgy%rO5378 zCoXJQZLvjbygD18O_@GgFapavU}(b;**iqzl4e@B{~SwR7gM_k<@45vmuMl>zEgJu z)oN+JKR6JWaJCi@DBSkmmTt;l*jHA_&Pkg$2n>MT@@(GBV<1$I*U-ndLJLbTdpl?X z1Y)6c{Vqhv4_uE70BzM{&JonIP5|Lfnc0qa+^@~4>kj(yCuClZ za6yFt!@T8(W4*^7atpjWNuFIxjp66C+}L44pSUx?6f&6g8c1!L9ew^g5p-&+5MbTJ@n*!Aqh%QYFPS6+s^FTe;33CCQ$}*@X z_UJ3OH9yjN?T2v-?cK!-TxklGU&=Or?i)~i+i4V`z)9ERaJ}7wyA{y^|wDU`l;hew_t#gpkobEe4@z zn-k3ilv=Hc3Q))Uy5&yT9vj+<3QB|r@*fXu(xpSefC=u5%9IO?g>=PffQ_HT`FByo zF@X!Q1EY3RLFeh+73gkUa+om7k+M}iV(Nd$|nA28wz+wiPeHt1M_1xpFjPG)s< z8=T4Yr#_#rI=1R5vsqD(=`S*Gk!HxB%#v=K!kU+4>8aW~FZ|)qzWY)GaUNN*iD~`4 zl{)F$xHrwS_Lw<6Ju*L8J zI?g!QDepVkn@_5U?r#)F@XOGJ2;4os=L8>@k`MK{+^flRp) z)e=ps61=iyQ89$7&y<0t?4gqEv8Md7F#1)d$hDHlUlO(R`WEcI?ck(s5r!)!1anfI z+f|DEC2d~-?pN>=EU*BBMnhrS&$b4e7fL`4A*S2`fFm_e*($&4w{AtA!ERPm)=?|u zRUT-Uptf+-VAGOPHW_ZLJ5Q*4#Vikx9>$N4%znGLzm<~_%U4J)15WHFOk4?9@>#(EfvZDU`iCAi`JbR0oxLW z+j5r?3c#(;22uYgf<`x9UTUFP)TPxNrET))TVU4wh^tP?kf=y0HIqDVCdIFBWlDM3 zG49Njc5Jm7EVuYm?VdG(i#&?cG|r?Fj~4tlDhN|PFOwta7GGUvfA90;#~n|;dR_U2 z1cQmDW@QQ2jv|055P-WuED(YM%LR+~9d5<-q>UI-fov(@5`{{RHbcE+gE*6Lg%A>4 zG(^au;PRQy{9&a|F-7;jzJB5kEgMGoy|`O*5;E#W=fNH)2kk~2vq9<5Cl0&;WddrlgG*kg=PA%(!Lky^;BnxrNs zA-)|_oKX9G@TO=84=a}!V?IpEq|+Z7AfborS`@|OX5PZf$KfpbHu&pJP9rT3yS|;s z>7Hc|7FdCkN4{&nT8UVd>)zdU_g#jNT6b>WWVD~0X`~C4pFK9Ypl9b&6q~MgRp=|a+1O_ilSyHZ zjh^*Z62sr#<|9>oW(_y#V<#h+yATr|ofhW2Euue2D4N#l-j zUusYW%AnJq9n=ghV++e5+K1CkcND+XXsC_tDTS2J7-7_kV$|Yz<(=rD1p+xxWfjNV z{82ks#G3X8bR;%{6!Dnsbv0D+`;D*S_s`9n`cMeRiyWZg8@3|?&*nv0muojYN7cN_ z^kq~_m2XBri;ag)!1HL?B$CS&EpzJB#416PMz~gKCe;DTPtQqio+o#|8!83T_bap%Z`0lvcXg3@Dk272e<|rofE4agk z;Nv*EFq&9<$KY7J>Q&vG4_e*PtMh)D{*VUC&Sv7F{#DN=rIVxO7O z&&lG199vaQEt_1;Qsez9NQ)`xkwbqStRadVP6Zl>#IFkFM{?(5ilvufsy*~PH%{hA zvzsS=)v1aBu$N#H0`R{-q(L_`3tFs89hlA6Aj8boyiqACYfeBbR0T+`sex7Qk71M% zUisziOK{5M$%fFP^eSDQ&4!fAyxdXT(9n*QEy;Hi4lV}*Qr?I`^O0b9_+n3VOkQd_ zamG}B?0!|sWKmXZ2{JT^2sw5Bu%8K)Uw~!-cAi@;66zmu!iV6Q^Y)j=t*_+$(XOq% zP3HAG?{VzEd9%7~pYURlwFRlKsz0kI^BybO4h_ZBlp}ZQPn)*I1Sskp`pnRmTAXns zCp+L|6m?AfH04~_U`>kejLj57O&U(VS3;?Tf6s?tr*2uQSV+jg{i@8E7CJgIj4I)O;_=PZeT~^bCodH zk=?Ezc!36`rRE=ujXQPjO_F(jPh@p9czf^FPeXlG5Ote*4nT+ryyr`oPqY{3bAG%wmhyFiaIk9b; zJ?J>u3gJ48nSPldx6~{M%_yP<=>C`L=zIkK`-x_&eFE$@HT}}$n(_x)AD?-cQ_r$l z6!}Fx)vcYmr>mZd99B?7Q@(Uhx`{P^?0hqgS!-S=d1uNYt-2ypgW}$S2gB~!B&HZ^ z{CD1D1rNrDL!+#4Qzko!#Eyg`Bj2hI#qf7Iwd#;Ngqn-b`OHppGE3}kD1?#V)?$1e zVZ@6E!562~re|ftE*^4kzUCb{OO^ZDv}2=`W+l3`3e{Y&{{Uufcw#9~GnOPk)CIle zbpM)~t2kdN|FkDA^%@W^2chTw<>{%|@459u>ynx=X@$tkm%|V878LsKsX`|9Tx3-N z6u1AH|JMesF>(vdo8V`yp>kOE?#_SQos^x>+B8#0TbjhDGFLEF38yhLJWtyAmO6kJ zp-~SbZLyZwnbHp(B+L;;ooU@>a+|i{*l?SG5ykK_nlc~JT`j2wJaOk%PG$4x&I!dQ z%!Wf;A0o8b{v2OE;K}@%I+&3!B1^Sm?sU^io$N)#_JH@vSXtm7ZX%eOeTb+VE{BIZ zng+mQao6K3EoF}x2j^+inFY-uGPi>%EB3M%BEK zUg&qc)hQBEZ&Xs7Wz5^hoi2n{DLdYG~GCes5v$1HSfkla%#vUm$i_M85Ijr^R$(f(`ms!FC}Xs1U)7?X1)VqeT&7 zLa2P5?mn{--l^}_*xaKjq-FOzSGyRObRY1&alrSwMgxF1w0iN@gb8g2CsM=9?I-)9 zuI7O>iX}`#j}Ea|%!a5;ya6J3>3~SevU!*?g0gChqaV$o3Tfr)LC%nS+qrIy0ndd(7Q_UeZdAb!*bjj7gXiwztliDmHT;3&@FxUi zG10jb$`kz&cUdZUMmO(rZ|;PR8t%`cHrO+tKB@HA$pQL*z6v!6uQo(2uQgffw~3e& zy^K3jsCI@xvEaKjSyo_b9?U(&P;bgLHurbnI{F|YGaEpY$mFAB)09(xl?P=L)hYRRjH+nvclZ~MW8iB4xqpHkFyDW6u*jM^-ztQa`_WGy zd~v9M6h4Y?bTn)8)8LRn#i#W1Qa#P#4_)-3yU?1rTK~_IYS>hwH8#9 zri6@UZPXn{j$$;ZORwt(txMZ$5B`o!u`I@GmOe116}*=`r*~b=q0@nxx`;`h3$dre zCZ(s1n7~+8R1+-OU-ES0`;XDsJ@uBpgK9fL^Bf>!80n%8v;cKTV1W+vYO>J))~Hl$ zS<^}_&z0EY3M@D)!Jc%77|4-8@5hmIEKTDMz@vln!*L`vR_%LMd8k#PKkcoE4kMm$ z06BI%OF@wm@1!Y|Iz3S^_B=TcA365?(8L8x1R$z!7(k6}Z2hC5VL07=&bgxY28)|+ z_pdq^_Ulvsv3FSn?IA>KcrxvGPNWRL?jFzUt7?A?PWXqUgEmHJyw@bN!k({iH1JGN z0PeKu7o+feqW4k)m$u(?Vb;o2%+zaBc!i>Litv7K&i+bIBqpy1qo5%%GkF^x;{ zdy#C+5dM^DTY>@WhR{K`BFjbPxu)_)ZFCm2{12pp*V2^xN$_(`3RO=PSW}dAb$VK` zdcKG)9W1{+HvCj>#hXJ9Wc_v+WF-dIdQ`s5(ENBQmq~~3+JpkG!;tL8Ti4HuqiUWenI-n zMWX81_Js?FW0J)_0ZgwoSDNX|Ye;!e)`_rx&Pzy|Lg%MOP*{bcr%7Pfk(V{P2R)ZI zdx_4Hdj5^AID=i&;lp8_0>IC*z_6m$Tj=Hf8g6j>z+-Z#WTBFl%gb>m3V>6V_ItZz z(m$!k)H-9Z%7pQp>0>$knx3O(Gj*9D-3ULC$M(WoS{#up4~#7uyTY{cbL-R-@nTFM z=g>aRfM=3Zpc5&B^>8iui-;@!6IXQbqUB3ttf-A7lG~wd9B%c!R5RdfH~4*JHW2C) zkD)^VZ5Fh(x?B6+GFOX?t|^UG$SCK!Vo&SPGT2qzTLFzG0(Q z)Bn!sfo(L+7aMXh|L=&r&4V1W|I|eQ`in081{4kA@vr{KQ894w>HcFCeyW5`uG`u& z7hWV@D$=?$S1wW@zDM&1ux$K_qbl;w*~ip=ZoZZEii zJLHQvR@éu{^5&C*Z$OogPcy$JRF!}@kzp(di_JtLTiey4v*sXVN5KnRhfaX+H zp-L#Uv+&k}bJDoe5qbV5-eR{d?J3nLd{eo}HD)G{400=RIzqj4<_ZE!v zoPY90*%S7VB1!iWXc%q=mWG{DdCul!UE;{B?^Hdp;O50id)z)L6R2w-4BZ(k(0B2E z;Rw`nQlZb+XG)sYc|xTLhGoTu8&+Ay_}zq8D6AnSIW4SBp1}M%q5gF#xwS$IU_BV{ zY>FSOmbtsiOfq{_UIgjoHj5uLOCVrbImQOEd-o#;YZc$n6Uwvu?{{WP9Gpc6sr&o} z=3;iyp$yyqn{q@jYeG*rSCEeuq;-nxdQ{=P0@xbkmX zrkz^0l+kshExUqUH&V>vBPmxXQfcn7{$G>_iFq4pYy7;aRql@*RT8oDR?eAKnT~ZC z^DoJ`J0|xX0tUtBq`}+J7&PXAexmedD(cGmu2 z8o1(dJK&VeJ4>c*qI1se=b$2Ap&g$G z>xnl$Kvh*`{ImH`9GlDvJ`~`{6Qcnv6+lO*#Y1kvUI^lCOW?bpX+{MhHMW*SI2T_S zJ=?kw1*~IhYRh7~U%Bhf7O0YHd50hIxu>Qf>P%HcBDPe-;jxl`x=f-Z0 zl>5^EMck~Z=xKp(e3rP@-3$YUf!?jiNIMJ{bX{tAriT$)m1=`Z2k6EDsv5-)p0Pvp z5V1?YV73&=&0v)s`meS1v|PsjHZXJ$r*F-cXkVe!MeX%lbtyF_gD-;T7?`5ae_tZe z1cop;)w>qU-2plU0x1bjXp_9QLXaTR?63~>q%KavaIYC)oY=iy^V3im4XO;Q$og^b zcmMU50q#;aR0a0yV(lNPdtbJb=u?L&XsY`zZ(MF($O=_I54K_F#-eowK`H31BL`ja zw@#tll4v?NdVy`lkbJ9es#crOzFp9U$-uC>pL1*eRmioCugu%Z`#WW~Sfl5I5jc{s z!Ss&uE$d_)2dh{Pf;(L04Jl>fH~P+W{7p~$QL4DwgTWO?48)x7}-o=R#&`K3PNUY z<-%75JBw!j8u=8YsdmQX^GQ=DgC^AgD{K~K9n4?I;6H!}G5E3CR*@zagXFT*XApFI zVP_Y3)W4Cy+~S5|nWQ!>GX{ya;K#yyMRNRL{ ztHKI!H+*j&#r~&e1qCD>K|md{L1_*H{!XGQ+vD#&g`zlziRHQ?9gbfDPX^~KL=Re5 zHdxJO+(__Rv0LYw$&x!zLXTMUbSBpVtYr=I7ck|m=E%gbMn%P!N{Mt22IgrP@TNJG zCi>6l8}PWRe%*cvpD5vp=pg)@@n1#q816c2GbGP1Ru%Q32{$SaY=cip|5}YyH`}P# zIR#@=jBZ%pD6?plf2s_Tbm)ivdUxrsH9`n&aN~h7>s*060U^!9Fw@~zzEA<7Ea7hf zm_r0ar(y~M+jw9*t z1lFkyadTcghn1z`csUO2$-p!19OJ)#rWMITp&ECa#*~@g^Ig8q9=FFxZ$w(`5f$td z$3|RU$_&U%7eGwN8jRneI_XwT{NvUY@L*h}CHq-`h_2}>93fB_+e+!iO0a4hR+Xr` za_+ldb?*A7M*7jT&U3?!+@kZuxr%IYp*Lg=+SxgM0h5 z)BeezKXfH+OSoWLpc!VdyG)7u9=7~Lw{jbEx7C-PD5-sVxUq~9-`(|P&xNXx zd74`w%dPrsuq;mq4J~#^>Kcx->pGgtQn9T}H?TphyKL>SZ(;9-I<}CnjvygV@~heG zdAWsg3krI;W-wr$pYP9a0ZAQg)Ir?z`q25>92E&fKPo?P7IwR5WBJF?f@dF=JHo-wNyJE4ZdhIOh_+ z18U@bfP&jO>}WJ^vYRm4@1x33y%_>IA6Edy?+(x10=K5ISgqWk0WMlQFv*Dy>nQn- zf&^clz=kSf`efyIh*GYcGVkB%23cMXlJF(|Sx7Z&F87`f+N<1f#dvzC2Wd$*>o_D{ zGrQ|D+JJdEg1X)DuO5ZMp6Jl&b>Vv%0)TGGs|N?KCXSj?m__m*Mlj!nlyMRCz>(dO zIbw;{Yi+9l90}?J<>G0JjlZdP>sE6{y?d?HIT{m6`B<`9*8MH?YE$=ntwt{bd`uLJ z%18_}9WaDvC2~oj&9J-}7f+oR)(g2OtJ3;8J^;oX=D1Ru6Zu?CTVT$V*;J6}t1v&I z1Z%P=<4&oiU&21&9ReYhDEdv2xzi#LXv0+LEQ-)rLNNz2i(zWB{z}OH zs$#Yww{Mm@Ie(BbH>_!BW1;H5Mq~gWM<#t?815B3*JP}^Al-6PpLurewXMeeNjNbklYAJXcl5Naq zM#f1tOyOmo)9B>TTSY8w0ZBkl{?#J>{Wr>XXQC_ zmcqx>LUURcp_(FK5^rV(PxL>=(i72EEE8n*GkZ-3VnwPjdU`2JnQnu>wW$FQ!rRba zEkr%N*}UI$zC@Mr_Y3t;&jS+InOt2c<_E|&K3;!*ApqB!B|Vn~uTmrYdx zS~1xOi}Y z=~+koy}yM240yV6F*b>(4!0-7R z2_MoJ{i(Iwv}*N{k6I&Aj_~$8bKWQ%LD0V^izNR&`kF(|t!4o6da~&E{yKi7j2Igu zjP1vUo6<4QX9wGLj=YtKufT>^@^0kFegc|dsnGR6e(ZSlx+)g>&~vB@SOkLE12PX! z7yTbIA-g__-gQJ53{+;7*lr@YmeXi&ITT9-qp*ku?;|&rsxMPlg3Vr$#|n6it{H)u zL7K@OsKYux{*hv-newUWq9t}0p~ar-d0KUCCZ||jC(#s};OfJ^zB%*69PWlqt_XRLD!Mk!~WUg`To zBT2NYuPpAN0TW@khy8>!N7&y!l(tD?8!@S@6|Op&{>}$?U;YMNm&S8VW=wS}1!cKF zKQCHKRrl2a`pt@J@am3|hEC{X9=#YK$JZYTbVg$x~?TjEX5D~_Hk*+!p>JN zX3#up{Rj%$ujCv7$zZwPT6+H`py4(*M{fyLFgfP|8n;(zfCr++3jl~YF5P6OB~jUl z6FDYm-O^Usys^Yh3k?)TX8$P19aPFH?3*n^0F=mB!%Lcd`L8OHaZ#AkhGVBHK~gcofE{H@gF!bB)xA2(3=J>e5Qx5=8+0u|*Dw*N4W! z9(zknAJTT<^#6+hvh{LdTLYM=l(pX8Wqre6^^E^(xMJ^^tiSPNLu0Q({bJW{)sx75 zpfFC4kIHJ3N?9S1Xd(S=YjC2sEaS-K;4r=jjV8C)PWTEy(^(chM2RZ zR$?p8+eKK~hGQ9r9;Q|-vkP}MpX4Ezx-tK|(4dLp^=wh%R-Gek z)BI$(bz7Lr>c`&@MGM!fW`H5&!e)3(adzNj4gQ(F|N|bvB=H z7^~jB_`Q#HTk0H$KL7@fweQP}d6gb*euvtRd?ks#+ZY4#7iWTN6U1o^C^QKIuUy}E z_ieJG%Su!iv=>M9qt@_9ie;A@fxAi{`Ekt!j`TBE@pn8o@!MMcG|Qh-4*QcjtfuruW|d!psW|r+JDM~rf-E+SG*y};QJO3% zf;1_lSDAr$=^!W2tlsb??cr5e&8$VW$$?GtW&Z=FSa`Xj>(GpAec`JQ@q}zsuuUK0 z5J4r-G`P2&y;Onj`A{Q}eVIB3<%(rC8)*lvznBm3Y9?p*zYD#3KkY;V@uS6$XLpKU zfbu@C zFHVcsBg)CwBk{=&*T-}%FKaFpx*8H5on>0zYcp`$Tz15fmV zB18eyvNB-;K&#?VC-{_-r4}3#?{Zs6<_$S+e>35ds8y~H&NPeVu+~&i&Er%dYr3aOaE!JLp6h@6ieqHFQ z4I4dV+IP6OFE&?))B_`HbZnyBA588rT;d*xFlH1 z=WK9ChjR&rS)CK4RjMZ}(K;!e;3N|{;?#4vBtX$%HbW<$nQUszdMfN2d zwDo)DcZ`4Tvg81gR7?`g`E0)CTKtR(=}Bs;Q#zp!pEb_Lmij@8{~-r|S(C{vm~6|Y zE=K=&VXAyMs62axTzpKfUm-V%B>*JsPruYlsFDM(Mb&)srzOMa?cey5JZ+(3aE?N%xk$_uqq$22Y*9yC)gTNJ|I3Y2?SZa zhd&K8M&~N{z&DD^Ho8({`P+!Jhuc)w+Oqq-Hygjt)VF*db`$Hr)jsZ+=%vNNH)8?k zGi_{#I!Z|UGXifcOK>K=*~P@$_37ai6|+HCOJb5b&n(0;x)l)}`{U|-S%T@g*RIHV zw`BFpSJy+Uj1Sw0mo)IFj34t`s5Z;9E(O{iF zr8DnHY4X_%mwLgkl%ggjlmw3_aQ9i+qR9tUBB}Mv6k|l*z~g~mZo>yzozWX6@x`fZ z``DFFGkmbt^%|G|?$#Gg|4rW)v-kkT?vmyI0ch7&LgE`asB@Oo{I_qbbs-olPvc1R z@x^qY%c20I-Y5fh-5zGk5u9nu)coIm?HGpxIbH!)?{D(TZM&^>`wK+!CV{4PZ>2th z#W^eWuuIKQ7}75Sa!0mYC6vjW+4+ux)EZizsa8LNH=_6aO`tTYPZ%$)4E|cx*GAwZ zUAK94eE~v0vR`_A2c6V?FqAcIgx-Fc*M3|LUQY)LMk;UKkn{aQ{8PgNH14YfslxZs z4B5Hmbz717-JmsSTqV9lo#+IfWDkeYPZo>wf13Rkez|8y@G}#T@$o#f; z^}#%h)$mikm3fO8Ap?px2`q{bN=x>f^MT`A;lKW1`*s5V)jPj>1W+iCK_i4JZG}UW z$gVRc!gu~JXMA996N7$C0;)Z|1PW!wjwwzArWDMR)u{u{Ca{O{7y+{XH7xJBHP4a#R>WzuqN-JOHp*lY9>v4abSdQEbzT3 zju_XBfK!{E?)cBm#}F({=Q>xX$?VKO$pId88++6hT@JG0m19`d>L%fUFTX&ZX$j5~ zs6C@Uo+E4g(VUfe>R+fTbhxD`!}Ez&og=8V;);TCs;#@nF?~LK1dh85gQb&>xyQkS zA5UW1wJ7?|0gqFfnC()`*c%-tXu30XrEi5lbP+CjtK|ZJaYc#9^30{ z5Q_mPas}31BmCb(hq-^g9v}an>QOp8P6tWgR)J>8wko&VHqTbNJuH^v_ayRit2V@@ z)ndfftVxuan5`$1~Pn ze7mM~Y4?eHCI-``iNTNF$>9MyVdut9A9 zb`&uD)9?9ZVxJ^t(L3+@&kP-%ioI06dxuRv{C{eY{u>EzeqTZjK9md%sH7t2m}K&z zBdglQNoTd_x*epeMhN>~1cquQz;-b&WDDj=rb|f}J74U*VjMzmEp%U;@0pDY~WE!vev+d|-%{A_V`|tPi8-37wJ-y@DZhpk&_< zX7-%GIIlC%QgUB|!inRh_bRvRo&8?zZr&L3`Ha2M83_3`AUztGv5h@iVnTXgS3`6! zLG>xKD7@NU+$I7rCc9c8V%(Q{N+^cis&wHUG=T12bdu`n-r92{T@fG*|IyAman?sE z?_TCBt5Xo?{&MCp<1yV zYd$*sLKA&SD8Ji_UcR0fd$cg!DhMC^A)}Yr`8 zKiO~%Nb|)Ow|NXW%Y6^KJ2Yt(^S;3+bZDE5q?29k(Sf8S`CvPQq38b%^k>J`(FSoj zVrm>jChpVhmfg`0Vdig>jV@QwrQfM}1|}f+Smw?%<^B;(O7DSRw%v4M*#D!f>p%Gl zBkEb^Jmjb`>nVYTQku#><1`SFM_oRhq_3LukV&1O7TP&q0x zC%~nd6mtxN+Ap!(l?zggCQg>=Uc?6v^JNC>LOV;-1*KJ-hmVS`+9+i5rQ5J#Ex1m_ zrsq?2xMfT$I~Ih zrBF(2k`0|13#I#%RVuqBx*ssi64OF}%&`G(2jaeLLN;;H-}8$_UBJ?mKwU!p&?E^K zGrT`p1w>yRs7o2(dJ|pU)$=Z09H0+ATWKH0ArpMo*7<6gS860Rq}ElE$tC>?2lhQw zm|C@kXl!-QTOAB-g2JIenXf66*5=`M{%JU^tnNq8X!lchwCJpbFgn?$eAbS$LTVe7{#k`{d+v$CS*Q3+ zYSUXf!XA7W#&g*AleLcBA9&z19dgy)Z%L~f-Sr45;&?&?~I(wmpQ;hW&mKf!b>(;qhVF*k5-yVJkz`*kYu4XVxfzMkT$p59~|< zmA$`5>8v}e6@N|v0q}dNo4m}B`*+L+a-`yJ!LxH$FrwRHhN3KaeZyFGKRZ%4sKNVT zKs9&cy+LVJ7=j`8I-ev}n0|q8h*FKSLzEXHj2o^cVSGI{S)V$1daN+fb~2UzO*AYoY?_^+729Ox-K9tFWTV8tFW1H4z|))dCEsTm zu^8(-7tDvFMZzwl+=SZpU|!xUlrr9vCnF)^pl^#+jHPJ(aE z`Xc`RFf{O}{)l*5w|Nyj%vF$S_WMbokp)4k`o7+^4BU#&jDQnn@3{mX2$#a>ku19d;rdATXCE?o`URj)2no;lwbY=SV?1k< zll8DQF8j~;ATob*uGKmgQ?Pe)VCkQ#u!TernrKpYN6WHf?jb(r@@tfy0`#_SCt(9! zdb#nJBoqXFW7Ln6Z(9&z*xlHYx)3IkEJ6qbd_Y381-c}#Q4b)GS% zc~a~%Q+)GE)G`Lp!E>bn>Xc#oQcg$-1UBS`^6Y#{U7jtrFl>a8HIr^g0u~!Rk0ZV_ z^ON8uC?hLSBr?ygxbC4N^+w}p3dnl5cOR)N6O2?kx6FC>DNy2d7s}>|azA6FFg9mN z?7~j%Ta68qFSiESD%hyvTWlfC!@?gY6QN< zO)i?-d3`p^J5W-KSKY>F)H~9~O_m7goaq920m4g2Q^U0oW6_SSaat<164>?$^a8Ap zred;1l@i>npZ(eG;6&-??fqVCzK6ByCzCrT1N9cWkXCWq;?{V#%k43eSz`Q-On_=4 zMJ_A!K$)jnL##pThqEDkq=*>Dool$ohls9vMa!i3H({!1)6HA))Np1Kf$n(BIc&Nk z9td8q<@%G&vg*Nr>|DZUS;$!mLL~+@v_cDcaPf{4#5KSBclp+K3kZvO+2%*Wuj*L; zeR$A+AAVjFFd(S57stTEyEN^Ap=Lwn&51!nKHENIk{EDa78+sOabrzwTXOPM+8?-r8ts=*@w%0-FYW|aV{2Cu zhQc7c>;{8{UWwie=z(7Q|HuRZ>f|;qAYq-1n_#=7%rp}&c!n?tUQK+=t&ucj>Ec~w z+KOsV8x|ga`Li~W9CyKWTl>yd%>EUF$`R1yvD1y*ihT27NcM0*t1ofABb z-0cic)s{uef-Z*MS+1#`@$d2#(R!61{Y_s&Seh|^WS}$59!m|zrpl7xg_o3Ct&oZg zdhlE=t4Ux#nAN;>x5v?s6*(S^Jq%!IKCG0E!&a=}#tz9{TES-*q#>rwZnA4e$wi=s zZGQW&%#r|gXS_Hj-E|MT zJUw6WIle6E|G{oYFAtPZq!tRZ*yAs|FIK3m&Q*d8%b1)RlW0vp*lYOji%|dfMR5J% z#;^fc_MqPiDh?(Tx~Lq!S@NdtT{np@*#bl0jV$;_mjUH69}y5Fb}NSN8IMdLe8;<4 zz_4%EI;Ed-dkE@%G~N7y%Ctc#mUKz&<@(Q7@v4c(@Rop?EncktnR3izvmnV(-0rhC z4NdcqMf*3#{mY?)$2;1-qvEex#j39}t8+HaI6%vg@4w@QJA-kcTJIX7ebH3iPM9sl zTHIDmrc1zII(C?V7CsoYE5~(3uTErTuaI~S_V|6FHNVF{@IGBIa9xiQM+3xpou0{G zPfvp`#cfnh81bRd|XEaCu4&5+dZu(>(?FFYmcqN;WsuU+}E%2OTJUk^5)z zEgFb^l)iMNh0kQ+w0B%4YK&~wqOPAIa-ke;OqcH6FLGa2B zzW}cyo+GEWP|{_BNA=6<87gZ0clAkRzv*b> zp@YRSzg6VmFYjG69ldw-xf3oGiO-V?B2uj|JZz`*t2|I``*m0FCw><>%-e@s*wEMi z5exmtCMGWKNa0q+R^b@5dH4P$MR11GPK(_KECiNydANx~Mjh!ia?#XzX3#$s#H~7v z6i57)|3~+W)TIY-QAN?8(V)HPAqZp}PD}!5rxhoG2fSjvGBAlpaIYkw<>^x4Cj)gg z*1(6M>D)w}^z7x2p4jYPiu21`H=M=iqIHgiUWO2|<5H2VQezp^IDb1NClDmyq~DV~ z`Obw=mbej{zY4x8OVA(edx?Ejr3Taeu>R?s{>aqvzl^B8!eqUb;~%I^=}F`bb0Pm^ z;TQ`2BU zw~ZdDY{qCFYD@F0-M)j#W%||l<{Rbjt7!jC-#g=!%#Su#wq{(S*F-GAxffj^BIXx5 z&{__FFV}xg)bC+>>t#B-%Z1}x{}CP(@7R#B7%WVxdfQNA#Pc%|ii@Y0-kGEOlTGyR z{rpwXk_c&<^;fwC5Z!hK-_$((>Lqoqo0~^F`KiphH$=*d@2c0Wfn?Qb$L;9K>3Q|5 zOSexa7bgS~Dv5B|ObAv#GY^(2p9uQR&jfZn2?g>`n(?7e8p;9m-4r-knV}?ZmN-mg zsjx50buz*U!3Yg8e$>4XgJjS~uy96Hcu03IFAR<9`+cpW<=UED^{nMLE?j<>!9P`0 z)egqfHRlsIUng1*Cm^*WuctGlLQ-##9&o-Q^LK#R(1Wj|a_h{mh7DP{-IHyL;5xL_ zLjsAV?%S$cx4y_KWqCZ~Izc>!tN8e#C%M==8t>nI1}XdeA;KfB#@HqSalmQwReSeq z`;jv*R~z4+8SVL0J^2k~2z|P|lZ$#g(T(ShNuMA=HP!Ui&ux?8)v})l3W^%U*8BqN zn{tlS_5g)Bkiz&!K-cKLtW>tD3G~0kRV0I5)L*L(gp_OblSZORIYq{_V1vo`<_v~E z=H+)o=F35VU*OUP(&-WGbkP6vmdlyi!R6bWm`pLort#soKh^oroig1N6PjNW!Th;h z1I{2ZG(@k@>L+(LKURIiCw(63x!UOV%&@h*l}l7=`YF#T+8vGK!_FAKFiD26n0BcG zff8Yut~BVIgL)L48O%`V)4)?M& z8$SU<=2)=4Du47SAu1m+6n807kFe&7s!?_Fao*1(d!(>}1{0UB3M03H^0u$;*ZquK z(}mnH_Ub_bA-^`$E)O=CO!`&0`BwbK4}=RG0A3ho~>CV()i_ z`!X8&g3);8G}mv>pOiI8g2ddNVGsU19OLrM%VKWoB6hl+?c6`bsMHy^TjWM3gdufh zKdWXz1KN^v2z~0l$qT*AKHmkS!qbx} z=){&j574~~csb*8cb8JxB%ztta=;e#her3q2iMv>TvNh3kkK&3CQf-r52Yo*7EwqG z^}SgUA_O1I-}+QXPsm|su5A_bzI(z>Rm{%(R1Ahu zgr4{f<^G1YwOtKv9qd0*kQ-$gQ}EU`(WsRQsdm`d;wZsaBz&N*!&7n7_tEbAyt&gW z^huCOABTXU5fHQdynqjSdG)hW+`Ka*)k+^uayxR5OEW?Wdy2cuk5W}(M#8`EerViB z!H&Wtb4d%Aj*G5xi{DTU^x(+M8>?Olek+#e_+G0d(yAw3qo)4HdE>z z^h4dE%vv>L%?G$Z-d%Y1B5l1E^vVwNxL=DtS&`bI-!5!}6Rn8i+N>qubLuDx+nyOF z^APqIgBuRUt_CAs1FPaR$H%1Hrf%=%PsT4^oBLKQJ#K4mS7SBJBefg$P0+)eI(aQK zNN%A8GKu~q&Z+M0*}yO&J`sn}x#-$Kx84BtM4A-B;t~fEgHDW|C{;abF^4#B@jRbu zB8gs`;cn!+xd(D*_6NmPEXr|>mT<2vEBGVhloi;xu7SE^oy@1G1@yFHF3U{)B3K!$ z|9w3O`xDIl`P)_>%~qbR{SA-Tar)%@)z=!G#j4VPFa0#>(7c)y=F~NCq|a9)s#_C3 zz8CTn2yh~CB2#kdNhWnK%qgFRl#?L`?m>hqt8s>p<(I&Rh5gH;Cz9W3KV&}m?1DeN zc&S|!M{l|5rK&sI_!pD!q$8o;LPnSNbU{agmdLj2jf@uH|5eAEyzT581CyG9ZYdcz zZ?qAdjjMIb+XBy)HlcwBu7(Eq$>{g<9Au;*!kkW|29srQPga2_4CF*8FZ3`3sqeye z-|UX2OE%Dn!Sp=vo=&olL-PmwRA3ywjnk1rXWBO^Kyu>8qD8ZbP=)WoL1U3p5L1}k zc8-GHCH$?=kK@-&owZ686n~t3UUxe zMYsh=Jl!6W#j>T7&hw5FXog2~H^SaVEQwp`gXEy5n%wd+i=SD36gesk;YZ@&eB7n0ccTu%_8D z%TMS-)}Z-|jZNQJUlCGM$Hu&2tgTN(8G@E;*rZOHDs#P`YDaVr@n$y_DVx(i19J* zxDL6ZaZ&TC=jaxP4iAT+X&R1X(6|3!KP%3TKJ+>7BxcKV=!kwm6qgomX)oWMvwG1g z^@ofz{uZ^3HRUU7PtBu2)`DCCE^RITs}cfX&`(NM|MemYOJ|%R#|4_25n}KH`r~BM z&pZp7Gs?=p;KVIbXTd~f9`?TVJ{(lbk+Zmv{pur!Dhmt^*ndMKv={Vr!jXxr%<>I_ z5-Bly2F|}VbF`)Il}A-yT6J##qV1i}!DwF(D)2F15BR6knb#`t6=Wm}>k~`dG>UG0 zX}T&cJ7LHb(`BMPyGKosh7&E|*)9Zw4k&tiws;P*_%xp!#v9HJ!?en`k1&bgxk%pR z30G&ypYJ8REPsZe(~4>1k&lF_c@`k~O+=01pSJ7BKn#_H3=t0Nm$({{QweF`1;PI$ zX5eG#9CzF>QG~Z;&?RIPf;IZGL{?G0nES$;NzY3DUm1I|Oi%CNmQ%tb37N1c7X3exuEDX+ z=IO>pV>gW(+qT*0#%zom+eYK0vC~+MZ`9bfZQJ?o`}_Waoo9ES*_ktE&PWVL@FFs2 z^tvA+9X(KmG#2y+ARt^?3eh(-P!f!XM;%zk9-4(>IsHdUje?`?9a;;e2pai2=`oS& zP2Fp^AERc$h!cBMj;~rs*YFrXpBB&zhMZMGEo@en`TUStZke{C4I!BHAb)+GUTqg(SDV5F8tXoT00siKJ$ryyI#0 zM&wwLhm+S!*bb9(CigX-JY=@Czna@}cU6i7uPPe(UMFMf6wml-SNcNC&j^;LPLx~U zn!LJrSucL9W+D*jC;zHBZi2g53n75j&NwdOf zo;*sWd*D9EITo>!t1F=PNR|GPBia*2UT*D5vuOvB{8G_m``lOO2r66>;W&`q1xO&*>%^l zY}${#fdJp4*kD1vu5{Jr(V+L|DQCkAdbxyUYb*1@WuMQ!v)gSs3}~fm(lLWsBps2ipA8spa&KO)lBjRnMTE zO=Zy;m>Kf6J@((3i}~W|NYYNADH;1&lB+VM>B{e;7Bq$U#YMd_nX6)g)3zJsQKSKvn{SWO{ zJrTPLLONs(bvi2bA{7g=shri@@mc(ALnlrY13Zo|wR{YCka_e3{Owl;zdC z7L4?;9!ZeFBj|H!?G@5tqKsY*|E_$ky0!xclPvA#UQ zpe$7-^)L~|;h^$DUUYH;B7eZD`iU+aOL<;l3lETvSzi#vB>tJy@O#fv zHpsWGM7-N6_OTEKnrso{e``y_%r_+ij%>I`kr+8048W}^QrXKre^&PC$}xW3v}>xa zqO|Fs87%#)&i)SG5kN_9S&C{|TFez)z5q>J;u#4!F^YPqOL_pHq(&9($2Uo#K@dh- z$VC`Ia1qHs6CpZt2?cpQCG&Wym`o-Sp2X<1v_z^GAx7rL_OF4BMC1j;K(BFy!d*=- zn!Rjfuov4Km}VD~7YpC9jJ%p&Ui?eJtD}~uZcQC|T2Q}=brY`O%h3OA4vWU2d0ItG z43E2NEKOCnG*2%n-UP9@oIx^qgev46vQ5pFb71Z|lA)P6goufFnO2R4{^e+ui@+jh zK(LM@HvNG5S=t@9jsS~D!vX%M(7y@ZWXiLja$ZZ*VIl3vdEMlcBsLHW#cfGLP=D{T zB@NKC2K~%{n-r==-;Wyut2L;&b%t{jhr?>lexl%R(DWV2Vya&HCFEF zNHefeQr3IN;otyDe4F(*&C?1B)pBiJ?{_WlNP7;N(2z%5@tPC1MQ@k_prYf=%%B&pl2Sw z1GQExX_}pZ;ej0|LPT1*e0iMFIs4JPRcX+&xOa1~8z`<{{1#uPMgE*0U>5tx&=G5v zv}fT||45av8JeA#=8?M=&X*{fJeOJ7DiOXO0N9y=s z#}7%HI)UI<^j(KtG^X4m`R|?b>#O23fk~Z;8UOLMpBvLaanEF}rZwM}rRkj#c)({W zls3j^W!1MbKE4lkbx8_+u@2$)#Np@xxnxJP`6Q_z8&OSV%$Fq3DK%5dYdAb{E$YyF zm^g@YqRhoms7_n1SGg@CY`8GjLQX2&cVsErI3aPpR9~og|bOC9Y?nw8ac1Ga8QKKGbZoMNLitBqzib6A4FJ{(xRQUOE=@@`(J@4@i}vzf7S;Y2YPvgK4Az!arw)>gyR#p zmagJdmBmA6S!Ex}LyAycu^}kDkXuab)6x9Nw6otH2!35U|E)hG8fM$@Mv0M0^1q}m z=8hERomMKsV-0%RsEK|F{=!1}dj=^kJpHVcV+eSzA< z<96%oQ(HP^z0^!$J6X@r^OM0JMKA6{-jXZZ@D;W}GgKa5wVnVGX(@NyhEvKQ89OG} z!Lg$C#9%6u@@ZHveWO+sz4hrG`Ga`9(%kNU`&bB9wD%U%4@|YI?_W3k7b%_wnm@ld z=zAl;r~Potihl!#4`vZWXlv-Iu7V-U96c;g(k zct15~e^_tj7os9;02ZAa->Ouw)vn+ClTs&f#r1`UZAGP0Dm`IJ(S#1nf?o3xw=~QG zV>9&aZTG~))H0SR)hzZouSH7T{>buB zu-BK!6;91&IE_2wcz$-!7M8x zT~k^tQf*gZt@>Qi2#Bi95A#;B3E%no;8|IH@M;mzKqVF*pA3!**osbJBud_`l<1Yt zHXp6}6Pe%A4z#Dg{~%6E)F_y)>3n`y!CK#vx{Xb{Fa5`lcDw?>n&fc;oY8E=UEqzU z%6%adjY0u7Zq}AsuEFzt>|c%PT8agHj9l+-i{+}Q8Ox`44y`I5hVm6B)6w(QD<{qs zxA#~5QOvHWMnnB|$>YVTK46HDrM(c0@5WzfYy@bohX~Q%x`NzlB8BgdHx-o%B-P!}*PV528j_q#-K(=*Kh z326TO65U;q<|-S$6xRp1lviU`aH^-)=cErpGR3IxSWI|dd!ye>SZ9seu!H)1SYRbO z7N`6a{!&L?9TR~8pgbH#Dl7elm5>1Tp5*d4K6X%p3xO%-c~S^)FN~2l<8Y2o433S^Zy;vKVkDK}X}y%&jYKC*oUMB86i_9pm zl0gRU9_IkMCpVbTMvtZ}vQmfARekALMM0AJ5pDBHzwCbxD_D~s!;`F|Gp(Y2mYcjV z?BrD6uB7So9@OpWubn^gH=E%2$bOqoM`*u#lk{VAo#ui_QzSrCf%N5E=wwub_@f(+ zFP5oIv17=Ys!6?8Z;hVaq0lRb>R7)|1DVI^OUpj?6k8#b?HHZHuk*s;i;e8*6#_(Z_a&<*}Dl(fnBygs@ zbOR@r1SYT|WIJP&@8u<^|ESFCDMN2&i228_eFw7+d{?zVSrJ3Hj~$kg@Xc^q+~fmm z(#u+M%@(=$S`TkG&fUsusFlo6T40YjPN3vc4~LjrUP&C|DPtObyC+6f;LXIOl2>k^bI|{51mopd?<3t>Se+PHO!Ds2l(bXm7 zWh^`(tqb~XzL#&3KJFQ%I5%;Z>RqoK+P(U;EOTQitHbUl2MjXDley7ldJRkglCApG zI68i=m`bl^xU5+@uHL3JIHKb6aJE?I5b7~$CJ*2HV|Dwdm%D44y>q*tI-zN0lo)7I z=HPl;=d{65#KISrS$y3GQ~z}h1+CXmHm8NsKohf>b?7q}X~`3$=c+Dj$K4U-IU$>8 zZDIi@VmS9HZMeoAkY3qLUW~wIuOkkxqsY<5RZ0Km3USX9C;WUf3`pw8b9k-5dDyLy z0~PydmZTd(XXl>{Mg*miEp*4kG#K3Eos@d5hnkYrK?pUXc-md)mgoVWhmS6X)(^QC zF*4bVWrePz85cEGqbb%aRAL<9^fYFM-F;HPPj+_mQ!00ms+;DVTONT;@fA=jT2vI1 zElcj$^ftB89Z~5WFi+^H;pD&8OJLSxjA5wn9<&oNB!|UB?7e9Y}i5UCN?4JO`}8FlBT9C2Evv zyI%^vbRiJr0H2B%Xarvx1%VXsj9II_Sgkot87uFh(y9ZzmTvBa&D(^bgAeF^gfe{c z-AX?Uq!fWK-Qr2o!Snx)tS3o+q#en^Sh^5BRxB*!n)@Cn1D^=(S+U z>b?E%mkN6EkhSx37m+Q@ZW%cHzaqBSiV0@+%sk&(w&4rJL%Hxq*5^(tzTNSw0c*lv zd!3ked47iu-yXuYX|S-- z1$epat7AthBlgyps50EKXlBk%iQbc%jxZQHZ^LFcDf3enhQ-2Mh;v6%w7xDdG?xh= zj3*1tr-Nw>#+A&%$Zvas-GO|y%Zc%mL73`0>g~XJFbb$rbCg+*zzAeX2ANNc@G%s~ zh~*C5uvg0N<0?6dhxE3WPDNBszZafAzq2~zr2PpI=Ln}iF{2u6Q2gu>2}Ltk{e0Tz z5e=BpLrf_~LLzVD^KJKRjh)!^A>na>;BiFI=7SkyguERLker@ilT;$Iw1qmi5wXx> zyL7crQS+0sjl6Oi5aEzxnM7+!L9-@{tFn>jZ7q64xhmI)e@n0A*a?7hvYBDdKbd-_ zhDqoK7#^|;55IE4oOw3=`1Nmu;uC3cc^s)kI}LlGa_`}lviH5~iTG-GmGZA{$V{qS zIg@(eg~((u4YxLbZaxANh8B5)S%RHpKnkU_jMN;?ShI#yv(>)@DYNCn4H(zBr$`XX zM~iin<902Q7Vf3<+a=t+xz_aj7wCO6RQ0cEm@(uYT+M+tX^=j6-=hPn{v(<0Ak{V? zF_1vuqC-`LyIR4PCCqO?t?W1sOH45`w!N?o2kAKvgGXKbT89^S`qSO~6<&#CF}Js2 z)2D2fYL+P*0FB0o(uM9^aEX`>E-RRn5jLNcdTzLdXsjtOQXW#Haf_K;Dm^IoQwAPv zAn6_2egPo;#9qPrfxt*W&0$p;ls)O{WyY~hDvZbw#jo)~Q<^Fqa=s8(sMdyeKeAq${44M02*yx?8C@z# zYb%i;0~T6zX8yr=#qY?FakC!sHZe~Fsc)+;ir?+_B-Yg*uCX*GABkx`&4JCae1O@g z%8n}&>ICyiiQE+3L%+RV+@=7 z2Z%(=8lDdFccRTNS~!})WFj8W%gAa7i`CwBgCZu=v4N2{9?$)OdpbN`{GusP-jKfQ$pUD8#O=*{Cp-s{o3%4zd{>=6ugvBGy%ybg<1y>|Ac5BZ zOdY@F%ee`)sPuhnM}|N6_*z~Zm#^MNggpQEH+|XzT}Fl64t2xQ85s)5QtS0Qv5w^R zR-&K7nOWh?$n9cJjwb%Pmp~Se-*kcTKm#v8&aA)l(%bHpi>}tzU(KJ)OdQxMx4&I9 zzC)+qfuz@NB%z`TGP>v8g7=5;c!#0_`%tth0va{qVFX8Ha>2j)i@TyVtb zPyb!0Lw>T!uIMT^JVOu6r!ncfJ3bJbg#qBu9JNQNX;m58gHWrg|R zLTBF~Ir_1{z>gHy+I3DG#u*128M4hmPu*S-Xbzc=T|s=hRhqQ_enpay;sV&sF0|e5 z>EKoiM_M0niD#L>&5q#lEx72zQ4f-HTHiBe&zIzUb|wYuy0+X2ZjH-}m@Dx|1LCO9 zFn6UToe>Rjd2FS_$0%sM*Z%iz5I*{@G#}QK8^-Va=e19YVz2u;eKFmSKD^i4FG`y7jP&BP zd4aAD)soD9wQts1?u47L?{5*+_c%vBDtJ>mH1Z1rAa^7&x+?#Xxz{-kxzC%&RRd2L z!J-Ch_T#GtsvLx)$eJX<+P6X+ho)SF8~dP5rX3`PO;o-~$9!c8GrL6^A)iN@Ol?1Q zTvkS@kd)UJ(u+C2i=>j+cH*hZ)n^zR%j(am_4eAr=tRGl;I{gfF+n^@`#n10A%#P7 zb0SKZrDMasXB+>(Z*S3VtWPx)c+qjGUV`dgRC91tDbR*su(2FhHPM$U+yEwx#{_zK zmJkVRQ@CY{9}~y{KdR52!=A!OW5ayCe*0nRZ%ex7ckG20cd~htO**51DGxyv^_r|!(#u1zb ztRiZ)%Bw9gwza&+bmF}yeMrFyJy7IR36ZBV9#&dPd82vm5?*aNcmKJVa-J%7b(Hu* zY{0QA7d&6fFXG-DeWA<0g!5|sh5S4Gcde*WMorbsngTugd_Bf|Fi6!3A(@BrB6#-- zeeTrSx-!uvW7ttq>T1K>chq+Meiq%5MeoW=vuB3-y7gge=~>(rLa;`a#z9WMV!LL1 zCNYhS?A6+C?$m*>><>;mvY_&kf}m%^&VSn3WSF`s+~N8Ytz_~II#X&ma?E*(u(cb~1%!VuXG1s99d7s9acT4}$MmxJ6FkvK-DGws zry5z|R23t)&d^xk)>i8SS`Y*v#QKC@2eoC6Q5h3ADqU%Z(+ zs@Q10NLi+hmTt@(Un1=)Xi^aDQYY124e-_w+ioHR=fK z*_@Ef6kAWoNkI?PZ}i?fhmSg4@NL{`#T&9I_0{4A1zrgY7?&1hYKWys=x_?Dh;S zOD1U14PSMX&r%{7%D#Tpw;REh@tBqwt>qR0Ela*SK_kPTTB{d~eR6x%P7|spP{e9z z$Bhryt9HnAJxDAZ{oI&snk=}bMdRO*JsDxB$K+_TUA2a6q;q^E`NU7@5gu^6C2z`9 zHvV({&Fh_J`dAn`#NlK`OD(lGiivhU{^2k#-Ua+2@(!fyrBog@je&}=c<&R;^~V!lE3^;n}CB)b_i@6 z5Km4h)S(z z!@X|a18MvL>*$VjFy-8WrTa03XVnTinr)@FX0?5JfGo)!8(X_?CzY);Cx{N6n}PX} z-tLq9Iy*B+X)mYQP-)lC=PR&a0dIw<1hE)z%e2|_&z9xex`BNyx&Y)`A%9>a?73U1 z-q)f+mgDgdR!nc!&SA0+fkXgzEeud2gl8R%jY73-LfD(DW~kjBdNZz*UF& z>cR*L3=OtFMNXv>nrU*sD>h>1LqQlY!olZgS08E-v$vDmRW@-uHxG-d3z2M4=P+r;o0_~)4(@ohvaq-h;IPv4i5|(nhw-hNU-T&$l)9__eNqg28LQZi-w@%>*3EPb3$Rm%%?> zW$21qu!4DiEsrV*z{{)1Vv%7LwZi~rmV^j0^ql`Zq>}Rl?-p%Y zYt8QoI6wRtneeTZeTt4+Q*?F}DP1Y}$bk<2(%t_k>ZN*XG{^FpFe2)Gc3VGcZvl46*{RCBn&6aa1pA9?@fvrPI$>b_Rw z>eiJw+?!!5-^hla6nHpC^WvA-N8%hK!^22tDW%K;sO@v7;9@%BoUa_JXVN-AZ{aB% zB2;yT%>)0gT7k2J4O1)ps_8sBsY4%X35Fk$Ye1Nm!&)?o>fc4~WfRQCqMjSprvlY( zSUj#sJkBrQKAsYkcS+TZ68`f7hKVjMarrp{zq#&sqDyZgk+?hAkC}*L%VCrlE98P$ z_VuiiAKwEcaMq2v@;u)}!VUY`?w$z%0;e7f17jrwi#ept^Q zBG+Hc@OVCSTc#y}%E~8VR^J;=h=x9*bHES<5ZlBu)69Fv zp;UJaiFnjvMS^=iE^B?mYrxz!A%<*Dd!vNdA02O^(#1gCU#B|-LacaFIow`tS-r;^ zSVDJijHPeJ>0{n_-x;89{{#wqeeu{PuBE>BL6n6jVK7Oc)#S>4QL65)&u7TJ#qh%I zYtLDzlUcD(<+>I4nat7Jm9&z6FYvRqN%fK0>v1Flo?CG<$QOlqq{*3f6~0NQn^Xwy z?d-jKgxIl)01*$4*2@_DB-A>#aU7V@GFvJ)YCp4Uvi+l9Nz^B628m|83se*;rLIV5 zfY58*Rz+Rn81q-p%8O@@3Kma{zZE`9SPtL+ZS1@w7QuS0^j9^rE`Xdu4e*|TK<3;v zknAfP`IlH0Ii@Z}{v@H74Vb@`j#?rFwq%)B1j55^jlFmOje|!2v@qIbp^2hS2bavN zyI*uCCHf?3veY8elb3wYsr}NjbY<5ptFHJqA_`ZPlejsmESKYMhbm&FOi1$nj+zme%Lt?6~AH!b;*yK zwE;m$eL3>$K|Npg`JVRZjW?a$sTztwEATn0I(7351$KF;c}U=xGZ4BNI+XB=1|1@s zskXLA`WxndEDcQaR4=9J$cS^NDFvys3a*?!KVE@qe)fv)+s*5p$5?K(`bT4d*q@)0 z${EfI-tB;-t63jE;E>-kmi2@Kgs+aFW@4S6b@{yV>MoVR*L zyG5F!V8JJM87fG^=`%Z=Vc(O3$@az|!#v(5E z-0*9{FO<~+wdUvgV2AxhhpP^&>0|D|y!=U_uRj`@;nm_QAti=)H+0wxbDd8mk^mA^4zx5!@JZHH#DIjOGoQj0vP z8?HmcH{v)0aGUxJac8*sA(vw2=HqD9OF^tLJ%Im-#?jjPu7$ zs4QOagIYQ9=cGA6pSG+P)rGJvOyhgxrLX>&Mkusm=VAnxyF@A>+YA&gcR*`!_oa`f zauUUTBh#eDHqQebGoCi~_3?m{M zF=#8W2CDFHvqSimjqc9ubmmk9V)+!N(b=q7(Kku&M+)$~7-EMp07CRGclTEeK`h-O za70njbH}H4NRV>(m?OwIc1n%%mcoxbS0lIGH*AiMB-(ngxM_i*NiT%*nfe$yTKAUS z)nn32kZ>goy&FTy82TlT(9aNZD;-`(##`H6kiYC=sGDYo$O-=cQ-SRVnw_$uEAexd zbVK(vu_|M9azBS_qE34$XK+#O*9{YrA#nax;#gl` ziZ2ZvlHi!16o;elfYn3&`tw5iYk8C*H1?Mj0~E14c(R}ii1oaX&XCtRnLb9NTeho{ zXc5_)DzKE}|JbWKkf~_D55x0?(P?q&3ezr_rfh7c=eb{Wsvoak1EMp#Nk6-~*MiDk zl#C@yf}x`I(BTe1)L4|<6ugZ$JXe*`2kSbC_T7K?5YEGG_K+*gF=GE_jW)bWU4~or zR1H5)*}kV2Zvtv_dm-7I_wIuE!F`Sf7uwJCD7At8E3b9h&)BJ_q@oUv++VW#O!R4N zDqC-rTnXKh5HnY)2ry9}a{moa%^ zA#lETAyEV@p$WF6E--DGH)J>uzzmd6Q68JiX z0ijl`jGFh5?Cxj?x_xbRerxp~)ivgl;WWN9dyt3NBRL>aZkOF0xOePPlT0YF>y26Ey>MC(oQCbbF1 z!MN(Meah^IRih6sFRb3SEO>m)tYS8@69tbkvj3rk7ldx=dp)SaxEbnYu9QZ>LV<3+ zV@wOpil5i4BJyWmZ2JfjW@jw|KU%O@HO=ahTp0t*qVu2eLsTq|dkr(l9nUo7LX@>n zJ1y%8mpUF!=E>9wl*hYsO^vs$gCf?4pV&ZpJI;m9{-RxxVNw{P0ERhQ0SJFkW`~py zH%EEagqYJTy4ETMoJQ&oD8{|oD+isNJ1g^sohi*$I{SSOcf_V11i3>_`Ks%yt=Cot zuSe#oKSqhVC|*lqfE8!bUM>Eh)ce5hcWc}72sILy_MQWfKhFoMyygF-8#ni+C zB{z;;#!>4tzSZ7ft51XbVpm#nlx8^we;>5S=8rHe@}Jo5r>qIvEwR{T0(pZRVKRA4 z6$M*?p!=ZdL%p5WbjM(#GzIMiqS zU5`o*;dT%x4u;qC=@R5apQKcC9Clu{IwR$dGZzik-^y&#GKltd5K~NG=b!0D_MzzR zG37KmWQy+sY4>>J-zbX7$Rl?;E8^Ro%nUap2dO$=>7^CWWTo7{f4w0Gz6rPB`vNVMdPx_)bvK1~2u5>jS~>1~MIGFwjDNj(9xwxs8V z@g}c3V8sbaSsf}l?^-O3NrFJCN#!aiQo*X|-?+iNh=^|P{70RQ!RtXlz=-7cX${5# zK0_(rx^h^p;-Z;o^&zDZ;)qpqq%5V(q)qWU2fzApf;c@&7YPpX%UW-}ZEHd8xn|p4{`rHr_*o{yTQF`ho?!S_?@!Pp@ zi=T}M2g^bB%OR%d0FY~1w{J~~BTQt&S6ku9rs$*zQq z$%iAhcI2c8r(`HjZZ!=M!T-qs#qs3cB(dBn)i<);$yy+wp zKX(45x?ZJtMRbxjFXcMX&m{K!)@7N;!Q6(~X0J+0`I%ek9@;P{kA$IwM5=_<6vH3K z^GIK<4D3T}v?Ads8+SwK23ln6&KSq5c#l^7oA2Q^u-^)w7~36#%v&a?IjgP?I4}4HByE-|2;+_3snH#mw+$-7oFo^I!^F{2HN*Es0wJ|tllT#GG&rq{S+qeP_ zEB7!g9#|)Mqode8a$aAu57rXHX@P(x`pXrH|Nb_%B?Uc57p6M!Ea=p&04oylW|CZ$h7ePz3iYFk zox&R&l`108Fj90~A+<|y7;c4RO4`14tmTA8#&EuGcHH=`6L_Xc8-DI%vEe96sId=C zeHd~_{@Bp6LgH13!haO!i+Gu2;lr%ueX=-QfuazE?`(`EC zP|;&=)=fQib`lX{^v1^eS4)SCT2crlcsGW|MJ=7|O$M%& zDPz4gCyokQf8Z^HrtPCvW0gbt&XXwB6C)7N9Wt#}fsdzrG=a!C!(0=pQ?HZ zwBX=&Z~Y&~EQ%!XcFL!~2DbZ^xYZwCecMphQZDZW+Ibw2y_gIA~piaCWsMSp=hY~qk{oHnb! z;E!FZH)s8cp(ZOv9ob-?WXFG6HH(LR(};06q(7+J*qGM?OeoG-tyah=pPjW+CYi8Q zS}1bN_nq|m(Ytuf3wS`_(&PD{ie!CSLq!Hi;GWag3roPiVT#GjkeZPw8~t3VHOPnu z=o@D}MFk3f__n@QHX{NG? zE^|NwT9Q3>yfS=YSoJP5E7CX)iOl#o0E%jDsA;rV_Z(xfL;^6`R7S`4*YEM+8$?Es zgtQ3tI_@nB>dP38;U_g>UeRqdzkSB-6$$gO$*`NR9tmfC8WGbS#(=W;uHcKxTS&S+ z1M8oiq;-mV2an1=Cyk51K_%|vCD~>%)c|!ZO8)00WE?rll z|G3~j27~yOEzUB5rk~owsj_CVq+H7oa*G{~QVIJG6#JrsLV}ZZcAXiQSkz{4zk|W; zj6rK|XuqWmf$GgnY3o7`bt(O{BWm?zc2|gq`}8v#slh0`W(4*RB^CA&wtIAxkqp`Q z9F^HZV}VElyZ}+NHAD5$mhfzFxpOI3J&n9AumcS!d)N7Euu*zik_~)O5r%snv#bnu zkc!$g&I?89A9GHbpnu%^%zW>t?29aHczwx{UNi@H={~ezB;df9ri@Xaf9;6!W|V^G zMI&;}l?+YNIn^7_cO!}_p5~GQu?RKHT#y|5-eD1?_t2;TjC-i?z0b=fmDN7`x?p)` z;{U@8z9fcfjqfBjJ!tage@&~b=tm&mWaN~clej#5#c4vRPLj7^%sS3uU=~WiQL6WA zSA@r65}mstI#(O>Gk7=s_;LC}FT#?@6q?o-KC(f6Fly|7y=*mvdefed_1~JiNTF-X zOTq~HX&9+PUuO1r$K}*`BU)5;Y^AZvsq$1H+So*IA-s@CNPl4>{gqG;kDKnv^&VLa zxsj@BGE3lGslQwg$(BO9u;1#$2wn{X-yfyae+GkAK|>)P;2$ky4Fx5pmTugUDD(b- zI~EJ4!}s-JlDui>RfPef zT|pRtLf5i2Ja8x3f!y=W_#g0H1Zg3XW->>dy4L#$Qkil6*K){>oE<}vxqA^JB$~vf z@LSSMab#2uG^t%ayYxDGAFN#lt;@L8gZ2fbp_VSCVF>e|1~W9yZJYL7Rm76oD8%<6 z(*}3oz*ecvJ|BQ0UzEbD2Q0Gun@aEKs{m6P-9-SC)k*b*V1}6fD+U7frS*SHUP=U} zEc_h8)KU05UbI$YbyJ`CQVNgU?znwf%k_ydmXcQ2l-Imu2N{c2yAH`kw6a|uQK2yd zZoi4V@ltk4F9BDlL%=FKgeOE*qW>*R!_Q`X>(Rn81a7UxI(U3|)K_d|D)##&&${Y- zZx-BR8Rp9oBJ*E>hTwPk=!f2Qh1}&>2ojZ9qy*u;FVADOes%Aa9dx{Wnnh@|gi$n% z6ZSeY+*QsM2#75u>M2v zf+l?q*jwDr3H{y|{Yi9nbuF7$k6ii`zU{TmaKxpAu%X*$S6PxUfei4eG0%lNEbUDGC<=Ml zeFN8*?&^qYwAy+2>IgHeX$`er%$^>I_h1~Dd%iE&Umn_|%#Q7s#87+RO1p^+f9MkA zvz^dBJJ%OrG^_IhfTD8@H1YTIta9V#$9Xu5G6L? z`8D4vIi_`&bDo37Y~Q46ShllOMrGuRQCtY``lKR7{VPi@YmwusLiUo8>O%;tMrQDl zc2RywpgDGwSr4jQ@(1?laKq-QMUOAzi)IZv!#K1}MR%?+WVgMjU6q?z{FH;?(3^x1v<>}R=f27c=Pmmnav%bh!d!f>!7?e zk)VtiOoXMc-Z`;fUTlWY<^pe=P34%J+ShdEq@i$OFD_dO7Ly;i(ccT1m@YemMnRKX zW!&CRw}+{$TD&0?(KN{*SC?ZBu2f|c-)$J&3i;4jD)rP8OT*frMN@Edi zmRjIgbcmll1bLQnElwbkx;u{QQduS=S3-0r5t>mT)Z|~sMhGQ16Lc~)HHF@M8sNU_ z6@Ke|I^gc|ECh*f@E2636~LuMRG=muaz+9Mq7^YM0WfPr+D+Kl#A(VU?3itqE?n0) z`_3NEH-?!_2dd1ZJu7cwuZ0$VCbx%|pVv+n0Vd26tvV1$=KC^W;&)@|xA2c#8eKWe zO~Kyl5^O;FPPz52Wp+(6sqTuhc2C)&84H-qTnbTTzb23s5(BO_Ivq|+llBh^J+Sft z_I`>$QBdI z!RD>QS2x}xDAI;rudRN{t8pU$!GyP0sB8wOq-iBqA%+b6-1*q3jq#er(gDY)OICMwbL>K&c77~oM(KAlm!lpS;+>J+YmmY?0& zWo+jKqHEUm9=P@sl#Z~9=Z+v82)%F~@qpL*z!odyB8{mXK z=r8pxpPUJ3?u%{}bebE}PUP)pMGoU^7B|^{Ve(?A;rqN{cFXv~!$ZzgJ!eZLe$t9w z*PVP<5ez=rk6OenvdQ(PJ%DX?l~d7Nu&)8|#A*34afI$$c!=jF7oaD)^L=;I3ANxl z-@BJP1s`jAKUsnlVtpO0O_$_{qCwmMR+{{wv(>-io7Qr3f`(GmhR%sY!lh>{!9wH| zXzJ?URZ2B&lvsN5^XkCCv9FP$(;<%edxf$c71`C*f2nE=+wX2qh|wnN@M(u(z!;cS zEoaNZ!a_S|%LV9C$Y%#DSH&bco;ZHB`1^yE1}G5?LWsdo3qqGbLOBa20-0a{wf^s= z`S5m>x8O?F{VsK6<@fqFOj;;DgxDkSZcXhuFAFdYA7d_7#K<*9m^6kIoEajh-?Yc* zCHpWHw^B~Z-xL^hL2*92&MSH7Penclj?q|-$VKp%v~hD0HGU=zch={&XtAYCnJE6c zB?Vrb7?xv%>b~v%G6RFp?WRxpq%ULwA5Xh2uNR}TAlIce}xENA$Jn6F4k|O6+o6=0_w)9j4egF8_;9WpkS5=pv zC``@AU>O?lpZ&ZVJk;6??6{FpE&BTg_6hcpA$545)rmB~~m z@klB;2VX#(Ya*Z1A2`Wb0+nbcqgOSAJA(|k=fvcY{71|d$g|o6^QeL*V6Y`!B9W<0 zMpo~8`woLhz$yK& zU?tqv;doVo*Od3Hety{zfef|ybTQ4k);(GB(cy5lj`S~r8U#SFj7?Me+~LY`0ccr5 zJf>nq;7SMDW1FoOET1ALvd-WvB@!vFfjdaYk)#J|HK9uCGS_3G{YtkZ*SFDMA@T>F zI0HVX>q%e0`-L|PI_8Vzpjlc>o3fa+;h&M10) z2M4`WSk!YxQK#8+hjf`s1p;aMl6Ly3Y)JXI^0y_LDLepqP7HvS3L|Q5XKe{}D=y^x z8KkbA5vVwuUgLE%f(>AZby$w3w+`F+yke0p`URCeFW;UTm4*@r404fNn)#mm$n6uKbLK=io+G#AY z3{v}2DhVx9OBqU}K{d8UOQ~hv&h^drKYZ6U=g0HIIq&tHbKYmUp8LLUe{*-!d{tK~ z%cmp7T+A4Lf~T{?_iIcXnQxiDVqE1z!e+Y&XT4@yFKIE=GS$k8c*iOq+SzD4tI|;b zk;ShzC*sewe%QUTbO15%-|dQsS{A}$KB}4)AX$Ap1@opjp)B1a%qGbkHQX@=*S5xU zw5NkcdkdQZHot$Rf!2)X19VDY7#DQTm@_&j29Wi7jWC$cNBO&`eIG^=qCAeC?@jHn z_gS-HT2DfJ8^~cdLa`ZA6YIaf5@Td?7WXu8{LM{`00sUbdM;+rR+>Cui&+LuW>D%E zq`bo2`M39D&*WL)5R&83viC4K3sUxH({<&78f^!ak%Y`2sv#PP-guzM+0i58KeuP< zKX-dfc#hxPBmt5JMxw7Qt4@F~&ePcI?bxA z!=aJw`B+7oAkimyu!iPtWVSo1K0LT)M)7+if(KB7%{H7V&f+R3sUDzLa8^q_TCSr( z&YJEVb&>G7*%24w4^DnWnMs&D+orF-)|rV1!X*-|&CXEoN>lt14HS~SlH;>6vfUYI zo1{S&>8(k2N8nP0>j6V=TP{R;>A5C{Li+Y46F*P*+|W85M6Mqs8dPml{o0<$=)8iC zWZ>1)Bl6xTuRvLhcyiW58IIMZ{r!XdaX70&;g@?qs>Cs~y)CczB-?_M)U zr1AY74qIF@Y}JZkKRfz`;Vmi{ukOJ`7c4jHyV&&}Yw#7`J)l(NMTOI2MUJ zg-sg!(jwvlhZ`z7N_vGqek}`~xDZ6TrMv*fpqWiiW}}+~Eq6b>iNJ0n)EhtGYI3z# z23q`hg?xC7ayUj*iDUI*W~Ny38f`XC2VknKW!cAb?8Bpo=`tvzU1#<81l67vy6Wgn z&Sl@iR=?8X7yA8XW^&!zwICEEuJx1z%=MF72+Vz@(YQo?i}x!VLQ~ecpcS3_3C*$6 z`o48^Lco^D?FO3mO5(XV^_I6W2h9c0!X7^TN8+Spn30VTUYrdRZHedQmG+%KVHH*0 z#`CvRrH_L2i{6+9)AiP!BcaJU&A!6}>gQYV1e2%l=#nFHARw8p3H3J2c$n+$rd(YS zM6jG7F9(Hj*-?~?{QE}>#u?g}sD?{pr%(OT>v8d@F2EzQyLX>xjkozCcz3$^L5R$6 zOq!VEz~d23B?=HNru6ZeYVU|Cew`fHpsQrhyr;GkciQMqU2LsoaX)R5bwI`}4Odh< zUj{DebJ#y}e5i&!k|d+8?Au(}jYQxL&Q_D5UeJO&jhp)n+^HTl0n5Nbh{3feC)W(Y zW9O53uDhB_4qD>7Lp~Q-y|2I(A&80}psuj5@Qi>hE5?!qn(7yoqNL={Cz}ryR)UW( z;!u}EBNX^ITx3-eBe5sBc>9Q`9n~y-#es}*AM9c`*^_#5{B{Drac!yU0~)5WgfZ2S zr!{T(NcRjkQr1ajTKl)bd?N{sLE=YFXI=P|o_%8QF#m}R3i$m@Res^k;qPO4;6GLo z`%-XdannzACj$|7gib*g98{Y!U(sjsHxlx}CE!EeD3!e^H6ErpSy7(=>zNzI@W~Cj ze%>?B(kFXl3oT_|j;2;X2{RTLe`}FHqQCAoiRwXu2gMASp%Q+%(l=nJuBD-i<~A6{ zO$YRK&|Dkn_VT&^wAG%^4BhMw==h?z!CRO!E$gBCT9NANhtxLrhhuEALX-T_1E#tIDJ}V}M%7`cGSIslF@SYUK zo}9-j=B-hp10G1$r^L31u${WX61%>9)uQ#N#%VPv1B4rl8$}ucJY}RPZzd>{VyQ3T zQWg;9l^D%+(W^UPx#&%r%G@OybS2exeUb&qy|}IoN#xuUzK$?G9HPp-gpcxzV7iEz zPvg|${)in`z4q-A4W*2|Y)Ex^TvAYTbzKG;t@Ee#MmN7hMNUytDL{ObH-<$YNw2Y( zn<-+oiifc{l|$SZd3)kT3Os*dCvnGJ_fiyh%C7m`y9TCJf1QXIh<3;%^epSVT>D zgSGX8+YgJ|Ji*GERVNKWapGa6Y zi)i|2rrxKe)D!F&8xb&Xl~?htG9UT;*SybJy~wQMW-ODSQ|?J5Axw!4E5LfsqVwnZ1VbcAxQe?a!2aKw5<*?ZZukp|6w;=WjS?#|hZ z*7=+La|+_N!VFpDmZPvzig>Ou@Zx|8rEf^Ce<%L6$G_L%|LZl-iHC|blfD - - - - - - - - - - diff --git a/apps/app/tauri.conf.json b/apps/app/tauri.conf.json index db4ef3624bf..ad9862a0400 100644 --- a/apps/app/tauri.conf.json +++ b/apps/app/tauri.conf.json @@ -55,14 +55,14 @@ } ] }, - "productName": "Modrinth App", + "productName": "Owyx", "version": "../app-frontend/package.json", - "mainBinaryName": "Modrinth App", - "identifier": "ModrinthApp", + "mainBinaryName": "Owyx", + "identifier": "site.owyx.app", "plugins": { "deep-link": { "desktop": { - "schemes": ["modrinth"] + "schemes": ["owyx"] }, "mobile": [] } @@ -77,7 +77,7 @@ "fullscreen": false, "height": 800, "resizable": true, - "title": "Modrinth App", + "title": "Owyx", "label": "main", "width": 1280, "minHeight": 700, diff --git a/legacy/.cursor-old/rules/agent-tool-catalog.mdc b/legacy/.cursor-old/rules/agent-tool-catalog.mdc new file mode 100644 index 00000000000..e6a242683d1 --- /dev/null +++ b/legacy/.cursor-old/rules/agent-tool-catalog.mdc @@ -0,0 +1,56 @@ +--- +description: Public agent-tool-catalog pointer — always visible; fetch the live README only when choosing or adding agent tooling +alwaysApply: true +--- + +# Agent tool catalog + +This rule is **always present** so every chat/message knows a useful public **agent-tool-catalog** exists and can be consulted when the task needs skills, MCP, UI tooling, or other agent tooling. + +**Presence ≠ fetch.** Seeing this rule does **not** mean you should hit the network. Do **not** `curl`/`gh` the catalog on every turn. + +## Fetch gate (mandatory) + +Fetch the live catalog README **only** when the task is about **choosing** or **adding** agent tooling (skills, MCP servers, UI tooling, or similar). + +Do **NOT** fetch on unrelated Launcher, Rust, Vite, site, or other product work — even though this rule is always in context. + +## Canon sources + +- Repository: https://github.com/ebluffy/agent-tool-catalog +- Raw README (authoritative list): https://raw.githubusercontent.com/ebluffy/agent-tool-catalog/main/README.md + +## How to read the catalog + +When the fetch gate above applies: + +1. **Primary:** fetch the current README with `curl` against the raw URL above (e.g. `curl -fsSL https://raw.githubusercontent.com/ebluffy/agent-tool-catalog/main/README.md`). +2. **Optional fallback:** `gh` (`gh api` / `gh repo view` against `ebluffy/agent-tool-catalog`) if curl is unavailable — note `gh` is often unauthenticated in cloud agents. +3. Use that live content to pick tools. **Do not** keep a local memory dump or paste the full catalog into project files. +4. **Do not** dump the whole catalog into chat answers — cite only the entries that apply to the task. +5. This rule does **not** replace `AGENTS.md` or other project rules; it only points at the external catalog. + +## Fallback if fetch fails + +If the catalog cannot be fetched (network error, 404, empty response, auth failure, etc.): + +1. **Do not invent** catalog contents or tool lists. +2. Tell the user the catalog fetch failed. +3. Fall back to `AGENTS.md` and other project rules for guidance. + +## Adding entries (user request) + +When the user asks to add something in a form like «добавь в каталог: url — зачем» (or equivalent: URL + short reason), follow the live catalog’s **How to add an entry** section (and table layout) so this rule does not drift: + +1. Pick the right section in that repo’s `README.md` (UI / Process / …) — or create a new section if none fits. +2. Insert **one markdown table row** of the form `| YYYY-MM-DD | | |` (do not append a free-form line outside the table). +3. Update the `Last updated` date at the top of the README. +4. Use a **PR-flow** in `ebluffy/agent-tool-catalog`: create a branch, commit there, open a pull request — **do not** commit and push straight to `main`. +5. Do not open unrelated PRs in Owyx for catalog-only edits. + +## Never put in the catalog + +- Personal projects or private-only tooling +- Local Windows paths such as `Z:\...` +- Secrets, tokens, credentials, or env values +- Private / non-shareable URLs diff --git a/legacy/.cursor-old/rules/cloud-agent-prompts.mdc b/legacy/.cursor-old/rules/cloud-agent-prompts.mdc new file mode 100644 index 00000000000..15b935695cf --- /dev/null +++ b/legacy/.cursor-old/rules/cloud-agent-prompts.mdc @@ -0,0 +1,50 @@ +--- +description: Как писать promt.md для Cloud Agent — коммиты, AutoReview, один PR +alwaysApply: true +--- + +# Cloud Agent prompts (promt.md) + +When authoring **`promt.md`** (or any paste-ready Cloud Agent task), **always** include a **Git / AutoReview workflow** block. Cloud agents tend to push many small commits; Cursor AutoReview often runs **once per push** and may lag or miss rapid-fire commits. + +## Commit strategy (pick one — state it explicitly in the prompt) + +### A) Single commit at the end (recommended) + +1. Do all work locally — **no push** until functionally done. +2. Run checks (`npm run check`, `check:rust`, lint, smoke) locally. +3. **One** commit (or squash locally) → **one push** → open/update PR. +4. **Wait for AutoReview** (see below) before declaring “ready to merge”. + +### B) Multiple commits allowed + +After **each push**: + +1. Wait **≥ 10 minutes** for AutoReview on the **latest** commit SHA. +2. Poll PR reviews / comments for `CURSOR_AUTOMATION_ID` / “Sent by Cursor Automation: AutoReview”. +3. If AutoReview comments on an **older** SHA — either wait for a re-run on HEAD or push an empty/amend **only if** fixes are needed. +4. If **no** AutoReview after 10 min — note in PR comment; owner may trigger **TEST** manually in Cursor Automations. +5. **Do not** push again while AutoReview on HEAD is still pending unless fixing a blocker it reported. + +## AutoReview block (copy into every promt.md) + +```markdown +## Git & AutoReview (mandatory) + +- One PR; **do not merge yourself**. +- Prefer **one final commit + one push** when work is complete. +- After the final push: wait up to **10 minutes** for AutoReview on **HEAD**. +- Final PR comment must cite: last commit SHA, AutoReview status (green / manual TEST / pending), CI status. +- If AutoReview is red — fix and push once; wait again. +- Do not stack 3+ commits in 30 seconds — AutoReview may only review the last push or skip triggers. +``` + +## AutoReview not firing automatically + +If automation is enabled but only **TEST + PR URL** works: + +- Re-check Cursor Automation trigger: **PR synchronize / push to PR branch**, not “PR opened” only. +- Re-authorize **Cursor GitHub App** on `ebluffy/Owyx` (repo rename breaks webhooks). +- Ensure PR is from a branch in the same repo (not fork without app access). + +Document findings in PR comment; do not block on automation if CI + self-review are green and owner ran manual TEST. diff --git a/legacy/AGENTS.monorepo.md b/legacy/AGENTS.monorepo.md new file mode 100644 index 00000000000..f091dcab6ed --- /dev/null +++ b/legacy/AGENTS.monorepo.md @@ -0,0 +1,82 @@ +# Agent notes (Owyx monorepo) + +Canonical plan: [`PLAN.md`](./PLAN.md). Design: [`DESIGN.md`](./DESIGN.md). +Launcher ↔ site API: [`owyxsite/LAUNCHER_SITE_CONTRACT.md`](./owyxsite/LAUNCHER_SITE_CONTRACT.md). +Launcher build gates: [`Launcher/BUILD.md`](./Launcher/BUILD.md). + +Do not expand local `Launcher/PLAN.md` / `owyxsite/PLAN.md` — they only point here. +Do not commit `.env`, secrets, `*.exe`, `target/`, `node_modules/`, DB dumps. + +## Cursor Cloud specific instructions + +This section is for agents that boot after the update script (npm installs only). +Standard commands live in the READMEs above — do not duplicate install steps here. + +**Product split.** `owyxsite/` is the control-plane (Next `:3000` + Express `:3001` + +Postgres). `Launcher/` is the client: **native Tauri** on Linux (WebKitGTK) and +Windows (WebView2), plus Vite `:1420` for fast UI-only preview. +`owyxplugin/` is out of friends-sprint scope. + +**Site DB.** Compose wants Postgres **17**. Cloud VMs often have **16** via apt — +that is enough for local API work. Existing Docker volumes do **not** auto-apply +new SQL (`initdb.d` runs once). Apply `owyxsite/postgres/migrations/007_servers_packs.sql` +with `psql -f` on old volumes. Backend also runs `ensureCatalogSchema()` on boot; +those tables must be **owned by** the API role (`owyx_user`). If created as +`postgres`, startup fails with `42501 must be owner of table packs`. +Launcher-only PRs should **not** edit `owyxsite/` unless the task is the +launcher↔site / VPS contour (this file’s site notes still apply). + +**Launcher — Cloud Linux (primary).** After `bash Launcher/scripts/linux-dev-setup.sh` +(WebKitGTK 4.1 / GTK / Rust ≥ 1.85), from `Launcher/apps/launcher`: + +- **Primary:** `npm run dev:tauri` — Vite + **native WebKit window**; Rust + invoke (catalog, install, skin-to-disk) is live. Needs `DISPLAY` (`:1` or `:0`). +- **Secondary / fast UI:** `OWYX_API_BASE_URL=http://127.0.0.1:3001 npm run dev` + — browser `:1420`; Download/Play/skin-to-disk are stubs (no invoke). +- **Compile gate:** `npm run check && npm run check:rust` +- **Smoke:** `npm run build:smoke` (or `build:smoke:linux`) → ELF + `src-tauri/target/debug/owyx`. Window opens; logs under `~/owyx/`. +- **Windows Play / ship exe:** hand-off after merge (MiniMax on Windows). + Do **not** treat Wine + `Owyx.exe` as the cloud path — WebView2 stays blank. + +**Frontend lint.** `owyxsite/frontend` `npm run lint` should be green after the +quality-pass AuthProvider / profile / admin effect fixes. If it fails, it is a +regression — do not ignore set-state-in-effect on auth. + +**Site + launcher together (Cloud).** Prefer Docker when the daemon is up: + +```bash +cd owyxsite && bash deploy/vps-up.sh --dev # or: cp .env.example .env && docker compose up -d --build +export OWYX_API_BASE_URL=http://127.0.0.1:3001 +cd ../Launcher/apps/launcher && npm run dev:tauri +``` + +`deploy/vps-up.sh --dev` sets `NODE_ENV=development` so `TURNSTILE_SKIP=true` +works. Without `--dev` (VPS): loopback binds + host nginx for `owyx.site` / +`api.owyx.site`; `TURNSTILE_SECRET_KEY` is required (`SKIP` is ignored in +production). **Do not** add `panel.owyx.site` (C³ CELERITY). See +`owyxsite/deploy/README.md` and `owyxsite/deploy/OBT_PREP.md`. Apt +Postgres 16 without Docker is still OK for API-only work. + +**Hot reload.** Backend `ensureCatalogSchema` only seeds when `packs`/`servers` +are empty. After changing seed SQL, insert/update rows yourself or use admin UI. +Restart Express after route changes; Vite/Next pick up UI edits. + +## AutoReview (Cursor Automation) + +Cloud PRs should get **AutoReview** comments on the latest commit. If it does +not run on push: + +1. Prefer **one commit + one push** at the end of work (see + `.cursor/rules/cloud-agent-prompts.mdc`). +2. After push, wait **~10 minutes** before marking the PR merge-ready. +3. Re-authorize the **Cursor GitHub App** on `ebluffy/Owyx` if webhooks broke + after the repo rename. +4. In Cursor Automations, trigger should include **PR synchronize**, not only + “PR opened”. +5. Manual **TEST** with the PR URL is an acceptable fallback; cite the run in + the PR comment. + +Do not stack many commits in seconds — AutoReview may attach only to the last +SHA or skip until manual TEST (seen on PR #13: 3 commits in ~4s, review only +after manual TEST on `0d70ac0`). diff --git a/legacy/DESIGN.md b/legacy/DESIGN.md new file mode 100644 index 00000000000..aaa76fc518a --- /dev/null +++ b/legacy/DESIGN.md @@ -0,0 +1,194 @@ +# Owyx — единый дизайн-система + +Живой документ для **сайта** (`owyxsite/`), **лаунчера** (`Launcher/`) и **плагина** (`owyxplugin/`). +Цель: один бренд во всех поверхностях. Использовать как ТЗ для редизайна сайта и облачных агентов. + +**Репо:** https://github.com/ebluffy/Owyx +**Обновлено:** 2026-08-06 + +--- + +## 1. Продукт одной фразой + +**Owyx** — экосистема приватного Minecraft: сайт (аккаунт, профиль, косметика) ↔ лаунчер (сборки, Play) ↔ плагин (логин/токен на сервере). Игрок узнаёт бренд за секунду: тёмный космос + **циановый** акцент, без «чужого» золота ванильного Minecraft-меню и без фиолетового AI-дефолта. + +--- + +## 2. Принципы (обязательны) + +1. **Один бренд на всех клиентах** — сайт, лаунчер, сообщения плагина в игре говорят одним языком цвета/тона. +2. **Brand first** — на лендинге имя **Owyx** — hero-уровень, не мелкая надпись в навбаре. +3. **Одна композиция** первого экрана — не дашборд: бренд + одна мысль + один CTA + атмосфера. +4. **Тёмный мир, не серый шаблон** — глубина (градиенты, туман, лёгкий starfield / particles), не плоский `#111`. +5. **Циан = действие** — Play, primary CTA, фокус, статус «живо». +6. **Карточки sparingly** — только если без контейнера ломается смысл/клик; в hero карточек нет. +7. **Без UI-мусора** — не пилить hero статами, чипами, плавающими бейджами, тремя колонками промо. +8. **RU по умолчанию**, EN — полный паритет строк, не смесь в одном экране. +9. **Доступность** — контраст текста к фону; фокус видимый; не полагаться только на цвет. +10. **Фаза 2 индивидуальности** — сейчас выравниваем токены; радикальный redesign layout ок, если токены и тон соблюдены. + +### Чего избегать (жёстко) + +- Золото/янтарь Minecraft-дефолт (`#FFAA00`, `#FF6600`) как **primary** на сайте (сейчас legacy — убрать при редизайне). +- Фиолетово-индиго «AI SaaS» градиенты на белом. +- Cream + terracotta + газетная вёрстка. +- Inter / Roboto / Arial как display (лаунчер уже кастомный стек; сайт — выразительный гротеск или уже согласованный web-font, не system UI по умолчанию для hero). +- Glow-радиоактив, rounded-full пилюли статами, emoji как декор. +- Inset hero-картинки в скруглённых карточках вместо full-bleed атмосферы. + +--- + +## 3. Токены (source of truth) + +База — **лаунчер** (`Launcher/apps/launcher/src/styles.css`). Сайт и плагин подтягиваются к ним. + +| Токен | Значение | Роль | +|-------|----------|------| +| `--bg` | `#050508` | Глубокий фон | +| `--panel` | `#131319` | Панели / поверхности | +| `--panel-2` | `#14141c` | Вторичные панели | +| `--rail` | `#0e0e14` | Боковая навигация | +| `--line` | `#2a2b30` | Бордеры / разделители | +| `--text` | `#f3f4f6` | Основной текст | +| `--muted` | `#9aa0a8` | Вторичный текст | +| `--accent` | `#00e5ff` | **Primary** — CTA, ссылки, фокус, brand | +| `--accent-ink` | `#041018` | Текст на accent-кнопке | +| `--accent-violet` | `#8b5cf6` | Secondary highlight (rail active, редко) | +| `--ok` | `#5eead4` | Успех / онлайн | +| `--danger` | `#ff5c6c` | Ошибки / destructive | + +**Радиусы:** 8–14px для контролов; модалки ~16–20px. Не «таблетки» на всё. +**Тени:** мягкие, одна плоскость; без многослойного neon. +**Progress / статус:** тонкая полоска accent по низу pill (как в лаунчере). + +### Типографика + +- **Display / brand:** выразительный геометрический или techno-гротеск (не Inter). Лаунчер: текущий UI-font стек; сайт — выбрать 1 display + 1 body, зафиксировать в CSS variables. +- **Body:** читаемый sans, ~15–16px, line-height ~1.5. +- **Mono:** логи, IP, версии — `ui-monospace` / Geist Mono / аналог. + +### Иконки и лого + +- Логотип: hex / кристалл Owyx (как в лаунчере) + слово **owyx** цветом `--accent`. +- Иконки: линейные, 1.5–2px stroke, цвет `text` / `muted`; active — accent. +- Аватары: круглые; Minecraft skin — ок в контексте профиля/онлайна. + +### Motion + +- 2–3 осознанных движения на поверхность: fade/slide hero, pulse статуса online, hover CTA translateY(−1–2px). +- Без бесконечного glitter и параллакса, от которого тошнит. + +--- + +## 4. Лаунчер (эталон UI уже в v0.1) + +**Стек:** Tauri 2 + Vite HTML/CSS/TS. +**Ощущение:** тёмный desktop shell, cyan Play, модалки настроек, status-pill в titlebar. + +Сохранять: + +- Rail слева (Home / Library / Servers roadmap / instances / + / settings). +- Filled pill inputs; settings = modal с табами. +- Progress: один global pill + optional tip скорость/размер. +- i18n ru/en полный паритет. + +Не тащить на сайт 1:1 chrome окна (min/max/close) — только токены, тон, паттерны кнопок/полей. + +--- + +## 5. Сайт (`owyxsite/`) — целевой вид + +**Сейчас (legacy):** gold Minecraft (`#FFAA00`), glass + skin-фоны, Segoe UI — **не целевое**. +**Цель редизайна:** визуально «брат» лаунчера: `#050508` + cyan CTA, тот же бренд Owyx. + +### Информационная архитектура (сохранить маршруты, обновить оболочку) + +| Зона | Маршруты (ориентир) | Задача экрана | +|------|---------------------|---------------| +| Маркетинг | `/` | Hero: бренд + сервер online/IP + CTA «Скачать лаунчер» (+ «Войти / Создать аккаунт») | +| Download | `/download` | Скачать лаунчер + 3 шага «скачал → вошёл → играешь» | +| Auth | `/login` `/register` `/verify` `/forgot-password` `/reset-password` | Чистые формы, без лишних карточек | +| Кабинет | `/profile` | Аккаунт, лаунчер (скачать/вход тем же аккаунтом), **внешний вид** (скин), настройки | +| Комьюнити | `/forum` `/chat` `/online` | Списки, топики, кто в сети | +| Экономика | `/shop` `/tokens` | Каталог (оплата — later) | +| Админ | `/admin` | Плотный инструмент, тот же бренд, не «другой продукт» | + +### Hero (первый viewport) + +Только: + +1. Логотип / слово **Owyx** (hero-уровень, accent или почти-белый с accent-подчёркиванием). +2. Одна строка ценности (сервер / комьюнити) — muted. +3. Статус сервера + IP (копирование) — компактно. +4. Одна primary CTA **«Скачать лаунчер»** (accent fill) + secondary ghost «Войти / Создать аккаунт». + +> **Модель доступа — открытая.** Игрок скачал лаунчер → ник → Play (offline), или вошёл аккаунтом Owyx. **Никаких «подай заявку и жди модератора».** Заявки убраны из продукта. + +Фон: full-bleed атмосфера (тёмный градиент + лёгкий particles/starfield **или** приглушённые скины с сильным затемнением). Не inset card-hero. Не золотой glow. + +### Компоненты сайта (паттерны) + +- **Header:** прозрачный/blur на `--bg`, ссылки muted → accent hover; brand слева. +- **Primary button:** `--accent` / `--accent-ink`, radius ~10px. +- **Secondary:** ghost / outline `--line`. +- **Inputs:** filled dark (`--panel`), border `--line`, focus ring accent. +- **Footer:** минимальный, без стены ссылок. +- **Forum/chat:** denser UI допустим; те же токены. + +### Тон копирайта + +Коротко, по-человечески, RU. Без корпоративного «инновационной платформы». Плагин/лаунчер в текстах — как части одной экосистемы. + +--- + +## 6. Плагин (`owyxplugin/`) — визуал в игре + бренд + +Плагин почти без GUI; «дизайн» = **префиксы, сообщения, конфиг**. + +- Префикс чата: `&bOwyx&7` / MiniMessage с hex `#00E5FF` (или legacy cyan), не золото Chiwawa. +- Команды: `/owyx` (+ алиасы со старого имени на переходный период). +- Kick/whitelist тексты: спокойные, с упоминанием сайта `owyx.site` / API `api.owyx.site`. +- Package / `plugin.yml` / JAR name — Owyx (см. корневой `PLAN.md`, раздел плагина). +- Не вводить отдельную «зелёную» или «золотую» палитру в сообщениях. + +--- + +## 7. Связка экосистемы + +```text +Сайт (аккаунт, косметика, токен) + │ + ├─► Плагин (проверка токена / сессия на сервере) + │ + └─► Лаунчер (offline | Owyx login | MS stub) +``` + +Один логотип, один accent, одни домены в копирайте. Скриншоты сайта и лаунчера рядом не должны выглядеть как два разных стартапа. + +--- + +## 8. Чеклист приёмки редизайна сайта + +- [ ] Primary accent = `#00e5ff` (не gold). +- [ ] Фон семейства `#050508` / панели `#131319`. +- [ ] Первый viewport: brand + 1 headline + 1 CTA + статус/IP; без стат-полок. +- [ ] Header/footer в том же языке, что лаунчер. +- [ ] Auth/profile/forum не «выпадают» в другой скин. +- [ ] RU/EN без смешанных экранов. +- [ ] Нет Inter-as-display / фиолетового SaaS-градиента / золотого btn-minecraft. +- [ ] Mobile: hero читаем, CTA не обрезан. + +--- + +## 9. Для облачного агента (сайт) + +При редизайне: + +1. Прочитать этот файл целиком + корневой `PLAN.md` + текущий `frontend/app/**`. +2. Заменить токены в `globals.css` / Tailwind theme на таблицу §3. +3. Пересобрать `HeroSection`, Header, Footer, кнопки — без смены бизнес-логики API. +4. Сохранить маршруты и функции (auth, forum, chat, admin). +5. Не трогать секреты / `.env`; не выдумывать оплату. +6. Свериться с лаунчером `Launcher/apps/launcher/src/styles.css` при сомнении в цвете. + +Phase 1 сайта = **визуальное выравнивание под лаунчер**. Новые фичи — только если не мешают редизайну. diff --git a/legacy/Launcher/.cursor/rules/browser-ui-testing.mdc b/legacy/Launcher/.cursor/rules/browser-ui-testing.mdc new file mode 100644 index 00000000000..fb9db693444 --- /dev/null +++ b/legacy/Launcher/.cursor/rules/browser-ui-testing.mdc @@ -0,0 +1,12 @@ +--- +description: Browser preview and UI screenshot testing for Owyx +alwaysApply: true +--- + +# Owyx — browser and UI testing + +- When opening a web preview (`npm run dev`, Vite, docs, etc.), use **Cursor Browser / browser MCP** (`user-browsermcp`), not an external system browser. +- For UI checks, the agent may take **screenshots via browser tools**, inspect the UI, and fix issues without waiting for the user — especially for layout, navigation, empty states, and create-instance flows that work in browser preview. +- Native install/Play still needs `Owyx.exe` / `tauri dev`; browser preview is for shell UI only. +- **Default verify = smoke/debug, not release.** Prefer `npm run check` + `npm run check:rust`, then `npm run build:smoke` (`target/debug/Owyx.exe` / optional `Launcher/Owyx.debug.exe`). Full `npm run build:release` only when shipping / hand-off — see `Launcher/BUILD.md`. +- After a **release** ship build, place `Owyx.exe` at `Launcher/Owyx.exe` when the user asks for a runnable hand-off binary. diff --git a/legacy/Launcher/.cursor/rules/modrinth-reference.mdc b/legacy/Launcher/.cursor/rules/modrinth-reference.mdc new file mode 100644 index 00000000000..aefb0ed386d --- /dev/null +++ b/legacy/Launcher/.cursor/rules/modrinth-reference.mdc @@ -0,0 +1,14 @@ +--- +description: Modrinth code as primary launcher UI/architecture reference +alwaysApply: true +--- + +# Owyx ↔ Modrinth reference + +- Reference clone (read-only intent): prefer `../modrinth-code` or `reference/modrinth-code` next to / inside the workspace — remote https://github.com/modrinth/code +- Key packages: `apps/app` (Tauri), `apps/app-frontend` (UI), `packages/app-lib` (Theseus Rust launcher core). +- **Phase 1 (now):** working full Modrinth-like copy as our functional reference — port behavior and UI structure aggressively; redesign / Owyx brand / layout changes come later. +- **Phase 2:** individuality — Owyx colors, logos, private servers, own login site, possible layout redesign. +- Stack stays **Rust + Tauri 2 + Vite (HTML/CSS/TS)** unless we explicitly decide otherwise. Port patterns into Owyx; do not replace the whole product with their monorepo as the shipping app. +- When unsure about a screen or flow, open the matching Modrinth source file first. +- Player artifact: single `Owyx.exe`; data: `%USERPROFILE%/owyx`. diff --git a/legacy/Launcher/.env.example b/legacy/Launcher/.env.example new file mode 100644 index 00000000000..fd3394db9cc --- /dev/null +++ b/legacy/Launcher/.env.example @@ -0,0 +1,9 @@ +# Launcher ↔ Owyx site (local / OBT) +# +# API base (prod default in Rust is https://api.owyx.site) +# Empty = use compiled default. +OWYX_API_BASE_URL= + +# Must match owyxsite LAUNCHER_CLIENT_KEY when talking to api.owyx.site. +# Also readable from %USERPROFILE%/owyx/client_key (one line). +OWYX_CLIENT_KEY= diff --git a/legacy/Launcher/.gitattributes b/legacy/Launcher/.gitattributes new file mode 100644 index 00000000000..1ff0c423042 --- /dev/null +++ b/legacy/Launcher/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/legacy/Launcher/.gitignore b/legacy/Launcher/.gitignore new file mode 100644 index 00000000000..d4e066ebe41 --- /dev/null +++ b/legacy/Launcher/.gitignore @@ -0,0 +1,55 @@ +# --- Secrets / local env --- +.env +.env.local +.env.*.local +!.env.example + +# --- Logs / OS --- +logs/ +*.log +.DS_Store +Thumbs.db +Desktop.ini + +# --- Node / frontend --- +node_modules/ +dist/ +dist-ssr/ +*.local +.npm +.pnpm-store/ + +# --- Rust / Cargo --- +target/ +**/*.rs.bk +Cargo.lock.bak + +# --- Tauri --- +apps/launcher/src-tauri/target/ +apps/launcher/src-tauri/gen/ +apps/launcher/src-tauri/WixTools/ + +# --- IDE --- +.vs/ +.vscode/* +!.vscode/extensions.json +!.vscode/settings.json +.idea/ +*.suo +*.user +*.userosscache + +# --- Legacy / build junk --- +[Bb]in/ +[Oo]bj/ +[Dd]ebug/ +[Rr]elease/ +publish/ +*.exe +*.pdb +*.dll +!legacy/**/*.md + +# --- Test / coverage --- +coverage/ +*.lcov diff --git a/legacy/Launcher/AGENTS.md b/legacy/Launcher/AGENTS.md new file mode 100644 index 00000000000..48d947ac433 --- /dev/null +++ b/legacy/Launcher/AGENTS.md @@ -0,0 +1,12 @@ +# Agent notes (Owyx Launcher) + +## Cursor Cloud / GitHub + +- **Canonical repo:** [`ebluffy/Owyx`](https://github.com/ebluffy/Owyx) (renamed from `KORESHon/Owyx`; old URLs redirect). +- Prefer remotes and `gh` calls against **`ebluffy/Owyx`**, not the old owner name. +- After the rename, the **Cursor GitHub App / cloud integration** may lose `createPullRequest` (and AutoReview) until it is **re-installed or re-authorized** on the `ebluffy` account/org. Local `gh` with a user token can still open PRs. +- Do not commit `*.exe`, `target/`, `node_modules/`, or a local `modrinth-code/` clone (gitignored reference only). + +## Build gates + +See [`BUILD.md`](./BUILD.md): `npm run check` → `check:rust` → `build:smoke` (debug) → `build:release` (ship only). diff --git a/legacy/Launcher/BUILD.md b/legacy/Launcher/BUILD.md new file mode 100644 index 00000000000..688c6478b53 --- /dev/null +++ b/legacy/Launcher/BUILD.md @@ -0,0 +1,324 @@ +# Building Owyx (Windows + Linux) + +One codebase. **Windows** ships `Owyx.exe` (WebView2). **Linux** cloud / desktop +dev uses a native WebKitGTK window and a debug ELF. Data: + +| Host | Player data | +|------|-------------| +| Windows | `%USERPROFILE%/owyx/` | +| Linux | `~/owyx/` | + +**Default for agents / local verify = smoke (debug), not release.** +Full Windows release is only for shipping / hand-off of the final exe. + +Work from: + +```bash +cd Launcher/apps/launcher +``` + +On Windows PowerShell the same directory works: + +```powershell +cd Launcher/apps/launcher +``` + +--- + +## Build gates (fast → slow) + +| Gate | Command | Typical time | What it proves | +|------|---------|--------------|----------------| +| **1. Compile check** | `npm run check` then `npm run check:rust` | seconds | TS + Rust typecheck / compile without linking a full app binary | +| **2. Linux smoke (debug ELF)** | `npm run build:smoke` or `npm run build:smoke:linux` | ~minutes | Runnable debug `src-tauri/target/debug/owyx` (ELF, not `.exe`) | +| **3. Windows smoke (debug)** | `npm run build:smoke` on a Windows host | ~minutes | Runnable debug `owyx.exe` (no release LTO / opt) | +| **4. Ship (Windows release)** | `npm run build:release` | much longer | Optimized ship `Owyx.exe` | + +Prefer gate 1 while iterating. Use gate 2 on Cloud Linux (native WebKit) or gate 3 +on Windows to confirm the native app builds and the window opens. Use gate 4 only +when handing off `Launcher/Owyx.exe`. + +Linux **release** `.deb` / AppImage is **not** a current gate — see `PLAN.md` backlog. + +Catalog zip overlay cap is **512 MB** (`MAX_PACK_BYTES` in `catalog.rs`). Do not raise +it without a streaming download. Foreg-sized (~2 GB) packs stay in backlog. + +--- + +## Linux native dev & smoke (recommended for Cloud Agent) + +Cloud Desktop VMs (Ubuntu 22.04 / 24.04) should develop against a **real Tauri +window**, not Vite-in-browser and not Wine + `Owyx.exe`. + +### One-time system deps + +```bash +# repo root +bash Launcher/scripts/linux-dev-setup.sh +``` + +Installs WebKitGTK 4.1, GTK 3, Ayatana (or `libappindicator3-dev` fallback), +librsvg, libsoup 3, build-essential / pkg-config, and ensures **Rust ≥ 1.85**. +Idempotent. Does **not** install Wine or MinGW. + +Headless CI that only compiles can set `OWYX_LINUX_DEV_GUI=0` to skip optional +`libxdo-dev`. + +### npm + compile gate + +```bash +cd Launcher/apps/launcher +npm ci +npm run check && npm run check:rust +``` + +### Dev: native window (`dev:tauri`) + +Needs a display. Cloud Desktop is usually `DISPLAY=:1` or `:0`. + +```bash +export DISPLAY="${DISPLAY:-:1}" +npm run dev:tauri +``` + +This is `tauri dev`: Vite on `:1420` **plus** a WebKitGTK window. Rust `invoke` +(catalog download, install, skin-to-disk, login) is live. Works the same on +Windows (`dev:tauri` → WebView2). + +**Smoke without Minecraft:** login UI, catalog fetch (if site API is on +`127.0.0.1:3001`), download progress UI, overlay error paths, navigation. +Smoke means: **window opens, UI is not blank, invoke does not crash, logs write +to `~/owyx/logs/`**. + +Pre-release QA (2026-08-30) additionally ran **Play + 2 Modrinth mods** on Cloud +Linux (`dev:tauri`, Fabric 1.20.1). Windows `build:release` stays an owner +hand-off — do not run it on Cloud. + +Optional catalog against a local site: + +```bash +OWYX_API_BASE_URL=http://127.0.0.1:3001 npm run dev:tauri +``` + +If the API is down, Servers empty/offline is fine — do not treat that as a +launcher crash. + +### Smoke: debug ELF + +```bash +npm run build:smoke +# alias: npm run build:smoke:linux +``` + +Output (Cargo package name `owyx`): + +```text +Launcher/apps/launcher/src-tauri/target/debug/owyx +``` + +Confirm it is an ELF, then run: + +```bash +file src-tauri/target/debug/owyx +# ELF 64-bit LSB pie executable, … +./src-tauri/target/debug/owyx +``` + +### Optional CI job + +`.github/workflows/launcher-check.yml` job **`linux-smoke`** runs +`npm run build:smoke` only on **`workflow_dispatch`** (not every push/PR), so +the fast `check` job stays cheap. Actions → launcher-check → Run workflow. + +--- + +## 1. Compile check (seconds) + +```bash +npm run check # tsc --noEmit +npm run check:rust # cargo check in src-tauri +``` + +PowerShell: the same `npm` scripts. + +--- + +## 2. Windows smoke / debug build + +Standard Tauri 2 fast path on a **Windows** host: + +```powershell +npm run build:smoke +# equivalent: npm run tauri build -- --debug +``` + +Output binary (Cargo package name `owyx`; on Windows same file as `Owyx.exe`): + +```text +Launcher/apps/launcher/src-tauri/target/debug/owyx.exe +``` + +Optional copy for a stable hand-off path (same idea as release smoke copy): + +```powershell +Copy-Item -Force src-tauri\target\debug\owyx.exe ..\..\Owyx.debug.exe +``` + +→ `Launcher/Owyx.debug.exe` + +### Alternative (frontend already built) + +If `dist/` is fresh (`npm run build`), you can skip the Tauri CLI wrapper and only rebuild Rust: + +```powershell +npm run build +cd src-tauri +cargo build +# -> target/debug/owyx.exe +``` + +`tauri build --debug` is preferred when you want the usual before-build frontend step in one command. + +--- + +## 3. Release / ship (Windows hand-off only) + +```powershell +npm run build:release +# equivalent: npm run tauri build +``` + +Output: + +```text +Launcher/apps/launcher/src-tauri/target/release/Owyx.exe +``` + +### Ship copy (repo convention) + +After a successful **release** build, copy to: + +```text +Launcher/Owyx.exe +``` + +```powershell +Copy-Item -Force src-tauri\target\release\Owyx.exe ..\..\Owyx.exe +``` + +This path is the documented hand-off location for friends and local QA (also referenced in `PLAN.md` and `RELEASE_NOTES_v0.1.0.md`). Do **not** treat a debug binary as `Launcher/Owyx.exe`. + +Linux `.deb` / AppImage bundling is **not** enabled (`bundle.targets` stays empty). + +--- + +## Fast UI without native invoke (secondary) + +Vite-only preview is still useful for CSS/i18n: + +```bash +OWYX_API_BASE_URL=http://127.0.0.1:3001 npm run dev +# open http://127.0.0.1:1420 — Download / Play / skin-to-disk are browser stubs +``` + +Prefer `npm run dev:tauri` when you need real Rust commands. + +--- + +## Legacy: cross-build Windows exe on Linux (UI blocked) + +**Not** the Cloud Agent path. Native `dev:tauri` / Linux smoke ELF above is the +supported Linux contour. This appendix stays so we do not re-spend time on +Wine + WebView2. + +Verified historically on a Cursor cloud Linux Desktop VM (Ubuntu 24.04, Wine 9.0, +Rust 1.97, mingw-w64 GCC 13): the **native backend** can boot under Wine +(install/meta/logging/window chrome). **The WebView2 UI does not render** +(Chromium/Edge under Wine — see “Known blocker”). Treat as **legacy / +unverified / Windows QA only**. + +### 1. Toolchain (one-time) + +```bash +# Rust Windows GNU target + MinGW cross-linker +rustup target add x86_64-pc-windows-gnu +sudo apt-get install -y --no-install-recommends mingw-w64 + +# Wine (64-bit) + 32-bit support +sudo dpkg --add-architecture i386 +sudo apt-get update +sudo apt-get install -y --no-install-recommends wine64 wine32 winbind +# If /usr/bin/wine is missing, the binary is /usr/lib/wine/wine64: +sudo ln -sf /usr/lib/wine/wine64 /usr/local/bin/wine64 + +# Init a 64-bit prefix (data will live under it, see §5) +WINEPREFIX=$HOME/.wine WINEARCH=win64 wine64 wineboot -u +``` + +### 2. Cross-compile the exe + +```bash +cd Launcher/apps/launcher +npm run build # produce dist/ (frontend) +cd src-tauri +cargo build --target x86_64-pc-windows-gnu --bin owyx +# -> target/x86_64-pc-windows-gnu/debug/owyx.exe (PE32+ x86-64) +``` + +**Caveat — `export ordinal too large`:** a plain `cargo build` also links the mobile-only `cdylib` (`owyx_lib.dll`) and MinGW `ld` fails on it (`export ordinal too large`) because the whole `windows` crate is re-exported. The desktop `.exe` does **not** need that artifact. Two ways around it: + +- Build only the binary: `cargo build --target x86_64-pc-windows-gnu --bin owyx` (still builds the cdylib in some cargo versions), **or** +- Temporarily set the lib `crate-type = ["rlib"]` in `Cargo.toml` for the cross-build, then revert. (Do **not** commit that change — `staticlib`/`cdylib` are needed for mobile.) + +### 3. Ship the WebView2 loader shim next to the exe + +The exe statically imports `WebView2Loader.dll` (produced by `webview2-com-sys`). Copy it beside the exe or Wine reports `WebView2Loader.dll ... not found (c0000135)`: + +```bash +cp target/x86_64-pc-windows-gnu/debug/WebView2Loader.dll / +``` + +### 4. Run under Wine + +```bash +export DISPLAY=:1 # the Desktop X display +export WINEPREFIX=$HOME/.wine +wine64 /Owyx.exe +``` + +Backend boots cleanly (launcher log line `=== Owyx launcher start ===`), the data layout is created, and a native window opens. + +### 5. Where player data lives under Wine + +Our code uses `%USERPROFILE%/owyx`. Under Wine that resolves to: + +```text +~/.wine/drive_c/users//owyx/ + ├─ meta/{versions,libraries,assets,natives,java_versions} + ├─ instances/ + ├─ cache/ + └─ logs/owyx.log +``` + +(Confirmed created on first run — the Theseus-style `meta/` layout is identical to Windows.) + +### 6. Known blocker — WebView2 UI does not render under Wine + +Tauri on Windows renders its UI with **WebView2 (Edge/Chromium)**. Under Wine the native window opens but stays blank: `CreateCoreWebView2Environment` never spawns `msedgewebview2.exe`. Attempts made (all still blank): + +1. Ship `WebView2Loader.dll` → exe loads, backend runs, blank window (no runtime). +2. Install the Evergreen runtime: `wine64 MicrosoftEdgeWebview2Setup.exe /silent /install` → the installer crashes (`Unhandled exception 0x80000003`) but lays down an Edge runtime under `EdgeCore/…`. +3. Force the fixed-version runtime + disable the Chromium sandbox (Wine can’t provide it): + ```bash + export WEBVIEW2_BROWSER_EXECUTABLE_FOLDER='C:\Program Files (x86)\Microsoft\EdgeCore\' + export WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS='--no-sandbox --disable-gpu --single-process --in-process-gpu' + ``` + → `msedgewebview2.exe` still does not start (Chromium/Edge does not run under Wine 9.0). + +**Recommendation:** +- **Linux Cloud Agent:** `bash Launcher/scripts/linux-dev-setup.sh` then `npm run dev:tauri` (native WebKit). Do not retry Wine WebView2. +- **Windows Play / ship exe:** Windows host, MiniMax QA, or release CI — not this Linux contour. + +### Proton + +Not attempted on this VM (no Steam / Proton / `protontricks` installed). If a Proton prefix is available, the same three env vars from §6 apply; document exact commands when a working Proton is present. Proton bundles a newer Wine + DXVK, so WebView2 *may* fare better, but it is unverified. diff --git a/legacy/Launcher/LICENSE.txt b/legacy/Launcher/LICENSE.txt new file mode 100644 index 00000000000..9fa2e16c052 --- /dev/null +++ b/legacy/Launcher/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 KORESHon / Owyx Launcher + +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/legacy/Launcher/PLAN.md b/legacy/Launcher/PLAN.md new file mode 100644 index 00000000000..10b1c0e66d7 --- /dev/null +++ b/legacy/Launcher/PLAN.md @@ -0,0 +1,5 @@ +# План лаунчера перенесён + +Единый план всего Owyx: **[../PLAN.md](../PLAN.md)** (корень монорепо). + +Этот файл оставлен, чтобы старые ссылки не умирали. Не дублировать сюда этапы. diff --git a/legacy/Launcher/README.md b/legacy/Launcher/README.md new file mode 100644 index 00000000000..c82c6ebc76b --- /dev/null +++ b/legacy/Launcher/README.md @@ -0,0 +1,108 @@ +# Owyx + +Кастомный лаунчер Minecraft под **свои** сервера и сборки: ваниль и моды. + +Один `.exe` для игроков. Не установщик Windows — сам лаунчер создаёт нужные папки, качает сборку и запускает игру. + +> Полный план, этапы и бэклог: **[PLAN.md](../PLAN.md)** (корень монорепо) + +--- + +## Идея + +1. Заливаешь сборку(и) на свой update-сервер. +2. Друзья скачивают только лаунчер. +3. Вводят ник → выбирают сборку → «Скачать» → «Играть». +4. Позже: связка с плагином на сервере (автологин, плюшки) для публичных режимов. + +--- + +## Стек + +| Слой | Технология | +|------|------------| +| Backend | Rust | +| Desktop shell | Tauri 2 | +| UI | TypeScript + Vite | +| Секреты / URL | `.env` (не в git) | + +Старый C# WinForms-прототип **не используется**. Фрагменты идей лежат в [`legacy/csharp/`](./legacy/csharp/) только как справочник. + +--- + +## Требования для разработки + +- Windows 10/11 +- [Rust](https://rustup.rs/) (stable) +- [Node.js](https://nodejs.org/) 20+ +- Microsoft Edge WebView2 (обычно уже есть на Windows) + +```powershell +# проверка +rustc --version +cargo --version +node --version +``` + +--- + +## Быстрый старт (когда каркас на месте) + +```powershell +copy .env.example .env +# OWYX_API_BASE_URL=http://127.0.0.1:3001 (сайт backend; пусто = prod) + +cd apps/launcher +npm install +npm run tauri dev +``` + +Вкладка **Серверы** читает `GET /api/launcher/v1/servers` с этого base. +Без native окна (Linux/cloud): `OWYX_API_BASE_URL=http://127.0.0.1:3001 npm run dev` +→ Vite `:1420`, каталог через proxy `/proxy/owyx`. Play / unzip — только Tauri. + +Проверка / smoke (по умолчанию — быстрее релиза): + +```powershell +npm run check +npm run check:rust +npm run build:smoke +# -> src-tauri/target/debug/owyx.exe +``` + +Ship (только для финального `.exe`): + +```powershell +npm run build:release +# -> src-tauri/target/release/Owyx.exe → copy Launcher/Owyx.exe +``` + +Подробности: [`BUILD.md`](./BUILD.md). + +--- + +## Конфигурация + +| Файл | Назначение | +|------|------------| +| `.env` | Локальные URL и секреты (**не коммитить**) | +| `.env.example` | Шаблон для разработчиков | +| `%USERPROFILE%/owyx/` | Данные игрока: конфиг, инстансы, логи | + +--- + +## Структура репозитория + +```text +PLAN.md # указатель → корневой ../PLAN.md +README.md # этот файл +.env.example +apps/launcher/ # Tauri + Rust + UI +legacy/csharp/ # справочный код старого прототипа +``` + +--- + +## Лицензия + +См. [LICENSE.txt](./LICENSE.txt). diff --git a/legacy/Launcher/RELEASE_NOTES_v0.1.0.md b/legacy/Launcher/RELEASE_NOTES_v0.1.0.md new file mode 100644 index 00000000000..cb3688636fa --- /dev/null +++ b/legacy/Launcher/RELEASE_NOTES_v0.1.0.md @@ -0,0 +1,59 @@ +# Owyx Launcher v0.1.0 — Release Notes (draft) + +**Status:** draft for first public/private drop. Do **not** publish the GitHub Release until smoke on Windows is signed off. + +## Highlights + +- Classic launcher flow: profile → create instance → Play installs → launch +- Shared Minecraft cache under `%USERPROFILE%/owyx/meta/` (Theseus-style): + - `meta/versions/{id}/` — version JSON + client jar + - `meta/libraries/` — libraries + - `meta/assets/` — assets + - `meta/natives/{version}/` — natives +- Fabric / Quilt / Forge / NeoForge / Vanilla +- Home · Library · instance detail (Content / Files / Worlds / Logs) +- Instance settings modals (memory presets, Java, hooks) with autosave +- RU / EN i18n +- Modrinth mods search **scaffold** (Content → Browse mods) — API wired, marketplace polish next + +## Critical fixes in this RC + +- Client jar no longer lands under a fake `libraries/com/mojang/minecraft/client.jar` path +- Install no longer freezes ~2 minutes at `N-1/N` after `client.jar` reaches 100% (SHA1 O(n²) bug) +- Existing wrong-path client jars are adopted into `meta/versions/` when size matches +- Play no longer re-hashes every jar with SHA256 before launch +- Gear and ⋮ actions next to Play are equal square buttons; ⋮ includes **Open instance folder** + +## Artifact + +```text +Build (Windows): + cd Launcher/apps/launcher + npm run tauri build + +Ship path: + src-tauri/target/release/Owyx.exe + +Smoke copy (documented): + Launcher/Owyx.exe +``` + +Data root: `%USERPROFILE%/owyx/` + +## Known gaps (post-v0.1) + +- Real Microsoft / Owyx browser auth (offline nick works for Play) +- Full Modrinth marketplace (install from search, versions, dependencies) +- Friends pack sync / control-plane +- CI Windows release build +- Autoupdate EXE checks (updater shell exists) + +## Smoke checklist + +1. Create offline profile +2. Create vanilla instance → Play → install completes without hang on last file +3. Second instance same MC version reuses `meta/versions` (no re-download of client) +4. Stop / exit → Play button returns (not stuck “running”) +5. ⋮ → Open instance folder +6. Content → Browse mods → search returns Modrinth hits +7. Switch tabs during install → top progress pill stays consistent diff --git a/legacy/Launcher/apps/launcher/README.md b/legacy/Launcher/apps/launcher/README.md new file mode 100644 index 00000000000..c17ab6ad9ce --- /dev/null +++ b/legacy/Launcher/apps/launcher/README.md @@ -0,0 +1,44 @@ +# apps/launcher — Owyx Launcher (Tauri 2) + +Skeleton for the desktop client. Product plan: repository root [`PLAN.md`](../../../PLAN.md). + +## Dev + +```powershell +# from repo root +copy .env.example .env # once + +cd apps\launcher +npm install + +# UI in browser (HTML/CSS) — screenshots without native build +npm run dev +# open http://localhost:1420 + +# Full app (WebView2 + Rust), hot reload +npm run tauri dev + +# Fast verify (preferred): typecheck → debug smoke build +npm run check +npm run check:rust +npm run build:smoke +# -> src-tauri/target/debug/owyx.exe +# optional: Copy-Item to ../../Owyx.debug.exe + +# Ship only (slow): release exe for hand-off +npm run build:release +# -> src-tauri/target/release/Owyx.exe → copy ../../Owyx.exe +# see ../../BUILD.md +``` + +Requires: Rust stable, Node 20+, WebView2 (Edge runtime, same family as Modrinth App). + +Shared Minecraft cache: `%USERPROFILE%/owyx/meta/versions|libraries|assets` (Theseus layout). + +## What this PR includes + +- Vite + TypeScript UI shell (nick field, packs placeholder, Play disabled until nick) +- Rust `greet` command to verify Tauri bridge +- Tauri window config for Windows + +Next (see PLAN stages 1–3): config.json, update API client, sync + SHA256, Fabric launch. diff --git a/legacy/Launcher/apps/launcher/docs/MICROSOFT_AUTH.md b/legacy/Launcher/apps/launcher/docs/MICROSOFT_AUTH.md new file mode 100644 index 00000000000..81f9614e98e --- /dev/null +++ b/legacy/Launcher/apps/launcher/docs/MICROSOFT_AUTH.md @@ -0,0 +1,44 @@ +# Microsoft authentication for Owyx Launcher (Path A) + +Owyx supports three profile kinds: **Offline**, **Owyx** (email → `api.owyx.site`), and **Microsoft** (licensed Minecraft). + +Tokens are stored as an opaque `ms1:` blob on the profile (machine-local +`profiles.json`). **Today this is base64 JSON, not OS-encrypted** — DPAPI / +keychain wrapping is a follow-up. Without the env var, the wizard stays +**`unconfigured`** and never invents fake user codes. + +## What the owner must configure + +1. Create an Azure AD app registration (Microsoft identity platform) as a **public client**. +2. Enable **Allow public client flows** and device-code / mobile+desktop auth. +3. Grant / enable Xbox Live sign-in for the app (same family of scopes as other Minecraft launchers: `XboxLive.signin` + `offline_access`). +4. Set at runtime (do not commit secrets; client ids for public native clients are often public): + +```bash +export MICROSOFT_CLIENT_ID="" +``` + +5. Reply URLs: for device code, the verification URI is Microsoft’s (`https://www.microsoft.com/link` / login.microsoftonline.com). No loopback redirect is required for the device-code path. + +## Launcher behavior + +| Phase | Meaning | +|-------|---------| +| `unconfigured` | `MICROSOFT_CLIENT_ID` missing — wizard explains this doc | +| `waiting` | Real device code + verification URI from Azure | +| `success` | Minecraft gamertag + `authBlob` (`ms1:…`) — profile `needsAuth=false` | +| `error` | Azure / Xbox / Minecraft failure (clear message; no fake codes) | + +Offline Play and Owyx email login are independent and must keep working when MS is unconfigured or failing. + +## Honest follow-ups + +- Windows DPAPI / OS keychain wrapping of `ms1:` blobs (today: opaque base64 JSON in profiles.json). +- Using the Minecraft access token in the Play / launch pipeline (Yggdrasil/MSA user type) — do not break offline / Owyx. +- SISU / Proof-of-Possession Xbox device-token flow (Modrinth Theseus) is not required for Path A device-code. + +## Reference + +- Modrinth Theseus auth: `packages/app-lib` (SISU + device patterns) +- Owyx profile storage: `src-tauri/src/profiles.rs` +- Site contract (Owyx account, not MS): `owyxsite/LAUNCHER_SITE_CONTRACT.md` diff --git a/legacy/Launcher/apps/launcher/docs/MODRINTH_PARITY_SPEC.md b/legacy/Launcher/apps/launcher/docs/MODRINTH_PARITY_SPEC.md new file mode 100644 index 00000000000..f8aaca03930 --- /dev/null +++ b/legacy/Launcher/apps/launcher/docs/MODRINTH_PARITY_SPEC.md @@ -0,0 +1,107 @@ +# Full Modrinth App parity map → Owyx surfaces + +SPEC for `cursor/modrinth-full-parity-*`. Source of truth: Modrinth `apps/app-frontend` + `packages/ui` (clone at `/tmp/modrinth-code`, not committed). Brand: Owyx `DESIGN.md` tokens. Control-plane: `api.owyx.site` + client key preserved. + +## Skills used (no SkillSpector) + +| Skill | Why | +|-------|-----| +| github/spec-kit (spec-driven) | This screen map before implement | +| mattpocock/skills | Engineering / requirements discipline | +| addyosmani/agent-skills | Spec → implement → ship | +| nutlope/hallmark | Anti-slop pass on large screens | +| nextlevelbuilder/ui-ux-pro-max | UX anti-patterns on Home/Browse/Content | + +## Screen map + +| Modrinth surface | Modrinth path | Owyx route / surface | Status | +|------------------|---------------|----------------------|--------| +| App shell (rail, titlebar, crumbs, accounts, downloads) | `App.vue` | `#shell` rail + topbar + history + status pill | Port | +| Home / Index | `pages/Index.vue` | `route=home` `renderHome` | Port density + Owyx news | +| Discover / Browse (global) | `pages/Browse.vue` `/browse/*` | `route=browse` (no instance) | Port | +| Browse for instance | Browse + `?i=` | `route=browse` + `browseInstanceId` | Port (Content CTA) | +| Project detail | `pages/project/*` | `route=project` + projectId | Port | +| Library | `components/ui/library/*` | `route=library` | Port filters/toolbar | +| Instance layout + header | `pages/instance/layout.vue` | `route=instance` | Port | +| Content (installed) | `instance/content` + ContentPageLayout | Instance tab `content` | Port — no inline search | +| Files / Worlds / Logs | `instance/files|worlds|logs` | Instance tabs | Keep + polish | +| Share | `instance/share` | Tab `share` | Honest stub (no Modrinth SaaS) | +| Create instance | CreationFlowModal | Multi-step `#modal-create` | Port stages | +| Skins | `pages/Skins.vue` | `route=skins` | Port spirit + Owyx `/me` apply | +| Screenshots (global) | `pages/Screenshots.vue` | Optional / deferred | Not blocker | +| Hosting / Modrinth+ | hosting/* | **Omit** | Replaced by Owyx Servers | +| Servers (Modrinth) | `pages/Servers.vue` | **Owyx Servers** `route=servers` | Keep API catalog | +| App settings | AppSettingsModal | `#modal-app-settings` | Expand sections | +| Instance settings | settings-modal/** | `#modal-inst-settings` | Keep tabs | +| Accounts | AccountsCard + MS auth | Profile wizard + Playing as | Offline + Owyx + MS B | +| Play / install / logs | app-lib | Rust `install`/`launch`/`modrinth` | Keep | + +## Left rail (target) + +1. Logo Owyx (hex) +2. Home +3. Discover / Browse +4. Skins +5. **Servers (Owyx)** — private catalog (not Modrinth Hosting) +6. Separator + instance icons (recent) +7. `+` create +8. Settings +9. Playing-as / avatar + +Stats moves out of primary Modrinth-like rail (reachable from Home/Settings if kept). + +## Content → Browse contract + +- Content tab: search installed · Upload files · **Browse content** (primary) · type chips · list with enable/delete. +- **No** eternal inline Modrinth search panel as primary UX. +- Browse content → `route=browse` with locked MC/loader from instance. +- Card click → `route=project` (Description / Gallery / Versions). +- Install always uses explicit `projectId` / `versionId`. + +## Create wizard stages (Modrinth-aligned, Owyx order) + +Owner baseline: **loader → MC → loader version → name → icon** (real multi-step panels, not a 2-panel collapse). + +1. Loader chips +2. Minecraft version +3. Loader version (vanilla skips with honest hint) +4. Name +5. Icon (optional) → Create + +Alt: **Browse modpacks** / **Import .mrpack** — Discover install + local file import create an instance (game jars still on Play). Export from Share is overrides-based (partial). + +## Project detail tabs + +Description · Gallery · **Changelog** (from version changelogs) · Versions. + +## Auth + +| Kind | Target | +|------|--------| +| Offline | Keep | +| Owyx email | `api.owyx.site` + `X-Owyx-Client-Key` | +| Microsoft | Path **A** when `MICROSOFT_CLIENT_ID` set (device-code → Xbox → MC); else `unconfigured`. See `docs/MICROSOFT_AUTH.md`. | + +## Explicit non-goals / honest gaps + +- Modrinth Hosting, Modrinth+, ads, wrench logo, green brand accent +- Friends / shared-instance cloud SaaS +- Full Theseus content DB / mrpack CDN-hash export / Mojang skin equip + capes +- Screenshots global page — optional +- MS token use in Play launch args / DPAPI wrapping of `ms1:` blobs + +## Modrinth source files used (primary) + +- `apps/app-frontend/src/App.vue` +- `pages/Index.vue`, `Browse.vue`, `Skins.vue` +- `pages/instance/layout.vue`, `content/index.vue`, `files|worlds|logs` +- `pages/project/Index.vue` (+ Description/Gallery/Versions) +- `packages/ui/.../content-tab/layout.vue`, `browse-tab/*` +- `packages/ui/.../creation-flow-modal/**` +- `packages/app-lib` (auth/install patterns referenced for MS B docs) + +## Verification + +```bash +cd Launcher/apps/launcher && npm run check && npm run check:rust && npm run build:smoke +``` diff --git a/legacy/Launcher/apps/launcher/index.html b/legacy/Launcher/apps/launcher/index.html new file mode 100644 index 00000000000..3d65593f799 --- /dev/null +++ b/legacy/Launcher/apps/launcher/index.html @@ -0,0 +1,12 @@ + + + + + + Owyx + + +
+ + + diff --git a/legacy/Launcher/apps/launcher/package-lock.json b/legacy/Launcher/apps/launcher/package-lock.json new file mode 100644 index 00000000000..323c8e92856 --- /dev/null +++ b/legacy/Launcher/apps/launcher/package-lock.json @@ -0,0 +1,1370 @@ +{ + "name": "owyx-launcher", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "owyx-launcher", + "version": "0.1.0", + "dependencies": { + "@tauri-apps/api": "^2.5.0", + "@tauri-apps/plugin-dialog": "^2.7.2", + "@tauri-apps/plugin-opener": "^2.2.6" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.5.0", + "typescript": "~5.8.3", + "vite": "^6.3.5" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.3.tgz", + "integrity": "sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.3.tgz", + "integrity": "sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.3.tgz", + "integrity": "sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.3.tgz", + "integrity": "sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.3.tgz", + "integrity": "sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.3.tgz", + "integrity": "sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.3.tgz", + "integrity": "sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.3.tgz", + "integrity": "sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.3.tgz", + "integrity": "sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.3.tgz", + "integrity": "sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.3.tgz", + "integrity": "sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.3.tgz", + "integrity": "sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.3.tgz", + "integrity": "sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.3.tgz", + "integrity": "sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.3.tgz", + "integrity": "sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.3.tgz", + "integrity": "sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.3.tgz", + "integrity": "sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.3.tgz", + "integrity": "sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.3.tgz", + "integrity": "sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.3.tgz", + "integrity": "sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.3.tgz", + "integrity": "sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.3.tgz", + "integrity": "sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.3.tgz", + "integrity": "sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.3.tgz", + "integrity": "sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.3.tgz", + "integrity": "sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tauri-apps/api": { + "version": "2.11.1", + "resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.11.1.tgz", + "integrity": "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA==", + "license": "Apache-2.0 OR MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + } + }, + "node_modules/@tauri-apps/cli": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli/-/cli-2.11.4.tgz", + "integrity": "sha512-R8xGtMpwyetawSqm9kYOuMmEqkhUbvcUy8n0aNXIxollKBLESUu5f4Fx+64hgASYm1H+jSWq6jCW6zqTnH6hqQ==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "bin": { + "tauri": "tauri.js" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/tauri" + }, + "optionalDependencies": { + "@tauri-apps/cli-darwin-arm64": "2.11.4", + "@tauri-apps/cli-darwin-x64": "2.11.4", + "@tauri-apps/cli-linux-arm-gnueabihf": "2.11.4", + "@tauri-apps/cli-linux-arm64-gnu": "2.11.4", + "@tauri-apps/cli-linux-arm64-musl": "2.11.4", + "@tauri-apps/cli-linux-riscv64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-gnu": "2.11.4", + "@tauri-apps/cli-linux-x64-musl": "2.11.4", + "@tauri-apps/cli-win32-arm64-msvc": "2.11.4", + "@tauri-apps/cli-win32-ia32-msvc": "2.11.4", + "@tauri-apps/cli-win32-x64-msvc": "2.11.4" + } + }, + "node_modules/@tauri-apps/cli-darwin-arm64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-2.11.4.tgz", + "integrity": "sha512-1ryOF3ZhpZ/nemHV5zVwBQBz9jDGKmKPvWPADOhc83ig0P4bMc2iER4NbC6r9sjeIZ6RVQ4g3RZIYvezhcl4TQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-darwin-x64": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-2.11.4.tgz", + "integrity": "sha512-uFsGQAAfuyz1k/yGLmkWfkBlgKAqZfxqlHmLWx81QU27RJWfmbNHCIq8T8w1e+VClleIuZUjpHWfoE4E3DLo3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm-gnueabihf": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-2.11.4.tgz", + "integrity": "sha512-IaHZn5CdBL21oUmjiVOS1ctw6Ip1O0pjp70FwOWmYz1myWe0SY96ZIj2FYf7pT0m8bI2h/hrs5ZbEXXh44/MkQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-2.11.4.tgz", + "integrity": "sha512-N41/ukTRVe6XSuUTESuFdGeOW2i7k62tK+6gHK5Kd5/q5RPvvi19GaWAVPPb9u95HSGmTChSolBfzynUsssFaA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-arm64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.11.4.tgz", + "integrity": "sha512-v277UnT/fB64xAfSroL5N3Km3tLmvATWqJJw/wRI+g6o+HkeD0slyE7gOhNs1MbjE41R7bQOTxMVoL3aomUJmw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-riscv64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-riscv64-gnu/-/cli-linux-riscv64-gnu-2.11.4.tgz", + "integrity": "sha512-qqgNkQ2u1yZHxjhxsZaxUtRDW8dIqIYm33rx/mzwQv0SfY9x1B+iraj8vWeFiXjjSVVhEMepXSOts1TqPzvXNQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-gnu": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-2.11.4.tgz", + "integrity": "sha512-2VRNWl84FOH0m2giiDkO2h0QXlcMJeX+zJDpI5kDIQAx6s+geF3v48F4DXfJez4GS/FdoDGnPnw1C2iYGbQ7bQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-linux-x64-musl": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-2.11.4.tgz", + "integrity": "sha512-o9GyhYor/nc7xarmwDE3ka2szuW3uuZzXjHWh64Q8YX5AtSgxdQkFWzrY4O8KiGtVNvFBI14H3Q49Qj5TOIP/A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-arm64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-2.11.4.tgz", + "integrity": "sha512-ld5Ehb598m0VkYyylRPNeCFsBe/km0jxis6KgMpl3IGY6I/i1RwQXO05I1AsXUXO2WC6AvB/Lw4qTf/asiuEiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-ia32-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-2.11.4.tgz", + "integrity": "sha512-12Hxi0XX/H5VFxO/bGgHkFWhml9VMgEOu9CidjeCeTNQ1l6fpUlbiGgSP7CLI3PFtW9/FfbeHieZ+kyWK5H7CA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/cli-win32-x64-msvc": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-2.11.4.tgz", + "integrity": "sha512-+vDiqBIU5dMISg/wNvX3sF+ZHfgJGJ5T0AcO+EHNXV9GGAG+P5fzodlDXD3QdKCRgZxMoCm5PPvj3BqLNjBthw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 OR MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tauri-apps/plugin-dialog": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-dialog/-/plugin-dialog-2.7.2.tgz", + "integrity": "sha512-pX0IGm1I3I6wc+zeKYcq1GSqogK6okCNX5fOdaNU5ab1AjGS6l1E5wFNjEb7meg7ZFSp0JUs+0jQGQNyOvLrsg==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@tauri-apps/plugin-opener": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/@tauri-apps/plugin-opener/-/plugin-opener-2.5.4.tgz", + "integrity": "sha512-1HnPkb+AmgO29HBazm4uPLKB+r7zzcTBW1d0fyYp1uP+jwtpoiNDGKMMzz58SFp49nOIrxdE3aUJtT57lfO9CQ==", + "license": "MIT OR Apache-2.0", + "dependencies": { + "@tauri-apps/api": "^2.11.0" + } + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "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/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/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", + "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/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.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.25", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz", + "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==", + "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.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.62.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.3.tgz", + "integrity": "sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.3", + "@rollup/rollup-android-arm64": "4.62.3", + "@rollup/rollup-darwin-arm64": "4.62.3", + "@rollup/rollup-darwin-x64": "4.62.3", + "@rollup/rollup-freebsd-arm64": "4.62.3", + "@rollup/rollup-freebsd-x64": "4.62.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.3", + "@rollup/rollup-linux-arm-musleabihf": "4.62.3", + "@rollup/rollup-linux-arm64-gnu": "4.62.3", + "@rollup/rollup-linux-arm64-musl": "4.62.3", + "@rollup/rollup-linux-loong64-gnu": "4.62.3", + "@rollup/rollup-linux-loong64-musl": "4.62.3", + "@rollup/rollup-linux-ppc64-gnu": "4.62.3", + "@rollup/rollup-linux-ppc64-musl": "4.62.3", + "@rollup/rollup-linux-riscv64-gnu": "4.62.3", + "@rollup/rollup-linux-riscv64-musl": "4.62.3", + "@rollup/rollup-linux-s390x-gnu": "4.62.3", + "@rollup/rollup-linux-x64-gnu": "4.62.3", + "@rollup/rollup-linux-x64-musl": "4.62.3", + "@rollup/rollup-openbsd-x64": "4.62.3", + "@rollup/rollup-openharmony-arm64": "4.62.3", + "@rollup/rollup-win32-arm64-msvc": "4.62.3", + "@rollup/rollup-win32-ia32-msvc": "4.62.3", + "@rollup/rollup-win32-x64-gnu": "4.62.3", + "@rollup/rollup-win32-x64-msvc": "4.62.3", + "fsevents": "~2.3.2" + } + }, + "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/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "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 + } + } + } + } +} diff --git a/legacy/Launcher/apps/launcher/package.json b/legacy/Launcher/apps/launcher/package.json new file mode 100644 index 00000000000..60877ac08e2 --- /dev/null +++ b/legacy/Launcher/apps/launcher/package.json @@ -0,0 +1,28 @@ +{ + "name": "owyx-launcher", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "check": "tsc --noEmit", + "check:rust": "cargo check --manifest-path src-tauri/Cargo.toml", + "dev:tauri": "tauri dev", + "build:smoke": "tauri build --debug", + "build:smoke:linux": "tauri build --debug", + "build:release": "tauri build", + "tauri": "tauri" + }, + "dependencies": { + "@tauri-apps/api": "^2.5.0", + "@tauri-apps/plugin-dialog": "^2.7.2", + "@tauri-apps/plugin-opener": "^2.2.6" + }, + "devDependencies": { + "@tauri-apps/cli": "^2.5.0", + "typescript": "~5.8.3", + "vite": "^6.3.5" + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/.cargo/config.toml b/legacy/Launcher/apps/launcher/src-tauri/.cargo/config.toml new file mode 100644 index 00000000000..a6b014e959d --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target-dir = "target" diff --git a/legacy/Launcher/apps/launcher/src-tauri/Cargo.lock b/legacy/Launcher/apps/launcher/src-tauri/Cargo.lock new file mode 100644 index 00000000000..17cdf5a5980 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/Cargo.lock @@ -0,0 +1,5444 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "async-signal" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae36dc4177970ef04fde5178d3e2429882def40e57a451f919c098f72baa6cec" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "atk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "brotli" +version = "8.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" +dependencies = [ + "serde", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.13.1", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.69", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camino" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 2.0.19", +] + +[[package]] +name = "cargo_toml" +version = "0.22.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" +dependencies = [ + "serde", + "toml 0.9.12+spec-1.1.0", +] + +[[package]] +name = "cc" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5add81bb678e6cb321aff7fa0dc7689ad82b112dbc032cea19f91d6b8e3582b9" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures 0.3.0", + "rand_core", +] + +[[package]] +name = "chrono" +version = "0.4.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" +dependencies = [ + "iana-time-zone", + "num-traits", + "serde", + "windows-link 0.2.1", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.13.1", + "core-foundation", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cssparser" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa", + "phf", + "smallvec", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ctor" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +dependencies = [ + "ctor-proc-macro", + "dtor", +] + +[[package]] +name = "ctor-proc-macro" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dbus" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab69f03cc8c4340c9c8e315114e1658e6775a9b16a04357973aa21cec22b32e" +dependencies = [ + "libc", + "libdbus-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "serde_core", +] + +[[package]] +name = "derive_arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "derive_more" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.119", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", +] + +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "displaydoc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "dlopen2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2c5bd4158e66d1e215c49b837e11d62f3267b30c92f1d171c4d3105e3dc4d4" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fbbb781877580993a8707ec48672673ec7b81eeba04cfd2310bd28c08e47c8f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "dom_query" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89" +dependencies = [ + "bit-set", + "cssparser", + "foldhash", + "html5ever", + "precomputed-hash", + "selectors", + "tendril", +] + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" +dependencies = [ + "serde", +] + +[[package]] +name = "dtoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "dtor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +dependencies = [ + "dtor-proc-macro", +] + +[[package]] +name = "dtor-proc-macro" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "embed-resource" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfdaacccebec3b28e4866b8973543c7647797db5ada1bdab552e48fe665fbbd" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 1.1.4+spec-1.1.0", + "vswhom", + "winreg", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erased-serde" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec" +dependencies = [ + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" +dependencies = [ + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-channel" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "262590f4fe6afeb0bc83be1daa64e52657fe185690a958af7f3ad0e92085c5ae" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd50c473c80f6d7c3670a752354b8e569b1a7cbfdc0419ec88e5edad85e0dc7" + +[[package]] +name = "futures-executor" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6754879cc9f2c66f88c6e5c35344bb0bdb0708b0352b1201815667c7eabc7458" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4577ecaa3c4f96589d473f679a71b596316f6641bc350038b962a5daf0085d7a" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d6d3cde68c518367be28956066ddfef33813991b77a55005a69dae04bf3b10b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "futures-sink" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e34418ac499d6305c2fb5ad0ed2f6ac998c5f8ca209b4510f7f94242c647e307" + +[[package]] +name = "futures-task" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b231ed28831efb4a61a08580c4bc233ec56bc009f4cd8f52da2c3cb97df0c109" + +[[package]] +name = "futures-util" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77a90a256fce34da66415271e30f94ee91c57b04b8a2c042d9cf3220179deaa" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "gdk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 6.0.0", + "rand_core", + "wasm-bindgen", +] + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.13.1", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.69", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.2", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gtk" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "html5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2" +dependencies = [ + "log", + "markup5ever", +] + +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9f41fd6a08e4d4ec69df65976da761afd5ad5e58a9d4acb46bd1c953a9e3ff2" +dependencies = [ + "bytes", + "futures-core", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22053281f852e11534f5198498373cbb59295120a20771d90f7ed1897490a72" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http", + "hyper", + "hyper-util", + "rustls", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" +dependencies = [ + "byteorder", + "png 0.17.16", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", + "serde", + "serde_core", +] + +[[package]] +name = "infer" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" +dependencies = [ + "cfb", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "is-docker" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" +dependencies = [ + "once_cell", +] + +[[package]] +name = "is-wsl" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" +dependencies = [ + "is-docker", + "once_cell", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "js-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +dependencies = [ + "cfg-if", + "futures-util", + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.13.1", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[package]] +name = "libdbus-sys" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "328c4789d42200f1eeec05bd86c9c13c7f091d2ba9a6ea35acdf51f31bc0f043" +dependencies = [ + "pkg-config", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libredox" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c943259e342f1e06ff2da7a83eabdfe7f92ce10262688dbf1895ff0b3e6e4652" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "markup5ever" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862" +dependencies = [ + "log", + "tendril", + "web_atoms", +] + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "muda" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.19", + "windows-sys 0.61.2", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.13.1", + "jni-sys 0.3.1", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys 0.3.1", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "num-conv" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", + "objc2-exception-helper", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.13.1", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-location" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-text" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-exception-helper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.13.1", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.13.1", + "objc2", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-core-image", + "objc2-core-location", + "objc2-core-text", + "objc2-foundation", + "objc2-quartz-core", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" +dependencies = [ + "bitflags 2.13.1", + "block2", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "open" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b3d059e795d52b8a72fef45658620edd4d9c359b338564aa14391ffa511ed5" +dependencies = [ + "dunce", + "is-wsl", + "libc", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owyx" +version = "0.1.0" +dependencies = [ + "dirs", + "flate2", + "futures-util", + "quartz_nbt", + "reqwest 0.12.28", + "serde", + "serde_json", + "sha2", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-opener", + "wait-timeout", + "zip", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_codegen" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49aa7f9d80421bca176ca8dbfebe668cc7a2684708594ec9f3c0db0805d5d6e1" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "piper" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "plist" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da1d65da6dd5d1e44199ac0f58712d241c0f439f80adea8924d832384087f85" +dependencies = [ + "base64 0.22.1", + "indexmap 2.14.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.13.1", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" +dependencies = [ + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit 0.25.13+spec-1.1.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quartz_nbt" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf389329ba2dad9c6d898b7955a64e58c89dd52d04f4e2753b9d86eb5f49821" +dependencies = [ + "anyhow", + "byteorder", + "cesu8", + "flate2", + "quartz_nbt_macros", +] + +[[package]] +name = "quartz_nbt_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "289baa0c8a4d1f840d2de528a7f8c29e0e9af48b3018172b3edad4f716e8daed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quick-xml" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" +dependencies = [ + "memchr", +] + +[[package]] +name = "quinn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "socket2", + "thiserror 2.0.19", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" +dependencies = [ + "bytes", + "getrandom 0.4.3", + "lru-slab", + "rand", + "rand_pcg", + "ring", + "rustc-hash", + "rustls", + "rustls-pki-types", + "slab", + "thiserror 2.0.19", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.61.2", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.19", +] + +[[package]] +name = "ref-cast" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216e8f773d7923bcba9ceb86a86c93cabb3903a11872fc3f138c49630e50b96d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9283685feec7d69af75fb0e858d5e7378f33fe4fc699383b2916ab9273e03c" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.4.2", + "web-sys", + "webpki-roots", +] + +[[package]] +name = "reqwest" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219c5811de6525e5416c7d5d53bb656d3afdbc6c5af816e0802bcfa42dbdc1c3" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "sync_wrapper", + "tokio", + "tokio-util", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams 0.5.0", + "web-sys", +] + +[[package]] +name = "rfd" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15ad77d9e70a92437d8f74c35d99b4e4691128df018833e99f90bcd36152672" +dependencies = [ + "block2", + "dispatch2", + "glib-sys", + "gobject-sys", + "gtk-sys", + "js-sys", + "log", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows-sys 0.60.2", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.13.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.23.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pki-types" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.119", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "selectors" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c" +dependencies = [ + "bitflags 2.13.1", + "cssparser", + "derive_more", + "log", + "new_debug_unreachable", + "phf", + "phf_codegen", + "precomputed-hash", + "rustc-hash", + "servo_arc", + "smallvec", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" +dependencies = [ + "erased-serde", + "serde", + "serde_core", + "typeid", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" +dependencies = [ + "base64 0.22.1", + "bs58", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.2", + "serde_core", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "servo_arc" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170fb83ab34de17dc69aa7c67482b22218ddb85da56546f9bd6b929e32a05930" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "digest", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "socket2" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "softbuffer" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac18da81ebbf05109ab275b157c22a653bb3c12cf884450179942f81bcbf6c3" +dependencies = [ + "bytemuck", + "js-sys", + "ndk", + "objc2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "tracing", + "wasm-bindgen", + "web-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "string_cache" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a18596f8c785a729f2819c0f6a7eae6ebeebdfffbfe4214ae6b087f690e31901" +dependencies = [ + "new_debug_unreachable", + "parking_lot", + "phf_shared", + "precomputed-hash", +] + +[[package]] +name = "string_cache_codegen" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585635e46db231059f76c5849798146164652513eb9e8ab2685939dd90f29b69" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.2", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.35.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9" +dependencies = [ + "bitflags 2.13.1", + "block2", + "core-foundation", + "core-graphics", + "crossbeam-channel", + "dbus", + "dispatch2", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "libc", + "log", + "ndk", + "ndk-sys", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "once_cell", + "parking_lot", + "percent-encoding", + "raw-window-handle", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" +dependencies = [ + "anyhow", + "bytes", + "cookie", + "dirs", + "dunce", + "embed_plist", + "getrandom 0.3.4", + "glob", + "gtk", + "heck 0.5.0", + "http", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "percent-encoding", + "plist", + "raw-window-handle", + "reqwest 0.13.4", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "swift-rs", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils", + "thiserror 2.0.19", + "tokio", + "tray-icon", + "url", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch", + "schemars 0.8.22", + "semver", + "serde", + "serde_json", + "tauri-utils", + "tauri-winres", + "walkdir", +] + +[[package]] +name = "tauri-codegen" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch", + "plist", + "png 0.17.16", + "proc-macro2", + "quote", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.119", + "tauri-utils", + "thiserror 2.0.19", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-macros" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "tauri-codegen", + "tauri-utils", +] + +[[package]] +name = "tauri-plugin" +version = "2.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri-utils", + "walkdir", +] + +[[package]] +name = "tauri-plugin-dialog" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940" +dependencies = [ + "log", + "raw-window-handle", + "rfd", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "tauri-plugin-fs", + "thiserror 2.0.19", + "url", +] + +[[package]] +name = "tauri-plugin-fs" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +dependencies = [ + "anyhow", + "dunce", + "glob", + "log", + "objc2-foundation", + "percent-encoding", + "schemars 0.8.22", + "serde", + "serde_json", + "serde_repr", + "tauri", + "tauri-plugin", + "tauri-utils", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", + "url", +] + +[[package]] +name = "tauri-plugin-opener" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29" +dependencies = [ + "dunce", + "glob", + "objc2-app-kit", + "objc2-foundation", + "open", + "schemars 0.8.22", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.19", + "url", + "windows", + "zbus", +] + +[[package]] +name = "tauri-runtime" +version = "2.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8" +dependencies = [ + "cookie", + "dpi", + "gtk", + "http", + "jni", + "objc2", + "objc2-ui-kit", + "objc2-web-kit", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils", + "thiserror 2.0.19", + "url", + "webkit2gtk", + "webview2-com", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f" +dependencies = [ + "gtk", + "http", + "jni", + "log", + "objc2", + "objc2-app-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-utils" +version = "2.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887" +dependencies = [ + "anyhow", + "brotli", + "cargo_metadata", + "ctor", + "dom_query", + "dunce", + "glob", + "http", + "infer", + "json-patch", + "log", + "memchr", + "phf", + "plist", + "proc-macro2", + "quote", + "regex", + "schemars 0.8.22", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 2.0.19", + "toml 1.1.4+spec-1.1.0", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" +dependencies = [ + "dunce", + "embed-resource", + "toml 1.1.4+spec-1.1.0", +] + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.4.3", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "tendril" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" +dependencies = [ + "new_debug_unreachable", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a43598840e33d5b0331f38c5e30d13bb11c11210a4b58f0d9b18a5a5eefcd9" +dependencies = [ + "thiserror-impl 2.0.19", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43cbfe0cf76104d42a574802844187e84a305e531ed54455f11fbde0f10541cd" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + +[[package]] +name = "time" +version = "0.3.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" + +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" +dependencies = [ + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.7.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "toml_edit 0.20.2", +] + +[[package]] +name = "toml" +version = "0.9.12+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 0.7.15", +] + +[[package]] +name = "toml" +version = "1.1.4+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" +dependencies = [ + "indexmap 2.14.0", + "serde_core", + "serde_spanned 1.1.1", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "toml_writer", + "winnow 1.0.4", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.14.0", + "serde", + "serde_spanned 0.6.9", + "toml_datetime 0.6.3", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap 2.14.0", + "toml_datetime 1.1.1+spec-1.1.0", + "toml_parser", + "winnow 1.0.4", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow 1.0.4", +] + +[[package]] +name = "toml_writer" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" +dependencies = [ + "bitflags 2.13.1", + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e" +dependencies = [ + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation", + "once_cell", + "png 0.18.1", + "serde", + "thiserror 2.0.19", + "windows-sys 0.61.2", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typeid" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "uds_windows" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e" +dependencies = [ + "memoffset", + "tempfile", + "windows-sys 0.61.2", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" +dependencies = [ + "getrandom 0.4.3", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "version-compare" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c2856837ef78f57382f06b2b8563a2f512f7185d732608fd9176cb3b8edf0e" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.119", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasm-streams" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web_atoms" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075474b12bcb3d2e3d4546580e9de478eeeead668a1761e2a8860c836b7ef297" +dependencies = [ + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.61.2", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a921c1b6914c367b2b823cd4cde6f96beec77d30a939c8199bb377cf9b9b54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "webview2-com-sys" +version = "0.38.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "381336cfffd772377d291702245447a5251a2ffa5bad679c99e61bc48bacbf9c" +dependencies = [ + "thiserror 2.0.19", + "windows", + "windows-core 0.61.2", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.61.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" +dependencies = [ + "windows-collections", + "windows-core 0.61.2", + "windows-future", + "windows-link 0.1.3", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" +dependencies = [ + "windows-core 0.61.2", +] + +[[package]] +name = "windows-core" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.4.2", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.1", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-future" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" +dependencies = [ + "windows-core 0.61.2", + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link 0.2.1", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows-threading" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" +dependencies = [ + "windows-link 0.1.3", +] + +[[package]] +name = "windows-version" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" +dependencies = [ + "windows-link 0.2.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" +dependencies = [ + "cfg-if", + "windows-sys 0.59.0", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wry" +version = "0.55.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dirs", + "dom_query", + "dpi", + "dunce", + "gdkx11", + "gtk", + "http", + "javascriptcore-rs", + "jni", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-core-foundation", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 2.0.19", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.61.2", + "windows-version", + "x11-dl", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zbus" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe18fb60dc696039e738717b76eaea21e7a4489bbb1885020b43c94236d7e98a" +dependencies = [ + "async-broadcast", + "async-executor", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-lite", + "hex", + "libc", + "ordered-stream", + "rustix", + "serde", + "serde_repr", + "tracing", + "uds_windows", + "uuid", + "windows-sys 0.61.2", + "winnow 1.0.4", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "5.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe96480bed92df2b442a1a30df364e12d08eed03aeb061f2b8dc6afb2be91119" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zbus_names", + "zvariant", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "4.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e" +dependencies = [ + "serde", + "winnow 1.0.4", + "zvariant", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zip" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "flate2", + "indexmap 2.14.0", + "memchr", + "thiserror 2.0.19", + "zopfli", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" + +[[package]] +name = "zopfli" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +dependencies = [ + "bumpalo", + "crc32fast", + "log", + "simd-adler32", +] + +[[package]] +name = "zvariant" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee2a0bcd2a907786a456fff45aaaaf54c9ba5f50b71ae9ec1a4edd200c94911" +dependencies = [ + "endi", + "enumflags2", + "serde", + "winnow 1.0.4", + "zvariant_derive", + "zvariant_utils", +] + +[[package]] +name = "zvariant_derive" +version = "5.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38a708216a18780796770bfe3f4739c7c83a3e8f789b755534bbbc06e4e23e12" +dependencies = [ + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.119", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90cb9383f9b45290407a1258b202d3f8f01db719eb60b4e4055c6375af4fc7c7" +dependencies = [ + "proc-macro2", + "quote", + "serde", + "syn 2.0.119", + "winnow 1.0.4", +] diff --git a/legacy/Launcher/apps/launcher/src-tauri/Cargo.toml b/legacy/Launcher/apps/launcher/src-tauri/Cargo.toml new file mode 100644 index 00000000000..7ef031a3c99 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "owyx" +version = "0.1.0" +description = "Owyx — custom Minecraft launcher" +authors = ["KORESHon"] +edition = "2021" +rust-version = "1.77" + +[lib] +name = "owyx_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = { version = "2", features = [] } + +[dependencies] +tauri = { version = "2", features = [] } +tauri-plugin-opener = "2" +tauri-plugin-dialog = "2" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +dirs = "6" +sha2 = "0.10" +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } +futures-util = "0.3" +wait-timeout = "0.2" +zip = { version = "2", default-features = false, features = ["deflate"] } +flate2 = { version = "1", default-features = false, features = ["rust_backend"] } +quartz_nbt = "0.2.9" + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = true +opt-level = "s" +strip = true diff --git a/legacy/Launcher/apps/launcher/src-tauri/assets/steve.png b/legacy/Launcher/apps/launcher/src-tauri/assets/steve.png new file mode 100644 index 0000000000000000000000000000000000000000..f97afdd5a38db604a1608872d48638a6d052b230 GIT binary patch literal 1311 zcmV+)1>pLLP)4e-7!_2IfS`gPf>wzHZIl>-f;mkgBz8)QG(oTl+F2;th}gtR3sa>%8=DjsHu(wp zPiNld-ty+nx3{^(?A^tE@R-?|Z};ZC`DS+6y)$QOaOdX59ym9BxhPrZ@#hy02GXxL zaiHMN?W?7D)ZKu0&*l=IDg#uom*3YqnRpU?e!Yo%Bi; z-W27pw`)b){h2FSEXZTFX`Lpp&BxO?I3OLU&Lo6FFoaV)iM~iwbWPS7&to4?x=a0UYqEQEMj2N`xoakCKG%{!`4DcDEASGw~_2at*H3O6sbfw|gLd9Ocu8KTEQWC8_=Awzd-L%wSNZ`2N7F;=!a{g^J*kZ2R;nrJqv= z3OuX<+7Du|=QlSCmV)|1nU>xj#U~=YjqNTTgy@Zp1JVGEtHU6Ho*mu~Lde;V9}A*h z{&2taHjj4`+^kFx**(aZ&;UKB4ub?%8K8BFA?pNrd?JjZRD`Fvlj79`WgT1~kE1s2 zBVAB3<7R-)eq=zl_PYn09LWt;%ZPf8>&@T>_zXve=&`4CX+U3y8{qMtA*J~KvEJfz z$JaI$t?|X?TZhO1Uj~EvDT?$I)>-w~DBjPFM5z&x0a|yx87QnuV4VRNq>3prKxdTM z&==(Kp#c&f8K6d}0VqAj^=9z&R^dvIBPmG5QMij^jK?Jgh4thzWFphkF%>&>vT zveE;6b8|AzsiGn?RG`O}28d`C52{!f7n$Jwt~Uc7Z#$h%B5HMYH4};$k40UVh#IDu zLnA26V|4jw3^K9G0L=_HKx18R20r6coC~DzC=PWsfYfEgk~8Y@zSl5@?JCAaf_`iC z7}wjPMT-_KTC|uP;00(E{qdPkok>iK7A;z|XwjlYQ}9=5Lw{V=cZB=&w?G~~c5nlR z{=9Am@J-L5UvZ5ZZopA9fRDPG0TXG!u`*!4t{E_vOF-ZL`b$pl(|*QeA2Wk*1iBH{vs9DlC z#@`!M@t+vz;&~jkX&>p|_WeVLfACPE&&Sg^ss#INYrn>;7`@-?&hNLvvAQir0_&E5 z(hV3ST>Dt}@iYz>h%z!DG6#%O-G#dWN*_<-@bveY*7j(bL~Gnd4$2B2PvhX1WD2aJ ze{Lu1#8(L)8w2>cTtyA@|ANQ>7wpH{=HqD`(fOUVEL002ovPDHLkV1f-pcVhqm literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/build.rs b/legacy/Launcher/apps/launcher/src-tauri/build.rs new file mode 100644 index 00000000000..d860e1e6a7c --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/build.rs @@ -0,0 +1,3 @@ +fn main() { + tauri_build::build() +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/capabilities/default.json b/legacy/Launcher/apps/launcher/src-tauri/capabilities/default.json new file mode 100644 index 00000000000..edc306f8924 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/capabilities/default.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schema.tauri.app/config/2/capability", + "identifier": "default", + "description": "Default permissions for Owyx Launcher", + "windows": ["main"], + "permissions": [ + "core:default", + "opener:default", + "dialog:default", + "core:window:allow-close", + "core:window:allow-minimize", + "core:window:allow-toggle-maximize", + "core:window:allow-is-maximized", + "core:window:allow-start-dragging", + "core:window:allow-set-size", + "core:window:allow-outer-size", + "core:window:allow-inner-size", + "core:window:allow-center", + "core:window:allow-current-monitor", + "core:window:allow-scale-factor" + ] +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs.json b/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs.json new file mode 100644 index 00000000000..f113bd464cc --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs.json @@ -0,0 +1,13 @@ +{ + "packs": [ + { + "id": "demo-friends", + "name": "Friends Demo", + "minecraft": "1.20.1", + "loader": "fabric", + "loaderVersion": "0.15.0", + "summary": "Локальный mock для Sync MVP", + "manifestUrl": "/v1/packs/demo-friends/manifest" + } + ] +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs/demo-friends/manifest.json b/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs/demo-friends/manifest.json new file mode 100644 index 00000000000..2dc1d2d7563 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/fixtures/v1/packs/demo-friends/manifest.json @@ -0,0 +1,18 @@ +{ + "id": "demo-friends", + "version": "2026.08.03", + "minecraft": "1.20.1", + "loader": "fabric", + "mainClass": "net.fabricmc.loader.impl.launch.knot.KnotClient", + "java": { "minMajor": 17 }, + "files": [ + { + "path": "mods/readme.txt", + "url": "mock://files/demo-friends/mods/readme.txt", + "sha256": "fd596093c0a340dc83b03ca39838527ee14fd9b22939e93ba155e6c165c4022d", + "size": 23 + } + ], + "jvmArgs": ["-Xmx2G"], + "gameArgs": [] +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/128x128.png b/legacy/Launcher/apps/launcher/src-tauri/icons/128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..679c6e7a31db300042d5f325271e8bf1cc6e2659 GIT binary patch literal 3604 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 J>opzY{sZcB!Ylv) literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/32x32.png b/legacy/Launcher/apps/launcher/src-tauri/icons/32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..6aabde33dfd2714a39dda65592828a650a563b87 GIT binary patch literal 1011 zcmV;o1O*X9T!{-eE=3R&ap}s9JJ;2Ph>CTiA_xjD zRFH}aBBEAXZEc%0nPg_X=O(rqlQe0qB6tZTOy0bA?zx|HpPfjiL;OXv@t5r%1z^a> zFv>sFLWE(+uh|7)n5G`=mrC$G4`C2YJU3kjmTfDL@6Uf906CP06tg+_#Uf(q6jDpN z;I<{y>*81rqwhXpd}vrfICJ7aP+?`J0C;dv@=+KWMd$hzSh{aJ7H(OGIi2%hMO`1m<)96Euq_n!nauW)7WG0h#blAzUQ*7M%WW|ek&-pb*+sjSU^`HIZyZfrSy6h#ROOr!SNT89%c z6OJ(_?X4XCBZzT%w|mbvEZVvr-e^|$o*Dq_TuP1E&V&p6VA@@dlv~mtmhInBPDEoW z24q1XO(vRd!@|vLHQSkR(=}x?mzNw`g~a?01YSw=t1bZb-YX*6HDBsHqor1z?JWV2 zcj-_((}A|dow~Qt2mmP{RcgH}ZKer7fQ zTEAb0RZ!U5!x@xeATehf?tkVy07PE-F?hj zSxY@915`B%3uD-__tXP<_to{gcys$9++?CAo3&xdFhM=1q*B!=EUkdx+DJNyp%-s( z@8o%z8-As}A%L)wJk)baDpf6>X;*dv->;pR@=X5|FJtrO;_K^oxOVV3avwkI;8HJ{ zEjJQ9RWE~yoT~Qn>KzG18ktqya3wrpP@em=vB)~3B0i*FjnTLL8qR4A zBtMO0B2JW4sv3oby`Alq9qv2jEH!336OJ(_c=g<$!ASOFGhtJrq;f+F3wt};D~(Nt zbFU@}2wn&}}%D_1iuB`T&@(oQ)!mK)k+w9XklKbW0+!Nh?wsyQ4|ChsK^GvS}P h88u1o|I2AJ_6<)9+j8|J-X;J5002ovPDHLkV1jW;)kFXQ literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/64x64.png b/legacy/Launcher/apps/launcher/src-tauri/icons/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..0723eafd43be69a03a020c26bac409fff5db6a45 GIT binary patch literal 1880 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 KMNUMnLSTXzR=X$w literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square142x142Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aba882811744216c1d88f5b154a8bdd99e106a65 GIT binary patch literal 4130 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square284x284Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9c6a09eba59d3a71bd1e0b9bef61cdfdc7fdbbb0 GIT binary patch literal 8050 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 W!Kt5m2czfJ098dzXqEh%@c#voA{B)I literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square30x30Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f57874528c081d430afac869ccd74fa8bf2400ad GIT binary patch literal 906 zcmV;519kj~P)rQm%R#6b#2iJ82J6v3MWhM9Zsx!?Dl@0^Jh>rDDsgJEHf#yw#mBWF)y$Em~U z-ZBW&w#(+ZD+Q!JOkw=i1B~9hCt1lM6pO%j-Qc~0+KHfrr7SuJ`*GmfMQq$Rg2HkZ zPA)H*EMLN!TVWfacofr5$ME?470ge3gxwhr1g{Fr^b#OG(1)XUt|Ga45V^UOPN6bX z)s1)<-*M5=ok05Y4DKJlfQ89V2t^}R({5DVL?$x5jI;!52yucyOHp%9PHN5rAH04^ zgL;fusrtYK%%_*I^Yjs&-V$iT?3cND0pBn(gk5KjVP$DqSZ~w;mV>cn$X*hOHD!96 z9m+DXlFnfJi9?9>^=k4}Ms1X*OKK~O?B6|vZb>ogTr0h`((dM0kPu=H>>buDuiVF| zTtIPPpPIr_-*4SNsAh&`$zI#!%9UiQ`h6VfO}0mn<=~N?WU+>g35aT+8>l9fE4Pqp z6R1LNeo-gBCa|uHGDUkQ;T8&ixKML}Dy>@I#wO&-(0d1xi`HgI(|>t3j@0`pErTr) zOxBoo2`e1~Y?Iw?a)2;*ttU;X1fiUsG;k+^1N^eyaoOh0SN zkBgpcie6{5%TVyCy_7+M{E9*q*-Ij^rc5s*C8*cRi@<7c<_2^b3O==$GN=_vx{ZCx zmLYpt7S@#M4T`j3;8IkyHo6Q2pW6Fdl6>8#Y#Fk*(U(2d)ISM109~e1@c-)TZHc+Q g>%;&57p8^r13|E!z{)$-YybcN07*qoM6N<$f>(&MuK)l5 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square310x310Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f905160c6115d5ad805d75a34c754b0b990113ce GIT binary patch literal 8876 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 QSD^spq?M#9Bn$)o8z{msX8-^I literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square44x44Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..55fcab792ea02bb1e586cc1518922a4b3c91ff8a GIT binary patch literal 1373 zcmV-j1)}`tb(AVQV|O(3O*>}qt7acP!L5Q?3-1=`X=>3 ze6jw3FJiH^3azD9ETyy*4M~HVr1{;S?9a^gJ9l>1^dYk|yF1W8CWK{oVeYx#obP<+ z+)ZTqata&hN??Osn}9a~#}3#qZhWuQO$J!-8Kx;O20YJ$s=0zuHL)9(rT+yvl&3o0 zKu3U00piwbsI24#hlgZ3jZ}Xx%%p!?uPWay=TVmLxuIkx4J(<{8*3MMTYyb^coioP z9>(O!U*Y8XrP6Nq0TXO#VG%o?c?|nMIEaKSUKV~DrZkmlgj$Ti3C`~A(eF>Z@jm`I zdQ3p)LW8#Kl=F5N8mulZ3)ua5{FApd_o}5;*+jyxYG}nXH2>XlRa0d9Q~OYyS-|w^ z-(mNpo9fb0g}FerP{b{J?!mLiKJ=SOl!2dja#7;=WD;oy-@foVCVxBwTR7dS5zW>& z_H=`hv!sDrt#%C7FNC4N@&4oQy$WYAr&R?lo|xH+3e-@l0UL~*HT4ka(onSgr#E=_ z9oX~obEp&wFk2ME44PmZ3e;Ij7uA3b*6mBnU8IL| zaEAKz+QvGF&7i4d**2_{Eq7ChvA#ZJS&yd4vVGsN-hvx0ahO5Dfm8@1=AB=vNyFxP zDhgn_D-I2@fW?`4-@7UmCtTlL%`fSHdX)84Y5fXQ(2GS}zx3i;djwa$IgV5=8!ADE%5>ayQZm={ne#e> zZF}NjKh~Ga&7>T*!3c^~CB1%r=VP2b{FxY@Y)dLc0^C?E+0&x~4^rewP`1c@N*C3D4MxtA1}e^jl(kt*pPNYrW2|9Pp!uesrA2HURnZ%8)N+Dx zC{Sl9T~q@$nAe6(8g2i^!RkqrVFuH&Mv?-}H~lOt+BjPyV2)c(Fb)N+vpnT&a|jt7 z|0q*G93fvx2YuYy;H0KRLeqlH*$L3@`QiHUQ{$|`WOdgZt||Bpr*6s<_&UHC^Xler f9GieQJmCKTJb;Itde~>^00000NkvXXu0mjfO{$o0 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square71x71Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4d507c1980a29c8e14d9fd5b7019b467718424bf GIT binary patch literal 2086 zcmV+>2-)|EP)Cjut|Cjut|Cjut|CjzJTOVjXm;f4`J4Z)Tw7zXY6cE&6swfYQz4s`_huqNR&$CHZOt}l6~kc= zvX@6FKQd0a(J_0YmPJOw5=&F1(*FY-fTGHZa>HZdCe4fHQs=rA)UkRQwJljl$&Pli zTGBQ+N{mLX&yS4J#GivSaPlnmA38=Ce(a&kzxJ_}70F7a#Ini(gQNvjm20{trwmXG zD^3gVUq@XJZKApNtfbVOcH4>yMJn^n!nLk+DiU|n%^1Z@Q+}2i9HtB1J#_kuebl@A zTgr}%QlcqsTN1n6bpsAgwJ?#TQocZoH?OCa&pt*SYnO|46vi`DE);Ad(QE+mBJFBI zRyH9kc}FqBAfvH?bhgAldQQ=icX!gsPrj0iq;G_bX4cwQQ6d z%#TjUjc6d_Yr@ksmU2j$UnYYDYwX+KO$Xn2hx&g$Mv0bYaYsKRoUh=3U$R3Z)U|m7 zZF=)%O5HS*vV$XH6`B*F{8$1K1Cd~^%8yOZfme4>&j+8A)s*_1(EV7kxRrR#KVXJw z)$@_R5XZWf~@kK9Y~bdt{QJ;*#|`1X0efKvfx^@~r^ z`fV>rq(LOX#siHe3=piOFp;4Jo7Qq#kQTDm+2zOwfT{*ZIEGyb76V|imxpbV_0f%{ zV@0si`5RVIoL#GT_jh(qRHb`W1x|&0!7*?pSd3i`XjJPZ0F48n)y#84bng2@6i+tV zBwcGlMjlh-Y&YFGo3`xQA(<{hcdaaDYNl3lIB@6B9({@WyN{BYW`IiG@*usMf)QXK zTq7z0sJa5<>(7xMH$4O685|HWGG8Qk$YT($;bLJ}$gFeh-W_X})3PTX zmfFl~V9>qg8A_5cWWKg3hf9aS;UR*pcxnqJXU^a0UlKKRPb85=sI@iMqSf z6cMbL$x-X#`LuM)147ighdt_Ei4R4j9hJh_O-8@~Cw4u!LFA6IhvHOsdm_+dniq9S zb&Vo2Y*sTlv=`a6X02FCv+lS>-n-qa%d7bVvpLpcZl~nz8C+c#eaS?FT4jz@CRgn9 z_#jKgg6sUto#l`%B|xZx*(wV6fCj*Tlrd-3Z5**o*9EC7aNxI)HrsDq%>G=gOD62@ z?wAI0d1~#NPYo=^LRfQS>AKqlE8di(H(+0!pVb2M>j&`}Ol z0B+@wF(lFP{sAF46>@Ntv*#S|Idf@suM-RxO+omBCw|Il%XSSs{Xqr_S+9zMaE4l9*ffQ2WTX(<2Ce}6=J*J#m(86kjy z^5NWp!(1~P!PZvz&(ZQ2JpG$YJ)n0TR1?4Yt|;%d!J>f^z1%K7PG-{mUUe@bHqvlR zJ0N0(wK4|~CWCW^n|wK*$nc_ZdrAT^AA`;!rX9>MT8|KMoJP-Iq!S5!5awer27+maa*amOrsYn| zFPDz@(vkOea@R8@U{S4`dI(jRkHHv7%m`0X2+PL4kj+<2t~+H61k(;^>H{Qbxz$(_I1V?C1P^%(!Zo52$k%FW za%655{yAif=3_nvV<4DzKvN&RYqVu?>h?1bQ_LV=Rm+Kr2a%kMNLUF<0%X2O@Q}wK zTq7z4k!J-r!H&9%LBMzk7YUxYQ9uc(7W6~+xIxUvAc8^eKvN&RYqV(5iA2K<+#!zxsDD~OkT#*pfRIH+M8x5iGFr6KiB#9}mK}X!!Z%8(nrGlfJqklLX@1YZ zyq;!F`LKiVF(MR|ZotPFohM?#D%3|0z((Li;6&g=;6&g=;6&g=;M{=gFR3lYZ0avB QI{*Lx07*qoM6N<$f+Gmq7ytkO literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/Square89x89Logo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 0000000000000000000000000000000000000000..130e59f93829c624a02b0f20d91410f98dc72dc2 GIT binary patch literal 2586 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/StoreLogo.png b/legacy/Launcher/apps/launcher/src-tauri/icons/StoreLogo.png new file mode 100644 index 0000000000000000000000000000000000000000..9c1ca60f06a9e3abd7f8f21e053583af2e375ef9 GIT binary patch literal 1487 zcmV;=1u*)FP)Z`e+kqEB0X%n>IG@WL}wjuje~68OIc6Zsu{5*13}jnYqmT=ljn&-#O>| z6G?P*`?w0O2(FT=1*8R}1!OaUSnFQ58wCTyYlo)x8$DDC*Sft52c%1 z1&E~p4BXr*a;dZ!>cfsk5lzHk50>2L<>g(ZFU?{0_dhW;I)?K<9mC?}6e5m;Xgmh5P7hhN zR(1^$Svwr-4upnXh1A6D4)(Km^)s45+g4>j(C5scqR=ulhe>*xM{Xq<%uqL1QEr6Ckg-pTms0G z-KQ7Yd%AGp$T+@vX+LI9oW1w_~IARhYUEp*>_9WpZuY7Bw`z~z+e z<@0Fk?$8|i>Z#W-{o8Q?)3G5ifq^iL@|mnA@FSnTqq)GaFww>^IE^OD(Yv2N`m%WD ztcG6DoH2nnP7<477*6y=BSDndZzYXbUk~=Z_a>aq1iaOJU{9N%i;$g|*vttHr)cAw z0$pce3EM_)!QNM&LvAHiszY@HVe+z0kYdSBbiFCohGtycpv>$7ZhiVeY~OvG5{nf8 zj0uz*QtVhKNU>z6niD%{zDO8H;_VoD{;@*BTlIQG3})NGip^q2o+rgN`(ike9f$6{ zQ}Zz|wW%7do66p>)c9-n?n0-qlpEj+8`XTelIZb)9t_>HTYzM$hF4`E>|)_zyYx=R zHd?X6x^!)6W!SeB?C@)E8rh25Q3riD4{NN3;*Bz|kbZl14oM#tuUbzkdW0WlXBr>q zD^^)6OdMMA+xxnurX&mfSA~rf)2(O^)n@Tv8&xL+df6t10BMqIggM<~kZC3g0;&RpSGF7X(%-D0MCJK{X zh(KsGhp+k56NNU#uA`3lMLwT8Jf@s(g_`KTZsgSHxcu#^9kl~t&m(HbUqAk;Gq&wG zp@o+=k8=x{`0j`Z6m445YVWn^UXg4TCoiZ_z(L0gA@O~w8IG(q`NJ=mIdMievzlaN z0!&mY*--7!VM>!OoT`5Gg9CwUm#L1!*XmBmhH3|e0#@9nweSLQ0nwE*(E5opEnbY;!kE%`}wpAM5YI(&R;a`NS(Y_w8ZH!_MXk zbmeMCZYiab4b=_`1)Q-to^rC&;zfnty1eb+FNO>21Syu@U}7^T7*4gQjP;4w6spAt zN;XtGC=_tU=6Fh`<2|z5f6hmwcVgSYip^rjIzfshJFOiv_^unS8edY_#VGbd+(iln zoUu8ca}DM + + + + \ No newline at end of file diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..2f9ddbfd06c1bc11f683a5af1780b61643d86448 GIT binary patch literal 1451 zcmV;c1yuTpP)cQb0-e& zgO}3*(E-sy5V`JN-41~+Ef%beu37CKd=xP1UIMUDZ1-nRB$@@QA@f?_1Jj8?DhtZC z!{7rgA2D!kTF+9-T<7-!KalIeYLM*!LZw_2Z)K?nzfv*5TMctV*TC3r3T`e7PrrrPD-%fNbI{z3P42Z8go;&r(!}fmmJl;w z0Nk8`lTO70P~#B(u6TP6Jr4}wnUBZ9ax9glm+W|xG1j`0h0@ZZ=>e7yGvH*>^%99c z8+0AW?njT{sdrvOWw{u8LsZn%vs^evIfdB7>;ZnJn`C1C-j@56X6NzHi>EL$`h+z4 zynNZodbU@Zyj@%n6>P~qgC3YP$!Q&mx9q@9Q>O-0 z!XWBAWO1E7C}o>BBwrr9D&84XP{62t(gRFUoP z!R#LsIQQO1p|m&I-zGo78l|bHC#I#OBU=FyyR_u{{2en|oSDNnua9AI>K5E=#>kI2 zgsQe8nQ7|jiD@ZsUl>Pj@2>haN@yME4aX=q!UQQ%=JxDF;rb-bo_-tu{Cv>>;PB1D_zD=Nw*|EaYL5@*QA!dO+z!G8x41j8@PCM4vReEAtN;)zc z8u|gsX$HG`N3|g`@&Lyurx2T%Jy0(pp!Fb(B$3@^u(XuiZ5kT-0m^BrQNy}HC?&|m zBr@^<$0(-|7mHg$$%1Hj(G#;D=*Wzrq3Tt3!({V~lpqt6$jAd`j0W*l@mdgx9Vqh< znY*6q&PhqkT>%PM?(%JgaslZvE#DwePL}?4oU- zo@$L&Ju_2ro>HRo9J_^?X!mTa7n_C7zeRLFbU-w|{skDFyXuSi_JaTb002ovPDHLk FV1ny*ugd@c literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..250f27be3e3c4eda9be757be893775a6e72c1c80 GIT binary patch literal 4615 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 NM_pMPUZH3n_&=sq#0dZZ literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..6aeea410dcf8dde37c8062bc0bed7fc3aaf268c6 GIT binary patch literal 1628 zcmV-i2BZ0jP)9(E6#njeZ{|&z&J?kPse}d+)C3|ykeEoKs6jT8C<|5?LtMxX6BjN>Oxzgb)&ygs z3pbh=7Y5_P7%~1u{G$+!KY@kN7HmPK?F^ln_vT&Cci+rV2=u*qZ=Mk3rPC(U&b{Z{ zbI$jj@7y}L2_EN`6EU7*X{qMV+S~<|)gG$f#`gO3!#Q<54DYu?>P9d=tuxk*=0K7? zR9_d@?QcrSmn>~9SU%9uT7JhDw^jX%i0bFbD946n+s4qq^AWUKmqIS@TR8zkWy$+K zwBHIHQYy7GD*fqeG2SsoHftBrtXIw3Ii~=p;CBDaZ#3b1brY<-y9D{-66hd6%lE^m zrEnxQPgwapJR0Aqp}b-QYaf3Il}+nVUVR4&OH1t(0~)h6%$%CU^w_VM{N^|=oF0dh zFTfovB9N$utOk|QoLnU%RHf%LLc{QDfGfn87B@M#wYtX~VSN^~y90+%_d{Q%Xe^SJAYN8y$S@zLG`XwKE(EGa;@g5+cug+@#vMt}~?O-#X- z(~N^I*Q!V-pTpeb6hR10kM{FmD`aiR{ci(PQ?pcSr z?7@SJ^4x zlgZfy46R-no>ibTOQ(gLSRNe_;*-A0YYGRc_weM7O53ivpI23M{C@$kF{uP$P#7BUTs3ip^D|5JFPD$Qm-Z0!@HQ&$6POdtDAip)29 zAiJ6lH3u8OspGOAe8~hcF`_k(WD+izcZ-<#YRo7yOBhsVIF4lc)c>Br#Fsw`w7ZdN zFCN(mPf(~_7#}y1lF~D)bmFp3A&<$g$8hfF6QVInCi+plWW_=zISq<>YGO)CGkVFu z54ITI#X82`crO%L3cYu+S4Akp+P;}eP}EZsQ&PqqwZvA8o`->DL-^_K4>0-NF$@T~ z2A+4#C@i$qirv#lT5&2tQBO@=8d+{S&a{r0&Q&_&;)-FM{``9!dF3s*#ZtS`RQ;XB z8ssn`Rz}pHI{YmLrK|NtuBJ&Xe!f^4#?;YY@bSKvjQq994S`Osu@{@Pu{JnX;Z%a6 z{^X(0Fj!e`a@nAW){#T7&OBDP8%chC{EHv(;hq;Tcjlb*OYLcgia+g8Nk*5J8Qav2 z5!A$#lvHF)FQQp@qQKArwm^Hu@Vg%@bZnb(IX{w|%Se`yPgrc6Bn39r; zjDp7KZzDq%V7#TeL`EJUj1q-d#H<0PP!NL?Vh_(^JEFpA9z{JhF(oAx83m2e1JX`+ z3ZK0YTM05TiHtnJ8Z#)wS!|#q>$vAJW-n85P9VeJ{Z06Vtv6Ubb zlgP|)fG~=5Q*qUoyNPy>MNuE7Szr_y1x+`bIDeI9&T4~zVPYL$C8lzsr|YLqAxoMl zOI^kxx`RlayzhZuQeU#9y06pet~mR8-SuBzJob8nYF&@Z^M3E~|GkXAss1ejxBgYA af6u>$o)jD=ev&Hy0000Rp literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..7bafc552c4e7dadbd0b6594f350fb1e88a34fdb5 GIT binary patch literal 1399 zcmV--1&I2IP)ue$b5|D8m3C^H>rH*!^p?SAcuKX+< zvB3AyX}6^oJ{)%h?${{c6NsmPHxz*7rqHf6&~Da{n<`+({ReQ%?wy#}ej8Gmv^J1e zZ=$kP#KqHRQ9QAT^779DB%?t5wzok5*cOuE`tO&Jo1Vh{g@c%T@LuG1+zv+qUyHB3 zMhoS0Mf~{LF`Rt&6O?{hLS`bbRSf!^57W;OhpiEyQLbR;!}sC9^G_i^cLzGn7QALN z>~a5^W2D6_+lDjZ!ggI$mVd<;FTaB`AAAZom(?@bYH@c#d;rY6Jk=~$vG4E`xcj+7 znpyULNIaI#!8}Flq12Hv~8Gq4PM?y z7K)t+(y9brJHLXx&pd`*k3WQZxg?2jV(p8_02n0Mh6Brr%={jyLhB!dep~=1lma~OR@t!5=!o+CdQ{opC>Z#no$ORf-f@=%B|D+xM`|N0 z%HafHJ1%nDr$a>k5bOe1gv`_Uwu0=4ZjzD!&|5%8<{&ki8Hyyn>P5QHtWMs+(4pRmW?iDw2400S)6L#Bh1(ye7(u zxFD@ahJ{K|%*chsv#MdZ7lH%_nZwI7=?yNP{$4o3)0qnr0ni0OCsq7%QT03}F##jk7MQAACMZ$>Rw1z zjrxJwKsqU!5$bteHUl%KNbz(^oLw1TzxAO?2wjrCpDX|xa8`jfkWNaCxf%SbgtIh~ zAIDd(zK08EzC(IE2fyVdE9QF4!y%)Gr46K$%1%v&S17*USLWH8W79X|lvMSbH$OsV zJRh2TGfY!28K;M(4J0U<5$btLVya3~;d&B4Sw(GSpl!p^(%TAKkW@*w;lQ%z**543#(r+7&7gOqWDVLtIw_hF>Um0Hs!9qozJc<9 z8i3CjmFo zWey|MnuTk!+RJ2^!27d>(!9Ll)eGmi)BRlnn#xJYQmyWa-oO8LPsCg4tJ@_ZK{%W* zI0m@uj4fc}e4&P|uUW4{1vYaP){4tu>zn#50RL|Qe*nkIfb%r&mSO+^002ovPDHLk FV1h2zr|$p& literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..b441e05837715cfbfca47ac4002e9bba7ff87b01 GIT binary patch literal 2972 zcmZ{mc{~%28^>pxk^4x_#2gL7Vp5LWIp@l4SY+ml4%AnUY!v1@LXHuU94X0BU-xWG zIfglMgp6{ONF+DE>i7Hi_jj+ zOeGO8JQ4ewP9eLQXFQ3|_bXMI_#iejIC;xFcwhm|$(qb%kq;JDfIB6Ai^c{Y3hVn2N za(2=i+Uc{5~ga( zp?bDJ5W2HXC2PQ;DeXbu4d1uY?|0s|aYr~qG-n1^1D{?jbCjeC93MGdM&DQUj#7wO z2-4=pjDLQ8`}OYlwgtb&LcjZABAJMjr!Hcv-%vc zndw0!GY=>Rpt(O?Y%dL;1{o9)2E6IBKa+5oT4MmHF^#4-^NtqKAp3s5uQ_n0%{wDj zTP~R-g~+lU{&YQez(FOjqcB#jS%fva_N)$&AFkF*QMEog+_hU;F+Z~GTwU$bQqAg{ z|Ca1nr)(~kc>w!i)jVLMk45!YDWkRL zT8YMLjU|m5Kv)9&%+#xs-9;i$5Xwx17fQtsZ{$$(w$4zP|BY&i^y-H7p^TrMd2 zxA=X8a z^9{RIy7IX^EB`295cj%xq0@JHAbg#DJ?Oi4Y{Zp^dnQMRGlHswxP=zN61E>?$%m#( znl>F1=Q+vWX@oT!jox~msdP5^=?$Pwv9awGbUD>jEj0cGtG<6>;2B!#B&+?)vlMOS z2rgnkGBrUbeIIz<2=b=vdjz{@csR} zAr;~e=d|UbIL6C~2iKdp1Eo*jR%m?gw0^uYU01cg(EI?Mizk)<#$?Y?;p+9b`tz(y zYc4Hf8BZB=#n07;4XpA93K|a`;5F?SS>vx>HKZu%jr@uFO%RX5540!Ivm$2$Z|saz zYm9IoGMZ`(m%Ry>;6$pH1E1f%k>?+8WI#BG%e0|LbVrCHyr29e}E*(nPgdAx;-Ok*`20AVep^t+2ac$ z@3Uj36r9eVkw1`9mQB$<()Duvs3o4=@=P+#-HFDU=jz}AJYQoz6v&d-+g@va+QR|y z4~g?gV|}@-VS2$+A{I)lKHV(L2E`!0_`$&#QnoA5*Bn1|P^n-N4#7o(szuhTpt^q-Rjy{lHhwMB^)vYRE?XN3Y)8bcEil5J%u&SC(g$A%r-!w7Hhn5 z?Y24kwZaMqg`}QEPJL3@Lxl~|YDAX&Yc$v&KU8VWp^zW2$cux~T zTY>M5pSc~g?(Ywi4Qn!Q=*ow(LNL+soKYc8u1tYny|c1OzUp1`O>{p2iftY ze=SsE(={^YT7VEc#BJcKdF{#v*($RoV|rgjXXuj8=}4QGAGWGFPAH;cVn>tlJ9!W$ z^%F75?!?PxM``q8E{?1#MG{1`Zgu3wuN1-51EK~X`al@1FIUc0jjEKNE$I? z6L(F3N-Z>^PJ?x15Dfe)u%6hO7A&LRA3+P;hlhVEesU}(9%t6Eh$9>EC-^9h-n8}f zq4uv`6A%cweMpjTWgik+!{9yGhIhpPi95Aeblm6RX5VCR{INTGNS)BjLW9~#B;BTm z(LQCHp*a3=xT{*^ovssgM5Bm+Jc+KtTj6#a4h%A$e*D<(VW*U>5ARpHa=Ew)^}^>{ zZH);BAK0g^R;sXnZrF0P@iDc+!lwU^IL%c+;Kk4Ufl3nl&79gPV6bo&!fU7f_%GEB Nur#wZtun^M{Rc2dkL&;d literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..976fce922755988d858b203381aec798afe95e2b GIT binary patch literal 1579 zcmV+`2Gse9P)Aao}PE>h`2aHY8N z2Z}32twkcOf|`}0t;RG`fATZ)CYk?v&-2|klcuIK@4cBfi7if;WSE)v?m6dv=R4;+ zHx_R4hjp_%U<`VJp-k2tVO z!j)%`)%_e%eHqVaib19rUN2WrEv?H96%s?kNbSjLqxopo>!_^SsI1!%_mD^pBbH9X zk@vYXemm05iM|RMBkt6j*jQOcI=2T0jy{Ho#}6WR&s|9E&4~l1=YT}JvXaNzrQfhL z_dOQReGU81tK#Sgtaw~@q%jy8?HGOHTq0kyixSBc9(e8;?tS)2j85JGOQP<|&gjT) zxw@Sf&3XgH#jE)7y^k^f*88Ze*+^zb1a8ju#1F6wswd;+SuPZ?@6dxd{OXIiefmB$ zs)G5NK*DuAJ36qCA^Bj4lU6c;l^-tS{K;7?oWF?F$Vdy7;ha#t8b5Vx1~aEm!b&Aj zwb#WkBN$zBcQh-xh!3av3SXRf9rJI0C{B!en-;=}P`wZ#&^G?)o2N7^s)Zs9%km5l z!u72n7;ZG59#)$ezU zn4dGQBrxwmNS%G=1QtHKfYjKiW~fd9*}4nC+$DDl+c05?dBUb4wAq*O?fN0R*Q_;k z((~Tw@iED#imofsw9~Q(dA_n<&}_qm)tD#8yAiZR++E8=ZKI4aq2K8jo|byDArLd+ zhIQaZ@L?oaq|&*)nkvaQ8mDfw{T%bFUMgei_zbf9C&Zx=Ow06TNW(We#J*J6{f7@} zo+nifN|+F)L;J=tIrA`TRc{yk0%iCn8F4BvCmx+{6)7i59dv!2kb84?@07Jn#B~LS z4=Z*3luXkU$Rvg`$W7htRakd0_P2`|EArTZ38coeXjH1cwA%So*TW?tlgy1uZDD%@&EGrW zz}E1EpwW)qo+Oteg+{l$O6`E@O0PxuC}sFMVsvF7!bhM}UMrxyoYyxTxD$f;O1_BF z@|suao$jpHHN~l6iT`TRM*i{@`SxIqS1p}U_;m@TzgH2HmPPAm)oUGK4ImTA&y~6F zw2mD_72Y}!fH2+f7v_bGYP!qS!l<7@Mm$o(E`ELywkRnr+y^!16oX5DtzzMmuMmr+ z;5427n>j|ET_`myWgy#L*NNT*Mmm;G;^&XfVdc^On6Z* zf68`2YuG1Vdr9vO#R%C-1r+t0yDG3@$8 zN{V8H{XFzo#qE481--Bh6P9oxY#8}OCZj)heJDDR1HL0g8o>!g-qsqHGLTA&VubJO z1k@DhUR$O;@D&ClRg!I(uylg33DW5Xo(lyX>N1iP;MA~`fmBiyBkbqd60@t+SeN`^ zd%z0IB1N7jRg!I(utD-D^kgpRa92;IO;c-F%0Mb9iV^nnx+SIq(wMQgVSB&|%Oa(D zo+I}FOxA6&t=Ar!sM7+daZY^8oYdq0 d|5oY$@eeMi5=wx=LZ<)#002ovPDHLkV1lI66Jh`W literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..86b4a4cd8babdfe4ea789b029240d95adf42a056 GIT binary patch literal 2713 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 TOOk>R00000NkvXXu0mjfV;Dvf literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..3a84fdb12954c0a6ebd19188277fe898f26ecb32 GIT binary patch literal 5900 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..98c439ab4426393c31463bc5079bfc9e96cf043d GIT binary patch literal 3215 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..96ae511607048f5ab04f2f21e0a389fd29ca5e35 GIT binary patch literal 4858 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/legacy/Launcher/apps/launcher/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..9b62149385ea7a81255ab6255a59dbfadc78c338 GIT binary patch literal 5543 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/android/values/ic_launcher_background.xml b/legacy/Launcher/apps/launcher/src-tauri/icons/android/values/ic_launcher_background.xml new file mode 100644 index 00000000000..ea9c223a6cb --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/icons/android/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #fff + \ No newline at end of file diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/icon.icns b/legacy/Launcher/apps/launcher/src-tauri/icons/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..0f900ecc07daf833ed540a285298e91acd060a47 GIT binary patch literal 58619 zcmeFZcUV)+wlKaE0tqA}p-8VPAVrE4=>!2mPy_@EB3(c_BE5y)n+l@R6p*GM2+|=) z5mB0;NDtC`@9o>@d+z(*d(J)Qp5OC(zJI<856PaH)o0e4J!>!aJu`b}02tr9XC@*B z02JtOElpKQ3ML8w04Oi1DeC|L6ug822r}?%-MwcQ0La@eDJ$x__b&`~*#+Lj;<{`i z6@tbuP6xB)M6yi>2dF^~Bh7h!OzFNgJ(wI~Z9$K%OOgP!twbsS4-$a^00;O50RRL5 z;J_=80T%dIL;oiDpG^Ko)c*wkQ>K5^_pjvyvHm3SKLY>L7+8P}@{h2W`R0m_^8Hfn z4EHtsBP*i2$JQALTtZmTc!HiLp#2>CkWeguM;g)M0l;9}6tr>qIu(oqAY{cdfR+~Y zX$0vyuACyn0eB5|P7uXlHw=OWh+kDvAPT+0g=3U$DkzB36pIBQ_(=935XE4h1BL~m z=@k%=V*o|OF#zTQ9`j%e;kXkx!YKh569epy34)+4{J?Q1KiC=fUpvLYP8`@N0T5R| zF0sOZ5YFu(B}0fYaKVrqPYDS6IkMpZ;~)Oc5D!v31n$8Ff|l>sdq5y~6S8(n1b`B8 z^ldp0u#u3_k5>V<0AT{tegX=hcpYo8fU%^%a|i$^ktd%ANmCIAIRW7yU;(ys6Lv0wY=CyDG|OcKKp+E-^Z>~vaD;?Vp$ZryfOZ8a5XvqLZ&AeqphkJ@ z!Wb+dIghWv0|ZX^7x*eA02q_tE8$LrB~PgK_(@On-RE4jIQ%6YxdmSYQx)`~>d12{6g_2iM^xM&KhZGz}wa}!{A0WZsUHIRm|HkkLh^zA;6{ffQ zPu+il{v*HtYoG5uIahF5DY$JRhHakHV<6yk0637?e?#J*1c6k$wV#~TeM6^~mEhnk z|9u!7?*KlfK|yW)u*aWrj28l{6a09ou-}G0wjIcS^-zHw^7D8V{Kdd{Z#ZDQcs#kk zB{V;{S_^UHI9^wOOv<=8fR_sWk11>ML=n6jz)_H0+zr6|3Yl@iALyWm7YmXIcl=&o zx}wH0f6OIEA<(jm60Um-3i2E6Rt6;L_VFx80M<-|>JK2jw-Bvwz~p0)(Xktl38(!* zMgm`9{%e`0zlZ#>Oo4BdNlL%5a~uf!^}n!j!6cJt(8s8R9Y8@q1#k%@Nus}@W?2Z{ zRDfhAFsW_`$^foo7lP~`Xr&~R2oQ~4Sm8GsZ~~LW4EmD=p&ADewMZsmJHP1T%RM06D7>;NpjSzrvCZXb|x;?nH%8?n~JzkLp z`#(TNkai5n2<2#x1sE*wYZq!E93!M)G`9tW#|af+U^juclYoH&46lN|Zy^LMtj-Gr z4Iyr!JxFn2B#vZf234qEVqyl~Qi6dW3Iu_H{}VqTe7Sz<#9ulEeL-UiKUk509e0Ae z!ZDO5<+!@C{kTA?238E~Mnh;-t(B8%zPf#Fb+igZyfla58*+?Ki%@*Vf_C|&OaRep9GbEG6ch`{ueDBuP8h* z43`zV$La*?0bEkiR4%w+9B|K8^c(Zdzh`O1}Q28NrHm2I!4*U z?Czf=Lj@yYlrR+++emQO<&R+#Cp)ld=Xe)O5d=ab80}*1NgUYVsK8@fcE^}wTrRR- zO)`%E)I=~H!#aYnL7*U%rcQQIVABFi0rEk?)PD1Mphd4@TKM_7MIJ{ENL52yVBt;`J zPfKnH>tWPC%TF+`FvaTw;fNg_2d5)BfVQHEmwQJd`S$S62I zGA?lp4~j(n@ehI>j1=ggW0tYMSuQ*Wu%HMSnB?T}u?VvuMNmX65Wn(EU&;>+Ew}Q(K$B2m$xb9rFOCz3heyU2W>cAA*eKAR z6cG8uwy~L+@s8)pP;zX{vCT;UdU0iC2}S^lLB}7@2n7rZg;8L!2_QEN7K=g8QqEyX zsHmx_60zjeG#Cm5f&xQB9gn4?q9KRT@QR7?(ZUeaR54f#H3lZ^mRsA{SeNH5MvA76 z!ctKqsofgdn(FK7>YKha`O;BPM_}R9NT#%ox|%wF0v!Bof5kyT9fl>P!ceDusSYKO zR)5Z>r=$wS!f0S_9o69kSao{<8FdI2Molis^@HD3ZqkJ}jP zoF;Ibw65_j1DYxj3!|dot*wtCkTi&pQ-e)vgji!;^fA6X{C8XYuWb@43ck7+0<5k< z6hR#XlB3Q4O|GGsiINKJpn-XR`Ni*Z=r4XCy<-4a?I)1lv3#Vy?Z4!03x`vOf*PUe zUVZ+h(We3y6jd0gIR!^{d+i^Z*R~aKlY{o4qNbn^`1qxfP+MEq@cC0X3pq^`XiQ2n zserc)A3rt}hswiI)G?sJso|syBJ%R0Or&sXs(5fZsL|wLaHFKAPQU_G{?q`~EY?=i z&ISzYh@=1g`CkkCuLb^}wE&nE1Mh?2#($p`190H&67E-4EbpGvFbKr{M^^0ifCKGa zT7|W?#rdqN8bydAOaR*xCW{q*hBx@hrG8m>Hc)8y=ogpIsRP8Y_uz8ud5I!CF zMA_`5VL1$0pQlI?A8DtTb9ShBU}$mCK(*)D=^|sBr2^6XqJqWcfl&IyRl8SB&%f(<4%MwV^r$#8}@?vo<=E9)7L=VvolZ>GLBtyty0601 zxDc_)?3LncEbQ|SnHA_9Dnnc6?GLIjj<_q|X&JI935`V`+Z)^;ktCZvTWs&;FTIaa zj1oq2&H6f0o=`0od%G2vEd9}yX$l&)Ibq;$G2DOUxq^>|>)_<{B6aGn5FT&Lbg6M> zjVCqZ(a3zZ`)z%l+^Ohf%~aJqr4m&F$?o;s9^o;but#r|ePdj1muXoq3QV$O@mnw$ z0XSV%5bTka0@X58HQ-*MmHs|>&1xf&r|&GqzGGf30GJ5N#<7fhWL8=*_{pPHB+)5Z zx7qyglLfVb9xX{zk8-MCqCJrz@P~o2OKv4wsqA)N%|en}X3R+@nzpom;0FSS14hX| z-CO8HfO$%Ku35Wa>q0W7A{@?**jos#=k(OFhfA<4XdIO8xGcL-k z1_U`nZSt#)to_b z+}C94(Y$Z3l=T)UmtRO*WA(y zeg4-zz*6|Av=}%s>+Bvfh zKdoK-iVaAc$ONe#zvj?kc{25}u3yQsak+;>FExi7nb0}QaYM1F=*{Fc(`l%-Z=!!q zjo9{Qs_*DoZAwF0kc&%i0(&qgGe@@*C`GMyGPv+i> z#!4`BEPtdQ34dr?@=BIprPT}BPM1J;fvZHiMNgB)KoQEWx+mK~J@021dOI_|8@L15 z6Flhn&IYwQ7rUP#F})krY`pB}?j%FWE~mY6a1r3}|41Fq1Olj6%by?V2F9qoY3{K0 ztTpeg@3jl{QTD$&`{e3vW>`O#8@_pP`k0fLIu+0Cx3dpfEr5sbq-TilF;+|Y4)0DU z=H)70dn6qdsu+qmCKy$J<|%U3h_3-XcQMG6W!m$7El)G^OrkMLE&aSgDr1%k^AhzN z^!*dG%wcr;(XH{YoAO#=n+W%152;Ookcf}prd?}eTGAQ(waAabwxyJjk2}wall7KA z^pX@T`{)F3Ao*0^5jTrnpjsxb`L>boNS`J}qyJ_QEn5!#mMD(0f+0r5sjpF46&oR6 zD9$+&H`B|E-8rOM*3?|WHhtURJ7_{h3~EoomF*+VZ)v6nGF;BO1SN-D>Pk_3_%JbF znpWa(XkVWdk;rnN*CRPWN!y}#%p=_)_Iv3-jU0waTFS~IJyrEmWF9)0($&C%dRF;; ziRaPR$J`lC>N+Q2$bFStatRoskCg>}v_9qSz{Youl8cAmljhhG6z|zZ5LFWx>us!W zdahzKPh?(K&p`%(>7c*;8g$Glu;<-vc}tHp1NY58^9*JpA^A4O9RsONR-q5h3(WaGKYwHjzYEqkXxYblA*f^r2Oa&vQQZ@)jo)=WX(mKtwM$7bm z3l58L$vBCi5Y&x}pg8&R`fWSA=VDLIEvl!u-!nZDyZ7d#JNfC$!_{t!6=}|CDQd5j z_Ep}kJXv5THE#JR+^W!XA;_equ#eO@=@r}j6ZK^|j0yI#?D;$JL_7Ytr4B!KKKv^pA<#P?i1b3bpQGnV8{ysd63N;?0ZL9bb@8s%O>Xru(jQ$2iB!p` z3Ak(hrN)U{hDm3_pCq)AW^#r06@?Y}`R>pyrd0qA<|tR$h)#??9M_?-12tXXov(JM zLrT0+JX{lo_C*m|FG=2G@;c;MYLeF3-rkn7XOZ?V+De1nED@wBg|ti#eknOSzbF-2 zK*=A^%yM1mc@geMIK^_kWufEUC6PAPcMsFQS$tm`{%n!p>N(sxTABO0&2J~-%dEYv zln<>6Ir4JGX1{(YjR;MQ2+zVBmcvtFP99}m9TEclm2AUS*SAucfH?#8=)U$KyFlwJyG(Yw{*W~cc>oa*bq|b&bUbw|za)P1m%&S`|rLV?v-kR^hv-Xo;!Lk$? zt)wQ&LWEa01FtJ@_*#e`>DL*B=xO~JXkdJ7!XaYGyy&-%>cf!m^;sd(1D-wX@9ob2 zpp)+*rcn0yQDxzj#gNYz{aYGxJS4i}6iBll#alfj9$Viws@$FTI0wyNaz8IM`6R3; zmz}Be?To-1Jh5L*I{XE_gX7Y;$5UqCtXfX|+lR6}&gy)6XH)OpaD|Q(rX;OiKB5sa zTbukjH|JLFx-5C0U15%>BlPs_d1^U5p}_Fuyv@~FR&o`lr+Pz!QqrfVhRs@w~Zj45rnq zZJLRiTzi>$Ux@-DUFVeXIYoD^7PK;p5e#-GgMtIDbYKbroT(hVNH#A@QJn!t4s8`nK{qFHv>sTZpE|Nk&QN(00NZ1;b}v|{zfbLPa=kNV=un&^HpNp-4j>eD^=d!fiQ~R3;X#kvf{PpsB*7u z@ha(Tr8#+9jV2s<=E+l3 zpq_XNo4NcT-BluwRh$i$XA5s)tMS#@%=l8KOz;Wxg-zVcObJ@v=a$xR_A zUIqJAM11(faJG7p@0{)U=zEw-|201J^;)&Nbfi?M1M$dz1}$55v)iE8?xOG4~#0Bbr-afh-l(rSvwIq z%>?zQlvUA{eGO>`SrcMM&*UkZPtm41Co-9cq?9@@7iXp39DKu2+XI^i4jTiAj7|@` z*oC>&%r0(=Du`?iL&FUV_*S_L$57$YACi$S13M%sFmPW7YZ zVTXVRi+WGG2R{qFTD!hw&A_hNoGY9tRiA(L`u5!2amzDknisX?u$~qrmaMS&Db;4H z<*YjojBONZ-Z?R6VbD(I*Gxqst)FomUB!|h@H{m&w5zLQ_b61Ut*1?wO}9@1I=VDM zLLWGwoEN&N$^0T-rUwv4@)$fgn6ypeq?mOr@~>+^cFimS0uRhJ{=(1i2H3nNS!mrEJR?Jz6=m-ILs-FU5a!yIdg-7 z1DZ23EdPj6<|6&;+J^-@6ACu``4^$fyH^w}IVh5+pQ(7IdB;c$uKGlyxu1suC-I^w zEvF1sHkXAe4lHJCrmmj|(&2`WIZ!zzvU?QNeKGX(XUk)fS!QGH+d>CRN)yl!5a*mP zYssh7@n=W7RCks)^3OP1Z3pE5CFs@U#-_a5Px#L5ai;-O|-L zhc33Qc@8KR@5!J*7Z;eusSIv2W1$EfSk)u!8wRBE!hmKB72#bl(DQz6{Iz`4h}TKt zT1ISxdrg*Z+`ZD`4$RnA=ljJQH&z*AlBZM%-B98be|~1omh*^V_7(Ya51`FU_o;}l zIHUwhW^1c9R;e`#bwsg%&?0>-dy&_k&|$mu!ZM8_uvq7&9c370q>O(6dpgl~YOwjU zs^?w%G?w|5tL{ExJMPM`eWpX9@=f*1-Fm$iDP* z_Jx{M8vm8i46!4jg3ibrcZ(marq zPk5AI_-ebQW4}wAq3+|9v@e!&_;sPQ5<#geedX)4{nKH75?PfME{bLAVYvKDwjRqu zWy))NgGbNjlOMfs3U z_T*|cZ)r2fi5j=r8nm>@4-)hT_ZQ!86wEzj_8R|+emYQ?Q3ct~aXDA@UbEON)secH zIXJc0uy=y%F8o>)t;fsG;@eU>^HrA%U7YtyEXQ^~u#bG@r&PFqBaP18(G0WwSYKN* zp)>MMsZ!^J8;YS<;Y+3)8+Xp5ZibbZZsA3rxRBKukt*oABB1BVpQ3vr;T^IGDVkv|D{*r0e;nEeLrwlCP_CL9x9Nno;A+|HyhO5 zmvL|rQn4tRIamgI4l;>1L)vR9pS)yU7-TaD0ZJ&osR!?Kt2qnR-SjFK8Ku8`7&V)tLqN5 z_-^JJ>${PhhQ_Jk+(=m1?4%8W(<8AZrClCI3wM`dYy5=U=AxtJrQhALfdm`q+mK-K z+=lZU&V!A6Jd?}ih1A>!0W)Rl#qH+EzV%{1>`K9ZU3Kzb|TVaD@-s0^O>u6J`0Gky3$N6urmM;hARSsK{u=U_!_dax#+ft z?Yi@If%{F@!Mc+h#MhB@I%0|U=c9nJ9t+gxpJeHu<+H!toIeVjTqmLRpcH)bM$uB@ z1!=Orf9@)#VmTwPNuk`Y(<*N^YEOeZ z%AnDwMjqsEzH-Yn5YJ#GFmjSgCcKTDrzO|}0bB4kP1UtZx|DL-=tq{|)bMHZN|n&E z62?dfVBiDK0+J>406-LnyzPJ(?_mH81+KJ}2ERRkUZXW0A_V|UE_Tq9rGV|`sv*BR~}vS>W*?A zaqaR+tPm&8hrZjiam`4ip)iQk1G`Ib;XqG!Qs%#;MZ7NdytBaY} zUzm5mlqovXX>tAjV^p;#B=P!y)o!kC_AqjqSOvMu@=mXcmevx2bH1h%4kUZZ4@o+G zR=I!nQ^lryZTN-o@<~%b>@F)BZ9~aH>oO^gl62e4GQA3GE;UZCIN!4@i2GEO!3&KM ztX+08Ca(vq`sva`j`T8tp6La8bOm_t9e-|#ZBk1hC>GV7PlB|eX?`2i%%Rdj^s9(x}d{`j7 z2^>GHFgx`u?NVw8uVVV*+?<-7kIK-y+NgZmXKTfQehlgNYs18V9`O&T#_hpR`79>r zO8yUGi>+NhtC`=Xpl$m;vGZu5V7hgmjPyJw{8c~Qf9fn!;HBlQW=wpsao?0g^a3u0 zMI!*b`~P%yN``kZ@j-%_NP*AI=imbN^f-#JNr|W@0o@bbM0^1u-mx^5T_FNVrrLcA zF^%Oi4+dVmgPvsNRmIo=ZH&7@ZD1`+L0Q?p!83KH8=(%DkFK(RpQ*oZjUDnQ>Mrde zxlGrauL({65DJG4KD)T9G}a-@mdeC}>XOQ@Rm++$x6zlZe-M*gR&|(K zJ0qC7dwY~jbgO{z#_hl;+nDBSC3~ZmXS}x6?Cd#S0?WKM78X@C79m4*7E$y)vR>Oh z{ocJ-=V#tvfo1a249D9SuI|;WzEeGue7UmL)m%2A!)`8HO@<->FJHU-vGnEPUb+3_ z&5J`V?z8p74)ib|d9VgrbMugnoj10Vxh_{KLc&3kVv7!jdd0)5ucn~ACVZlSNB&8M17J8t5#bYI=f3pDhZ7TI0fwY0e{qeg0c;2LzZ z{lxUn(n0>kuyeBm{7t4~rAXFw#gRiZ)&+sQSdpLOD|voT9}cCg&j!YJrBZfOd3KDf zL4~Pi!&f2^VGLor8EnL%Y9o~4$q(RhkA{Uag2SEMp$E{+gSW_T)!(V&1#j+mYzoIc z2|0IGNK@~V`3{c>-F04{o2ym5TRZs~7MMD~En!Hxr@R37J!Dw$S(S=N`8K-kHC#U< z1u?p^oL049l#|4^Wh-qZdwbhNKoDhLKCw5rG*tM=kOMlra`=_Ic4a^z^Stk#>4G4+ zgS^++gh+?Knp%eclf#2L56I(R5`pv|o6jDP9gVM1{@l3$Xd0fzLL3+rQu$%PNni|) z1;T(Rb||2!4HGtGX~sa73lQ5C4ge1#H%n%Je5cW(BlCP($chp$dj`sUxVuzpH2C?B z*_+{^kD=SVkJZ1{8Xd*>e(um{cOz^oFdE7B#k_M&+vHxk@KEX03-hS!LvH8Kg17HX z?DE!E88$~3i>^z4F+jh7H@AaKd%pg8oEz0_}fl9qmFa5ml6#KmqQK4nY!p%=pWLQYgQk$s~y~DMiy2gj%J|(;K zTXCanB*F0|lh4xYITcim&V5m8UptDKl4;46&$J2yUWrr3$zDTKQ7-f=g&OYCWO-V2 ze?d;!_~7hMt#Wc%skI1wbmQlWbX`^~SWwuNniUNLm?GW1H}+Y;7{o#4uXjdA%IIxq zBo6WFu6FCPAnU$r+30d-eSZC9A_SyzRHOg1bs$ z9ydRJv8!UZ`Kc|4Zqxk1R;1fuD0=yEyrFb6GM@q3St0}9&T830H(REuMB3j}`fOj5 z`XLuKq1rrOc#26f!@%hM>UgDKMUkrDLfqKEs#MBwON!(0wud*@oPpz5Dr(3>LWEHa@xBxo;M0(Es9!Le8oZm>Xc~><6Z@b)xhM z^l`7Nx6l#JxASbTDIzq#EniadqSCAQdS%h&aisJ_f&8U>$5LikdJ}VKl;@dT%0?N> zug3?3NPC0NGGur5D+GdwG?WUQP6`Vn)sM*73_8}BjJ`V>+0W=Tg!YC4lDuc%s&nzh zSn_@wQi*iX-{a)O7A@b8CZ3`^da<#~*DM$heDFcw-*rPJ?u%@iE-G`XZGP$MN!JnZ zd22(2h+s4512@-nQ-P7bGi1ImM{n3FE>lH#V*z?3B%6%B;P#cGTcRGl90ddVUkwf3 z=nlC#<=RdZiD>Aaw&Xkgx`UPR#fuwTo%|SCa7!dCa{_EM0rv$9uZ33$-MJv=^Lb`4 z--}nO?Apgi8s;2ZblXuKwe5pbgn~;JCyV15y{X%8vn;f@4%aV`tZ%*>I3p*iOjk$0 zDt}CAc$PixjgrKDssQz@*WKYVPkciX{kA-P5^5a0n2XXwIN7gC(3k4xrIU3Gxz9Io z1;opF=Gv(#1PwMNF|u6$mAiP$$3>ws#)mq2U)URg&yEZ>h5cM-`N${;b7($Xl*%j`ahiGL|ft}PA>@z-_dQkF;Ms}-Adc;|^g7gNJM%-LL4pZ5_e$BATd*Ko~oJ-@alSt|c8qb7$AdTSnetZ@%1j?By0 zE_fq=90&9C(Hca+2+R3|mh9nL+Y?-pQzP0h5Rppdr=%w025!ih+Aw?E)roHWv5@}Z zh6X%FgT{Cn3v_~Umz@^I(^T)as|SoIQ#dBa`$d;_2?#LF_M-l5;t1k?0zwhHl zc~U(6I8K@ere9bD(0|ReBY3%+u9mSl2f1pkmQKV?oJL4PVSoI z{$M#WOv2s9&feb6#$5`A@<&3AoxnP73OgrLN(v+jL2v62WRI|8M4_NyNN+<>c7VVN^DdBJwSno@Y25X^tc+dbPI)D<1M#ArX7#L`< zB}alya`=<=$G0 z5stm#o>|mCRz9w#?L0bg6ClM|Z4Qd<1fGAZpJknUVZt;%Z-PQE_X2lQOVmem1^-A- zC*SKwH}`KB={_|5Bze?sKELeu%?fgoE&9rN^T50WiW8x0`=!c7$`8M;-9EGB@7j9D zkF`|5A!EL{Y5%|l6;=F(Q4oq(u{fz2m|c0Vd`~tydEtfsk&DjJC&3-(EZvij(oUt? z8{5Edj-GvKrRY2tG-vy>Vi6G#p_(TrSCmwZ9PyDpE&qFQUAs;?rHEFS_ie2 zPqAxC{N{Rj?^Ej<>3%4PnsPtgUy9&1PLE2SdvWL{JyWBkI=!CSn>$sZ6{CQwh2dmX_ABvbOCW5XhvFBXms&ap=>9(xW0 zK6yLnkQ_hR(1YZ=Ox|VBrMFx=SEgLA_0}q_GEvWn1qyt6mdzx+hUEi@4}QYvLqaA> zM)r5wN_I8UUIw$^GV!;V*}gM2u%5T%6Ibmdi{ms_6DG9o8`P*?{VL-( zqU0cd0Ht(w5yhUPy~@=@%L^0~nT2-WVqkb>E}_I~< zO2UQsh#hUI1Spmrb{>j{%qnyx#kU=G6uN#LRgnK!ScuCtpxI-smq7ZH;&UA2+sqCE z#f~N?9_)RGt4!SfITPE@H=G@v_T@6+PzER2P+QNhu)~_-yCbeHA>KNNnvLd+1Ms^+ zYu8ymb?+A1zqk_X`r=<@ZrhB&nv!*7d*Xz)o1xxapJ|8u;l{5q$(WdF( zKkf>mV$?b(hmDTn5`Dp}~HQTLq=72|TrS z7h`zNo?TR{sK5H6be&-2`-$Ub^9ZJ;qoI7KeIZL$y7_#t*qgmp9~Rw8+?_p)&cg#3 zIWIpjd)^P9=>Po!hw`w=U)i%%(A;sZ>8TKs+xR-R{)410p-c(fuHG|vyPJjaw8)$LG^W#`;|H3F}1WkR&i`zhJOeXXJ09r%-gMwVWJ(lx;1>k`d3a1<009jpf}Sl7>BOON%iJD<{L(?a&X*b5Qj%Z#xZ$_&DuK zR!1V(kKt772hy&nS9K~VM>^bYfRCDV;mt3y062MFcGEq?(g!%g`eyH=Cd&Z@&lhRm z{d|ybJc%^-g{!{@4Hw9hu-uY6?V5g=PS(IQUXduT_>}*dz2CTE>lcRvaZXHcv(drT#=6^z=XMW zM@7HHw>0Te;pL1OuqffKLC(0MNN7sOd6%hs7k-|3lAzA>xY+A1)0K{4gGUFGTA$34 zJokBGBfg_Q?dsjXviUPE$?&m##(g?hBTYZUt4DV+>RGQyf6#JhO$I-G;Kx%=OOa5L zGpqucGT7S99z=DcV@Dce?u%wOXiv;v3XD?>`&b(1lAi0iAFxvj;%g4-k zC|>KSVM$4}^J(Pw0xae1t8UxM-HVbnGJb7WdWwH~lHn9HRqg+^H@8t~2R9gisCS54q4J`v8a6!aKlEU^SW5 z{b=(t8!6$-)<|5)wOdL($jXusrzg+u?o2#4n0a1$-l+8GwHTl?okJhR^{9X}=yF+q zmYKm+8Qu&KCbd4Y%vI^zv8gSJ4!t8Dd2PD+3df>7TaHBBrL%rvEix7T_Qv*d#u<@(3Vbe9k)>8(3Yl|Xi``f-Cc-5| zHkYhi-%g*|(JsjG`m(!E)h_VPHIoW<&YaHZHI^_;ad=f>L;!AuvUR9~=uO?-RH;DwWw^pQ_ogm>6rGCk3n1^B|0 z6nq{b8mA*F{K$mKDnn*X9o}U6$uTiF^3)k$0_o@v2t&zv<7e>DO9knN9WK=iyOmGv z2hOdN;f*idZg^E?;d*{!g?_6=i?VxS$A1x;Zrxkre+M}%uz?Rs`a(c3eV7rvn5f!D)hINBTkQlFclzik)4Q87(y7}t8!S>LHmVp0^;f+y z=xN>2al9^7wWs3gYwNoF?~UaQvjc7Sn4jH$zr}vH7AT3VA0Ry@F*Um`Jh(JUZ(^`t zuq4+WEPB`I;`Gznp2}}IJ%k)`9hF@ABn`;P&xb)<2dnQ{d%WgPW4>zc6_dSEm@ZRl zRCC8`i`G+JfHbjGFkJw>^V!uszfIbjgR&=QhWdX#=UtDMXxF6Ap80T_CrF#d+cPQF zrk9E#-gWm}9kt3bL4FaR_c8G(om&~LkH(UxBW?k(UR zgdVYxIV5<*=^9HYID#+65XEIvT)Yy;XR67z*m|?1(~86q_GEzrV<=PL`Ez0Fnaz0u zQNV-aGJ$K7V?a$Q#d2o)-4XUI{%J*=`U_fjtnrw3cPv%m9fNOsKhOIT#N**-y8D@0 zZmJT+aB|;J7UM6a>3&Z!lXT48c#?}!Q>WhpH&44_2UOkZspMfE0ZglC0bn-tGC>Gb z+I@qN9cW696{v3xuxRSYe{3tOAopPaoB1IAo02KK$cNmKRI-)P3h3D*wK_-o3qd~Q zITR1Xq^L)`_wla*qQRzDB;ROmYEm0`|BUbWIG51M6H6l#Pl^{+yxrfHbcLkaGyQs? z1W->c=^A&Nu#{Z?_=2X>8?nH<;k_}@s_M)xduN6&ZU|CH7OenyuJ8izDX()`JKui57uX2+(EL+SoPzEZzmLmoqKbKS)jXG_yq}dGquerh7nWRsFMFL4*{6|sK9je!ml@Gdd z!VTq0Y(|UR+uxqA3}ORlENS`-%eZc+Nyc#8j_aGKHVJDnSuVDH=5()`&5z!dmHq9` z-v~rXhy_UEsq*fG(E{Ak(H9pQnB2zmHhUI6Q;Yp@rZnfc)@Jlp&X>QqO~C2p^!0&= zDftz3kEZGmdpv_Dzg~I~pIn=HF7&@1h5kneB<1Uen1+obu%2iPd@IOb5-?^W!r*gX z#=k!s9#?RJuSp;Szx-JF!PgtO{rG)0oFDr9Xs|bdXY*0r7f*;@&WC&e5`ZiHL5qV@ zU%J$msuh%*?nU=3u|+$G`vUb9r>wq``6LBJ8!ypK_laQE2u7(7qY2Fm%bH_`XI{=M zy5s)_Vp8h)5{(6ZBI0jb10>9E@|LO8y;^B|cj^9H9{``f+ zKgQ$u1$Jz*|Bm(F;T;PPa2$VtW(I%o#~=Rc6z|-|_ortp85Ve@9jPFU|gr#DDOMs?~p!c$l`-aCW2nXk)JybL>EPZQt?* z)i-%BzvnzL3awKe*EL^WnBF)kJyc&P&P#qAA&hl3SNFWw9J^HuyTjXCudi38tUIvo z4>yJaG9!WeH}o8o&Fs1JE}AX-F#0-JOM`ED0VOFqy1M$gHw!-GTlSpoaG)!Ek+>z7 zk7nx+ZBje$<6!enJ1vzd2wFjd17G(t=vEqt)M&*5$)M5{ z$ar?y>EC)kL_=9gfFLvgIKK2#&|K|ax^dvSn^%8nbG|F9e0vq?v^#fI#jT2Qp!WtG zlm9I!1gP;Pzh;49kJz2RT)p%QB}CfU(g zue~c`-35H3k2DxRHiyWMQc~wf7QzpCq&^8LDx*2AyV?~SqDyaj?bX!#g_;P9jJA@v z?#fTVS0;Emnsj$dM?Rn3ABy!`t_?*8$Sg3F=Rbu?lLDQftE7D(_w%hS962;UvcI~% zv~ybF$Su#B3;%~tNSw(|w=fl|ENAeB=YE39mWp~dg}eIPCnFY}bQ^Qc_YzxwP2O8|I50s!*6nRR|k zJo`H)`On&U_H4=&`s$w0`0(tcwSN!U8&q7@W+mC_xFvMJ_^c}MDU@AYg9ENrsxNmG zni*H02mu~|FTYYvTVL9r^O6}g;s=)u)ZVN3=#u7o%6O~=yq@&|YOw3F|A0Na8mHdw zRNpxO2a3&+yga;`SvS&#A?kTvpG~|zS0y((!pF0}ai3=|MsqV|`YMR~(FHYbo8$Ey zWGkg%%s1QJ?L=(sTJ0G0JZc_tU=)@C0MM9?LCNd?hqm_&YiirthF7R6A}9(fQrvDu zMVd%2!3IiIX$nXXmEJ)*B#H_aL^sk)P^6cDG$|pd6s1b=KrG;` z#ge_z0>7I-HS!7WxwV^BR^o1`Q&xoFHny^yhpv1qkMsbm*CXW;EX}H_tR?KlN zGv*n^;C9m|w92D8Q#L0hB{eX00A?ZiibQmo^5!%o4EwnWFTK#+OqgF0w%XI-GeP8AZzUUH`uvJ9y-j@}Li5YrCqHUEp~$-E)=;I< zvhT~QW{gLQFuMzdUD}KP>6_mzag8{k0{VPcK8@H5gfYh7dO}KsYhK|D)4W^3WdzJ>zAk!H(b8`NsFIEu2814QDOK3 zW-@8RWWi?Ih`x#;;6IxvGFyd-*VIIzLNwsj-r>2un{hB5{U)@CfAS0=kseUAx;8mI zf4P9^+wX3SJ|*kwQju0K;ps%0NxTm=iMrmem`gAkK7=2e2 z`N*Ys`y6U(Ev|SMWC5&a*Zy#NbC-(tGJ3*;BEuy-_el&Y9VC!+kpmk!OawXU5!&43 zVQ5&hXs|XAmX@0x5iI`-hZDVRwD_RYBga-Y@0h^su-w0=0ajo;mOi z`)yqO>i5f_@w7J><)HiYO*h|atT@+Z>4_vKPyv9Y)TRVSnzM= zbLY_7@MuG8cx^pqlo9G!X$)PM%bG-}B7dOU#F$F6k{b8?+7Bf$gGZ?S zVIlg5?c~%sX(<(S(zdh*%Wqk^ptsE>pzHOlC5nB$B3A;puw@3+*}RAXaYGr}8lSGL zlon0$Ll^G?@B>V(_ImRLj9x>1Vuv|SLO-}j8uTRx#bxCDCn1OZJ-vS{!PUdtUa+pl zZw^qWRKu727khEFF=>R@=jb9!TK(h!Zh0cRDT`{})e+LrKVu8#fyaZjT8FNiLT=^g z;p@nrKO_hKaJl+VMf7S|bN4PI^oF@lmBiPJc(*pL;$8Dj`+sn)Qyx8_Z@LN~b_ip? z>M|*n2L__)`GiHpvua3;iFmOx_r!16x$iZ`mFM+J&DVuA`+Gd{%j_O3U~G)VdCG%U z)4%``{f}!57&N!;cETpJA`@c*{&meLaN>r1-N;21mCX&MK^vuIcFWI7Oh?bCrOV9j z$0t}^+{aipi(`Ux_s8)<19QaWemhe9rgJb4+Ty$tla-c+T7d7_vJ8GI!;fpaBw(e-WQCpX8o_onh;2cs$~Ez?P7{>@TeXgp~sanoV6=>#7?9YFzTi(~yG*cKm zxoDpmspWE`b8ZrQ)1A!v+JpB7zyCycjXFI&%A%lq;flSz3M<4u-ZPF0=}md|WnHM< z5Yx&3@U$J?NblZP56TY|N|3%4)O{NO1jxR{h14zQh)CFAvJ3?6!NC z?2sRUg>5Y+*8=0 z$qfowm=&`|b3)w35VRLy>sy|xj7>jDw%@i4-S2_M91eCwgdX6XXwKa}iY-Twf2kec zQIePW^SD9g$56@%&;)}5uF|mZwn90OX@%0 zC@K@GoFmwlA*)V1b6i7Iv0E{BSdWeTyiY8uxMRiKbAUlznCSR3uxXP`Zf;cMukToe zN3Y81sawpiXNxghjcl76@P|gW9&ggD@ODC6{z+&TIDTwdk+wa(MGajQ#*&`OI%h|o zfrE7uU*onn*xTER|11{h&G+y^=jsTd?B<@@nwI#Gy2=$Z zGk*%@cHmgPjiXa-pHkGvgg)9zchsGm8PNv3O!F(pAFq8a#yFWYlm*-ubKHCT45DgO zqq%w@|8mA<3l-U6AA*OcjB)qJ(tL9(gn^Q&nVk~pi1`u%0abm`rRa&kdKIhwM};3L zA9}`LzHwXDrru4tm_s2cHCbt=-4WMl=?8On1cJg5o z)1h%G{-kg#W(Sn1*msz0A3*3YItk^mLRIhKoC60tGN~3#?~OGuH-$KE2u`dp2L$Go zfN2FRn7U2UrC>eDT-@VbySt)4pM-?Lf@)LbCWV9@cITaBxL=~lTo^G#F$=>JqEAPF zFB$hpP6|P$OppT*tlw7*ye;U_<5IVom)@4JOk6CGmR3YyB$=U+asq%HGTnUVk zYB#(4YO2;ZhV{m!=~~^oJHw{jj1gp&(@WoG>T$AdJc?VGS?#y|f|7_-^~;RkMlQFl zNTFxF&wi7wpFV+F(bK07uCb3)HnG_lOeUfiS)z4KAHGS1FExsbRTsh0UCg;d*PP{S zMRjs+Dt0{oZsqRcD7!-i12qiHqsP@78(X3>8YySh%t=w*+mkO~AM2Ich>eDyXu&-; z^+<@zQcEpxbGWk7qzjtbNDMqmk1Ao-h9@6?7ME<<_hXJ(E;qZnW8UnJsErnsH{7vL z{M?!F#{phstPlfh=EL2yvg1FjTdKS1om!J$k?fGdF8S@A6GYu9e`>es$6(X`;E1GTuO3zjMNoL;i*$6BVW-tEouyGYPgnf;#uD)I}g}E3o#U0X?&35t#BI z1sMIJ^h)wL-}t3iGQq`8;kUMHwfDMpu~R5M(;z|#hN>^e?Y_bJoMvcS<6y4Q-)AB* z#}uZrY}0o@Qiw!Yk1ISmqTYAlM$P=_vl*|p)mV>*RoV;}OP=57&+cR_Fgq?r2+@VM znz5hGz%6N8kzrTu-KD#RN)IkHEwmlEF`MptSB$ml`(2*slJ-wsaK&+pty+^<&b(Vp znC}m@sy=iaf2-IrRC%DOP)r!b{KMHJG={k9tn2Kp(vJY{xseH&R|H00Zt|+d3HY&A3~~4!omRt5ARweZwKtlx8~&=11kDj0#Mbn_JqzI2h!sF1pG{% zz9|$L4Esl&=hLF7J~Sw`yQP3w%1DD!_>(ld5pHs7D^wG0f#}ebw%vIKR;)l>04Ix= z2N~_}LLPQV3#Ommfv?4IGXuUJC=rJH>PvSxe73&uA>i@({yI2Qc80}j`+1Z ziHAW-y7Yu?W^f7SOrF9HB`{plRX>psXkzDAgc_r+|G0!)$Xt*jW9*o4H1um{5F#+B zapy)Tep`vct|o%f{dbK!H;+sRK^{yDmzf9*{bzd^u(AK$9t(sCM*sfxpN{>z8c_Ck z$3mF?bveWGPxGKgHDJH~Q#mO9doZAK7c%L0(~RPT;D2`+`d=y^xfg%BgZ$!~ry>P) zH!QGZ8WdCi!Xpg#4Gn0f!L;-=U8sc)YW$%AXRHxkQacPBaJlN`!*76s(-wgxQiI{? z_Mh-)FfE5;bTLS<&>XI7YaP4ud{2CA4+Y!%RZr|9Vzo^}=O7r2#S^{#nQmiP95lgg zanDCVkhU&2b_p~dI3@*VLDDh-D$w9cne(^L4CU}hwcuwwEOu4>b0P;!{aM{0Y1oh0;mnd#;{2@qk0Bwr>3*k-l(&XJw0QTC1uVKyjZ zCaYs==e2#Yq|{P~mL~{(+Y4D#=KXH`ZstuF0X0sM+I}5+Kum%G|Cm383d29vM zvRI(WMS|^Dh&%awzX*C_i%!A&FK)h*U!Ew9zN=}9FyGQ~$Q}&IME#~1-`0j8L_-|j zSzs50Syra#alt-@Hv%_FkCa?zCVqO)E49?{NT>*jh$rfyx;PNzWz4h5N$=JE z;Sdhu1hCxd>c68ED7f|bZ9f3Wb_2%$X{Os8@f6CXN4pwrMtBdV*GkFyVUV5On=k)Rp&2Un;lV=W^`2& z^P+=HL-zzHLJ$a_atRdS3uJbBgMN$alZkLQ3x(t!`quv0Ev^ahfG0p%nASKd$^^dE zk9M4{!{hVssQR{^abB8qSJHoi?`5uf+QFK^_M@mOPdo(3NEuXX_PqqEl_TOZ)vr_I z447iSjv@NYI`t}qKl~wc~=`rblUF0Pmv52YI4>}$``_w6x z;}_Q)f?<5FdwoO69Bq}C3}@TU*2wDC)`#^zWx&V~4kY6ed)of78+2ol9tYBSq|OvP zCTmoZu=bBj$2G>P!>27h&p5JrFUWz-z=_PjLj}QnABTxoCAiqm)jZh|kN|~+lE^e# z>H|V)nRzNKr08>AaI4vUxmv5G?!~KVef3|WU)2Jaa47;`p{l2j?3!6{*@9=Ifa%MW z0&B~uAD3pCu9-d_3M6a;4nErt6d}eM4aj}#W@UfWDf+Y_`fuR&W_omz?7j&xfP?DX&q=`jZr=|$~e}mz92?h*f*&pYzafi^PJLMLZn#%oy z^#fMk44+>^>Z~>KBkDWg!sAunkx;sjo6e2dV1pAACLcPuGCU7Ean{RR%@uRtWI{lB zLL1b@?b}=%)F}Z1g|pur1&tIxx{`UsZ9y{ogypXjNpCPxtxIB@<&HIyNLsz5INy5BBvyWk)Bl!WIM6(6xDnVlU(_?%F??|G{8(BK8WB^mkn#m0A2f2mWOqs@deBp8>Wx@UTd%Z~`-9_; z5ZQIL{iG;Vf1K$NN?QGFZ^|8$SV&(j*|hoH~&4zjUY~~G9ah$e}~+%Kb8SGmo$OrhOw#RHSa$A$4rp9hD0%^Hy#9`!zDG+j3IHAfGu-7<5jRC-svG9+_cY1z7(+|GN!;>3W~O?;o@D-_vt&qg zh3RNPdrB|&E_>*)w~M}SyY5g$oR@rx9BE!mA8vm?1Sm$ErpM2uyv+=4e14eT!Jm=( zqv&de+^rm`f%EU}-Wm#a6*repQ!k?#thpGZ_O1DDa*@xa6+#e)} zc*OoX8suSA&w%>GXbDXVHbb|y#C!~oDFj%_y+9G%O0&1Zt3fOH6-iDOGv~WQ3(5{T zjts|wrk5JsKfp6}FUx#67j%yea)Hz6SWSHxp5OXM^*_9=w-2fxM7Mh*Fkg@b!M}+u z^k2kgd(T?5>X9h|n8nIV8St>Lta!!hg1pbN|DG8?+w&w}AHZ5a@es68wC_3>|J6Oebv zBCF$6kOYy`cs%o&EVK)Ft-j1DdEs?M6m8R+2R?k4@_Hbp8?bQ62X&X=mQvUkL*;_} z6-^Pj?_>Y$K2<8saPm=T=CP&*lck7DP!GC=52V0sKlr9vxixGue2$9>Bu*%du$i+t zP=FGJDaKj#zP*p@?T{$~YVX7K)$xt^=@T;OG?)z6|= z`>uj9Z@AStP1kvN*X8o(bnG8_10J=^Wpyxx(d+L=t_D3rSRK3w{E*cGy1hAuYi?1w zKKI4&rADq3t1*LT${CwfIa7U4Fh}`^gdZ{OEjd`!C3}A%LF=Ku+9FeWOY@a7oQ)tf z&$C91>BVl!s?En;!ACBxb?e(z;>(UM1S;|BB>;z5@5cByE^HX3UF2i`F%M|sJK76O zyq>+$&G-8-<{3IuZ-lO|ylk$SZ@Xj`Km#5zUzOihzQNF{<}U78UN97)3jJ=>Z$ZN zp|ZN6rPEIGY&r+X+9fLkUdUN^|EXlWhbOEy97%PGhlk|uk9N2f%E~q5C4Ak4&pw!e zs?tz|iO&yQx(V$Lz%+SXP!wsq8r{93ohd`!#LIX7C z9Op=O8joILSRHEHh!IbT6izau=wV4IEevSS4?nLB^r>p$qLx1R$wen@y&}Bn4qTsh zB^u+R-dgz5)hHFZ&@N-h;v>(Br}SXB{o<)9>qK2d)$;eC>WX$L6+S5B-HeTPkyh?K zH!Ua~(f9jN`!+<|Jdg7(icb{>koA<%QhFDA>^<+dOQ>cNuZV?XmB` z?bJ9*G3d``*ww@j1e9G;V2OS0eh`X0pGq$&Db_zf^ya>v@=-ndOt~xFZ}{~y{f5@Q zfpg#8*~a0lw=bBXWMk6Ad8_{dk?ssczJ>?Ctb4|Wl;i#67CWLm7wKu`u9Ttpau}+* z-NSs|) z-oEo3jGb@D^)FknhETXt$}|)^yxu6gYj|!*}kdXZXy8^iyZAgGmb@RSaYlJx_?blTqVgehGxymMu2g z)>l?xN=>v%na7HF-%vUH#0J7_$@!h>yq#d>=(T<;t@q7BA*Zl2>km^XvmU(pGFd2t z!S=UC#8Y88jT}!%jY{o|r30XCWFXvIm;*EO$w6=& z!TY2+jo30y&T{@_h|!lSkVob2-h}|j#jq>TV2?yP`a%Amzf{@*bOo=mTjdtHH9hJB z{(BJd1C?3uGk_{d13+bb2i>Cr7&PiL(7V&VRTE@2eXay_^a&L-PfW&|o2_#T?a+T4Y!( z+v&gznL;B@rj41thjP}MW;Upp{YF3w?ojEf_C^I^r`E!uAh?0;KE<>SZeYs z*C`?{val2%lM0vU!0eFsOh0ssGtxfaEPS%>T(?cBQG<+W?qH^yN)-aUhg5iRX%U^c ziPc@-QsUe0=kK3P=Fj;{o=cZDD8&qIcFYzUfN~DE(>QBc(%Tu5{$=Zd!r<{Z)7xjo z;O`H7K*j^v>cky3X!E_2j6Po#)ziI1zo4M#ZZ6BjBIXvZvxy0V|2sO4!5hQ+9|zLY z4*G~H_M5t{zCv^B(HqeFrwMS&*e~F=Yjf~(na-BoG=U&NdUon*0SJG7lcc7Ytw5iY zsQo&wVL934b$>0#OAFs6FPQ}>5ljQkqt_``JTA8WdHX};R);>3#Ko1`;K?Ai9=`tA zTaJEUS z-_rE?f0ZV;9cgOXk*2Lrk9VZ0_5UGFz;?of#nI7qt!yhIVW@);3g&)zi{CPTcanF zG$bh|tMh8XtDQlNpVyt`#ftG>RKhWkM(k0nlyWpzWq|FiUAb<7VHeXBCqn2p->&fW z6K*c|eq#Mk6|NvpekVHJc7Ldn^USu6T;uM#JjpjU@80rWSXksc#a>emV+7{;a41`g z3fE@FbKrV*rjJEp^{J5>l~Jjyz5yT z8IbP>QXQeg8T(qA^O%J@JsE>D&!xC6qbi^%^?2T0RAdn ze3V^Pq9gPayvXySLe)s8Dt6VYq}`+ES`IvzsB{l3nz=M~XCP)PlYP$4V&FBZ(QoCR znov`^7pvFTI(y9Tyl^VNfA$V3pz$HAU1i5sv~7SOGh4kaezTWxG4h>uV-ect0-_aKd+gM;nS34Y{oA z%h3+u=}oR)U-~asEQH{Y7!!;sJR;r|tI9GqOCM$!`rvpWJnLh(mM`T6_w|<$VFO=u@R9 zV;;DKUg5)4XCY}mW`S#=>9Y)7Ekx5b-o-G3#v>swrPk{kmCtuC5!2WNpaeX~tpG1^ zVz;sGLAMEU_CIU310#DeDa~7P+ih2`!vmEL7S3 zxgewD8T1gg@1vRM$gv59CaC0@uL1xO_BqUFFkco30i2K>K5Sk-u+gUzI2Zbv--rw* zZ7LxtW2&KOIFIK-_tR3@j@=-nQoFWjym!%$lN30akhd5J=Hg1@llr1z7v2tGeo2m( zz!t7`rP>qXQsEYf$RhN2B5ncS4o`w%kC$_v?et$51$v&tGdAZlucY&?&8jlB!`(v9 zfT2WxDm|3|pCRga;bTSTY@4){A|(=Ey^H6s1-ykbT!!atC#ID5So709Q&F&QuAN{dL>Sbr@&?x>iEB@Q^%kCY=xk@;pl5l>iJHF@gq9dSF z?&=++&LBbX3gW6S^q)9RRZrAXfEK9O9JUgva#Gm^It@M`8(&!cJW(JK>}RTm`fgaC zW`aVN%jOQP#d+b$DiU76QD^yw_2rbX!8=ff`UU=%4EWge+2a!ADu&|MO*+|M;DFs{ z@mY|bWs<=f-2b7Bh?`k+b_%{FbU+cZDBQr;TGY+C4BLwlmijmLK$5PShobGin(<8a zx%{FG_vi4lG7_>5f92bFKen!zFymD&B}X`1pb<5;+Kqk5IGi!mCywR+6JKczK|D(n z1XH0Y6G;Y4<}aA$2dt@kw2{`@zoR26Qzcj|j-gpV_6H@rsb`3SlbLNbyAx(!BGACs zvXfj~(4wOM1T%`qwQ-I#^8xBq51L72-!@>LVu$6>%bFF`c5L0G@o-3{>LKY@E3G7t zXFG&vx7)ddC&2?}AH9?qXb1Kiz5NIfeZTT3#PhiTlp%Y}Gh`}Os{4)NmEB+^JV@RT zzbly!+N6jg7QF$8KDC5s%G}H443_@5-t`6;zWW0n<5E!1_03C+jXw4-4#bo9fX+-r zrh{dDUT*r)Q*{~>0%lrWo~0*d_l@<6)SXrR@-Sd#R0si*#ju-wBlkC0he}u=i?LN_ zPp0{G=fki&B?9n~SI6SzS?s(JBUZejb&>pX+0=v_P z2S~AA<$a_*5ZLV8o~K*yQ)5uO zWG@$NnA7o`fo)3$iw0&KPfj)e(*vsdQIRywx3Jm@;=FgjSs1*z1U@N^kNS3=3DPdR zbttt@vOA>I=$Hq6!*lN1PI9ICNR4tzF>u3D2b~(5Bx=EF8hP4U8c2h(EG#K*m}dK# zOF9IoT$MuVdQ~dhC}Wv>NU6!l0fpb6uh&W<$vA{T`|PIjH#i_c$HmZ zSiwD{7fuWagxN>W{7(?@dc6Yyqhp@0r;eWQ{!3AP2Lg*800MV^L%;*L{erlsWH)s;cLP=UIAk_>Kdw1Ni(m z51jo6MuZu~{-5Rk&)E9k%6&nxK!P-ePDr_Fmp zSRi@{d<{TbHKQd$|2M*l_*)&lJ{sY;$`DUMcQ6p7Zsz+1H%Vv<3Y4Hl0RLa|FfnpC ztJ92qr?--1yEPB;u&xN4pnJ?r@c>6!FmAv{bX0Lm$q1xxJ=Ah&lV*qK8+$WTF2~#OJb0lq4aC!5T_W98@lwB zAV#tdg97e^ohl z)km^Ic-=Jr34+j5W|`r`z|H#C^B0T15seXn16Td<>3TXf^J5>PRs2t9W~i?Q-vu$3 zTJ1^Gs-8Zduayr!azGf9e5AZ^W@lDmd#qCV zm&5&{StlnWW&i~hoADThs{3x@>bi;|zR>67#uHF?sqR`Zo;iT&oe4XSp3(`lb2Pq`4vew)2uk3u!io>&^J6i>Y0%4F5IQLeLN)9@R zfaXae@WqdDxBAsfP`3u+r(~^C!8Y{Pg(<7{0<@Sf(cZ2MOvt^|G*V)P1nwq-xUb}%7mEYh*PV^&^o7ki^hyEw9UN$7`@vrqj6LaoA(rhb zmy&vN<4gLDy3@d|d|}aJvYno@7V+2AK9a}edpUG-f;dQdo{zbSKL&YtS*v%hpgKF6 zVs0{IB5t;9rOsczQzoqk7Z=UD-;<{bjkUnT z%FBIegGb$_#i6IiF_KTD5pJ<@`h)Z(@u+{Hj#o(A)vvDYsXCt02_mC999&V$2UkNC~%|j5I{l50W@g^9~Qz3f$E1y6GT02?hgY8KbM;&VA-S6?NWXo zXO6lT5Z4I2_*EI1<3Q;@cpp-#>Tsd$I~v~++>NGLW$a%Wmb-QAt$p3av~<#;@ibKx z=`EgNw%SsBR#!SmF^mD3x1kL{U%cn&tAl_M2IDt-W@s>zG)E^~AKe4Gw`s zCnCA^*{8?)_z9sX8W(I|K__er#Ou*QQ0KJMt_`_2Ktk`HOcj~A`f1$ftG4bPR2gDkKQ(jVQ#6Aa0E8YU;FSj7ZIy97rDfrL)4tdg**=`u>)`XG z+Ij3NwDOftvh<1T)IO`B#*>?Z2hcB&CyTRpNpbhTzsJn83&+F~Uj0)04oA(8zplOb zRGq`OK6JOiuQ?<0)Kzy>c@|c~=G~(B9`);kuzTR#t$11*N(0~ddi?|QO{`7Y^u?3D zM43Yu0c|cTADCLPz$c2sMQ(y-n9akC&@Xcdz z7U2~SZu<|Tmb<5|tL+p;ji^E0muwIiywGw}FMTZ{<%>VnuDax%Y82tr7-K(n=mW7a zswFV_{)=wbQ>^sY!nTF%S!f zv`Qm>+iCmh*^X{=uRP{1E`KmegCnP&w#DGO7v6XMTIZ1t8iMTb^+vTn($Rak!N3X(2yW7a<~5=Bn#l~G*iP=)v+tzfuo}K z^MMNwDfXf2+Ko*S^XOcrnb79vCy!4!0^+W97pzJ@AZ&=3H(&x*>QF(FUB(77R;eIK z-JOxXg;@@OCWKZ>VPp%!Chhc6ZCk`BFH`_PYPq-MqM=>Uc^Y~&D62oIelI50@y0IT zZO}tEskfut56Wu<5hQ7bR{;~;ZVa4FON6NdR}A7pzqoAEyti=ZqiLwEsGctshjU_L z61vlOfg5XGVf&Zlu5wxe4Yy__-50#?Jq;J(K_R7d8yEn#d)-2jFoZ6&-EsDym-|ya zh|dyz$ix{Z$23Sy-t-&GFTmm5%0A|}kCi^;xn{v0r?e}<3y)c$ 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/icon.ico b/legacy/Launcher/apps/launcher/src-tauri/icons/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df5c35857fa73553d368a2d56c7bf1f4c42387c1 GIT binary patch literal 13052 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 oPCFc!f&Ndw1Nh(X9{&9fUp8x;= literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/icon.png b/legacy/Launcher/apps/launcher/src-tauri/icons/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3f04b041cc0c1098338a4ef9c56f98a6fc0c62c9 GIT binary patch literal 2566 zcmbVNe^69a6#nkMW%mKQ>@r46BJegcD`vLW4{;f-eF8~l8e=xqQ{G&SuMlTGD}Q;m|1jTD2=)CmpO>?b%(k`K-;nZ0P$k)Mwqu4=f;tsGv~ z99SEkb8KDCmgbye>(<=NPB&Lh>ls+ow)9k_FS{%4yAi*D&I3j|IEh#RiGCO$0t$Um z0yq9`=>p-2B>zc00Z-I)uGqiVNvwp#e}X3t!;KtvF80t>KfZJ3t*2h8Dj%P>y1D(C z&%PVU)TdtUro;0+UP0%l^`=_f;HgV4;=tn3rF6zSN7Ahl^vxSH>7;#6?j>FAc%DrG zpO@<;%HosjnH$EZr4FKa0!1ceG~Gg!eH-0iyg7F*Q5KI&RyUzN0g;)2*`f(>6>--i zCq!+m;TvxORAWt*DM-++e3-#}3by<;IGutD1q)yde>9kFMWc7LuehA4C@N3pPWYbE zauldNt7}+o5@+_>sRZ3QzPpw&USSJ4ML4d}>bqtjN3eOqA7DB3?_Hq`3mjK!oo=Z9 z)isSkadPVnl1?{{dLggHfQ#{O1%DHfv-R2%l1FH&1;sY)#&l%*c+Jz$%UJ83L`gP| zUJAKHA6r>ZOF71r2I!w);1Y($B>z_=kgSi*p)?2;Zn}R+gl@x`JK!Ir6+v$=g(@Nx zu%Ibdws)0s(2m~Bm0fQ5f8y;Ny4T)qA9ez&z~8rbCtHy=T`iZO1zAl)odERU)qWNg zm@#At=7lpR0!LW)q%4@3cBH9WMNC z@)&A{npQD^+ER_EIH9Ff3Bh>xe_2^)5~6a+H0H$V-1LNXxE8^dRZc zFev4$<=0F#WY!d)k};b!xDVYk&4P&?&QQLrKqM!gH8%B9E_=>Zf$l&&IgK>+LHLx1 z7e0_siVeDQIz?L2X$dyQCVW^jvd)cC7xv8y=;$3Osf~ z{Ce5T9v7qQfI?#bAaNcOc%>@Z@9pUA%Nr`T(=Gqq2E&K2f0KoF6F-kc9pP;l{yv`< zu8$qGd3Kb4_;etb^_yLA)&cW6JJesy%Z*i7dFr-Krb%XB#V;j19lWsVk1OkX+@aU) zp;b!PawjV1+tjUbI!*X?pCBKK_1B{7)Mw*&DQ!d7Nr$|vjS7j;?tYyG?=f$o01r*p zJ3b`6HdgipBF|GIa|~?qrnpQ2Z?Bwa(^ubP@ixU5&R}tjy=8?yzI%eLtP>(>G-K)V z3Mzy)pu8XiuZy96n4;IE!~X^%x0F*2)W<9JS#jD9AtDmZBL`wMWVnJ^G*9>G9SV#x zAz~ei>Guf{fq+wF&&1%?DxD-n9es)ya%iL3_1bAN2Me#+2wg_&W5el^xs@|lp|yrQ zL@?^|AYX=o$>dqge~7%nsTY!KtU~B&vK^~dP4vroG-f-u6D8HCBipIe+pR}JDTKQB0_#cZ|}dQnx57hY~}Zw9l3bChZ3=n zixN4sYBw_PD3`OQc0=I=867WoYGg0=^dt`-VGg0swpAu?4d+|mQieu-w<26FpsnSk^fbhtxNQge@$}ao~R*3iy1AP7^PQ=7mUP$8q qRcCzA&tod*S+erdzwA<*A9%5R!>sEc%zl{mfw?y=DA`)1uK5juq%q|H literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@1x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..15faa31a7a9967cefbdae9653bdcff7fb6036388 GIT binary patch literal 672 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@1x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..39a3075345f156e672e231a175d95a7dc88ca384 GIT binary patch literal 875 zcmV-x1C;!UP)?6B|1Oh4=qDiAxfoOt@fqmd{p`iB7#<0DPp6AjR-<) zq9Bn-5G(?c1rv~9%$n!E=JTFAn?yG=`%=`xS%%&DcK5sYo_o%@pPOoJxA?=Ci@$LF z`$3K4z!(E-H#?%we3iW48`MM`-88?r49_dVaa>72f_YY-jfo((ExGZ#Uk=KRa@i$B zTN2oFbO4=$2hrBO8HY0DjZ%gPt zHi&_Xr?9Reos&hcBPO zz@^i&aS4UxRfUw_tzYaX(~G8BG@-Y*A7bpr9k_ywW*xA5Bo{?v!h=ed)LrM1KA)vtbGB^DZKAx^i599;It_*2-qWeF zF!jP3zEC3LKaq+uQ+KLLq;gNQ z)3Zu-iza)@Hp&09nOT$yET9UJwCQ5r^if({B>@@@%zd~=W%5p?Mma4$jZLVR(%KZB zMuK_1&c9A&kQsd=dnC80AkdLG!f4(q8#1Z^RxtpR9l!NJ?bC_6TmB#DNE}a`7BuhF zjt=RwSF>V%Pno24c3|?}6MT5|%y%S_UR{RI?vn1A7q8W{yN3G9Y|L+-8p;ST7}p4C zLXw@l`xq~;j>wdWH#bkYDQ%4AO)sUj5q{s3{eeoBGAMgUNLeA_tvuG$7Zm;+CfzwL z2o=3_D{GLaRE|A)Zvy1og0~pc_?l zU{iOtdpRi|p66EIlC1y$002ovPDHLkV1l4< BoS6Us literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-29x29@2x-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e70de526a1c4254dd9b6bde1a832c7d87985d0 GIT binary patch literal 1712 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 LYkZ?d+adBl2VisS literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-512@2x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-512@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..59180a34a86ecac713342431af1a920634ef842f GIT binary patch literal 30737 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 n|5Ll~-TzGCa4w=gk@|M=uFi=$6}b-(ss)td?3 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@2x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..c312140595c29dc88f505097dfb8948e72569d44 GIT binary patch literal 3396 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 LYkZ?d+adBl2VisS literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@3x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2400fb4ea434f3bd8289e8683ed8f613d164a68d GIT binary patch literal 5006 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 Z*S~9CKRYCWR5btq002ovPDHLkV1kHr6CMBn literal 0 HcmV?d00001 diff --git a/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-76x76@2x.png b/legacy/Launcher/apps/launcher/src-tauri/icons/ios/AppIcon-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..aef57872e5f42fb9bd7837df4782afd43f3c0092 GIT binary patch literal 4282 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 -> Result { + let base_url = base_url.into().trim_end_matches('/').to_string(); + let http = reqwest::Client::builder() + .user_agent(concat!("Owyx/", env!("CARGO_PKG_VERSION"))) + .timeout(DEFAULT_TIMEOUT) + .connect_timeout(CONNECT_TIMEOUT) + .build() + .map_err(|e| format!("HTTP client error: {e}"))?; + Ok(Self { base_url, http }) + } + + pub fn from_config_url(url: Option<&str>) -> Result { + let base = match url.map(str::trim).filter(|s| !s.is_empty()) { + Some(u) => u.to_string(), + None => "mock://local".to_string(), + }; + Self::new(base) + } + + pub fn is_mock(&self) -> bool { + self.base_url.starts_with("mock://") + } + + pub async fn fetch_packs(&self) -> Result { + if self.is_mock() { + return serde_json::from_str(FIXTURE_PACKS) + .map_err(|e| format!("Invalid fixture packs.json: {e}")); + } + + let url = format!("{}/v1/packs", self.base_url); + let response = self + .http + .get(&url) + .send() + .await + .map_err(|e| format!("Failed to fetch packs: {e}"))? + .error_for_status() + .map_err(|e| format!("Packs API error: {e}"))?; + response + .json() + .await + .map_err(|e| format!("Invalid packs JSON: {e}")) + } + + pub async fn fetch_manifest(&self, manifest_url: &str) -> Result { + if self.is_mock() || manifest_url.starts_with("mock://") { + if manifest_url.contains("demo-friends") || self.is_mock() { + return serde_json::from_str(FIXTURE_DEMO_MANIFEST) + .map_err(|e| format!("Invalid fixture manifest: {e}")); + } + return Err(format!("No mock manifest for {manifest_url}")); + } + + let url = resolve_url(&self.base_url, manifest_url)?; + let response = self + .http + .get(url) + .send() + .await + .map_err(|e| format!("Failed to fetch manifest: {e}"))? + .error_for_status() + .map_err(|e| format!("Manifest API error: {e}"))?; + response + .json() + .await + .map_err(|e| format!("Invalid manifest JSON: {e}")) + } + + #[allow(dead_code)] + pub async fn download_bytes( + &self, + file_url: &str, + max_bytes: u64, + ) -> Result, String> { + self.download_bytes_with_progress(file_url, max_bytes, None) + .await + } + + pub async fn download_bytes_with_progress( + &self, + file_url: &str, + max_bytes: u64, + mut on_progress: Option<&mut (dyn FnMut(u64, Option) -> Result<(), String> + Send)>, + ) -> Result, String> { + let max_bytes = max_bytes.max(1).min(512 * 1024 * 1024); + if file_url.starts_with("mock://") || self.is_mock() { + if file_url.contains("demo-friends/mods/readme.txt") || file_url.ends_with("readme.txt") + { + let bytes = FIXTURE_DEMO_FILE.to_vec(); + if bytes.len() as u64 > max_bytes { + return Err("Mock file exceeds size limit".into()); + } + if let Some(cb) = on_progress.as_mut() { + cb(bytes.len() as u64, Some(bytes.len() as u64))?; + } + return Ok(bytes); + } + return Err(format!("No mock file for {file_url}")); + } + + let url = resolve_url(&self.base_url, file_url)?; + let response = self + .http + .get(url) + .send() + .await + .map_err(|e| format!("Failed to download file: {e}"))? + .error_for_status() + .map_err(|e| format!("Download HTTP error: {e}"))?; + + let content_len = response.content_length(); + if let Some(len) = content_len { + if len > max_bytes { + return Err(format!( + "Remote file too large: {len} bytes (limit {max_bytes})" + )); + } + } + + let mut data = Vec::new(); + let mut stream = response.bytes_stream(); + let mut last_reported = 0u64; + const MIN_DELTA: u64 = 256 * 1024; + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Download stream error: {e}"))?; + if (data.len() as u64).saturating_add(chunk.len() as u64) > max_bytes { + return Err(format!("Download exceeded size limit ({max_bytes} bytes)")); + } + data.extend_from_slice(&chunk); + if let Some(cb) = on_progress.as_mut() { + let received = data.len() as u64; + let min_delta = content_len + .map(|t| (t / 200).max(MIN_DELTA)) + .unwrap_or(MIN_DELTA); + let at_end = content_len.is_some_and(|t| received >= t); + if last_reported == 0 + || at_end + || received.saturating_sub(last_reported) >= min_delta + { + last_reported = received; + cb(received, content_len)?; + } + } + } + if let Some(cb) = on_progress.as_mut() { + let received = data.len() as u64; + if received != last_reported { + cb(received, content_len.or(Some(received)))?; + } + } + Ok(data) + } + + pub fn base_url(&self) -> &str { + &self.base_url + } +} + +fn resolve_url(base: &str, maybe_relative: &str) -> Result { + if maybe_relative.starts_with("http://") || maybe_relative.starts_with("https://") { + return Url::parse(maybe_relative).map_err(|e| format!("Bad URL: {e}")); + } + let base = Url::parse(&format!("{base}/")).map_err(|e| format!("Bad base URL: {e}"))?; + base.join(maybe_relative.trim_start_matches('/')) + .map_err(|e| format!("Bad relative URL: {e}")) +} + +#[allow(dead_code)] +pub fn default_max_download() -> u64 { + DEFAULT_MAX_DOWNLOAD +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/catalog.rs b/legacy/Launcher/apps/launcher/src-tauri/src/catalog.rs new file mode 100644 index 00000000000..e736ef1b50f --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/catalog.rs @@ -0,0 +1,1100 @@ +//! Site catalog: list servers/packs, download http_zip / manifest overlay, +//! write servers.dat for Play. Players never see SFTP credentials. + +use crate::config; +use crate::install; +use crate::instances; +use crate::owyx; +use flate2::write::GzEncoder; +use flate2::Compression; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use std::fs::{self, File}; +use std::io::{Cursor, Write}; +use std::net::IpAddr; +use std::path::{Component, Path, PathBuf}; +use std::time::Duration; +use tauri::{AppHandle, Emitter}; +use zip::ZipArchive; + +const USER_AGENT: &str = concat!("Owyx/", env!("CARGO_PKG_VERSION")); +const MAX_PACK_BYTES: u64 = 512 * 1024 * 1024; +const MAX_PACK_FILES: usize = 50_000; +const MAX_REDIRECTS: usize = 8; + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CatalogPack { + pub id: String, + pub name: String, + pub minecraft: String, + pub loader: String, + #[serde(default)] + pub icon_url: Option, + #[serde(default)] + pub description: String, + #[serde(default)] + pub source_type: String, + #[serde(default)] + pub download_url: Option, + #[serde(default)] + pub sha256: Option, + #[serde(default)] + pub manifest_url: Option, + #[serde(default)] + pub download_available: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CatalogServer { + pub id: String, + pub name: String, + #[serde(default)] + pub icon_url: Option, + pub address: String, + #[serde(default = "default_port")] + pub port: u16, + #[serde(default)] + pub kind: String, + #[serde(default)] + pub pack_id: Option, + #[serde(default)] + pub minecraft: Option, + #[serde(default)] + pub loader: Option, + #[serde(default)] + pub requires_account: bool, + #[serde(default)] + pub pack: Option, +} + +fn default_port() -> u16 { + 25565 +} + +#[derive(Debug, Clone, Serialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct CatalogLoadResult { + pub servers: Vec, + pub packs: Vec, + pub error: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CatalogInstallResult { + pub instance_id: String, + pub ready: bool, + pub message: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct CatalogMeta { + pub server_id: String, + pub pack_id: Option, + pub address: String, + pub port: u16, + #[serde(default)] + pub pack_sha256: Option, +} + +pub(crate) fn http_client(api_base: &str) -> Result { + let api_base = api_base.to_string(); + let redirect_policy = reqwest::redirect::Policy::custom(move |attempt| { + if attempt.previous().len() >= MAX_REDIRECTS { + return attempt.error("Too many redirects"); + } + let Some(initial) = attempt.previous().first() else { + return attempt.error("Redirect has no source URL"); + }; + if redirect_allowed(initial, attempt.url(), &api_base) { + attempt.follow() + } else { + attempt.error("Unsafe download redirect") + } + }); + reqwest::Client::builder() + .user_agent(USER_AGENT) + .default_headers({ + let mut headers = reqwest::header::HeaderMap::new(); + if let Some(key) = owyx::resolve_client_key() { + if let (Ok(name), Ok(val)) = ( + reqwest::header::HeaderName::from_bytes(owyx::CLIENT_KEY_HEADER.as_bytes()), + reqwest::header::HeaderValue::from_str(&key), + ) { + headers.insert(name, val); + } + } + headers + }) + .timeout(Duration::from_secs(60)) + .connect_timeout(Duration::from_secs(10)) + .redirect(redirect_policy) + .build() + .map_err(|e| format!("network: {e}")) +} + +fn is_loopback_or_private(host: &str) -> bool { + if host == "localhost" || host == "127.0.0.1" || host == "::1" || host == "[::1]" { + return true; + } + if let Ok(ip) = host.parse::() { + return match ip { + IpAddr::V4(v) => v.is_loopback() || v.is_private() || v.is_link_local(), + IpAddr::V6(v) => v.is_loopback() || v.is_unique_local(), + }; + } + false +} + +fn is_owyx_host(host: &str) -> bool { + host == "owyx.site" + || host == "api.owyx.site" + || host == "mc.owyx.site" + || host.ends_with(".owyx.site") +} + +fn redirect_allowed(initial: &reqwest::Url, next: &reqwest::Url, api_base: &str) -> bool { + if next.username() != "" || next.password().is_some() { + return false; + } + if !matches!(next.scheme(), "http" | "https") { + return false; + } + // Never let a trusted HTTPS URL silently downgrade to clear-text HTTP. + if initial.scheme() == "https" && next.scheme() != "https" { + return false; + } + let Some(initial_host) = initial.host_str().map(str::to_ascii_lowercase) else { + return false; + }; + let Some(next_host) = next.host_str().map(str::to_ascii_lowercase) else { + return false; + }; + let api_host = reqwest::Url::parse(api_base) + .ok() + .and_then(|url| url.host_str().map(str::to_ascii_lowercase)); + let initial_is_private = + is_loopback_or_private(&initial_host) || api_host.as_deref() == Some(initial_host.as_str()); + let next_is_private = is_loopback_or_private(&next_host); + + // A public warehouse must not redirect into localhost, LAN, or link-local + // services. Direct private/API URLs remain available for local development. + !next_is_private || initial_is_private || api_host.as_deref() == Some(next_host.as_str()) +} + +/// Players: HTTPS on the public internet; HTTP only for loopback/private + API host. +/// No credentials in the URL. Decision recorded in PLAN.md. +pub fn assert_pack_download_url(raw: &str, api_base: &str) -> Result<(), String> { + let parsed = reqwest::Url::parse(raw).map_err(|e| format!("Bad pack URL: {e}"))?; + if parsed.username() != "" || parsed.password().is_some() { + return Err("Download URL must not include credentials".into()); + } + let host = parsed + .host_str() + .ok_or_else(|| "Missing host".to_string())? + .to_ascii_lowercase(); + let api_host = reqwest::Url::parse(api_base) + .ok() + .and_then(|u| u.host_str().map(|s| s.to_ascii_lowercase())); + let same_api = api_host.as_deref() == Some(host.as_str()); + match parsed.scheme() { + "https" => { + if is_loopback_or_private(&host) || is_owyx_host(&host) || same_api { + return Ok(()); + } + // Public warehouse HTTPS is allowed (mini-PC behind FRPC / object storage). + Ok(()) + } + "http" => { + if is_loopback_or_private(&host) || same_api || is_owyx_host(&host) { + return Ok(()); + } + Err(format!( + "HTTP pack downloads only from local/private or API host, not {host}" + )) + } + other => Err(format!("Unsupported pack URL scheme: {other}")), + } +} + +pub async fn list_catalog(base_url: Option) -> Result { + let base = owyx::resolve_base(base_url.as_deref()); + let client = http_client(&base)?; + let servers_res = client + .get(format!("{base}/api/launcher/v1/servers")) + .send() + .await + .map_err(|_| "network".to_string())?; + let packs_res = client + .get(format!("{base}/api/launcher/v1/packs")) + .send() + .await + .map_err(|_| "network".to_string())?; + + if !servers_res.status().is_success() { + return Ok(CatalogLoadResult { + servers: Vec::new(), + packs: Vec::new(), + error: Some("server".into()), + }); + } + let s_body: serde_json::Value = servers_res.json().await.map_err(|_| "server".to_string())?; + let p_body: serde_json::Value = if packs_res.status().is_success() { + packs_res.json().await.unwrap_or(serde_json::json!({})) + } else { + crate::log::warn(&format!( + "Catalog packs request returned HTTP {}", + packs_res.status() + )); + serde_json::json!({}) + }; + let servers: Vec = serde_json::from_value( + s_body + .get("servers") + .cloned() + .unwrap_or(serde_json::json!([])), + ) + .unwrap_or_default(); + let packs: Vec = serde_json::from_value( + p_body + .get("packs") + .cloned() + .unwrap_or(serde_json::json!([])), + ) + .unwrap_or_default(); + Ok(CatalogLoadResult { + servers, + packs, + error: None, + }) +} + +#[allow(clippy::too_many_arguments)] +pub async fn install_catalog_server( + app: AppHandle, + server_id: String, + name: String, + address: String, + port: u16, + pack_id: Option, + minecraft: String, + loader: String, + download_url: Option, + sha256: Option, + manifest_url: Option, + source_type: String, +) -> Result { + let loader_version = if loader.eq_ignore_ascii_case("vanilla") { + String::new() + } else { + crate::versions::list_loader_versions(&loader, &minecraft) + .await + .ok() + .and_then(|v| v.into_iter().next()) + .unwrap_or_default() + }; + let instance_id = existing_or_prepare(&name, &loader, &minecraft, &loader_version, &server_id)?; + write_catalog_meta( + &instance_id, + CatalogMeta { + server_id: server_id.clone(), + pack_id: pack_id.clone(), + address: address.clone(), + port, + pack_sha256: sha256.clone(), + }, + )?; + + emit( + &app, + &instance_id, + "install", + 0, + 3, + "Installing Minecraft…".into(), + )?; + + install::install_instance( + app.clone(), + instance_id.clone(), + name.clone(), + loader.clone(), + minecraft.clone(), + loader_version, + ) + .await?; + + emit( + &app, + &instance_id, + "overlay", + 1, + 3, + "Downloading pack…".into(), + )?; + + let base = owyx::resolve_base(None); + let overlay = download_overlay( + &app, + &instance_id, + &base, + &source_type, + download_url.as_deref(), + sha256.as_deref(), + manifest_url.as_deref(), + ) + .await; + if let Err(err) = overlay { + crate::log::error(&format!( + "Catalog overlay failed for instance {instance_id}: {err}" + )); + return Err(match mark_error(&instance_id) { + Ok(()) => err, + Err(cleanup) => format!("{err}; failed to mark instance as broken: {cleanup}"), + }); + } + + let game_dir = config::ensure_layout()? + .join("instances") + .join(&instance_id) + .join("game"); + if let Err(err) = write_servers_dat(&game_dir, &name, &address, port) { + return Err(match mark_error(&instance_id) { + Ok(()) => err, + Err(cleanup) => format!("{err}; failed to mark instance as broken: {cleanup}"), + }); + } + emit(&app, &instance_id, "done", 3, 3, "Pack ready".into())?; + + Ok(CatalogInstallResult { + instance_id, + ready: true, + message: "ready".into(), + }) +} + +fn existing_or_prepare( + name: &str, + loader: &str, + minecraft: &str, + loader_version: &str, + server_id: &str, +) -> Result { + let preferred = format!("srv-{server_id}"); + if let Ok(root) = instance_root_if_exists(&preferred) { + if root.join("instance.json").is_file() { + return Ok(preferred); + } + } + // Reuse any instance that already points at this server. + if let Some(id) = find_instance_for_server(server_id)? { + return Ok(id); + } + let disk = instances::prepare_instance(name, loader, minecraft, loader_version, None)?; + // Rename folder to srv-{id} when possible so Play can find it next time. + if disk.id != preferred { + if let Ok(from) = instance_root_if_exists(&disk.id) { + let to = config::ensure_layout()?.join("instances").join(&preferred); + if !to.exists() { + if fs::rename(&from, &to).is_ok() { + if let Ok(raw) = fs::read_to_string(to.join("instance.json")) { + if let Ok(mut rec) = serde_json::from_str::(&raw) { + rec["id"] = serde_json::Value::String(preferred.clone()); + let _ = fs::write( + to.join("instance.json"), + serde_json::to_string_pretty(&rec).unwrap_or(raw), + ); + } + } + return Ok(preferred); + } + } + } + return Ok(disk.id); + } + Ok(disk.id) +} + +fn instance_root_if_exists(id: &str) -> Result { + instances::validate_instance_id(id)?; + Ok(config::ensure_layout()?.join("instances").join(id)) +} + +fn find_instance_for_server(server_id: &str) -> Result, String> { + let root = config::ensure_layout()?.join("instances"); + let Ok(entries) = fs::read_dir(&root) else { + return Ok(None); + }; + for entry in entries.flatten() { + let meta = entry.path().join("catalog.json"); + if !meta.is_file() { + continue; + } + let Ok(raw) = fs::read_to_string(&meta) else { + continue; + }; + let Ok(parsed) = serde_json::from_str::(&raw) else { + continue; + }; + if parsed.server_id == server_id { + if let Some(name) = entry.file_name().to_str() { + return Ok(Some(name.to_string())); + } + } + } + Ok(None) +} + +fn write_catalog_meta(instance_id: &str, meta: CatalogMeta) -> Result<(), String> { + let root = instance_root_if_exists(instance_id)?; + fs::create_dir_all(&root).map_err(|e| format!("Create instance: {e}"))?; + let raw = serde_json::to_string_pretty(&meta).map_err(|e| format!("Serialize catalog: {e}"))?; + crate::config::atomic_write_path(&root.join("catalog.json"), raw.as_bytes()) +} + +pub fn read_catalog_meta(instance_id: &str) -> Option { + let root = instance_root_if_exists(instance_id).ok()?; + let raw = fs::read_to_string(root.join("catalog.json")).ok()?; + serde_json::from_str(&raw).ok() +} + +fn mark_error(instance_id: &str) -> Result<(), String> { + let root = instance_root_if_exists(instance_id)?; + mark_error_at(&root) +} + +fn mark_error_at(root: &Path) -> Result<(), String> { + let meta_path = root.join("meta.json"); + if meta_path.exists() { + fs::remove_file(&meta_path).map_err(|e| format!("Remove stale meta.json: {e}"))?; + } + let instance_path = root.join("instance.json"); + let raw = fs::read_to_string(&instance_path).map_err(|e| format!("Read instance.json: {e}"))?; + let mut rec: serde_json::Value = + serde_json::from_str(&raw).map_err(|e| format!("Parse instance.json: {e}"))?; + rec["status"] = serde_json::Value::String("error".into()); + let updated = + serde_json::to_vec_pretty(&rec).map_err(|e| format!("Serialize instance.json: {e}"))?; + config::atomic_write_path(&instance_path, &updated) +} + +async fn download_overlay( + app: &AppHandle, + instance_id: &str, + api_base: &str, + source_type: &str, + download_url: Option<&str>, + sha256: Option<&str>, + manifest_url: Option<&str>, +) -> Result<(), String> { + let instance_dir = config::ensure_layout()?.join("instances").join(instance_id); + let game_dir = instance_dir.join("game"); + fs::create_dir_all(&game_dir).map_err(|e| format!("Create game dir: {e}"))?; + let staging_dir = instance_dir.join(".catalog-overlay"); + if staging_dir.exists() { + fs::remove_dir_all(&staging_dir).map_err(|e| format!("Clean overlay staging: {e}"))?; + } + fs::create_dir_all(&staging_dir).map_err(|e| format!("Create overlay staging: {e}"))?; + + let result = async { + if source_type == "sftp" { + return Err("SFTP is admin-only. Publish an HTTP zip first.".into()); + } + if source_type == "mrpack" { + let url = download_url + .filter(|s| !s.is_empty()) + .ok_or_else(|| "mrpack download URL is missing".to_string())?; + assert_pack_download_url(url, api_base)?; + emit( + app, + instance_id, + "download", + 1, + 3, + format!("Downloading mrpack {url}"), + )?; + let bytes = download_capped(url, api_base).await?; + if let Some(expected) = sha256.filter(|s| !s.is_empty()) { + let actual = hex_sha256(&bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!( + "SHA256 mismatch: expected {expected}, got {actual}" + )); + } + } + // Write bytes to a temp file path-free install via mrpack module. + crate::mrpack::install_mrpack_bytes_into_instance(instance_id, &bytes).await?; + return Ok(()); + } + if source_type == "http_manifest" { + let url = manifest_url + .filter(|s| !s.is_empty()) + .ok_or_else(|| "Manifest URL is missing".to_string())?; + download_manifest_files(app, instance_id, api_base, url, &staging_dir).await?; + return apply_staged_overlay(&staging_dir, &game_dir); + } + let Some(url) = download_url.filter(|s| !s.is_empty()) else { + // No overlay is OK (vanilla + servers.dat only). + return Ok(()); + }; + assert_pack_download_url(url, api_base)?; + emit( + app, + instance_id, + "download", + 1, + 3, + format!("Downloading {url}"), + )?; + let bytes = download_capped(url, api_base).await?; + if let Some(expected) = sha256.filter(|s| !s.is_empty()) { + let actual = hex_sha256(&bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!( + "SHA256 mismatch: expected {expected}, got {actual}" + )); + } + } + extract_zip_overlay(&bytes, &staging_dir)?; + apply_staged_overlay(&staging_dir, &game_dir) + }; + let outcome = result.await; + let cleanup = fs::remove_dir_all(&staging_dir); + match (outcome, cleanup) { + (Err(err), _) => Err(err), + (Ok(()), Err(err)) => Err(format!("Clean overlay staging: {err}")), + (Ok(()), Ok(())) => Ok(()), + } +} + +#[derive(Debug, Deserialize)] +struct ManifestFile { + path: Option, + url: Option, + sha256: Option, + size: Option, +} + +#[derive(Debug, Deserialize)] +struct PackManifestBody { + #[serde(default)] + files: Vec, +} + +async fn download_manifest_files( + app: &AppHandle, + instance_id: &str, + api_base: &str, + manifest_url: &str, + game_dir: &Path, +) -> Result<(), String> { + assert_pack_download_url(manifest_url, api_base)?; + let client = http_client(api_base)?; + let res = client + .get(manifest_url) + .send() + .await + .map_err(|e| format!("Manifest: {e}"))? + .error_for_status() + .map_err(|e| format!("Manifest HTTP: {e}"))?; + assert_pack_download_url(res.url().as_str(), api_base)?; + let body: PackManifestBody = res + .json() + .await + .map_err(|e| format!("Manifest JSON: {e}"))?; + let total = body.files.len() as u32; + for (i, file) in body.files.iter().enumerate() { + let url = file + .url + .as_deref() + .filter(|s| !s.is_empty()) + .ok_or_else(|| format!("Manifest file {} has no URL", i + 1))?; + let rel = file + .path + .as_deref() + .filter(|s| !s.is_empty()) + .ok_or_else(|| format!("Manifest file {} has no path", i + 1))?; + emit( + app, + instance_id, + "download", + i as u32, + total.max(1), + format!("Downloading {rel}"), + )?; + let bytes = download_capped(url, api_base).await?; + if let Some(expected_size) = file.size { + if bytes.len() as u64 != expected_size { + return Err(format!( + "Size mismatch for {rel}: expected {expected_size}, got {}", + bytes.len() + )); + } + } + if let Some(expected) = file.sha256.as_deref().filter(|s| !s.is_empty()) { + let actual = hex_sha256(&bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!("SHA256 mismatch for {rel}")); + } + } + if url.ends_with(".zip") || rel.ends_with(".zip") { + extract_zip_overlay(&bytes, game_dir)?; + } else { + let dest = game_dir.join(safe_rel(rel)?); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + } + crate::config::atomic_write_path(&dest, &bytes)?; + } + } + Ok(()) +} + +async fn download_capped(url: &str, api_base: &str) -> Result, String> { + use futures_util::StreamExt; + assert_pack_download_url(url, api_base)?; + let client = http_client(api_base)?; + let res = client + .get(url) + .send() + .await + .map_err(|e| format!("Download: {e}"))? + .error_for_status() + .map_err(|e| format!("Download HTTP: {e}"))?; + assert_pack_download_url(res.url().as_str(), api_base)?; + if let Some(len) = res.content_length() { + if len > MAX_PACK_BYTES { + return Err(format!("File too large ({len} bytes)")); + } + } + let mut out = Vec::new(); + let mut stream = res.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Download stream: {e}"))?; + if out.len() as u64 + chunk.len() as u64 > MAX_PACK_BYTES { + return Err(format!("File exceeded {MAX_PACK_BYTES} bytes")); + } + out.extend_from_slice(&chunk); + } + Ok(out) +} + +fn extract_zip_overlay(bytes: &[u8], game_dir: &Path) -> Result<(), String> { + let cursor = Cursor::new(bytes); + let mut archive = ZipArchive::new(cursor).map_err(|e| format!("Zip: {e}"))?; + if archive.len() > MAX_PACK_FILES { + return Err(format!("Zip has too many entries ({})", archive.len())); + } + let mut unpacked_bytes = 0u64; + for i in 0..archive.len() { + let mut entry = archive.by_index(i).map_err(|e| format!("Zip entry: {e}"))?; + if entry.is_dir() { + continue; + } + if entry + .unix_mode() + .is_some_and(|mode| mode & 0o170000 == 0o120000) + { + return Err(format!( + "Zip symlink entries are not allowed: {}", + entry.name() + )); + } + unpacked_bytes = unpacked_bytes + .checked_add(entry.size()) + .ok_or_else(|| "Zip unpacked size overflow".to_string())?; + if unpacked_bytes > MAX_PACK_BYTES { + return Err(format!( + "Zip expands past the {MAX_PACK_BYTES} byte safety limit" + )); + } + let name = entry.name().to_string(); + if is_meta_inf_path(&name) { + continue; + } + let rel = safe_rel(&name)?; + let dest = game_dir.join(rel); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create overlay dir: {e}"))?; + } + let mut out = File::create(&dest).map_err(|e| format!("Write overlay: {e}"))?; + std::io::copy(&mut entry, &mut out).map_err(|e| format!("Extract: {e}"))?; + } + Ok(()) +} + +fn is_meta_inf_path(raw: &str) -> bool { + raw.replace('\\', "/") + .split('/') + .next() + .is_some_and(|part| part.eq_ignore_ascii_case("META-INF")) +} + +fn apply_staged_overlay(staging_dir: &Path, game_dir: &Path) -> Result<(), String> { + fs::create_dir_all(game_dir).map_err(|e| format!("Create game dir: {e}"))?; + if fs::symlink_metadata(game_dir) + .map(|meta| meta.file_type().is_symlink()) + .unwrap_or(false) + { + return Err("Game directory must not be a symlink".into()); + } + + let mut pending = vec![staging_dir.to_path_buf()]; + while let Some(dir) = pending.pop() { + for entry in fs::read_dir(&dir).map_err(|e| format!("Read overlay staging: {e}"))? { + let entry = entry.map_err(|e| format!("Read overlay entry: {e}"))?; + let file_type = entry + .file_type() + .map_err(|e| format!("Read overlay file type: {e}"))?; + if file_type.is_symlink() { + return Err(format!( + "Overlay symlinks are not allowed: {}", + entry.path().display() + )); + } + let rel = entry + .path() + .strip_prefix(staging_dir) + .map_err(|_| "Overlay path escaped staging".to_string())? + .to_path_buf(); + let dest = safe_overlay_destination(game_dir, &rel, file_type.is_dir())?; + if file_type.is_dir() { + fs::create_dir_all(&dest).map_err(|e| format!("Create overlay dir: {e}"))?; + pending.push(entry.path()); + continue; + } + if !file_type.is_file() { + return Err(format!( + "Unsupported overlay entry: {}", + entry.path().display() + )); + } + replace_from_staging(&entry.path(), &dest)?; + } + } + Ok(()) +} + +fn safe_overlay_destination(game_dir: &Path, rel: &Path, expect_dir: bool) -> Result { + let rel = safe_rel(&rel.to_string_lossy())?; + let mut current = game_dir.to_path_buf(); + if let Some(parent) = rel.parent() { + for component in parent.components() { + let Component::Normal(part) = component else { + return Err("Unsafe overlay path".into()); + }; + current.push(part); + match fs::symlink_metadata(¤t) { + Ok(meta) if meta.file_type().is_symlink() => { + return Err(format!( + "Overlay destination contains a symlink: {}", + current.display() + )); + } + Ok(meta) if !meta.is_dir() => { + return Err(format!( + "Overlay destination parent is not a directory: {}", + current.display() + )); + } + Ok(_) => {} + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + fs::create_dir(¤t) + .map_err(|e| format!("Create overlay destination: {e}"))?; + } + Err(err) => return Err(format!("Inspect overlay destination: {err}")), + } + } + } + let dest = game_dir.join(rel); + if let Ok(meta) = fs::symlink_metadata(&dest) { + if meta.file_type().is_symlink() { + return Err(format!("Unsafe overlay destination: {}", dest.display())); + } + if meta.is_dir() { + // Vanilla/loader install already creates mods/, config/, etc. + // A directory zip entry may merge into those folders. + if expect_dir { + return Ok(dest); + } + return Err(format!("Unsafe overlay destination: {}", dest.display())); + } + if expect_dir { + return Err(format!( + "Overlay directory target is a file: {}", + dest.display() + )); + } + } + Ok(dest) +} + +fn replace_from_staging(source: &Path, dest: &Path) -> Result<(), String> { + let parent = dest + .parent() + .ok_or_else(|| "Overlay destination has no parent".to_string())?; + let file_name = dest + .file_name() + .and_then(|name| name.to_str()) + .unwrap_or("overlay"); + let temp = parent.join(format!(".{file_name}.{}.owyx-tmp", std::process::id())); + if temp.exists() { + fs::remove_file(&temp).map_err(|e| format!("Clean overlay temp file: {e}"))?; + } + fs::copy(source, &temp).map_err(|e| format!("Copy overlay file: {e}"))?; + File::open(&temp) + .and_then(|file| file.sync_all()) + .map_err(|e| format!("Sync overlay file: {e}"))?; + if let Err(first) = fs::rename(&temp, dest) { + if dest.exists() { + fs::remove_file(dest).map_err(|e| format!("Replace overlay file: {e}"))?; + fs::rename(&temp, dest).map_err(|e| format!("Replace overlay file: {e}"))?; + } else { + let _ = fs::remove_file(&temp); + return Err(format!("Move overlay file: {first}")); + } + } + Ok(()) +} + +fn safe_rel(raw: &str) -> Result { + let cleaned = raw.replace('\\', "/"); + let mut out = PathBuf::new(); + for component in Path::new(&cleaned).components() { + match component { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe zip path: {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err("Empty zip path".into()); + } + Ok(out) +} + +fn hex_sha256(bytes: &[u8]) -> String { + Sha256::digest(bytes) + .iter() + .map(|b| format!("{b:02x}")) + .collect() +} + +fn emit( + app: &AppHandle, + id: &str, + phase: &str, + done: u32, + total: u32, + message: String, +) -> Result<(), String> { + app.emit( + "install://progress", + crate::models::SyncProgress { + pack_id: id.to_string(), + phase: phase.into(), + current_file: None, + done_files: done, + total_files: total, + message, + file_bytes_done: None, + file_bytes_total: None, + }, + ) + .map_err(|e| format!("Emit progress: {e}")) +} + +pub fn sanitize_server_addr(raw: &str) -> Result { + let s = raw.trim(); + if s.is_empty() || s.len() > 255 { + return Err("Invalid server address".into()); + } + if s.starts_with('-') || s.contains(char::is_whitespace) { + return Err("Invalid server address".into()); + } + if !s + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '-' | '_' | ':')) + { + return Err("Invalid server address".into()); + } + Ok(s.to_string()) +} + +pub fn write_servers_dat( + game_dir: &Path, + name: &str, + address: &str, + port: u16, +) -> Result<(), String> { + let address = sanitize_server_addr(address)?; + let ip = if port == 25565 { + address + } else { + format!("{address}:{port}") + }; + let nbt = encode_servers_nbt(name, &ip); + fs::create_dir_all(game_dir).map_err(|e| format!("Create game dir: {e}"))?; + let path = game_dir.join("servers.dat"); + let file = File::create(&path).map_err(|e| format!("Create servers.dat: {e}"))?; + let mut enc = GzEncoder::new(file, Compression::default()); + enc.write_all(&nbt) + .map_err(|e| format!("Write servers.dat: {e}"))?; + enc.finish().map_err(|e| format!("Gzip servers.dat: {e}"))?; + Ok(()) +} + +fn encode_servers_nbt(name: &str, ip: &str) -> Vec { + let mut out = Vec::new(); + out.push(10); // compound + put_str(&mut out, ""); + // list "servers" + out.push(9); + put_str(&mut out, "servers"); + out.push(10); // element type = compound + out.extend_from_slice(&1i32.to_be_bytes()); + put_named_string(&mut out, "name", name); + put_named_string(&mut out, "ip", ip); + out.push(1); + put_str(&mut out, "hidden"); + out.push(0); + out.push(0); // end server compound + out.push(0); // end root + out +} + +fn put_str(out: &mut Vec, s: &str) { + let bytes = s.as_bytes(); + out.extend_from_slice(&(bytes.len() as u16).to_be_bytes()); + out.extend_from_slice(bytes); +} + +fn put_named_string(out: &mut Vec, name: &str, value: &str) { + out.push(8); + put_str(out, name); + put_str(out, value); +} + +pub fn supports_quick_play(minecraft: &str) -> bool { + let mut parts = minecraft.split('.'); + let major = parts + .next() + .and_then(|s| s.parse::().ok()) + .unwrap_or(0); + let minor = parts + .next() + .and_then(|s| { + s.chars() + .take_while(|c| c.is_ascii_digit()) + .collect::() + .parse::() + .ok() + }) + .unwrap_or(0); + let patch = parts + .next() + .and_then(|s| { + s.chars() + .take_while(|c| c.is_ascii_digit()) + .collect::() + .parse::() + .ok() + }) + .unwrap_or(0); + major > 1 || (major == 1 && (minor > 20 || (minor == 20 && patch >= 2))) +} + +/// Skin / cosmetics download allowlist (same hosts as pack overlay). +pub fn assert_asset_url(raw: &str, api_base: &str) -> Result<(), String> { + assert_pack_download_url(raw, api_base) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn blocks_public_redirects_into_private_networks() { + let public = reqwest::Url::parse("https://packs.example/pack.zip").unwrap(); + let private = reqwest::Url::parse("https://169.254.169.254/latest/meta-data").unwrap(); + assert!(!redirect_allowed( + &public, + &private, + "http://127.0.0.1:3001" + )); + + let local = reqwest::Url::parse("http://127.0.0.1:3001/pack.zip").unwrap(); + let local_next = reqwest::Url::parse("http://127.0.0.1:3001/files/pack.zip").unwrap(); + assert!(redirect_allowed( + &local, + &local_next, + "http://127.0.0.1:3001" + )); + } + + #[test] + fn blocks_https_downgrades_and_credentials() { + let initial = reqwest::Url::parse("https://packs.example/pack.zip").unwrap(); + let downgrade = reqwest::Url::parse("http://packs.example/pack.zip").unwrap(); + let credentials = reqwest::Url::parse("https://user:pass@packs.example/pack.zip").unwrap(); + assert!(!redirect_allowed( + &initial, + &downgrade, + "https://api.owyx.site" + )); + assert!(!redirect_allowed( + &initial, + &credentials, + "https://api.owyx.site" + )); + } + + #[test] + fn validates_overlay_paths_and_meta_inf() { + assert_eq!( + safe_rel(r"mods\example.jar").unwrap(), + PathBuf::from("mods/example.jar") + ); + assert!(safe_rel("../outside.txt").is_err()); + assert!(safe_rel("/absolute.txt").is_err()); + assert!(is_meta_inf_path("META-INF/MANIFEST.MF")); + assert!(is_meta_inf_path("meta-inf/signature")); + assert!(!is_meta_inf_path("mods/not-META-INF.jar")); + } + + #[test] + fn quick_play_starts_at_minecraft_1_20_2() { + assert!(!supports_quick_play("1.19.4")); + assert!(!supports_quick_play("1.20")); + assert!(!supports_quick_play("1.20.1")); + assert!(supports_quick_play("1.20.2")); + assert!(supports_quick_play("1.21.1")); + } + + #[test] + fn failed_overlay_removes_ready_marker() { + let unique = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(); + let root = std::env::temp_dir().join(format!("owyx-catalog-test-{unique}")); + fs::create_dir_all(&root).unwrap(); + fs::write(root.join("meta.json"), b"{}").unwrap(); + fs::write( + root.join("instance.json"), + br#"{"id":"test","status":"ready"}"#, + ) + .unwrap(); + + mark_error_at(&root).unwrap(); + + assert!(!root.join("meta.json").exists()); + let instance: serde_json::Value = + serde_json::from_slice(&fs::read(root.join("instance.json")).unwrap()).unwrap(); + assert_eq!(instance["status"], "error"); + fs::remove_dir_all(root).unwrap(); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/config.rs b/legacy/Launcher/apps/launcher/src-tauri/src/config.rs new file mode 100644 index 00000000000..9c6e59b07dc --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/config.rs @@ -0,0 +1,349 @@ +use crate::java::JavaInstallation; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::sync::{LazyLock, Mutex}; +use std::time::{SystemTime, UNIX_EPOCH}; + +static CONFIG_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct UpdaterConfig { + #[serde(default = "default_channel")] + pub channel: String, + #[serde(default)] + pub last_check_at: Option, +} + +fn default_channel() -> String { + "stable".into() +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LauncherConfig { + pub nick: String, + #[serde(default)] + pub update_base_url: Option, + #[serde(default)] + pub java_installations: Vec, + /// Preferred java path per major version (8 / 17 / 21 / 25), Modrinth-style. + #[serde(default)] + pub java_versions: HashMap, + #[serde(default = "default_locale")] + pub locale: String, + #[serde(default)] + pub active_profile_id: Option, + #[serde(default)] + pub updater: UpdaterConfig, + #[serde(default = "default_memory_mb")] + pub default_memory_mb: u32, +} + +fn default_locale() -> String { + "ru".into() +} + +fn default_memory_mb() -> u32 { + 4096 +} + +impl Default for LauncherConfig { + fn default() -> Self { + Self { + nick: String::new(), + update_base_url: None, + java_installations: Vec::new(), + java_versions: HashMap::new(), + locale: default_locale(), + active_profile_id: None, + updater: UpdaterConfig::default(), + default_memory_mb: default_memory_mb(), + } + } +} + +pub fn app_data_dir() -> Result { + // Player data lives in %USERPROFILE%\owyx (not AppData, not *Launcher*). + let home = dirs::home_dir().ok_or_else(|| "Could not resolve user home directory".to_string())?; + Ok(home.join("owyx")) +} + +pub fn ensure_layout() -> Result { + let root = app_data_dir()?; + for sub in [ + "instances", + "cache", + "logs", + "skins", + "meta", + "meta/libraries", + "meta/assets", + "meta/assets/indexes", + "meta/assets/objects", + "meta/natives", + "meta/versions", + "meta/log_configs", + "meta/java_versions", + ] { + fs::create_dir_all(root.join(sub)) + .map_err(|e| format!("Failed to create {sub}/: {e}"))?; + } + Ok(root) +} + +/// Shared Minecraft artifacts (Modrinth Theseus-style `meta/`). +pub fn meta_dir() -> Result { + Ok(ensure_layout()?.join("meta")) +} + +pub fn meta_libraries_dir() -> Result { + Ok(meta_dir()?.join("libraries")) +} + +pub fn meta_assets_dir() -> Result { + Ok(meta_dir()?.join("assets")) +} + +pub fn meta_natives_dir(version: &str) -> Result { + let version = sanitize_meta_segment(version, "natives version")?; + let dir = meta_dir()?.join("natives").join(version); + fs::create_dir_all(&dir).map_err(|e| format!("Create natives dir: {e}"))?; + Ok(dir) +} + +fn sanitize_meta_segment(value: &str, label: &str) -> Result { + let value = value.trim(); + if value.is_empty() || value.len() > 64 || value == "." || value == ".." { + return Err(format!("Invalid {label}")); + } + if !value + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-')) + { + return Err(format!("Invalid {label} characters")); + } + Ok(value.to_string()) +} + +pub fn meta_versions_dir() -> Result { + Ok(meta_dir()?.join("versions")) +} + +/// Resolve a manifest-relative path: libraries/assets/versions live in shared meta, rest under game/. +/// Matches Modrinth Theseus: `meta/libraries`, `meta/assets`, `meta/versions/{id}/`. +pub fn resolve_game_or_meta(rel: &str, game_dir: &Path) -> Result { + let safe = safe_rel_component(rel)?; + let trimmed = safe.to_string_lossy().replace('\\', "/"); + if trimmed.starts_with("libraries/") + || trimmed.starts_with("assets/") + || trimmed.starts_with("versions/") + { + Ok(meta_dir()?.join(&safe)) + } else { + Ok(game_dir.join(&safe)) + } +} + +/// Theseus-style shared version folder: `meta/versions/{id}/`. +pub fn meta_version_dir(version_id: &str) -> Result { + let id = sanitize_meta_segment(version_id, "minecraft version")?; + let dir = meta_versions_dir()?.join(id); + fs::create_dir_all(&dir).map_err(|e| format!("Create version dir: {e}"))?; + Ok(dir) +} + +fn safe_rel_component(raw: &str) -> Result { + use std::path::{Component, Path}; + let path = Path::new(raw.trim_start_matches(['/', '\\'])); + if path.is_absolute() { + return Err(format!("Absolute paths are not allowed: {raw}")); + } + let mut out = PathBuf::new(); + for comp in path.components() { + match comp { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe path component in {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err("Empty relative path".into()); + } + Ok(out) +} + +fn with_config_lock(f: impl FnOnce() -> Result) -> Result { + let _guard = CONFIG_LOCK + .lock() + .map_err(|_| "Config lock poisoned".to_string())?; + f() +} + +pub fn load() -> Result { + with_config_lock(load_unlocked) +} + +fn load_unlocked() -> Result { + let root = ensure_layout()?; + let path = root.join("config.json"); + if !path.exists() { + let cfg = LauncherConfig::default(); + save_unlocked(&cfg)?; + return Ok(cfg); + } + + let raw = fs::read_to_string(&path).map_err(|e| format!("Failed to read config: {e}"))?; + match serde_json::from_str::(&raw) { + Ok(cfg) => Ok(cfg), + Err(err) => { + // Corrupt/partial file: quarantine and recover so the UI can keep working. + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let backup = root.join(format!("config.corrupt.{stamp}.json")); + let _ = fs::rename(&path, &backup); + let cfg = LauncherConfig::default(); + save_unlocked(&cfg)?; + eprintln!("config.json invalid ({err}); backed up to {}", backup.display()); + Ok(cfg) + } + } +} + +#[allow(dead_code)] // used by upcoming sync/settings commands +pub fn save(config: &LauncherConfig) -> Result<(), String> { + with_config_lock(|| save_unlocked(config)) +} + +fn save_unlocked(config: &LauncherConfig) -> Result<(), String> { + let root = ensure_layout()?; + let path = root.join("config.json"); + let raw = serde_json::to_string_pretty(config) + .map_err(|e| format!("Failed to serialize config: {e}"))?; + atomic_write(&path, raw.as_bytes()) +} + +fn atomic_write(path: &Path, bytes: &[u8]) -> Result<(), String> { + atomic_write_path(path, bytes) +} + +pub fn atomic_write_path(path: &Path, bytes: &[u8]) -> Result<(), String> { + let parent = path + .parent() + .ok_or_else(|| "Config path has no parent directory".to_string())?; + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_nanos()) + .unwrap_or(0); + let tmp = parent.join(format!( + ".{}.{}.{}.tmp", + path.file_name() + .and_then(|s| s.to_str()) + .unwrap_or("config.json"), + std::process::id(), + stamp + )); + + { + let mut file = + fs::File::create(&tmp).map_err(|e| format!("Failed to create temp config: {e}"))?; + file.write_all(bytes) + .map_err(|e| format!("Failed to write temp config: {e}"))?; + file.sync_all() + .map_err(|e| format!("Failed to sync temp config: {e}"))?; + } + + fs::rename(&tmp, path).map_err(|e| { + let _ = fs::remove_file(&tmp); + format!("Failed to replace config.json: {e}") + }) +} + +pub fn set_nick(nick: String) -> Result { + let nick = nick.trim().to_string(); + if nick.chars().count() > 16 { + return Err("Nick must be at most 16 characters".into()); + } + if !nick.is_empty() + && !nick + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_') + { + return Err("Nick may only contain letters, numbers, and _".into()); + } + + with_config_lock(|| { + let mut config = load_unlocked()?; + config.nick = nick; + save_unlocked(&config)?; + Ok(config) + }) +} + +pub fn set_java_installations(java: Vec) -> Result { + with_config_lock(|| { + let mut config = load_unlocked()?; + config.java_installations = java; + save_unlocked(&config)?; + Ok(config) + }) +} + +pub fn set_java_version_path(major: u32, path: Option) -> Result { + with_config_lock(|| { + let mut config = load_unlocked()?; + let key = major.to_string(); + match path { + Some(p) if !p.trim().is_empty() => { + config.java_versions.insert(key, p.trim().to_string()); + } + _ => { + config.java_versions.remove(&key); + } + } + save_unlocked(&config)?; + Ok(config) + }) +} + +pub fn java_versions_dir() -> Result { + Ok(meta_dir()?.join("java_versions")) +} + +pub fn prefetch_marker_path() -> Result { + Ok(meta_dir()?.join(".prefetch_ready.json")) +} + +pub fn set_locale(locale: String) -> Result { + let locale = if locale == "en" { "en" } else { "ru" }.to_string(); + with_config_lock(|| { + let mut config = load_unlocked()?; + config.locale = locale; + save_unlocked(&config)?; + Ok(config) + }) +} + +pub fn set_updater_checked(channel: Option) -> Result { + with_config_lock(|| { + let mut config = load_unlocked()?; + if let Some(ch) = channel { + if !ch.trim().is_empty() { + config.updater.channel = ch.trim().to_string(); + } + } + config.updater.last_check_at = Some( + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0), + ); + save_unlocked(&config)?; + Ok(config) + }) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/install.rs b/legacy/Launcher/apps/launcher/src-tauri/src/install.rs new file mode 100644 index 00000000000..124f1c764c2 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/install.rs @@ -0,0 +1,2120 @@ +use crate::config; +use crate::java; +use crate::models::{JavaRequirement, ManifestFile, PackLocalStatus, PackManifest, SyncProgress}; +use crate::sync; +use serde_json::Value; +use sha2::{Digest, Sha256}; +use std::collections::HashSet; +use std::fs::{self, File}; +use std::io::{copy, Read, Write}; +use std::path::{Component, Path, PathBuf}; +use std::process::{Command, Stdio}; +#[cfg(windows)] +use std::os::windows::process::CommandExt; +use std::sync::{LazyLock, Mutex}; +use std::time::Duration; +use tauri::{AppHandle, Emitter}; +use wait_timeout::ChildExt; +use zip::ZipArchive; + +static INSTALL_LOCK: LazyLock>> = LazyLock::new(|| Mutex::new(None)); + +fn acquire_install(id: &str) -> Result<(), String> { + let mut guard = INSTALL_LOCK + .lock() + .map_err(|_| "Install lock poisoned".to_string())?; + if let Some(active) = guard.as_ref() { + return Err(format!( + "Another install is already running ({active}). Wait for it to finish." + )); + } + *guard = Some(id.to_string()); + Ok(()) +} + +fn release_install(id: &str) { + if let Ok(mut guard) = INSTALL_LOCK.lock() { + if guard.as_deref() == Some(id) { + *guard = None; + } + } +} + +pub fn is_install_active(id: &str) -> bool { + INSTALL_LOCK + .lock() + .ok() + .and_then(|g| g.as_ref().map(|active| active == id)) + .unwrap_or(false) +} + +const MOJANG_MANIFEST: &str = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"; +const LIBRARIES_BASE: &str = "https://libraries.minecraft.net/"; +const RESOURCES_BASE: &str = "https://resources.download.minecraft.net/"; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InstanceRecord { + pub id: String, + pub name: String, + pub loader: String, + pub minecraft: String, + pub loader_version: String, + pub created_at: u64, + #[serde(default)] + pub status: String, +} + +pub async fn install_instance( + app: AppHandle, + id: String, + name: String, + loader: String, + minecraft: String, + loader_version: String, +) -> Result { + acquire_install(&id)?; + let result = install_instance_inner( + app, + id.clone(), + name, + loader, + minecraft, + loader_version, + ) + .await; + release_install(&id); + match result { + Ok(status) => Ok(status), + Err(err) => { + let _ = mark_instance_status(&id, "error"); + Err(err) + } + } +} + +async fn install_instance_inner( + app: AppHandle, + id: String, + name: String, + loader: String, + minecraft: String, + loader_version: String, +) -> Result { + validate_id(&id)?; + let loader = loader.to_ascii_lowercase(); + if !matches!( + loader.as_str(), + "vanilla" | "fabric" | "quilt" | "forge" | "neoforge" + ) { + return Err(format!("Unsupported loader: {loader}")); + } + if minecraft.trim().is_empty() { + return Err("Minecraft version is required".into()); + } + if loader != "vanilla" && loader_version.trim().is_empty() { + return Err("Loader version is required".into()); + } + + let root = config::ensure_layout()?.join("instances").join(&id); + let game_dir = root.join("game"); + fs::create_dir_all(&game_dir).map_err(|e| format!("Create game dir: {e}"))?; + + let record = InstanceRecord { + id: id.clone(), + name: name.trim().chars().take(48).collect(), + loader: loader.clone(), + minecraft: minecraft.clone(), + loader_version: loader_version.clone(), + created_at: unix_now(), + status: "installing".into(), + }; + write_json(&root.join("instance.json"), &record)?; + + // Remove stale ready marker while installing. + let meta_path = root.join("meta.json"); + if meta_path.exists() { + let _ = fs::remove_file(&meta_path); + } + + emit( + &app, + &id, + "resolve", + None, + 0, + 0, + format!("Resolving {loader} {minecraft}"), + )?; + + let http = http_client()?; + let mojang = fetch_mojang_version(&http, &minecraft).await?; + let asset_index_id = mojang + .pointer("/assetIndex/id") + .and_then(|v| v.as_str()) + .unwrap_or(&minecraft) + .to_string(); + let java_min = mojang + .pointer("/javaVersion/majorVersion") + .and_then(|v| v.as_u64()) + .unwrap_or(17) as u32; + + let mut jobs: Vec = Vec::new(); + let mut natives_jobs: Vec = Vec::new(); + store_mojang_version_json(&minecraft, &mojang)?; + collect_mojang_jobs(&mojang, &minecraft, &mut jobs, &mut natives_jobs)?; + + let mut main_class = mojang + .get("mainClass") + .and_then(|v| v.as_str()) + .unwrap_or("net.minecraft.client.main.Main") + .to_string(); + let mut jvm_args: Vec = vec!["-Xmx2G".into()]; + let mut game_args: Vec = Vec::new(); + + match loader.as_str() { + "fabric" => { + let profile = fetch_json( + &http, + &format!( + "https://meta.fabricmc.net/v2/versions/loader/{}/{}/profile/json", + enc(&minecraft), + enc(&loader_version) + ), + ) + .await?; + if let Some(mc) = profile.get("mainClass").and_then(|v| v.as_str()) { + main_class = mc.to_string(); + } + collect_profile_libs(&profile, &mut jobs)?; + } + "quilt" => { + let profile = fetch_json( + &http, + &format!( + "https://meta.quiltmc.org/v3/versions/loader/{}/{}/profile/json", + enc(&minecraft), + enc(&loader_version) + ), + ) + .await?; + if let Some(mc) = profile.get("mainClass").and_then(|v| v.as_str()) { + main_class = mc.to_string(); + } + collect_profile_libs(&profile, &mut jobs)?; + } + "forge" | "neoforge" => { + // Download + run official installer, then merge resulting version JSON libs. + run_modded_installer( + &app, + &http, + &id, + &loader, + &minecraft, + &loader_version, + &game_dir, + ) + .await?; + // Move installer-written libraries into shared meta (Theseus-style). + merge_tree_into( + &game_dir.join("libraries"), + &config::meta_libraries_dir()?, + )?; + let version_id = if loader == "forge" { + format!("{minecraft}-forge-{loader_version}") + } else { + format!("neoforge-{loader_version}") + }; + let version_json_path = game_dir + .join("versions") + .join(&version_id) + .join(format!("{version_id}.json")); + let version_json = if version_json_path.is_file() { + read_json_file(&version_json_path)? + } else { + find_best_version_json(&game_dir, &minecraft, &loader)? + }; + if let Some(mc) = version_json.get("mainClass").and_then(|v| v.as_str()) { + main_class = mc.to_string(); + } + collect_version_tree_libs(&http, &game_dir, &version_json, &mut jobs, &mut natives_jobs) + .await?; + let (extracted_jvm, extracted_game) = + collect_modded_launch_args(&http, &game_dir, &version_json).await?; + ensure_modded_bootstrap_args(&extracted_jvm, &extracted_game)?; + jvm_args = extracted_jvm; + if !jvm_args.iter().any(|a| a.starts_with("-Xmx")) { + jvm_args.insert(0, "-Xmx2G".into()); + } + game_args = extracted_game; + } + _ => {} + } + + // Deduplicate by dest path. + jobs = dedupe_jobs(jobs); + natives_jobs = dedupe_jobs(natives_jobs); + + let asset_jobs = collect_asset_jobs(&http, &mojang, &game_dir).await?; + let total = (jobs.len() + natives_jobs.len() + asset_jobs.len()) as u32; + let mut done = count_reusable_jobs( + jobs.iter().chain(natives_jobs.iter()).chain(asset_jobs.iter()), + &game_dir, + )?; + let mut files: Vec = Vec::new(); + + if done > 0 { + emit( + &app, + &id, + "download", + None, + done, + total, + format!("Reusing {done}/{total} cached meta files"), + )?; + } + + for job in jobs.iter().chain(natives_jobs.iter()) { + let dest = config::resolve_game_or_meta(&job.rel, &game_dir)?; + let reused = ensure_dest_reusable(&job.rel, &dest, job.size); + if !reused { + emit( + &app, + &id, + "download", + Some(job.rel.clone()), + done, + total, + format!("Downloading {}", job.rel), + )?; + } + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + } + let outcome = if reused { + ensure_meta_file( + &http, + &job.url, + &dest, + job.sha1.as_deref(), + job.size, + VerifyAfterDownload::Sha1, + None, + ) + .await? + } else { + let mut on_prog = file_progress_callback( + app.clone(), + id.clone(), + "download".into(), + Some(job.rel.clone()), + done, + total, + format!("Downloading {}", job.rel), + job.size, + ); + ensure_meta_file( + &http, + &job.url, + &dest, + job.sha1.as_deref(), + job.size, + VerifyAfterDownload::Sha1, + Some(&mut on_prog), + ) + .await? + }; + if job.rel.to_ascii_lowercase().ends_with(".jar") && !job.natives_only { + // Prefer Mojang SHA1 in the manifest field (prefixed) so we never re-hash + // multi‑MB jars on disk after a cache hit — that froze install at N-1/N. + let (sha256, size) = match outcome { + EnsureOutcome::Reused => { + let size = fs::metadata(&dest).map(|m| m.len()).unwrap_or(0); + let hash = job + .sha1 + .as_ref() + .map(|s| format!("sha1:{s}")) + .unwrap_or_else(|| "reuse".into()); + (hash, size) + } + EnsureOutcome::Downloaded { bytes } => { + let hash = job + .sha1 + .as_ref() + .map(|s| format!("sha1:{s}")) + .unwrap_or_else(|| hex_sha256(&bytes)); + (hash, bytes.len() as u64) + } + }; + files.push(ManifestFile { + path: job.rel.clone(), + url: job.url.clone(), + sha256, + size: Some(size), + }); + } + if !reused { + done += 1; + } + } + + // Extract natives into shared meta/natives/{minecraft} + let natives_dir = config::meta_natives_dir(&minecraft)?; + for job in &natives_jobs { + let jar = config::resolve_game_or_meta(&job.rel, &game_dir)?; + extract_natives(&jar, &natives_dir)?; + } + // Forge installer may have written natives under game/ — merge into shared. + merge_tree_into(&game_dir.join("natives"), &natives_dir)?; + + download_missing_assets( + &app, + &id, + &http, + &asset_jobs, + &game_dir, + &mut done, + total, + None, + ) + .await?; + + let version_label = if loader == "vanilla" { + minecraft.clone() + } else { + format!("{minecraft}-{loader}-{loader_version}") + }; + + let manifest = PackManifest { + id: id.clone(), + version: version_label, + minecraft: minecraft.clone(), + loader: loader.clone(), + main_class: Some(main_class), + java: Some(JavaRequirement { + min_major: java_min, + }), + asset_index: Some(asset_index_id), + files, + jvm_args, + game_args, + }; + write_json(&meta_path, &manifest)?; + + let mut ready_record = record; + ready_record.status = "ready".into(); + write_json(&root.join("instance.json"), &ready_record)?; + + emit( + &app, + &id, + "done", + None, + done, + total, + "Install complete".into(), + )?; + + sync::pack_status(&id) +} + +fn mark_instance_status(id: &str, status: &str) -> Result<(), String> { + let path = config::ensure_layout()? + .join("instances") + .join(id) + .join("instance.json"); + if !path.is_file() { + return Ok(()); + } + let mut record: InstanceRecord = read_json_file(&path).and_then(|v| { + serde_json::from_value(v).map_err(|e| format!("Parse instance.json: {e}")) + })?; + record.status = status.to_string(); + write_json(&path, &record) +} + +#[derive(Clone)] +struct DownloadJob { + rel: String, + url: String, + sha1: Option, + size: Option, + natives_only: bool, +} + +fn http_client() -> Result { + reqwest::Client::builder() + .user_agent(concat!("Owyx/", env!("CARGO_PKG_VERSION"))) + .timeout(Duration::from_secs(120)) + .connect_timeout(Duration::from_secs(15)) + .redirect(reqwest::redirect::Policy::custom(|attempt| { + if attempt.previous().len() >= 5 { + return attempt.error("too many redirects"); + } + match assert_allowed_download_url(attempt.url().as_str()) { + Ok(()) => attempt.follow(), + Err(err) => attempt.error(err), + } + })) + .build() + .map_err(|e| format!("HTTP client: {e}")) +} + +async fn fetch_mojang_version(http: &reqwest::Client, id: &str) -> Result { + let manifest = fetch_json(http, MOJANG_MANIFEST).await?; + let versions = manifest + .get("versions") + .and_then(|v| v.as_array()) + .ok_or("Invalid Mojang manifest")?; + let url = versions + .iter() + .find(|v| v.get("id").and_then(|x| x.as_str()) == Some(id)) + .and_then(|v| v.get("url").and_then(|x| x.as_str())) + .ok_or_else(|| format!("Minecraft version not found: {id}"))? + .to_string(); + fetch_json(http, &url).await +} + +async fn fetch_json(http: &reqwest::Client, url: &str) -> Result { + assert_allowed_download_url(url)?; + let res = http + .get(url) + .send() + .await + .map_err(|e| format!("GET {url}: {e}"))? + .error_for_status() + .map_err(|e| format!("HTTP {url}: {e}"))?; + assert_allowed_download_url(res.url().as_str())?; + res.json() + .await + .map_err(|e| format!("JSON {url}: {e}")) +} + +fn collect_mojang_jobs( + version: &Value, + version_id: &str, + jobs: &mut Vec, + natives: &mut Vec, +) -> Result<(), String> { + // Theseus: client jar lives at meta/versions/{id}/{id}.jar — NOT under libraries/. + if let Some(client) = version.pointer("/downloads/client") { + let client_url = client + .get("url") + .and_then(|v| v.as_str()) + .ok_or("client.url missing")?; + let client_sha1 = client.get("sha1").and_then(|v| v.as_str()).map(str::to_string); + let client_size = client.get("size").and_then(|v| v.as_u64()); + let id = version_id.trim(); + if id.is_empty() { + return Err("Minecraft version id missing for client jar".into()); + } + jobs.push(DownloadJob { + rel: format!("versions/{id}/{id}.jar"), + url: client_url.to_string(), + sha1: client_sha1, + size: client_size, + natives_only: false, + }); + } + + let libs = version + .get("libraries") + .and_then(|v| v.as_array()) + .cloned() + .unwrap_or_default(); + for lib in libs { + if !library_allowed(&lib) { + continue; + } + if let Some(artifact) = lib.pointer("/downloads/artifact") { + if let Some(job) = artifact_job(artifact, false)? { + jobs.push(job); + } + } + if let Some(classifiers) = lib.pointer("/downloads/classifiers") { + let key = natives_classifier_key(&lib); + if let Some(key) = key { + if let Some(native_art) = classifiers.get(&key) { + if let Some(job) = artifact_job(native_art, true)? { + natives.push(job); + } + } + } + } + } + Ok(()) +} + +/// Persist Mojang version JSON under shared `meta/versions/{id}/{id}.json` (Theseus). +fn store_mojang_version_json(version_id: &str, version: &Value) -> Result<(), String> { + let dir = config::meta_version_dir(version_id)?; + let path = dir.join(format!("{version_id}.json")); + if path.is_file() { + return Ok(()); + } + write_json(&path, version) +} + +fn collect_profile_libs(profile: &Value, jobs: &mut Vec) -> Result<(), String> { + let libs = profile + .get("libraries") + .and_then(|v| v.as_array()) + .cloned() + .unwrap_or_default(); + for lib in libs { + if !library_allowed(&lib) { + continue; + } + if let Some(artifact) = lib.pointer("/downloads/artifact") { + if let Some(job) = artifact_job(artifact, false)? { + jobs.push(job); + continue; + } + } + // Fabric/Quilt sometimes only provide name maven coords. + if let Some(name) = lib.get("name").and_then(|v| v.as_str()) { + let url_base = lib + .get("url") + .and_then(|v| v.as_str()) + .unwrap_or(LIBRARIES_BASE); + if let Some(job) = maven_job(name, url_base)? { + jobs.push(job); + } + } + } + Ok(()) +} + +async fn collect_version_tree_libs( + http: &reqwest::Client, + game_dir: &Path, + version: &Value, + jobs: &mut Vec, + natives: &mut Vec, +) -> Result<(), String> { + let mut current = version.clone(); + let mut guard = 0; + loop { + let vid = current + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or("unknown") + .to_string(); + // Only the vanilla parent usually carries downloads.client; path uses that id. + collect_mojang_jobs(¤t, &vid, jobs, natives)?; + collect_profile_libs(¤t, jobs)?; + let Some(parent) = current + .get("inheritsFrom") + .and_then(|v| v.as_str()) + .map(str::to_string) + else { + break; + }; + guard += 1; + if guard > 6 { + return Err("Version inheritance too deep".into()); + } + let shared = config::meta_version_dir(&parent)?.join(format!("{parent}.json")); + let local = game_dir + .join("versions") + .join(&parent) + .join(format!("{parent}.json")); + current = if shared.is_file() { + read_json_file(&shared)? + } else if local.is_file() { + read_json_file(&local)? + } else { + let fetched = fetch_mojang_version(http, &parent).await?; + let _ = store_mojang_version_json(&parent, &fetched); + fetched + }; + } + Ok(()) +} + +/// Walk inheritsFrom and collect JVM/game args needed for Forge/NeoForge BootstrapLauncher. +async fn collect_modded_launch_args( + http: &reqwest::Client, + game_dir: &Path, + version: &Value, +) -> Result<(Vec, Vec), String> { + let mut chain: Vec = Vec::new(); + let mut current = version.clone(); + let mut guard = 0; + loop { + chain.push(current.clone()); + let Some(parent) = current + .get("inheritsFrom") + .and_then(|v| v.as_str()) + .map(str::to_string) + else { + break; + }; + guard += 1; + if guard > 6 { + return Err("Version inheritance too deep while reading args".into()); + } + let local = game_dir + .join("versions") + .join(&parent) + .join(format!("{parent}.json")); + current = if local.is_file() { + read_json_file(&local)? + } else { + fetch_mojang_version(http, &parent).await? + }; + } + // Parent first, then child overrides/appends (Minecraft launcher merge order). + chain.reverse(); + + let version_name = version + .get("id") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let natives = config::meta_natives_dir( + version + .pointer("/inheritsFrom") + .and_then(|v| v.as_str()) + .unwrap_or(version_name), + )?; + let libraries = config::meta_libraries_dir()?; + let classpath_sep = if cfg!(windows) { ";" } else { ":" }; + + let mut jvm_raw = Vec::new(); + let mut game_raw = Vec::new(); + for node in &chain { + append_version_arg_list(node.pointer("/arguments/jvm"), &mut jvm_raw); + append_version_arg_list(node.pointer("/arguments/game"), &mut game_raw); + } + + let jvm_args = resolve_modded_jvm_args( + &jvm_raw, + &natives, + &libraries, + classpath_sep, + version_name, + )?; + let game_args = filter_modded_game_args(&game_raw)?; + Ok((jvm_args, game_args)) +} + +fn ensure_modded_bootstrap_args(jvm: &[String], game: &[String]) -> Result<(), String> { + let has_module_path = jvm.iter().any(|a| a == "-p" || a == "--module-path"); + if !has_module_path { + return Err( + "Forge/NeoForge install did not produce a module-path (-p). Try another loader version." + .into(), + ); + } + let has_launch_target = game.windows(2).any(|w| w[0] == "--launchTarget" && !w[1].is_empty()); + if !has_launch_target { + return Err( + "Forge/NeoForge install did not produce --launchTarget. Try another loader version." + .into(), + ); + } + Ok(()) +} + +fn append_version_arg_list(node: Option<&Value>, out: &mut Vec) { + let Some(arr) = node.and_then(|v| v.as_array()) else { + return; + }; + for item in arr { + if let Some(s) = item.as_str() { + out.push(s.to_string()); + continue; + } + if !argument_rules_allow(item) { + continue; + } + match item.get("value") { + Some(Value::String(s)) => out.push(s.clone()), + Some(Value::Array(vals)) => { + for v in vals { + if let Some(s) = v.as_str() { + out.push(s.to_string()); + } + } + } + _ => {} + } + } +} + +fn argument_rules_allow(arg: &Value) -> bool { + let Some(rules) = arg.get("rules").and_then(|v| v.as_array()) else { + return true; + }; + let mut allowed = false; + for rule in rules { + let action = rule.get("action").and_then(|v| v.as_str()).unwrap_or("allow"); + let os_name = rule.pointer("/os/name").and_then(|v| v.as_str()); + let matches_os = match os_name { + None => true, + Some("windows") => cfg!(windows), + Some("osx") => cfg!(target_os = "macos"), + Some("linux") => cfg!(target_os = "linux"), + _ => false, + }; + if matches_os { + allowed = action == "allow"; + } + } + allowed +} + +fn resolve_modded_jvm_args( + raw: &[String], + natives: &Path, + libraries: &Path, + classpath_sep: &str, + version_name: &str, +) -> Result, String> { + let mut out = Vec::new(); + let mut i = 0; + while i < raw.len() { + let substituted = substitute_jvm_templates( + &raw[i], + natives, + libraries, + classpath_sep, + version_name, + ); + // Launcher already supplies -cp / java.library.path. + if substituted == "-cp" || substituted == "-classpath" { + i += 2; + continue; + } + if substituted == "${classpath}" || substituted.contains("${classpath}") { + i += 1; + continue; + } + if substituted.starts_with("-Djava.library.path=") { + i += 1; + continue; + } + if substituted.is_empty() { + i += 1; + continue; + } + out.push(substituted); + i += 1; + } + Ok(out) +} + +fn substitute_jvm_templates( + arg: &str, + natives: &Path, + libraries: &Path, + classpath_sep: &str, + version_name: &str, +) -> String { + arg.replace("${natives_directory}", &natives.display().to_string()) + .replace("${library_directory}", &libraries.display().to_string()) + .replace("${classpath_separator}", classpath_sep) + .replace("${version_name}", version_name) + .replace("${launcher_name}", "Owyx") + .replace("${launcher_version}", env!("CARGO_PKG_VERSION")) + .replace("${/}", std::path::MAIN_SEPARATOR_STR) +} + +fn filter_modded_game_args(raw: &[String]) -> Result, String> { + const FLAGS: &[&str] = &[ + "--launchTarget", + "--fml.forgeVersion", + "--fml.mcVersion", + "--fml.forgeGroup", + "--fml.mcpVersion", + "--fml.neoForgeVersion", + "--fml.fmlVersion", + "--fml.neoFormVersion", + ]; + let mut out = Vec::new(); + let mut i = 0; + while i < raw.len() { + let flag = raw[i].trim(); + if !FLAGS.contains(&flag) { + i += 1; + continue; + } + let Some(value) = raw.get(i + 1).map(|s| s.trim()) else { + return Err(format!("Missing value for Forge game arg {flag}")); + }; + if value.is_empty() || value.starts_with('-') { + return Err(format!("Invalid value for Forge game arg {flag}")); + } + out.push(flag.to_string()); + out.push(value.to_string()); + i += 2; + } + Ok(out) +} + +fn artifact_job(artifact: &Value, natives_only: bool) -> Result, String> { + let path = artifact + .get("path") + .and_then(|v| v.as_str()) + .ok_or("artifact.path missing")?; + let url = artifact + .get("url") + .and_then(|v| v.as_str()) + .map(str::to_string) + .unwrap_or_else(|| format!("{LIBRARIES_BASE}{path}")); + let sha1 = artifact.get("sha1").and_then(|v| v.as_str()).map(str::to_string); + let size = artifact.get("size").and_then(|v| v.as_u64()); + Ok(Some(DownloadJob { + rel: format!("libraries/{path}"), + url, + sha1, + size, + natives_only, + })) +} + +fn maven_job(name: &str, base: &str) -> Result, String> { + // group:artifact:version[:classifier] + let parts: Vec<&str> = name.split(':').collect(); + if parts.len() < 3 { + return Ok(None); + } + let group = parts[0].replace('.', "/"); + let artifact = parts[1]; + let version = parts[2]; + let classifier = parts.get(3).copied(); + let file = match classifier { + Some(c) => format!("{artifact}-{version}-{c}.jar"), + None => format!("{artifact}-{version}.jar"), + }; + let path = format!("{group}/{artifact}/{version}/{file}"); + let base = base.trim_end_matches('/'); + Ok(Some(DownloadJob { + rel: format!("libraries/{path}"), + url: format!("{base}/{path}"), + sha1: None, + size: None, + natives_only: false, + })) +} + +fn library_allowed(lib: &Value) -> bool { + let Some(rules) = lib.get("rules").and_then(|v| v.as_array()) else { + return true; + }; + let mut allowed = false; + for rule in rules { + let action = rule.get("action").and_then(|v| v.as_str()).unwrap_or("allow"); + let os_name = rule.pointer("/os/name").and_then(|v| v.as_str()); + let matches_os = match os_name { + None => true, + Some("windows") => cfg!(windows), + Some("osx") => cfg!(target_os = "macos"), + Some("linux") => cfg!(target_os = "linux"), + _ => false, + }; + if matches_os { + allowed = action == "allow"; + } + } + allowed +} + +fn natives_classifier_key(lib: &Value) -> Option { + let natives = lib.get("natives")?; + let key = if cfg!(windows) { + natives.get("windows") + } else if cfg!(target_os = "macos") { + natives.get("osx") + } else { + natives.get("linux") + }? + .as_str()?; + Some(key.replace("${arch}", if cfg!(target_pointer_width = "64") { "64" } else { "32" })) +} + +async fn collect_asset_jobs( + http: &reqwest::Client, + version: &Value, + game_dir: &Path, +) -> Result, String> { + let index_url = version + .pointer("/assetIndex/url") + .and_then(|v| v.as_str()) + .ok_or("assetIndex.url missing")?; + let index_id = version + .pointer("/assetIndex/id") + .and_then(|v| v.as_str()) + .unwrap_or("legacy"); + let index = fetch_json(http, index_url).await?; + let index_path = config::meta_assets_dir()? + .join("indexes") + .join(format!("{index_id}.json")); + if let Some(parent) = index_path.parent() { + fs::create_dir_all(parent).map_err(|e| format!("assets indexes: {e}"))?; + } + write_json(&index_path, &index)?; + let _ = game_dir; // assets are shared in meta/; game_dir kept for API stability + + let objects = index + .get("objects") + .and_then(|v| v.as_object()) + .ok_or("asset index objects missing")?; + let mut jobs = Vec::new(); + for (_name, obj) in objects { + let hash = obj + .get("hash") + .and_then(|v| v.as_str()) + .ok_or("asset hash missing")?; + if hash.len() < 2 { + continue; + } + let prefix = &hash[..2]; + let rel = format!("assets/objects/{prefix}/{hash}"); + let url = format!("{RESOURCES_BASE}{prefix}/{hash}"); + let size = obj.get("size").and_then(|v| v.as_u64()); + jobs.push(DownloadJob { + rel, + url, + sha1: Some(hash.to_string()), + size, + natives_only: false, + }); + } + Ok(jobs) +} + +async fn run_modded_installer( + app: &AppHandle, + http: &reqwest::Client, + id: &str, + loader: &str, + minecraft: &str, + loader_version: &str, + game_dir: &Path, +) -> Result<(), String> { + let (url, jar_name) = if loader == "forge" { + let ver = format!("{minecraft}-{loader_version}"); + ( + format!( + "https://maven.minecraftforge.net/net/minecraftforge/forge/{ver}/forge-{ver}-installer.jar" + ), + format!("forge-{ver}-installer.jar"), + ) + } else { + ( + format!( + "https://maven.neoforged.net/releases/net/neoforged/neoforge/{loader_version}/neoforge-{loader_version}-installer.jar" + ), + format!("neoforge-{loader_version}-installer.jar"), + ) + }; + + emit( + app, + id, + "installer", + Some(jar_name.clone()), + 0, + 0, + format!("Downloading {loader} installer"), + )?; + + let installer_path = game_dir.join(&jar_name); + let bytes = { + let mut on_prog = file_progress_callback( + app.clone(), + id.to_string(), + "installer".into(), + Some(jar_name.clone()), + 0, + 0, + format!("Downloading {loader} installer"), + None, + ); + download_bytes(http, &url, 256 * 1024 * 1024, Some(&mut on_prog)).await? + }; + atomic_write(&installer_path, &bytes)?; + + let java = java::find_compatible(17)?; + emit( + app, + id, + "installer", + Some(jar_name.clone()), + 0, + 0, + format!("Running {loader} installer"), + )?; + + let java_bin = java::for_launch(Path::new(&java.path)); + let mut installer_cmd = Command::new(&java_bin); + installer_cmd + .arg("-jar") + .arg(&installer_path) + .arg("--installClient") + .arg(game_dir) + .current_dir(game_dir) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + #[cfg(windows)] + { + installer_cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW + } + let mut child = installer_cmd + .spawn() + .map_err(|e| format!("Failed to start installer: {e}"))?; + + let timeout = Duration::from_secs(10 * 60); + match child + .wait_timeout(timeout) + .map_err(|e| format!("Wait installer: {e}"))? + { + Some(status) if status.success() => {} + Some(status) => { + return Err(format!( + "{loader} installer failed with status {status}. Try another loader version." + )); + } + None => { + let _ = child.kill(); + let _ = child.wait(); + return Err(format!( + "{loader} installer timed out after {}s", + timeout.as_secs() + )); + } + } + let _ = fs::remove_file(&installer_path); + Ok(()) +} + +fn find_best_version_json(game_dir: &Path, minecraft: &str, loader: &str) -> Result { + let versions = game_dir.join("versions"); + if !versions.is_dir() { + return Err("Installer did not create versions/".into()); + } + let needle = if loader == "neoforge" { + "neoforge" + } else { + "forge" + }; + let mut preferred: Option = None; + let mut fallback: Option = None; + for entry in fs::read_dir(&versions).map_err(|e| format!("Read versions: {e}"))? { + let entry = entry.map_err(|e| format!("Read versions entry: {e}"))?; + let name = entry.file_name().to_string_lossy().to_string(); + if name == minecraft { + continue; + } + let json = entry.path().join(format!("{name}.json")); + if !json.is_file() { + continue; + } + if name.to_ascii_lowercase().contains(needle) { + preferred = Some(json); + } else if fallback.is_none() { + fallback = Some(json); + } + } + let path = preferred + .or(fallback) + .ok_or("Could not find installed mod loader version JSON")?; + read_json_file(&path) +} + +/// Theseus-style reusable check: exist + size match when known (no full-file hash). +fn meta_file_reusable(path: &Path, expected_size: Option) -> bool { + let Ok(meta) = fs::metadata(path) else { + return false; + }; + if !meta.is_file() { + return false; + } + match expected_size { + Some(sz) => meta.len() == sz, + None => meta.len() > 0, + } +} + +/// If an older build stored client.jar under libraries/, adopt it into versions/{id}/. +fn adopt_legacy_client_jar(rel: &str, dest: &Path, expected_size: Option) -> bool { + let norm = rel.replace('\\', "/"); + if !(norm.starts_with("versions/") && norm.ends_with(".jar")) { + return false; + } + if meta_file_reusable(dest, expected_size) { + return true; + } + let Ok(legacy) = config::meta_libraries_dir().map(|d| { + d.join("com") + .join("mojang") + .join("minecraft") + .join("client.jar") + }) else { + return false; + }; + if !meta_file_reusable(&legacy, expected_size) { + return false; + } + if let Some(parent) = dest.parent() { + let _ = fs::create_dir_all(parent); + } + match fs::copy(&legacy, dest) { + Ok(_) => { + let _ = fs::remove_file(&legacy); + true + } + Err(_) => false, + } +} + +fn ensure_dest_reusable(rel: &str, dest: &Path, expected_size: Option) -> bool { + if meta_file_reusable(dest, expected_size) { + return true; + } + adopt_legacy_client_jar(rel, dest, expected_size) +} + +fn count_reusable_jobs<'a, I>(jobs: I, game_dir: &Path) -> Result +where + I: IntoIterator, +{ + let mut n = 0u32; + for job in jobs { + let dest = config::resolve_game_or_meta(&job.rel, game_dir)?; + if ensure_dest_reusable(&job.rel, &dest, job.size) { + n += 1; + } + } + Ok(n) +} + +enum EnsureOutcome { + Reused, + Downloaded { bytes: Vec }, +} + +/// Post-download integrity policy. +/// Mojang asset object names are already content hashes — Theseus-style size trust is enough. +#[derive(Clone, Copy)] +enum VerifyAfterDownload { + SizeOnly, + Sha1, +} + +/// Concurrent Mojang asset fetches (Theseus uses loading_try_for_each_concurrent). +const ASSET_DOWNLOAD_CONCURRENCY: usize = 24; + +/// Download into shared meta (or game) unless the file already exists and passes size check. +/// Matches Modrinth/Theseus `should_download(!exists)` for skips; fresh assets skip SHA1 when size matches. +async fn ensure_meta_file( + http: &reqwest::Client, + url: &str, + dest: &Path, + sha1: Option<&str>, + expected_size: Option, + verify: VerifyAfterDownload, + on_progress: Option<&mut (dyn FnMut(u64, Option) -> Result<(), String> + Send)>, +) -> Result { + if meta_file_reusable(dest, expected_size) { + return Ok(EnsureOutcome::Reused); + } + let bytes = download_bytes(http, url, 512 * 1024 * 1024, on_progress).await?; + if let Some(sz) = expected_size { + if bytes.len() as u64 != sz { + return Err(format!( + "Size mismatch for {url}: expected {sz}, got {}", + bytes.len() + )); + } + } + // Assets: size match is enough (object path is the SHA1). Full-file hash after every + // download froze the titlebar for minutes on large objects. + if matches!(verify, VerifyAfterDownload::Sha1) { + if let Some(expected) = sha1 { + let actual = hex_sha1(&bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!( + "SHA1 mismatch for {url}: expected {expected}, got {actual}" + )); + } + } + } + atomic_write(dest, &bytes)?; + Ok(EnsureOutcome::Downloaded { bytes }) +} + +/// Download missing asset objects concurrently; advances `done` as each file finishes. +async fn download_missing_assets( + app: &AppHandle, + pack_id: &str, + http: &reqwest::Client, + asset_jobs: &[DownloadJob], + game_dir: &Path, + done: &mut u32, + total: u32, + // When set (prefetch), refresh in-memory prefetch progress marker. + prefetch_minecraft: Option<&str>, +) -> Result<(), String> { + use futures_util::stream::{self, StreamExt}; + use std::sync::atomic::{AtomicU32, Ordering}; + use std::sync::Arc; + + let mut pending: Vec = Vec::new(); + for job in asset_jobs { + let dest = config::resolve_game_or_meta(&job.rel, game_dir)?; + if !meta_file_reusable(&dest, job.size) { + pending.push(job.clone()); + } + } + // One hash object can appear under many logical asset names; dedupe by rel + // so buffer_unordered writers never race on the same assets/objects path. + pending = dedupe_jobs(pending); + if pending.is_empty() { + return Ok(()); + } + + let done_atomic = Arc::new(AtomicU32::new(*done)); + let game_dir = game_dir.to_path_buf(); + let pack_id_owned = pack_id.to_string(); + + let mut tasks = stream::iter(pending.into_iter().map(|job| { + let http = http.clone(); + let app = app.clone(); + let pack_id = pack_id_owned.clone(); + let game_dir = game_dir.clone(); + let done_atomic = Arc::clone(&done_atomic); + async move { + let dest = config::resolve_game_or_meta(&job.rel, &game_dir)?; + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + } + let snapshot = done_atomic.load(Ordering::Relaxed); + let rel = job.rel.clone(); + let mut on_prog = file_progress_callback( + app.clone(), + pack_id.clone(), + "assets".into(), + Some(rel.clone()), + snapshot, + total, + format!("Asset {rel}"), + job.size, + ); + ensure_meta_file( + &http, + &job.url, + &dest, + job.sha1.as_deref(), + job.size, + VerifyAfterDownload::SizeOnly, + Some(&mut on_prog), + ) + .await?; + let new_done = done_atomic.fetch_add(1, Ordering::Relaxed) + 1; + // Clear per-file tip by emitting without byte fields; advance N/M immediately. + emit( + &app, + &pack_id, + "assets", + Some(job.rel.clone()), + new_done, + total, + format!("Asset {}", job.rel), + )?; + Ok::(new_done) + } + })) + .buffer_unordered(ASSET_DOWNLOAD_CONCURRENCY); + + while let Some(res) = tasks.next().await { + let new_done = res?; + if let Some(mc) = prefetch_minecraft { + set_prefetch_state(PrefetchStatus { + ready: false, + minecraft: Some(mc.to_string()), + message: format!("Prefetch {new_done}/{total}"), + done_files: new_done, + total_files: total, + }); + } + } + + *done = done_atomic.load(Ordering::Relaxed); + Ok(()) +} + +/// Min delta between byte-progress events (Theseus uses ~256 KiB / 0.5% of file). +const FILE_PROGRESS_MIN_BYTES: u64 = 256 * 1024; + +async fn download_bytes( + http: &reqwest::Client, + url: &str, + max_bytes: u64, + mut on_progress: Option<&mut (dyn FnMut(u64, Option) -> Result<(), String> + Send)>, +) -> Result, String> { + use futures_util::StreamExt; + + assert_allowed_download_url(url)?; + let res = http + .get(url) + .send() + .await + .map_err(|e| format!("Download {url}: {e}"))? + .error_for_status() + .map_err(|e| format!("Download HTTP {url}: {e}"))?; + assert_allowed_download_url(res.url().as_str())?; + let content_len = res.content_length(); + if let Some(len) = content_len { + if len > max_bytes { + return Err(format!( + "File too large ({len} bytes, max {max_bytes}): {url}" + )); + } + } + let mut stream = res.bytes_stream(); + let mut buf: Vec = Vec::new(); + let mut last_reported = 0u64; + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Read body {url}: {e}"))?; + if buf.len() as u64 + chunk.len() as u64 > max_bytes { + return Err(format!("File too large (max {max_bytes} bytes): {url}")); + } + buf.extend_from_slice(&chunk); + if let Some(cb) = on_progress.as_mut() { + let received = buf.len() as u64; + let min_delta = content_len + .map(|t| (t / 200).max(FILE_PROGRESS_MIN_BYTES)) + .unwrap_or(FILE_PROGRESS_MIN_BYTES); + let at_end = content_len.is_some_and(|t| received >= t); + if last_reported == 0 + || at_end + || received.saturating_sub(last_reported) >= min_delta + { + last_reported = received; + cb(received, content_len)?; + } + } + } + if let Some(cb) = on_progress.as_mut() { + let received = buf.len() as u64; + if received != last_reported { + cb(received, content_len.or(Some(received)))?; + } + } + Ok(buf) +} + +fn assert_allowed_download_url(raw: &str) -> Result<(), String> { + let parsed = reqwest::Url::parse(raw).map_err(|e| format!("Bad download URL: {e}"))?; + if parsed.scheme() != "https" { + return Err(format!("Only https downloads are allowed: {raw}")); + } + if parsed.username() != "" || parsed.password().is_some() { + return Err(format!("Download URL must not include credentials: {raw}")); + } + let host = parsed + .host_str() + .ok_or_else(|| format!("Download URL missing host: {raw}"))? + .to_ascii_lowercase(); + const ALLOWED_SUFFIXES: &[&str] = &[ + "mojang.com", + "minecraft.net", + "fabricmc.net", + "quiltmc.org", + "minecraftforge.net", + "neoforged.net", + "azul.com", + ]; + let ok = ALLOWED_SUFFIXES + .iter() + .any(|suffix| host == *suffix || host.ends_with(&format!(".{suffix}"))); + if !ok { + return Err(format!("Download host not allowed: {host}")); + } + Ok(()) +} + +fn extract_natives(jar: &Path, out_dir: &Path) -> Result<(), String> { + let file = File::open(jar).map_err(|e| format!("Open natives jar: {e}"))?; + let mut archive = ZipArchive::new(file).map_err(|e| format!("Zip natives: {e}"))?; + for i in 0..archive.len() { + let mut entry = archive + .by_index(i) + .map_err(|e| format!("Zip entry: {e}"))?; + let name = entry.name().to_string(); + if name.ends_with('/') || name.contains("META-INF") { + continue; + } + let rel = safe_rel(&name)?; + // Only extract native binaries / related files at top levels. + let dest = out_dir.join(rel.file_name().unwrap_or_default()); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("natives parent: {e}"))?; + } + let mut outfile = File::create(&dest).map_err(|e| format!("Create native: {e}"))?; + copy(&mut entry, &mut outfile).map_err(|e| format!("Extract native: {e}"))?; + } + Ok(()) +} + +fn dedupe_jobs(jobs: Vec) -> Vec { + let mut seen = HashSet::new(); + let mut out = Vec::new(); + for job in jobs { + if seen.insert(job.rel.clone()) { + out.push(job); + } + } + out +} + +fn merge_tree_into(src: &Path, dst: &Path) -> Result<(), String> { + if !src.is_dir() { + return Ok(()); + } + fs::create_dir_all(dst).map_err(|e| format!("Create merge dest: {e}"))?; + for entry in fs::read_dir(src).map_err(|e| format!("Read merge src: {e}"))? { + let entry = entry.map_err(|e| format!("Read merge entry: {e}"))?; + let from = entry.path(); + let to = dst.join(entry.file_name()); + let ft = entry.file_type().map_err(|e| format!("File type: {e}"))?; + if ft.is_dir() { + merge_tree_into(&from, &to)?; + } else if ft.is_file() { + if let Some(parent) = to.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + } + fs::copy(&from, &to).map_err(|e| format!("Merge copy: {e}"))?; + } + } + Ok(()) +} + +fn write_json(path: &Path, value: &T) -> Result<(), String> { + let raw = serde_json::to_string_pretty(value).map_err(|e| format!("Serialize: {e}"))?; + atomic_write(path, raw.as_bytes()) +} + +fn read_json_file(path: &Path) -> Result { + let raw = fs::read_to_string(path).map_err(|e| format!("Read {}: {e}", path.display()))?; + serde_json::from_str(&raw).map_err(|e| format!("Parse {}: {e}", path.display())) +} + +fn atomic_write(path: &Path, bytes: &[u8]) -> Result<(), String> { + use std::sync::atomic::{AtomicU64, Ordering}; + static TMP_SEQ: AtomicU64 = AtomicU64::new(0); + + let parent = path + .parent() + .ok_or_else(|| "Destination has no parent".to_string())?; + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + // Unique per call so concurrent writers to the same dest never share a tmp. + let seq = TMP_SEQ.fetch_add(1, Ordering::Relaxed); + let tmp = parent.join(format!( + ".{}.{}.{}.tmp", + path.file_name() + .and_then(|s| s.to_str()) + .unwrap_or("file"), + std::process::id(), + seq + )); + { + let mut file = fs::File::create(&tmp).map_err(|e| format!("Create temp: {e}"))?; + file.write_all(bytes).map_err(|e| format!("Write temp: {e}"))?; + // Theseus does not fsync every asset/lib write. sync_all() here stalled the UI + // for 1–2+ minutes per file on Windows (Defender / slow disks). + } + fs::rename(&tmp, path).map_err(|e| { + let _ = fs::remove_file(&tmp); + format!("Replace failed: {e}") + }) +} + +fn safe_rel(raw: &str) -> Result { + let path = Path::new(raw); + if path.is_absolute() { + return Err(format!("Absolute paths are not allowed: {raw}")); + } + let mut out = PathBuf::new(); + for comp in path.components() { + match comp { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe path component in {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err("Empty file path".into()); + } + Ok(out) +} + +fn hex_sha256(bytes: &[u8]) -> String { + Sha256::digest(bytes) + .iter() + .map(|b| format!("{b:02x}")) + .collect() +} + +#[allow(dead_code)] +fn hex_sha256_file(path: &Path) -> Result { + let mut file = File::open(path).map_err(|e| format!("Open {}: {e}", path.display()))?; + let mut hasher = Sha256::new(); + let mut buf = [0u8; 64 * 1024]; + loop { + let n = file + .read(&mut buf) + .map_err(|e| format!("Read {}: {e}", path.display()))?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + Ok(hasher + .finalize() + .iter() + .map(|b| format!("{b:02x}")) + .collect()) +} + +pub(crate) fn hex_sha1(bytes: &[u8]) -> String { + // Prefer sha1 crate? Avoid new dep: use a tiny impl via openssl-less approach. + // sha2 doesn't do sha1 — add quick dependency-free via `sha1_smol` or compute only when needed. + // Use `sha1` from existing? Not in Cargo. Implement with `sha1` crate — add soft check: + use sha1_compat::Sha1; + let mut h = Sha1::new(); + h.update(bytes); + h.digest().to_string() +} + +// Minimal SHA-1 (public domain style) to avoid extra crate churn if pull fails — use module. +mod sha1_compat { + pub struct Sha1 { + state: [u32; 5], + buf: Vec, + len: u64, + } + impl Sha1 { + pub fn new() -> Self { + Self { + state: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0], + buf: Vec::new(), + len: 0, + } + } + pub fn update(&mut self, data: &[u8]) { + self.len += data.len() as u64; + let mut offset = 0usize; + // Finish any partial block first (O(1) per call, not O(n²) via drain). + if !self.buf.is_empty() { + let need = 64 - self.buf.len(); + let take = need.min(data.len()); + self.buf.extend_from_slice(&data[..take]); + offset = take; + if self.buf.len() == 64 { + let block: [u8; 64] = self.buf.as_slice().try_into().unwrap(); + self.buf.clear(); + Self::process(&mut self.state, &block); + } + } + while offset + 64 <= data.len() { + let block: [u8; 64] = data[offset..offset + 64].try_into().unwrap(); + Self::process(&mut self.state, &block); + offset += 64; + } + if offset < data.len() { + self.buf.extend_from_slice(&data[offset..]); + } + } + pub fn digest(mut self) -> Digest { + let bit_len = self.len * 8; + self.buf.push(0x80); + while (self.buf.len() % 64) != 56 { + self.buf.push(0); + } + self.buf.extend_from_slice(&bit_len.to_be_bytes()); + let mut offset = 0usize; + while offset < self.buf.len() { + let block: [u8; 64] = self.buf[offset..offset + 64].try_into().unwrap(); + Self::process(&mut self.state, &block); + offset += 64; + } + Digest(self.state) + } + fn process(state: &mut [u32; 5], block: &[u8; 64]) { + let mut w = [0u32; 80]; + for i in 0..16 { + w[i] = u32::from_be_bytes([ + block[i * 4], + block[i * 4 + 1], + block[i * 4 + 2], + block[i * 4 + 3], + ]); + } + for i in 16..80 { + w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1); + } + let (mut a, mut b, mut c, mut d, mut e) = + (state[0], state[1], state[2], state[3], state[4]); + for i in 0..80 { + let (f, k) = match i { + 0..=19 => ((b & c) | ((!b) & d), 0x5A827999), + 20..=39 => (b ^ c ^ d, 0x6ED9EBA1), + 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC), + _ => (b ^ c ^ d, 0xCA62C1D6), + }; + let temp = a + .rotate_left(5) + .wrapping_add(f) + .wrapping_add(e) + .wrapping_add(k) + .wrapping_add(w[i]); + e = d; + d = c; + c = b.rotate_left(30); + b = a; + a = temp; + } + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + } + } + pub struct Digest([u32; 5]); + impl Digest { + pub fn to_string(&self) -> String { + self.0.iter().map(|x| format!("{x:08x}")).collect() + } + } + + #[cfg(test)] + mod tests { + use super::Sha1; + + #[test] + fn sha1_empty_and_abc() { + let h = Sha1::new(); + assert_eq!(h.digest().to_string(), "da39a3ee5e6b4b0d3255bfef95601890afd80709"); + let mut h = Sha1::new(); + h.update(b"abc"); + assert_eq!(h.digest().to_string(), "a9993e364706816aba3e25717850c26c9cd0d89d"); + } + + #[test] + fn sha1_large_is_linear() { + // Regression: old drain-based update was O(n²) and hung install on client.jar. + let chunk = vec![0x5Au8; 1024 * 1024]; // 1 MiB + let mut h = Sha1::new(); + for _ in 0..8 { + h.update(&chunk); + } + let dig = h.digest().to_string(); + assert_eq!(dig.len(), 40); + } + } +} + +fn validate_id(id: &str) -> Result<(), String> { + crate::instances::validate_instance_id(id) +} + +fn enc(s: &str) -> String { + // enough for version tokens + s.replace(' ', "%20") +} + +fn unix_now() -> u64 { + use std::time::{SystemTime, UNIX_EPOCH}; + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0) +} + +fn emit( + app: &AppHandle, + id: &str, + phase: &str, + current: Option, + done: u32, + total: u32, + message: String, +) -> Result<(), String> { + emit_progress(app, id, phase, current, done, total, message, None, None) +} + +fn emit_progress( + app: &AppHandle, + id: &str, + phase: &str, + current: Option, + done: u32, + total: u32, + message: String, + file_bytes_done: Option, + file_bytes_total: Option, +) -> Result<(), String> { + app.emit( + "install://progress", + SyncProgress { + pack_id: id.to_string(), + phase: phase.into(), + current_file: current, + done_files: done, + total_files: total, + message, + file_bytes_done, + file_bytes_total, + }, + ) + .map_err(|e| format!("Emit progress: {e}")) +} + +/// Throttled per-file byte progress (Modrinth/Theseus-style: ~0.5% or 256 KiB). +fn file_progress_callback( + app: AppHandle, + id: String, + phase: String, + current: Option, + done: u32, + total: u32, + message: String, + expected_size: Option, +) -> impl FnMut(u64, Option) -> Result<(), String> { + move |received, content_len| { + let file_total = expected_size.or(content_len); + emit_progress( + &app, + &id, + &phase, + current.clone(), + done, + total, + message.clone(), + Some(received), + file_total, + ) + } +} + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PrefetchStatus { + pub ready: bool, + pub minecraft: Option, + pub message: String, + pub done_files: u32, + pub total_files: u32, +} + +static PREFETCH_STATE: LazyLock> = LazyLock::new(|| { + Mutex::new(PrefetchStatus { + ready: false, + minecraft: None, + message: "Not started".into(), + done_files: 0, + total_files: 0, + }) +}); + +pub fn meta_prefetch_status() -> PrefetchStatus { + if let Ok(marker) = config::prefetch_marker_path() { + if marker.is_file() { + if let Ok(raw) = fs::read_to_string(&marker) { + if let Ok(parsed) = serde_json::from_str::(&raw) { + if parsed.ready { + return parsed; + } + } + } + } + } + PREFETCH_STATE + .lock() + .map(|g| g.clone()) + .unwrap_or_else(|_| PrefetchStatus { + ready: false, + minecraft: None, + message: "Busy".into(), + done_files: 0, + total_files: 0, + }) +} + +fn set_prefetch_state(status: PrefetchStatus) { + if let Ok(mut guard) = PREFETCH_STATE.lock() { + *guard = status.clone(); + } + if status.ready { + if let Ok(path) = config::prefetch_marker_path() { + let _ = write_json(&path, &status); + } + } +} + +/// Prefetch shared Mojang libraries + assets for the latest release into meta/. +pub async fn prefetch_shared_meta(app: AppHandle) -> Result { + let existing = meta_prefetch_status(); + if existing.ready { + return Ok(existing); + } + + let prefetch_id = "__meta_prefetch__"; + let mut acquired = false; + for _ in 0..30 { + if acquire_install(prefetch_id).is_ok() { + acquired = true; + break; + } + // Another install/prefetch holds the lock — wait briefly. + std::thread::sleep(Duration::from_millis(500)); + let status = meta_prefetch_status(); + if status.ready { + return Ok(status); + } + } + if !acquired { + return Err("Prefetch could not acquire install lock".into()); + } + + let result = prefetch_shared_meta_inner(&app, prefetch_id).await; + release_install(prefetch_id); + result +} + +async fn prefetch_shared_meta_inner( + app: &AppHandle, + prefetch_id: &str, +) -> Result { + set_prefetch_state(PrefetchStatus { + ready: false, + minecraft: None, + message: "Resolving latest Minecraft release…".into(), + done_files: 0, + total_files: 0, + }); + emit( + app, + prefetch_id, + "resolve", + None, + 0, + 0, + "Prefetch: resolving latest release".into(), + )?; + + let http = http_client()?; + let manifest: Value = fetch_json(&http, MOJANG_MANIFEST).await?; + let latest = manifest + .pointer("/latest/release") + .and_then(|v| v.as_str()) + .ok_or("Mojang manifest missing latest.release")? + .to_string(); + + let mojang = fetch_mojang_version(&http, &latest).await?; + let mut jobs: Vec = Vec::new(); + let mut natives_jobs: Vec = Vec::new(); + store_mojang_version_json(&latest, &mojang)?; + collect_mojang_jobs(&mojang, &latest, &mut jobs, &mut natives_jobs)?; + jobs = dedupe_jobs(jobs); + natives_jobs = dedupe_jobs(natives_jobs); + + // Dummy game dir — assets/libs resolve to meta via resolve_game_or_meta. + let game_dir = config::ensure_layout()?.join("cache").join("prefetch"); + fs::create_dir_all(&game_dir).map_err(|e| format!("prefetch cache: {e}"))?; + let asset_jobs = collect_asset_jobs(&http, &mojang, &game_dir).await?; + + let total = (jobs.len() + natives_jobs.len() + asset_jobs.len()) as u32; + let mut done = count_reusable_jobs( + jobs.iter().chain(natives_jobs.iter()).chain(asset_jobs.iter()), + &game_dir, + )?; + + set_prefetch_state(PrefetchStatus { + ready: false, + minecraft: Some(latest.clone()), + message: if done >= total && total > 0 { + format!("Verifying cached meta for {latest}…") + } else { + format!("Downloading shared meta for {latest} ({done}/{total} cached)…") + }, + done_files: done, + total_files: total, + }); + emit( + app, + prefetch_id, + "download", + None, + done, + total, + format!("Prefetch cached {done}/{total}"), + )?; + + for job in jobs.iter().chain(natives_jobs.iter()) { + let dest = config::resolve_game_or_meta(&job.rel, &game_dir)?; + if ensure_dest_reusable(&job.rel, &dest, job.size) { + continue; + } + emit( + app, + prefetch_id, + "download", + Some(job.rel.clone()), + done, + total, + format!("Prefetch {}", job.rel), + )?; + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent: {e}"))?; + } + { + let mut on_prog = file_progress_callback( + app.clone(), + prefetch_id.to_string(), + "download".into(), + Some(job.rel.clone()), + done, + total, + format!("Prefetch {}", job.rel), + job.size, + ); + let _ = ensure_meta_file( + &http, + &job.url, + &dest, + job.sha1.as_deref(), + job.size, + VerifyAfterDownload::Sha1, + Some(&mut on_prog), + ) + .await?; + } + done += 1; + set_prefetch_state(PrefetchStatus { + ready: false, + minecraft: Some(latest.clone()), + message: format!("Prefetch {done}/{total}"), + done_files: done, + total_files: total, + }); + } + + let natives_dir = config::meta_natives_dir(&latest)?; + for job in &natives_jobs { + let jar = config::resolve_game_or_meta(&job.rel, &game_dir)?; + extract_natives(&jar, &natives_dir)?; + } + + download_missing_assets( + app, + prefetch_id, + &http, + &asset_jobs, + &game_dir, + &mut done, + total, + Some(latest.as_str()), + ) + .await?; + + let status = PrefetchStatus { + ready: true, + minecraft: Some(latest.clone()), + message: format!("Shared meta ready ({latest})"), + done_files: done, + total_files: total, + }; + set_prefetch_state(status.clone()); + emit( + app, + prefetch_id, + "done", + None, + done, + total, + status.message.clone(), + )?; + crate::log::info(&status.message); + Ok(status) +} + +/// Update loader / game version on an existing instance (reinstalls on next Play). +pub fn update_instance_installation( + id: &str, + loader: &str, + minecraft: &str, + loader_version: &str, +) -> Result { + crate::instances::validate_instance_id(id)?; + let loader = loader.trim().to_ascii_lowercase(); + if !matches!( + loader.as_str(), + "vanilla" | "fabric" | "quilt" | "forge" | "neoforge" + ) { + return Err(format!("Unsupported loader: {loader}")); + } + if minecraft.trim().is_empty() { + return Err("Minecraft version is required".into()); + } + if loader != "vanilla" && loader_version.trim().is_empty() { + return Err("Loader version is required".into()); + } + if is_install_active(id) { + return Err("Cannot change installation while install is running".into()); + } + + let path = config::ensure_layout()? + .join("instances") + .join(id) + .join("instance.json"); + let mut record: InstanceRecord = read_json_file(&path).and_then(|v| { + serde_json::from_value(v).map_err(|e| format!("Parse instance.json: {e}")) + })?; + record.loader = loader; + record.minecraft = minecraft.trim().to_string(); + record.loader_version = if record.loader == "vanilla" { + String::new() + } else { + loader_version.trim().to_string() + }; + record.status = "pending".into(); + write_json(&path, &record)?; + + // Drop ready marker so Play reinstalls. + let meta = config::ensure_layout()? + .join("instances") + .join(id) + .join("meta.json"); + if meta.exists() { + let _ = fs::remove_file(meta); + } + Ok(record) +} + +pub async fn repair_instance(app: AppHandle, id: String) -> Result { + crate::instances::validate_instance_id(&id)?; + let path = config::ensure_layout()? + .join("instances") + .join(&id) + .join("instance.json"); + let record: InstanceRecord = read_json_file(&path).and_then(|v| { + serde_json::from_value(v).map_err(|e| format!("Parse instance.json: {e}")) + })?; + install_instance( + app, + record.id.clone(), + record.name, + record.loader, + record.minecraft, + record.loader_version, + ) + .await +} + diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/instances.rs b/legacy/Launcher/apps/launcher/src-tauri/src/instances.rs new file mode 100644 index 00000000000..c1df768c184 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/instances.rs @@ -0,0 +1,1651 @@ +use crate::config; +use crate::install::InstanceRecord; +use crate::log as owyx_log; +use serde::Serialize; +use std::collections::HashMap; +use std::fs; +use std::path::{Component, Path, PathBuf}; +use std::time::UNIX_EPOCH; +use tauri::AppHandle; +use tauri_plugin_opener::OpenerExt; + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DiskInstance { + pub id: String, + pub name: String, + pub loader: String, + pub minecraft: String, + pub loader_version: String, + pub created_at: u64, + pub status: String, + pub ready: bool, + pub path: String, + pub has_icon: bool, + /// From `{instance}/catalog.json` when present (survives localStorage wipe). + #[serde(skip_serializing_if = "Option::is_none")] + pub catalog_server_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub catalog_pack_id: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub server_address: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub server_port: Option, +} + +fn catalog_fields_for(id: &str) -> (Option, Option, Option, Option) { + match crate::catalog::read_catalog_meta(id) { + Some(meta) => ( + Some(meta.server_id), + meta.pack_id, + Some(meta.address), + Some(meta.port), + ), + None => (None, None, None, None), + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DirEntryInfo { + pub name: String, + pub path: String, + pub is_dir: bool, + pub size: Option, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LogFileInfo { + pub name: String, + pub path: String, + pub size: u64, + pub modified_at: u64, +} + +/// Folder name rules aligned with Modrinth Theseus `sanitize_instance_name`. +pub fn sanitize_instance_name(input: &str) -> String { + let cleaned: String = input + .trim() + .chars() + .map(|c| match c { + '/' | '\\' | '?' | '*' | ':' | '\'' | '"' | '|' | '<' | '>' | '!' => '_', + c if c.is_control() => '_', + c => c, + }) + .take(64) + .collect(); + let cleaned = cleaned + .trim_matches(|c: char| c == '.' || c.is_whitespace()) + .to_string(); + if cleaned.is_empty() { + "instance".into() + } else { + cleaned + } +} + +pub fn validate_instance_id(id: &str) -> Result<(), String> { + if id.is_empty() || id.len() > 96 || id == "." || id == ".." { + return Err("Invalid instance id".into()); + } + if id.chars().any(|c| { + matches!( + c, + '/' | '\\' | '?' | '*' | ':' | '"' | '|' | '<' | '>' | '\0' + ) || c.is_control() + }) { + return Err("Invalid instance id".into()); + } + // Single path segment only. + if Path::new(id).components().count() != 1 { + return Err("Invalid instance id".into()); + } + Ok(()) +} + +fn validate_id(id: &str) -> Result<(), String> { + validate_instance_id(id) +} + +fn instance_root(id: &str) -> Result { + validate_id(id)?; + Ok(config::ensure_layout()?.join("instances").join(id)) +} + +fn allocate_unique_id(base: &str) -> Result { + let base = sanitize_instance_name(base); + validate_id(&base)?; + let root = config::ensure_layout()?.join("instances"); + let mut candidate = base.clone(); + let mut n = 1u32; + loop { + let path = root.join(&candidate); + if !path.exists() { + validate_id(&candidate)?; + return Ok(candidate); + } + candidate = format!("{base} ({n})"); + n += 1; + if n > 999 { + return Err("Could not allocate instance folder name".into()); + } + } +} + +/// Create instance folder + `instance.json` without downloading game files. +/// Full install runs later on Play (Modrinth-like: create first, install when needed). +pub fn prepare_instance( + name: &str, + loader: &str, + minecraft: &str, + loader_version: &str, + icon_source: Option<&str>, +) -> Result { + let loader = loader.trim().to_ascii_lowercase(); + if !matches!( + loader.as_str(), + "vanilla" | "fabric" | "quilt" | "forge" | "neoforge" + ) { + return Err(format!("Unsupported loader: {loader}")); + } + if minecraft.trim().is_empty() { + return Err("Minecraft version is required".into()); + } + if loader != "vanilla" && loader_version.trim().is_empty() { + return Err("Loader version is required".into()); + } + + let display_name: String = name.trim().chars().take(48).collect(); + let display_name = if display_name.is_empty() { + sanitize_instance_name(&format!( + "{} {}", + if loader == "vanilla" { + "Vanilla" + } else { + &loader + }, + minecraft.trim() + )) + } else { + display_name + }; + let id = allocate_unique_id(&display_name)?; + let root = instance_root(&id)?; + fs::create_dir_all(root.join("game").join("mods")).map_err(|e| format!("Create mods: {e}"))?; + fs::create_dir_all(root.join("game").join("resourcepacks")) + .map_err(|e| format!("Create resourcepacks: {e}"))?; + fs::create_dir_all(root.join("game").join("shaderpacks")) + .map_err(|e| format!("Create shaderpacks: {e}"))?; + fs::create_dir_all(root.join("game").join("saves")) + .map_err(|e| format!("Create saves: {e}"))?; + + let created_at = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let record = InstanceRecord { + id: id.clone(), + name: display_name.clone(), + loader: loader.clone(), + minecraft: minecraft.trim().to_string(), + loader_version: loader_version.trim().to_string(), + created_at, + status: "pending".into(), + }; + let raw = serde_json::to_string_pretty(&record).map_err(|e| format!("Serialize: {e}"))?; + fs::write(root.join("instance.json"), raw).map_err(|e| format!("Write instance.json: {e}"))?; + + if let Some(src) = icon_source.map(str::trim).filter(|s| !s.is_empty()) { + if let Err(e) = set_instance_icon(&id, Some(src)) { + let _ = fs::remove_dir_all(&root); + return Err(e); + } + } + + let (catalog_server_id, catalog_pack_id, server_address, server_port) = + catalog_fields_for(&id); + Ok(DiskInstance { + id, + name: display_name, + loader, + minecraft: minecraft.trim().to_string(), + loader_version: loader_version.trim().to_string(), + created_at, + status: "pending".into(), + ready: false, + path: root.display().to_string(), + has_icon: icon_dest(&root).is_file(), + catalog_server_id, + catalog_pack_id, + server_address, + server_port, + }) +} + +fn icon_dest(root: &Path) -> PathBuf { + // Prefer existing icon.* if present; default write target is icon.png. + for name in ["icon.png", "icon.jpg", "icon.jpeg", "icon.webp", "icon.gif", "icon.bmp"] { + let p = root.join(name); + if p.is_file() { + return p; + } + } + root.join("icon.png") +} + +fn icon_write_dest(root: &Path, source: &Path) -> PathBuf { + let ext = source + .extension() + .and_then(|e| e.to_str()) + .map(|e| e.to_ascii_lowercase()) + .filter(|e| matches!(e.as_str(), "png" | "jpg" | "jpeg" | "webp" | "gif" | "bmp")) + .unwrap_or_else(|| "png".into()); + root.join(format!("icon.{ext}")) +} + +fn clear_instance_icons(root: &Path) -> Result<(), String> { + for name in ["icon.png", "icon.jpg", "icon.jpeg", "icon.webp", "icon.gif", "icon.bmp"] { + let p = root.join(name); + if p.is_file() { + fs::remove_file(&p).map_err(|e| format!("Remove icon: {e}"))?; + } + } + Ok(()) +} + +fn clear_other_instance_icons(root: &Path, keep: &Path) -> Result<(), String> { + for name in ["icon.png", "icon.jpg", "icon.jpeg", "icon.webp", "icon.gif", "icon.bmp"] { + let p = root.join(name); + if p == keep { + continue; + } + if p.is_file() { + fs::remove_file(&p).map_err(|e| format!("Remove old icon: {e}"))?; + } + } + Ok(()) +} + +fn is_image_ext(path: &Path) -> bool { + path.extension() + .and_then(|e| e.to_str()) + .map(|e| { + matches!( + e.to_ascii_lowercase().as_str(), + "png" | "jpg" | "jpeg" | "webp" | "gif" | "bmp" + ) + }) + .unwrap_or(false) +} + +/// Copy a user-picked image into `{instance}/icon.`, or remove it when `source` is None. +pub fn set_instance_icon(id: &str, source: Option<&str>) -> Result<(), String> { + let root = instance_root(id)?; + match source.map(str::trim).filter(|s| !s.is_empty()) { + None => clear_instance_icons(&root), + Some(src) => { + let src_path = Path::new(src); + if !src_path.is_file() { + return Err("Icon file not found".into()); + } + if !is_image_ext(src_path) { + return Err("Icon must be png, jpg, webp, gif, or bmp".into()); + } + let meta = fs::metadata(src_path).map_err(|e| format!("Stat icon: {e}"))?; + if meta.len() > 8 * 1024 * 1024 { + return Err("Icon file is too large (max 8 MB)".into()); + } + let dest = icon_write_dest(&root, src_path); + // Write via temp first so a failed copy never deletes the previous icon. + let tmp = root.join(format!( + ".{}.tmp", + dest.file_name() + .and_then(|s| s.to_str()) + .unwrap_or("icon.png") + )); + fs::copy(src_path, &tmp).map_err(|e| format!("Copy icon: {e}"))?; + // Atomic replace: std::fs::rename overwrites dest on Windows too + // (MoveFileExW + MOVEFILE_REPLACE_EXISTING). Do not delete dest first — + // a failed rename must leave the previous icon intact. + fs::rename(&tmp, &dest).map_err(|e| { + let _ = fs::remove_file(&tmp); + format!("Replace icon: {e}") + })?; + // Drop other formats only after the new icon is in place. + clear_other_instance_icons(&root, &dest)?; + Ok(()) + } + } +} + +/// Read instance icon (or arbitrary image path) as a data URL for the WebView. +pub fn image_as_data_url(path: &Path) -> Result { + if !path.is_file() { + return Err("Image not found".into()); + } + let meta = fs::metadata(path).map_err(|e| format!("Stat image: {e}"))?; + if meta.len() > 8 * 1024 * 1024 { + return Err("Image is too large".into()); + } + let bytes = fs::read(path).map_err(|e| format!("Read image: {e}"))?; + let mime = match path + .extension() + .and_then(|e| e.to_str()) + .unwrap_or("png") + .to_ascii_lowercase() + .as_str() + { + "jpg" | "jpeg" => "image/jpeg", + "webp" => "image/webp", + "gif" => "image/gif", + "bmp" => "image/bmp", + _ => "image/png", + }; + Ok(format!( + "data:{mime};base64,{}", + base64_encode(&bytes) + )) +} + +pub fn instance_icon_data_url(id: &str) -> Result, String> { + let root = instance_root(id)?; + let dest = icon_dest(&root); + if !dest.is_file() { + return Ok(None); + } + Ok(Some(image_as_data_url(&dest)?)) +} + +fn instance_has_icon(root: &Path) -> bool { + icon_dest(root).is_file() +} + +fn base64_encode(bytes: &[u8]) -> String { + const TABLE: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let mut out = String::with_capacity((bytes.len() + 2) / 3 * 4); + for chunk in bytes.chunks(3) { + let b0 = chunk[0] as u32; + let b1 = chunk.get(1).copied().unwrap_or(0) as u32; + let b2 = chunk.get(2).copied().unwrap_or(0) as u32; + let n = (b0 << 16) | (b1 << 8) | b2; + out.push(TABLE[((n >> 18) & 63) as usize] as char); + out.push(TABLE[((n >> 12) & 63) as usize] as char); + out.push(if chunk.len() > 1 { + TABLE[((n >> 6) & 63) as usize] as char + } else { + '=' + }); + out.push(if chunk.len() > 2 { + TABLE[(n & 63) as usize] as char + } else { + '=' + }); + } + out +} + +fn safe_rel(raw: &str) -> Result { + let path = Path::new(raw); + if path.is_absolute() { + return Err(format!("Absolute paths are not allowed: {raw}")); + } + let mut out = PathBuf::new(); + for comp in path.components() { + match comp { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe path component in {raw}")), + } + } + Ok(out) +} + +fn path_under(root: &Path, candidate: &Path) -> Result { + let root = fs::canonicalize(root).map_err(|e| format!("Resolve root: {e}"))?; + let full = if candidate.exists() { + fs::canonicalize(candidate).map_err(|e| format!("Resolve path: {e}"))? + } else { + return Err("Path does not exist".into()); + }; + if !full.starts_with(&root) { + return Err("Path escapes instance root".into()); + } + Ok(full) +} + +pub fn list_instances() -> Result, String> { + let root = config::ensure_layout()?.join("instances"); + if !root.is_dir() { + return Ok(Vec::new()); + } + let mut out = Vec::new(); + for entry in fs::read_dir(&root).map_err(|e| format!("Read instances: {e}"))? { + let entry = entry.map_err(|e| format!("Read instances entry: {e}"))?; + if !entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { + continue; + } + let id = entry.file_name().to_string_lossy().to_string(); + if validate_id(&id).is_err() { + continue; + } + let record_path = entry.path().join("instance.json"); + let mut record: InstanceRecord = if record_path.is_file() { + let raw = fs::read_to_string(&record_path) + .map_err(|e| format!("Read instance.json: {e}"))?; + serde_json::from_str(&raw).unwrap_or(InstanceRecord { + id: id.clone(), + name: id.clone(), + loader: "vanilla".into(), + minecraft: "".into(), + loader_version: "".into(), + created_at: 0, + status: "pending".into(), + }) + } else { + InstanceRecord { + id: id.clone(), + name: id.clone(), + loader: "vanilla".into(), + minecraft: "".into(), + loader_version: "".into(), + created_at: 0, + status: "pending".into(), + } + }; + // Folder name is canonical — fixes partial duplicate copies that still carry the source id. + if record.id != id { + record.id = id.clone(); + if let Ok(raw) = serde_json::to_string_pretty(&record) { + let _ = fs::write(&record_path, raw); + } + } + let mut status = if record.status.is_empty() { + if entry.path().join("meta.json").is_file() { + "ready".into() + } else { + "pending".into() + } + } else { + record.status.clone() + }; + // Crash/restart left "installing" without a live lock — treat as pending and heal JSON. + if status == "installing" && !crate::install::is_install_active(&id) { + status = "pending".into(); + record.status = "pending".into(); + if let Ok(raw) = serde_json::to_string_pretty(&record) { + let _ = fs::write(&record_path, raw); + } + } + // Cheap listing signal only — full verify stays on Play/repair (shared meta aware). + let ready = entry.path().join("meta.json").is_file() && status == "ready"; + let (catalog_server_id, catalog_pack_id, server_address, server_port) = + catalog_fields_for(&id); + out.push(DiskInstance { + id, + name: record.name, + loader: record.loader, + minecraft: record.minecraft, + loader_version: record.loader_version, + created_at: record.created_at, + status, + ready, + path: entry.path().display().to_string(), + has_icon: instance_has_icon(&entry.path()), + catalog_server_id, + catalog_pack_id, + server_address, + server_port, + }); + } + out.sort_by(|a, b| b.created_at.cmp(&a.created_at).then(a.name.cmp(&b.name))); + Ok(out) +} + +pub fn delete_instance(id: &str) -> Result<(), String> { + let root = instance_root(id)?; + if !root.exists() { + return Ok(()); + } + // Only block while an install lock is held — stale "installing" in JSON must not trap delete. + if crate::install::is_install_active(id) { + return Err("Cannot delete instance while install is in progress".into()); + } + fs::remove_dir_all(&root).map_err(|e| format!("Delete instance: {e}")) +} + +pub fn open_instance_dir(app: AppHandle, id: &str, which: &str) -> Result<(), String> { + let target = match which { + "logs" => owyx_log::logs_dir()?, + "root" => { + validate_id(id)?; + instance_root(id)? + } + "game" => { + validate_id(id)?; + instance_root(id)?.join("game") + } + "mods" => { + validate_id(id)?; + instance_root(id)?.join("game").join("mods") + } + "saves" => { + validate_id(id)?; + instance_root(id)?.join("game").join("saves") + } + _ => return Err(format!("Unknown folder kind: {which}")), + }; + if !target.exists() { + fs::create_dir_all(&target).map_err(|e| format!("Create folder: {e}"))?; + } + if which != "logs" { + let root = instance_root(id)?; + let _ = path_under(&root, &target)?; + } + let canon = fs::canonicalize(&target).map_err(|e| format!("Resolve folder: {e}"))?; + app.opener() + .open_path(canon.display().to_string(), None::<&str>) + .map_err(|e| format!("Open folder: {e}")) +} + +pub fn list_instance_dir(id: &str, relative: &str) -> Result, String> { + let root = instance_root(id)?.join("game"); + if !root.is_dir() { + return Ok(Vec::new()); + } + let rel = if relative.trim().is_empty() { + PathBuf::new() + } else { + safe_rel(relative)? + }; + let dir = if rel.as_os_str().is_empty() { + root.clone() + } else { + root.join(&rel) + }; + let dir = path_under(&root, &dir)?; + if !dir.is_dir() { + return Err("Not a directory".into()); + } + let mut out = Vec::new(); + // Cap listing so huge folders (assets/objects) cannot freeze the UI. + const MAX_ENTRIES: usize = 2_000; + for entry in fs::read_dir(&dir).map_err(|e| format!("Read dir: {e}"))? { + if out.len() >= MAX_ENTRIES { + break; + } + let entry = entry.map_err(|e| format!("Read entry: {e}"))?; + // Prefer file_type() — cheaper than full metadata() on Windows. + let file_type = entry + .file_type() + .map_err(|e| format!("File type: {e}"))?; + let is_dir = file_type.is_dir(); + let name = entry.file_name().to_string_lossy().to_string(); + let child_rel = if rel.as_os_str().is_empty() { + name.clone() + } else { + format!("{}/{}", rel.to_string_lossy().replace('\\', "/"), name) + }; + let size = if is_dir { + None + } else { + entry.metadata().ok().map(|m| m.len()) + }; + out.push(DirEntryInfo { + name, + path: child_rel.replace('\\', "/"), + is_dir, + size, + }); + } + out.sort_by(|a, b| { + b.is_dir + .cmp(&a.is_dir) + .then(a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase())) + }); + Ok(out) +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InstanceLogInfo { + pub id: String, + pub name: String, + pub source: String, + pub filename: String, + pub size: u64, + pub modified_at: u64, + pub live: bool, +} + +/// Live Log + game/logs (+ .gz) + Owyx launcher launch-*.log for this instance. +pub fn list_instance_logs(pack_id: &str) -> Result, String> { + validate_instance_id(pack_id)?; + let mut out = Vec::new(); + out.push(InstanceLogInfo { + id: "live".into(), + name: "Live Log".into(), + source: "live".into(), + filename: String::new(), + size: 0, + modified_at: 0, + live: true, + }); + + // Minecraft game logs + let game_logs = instance_root(pack_id)?.join("game").join("logs"); + if game_logs.is_dir() { + for entry in fs::read_dir(&game_logs).map_err(|e| format!("Read game logs: {e}"))? { + let entry = entry.map_err(|e| format!("Read game log entry: {e}"))?; + let name = entry.file_name().to_string_lossy().to_string(); + let lower = name.to_ascii_lowercase(); + if !(lower.ends_with(".log") || lower.ends_with(".log.gz") || lower.ends_with(".txt")) { + continue; + } + let meta = match entry.metadata() { + Ok(m) if m.is_file() => m, + _ => continue, + }; + let modified_at = meta + .modified() + .ok() + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_secs()) + .unwrap_or(0); + out.push(InstanceLogInfo { + id: format!("game:{name}"), + name: name.clone(), + source: "game".into(), + filename: name, + size: meta.len(), + modified_at, + live: false, + }); + } + } + + // Owyx launcher launch logs for this pack + let launcher_dir = owyx_log::logs_dir()?; + if launcher_dir.is_dir() { + for entry in fs::read_dir(&launcher_dir).map_err(|e| format!("Read logs: {e}"))? { + let entry = entry.map_err(|e| format!("Read log entry: {e}"))?; + let name = entry.file_name().to_string_lossy().to_string(); + if !name.ends_with(".log") { + continue; + } + if !is_launch_log_for_pack(&name, pack_id) { + continue; + } + let meta = match entry.metadata() { + Ok(m) if m.is_file() => m, + _ => continue, + }; + let modified_at = meta + .modified() + .ok() + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_secs()) + .unwrap_or(0); + out.push(InstanceLogInfo { + id: format!("launcher:{name}"), + name: format!("launcher/{name}"), + source: "launcher".into(), + filename: name, + size: meta.len(), + modified_at, + live: false, + }); + } + } + + // Live first, then newest historical. + let (live, mut rest): (Vec<_>, Vec<_>) = out.into_iter().partition(|l| l.live); + rest.sort_by(|a, b| b.modified_at.cmp(&a.modified_at)); + let mut merged = live; + merged.extend(rest); + Ok(merged) +} + +pub fn read_instance_log( + pack_id: &str, + source: &str, + filename: &str, + max_bytes: Option, +) -> Result { + validate_instance_id(pack_id)?; + let limit = max_bytes.unwrap_or(512 * 1024).clamp(4 * 1024, 2 * 1024 * 1024); + + let path = match source { + "live" => resolve_live_log_path(pack_id)?, + "game" => { + let safe = Path::new(filename) + .file_name() + .ok_or_else(|| "Invalid log name".to_string())?; + let path = instance_root(pack_id)?.join("game").join("logs").join(safe); + if !path.is_file() { + return Err("Log not found".into()); + } + path + } + "launcher" => { + let safe = Path::new(filename) + .file_name() + .ok_or_else(|| "Invalid log name".to_string())?; + let name = safe.to_string_lossy(); + if !is_launch_log_for_pack(&name, pack_id) { + return Err("Log does not belong to this instance".into()); + } + let path = owyx_log::logs_dir()?.join(safe); + if !path.is_file() { + return Err("Log not found".into()); + } + path + } + _ => return Err("Unknown log source".into()), + }; + + read_log_file_tail(&path, limit) +} + +/// Match only `launch-{pack_id}-{unix_secs}.log` (same shape as `create_launch_log`). +/// Require the stamp to be digits so `mod` cannot claim `launch-mod-pack-….log`. +fn is_launch_log_for_pack(name: &str, pack_id: &str) -> bool { + let Some(rest) = name.strip_prefix(&format!("launch-{pack_id}-")) else { + return false; + }; + let Some(stamp) = rest.strip_suffix(".log") else { + return false; + }; + !stamp.is_empty() && stamp.chars().all(|c| c.is_ascii_digit()) +} + +fn resolve_live_log_path(pack_id: &str) -> Result { + if let Some(path) = crate::launch::live_log_path(pack_id) { + if path.is_file() { + return Ok(path); + } + } + // Prefer Minecraft latest.log while/after a session. + let latest = instance_root(pack_id)?.join("game").join("logs").join("latest.log"); + if latest.is_file() { + return Ok(latest); + } + // Fall back to newest Owyx launch-*.log for this pack. + let dir = owyx_log::logs_dir()?; + let mut best: Option<(u64, PathBuf)> = None; + if let Ok(entries) = fs::read_dir(&dir) { + for entry in entries.flatten() { + let name = entry.file_name().to_string_lossy().to_string(); + if !name.ends_with(".log") { + continue; + } + if !is_launch_log_for_pack(&name, pack_id) { + continue; + } + let meta = match entry.metadata() { + Ok(m) if m.is_file() => m, + _ => continue, + }; + let modified = meta + .modified() + .ok() + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_secs()) + .unwrap_or(0); + if best.as_ref().map(|(m, _)| modified >= *m).unwrap_or(true) { + best = Some((modified, entry.path())); + } + } + } + best.map(|(_, p)| p) + .ok_or_else(|| "No live log yet — start the instance".into()) +} + +fn read_log_file_tail(path: &Path, limit: u64) -> Result { + use std::io::{Read, Seek, SeekFrom}; + + let name = path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("") + .to_ascii_lowercase(); + + if name.ends_with(".gz") { + // Stream-decompress and keep only the last `limit` bytes (never buffer the whole file). + const MAX_COMPRESSED: u64 = 16 * 1024 * 1024; + let meta_len = fs::metadata(path) + .map(|m| m.len()) + .unwrap_or(0); + if meta_len > MAX_COMPRESSED { + return Err(format!( + "Compressed log is too large ({} MB). Open it from the logs folder.", + meta_len / (1024 * 1024) + )); + } + let file = fs::File::open(path).map_err(|e| format!("Open log: {e}"))?; + let mut decoder = flate2::read::GzDecoder::new(file); + let mut chunks: Vec> = Vec::new(); + let mut total = 0u64; + let mut buf = vec![0u8; 64 * 1024]; + loop { + let n = decoder + .read(&mut buf) + .map_err(|e| format!("Decompress log: {e}"))?; + if n == 0 { + break; + } + total += n as u64; + chunks.push(buf[..n].to_vec()); + while total > limit && !chunks.is_empty() { + let first_len = chunks[0].len() as u64; + if total - first_len >= limit { + total -= first_len; + chunks.remove(0); + } else { + let drop = (total - limit) as usize; + chunks[0].drain(..drop); + total = limit; + break; + } + } + } + let mut out = Vec::with_capacity(total as usize); + for chunk in chunks { + out.extend_from_slice(&chunk); + } + return Ok(String::from_utf8_lossy(&out).into_owned()); + } + + let mut file = fs::File::open(path).map_err(|e| format!("Open log: {e}"))?; + let len = file + .metadata() + .map_err(|e| format!("Stat log: {e}"))? + .len(); + if len > limit { + file.seek(SeekFrom::Start(len - limit)) + .map_err(|e| format!("Seek log: {e}"))?; + } + let mut buf = Vec::new(); + file.take(limit) + .read_to_end(&mut buf) + .map_err(|e| format!("Read log: {e}"))?; + Ok(String::from_utf8_lossy(&buf).into_owned()) +} + +pub fn list_launch_logs(pack_id: Option) -> Result, String> { + let dir = owyx_log::logs_dir()?; + let mut out = Vec::new(); + for entry in fs::read_dir(&dir).map_err(|e| format!("Read logs: {e}"))? { + let entry = entry.map_err(|e| format!("Read log entry: {e}"))?; + let name = entry.file_name().to_string_lossy().to_string(); + if !name.ends_with(".log") { + continue; + } + if let Some(pid) = pack_id.as_deref() { + if !is_launch_log_for_pack(&name, pid) { + continue; + } + } + let meta = entry.metadata().map_err(|e| format!("Stat log: {e}"))?; + if !meta.is_file() { + continue; + } + let modified_at = meta + .modified() + .ok() + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_secs()) + .unwrap_or(0); + out.push(LogFileInfo { + name, + path: entry.path().display().to_string(), + size: meta.len(), + modified_at, + }); + } + out.sort_by(|a, b| b.modified_at.cmp(&a.modified_at)); + Ok(out) +} + +pub fn read_launch_log(name: &str, max_bytes: Option) -> Result { + use std::io::{Read, Seek, SeekFrom}; + + let safe = Path::new(name) + .file_name() + .ok_or_else(|| "Invalid log name".to_string())?; + let path = owyx_log::logs_dir()?.join(safe); + if !path.is_file() { + return Err("Log not found".into()); + } + let limit = max_bytes.unwrap_or(256 * 1024).clamp(4 * 1024, 2 * 1024 * 1024) as u64; + let mut file = fs::File::open(&path).map_err(|e| format!("Open log: {e}"))?; + let len = file + .metadata() + .map_err(|e| format!("Stat log: {e}"))? + .len(); + if len > limit { + file.seek(SeekFrom::Start(len - limit)) + .map_err(|e| format!("Seek log: {e}"))?; + } + let mut buf = Vec::new(); + file.take(limit) + .read_to_end(&mut buf) + .map_err(|e| format!("Read log: {e}"))?; + Ok(String::from_utf8_lossy(&buf).into_owned()) +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorldInfo { + pub id: String, + pub name: String, + pub mode: String, + pub last_played_at: u64, + pub hardcore: bool, + /// `icon.png` of the world as a data URL (Theseus-style thumbnail), when present. + #[serde(skip_serializing_if = "Option::is_none")] + pub icon: Option, +} + +/// World thumbnail: `icon.png` inside the save folder, as a data URL (small, so inline is fine). +fn world_icon_data_url(world_path: &Path) -> Option { + let icon = world_path.join("icon.png"); + if icon.is_file() { + image_as_data_url(&icon).ok() + } else { + None + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ContentInfo { + pub id: String, + pub name: String, + pub kind: String, + pub file_name: String, + pub enabled: bool, + pub size: u64, + /// Modrinth project id when this file was installed via Modrinth API. + #[serde(skip_serializing_if = "Option::is_none")] + pub modrinth_project_id: Option, +} + +fn content_dir(kind: &str) -> Result<&'static str, String> { + match kind { + "mod" => Ok("mods"), + "resourcepack" => Ok("resourcepacks"), + "shader" => Ok("shaderpacks"), + "datapack" => Ok("datapacks"), + _ => Err(format!("Unknown content kind: {kind}")), + } +} + +fn game_mode_label(game_type: i32, hardcore: bool) -> String { + if hardcore { + return "Hardcore".into(); + } + match game_type { + 1 => "Creative".into(), + 2 => "Adventure".into(), + 3 => "Spectator".into(), + _ => "Survival".into(), + } +} + +fn read_hardcore(data: &quartz_nbt::NbtCompound) -> bool { + data.get::<_, &quartz_nbt::NbtCompound>("difficulty_settings") + .ok() + .and_then(|settings| settings.get::<_, i8>("hardcore").ok()) + .or_else(|| data.get::<_, i8>("hardcore").ok()) + .unwrap_or(0) + != 0 +} + +/// Read LevelName / LastPlayed / GameType from `level.dat` (Modrinth Theseus pattern via quartz_nbt). +fn read_world_from_level_dat(world_path: &Path, folder_name: &str) -> WorldInfo { + let fallback_modified = fs::metadata(world_path) + .ok() + .and_then(|m| m.modified().ok()) + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_millis() as u64) + .unwrap_or(0); + let icon = world_icon_data_url(world_path); + let level_dat = world_path.join("level.dat"); + let Ok(raw) = fs::read(&level_dat) else { + return WorldInfo { + id: folder_name.into(), + name: folder_name.into(), + mode: "Local save".into(), + last_played_at: fallback_modified, + hardcore: false, + icon, + }; + }; + let parsed = quartz_nbt::io::read_nbt( + &mut std::io::Cursor::new(raw), + quartz_nbt::io::Flavor::GzCompressed, + ); + let Ok((root, _)) = parsed else { + return WorldInfo { + id: folder_name.into(), + name: folder_name.into(), + mode: "Local save".into(), + last_played_at: fallback_modified, + hardcore: false, + icon, + }; + }; + let Ok(data) = root.get::<_, &quartz_nbt::NbtCompound>("Data") else { + return WorldInfo { + id: folder_name.into(), + name: folder_name.into(), + mode: "Local save".into(), + last_played_at: fallback_modified, + hardcore: false, + icon, + }; + }; + let level_name = data + .get::<_, &str>("LevelName") + .ok() + .map(|s| s.to_string()) + .filter(|s| !s.is_empty()) + .unwrap_or_else(|| folder_name.to_string()); + let last_played = data + .get::<_, i64>("LastPlayed") + .ok() + .filter(|v| *v > 0) + .map(|v| v as u64) + .unwrap_or(fallback_modified); + let game_type = data.get::<_, i32>("GameType").unwrap_or(0); + let hardcore = read_hardcore(data); + WorldInfo { + id: folder_name.into(), + name: level_name, + mode: game_mode_label(game_type, hardcore), + last_played_at: last_played, + hardcore, + icon, + } +} + +pub fn list_worlds(id: &str) -> Result, String> { + let saves = instance_root(id)?.join("game").join("saves"); + if !saves.is_dir() { + return Ok(Vec::new()); + } + let mut out = Vec::new(); + for entry in fs::read_dir(&saves).map_err(|e| format!("Read saves: {e}"))? { + let entry = entry.map_err(|e| format!("Read save entry: {e}"))?; + if !entry.file_type().map(|t| t.is_dir()).unwrap_or(false) { + continue; + } + let name = entry.file_name().to_string_lossy().to_string(); + if name.starts_with('.') { + continue; + } + // Prefer folders that look like real worlds (level.dat), same as Modrinth. + if !entry.path().join("level.dat").is_file() { + continue; + } + out.push(read_world_from_level_dat(&entry.path(), &name)); + } + out.sort_by(|a, b| b.last_played_at.cmp(&a.last_played_at).then(a.name.cmp(&b.name))); + Ok(out) +} + +pub fn delete_world(id: &str, world_id: &str) -> Result<(), String> { + let safe = Path::new(world_id) + .file_name() + .ok_or_else(|| "Invalid world id".to_string())?; + let root = instance_root(id)?.join("game").join("saves"); + let target = root.join(safe); + let target = path_under(&root, &target)?; + if !target.is_dir() { + return Err("World not found".into()); + } + fs::remove_dir_all(&target).map_err(|e| format!("Delete world: {e}")) +} + +pub fn list_content(id: &str) -> Result, String> { + let game = instance_root(id)?.join("game"); + let modrinth_index = load_modrinth_index(id).unwrap_or_default(); + let mut out = Vec::new(); + for (kind, folder) in [ + ("mod", "mods"), + ("resourcepack", "resourcepacks"), + ("shader", "shaderpacks"), + ("datapack", "datapacks"), + ] { + let dir = game.join(folder); + if !dir.is_dir() { + continue; + } + for entry in fs::read_dir(&dir).map_err(|e| format!("Read {folder}: {e}"))? { + let entry = entry.map_err(|e| format!("Read {folder} entry: {e}"))?; + let meta = entry.metadata().map_err(|e| format!("Stat content: {e}"))?; + let file_name = entry.file_name().to_string_lossy().to_string(); + if file_name.starts_with('.') { + continue; + } + let enabled = !file_name.to_ascii_lowercase().ends_with(".disabled"); + let display = if enabled { + file_name.clone() + } else { + file_name[..file_name.len().saturating_sub(".disabled".len())].to_string() + }; + if kind == "mod" { + let lower = display.to_ascii_lowercase(); + if !lower.ends_with(".jar") { + continue; + } + } + let name = Path::new(&display) + .file_stem() + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_else(|| display.clone()); + let enabled_name = if file_name.to_ascii_lowercase().ends_with(".disabled") { + file_name[..file_name.len().saturating_sub(".disabled".len())].to_string() + } else { + file_name.clone() + }; + out.push(ContentInfo { + id: format!("{kind}:{file_name}"), + name, + kind: kind.into(), + file_name: file_name.clone(), + enabled, + size: if meta.is_file() { meta.len() } else { 0 }, + modrinth_project_id: modrinth_index + .get(&file_name) + .or_else(|| modrinth_index.get(&enabled_name)) + .cloned(), + }); + } + } + out.sort_by(|a, b| { + a.kind + .cmp(&b.kind) + .then(a.name.to_ascii_lowercase().cmp(&b.name.to_ascii_lowercase())) + }); + Ok(out) +} + +pub fn find_content_by_file_name(id: &str, file_name: &str) -> Result, String> { + Ok(list_content(id)? + .into_iter() + .find(|item| { + item.file_name.eq_ignore_ascii_case(file_name) + || item + .file_name + .strip_suffix(".disabled") + .is_some_and(|name| name.eq_ignore_ascii_case(file_name)) + })) +} + +pub fn set_content_enabled(id: &str, kind: &str, file_name: &str, enabled: bool) -> Result<(), String> { + let folder = content_dir(kind)?; + let safe = Path::new(file_name) + .file_name() + .ok_or_else(|| "Invalid file name".to_string())?; + let dir = instance_root(id)?.join("game").join(folder); + let current = dir.join(safe); + let current = path_under(&dir, ¤t)?; + if !current.exists() { + return Err("Content file not found".into()); + } + let name = current + .file_name() + .and_then(|s| s.to_str()) + .ok_or_else(|| "Invalid content name".to_string())? + .to_string(); + let is_disabled = name.to_ascii_lowercase().ends_with(".disabled"); + if enabled == !is_disabled { + return Ok(()); + } + let target_name = if enabled { + name.trim_end_matches(".disabled") + .trim_end_matches(".DISABLED") + .to_string() + } else { + format!("{name}.disabled") + }; + let target = dir.join(&target_name); + if target.exists() { + return Err("Target content name already exists".into()); + } + fs::rename(¤t, &target).map_err(|e| format!("Rename content: {e}"))?; + // Keep hide-installed accurate: if the index key was the pre-rename filename, move it. + retarget_modrinth_index_key(id, &name, &target_name)?; + Ok(()) +} + +pub fn delete_content(id: &str, kind: &str, file_name: &str) -> Result<(), String> { + let folder = content_dir(kind)?; + let safe = Path::new(file_name) + .file_name() + .and_then(|s| s.to_str()) + .ok_or_else(|| "Invalid file name".to_string())? + .to_string(); + let dir = instance_root(id)?.join("game").join(folder); + // Clear sidecar BEFORE unlink so a clear failure leaves the file for retry. + // Also runs when the file is already gone (stale index after partial failure). + clear_modrinth_index_for_file(id, &safe)?; + + let candidate = dir.join(&safe); + if !candidate.exists() { + // Idempotent: index already cleaned; nothing on disk. + return Ok(()); + } + let target = path_under(&dir, &candidate)?; + if target.is_dir() { + fs::remove_dir_all(&target).map_err(|e| format!("Delete content dir: {e}"))?; + } else if target.is_file() { + fs::remove_file(&target).map_err(|e| format!("Delete content file: {e}"))?; + } + Ok(()) +} + +pub fn read_content_file(id: &str, kind: &str, file_name: &str) -> Result>, String> { + let target = content_target_path(id, kind, file_name)?; + if !target.is_file() { + return Ok(None); + } + fs::read(&target) + .map(Some) + .map_err(|e| format!("Read content: {e}")) +} + +fn content_target_path(id: &str, kind: &str, file_name: &str) -> Result { + let folder = content_dir(kind)?; + let safe = Path::new(file_name) + .file_name() + .ok_or_else(|| "Invalid file name".to_string())?; + let dir = instance_root(id)?.join("game").join(folder); + path_under(&dir, &dir.join(safe)) +} + +fn is_safe_file_name(name: &str) -> bool { + if name.is_empty() || name.len() > 200 { + return false; + } + let path = Path::new(name); + if path.components().count() != 1 { + return false; + } + !matches!( + path.components().next(), + Some(Component::ParentDir | Component::RootDir | Component::Prefix(_)) + ) && !name.contains('/') + && !name.contains('\\') + && name != "." + && name != ".." +} + +/// Infer content kind from zip/jar markers (Modrinth `infer_project_type` logic). +fn infer_content_kind(bytes: &[u8]) -> Result<&'static str, String> { + let cursor = std::io::Cursor::new(bytes); + let mut archive = zip::ZipArchive::new(cursor) + .map_err(|_| "Unable to infer content type for input file".to_string())?; + if archive.by_name("fabric.mod.json").is_ok() + || archive.by_name("quilt.mod.json").is_ok() + || archive.by_name("META-INF/neoforge.mods.toml").is_ok() + || archive.by_name("META-INF/mods.toml").is_ok() + || archive.by_name("mcmod.info").is_ok() + { + return Ok("mod"); + } + if archive.by_name("pack.mcmeta").is_ok() { + let has_data = archive.file_names().any(|name| name.starts_with("data/")); + return Ok(if has_data { "datapack" } else { "resourcepack" }); + } + if archive + .file_names() + .any(|name| name.starts_with("shaders/")) + { + return Ok("shader"); + } + Err("Unable to infer content type for input file".into()) +} + +const MAX_CONTENT_BYTES: u64 = 512 * 1024 * 1024; + +/// Copy a local file into the instance content folder (Modrinth `add_project_from_path` pattern). +pub fn add_content_from_path( + id: &str, + path: &str, + kind_hint: Option<&str>, +) -> Result { + validate_id(id)?; + let src = PathBuf::from(path); + if !src.is_file() { + return Err("Source file not found".into()); + } + let file_name = src + .file_name() + .and_then(|s| s.to_str()) + .ok_or_else(|| "Invalid file name".to_string())? + .to_string(); + let meta = fs::metadata(&src).map_err(|e| format!("Stat source: {e}"))?; + if meta.len() > MAX_CONTENT_BYTES { + return Err("File too large".into()); + } + let bytes = fs::read(&src).map_err(|e| format!("Read source: {e}"))?; + add_content_from_bytes(id, &file_name, bytes, kind_hint) +} + +/// Write already-fetched content bytes into the instance folder. +/// Shared by local-file add and Modrinth install; same safety (name, size, infer, path_under). +pub fn add_content_from_bytes( + id: &str, + file_name: &str, + bytes: Vec, + kind_hint: Option<&str>, +) -> Result { + write_content_from_bytes(id, file_name, bytes, kind_hint, false) +} + +/// Overwrite an existing jar atomically (temp + rename). Used for Modrinth +/// hash-mismatch upgrades so we never delete the old file before the new one +/// is on disk. +pub fn replace_content_from_bytes( + id: &str, + file_name: &str, + bytes: Vec, + kind_hint: Option<&str>, +) -> Result { + write_content_from_bytes(id, file_name, bytes, kind_hint, true) +} + +fn write_content_from_bytes( + id: &str, + file_name: &str, + bytes: Vec, + kind_hint: Option<&str>, + overwrite: bool, +) -> Result { + validate_id(id)?; + if !is_safe_file_name(file_name) { + return Err(format!("Invalid content file name: {file_name}")); + } + if bytes.len() as u64 > MAX_CONTENT_BYTES { + return Err("File too large".into()); + } + let kind = if let Some(hint) = kind_hint.filter(|k| !k.is_empty()) { + content_dir(hint)?; + hint + } else { + infer_content_kind(&bytes)? + }; + let folder = content_dir(kind)?; + let dir = instance_root(id)?.join("game").join(folder); + fs::create_dir_all(&dir).map_err(|e| format!("Create {folder}: {e}"))?; + // Canonicalize the content folder only — dest file does not exist yet. + let dir = path_under(&dir, &dir)?; + let dest = dir.join(file_name); + if dest.exists() && !overwrite { + return Err("Content file already exists".into()); + } + config::atomic_write_path(&dest, &bytes)?; + let name = Path::new(file_name) + .file_stem() + .map(|s| s.to_string_lossy().into_owned()) + .unwrap_or_else(|| file_name.to_string()); + Ok(ContentInfo { + id: format!("{kind}:{file_name}"), + name, + kind: kind.into(), + file_name: file_name.to_string(), + enabled: true, + size: bytes.len() as u64, + modrinth_project_id: None, + }) +} + +/// Sidecar index: file_name → Modrinth project id (for Hide installed / Installed badges). +fn modrinth_index_path(id: &str) -> Result { + Ok(instance_root(id)?.join("game").join(".owyx-modrinth-index.json")) +} + +fn load_modrinth_index(id: &str) -> Result, String> { + let path = modrinth_index_path(id)?; + if !path.is_file() { + return Ok(HashMap::new()); + } + let raw = fs::read_to_string(&path).map_err(|e| format!("Read modrinth index: {e}"))?; + serde_json::from_str(&raw).map_err(|e| format!("Parse modrinth index: {e}")) +} + +fn save_modrinth_index(id: &str, map: &HashMap) -> Result<(), String> { + let path = modrinth_index_path(id)?; + if let Some(parent) = path.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create game dir: {e}"))?; + } + let raw = serde_json::to_vec_pretty(map).map_err(|e| format!("Serialize modrinth index: {e}"))?; + config::atomic_write_path(&path, &raw) +} + +/// Record that `file_name` was installed from Modrinth project `project_id`. +pub fn record_modrinth_project_id(id: &str, file_name: &str, project_id: &str) -> Result<(), String> { + validate_id(id)?; + let safe_name = Path::new(file_name) + .file_name() + .and_then(|s| s.to_str()) + .ok_or_else(|| "Invalid file name".to_string())?; + let pid = project_id.trim(); + if pid.is_empty() || pid.len() > 64 { + return Err("Invalid Modrinth project id".into()); + } + let mut map = load_modrinth_index(id)?; + map.insert(safe_name.to_string(), pid.to_string()); + save_modrinth_index(id, &map) +} + +fn strip_disabled_suffix(name: &str) -> &str { + let lower = name.to_ascii_lowercase(); + if let Some(stripped) = lower.strip_suffix(".disabled") { + &name[..stripped.len()] + } else { + name + } +} + +/// Remove both enabled and `.disabled` keys so hide-installed cannot lie after delete/re-add. +fn clear_modrinth_index_for_file(id: &str, file_name: &str) -> Result<(), String> { + let safe = Path::new(file_name) + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or(file_name); + let base = strip_disabled_suffix(safe); + let disabled = format!("{base}.disabled"); + let (mut map, load_ok) = match load_modrinth_index(id) { + Ok(m) => (m, true), + // Corrupt JSON → rewrite from empty rather than leave stale project ids. + Err(_) => (HashMap::new(), false), + }; + let mut changed = false; + for key in [safe, base, disabled.as_str()] { + if map.remove(key).is_some() { + changed = true; + } + } + if changed || !load_ok { + save_modrinth_index(id, &map)?; + } + Ok(()) +} + +/// If the index used the pre-rename filename as key, move the project id to the new name. +fn retarget_modrinth_index_key(id: &str, from: &str, to: &str) -> Result<(), String> { + if from == to { + return Ok(()); + } + let mut map = load_modrinth_index(id)?; + if let Some(pid) = map.remove(from) { + map.insert(to.to_string(), pid); + save_modrinth_index(id, &map)?; + } + Ok(()) +} + +pub fn duplicate_instance(id: &str, new_id: &str, new_name: &str) -> Result { + validate_id(id)?; + validate_id(new_id)?; + if id == new_id { + return Err("Duplicate id must be different".into()); + } + let src = instance_root(id)?; + if !src.is_dir() { + return Err("Source instance not found".into()); + } + if crate::install::is_install_active(id) { + return Err("Cannot duplicate while install is in progress".into()); + } + let dst = instance_root(new_id)?; + if dst.exists() { + return Err("Target instance id already exists".into()); + } + let result = (|| -> Result { + copy_dir_recursive(&src, &dst)?; + let mut record: InstanceRecord = if dst.join("instance.json").is_file() { + let raw = fs::read_to_string(dst.join("instance.json")) + .map_err(|e| format!("Read copied instance.json: {e}"))?; + serde_json::from_str(&raw).map_err(|e| format!("Parse copied instance.json: {e}"))? + } else { + InstanceRecord { + id: new_id.into(), + name: new_name.into(), + loader: "vanilla".into(), + minecraft: "".into(), + loader_version: "".into(), + created_at: 0, + status: "pending".into(), + } + }; + record.id = new_id.to_string(); + record.name = new_name.trim().chars().take(48).collect(); + if record.name.is_empty() { + record.name = new_id.to_string(); + } + record.created_at = std::time::SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let raw = serde_json::to_string_pretty(&record).map_err(|e| format!("Serialize: {e}"))?; + fs::write(dst.join("instance.json"), raw).map_err(|e| format!("Write instance.json: {e}"))?; + + let status = if record.status.is_empty() { + if dst.join("meta.json").is_file() { + "ready".into() + } else { + "pending".into() + } + } else { + record.status.clone() + }; + let (catalog_server_id, catalog_pack_id, server_address, server_port) = + catalog_fields_for(&record.id); + Ok(DiskInstance { + id: record.id, + name: record.name, + loader: record.loader, + minecraft: record.minecraft, + loader_version: record.loader_version, + created_at: record.created_at, + ready: dst.join("meta.json").is_file() && status == "ready", + status, + path: dst.display().to_string(), + has_icon: instance_has_icon(&dst), + catalog_server_id, + catalog_pack_id, + server_address, + server_port, + }) + })(); + if result.is_err() && dst.exists() { + let _ = fs::remove_dir_all(&dst); + } + result +} + +fn copy_dir_recursive(src: &Path, dst: &Path) -> Result<(), String> { + fs::create_dir_all(dst).map_err(|e| format!("Create dest: {e}"))?; + for entry in fs::read_dir(src).map_err(|e| format!("Read source: {e}"))? { + let entry = entry.map_err(|e| format!("Read source entry: {e}"))?; + let name = entry.file_name(); + let from = entry.path(); + let to = dst.join(&name); + let ft = entry.file_type().map_err(|e| format!("File type: {e}"))?; + if ft.is_dir() { + copy_dir_recursive(&from, &to)?; + } else if ft.is_file() { + fs::copy(&from, &to).map_err(|e| format!("Copy file: {e}"))?; + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn with_temp_instance(test_id: &str, body: impl FnOnce(&str) -> Result<(), String>) { + let id = format!("_test_{test_id}_{}", std::process::id()); + let root = config::ensure_layout() + .expect("layout") + .join("instances") + .join(&id); + let game = root.join("game").join("mods"); + fs::create_dir_all(&game).expect("mkdir"); + let result = body(&id); + let _ = fs::remove_dir_all(&root); + result.expect("test body"); + } + + #[test] + fn delete_missing_file_still_clears_index_keys() { + with_temp_instance("del_missing", |id| { + record_modrinth_project_id(id, "sodium.jar", "AANobbMI")?; + // Also leave a .disabled key as if enable/disable retargeted. + let mut map = load_modrinth_index(id)?; + map.insert("sodium.jar.disabled".into(), "AANobbMI".into()); + save_modrinth_index(id, &map)?; + + // File never existed — must still clear both keys. + delete_content(id, "mod", "sodium.jar")?; + let after = load_modrinth_index(id)?; + assert!( + !after.contains_key("sodium.jar"), + "enabled key must be gone: {after:?}" + ); + assert!( + !after.contains_key("sodium.jar.disabled"), + "disabled key must be gone: {after:?}" + ); + Ok(()) + }); + } + + #[test] + fn delete_clears_index_before_and_after_file_removal() { + with_temp_instance("del_file", |id| { + let jar = instance_root(id)?.join("game").join("mods").join("lithium.jar"); + fs::write(&jar, b"fake").map_err(|e| e.to_string())?; + record_modrinth_project_id(id, "lithium.jar", "gvQqB4Zr")?; + + delete_content(id, "mod", "lithium.jar")?; + assert!(!jar.exists()); + let after = load_modrinth_index(id)?; + assert!(!after.contains_key("lithium.jar")); + assert!(!after.contains_key("lithium.jar.disabled")); + + // Idempotent retry after partial failure scenario. + record_modrinth_project_id(id, "lithium.jar", "gvQqB4Zr")?; + delete_content(id, "mod", "lithium.jar")?; + let after2 = load_modrinth_index(id)?; + assert!(!after2.contains_key("lithium.jar")); + Ok(()) + }); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/java.rs b/legacy/Launcher/apps/launcher/src-tauri/src/java.rs new file mode 100644 index 00000000000..595cd33c4ff --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/java.rs @@ -0,0 +1,475 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::fs::{self, File}; +use std::io::Read; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::sync::{LazyLock, Mutex}; +use std::time::Duration; +use wait_timeout::ChildExt; + +#[cfg(windows)] +use std::os::windows::process::CommandExt; + +#[cfg(windows)] +const CREATE_NO_WINDOW: u32 = 0x0800_0000; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct JavaInstallation { + pub path: String, + pub version: String, + pub major_version: u32, + pub is_64_bit: bool, +} + +const PROBE_TIMEOUT: Duration = Duration::from_secs(5); +static JAVA_INSTALL_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); + +pub fn find_all() -> Vec { + let mut found = Vec::new(); + let mut seen = HashSet::new(); + + if let Ok(home) = std::env::var("JAVA_HOME") { + consider(&PathBuf::from(home).join("bin").join(java_bin()), &mut found, &mut seen); + } + + if let Ok(path) = std::env::var("PATH") { + for dir in std::env::split_paths(&path) { + consider(&dir.join(java_bin()), &mut found, &mut seen); + } + } + + for root in common_roots() { + if !root.is_dir() { + continue; + } + if let Ok(entries) = std::fs::read_dir(&root) { + for entry in entries.flatten() { + let candidate = entry.path().join("bin").join(java_bin()); + consider(&candidate, &mut found, &mut seen); + } + } + consider(&root.join("bin").join(java_bin()), &mut found, &mut seen); + } + + found.sort_by(|a, b| b.major_version.cmp(&a.major_version)); + found +} + +pub fn find_compatible(min_major: u32) -> Result { + // Prefer explicitly configured path for the required major (or newest >= min). + if let Ok(cfg) = crate::config::load() { + let mut majors: Vec = cfg + .java_versions + .keys() + .filter_map(|k| k.parse::().ok()) + .filter(|m| *m >= min_major) + .collect(); + majors.sort_by(|a, b| b.cmp(a)); + for major in majors { + if let Some(path) = cfg.java_versions.get(&major.to_string()) { + let p = PathBuf::from(path); + if p.is_file() { + if let Some(info) = probe(&p) { + return Ok(info); + } + } + } + } + } + + let cached = crate::config::load() + .map(|c| c.java_installations) + .unwrap_or_default(); + if let Some(hit) = cached + .into_iter() + .find(|j| j.major_version >= min_major && Path::new(&j.path).is_file()) + { + return Ok(hit); + } + + let all = find_all(); + let _ = crate::config::set_java_installations(all.clone()); + all.into_iter() + .find(|j| j.major_version >= min_major) + .ok_or_else(|| { + format!("Java {min_major}+ not found. Install a JDK/JRE and Detect in Settings.") + }) +} + +pub fn find_for_major(major: u32) -> Vec { + find_all() + .into_iter() + .filter(|j| j.major_version == major) + .collect() +} + +pub fn probe_path(path: &Path) -> Option { + probe(path) +} + +/// Download Azul Zulu JRE (Modrinth-style) into meta/java_versions/{major}/. +pub async fn auto_install(major: u32) -> Result { + const MAX_JAVA_ZIP: u64 = 400 * 1024 * 1024; + let arch = match std::env::consts::ARCH { + "x86_64" => "x64", + "aarch64" => "aarch64", + other => other, + }; + let os = match std::env::consts::OS { + "windows" => "windows", + "macos" => "macos", + _ => "linux", + }; + let metadata_url = format!( + "https://api.azul.com/metadata/v1/zulu/packages?arch={arch}&java_version={major}&os={os}&archive_type=zip&javafx_bundled=false&java_package_type=jre&page_size=1" + ); + assert_azul_url(&metadata_url)?; + + let http = reqwest::Client::builder() + .user_agent(concat!("Owyx/", env!("CARGO_PKG_VERSION"))) + .timeout(Duration::from_secs(180)) + .redirect(reqwest::redirect::Policy::custom(|attempt| { + if attempt.previous().len() >= 5 { + return attempt.error("too many redirects"); + } + match assert_azul_url(attempt.url().as_str()) { + Ok(()) => attempt.follow(), + Err(err) => attempt.error(err), + } + })) + .build() + .map_err(|e| format!("HTTP client: {e}"))?; + + #[derive(serde::Deserialize)] + struct Package { + download_url: String, + name: String, + } + + let packages: Vec = http + .get(&metadata_url) + .send() + .await + .map_err(|e| format!("Azul metadata: {e}"))? + .error_for_status() + .map_err(|e| format!("Azul metadata HTTP: {e}"))? + .json() + .await + .map_err(|e| format!("Azul metadata JSON: {e}"))?; + + let package = packages + .first() + .ok_or_else(|| format!("No Azul Zulu package for Java {major}"))?; + assert_azul_url(&package.download_url)?; + let zip_name = sanitize_zip_name(&package.name)?; + + let cache = crate::config::ensure_layout()?.join("cache").join("java"); + fs::create_dir_all(&cache).map_err(|e| format!("Create java cache: {e}"))?; + let zip_path = cache.join(format!("{major}-{zip_name}")); + let bytes = download_capped(&http, &package.download_url, MAX_JAVA_ZIP).await?; + + // Serialize write/extract/register so parallel Install clicks cannot race the same major. + let _guard = JAVA_INSTALL_LOCK + .lock() + .map_err(|_| "Java install lock poisoned".to_string())?; + fs::write(&zip_path, &bytes).map_err(|e| format!("Write Java zip: {e}"))?; + + let dest_root = crate::config::java_versions_dir()?.join(major.to_string()); + if dest_root.exists() { + fs::remove_dir_all(&dest_root).map_err(|e| format!("Clear java dir: {e}"))?; + } + fs::create_dir_all(&dest_root).map_err(|e| format!("Create java dir: {e}"))?; + extract_zip_safe(&zip_path, &dest_root)?; + let _ = fs::remove_file(&zip_path); + + let java_bin = find_java_binary(&dest_root) + .ok_or_else(|| "Extracted Java but could not find javaw.exe/java".to_string())?; + let info = probe(&java_bin).ok_or_else(|| "Installed Java failed -version probe".to_string())?; + let _ = crate::config::set_java_version_path(major, Some(info.path.clone())); + + let mut all = find_all(); + if !all.iter().any(|j| j.path.eq_ignore_ascii_case(&info.path)) { + all.push(info.clone()); + let _ = crate::config::set_java_installations(all); + } + Ok(info) +} + +fn assert_azul_url(raw: &str) -> Result<(), String> { + let parsed = reqwest::Url::parse(raw).map_err(|e| format!("Bad Java URL: {e}"))?; + if parsed.scheme() != "https" { + return Err(format!("Only https Java downloads allowed: {raw}")); + } + if parsed.username() != "" || parsed.password().is_some() { + return Err("Java download URL must not include credentials".into()); + } + let host = parsed + .host_str() + .ok_or_else(|| format!("Java URL missing host: {raw}"))? + .to_ascii_lowercase(); + let ok = host == "azul.com" || host.ends_with(".azul.com"); + if !ok { + return Err(format!("Java download host not allowed: {host}")); + } + Ok(()) +} + +fn sanitize_zip_name(name: &str) -> Result { + let name = name.trim().replace('\\', "/"); + let base = name + .rsplit('/') + .next() + .unwrap_or("") + .trim() + .to_string(); + if base.is_empty() + || base.contains("..") + || !base.chars().all(|c| { + c.is_ascii_alphanumeric() || matches!(c, '.' | '_' | '-' | '+') + }) + || !base.to_ascii_lowercase().ends_with(".zip") + { + return Err(format!("Unsafe Java archive name: {name}")); + } + Ok(base) +} + +async fn download_capped( + http: &reqwest::Client, + url: &str, + max_bytes: u64, +) -> Result, String> { + use futures_util::StreamExt; + assert_azul_url(url)?; + let res = http + .get(url) + .send() + .await + .map_err(|e| format!("Download Java: {e}"))? + .error_for_status() + .map_err(|e| format!("Download Java HTTP: {e}"))?; + assert_azul_url(res.url().as_str())?; + if let Some(len) = res.content_length() { + if len > max_bytes { + return Err(format!("Java archive too large: {len} > {max_bytes}")); + } + } + let mut out = Vec::new(); + let mut stream = res.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Java download stream: {e}"))?; + if out.len() as u64 + chunk.len() as u64 > max_bytes { + return Err(format!("Java archive exceeded {max_bytes} bytes")); + } + out.extend_from_slice(&chunk); + } + Ok(out) +} + +fn extract_zip_safe(zip_path: &Path, dest: &Path) -> Result<(), String> { + use std::io::copy; + let dest_canon = fs::canonicalize(dest).unwrap_or_else(|_| dest.to_path_buf()); + let file = File::open(zip_path).map_err(|e| format!("Open Java zip: {e}"))?; + let mut archive = zip::ZipArchive::new(file).map_err(|e| format!("Java zip: {e}"))?; + for i in 0..archive.len() { + let mut entry = archive + .by_index(i) + .map_err(|e| format!("Java zip entry: {e}"))?; + let name = entry.name().replace('\\', "/"); + if name.is_empty() || name.starts_with('/') || name.contains('\0') { + continue; + } + let mut safe = PathBuf::new(); + for comp in Path::new(&name).components() { + match comp { + std::path::Component::Normal(part) => safe.push(part), + std::path::Component::CurDir => {} + _ => return Err(format!("Unsafe zip path component: {name}")), + } + } + if safe.as_os_str().is_empty() { + continue; + } + let out = dest.join(&safe); + // Ensure destination stays under dest_root (zip-slip). + let parent_for_check = if name.ends_with('/') { + out.clone() + } else { + out.parent().unwrap_or(dest).to_path_buf() + }; + fs::create_dir_all(&parent_for_check).map_err(|e| format!("Java zip parent: {e}"))?; + let check = if name.ends_with('/') { + fs::canonicalize(&out).unwrap_or(out.clone()) + } else { + fs::canonicalize(out.parent().unwrap_or(dest)).unwrap_or_else(|_| out.clone()) + }; + if !check.starts_with(&dest_canon) && !out.starts_with(dest) { + return Err(format!("Zip slip blocked: {name}")); + } + if name.ends_with('/') { + continue; + } + let mut outfile = File::create(&out).map_err(|e| format!("Java zip create: {e}"))?; + copy(&mut entry, &mut outfile).map_err(|e| format!("Java zip extract: {e}"))?; + } + Ok(()) +} + +fn find_java_binary(root: &Path) -> Option { + let bin_name = java_bin(); + let mut stack = vec![root.to_path_buf()]; + while let Some(dir) = stack.pop() { + let candidate = dir.join("bin").join(bin_name); + if candidate.is_file() { + return Some(candidate); + } + if let Ok(entries) = fs::read_dir(&dir) { + for entry in entries.flatten() { + let p = entry.path(); + if p.is_dir() { + stack.push(p); + } + } + } + } + None +} + +fn consider(path: &Path, found: &mut Vec, seen: &mut HashSet) { + if !path.is_file() { + return; + } + let key = path.to_string_lossy().to_ascii_lowercase(); + if !seen.insert(key) { + return; + } + if let Some(info) = probe(path) { + found.push(info); + } +} + +fn probe(path: &Path) -> Option { + let mut cmd = Command::new(path); + cmd.arg("-version") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .stdin(Stdio::null()); + #[cfg(windows)] + { + cmd.creation_flags(CREATE_NO_WINDOW); + } + let mut child = cmd.spawn().ok()?; + + let mut stdout_pipe = child.stdout.take()?; + let mut stderr_pipe = child.stderr.take()?; + let reader = std::thread::spawn(move || { + let mut stdout = String::new(); + let mut stderr = String::new(); + let _ = stdout_pipe.read_to_string(&mut stdout); + let _ = stderr_pipe.read_to_string(&mut stderr); + (stdout, stderr) + }); + + match child.wait_timeout(PROBE_TIMEOUT).ok()? { + Some(_) => {} + None => { + let _ = child.kill(); + let _ = child.wait(); + return None; + } + } + + let (stdout, stderr) = reader.join().ok()?; + let text = format!("{stderr}{stdout}"); + let version = parse_version(&text)?; + let major = major_version(&version)?; + Some(JavaInstallation { + path: path.display().to_string(), + version, + major_version: major, + is_64_bit: text.to_ascii_lowercase().contains("64-bit"), + }) +} + +fn parse_version(output: &str) -> Option { + for line in output.lines() { + if !line.contains("version") { + continue; + } + let start = line.find('"')?; + let end = line.rfind('"')?; + if end > start + 1 { + return Some(line[start + 1..end].to_string()); + } + } + None +} + +fn major_version(version: &str) -> Option { + let mut parts = version.split(['.', '_', '+', '-']); + let first = parts.next()?.parse::().ok()?; + if first == 1 { + parts.next()?.parse().ok() + } else { + Some(first) + } +} + +fn java_bin() -> &'static str { + // Windows: javaw.exe is a GUI subsystem binary (no console window). + // java.exe is console-subsystem and flashes a blank cmd when spawned. + if cfg!(windows) { + "javaw.exe" + } else { + "java" + } +} + +/// Prefer `javaw.exe` beside `java.exe` so game launch stays console-free on Windows. +pub fn for_launch(path: &Path) -> PathBuf { + #[cfg(windows)] + { + if let Some(name) = path.file_name().and_then(|n| n.to_str()) { + if name.eq_ignore_ascii_case("java.exe") { + let javaw = path.with_file_name("javaw.exe"); + if javaw.is_file() { + return javaw; + } + } + } + } + path.to_path_buf() +} + +fn common_roots() -> Vec { + let mut roots = Vec::new(); + if cfg!(windows) { + let program_files = std::env::var_os("ProgramFiles").map(PathBuf::from); + let program_files_x86 = std::env::var_os("ProgramFiles(x86)").map(PathBuf::from); + let local = std::env::var_os("LOCALAPPDATA").map(PathBuf::from); + for base in [program_files, program_files_x86].into_iter().flatten() { + for name in [ + "Java", + "Eclipse Adoptium", + "Eclipse Foundation", + "Microsoft", + "BellSoft", + "Amazon Corretto", + "Zulu", + "Semeru", + "SapMachine", + ] { + roots.push(base.join(name)); + } + } + if let Some(local) = local { + roots.push(local.join("Programs").join("Eclipse Adoptium")); + } + } else { + roots.push(PathBuf::from("/usr/lib/jvm")); + roots.push(PathBuf::from("/Library/Java/JavaVirtualMachines")); + } + roots +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/launch.rs b/legacy/Launcher/apps/launcher/src-tauri/src/launch.rs new file mode 100644 index 00000000000..e4354f2cffa --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/launch.rs @@ -0,0 +1,1163 @@ +use crate::config; +use crate::java::{self, JavaInstallation}; +use crate::log as owyx_log; +use crate::models::PackManifest; +use crate::sync; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs::{self, File}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::{LazyLock, Mutex}; +use tauri::{AppHandle, Emitter}; + +#[cfg(windows)] +use std::os::windows::process::CommandExt; + +#[cfg(windows)] +const CREATE_NO_WINDOW: u32 = 0x0800_0000; + +static RUNNING: LazyLock>>> = + LazyLock::new(|| Mutex::new(HashMap::new())); + +/// Last launch log path per pack (kept after exit so Live Log can still show it). +static LIVE_LOGS: LazyLock>> = + LazyLock::new(|| Mutex::new(HashMap::new())); + +fn apply_no_window(_cmd: &mut Command) { + #[cfg(windows)] + { + _cmd.creation_flags(CREATE_NO_WINDOW); + } +} + +pub fn live_log_path(pack_id: &str) -> Option { + LIVE_LOGS + .lock() + .ok() + .and_then(|g| g.get(pack_id).cloned()) +} + +fn set_live_log(pack_id: &str, path: PathBuf) { + if let Ok(mut guard) = LIVE_LOGS.lock() { + guard.insert(pack_id.to_string(), path); + } +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LaunchResult { + pub pack_id: String, + pub mode: String, + pub pid: u32, + pub java_path: String, + pub java_version: String, + pub log_path: String, + pub message: String, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ProcessFinishedEvent { + pub pack_id: String, + pub pid: u32, +} + +#[derive(Debug, Clone, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct LaunchOverrides { + pub memory_mb: Option, + pub width: Option, + pub height: Option, + pub jvm_args: Option>, + pub java_path: Option, + pub env_vars: Option>, + pub pre_launch: Option, + pub wrapper: Option, + pub post_exit: Option, + /// Join this server on launch (Theseus-style servers.dat + quickPlay). + pub server_address: Option, + pub server_port: Option, +} + +pub fn is_pack_running(pack_id: &str) -> bool { + let Ok(mut guard) = RUNNING.lock() else { + return false; + }; + match guard.get(pack_id) { + Some(None) => true, // reserved / launching + Some(Some(pid)) if process_alive(*pid) => true, + Some(Some(_)) => { + guard.remove(pack_id); + false + } + None => false, + } +} + +fn reserve_launch(pack_id: &str) -> Result<(), String> { + let mut guard = RUNNING + .lock() + .map_err(|_| "Process map lock poisoned".to_string())?; + match guard.get(pack_id) { + Some(None) => return Err("Instance is already launching".into()), + Some(Some(pid)) if process_alive(*pid) => { + return Err("Instance is already running. Stop it first.".into()); + } + Some(Some(_)) => { + guard.remove(pack_id); + } + None => {} + } + guard.insert(pack_id.to_string(), None); + Ok(()) +} + +fn commit_launch(pack_id: &str, pid: u32) { + if let Ok(mut guard) = RUNNING.lock() { + guard.insert(pack_id.to_string(), Some(pid)); + } +} + +fn abort_launch(pack_id: &str) { + if let Ok(mut guard) = RUNNING.lock() { + if matches!(guard.get(pack_id), Some(None)) { + guard.remove(pack_id); + } + } +} + +fn clear_running(pack_id: &str, expected_pid: Option) { + let Ok(mut guard) = RUNNING.lock() else { + return; + }; + match (guard.get(pack_id), expected_pid) { + // Exit watcher: only clear when the committed PID still matches. + (Some(Some(pid)), Some(expected)) if *pid == expected => { + guard.remove(pack_id); + } + // Explicit clear without a PID — never touch a fresh launching placeholder. + (Some(Some(_)), None) => { + guard.remove(pack_id); + } + // Some(None) is a reserve_launch placeholder for a newer Play — leave it. + _ => {} + } +} + +fn spawn_exit_watcher( + app: AppHandle, + pack_id: String, + pid: u32, + mut child: Child, + post_exit: Option<(String, PathBuf)>, +) { + std::thread::spawn(move || { + let _ = child.wait(); + clear_running(&pack_id, Some(pid)); + let _ = app.emit( + "process://finished", + ProcessFinishedEvent { + pack_id: pack_id.clone(), + pid, + }, + ); + if let Some((cmd, cwd)) = post_exit { + let _ = run_hook_command(&cmd, &cwd); + } + }); +} + +pub fn stop_pack(pack_id: &str) -> Result<(), String> { + validate_pack_id(pack_id)?; + let pid = { + let guard = RUNNING + .lock() + .map_err(|_| "Process map lock poisoned".to_string())?; + match guard.get(pack_id) { + Some(None) => return Err("Instance is still starting".into()), + Some(Some(pid)) => *pid, + None => return Err("No running process for this instance".into()), + } + }; + // Keep map entry until wait() clears it so UI stays consistent until exit. + kill_pid(pid)?; + Ok(()) +} + +fn process_alive(pid: u32) -> bool { + #[cfg(windows)] + { + // Prefer OpenProcess over shelling out to tasklist (faster + reliable). + // SAFETY: Win32 process query APIs with a valid PID and cleaned-up handle. + unsafe { + #[link(name = "kernel32")] + extern "system" { + fn OpenProcess(access: u32, inherit: i32, pid: u32) -> *mut core::ffi::c_void; + fn CloseHandle(handle: *mut core::ffi::c_void) -> i32; + fn GetExitCodeProcess(handle: *mut core::ffi::c_void, code: *mut u32) -> i32; + } + const PROCESS_QUERY_LIMITED_INFORMATION: u32 = 0x1000; + const STILL_ACTIVE: u32 = 259; + let handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, 0, pid); + if handle.is_null() { + return false; + } + let mut code = 0u32; + let ok = GetExitCodeProcess(handle, &mut code); + CloseHandle(handle); + ok != 0 && code == STILL_ACTIVE + } + } + #[cfg(not(windows))] + { + Path::new(&format!("/proc/{pid}")).exists() + } +} + +fn kill_pid(pid: u32) -> Result<(), String> { + #[cfg(windows)] + { + let mut cmd = Command::new("taskkill"); + cmd.args(["/PID", &pid.to_string(), "/T", "/F"]); + apply_no_window(&mut cmd); + let status = cmd + .status() + .map_err(|e| format!("taskkill failed: {e}"))?; + if !status.success() { + return Err(format!("Failed to stop process {pid}")); + } + Ok(()) + } + #[cfg(not(windows))] + { + let status = Command::new("kill") + .args(["-9", &pid.to_string()]) + .status() + .map_err(|e| format!("kill failed: {e}"))?; + if !status.success() { + return Err(format!("Failed to stop process {pid}")); + } + Ok(()) + } +} + +pub fn launch_pack( + app: AppHandle, + pack_id: &str, + nick: &str, + overrides: LaunchOverrides, +) -> Result { + validate_pack_id(pack_id)?; + let nick = nick.trim(); + if nick.is_empty() { + return Err("Nick is required to launch".into()); + } + if !is_safe_nick(nick) { + return Err("Nick may only contain letters, numbers, and _".into()); + } + + let status = sync::pack_status(pack_id)?; + if !status.ready { + return Err("Pack is not ready. Download/verify it before Play.".into()); + } + + let instance = config::ensure_layout()?.join("instances").join(pack_id); + let meta_path = instance.join("meta.json"); + let raw = fs::read_to_string(&meta_path).map_err(|e| format!("Read meta.json: {e}"))?; + let manifest: PackManifest = + serde_json::from_str(&raw).map_err(|e| format!("Invalid meta.json: {e}"))?; + + let min_major = manifest + .java + .as_ref() + .map(|j| j.min_major) + .unwrap_or(17); + let java = if let Some(path) = overrides + .java_path + .as_ref() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + { + let p = PathBuf::from(path); + java::probe_path(&p).ok_or_else(|| format!("Custom Java path is invalid: {path}"))? + } else { + java::find_compatible(min_major)? + }; + + let game_dir = instance.join("game"); + let jars = collect_manifest_jars(&game_dir, &manifest)?; + let natives_dir = resolve_natives_dir(&game_dir, &manifest.minecraft)?; + let assets_dir = resolve_assets_dir(&game_dir)?; + let (mut log_file, log_path) = { + let (path, file) = owyx_log::create_launch_log(pack_id)?; + (file, path) + }; + + owyx_log::write_line( + &mut log_file, + &format!( + "Owyx launch start pack={pack_id} nick={nick} java={} ({})", + java.path, java.version + ), + )?; + + if jars.is_empty() { + if pack_id.starts_with("demo-") { + return launch_smoke(pack_id, &java, log_path, log_file); + } + return Err( + "No .jar files in manifest. Sync a full Fabric client pack before Play.".into(), + ); + } + + let loader = manifest.loader.to_ascii_lowercase(); + if !matches!( + loader.as_str(), + "fabric" | "vanilla" | "quilt" | "forge" | "neoforge" + ) { + return Err(format!("Loader '{loader}' is not supported yet")); + } + + let main_class = sanitize_main_class( + manifest + .main_class + .as_deref() + .filter(|s| !s.trim().is_empty()) + .unwrap_or(match loader.as_str() { + "fabric" => "net.fabricmc.loader.impl.launch.knot.KnotClient", + "quilt" => "org.quiltmc.loader.impl.launch.knot.KnotClient", + "forge" | "neoforge" => "cpw.mods.bootstraplauncher.BootstrapLauncher", + _ => "net.minecraft.client.main.Main", + }), + )?; + + let is_modded = matches!(loader.as_str(), "forge" | "neoforge"); + + // Remote gameArgs ignored for Fabric/Quilt/Vanilla. Forge FML flags are allowlisted. + let mut jvm_args = sanitize_jvm_args(&manifest.jvm_args, &game_dir, is_modded)?; + #[cfg(target_os = "macos")] + { + if !jvm_args.iter().any(|a| a == "-XstartOnFirstThread") { + jvm_args.insert(0, "-XstartOnFirstThread".into()); + } + } + if let Some(extra) = overrides.jvm_args.as_ref() { + let sanitized_extra = sanitize_jvm_args(extra, &game_dir, false)?; + jvm_args.extend(sanitized_extra); + } + // UI memory wins over any -Xmx/-Xms from manifest or advanced JVM args. + apply_memory_override(&mut jvm_args, overrides.memory_mb); + + let mut extra_game_args = if is_modded { + sanitize_modded_game_args(&manifest.game_args)? + } else { + Vec::new() + }; + apply_window_override(&mut extra_game_args, overrides.width, overrides.height); + + let catalog_meta = crate::catalog::read_catalog_meta(pack_id); + let join_addr = overrides + .server_address + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .or_else(|| catalog_meta.as_ref().map(|m| m.address.clone())); + let join_port = overrides + .server_port + .or_else(|| catalog_meta.as_ref().map(|m| m.port)) + .unwrap_or(25565); + if let Some(addr) = join_addr.as_deref() { + crate::catalog::write_servers_dat(&game_dir, &manifest.id, addr, join_port)?; + if crate::catalog::supports_quick_play(&manifest.minecraft) { + if let Ok(safe) = crate::catalog::sanitize_server_addr(addr) { + extra_game_args.push("--quickPlayMultiplayer".into()); + extra_game_args.push(format!("{safe}:{join_port}")); + } + } else if let Ok(safe) = crate::catalog::sanitize_server_addr(addr) { + extra_game_args.push("--server".into()); + extra_game_args.push(safe); + extra_game_args.push("--port".into()); + extra_game_args.push(join_port.to_string()); + } + } + + let classpath = join_classpath(&jars); + let mut args: Vec = Vec::new(); + args.extend(jvm_args); + args.push(format!( + "-Djava.library.path={}", + natives_dir.display() + )); + args.push("-cp".into()); + args.push(classpath); + args.push(main_class.clone()); + + args.push("--username".into()); + args.push(nick.to_string()); + args.push("--version".into()); + args.push(sanitize_token(&manifest.minecraft, "minecraft version")?); + args.push("--gameDir".into()); + args.push(game_dir.display().to_string()); + args.push("--assetsDir".into()); + args.push(assets_dir.display().to_string()); + args.push("--assetIndex".into()); + args.push(sanitize_token( + manifest + .asset_index + .as_deref() + .unwrap_or(&manifest.minecraft), + "asset index", + )?); + args.push("--accessToken".into()); + args.push("0".into()); + args.push("--userType".into()); + args.push("legacy".into()); + args.extend(extra_game_args); + + owyx_log::write_line( + &mut log_file, + &format!("mode={loader} main={main_class} jars={}", jars.len()), + )?; + owyx_log::write_line( + &mut log_file, + &format!("cmd={} {}", java.path, args.join(" ")), + )?; + + drop(log_file); + let log_out = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + .map_err(|e| format!("Reopen launch log: {e}"))?; + let log_err = log_out + .try_clone() + .map_err(|e| format!("Clone launch log: {e}"))?; + + if let Some(pre) = overrides + .pre_launch + .as_ref() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + { + run_hook_command(pre, &game_dir)?; + } + + let (program, program_args) = if let Some(wrapper) = overrides + .wrapper + .as_ref() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + { + let mut parts = shell_split(wrapper); + if parts.is_empty() { + return Err("Wrapper command is empty".into()); + } + let prog = parts.remove(0); + let java_launch = java::for_launch(Path::new(&java.path)); + parts.push(java_launch.display().to_string()); + parts.extend(args); + (prog, parts) + } else { + ( + java::for_launch(Path::new(&java.path)) + .display() + .to_string(), + args, + ) + }; + + let mut cmd = Command::new(&program); + cmd.args(&program_args) + .current_dir(&game_dir) + .stdin(Stdio::null()) + .stdout(Stdio::from(log_out)) + .stderr(Stdio::from(log_err)); + apply_no_window(&mut cmd); + + if let Some(vars) = overrides.env_vars.as_ref() { + for (k, v) in vars { + let key = k.trim(); + if key.is_empty() || key.contains('=') || key.contains('\0') { + continue; + } + cmd.env(key, v); + } + } + + reserve_launch(pack_id)?; + let child = match cmd.spawn() { + Ok(child) => child, + Err(e) => { + abort_launch(pack_id); + return Err(format!("Failed to start Minecraft process: {e}")); + } + }; + let pid = child.id(); + commit_launch(pack_id, pid); + set_live_log(pack_id, log_path.clone()); + + let post_exit = overrides + .post_exit + .as_ref() + .map(|s| s.trim()) + .filter(|s| !s.is_empty()) + .map(|s| (s.to_string(), game_dir.clone())); + // Keep Child handle and wait on a background thread so RUNNING clears on exit + // (closing the game with window X must update Stop → Play without pressing Stop). + spawn_exit_watcher(app, pack_id.to_string(), pid, child, post_exit); + + Ok(LaunchResult { + pack_id: pack_id.to_string(), + mode: loader, + pid, + java_path: java.path, + java_version: java.version, + log_path: log_path.display().to_string(), + message: format!("Game started (pid {pid})"), + }) +} + +fn run_hook_command(command: &str, cwd: &Path) -> Result<(), String> { + let parts = shell_split(command); + if parts.is_empty() { + return Ok(()); + } + let mut cmd = Command::new(&parts[0]); + if parts.len() > 1 { + cmd.args(&parts[1..]); + } + cmd.current_dir(cwd) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .stderr(Stdio::null()); + apply_no_window(&mut cmd); + let status = cmd + .status() + .map_err(|e| format!("Hook command failed: {e}"))?; + if !status.success() { + return Err(format!("Hook command exited with {status}")); + } + Ok(()) +} + +fn shell_split(input: &str) -> Vec { + let mut out = Vec::new(); + let mut cur = String::new(); + let mut in_quotes = false; + for ch in input.chars() { + match ch { + '"' => in_quotes = !in_quotes, + c if c.is_whitespace() && !in_quotes => { + if !cur.is_empty() { + out.push(std::mem::take(&mut cur)); + } + } + c => cur.push(c), + } + } + if !cur.is_empty() { + out.push(cur); + } + out +} + +fn apply_memory_override(jvm_args: &mut Vec, memory_mb: Option) { + let Some(mb) = memory_mb else { + return; + }; + let mb = mb.clamp(512, 32768); + jvm_args.retain(|a| !(a.starts_with("-Xmx") || a.starts_with("-Xms"))); + jvm_args.insert(0, format!("-Xmx{mb}M")); +} + +fn apply_window_override(game_args: &mut Vec, width: Option, height: Option) { + let strip_pair = |args: &mut Vec, flag: &str| { + let mut i = 0; + while i < args.len() { + if args[i] == flag { + args.remove(i); + if i < args.len() { + args.remove(i); + } + } else { + i += 1; + } + } + }; + if let Some(w) = width.filter(|w| (640..=7680).contains(w)) { + strip_pair(game_args, "--width"); + game_args.push("--width".into()); + game_args.push(w.to_string()); + } + if let Some(h) = height.filter(|h| (480..=4320).contains(h)) { + strip_pair(game_args, "--height"); + game_args.push("--height".into()); + game_args.push(h.to_string()); + } +} + +fn launch_smoke( + pack_id: &str, + java: &JavaInstallation, + log_path: PathBuf, + mut log_file: File, +) -> Result { + owyx_log::write_line( + &mut log_file, + "mode=smoke reason=no-jars (demo pack) running java -version", + )?; + drop(log_file); + + let log_out = fs::OpenOptions::new() + .create(true) + .append(true) + .open(&log_path) + .map_err(|e| format!("Reopen launch log: {e}"))?; + let log_err = log_out + .try_clone() + .map_err(|e| format!("Clone launch log: {e}"))?; + + let mut cmd = Command::new(java::for_launch(Path::new(&java.path))); + cmd.arg("-version") + .stdin(Stdio::null()) + .stdout(Stdio::from(log_out)) + .stderr(Stdio::from(log_err)); + apply_no_window(&mut cmd); + let child = cmd + .spawn() + .map_err(|e| format!("Failed to start Java smoke process: {e}"))?; + let pid = child.id(); + set_live_log(pack_id, log_path.clone()); + + Ok(LaunchResult { + pack_id: pack_id.to_string(), + mode: "smoke".into(), + pid, + java_path: java.path.clone(), + java_version: java.version.clone(), + log_path: log_path.display().to_string(), + message: format!( + "Java OK (smoke). Full Fabric launch needs client jars in the pack. Log: {}", + log_path.display() + ), + }) +} + +fn sanitize_main_class(value: &str) -> Result { + let value = value.trim(); + if value.is_empty() || value.len() > 256 { + return Err("Invalid main class".into()); + } + if !value + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_' || c == '$') + { + return Err("Main class contains forbidden characters".into()); + } + if value.contains("..") { + return Err("Main class looks invalid".into()); + } + Ok(value.to_string()) +} + +fn sanitize_jvm_args( + args: &[String], + game_dir: &Path, + allow_modded: bool, +) -> Result, String> { + let mut out = Vec::with_capacity(args.len()); + let mut expect: Option = None; + for arg in args { + if let Some(kind) = expect.take() { + if !allow_modded { + return Err("Modded JVM flags are only allowed for Forge/NeoForge".into()); + } + out.push(sanitize_jvm_value(arg, kind, game_dir)?); + continue; + } + let trimmed = arg.trim(); + if trimmed.is_empty() { + return Err("Empty JVM argument".into()); + } + if allow_modded { + match trimmed { + "-p" | "--module-path" => { + out.push(trimmed.to_string()); + expect = Some(JvmValueKind::ModulePath); + continue; + } + "--add-modules" => { + out.push(trimmed.to_string()); + expect = Some(JvmValueKind::AddModules); + continue; + } + "--add-opens" => { + out.push(trimmed.to_string()); + expect = Some(JvmValueKind::AddOpensExports); + continue; + } + "--add-exports" => { + out.push(trimmed.to_string()); + expect = Some(JvmValueKind::AddOpensExports); + continue; + } + _ => {} + } + } + out.push(sanitize_jvm_arg(trimmed, game_dir, allow_modded)?); + } + if expect.is_some() { + return Err("Incomplete JVM argument (missing value)".into()); + } + Ok(out) +} + +#[derive(Clone, Copy)] +enum JvmValueKind { + ModulePath, + AddModules, + AddOpensExports, +} + +fn sanitize_jvm_arg(arg: &str, game_dir: &Path, allow_modded: bool) -> Result { + let arg = arg.trim(); + if arg.is_empty() || arg.len() > 8192 { + return Err("Invalid JVM argument length".into()); + } + if arg.chars().any(|c| c.is_control() || c == '\0') { + return Err("JVM argument contains forbidden characters".into()); + } + if is_dangerous_jvm_arg(arg) { + return Err(format!("JVM argument not allowed: {arg}")); + } + + let memory = regex_is_memory_flag(arg); + let xx_safe = matches!( + arg, + "-XX:+UseG1GC" + | "-XX:+UseZGC" + | "-XX:+UseShenandoahGC" + | "-XX:+UnlockExperimentalVMOptions" + | "-XX:+DisableExplicitGC" + | "-XX:HeapDumpPath=MojangTricksIntelDriversForPerformance_javaw.exe_minecraft.exe.heapdump" + ); + let mac_first = arg == "-XstartOnFirstThread"; + if memory || xx_safe || mac_first { + return Ok(arg.to_string()); + } + if allow_modded { + if let Some(sanitized) = sanitize_allowed_d_prop(arg, game_dir)? { + return Ok(sanitized); + } + } + Err(format!("JVM argument not in allowlist: {arg}")) +} + +fn sanitize_jvm_value(arg: &str, kind: JvmValueKind, game_dir: &Path) -> Result { + let arg = arg.trim(); + if arg.is_empty() || arg.len() > 8192 { + return Err("Invalid JVM argument value length".into()); + } + if arg.chars().any(|c| c.is_control() || c == '\0' || c == '\n' || c == '\r') { + return Err("JVM argument value contains forbidden characters".into()); + } + if is_dangerous_jvm_arg(arg) { + return Err(format!("JVM argument value not allowed: {arg}")); + } + match kind { + JvmValueKind::ModulePath => sanitize_module_path(arg, game_dir), + JvmValueKind::AddModules => { + if arg != "ALL-MODULE-PATH" + && !arg + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == ',' || c == '_' || c == '-') + { + return Err("Invalid --add-modules value".into()); + } + Ok(arg.to_string()) + } + JvmValueKind::AddOpensExports => { + if !arg.contains('/') || !arg.contains('=') { + return Err("Invalid --add-opens/--add-exports value".into()); + } + if !arg + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '/' | '=' | ',' | '-' | '_')) + { + return Err("Invalid --add-opens/--add-exports characters".into()); + } + Ok(arg.to_string()) + } + } +} + +fn sanitize_module_path(raw: &str, game_dir: &Path) -> Result { + let libraries = canonicalize_dir(&config::meta_libraries_dir()?)?; + let legacy_libraries = canonicalize_dir(&game_dir.join("libraries"))?; + let sep = if cfg!(windows) { ';' } else { ':' }; + // On Windows paths also contain `:`, so split carefully: prefer `;` on Windows. + let parts: Vec<&str> = if cfg!(windows) { + raw.split(';').filter(|p| !p.is_empty()).collect() + } else { + raw.split(sep).filter(|p| !p.is_empty()).collect() + }; + if parts.is_empty() { + return Err("Empty module path".into()); + } + let mut cleaned = Vec::with_capacity(parts.len()); + for part in parts { + let path = Path::new(part); + if !path + .extension() + .and_then(|e| e.to_str()) + .map(|e| e.eq_ignore_ascii_case("jar")) + .unwrap_or(false) + { + return Err(format!("Module path entry is not a jar: {part}")); + } + let canon = path + .canonicalize() + .map_err(|e| format!("Module path resolve failed ({part}): {e}"))?; + if !(path_under_root(&canon, &libraries) || path_under_root(&canon, &legacy_libraries)) { + return Err(format!( + "Module path jar outside meta/libraries or game/libraries: {}", + canon.display() + )); + } + cleaned.push(canon.display().to_string()); + } + Ok(cleaned.join(&sep.to_string())) +} + +fn canonicalize_dir(path: &Path) -> Result { + if !path.exists() { + fs::create_dir_all(path).map_err(|e| format!("Create {}: {e}", path.display()))?; + } + path.canonicalize() + .map_err(|e| format!("Canonicalize {}: {e}", path.display())) +} + +fn path_under_root(path: &Path, root: &Path) -> bool { + path.starts_with(root) +} + +fn is_dangerous_jvm_arg(arg: &str) -> bool { + let lower = arg.to_ascii_lowercase(); + lower.starts_with("-javaagent") + || lower.starts_with("-agentpath") + || lower.starts_with("-agentlib") + || lower.starts_with("-xbootclasspath") + || lower.contains("onerror") + || lower.contains("onoutofmemoryerror") + || lower.contains("java.security.manager") + || lower.contains("${") +} + +fn sanitize_allowed_d_prop(arg: &str, game_dir: &Path) -> Result, String> { + let Some(rest) = arg.strip_prefix("-D") else { + return Ok(None); + }; + let Some((key, value)) = rest.split_once('=') else { + return Ok(None); + }; + let path_keys = matches!( + key, + "libraryDirectory" + | "jna.tmpdir" + | "org.lwjgl.system.SharedLibraryExtractPath" + | "io.netty.native.workdir" + ); + let key_ok = path_keys + || matches!( + key, + "ignoreList" + | "mergeModules" + | "java.net.preferIPv6Addresses" + | "minecraft.launcher.brand" + | "minecraft.launcher.version" + ) + || key.starts_with("forge.") + || key.starts_with("fml.") + || key.starts_with("neoforge."); + if !key_ok { + return Ok(None); + } + if value.len() > 4096 { + return Err(format!("JVM -D{key} value too long")); + } + if value.chars().any(|c| c.is_control() || c == '\0') { + return Err(format!("JVM -D{key} has forbidden characters")); + } + + if path_keys { + let libraries = canonicalize_dir(&config::meta_libraries_dir()?)?; + let legacy_libraries = canonicalize_dir(&game_dir.join("libraries"))?; + let natives_meta = canonicalize_dir(&config::meta_dir()?.join("natives"))?; + let natives_legacy = canonicalize_dir(&game_dir.join("natives"))?; + let path = Path::new(value); + let canon = path + .canonicalize() + .map_err(|e| format!("JVM -D{key} resolve failed: {e}"))?; + let ok = match key { + "libraryDirectory" => { + path_under_root(&canon, &libraries) + || canon == libraries + || path_under_root(&canon, &legacy_libraries) + || canon == legacy_libraries + } + _ => { + path_under_root(&canon, &natives_meta) + || path_under_root(&canon, &natives_legacy) + || canon == natives_meta + || canon == natives_legacy + } + }; + if !ok { + return Err(format!( + "JVM -D{key} must stay under meta/libraries|natives or game/libraries|natives" + )); + } + return Ok(Some(format!("-D{key}={}", canon.display()))); + } + + // Non-path forge/Mojang props: tight token charset (no paths). + if !value + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '.' | '-' | '_' | ',' | '=' | '/' | ':')) + { + return Err(format!("JVM -D{key} value has forbidden characters")); + } + Ok(Some(arg.to_string())) +} + +fn sanitize_modded_game_args(args: &[String]) -> Result, String> { + const FLAGS: &[&str] = &[ + "--launchTarget", + "--fml.forgeVersion", + "--fml.mcVersion", + "--fml.forgeGroup", + "--fml.mcpVersion", + "--fml.neoForgeVersion", + "--fml.fmlVersion", + "--fml.neoFormVersion", + ]; + if args.is_empty() { + return Ok(Vec::new()); + } + let mut out = Vec::with_capacity(args.len()); + let mut i = 0; + while i < args.len() { + let flag = args[i].trim(); + if !FLAGS.contains(&flag) { + return Err(format!("Game argument not in allowlist: {flag}")); + } + let Some(value) = args.get(i + 1).map(|s| s.trim()) else { + return Err(format!("Missing value for {flag}")); + }; + if value.is_empty() || value.len() > 128 { + return Err(format!("Invalid value for {flag}")); + } + if !value + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_' || c == '-') + { + return Err(format!("Invalid characters in {flag} value")); + } + out.push(flag.to_string()); + out.push(value.to_string()); + i += 2; + } + Ok(out) +} + +fn regex_is_memory_flag(arg: &str) -> bool { + // -Xmx2G / -Xms512M / -Xss1M + let bytes = arg.as_bytes(); + if bytes.len() < 5 || !arg.starts_with("-X") { + return false; + } + let kind = &arg[2..4]; + if kind != "mx" && kind != "ms" && kind != "ss" { + return false; + } + let rest = &arg[4..]; + let (num, unit) = rest.split_at(rest.len().saturating_sub(1)); + if num.is_empty() || !num.chars().all(|c| c.is_ascii_digit()) { + return false; + } + matches!(unit, "k" | "K" | "m" | "M" | "g" | "G") +} + +fn resolve_natives_dir(game_dir: &Path, minecraft: &str) -> Result { + let shared = config::meta_natives_dir(minecraft)?; + let legacy = game_dir.join("natives"); + // Prefer shared meta when it has content; else legacy game/natives for older installs. + let shared_has = shared + .read_dir() + .map(|mut it| it.next().is_some()) + .unwrap_or(false); + if shared_has { + Ok(shared) + } else if legacy.is_dir() { + Ok(legacy) + } else { + Ok(shared) + } +} + +fn resolve_assets_dir(game_dir: &Path) -> Result { + let shared = config::meta_assets_dir()?; + let legacy = game_dir.join("assets"); + let shared_objects = shared.join("objects"); + let shared_has = shared_objects + .read_dir() + .map(|mut it| it.next().is_some()) + .unwrap_or(false); + if shared_has { + Ok(shared) + } else if legacy.is_dir() { + Ok(legacy) + } else { + Ok(shared) + } +} + +fn collect_manifest_jars( + game_dir: &Path, + manifest: &PackManifest, +) -> Result, String> { + let mut jars = Vec::new(); + for file in &manifest.files { + if !file + .path + .to_ascii_lowercase() + .ends_with(".jar") + { + continue; + } + let path = resolve_manifest_file(game_dir, &file.path)?; + if !path.is_file() { + return Err(format!("Missing jar from manifest: {}", file.path)); + } + // Theseus trusts install-time checks; re-hashing every jar on Play freezes launch. + // Prefer size match when known; accept sha1:/reuse markers without full-file SHA256. + if !jar_integrity_ok(&path, &file.sha256, file.size)? { + return Err(format!("Jar integrity check failed: {}", file.path)); + } + jars.push(path); + } + jars.sort(); + Ok(jars) +} + +fn resolve_manifest_file(game_dir: &Path, rel: &str) -> Result { + let preferred = config::resolve_game_or_meta(rel, game_dir)?; + if preferred.is_file() { + return Ok(preferred); + } + // Legacy installs put client.jar under libraries/com/mojang/minecraft/. + let legacy_client = "libraries/com/mojang/minecraft/client.jar"; + if rel.replace('\\', "/").starts_with("versions/") && rel.ends_with(".jar") { + let old = config::resolve_game_or_meta(legacy_client, game_dir)?; + if old.is_file() { + return Ok(old); + } + let old_game = game_dir.join(safe_rel_path(legacy_client)?); + if old_game.is_file() { + return Ok(old_game); + } + } + // Legacy installs kept libraries/assets/versions under game/. + let legacy = game_dir.join(safe_rel_path(rel)?); + if legacy.is_file() { + return Ok(legacy); + } + Ok(preferred) +} + +fn jar_integrity_ok(path: &Path, expected_hash: &str, expected_size: Option) -> Result { + let meta = fs::metadata(path).map_err(|e| format!("Stat jar: {e}"))?; + if let Some(sz) = expected_size { + if meta.len() != sz { + return Ok(false); + } + } + let hash = expected_hash.trim(); + if hash.is_empty() || hash == "reuse" || hash.starts_with("sha1:") { + return Ok(true); + } + // Older manifests stored full SHA256 — verify only then. + file_sha256_matches(path, hash) +} + +fn safe_rel_path(raw: &str) -> Result { + use std::path::{Component, Path}; + let path = Path::new(raw); + if path.is_absolute() { + return Err(format!("Absolute paths are not allowed: {raw}")); + } + let mut out = PathBuf::new(); + for comp in path.components() { + match comp { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe path component in {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err("Empty file path".into()); + } + Ok(out) +} + +fn file_sha256_matches(path: &Path, expected: &str) -> Result { + use sha2::{Digest, Sha256}; + let mut file = fs::File::open(path).map_err(|e| format!("Read jar: {e}"))?; + let mut hasher = Sha256::new(); + let mut buf = [0u8; 64 * 1024]; + loop { + let n = std::io::Read::read(&mut file, &mut buf).map_err(|e| format!("Read jar: {e}"))?; + if n == 0 { + break; + } + hasher.update(&buf[..n]); + } + let actual: String = hasher.finalize().iter().map(|b| format!("{b:02x}")).collect(); + Ok(actual.eq_ignore_ascii_case(expected)) +} + +fn sanitize_token(value: &str, label: &str) -> Result { + let value = value.trim(); + if value.is_empty() || value.len() > 64 { + return Err(format!("Invalid {label}")); + } + if !value + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '.' || c == '_' || c == '-') + { + return Err(format!("Invalid {label} characters")); + } + Ok(value.to_string()) +} + +fn is_safe_nick(nick: &str) -> bool { + !nick.is_empty() + && nick.len() <= 16 + && nick + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_') +} + +fn join_classpath(jars: &[PathBuf]) -> String { + let sep = if cfg!(windows) { ';' } else { ':' }; + jars.iter() + .map(|p| p.display().to_string()) + .collect::>() + .join(&sep.to_string()) +} + +fn validate_pack_id(pack_id: &str) -> Result<(), String> { + crate::instances::validate_instance_id(pack_id).map_err(|_| "Invalid pack id".into()) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/lib.rs b/legacy/Launcher/apps/launcher/src-tauri/src/lib.rs new file mode 100644 index 00000000000..78f17549f46 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/lib.rs @@ -0,0 +1,688 @@ +mod api; +mod catalog; +mod config; +mod install; +mod instances; +mod java; +mod launch; +mod log; +mod models; +mod modrinth; +mod mrpack; +mod ms_auth; +mod owyx; +mod profiles; +mod skins; +mod sync; +mod versions; + +use config::LauncherConfig; +use install::{InstanceRecord, PrefetchStatus}; +use instances::{ContentInfo, DirEntryInfo, DiskInstance, InstanceLogInfo, LogFileInfo, WorldInfo}; +use java::JavaInstallation; +use launch::{LaunchOverrides, LaunchResult}; +use models::{PackLocalStatus, PackSummary}; +use modrinth::ModrinthSearchResult; +use profiles::{Profile, ProfilesState}; +use tauri::AppHandle; +use versions::{LoaderKind, MinecraftVersion}; + +#[tauri::command] +fn greet(name: &str) -> String { + format!("Owyx backend online · hello, {name}") +} + +#[tauri::command] +fn get_config() -> Result { + config::load() +} + +#[tauri::command] +fn get_data_dir() -> Result { + config::app_data_dir().map(|p| p.display().to_string()) +} + +#[tauri::command] +fn set_nick(nick: String) -> Result { + config::set_nick(nick) +} + +#[tauri::command] +fn set_locale(locale: String) -> Result { + config::set_locale(locale) +} + +#[tauri::command] +fn get_profiles() -> Result { + profiles::load_state() +} + +#[tauri::command] +fn save_profiles( + profiles: Vec, + active_profile_id: Option, +) -> Result { + profiles::save_state(profiles, active_profile_id) +} + +#[tauri::command] +fn check_updates() -> Result { + // Stub: record check time; real EXE updater comes later. + config::set_updater_checked(None) +} + +#[tauri::command] +async fn list_packs() -> Result, String> { + let cfg = config::load()?; + sync::list_packs(cfg.update_base_url).await +} + +#[tauri::command] +fn get_pack_status(pack_id: String) -> Result { + sync::pack_status(&pack_id) +} + +#[tauri::command] +async fn sync_pack(app: AppHandle, pack_id: String) -> Result { + let cfg = config::load()?; + sync::sync_pack(app, pack_id, cfg.update_base_url).await +} + +#[tauri::command] +fn list_java() -> Result, String> { + let cfg = config::load()?; + Ok(cfg + .java_installations + .into_iter() + .filter(|j| std::path::Path::new(&j.path).is_file()) + .collect()) +} + +#[tauri::command] +async fn detect_java() -> Result, String> { + let found = tauri::async_runtime::spawn_blocking(java::find_all) + .await + .map_err(|e| format!("Java detect task failed: {e}"))?; + config::set_java_installations(found.clone())?; + Ok(found) +} + +#[tauri::command] +async fn find_java_for_major(major: u32) -> Result, String> { + tauri::async_runtime::spawn_blocking(move || java::find_for_major(major)) + .await + .map_err(|e| format!("Java filter task failed: {e}")) +} + +#[tauri::command] +fn set_java_version(major: u32, path: Option) -> Result { + config::set_java_version_path(major, path) +} + +#[tauri::command] +async fn install_java(major: u32) -> Result { + java::auto_install(major).await +} + +#[tauri::command] +fn meta_prefetch_status() -> PrefetchStatus { + install::meta_prefetch_status() +} + +#[tauri::command] +async fn prefetch_shared_meta(app: AppHandle) -> Result { + install::prefetch_shared_meta(app).await +} + +#[tauri::command] +fn update_instance_installation( + id: String, + loader: String, + minecraft: String, + loader_version: String, +) -> Result { + install::update_instance_installation(&id, &loader, &minecraft, &loader_version) +} + +#[tauri::command] +async fn repair_instance(app: AppHandle, id: String) -> Result { + install::repair_instance(app, id).await +} + +#[tauri::command] +fn system_memory_mb() -> u32 { + // Approximate physical RAM for the memory slider max. Fallback 16G. + #[cfg(windows)] + { + // SAFETY: GlobalMemoryStatusEx is a well-defined Win32 call with a sized buffer. + unsafe { + #[repr(C)] + struct MemoryStatusEx { + dw_length: u32, + dw_memory_load: u32, + ull_total_phys: u64, + ull_avail_phys: u64, + ull_total_page_file: u64, + ull_avail_page_file: u64, + ull_total_virtual: u64, + ull_avail_virtual: u64, + ull_avail_extended_virtual: u64, + } + #[link(name = "kernel32")] + extern "system" { + fn GlobalMemoryStatusEx(lp_buffer: *mut MemoryStatusEx) -> i32; + } + let mut status = std::mem::zeroed::(); + status.dw_length = std::mem::size_of::() as u32; + if GlobalMemoryStatusEx(&mut status) != 0 { + let total = status.ull_total_phys / (1024 * 1024); + return total.clamp(2048, 262144) as u32; + } + } + } + 16384 +} + +#[tauri::command] +fn launch_pack( + app: AppHandle, + pack_id: String, + overrides: Option, +) -> Result { + let nick = profiles::active_nick()?; + launch::launch_pack(app, &pack_id, &nick, overrides.unwrap_or_default()) +} + +#[tauri::command] +fn stop_pack(pack_id: String) -> Result<(), String> { + launch::stop_pack(&pack_id) +} + +#[tauri::command] +fn is_pack_running(pack_id: String) -> bool { + launch::is_pack_running(&pack_id) +} + +#[tauri::command] +fn list_loaders() -> Vec { + versions::list_loaders() +} + +#[tauri::command] +async fn list_minecraft_versions( + loader: String, + include_snapshots: bool, +) -> Result, String> { + versions::list_minecraft_versions(&loader, include_snapshots).await +} + +#[tauri::command] +async fn list_loader_versions(loader: String, minecraft: String) -> Result, String> { + versions::list_loader_versions(&loader, &minecraft).await +} + +#[tauri::command] +async fn install_instance( + app: AppHandle, + id: String, + name: String, + loader: String, + minecraft: String, + loader_version: String, +) -> Result { + install::install_instance(app, id, name, loader, minecraft, loader_version).await +} + +#[tauri::command] +fn prepare_instance( + name: String, + loader: String, + minecraft: String, + loader_version: String, + icon_path: Option, +) -> Result { + instances::prepare_instance( + &name, + &loader, + &minecraft, + &loader_version, + icon_path.as_deref(), + ) +} + +#[tauri::command] +fn set_instance_icon(id: String, path: Option) -> Result<(), String> { + instances::set_instance_icon(&id, path.as_deref()) +} + +#[tauri::command] +fn get_instance_icon(id: String) -> Result, String> { + instances::instance_icon_data_url(&id) +} + +#[tauri::command] +fn read_image_data_url(path: String) -> Result { + instances::image_as_data_url(std::path::Path::new(&path)) +} + +#[tauri::command] +fn list_instances() -> Result, String> { + instances::list_instances() +} + +#[tauri::command] +fn delete_instance(id: String) -> Result<(), String> { + instances::delete_instance(&id) +} + +#[tauri::command] +fn open_instance_dir(app: AppHandle, id: String, which: String) -> Result<(), String> { + instances::open_instance_dir(app, &id, &which) +} + +#[tauri::command] +async fn modrinth_search( + query: String, + limit: Option, + offset: Option, + loader: Option, + game_version: Option, + category: Option, + project_type: Option, + index: Option, +) -> Result { + modrinth::search_projects( + query, + limit, + offset, + loader, + game_version, + category, + project_type, + index, + ) + .await +} + +#[tauri::command] +async fn modrinth_project_versions( + project_id: String, + loader: Option, + game_version: Option, +) -> Result, String> { + modrinth::list_project_versions(project_id, loader, game_version).await +} + +#[tauri::command] +async fn modrinth_get_project(project_id: String) -> Result { + modrinth::get_project(project_id).await +} + +#[tauri::command] +async fn modrinth_install( + instance_id: String, + project_id: String, + loader: String, + game_version: String, + include_optional_dependencies: Option, +) -> Result { + modrinth::install_to_instance( + instance_id, + project_id, + loader, + game_version, + include_optional_dependencies.unwrap_or(false), + ) + .await +} + +#[tauri::command] +async fn list_instance_dir( + id: String, + relative: Option, +) -> Result, String> { + let rel = relative.unwrap_or_default(); + tauri::async_runtime::spawn_blocking(move || instances::list_instance_dir(&id, &rel)) + .await + .map_err(|e| format!("list_instance_dir join: {e}"))? +} + +#[tauri::command] +async fn list_instance_logs(pack_id: String) -> Result, String> { + tauri::async_runtime::spawn_blocking(move || instances::list_instance_logs(&pack_id)) + .await + .map_err(|e| format!("list_instance_logs join: {e}"))? +} + +#[tauri::command] +async fn read_instance_log( + pack_id: String, + source: String, + filename: String, + max_bytes: Option, +) -> Result { + tauri::async_runtime::spawn_blocking(move || { + instances::read_instance_log(&pack_id, &source, &filename, max_bytes) + }) + .await + .map_err(|e| format!("read_instance_log join: {e}"))? +} + +#[tauri::command] +async fn list_launch_logs(pack_id: Option) -> Result, String> { + tauri::async_runtime::spawn_blocking(move || instances::list_launch_logs(pack_id)) + .await + .map_err(|e| format!("list_launch_logs join: {e}"))? +} + +#[tauri::command] +async fn read_launch_log(name: String, max_bytes: Option) -> Result { + tauri::async_runtime::spawn_blocking(move || instances::read_launch_log(&name, max_bytes)) + .await + .map_err(|e| format!("read_launch_log join: {e}"))? +} + +#[tauri::command] +fn list_worlds(id: String) -> Result, String> { + instances::list_worlds(&id) +} + +#[tauri::command] +fn delete_world(id: String, world_id: String) -> Result<(), String> { + instances::delete_world(&id, &world_id) +} + +#[tauri::command] +fn list_content(id: String) -> Result, String> { + instances::list_content(&id) +} + +#[tauri::command] +fn set_content_enabled( + id: String, + kind: String, + file_name: String, + enabled: bool, +) -> Result<(), String> { + instances::set_content_enabled(&id, &kind, &file_name, enabled) +} + +#[tauri::command] +fn delete_content(id: String, kind: String, file_name: String) -> Result<(), String> { + instances::delete_content(&id, &kind, &file_name) +} + +#[tauri::command] +fn add_content_from_path( + id: String, + path: String, + kind: Option, +) -> Result { + instances::add_content_from_path(&id, &path, kind.as_deref()) +} + +#[tauri::command] +fn duplicate_instance( + id: String, + new_id: String, + new_name: String, +) -> Result { + instances::duplicate_instance(&id, &new_id, &new_name) +} + +#[tauri::command] +async fn ms_auth_start() -> Result { + ms_auth::start().await +} + +#[tauri::command] +async fn ms_auth_poll() -> Result { + ms_auth::poll().await +} + +#[tauri::command] +fn ms_auth_cancel() -> Result<(), String> { + ms_auth::cancel() +} + +#[tauri::command] +fn list_skins() -> Result, String> { + skins::list_skins() +} + +#[tauri::command] +fn import_skin(path: String, name: Option) -> Result { + skins::import_skin(path, name) +} + +#[tauri::command] +fn apply_local_skin( + skin_id: String, + instance_id: Option, +) -> Result { + skins::apply_skin(skin_id, instance_id) +} + +#[tauri::command] +fn remove_skin(skin_id: String) -> Result<(), String> { + skins::remove_skin(skin_id) +} + +#[tauri::command] +async fn import_mrpack(path: String) -> Result { + mrpack::import_mrpack_file(path).await +} + +#[tauri::command] +async fn import_mrpack_modrinth( + project_id: String, + version_id: Option, +) -> Result { + mrpack::import_mrpack_from_modrinth(project_id, version_id).await +} + +#[tauri::command] +fn export_mrpack(instance_id: String, dest_path: String) -> Result { + mrpack::export_mrpack(instance_id, dest_path) +} + +#[tauri::command] +async fn owyx_login( + base_url: Option, + email: String, + password: String, +) -> Result { + owyx::login(base_url.as_deref(), &email, &password).await +} + +#[tauri::command] +async fn owyx_me(nickname: String) -> Result { + owyx::me(&nickname).await +} + +#[tauri::command] +fn owyx_logout(nickname: String) -> Result<(), String> { + owyx::logout(&nickname) +} + +#[tauri::command] +async fn catalog_list() -> Result { + catalog::list_catalog(None).await +} + +#[tauri::command] +async fn install_catalog_server( + app: AppHandle, + server_id: String, + name: String, + address: String, + port: u16, + pack_id: Option, + minecraft: String, + loader: String, + download_url: Option, + sha256: Option, + manifest_url: Option, + source_type: String, +) -> Result { + catalog::install_catalog_server( + app, + server_id, + name, + address, + port, + pack_id, + minecraft, + loader, + download_url, + sha256, + manifest_url, + source_type, + ) + .await +} + +#[tauri::command] +async fn owyx_admin_request( + nickname: String, + method: String, + path: String, + body: Option, +) -> Result { + owyx::admin_request(&nickname, &method, &path, body).await +} + +#[tauri::command] +async fn apply_owyx_skin( + nickname: String, + instance_id: Option, +) -> Result { + owyx::apply_skin(&nickname, instance_id).await +} + +#[tauri::command] +async fn modrinth_install_version( + instance_id: String, + version_id: String, + with_dependencies: Option, + include_optional_dependencies: Option, +) -> Result { + modrinth::install_version_to_instance( + instance_id, + version_id, + with_dependencies.unwrap_or(true), + include_optional_dependencies.unwrap_or(false), + ) + .await +} + +fn fit_main_window(app: &tauri::App) { + use tauri::{LogicalSize, Manager, Size}; + + let Some(win) = app.get_webview_window("main") else { + return; + }; + let (w, h) = match win.current_monitor().ok().flatten() { + Some(monitor) => { + let size = monitor.size(); + let scale = monitor.scale_factor(); + let avail_w = size.width as f64 / scale; + let avail_h = size.height as f64 / scale; + let target_w = 1440_f64.min(avail_w * 0.92).max(1024.0); + let target_h = 900_f64.min(avail_h * 0.88).max(640.0); + (target_w, target_h) + } + None => (1440.0, 900.0), + }; + let _ = win.set_size(Size::Logical(LogicalSize::new(w, h))); + let _ = win.center(); +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_opener::init()) + .plugin(tauri_plugin_dialog::init()) + .setup(|app| { + fit_main_window(app); + if let Err(e) = log::init_launcher_logging() { + eprintln!("Failed to init launcher log: {e}"); + } + // Prefetch is started once from the splash UI (`prefetch_shared_meta`). + // Do not also spawn it here — dual callers fight INSTALL_LOCK and break Play. + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + greet, + get_config, + get_data_dir, + set_nick, + set_locale, + get_profiles, + save_profiles, + check_updates, + list_packs, + get_pack_status, + sync_pack, + list_java, + detect_java, + find_java_for_major, + set_java_version, + install_java, + meta_prefetch_status, + prefetch_shared_meta, + update_instance_installation, + repair_instance, + system_memory_mb, + launch_pack, + stop_pack, + is_pack_running, + list_loaders, + list_minecraft_versions, + list_loader_versions, + install_instance, + prepare_instance, + set_instance_icon, + get_instance_icon, + read_image_data_url, + list_instances, + delete_instance, + open_instance_dir, + modrinth_search, + modrinth_project_versions, + modrinth_get_project, + modrinth_install, + list_instance_dir, + list_instance_logs, + read_instance_log, + list_launch_logs, + read_launch_log, + list_worlds, + delete_world, + list_content, + set_content_enabled, + delete_content, + add_content_from_path, + duplicate_instance, + owyx_login, + owyx_me, + owyx_logout, + catalog_list, + install_catalog_server, + owyx_admin_request, + apply_owyx_skin, + modrinth_install_version, + ms_auth_start, + ms_auth_poll, + ms_auth_cancel, + list_skins, + import_skin, + apply_local_skin, + remove_skin, + import_mrpack, + import_mrpack_modrinth, + export_mrpack + ]) + .run(tauri::generate_context!()) + .expect("error while running Owyx"); +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/log.rs b/legacy/Launcher/apps/launcher/src-tauri/src/log.rs new file mode 100644 index 00000000000..ea1777864cf --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/log.rs @@ -0,0 +1,152 @@ +use crate::config; +use std::fs::{self, File, OpenOptions}; +use std::io::Write; +use std::path::{Path, PathBuf}; +use std::sync::{LazyLock, Mutex}; +use std::time::{SystemTime, UNIX_EPOCH}; +use zip::write::SimpleFileOptions; +use zip::ZipWriter; + +static LAUNCHER_LOG: LazyLock>> = LazyLock::new(|| Mutex::new(None)); + +pub fn logs_dir() -> Result { + let dir = config::ensure_layout()?.join("logs"); + fs::create_dir_all(&dir).map_err(|e| format!("Create logs dir: {e}"))?; + Ok(dir) +} + +fn current_log_path() -> Result { + Ok(logs_dir()?.join("owyx.log")) +} + +/// Archive previous `owyx.log` into a zip, keep last 10 archives, open a fresh log. +pub fn init_launcher_logging() -> Result { + let dir = logs_dir()?; + let current = current_log_path()?; + if current.is_file() { + archive_previous_log(&dir, ¤t)?; + } + prune_archives(&dir, 10)?; + + let file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(¤t) + .map_err(|e| format!("Open launcher log: {e}"))?; + + { + let mut guard = LAUNCHER_LOG + .lock() + .map_err(|_| "Launcher log lock poisoned".to_string())?; + *guard = Some(file); + } + + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + info(&format!("=== Owyx launcher start ts={stamp} ===")); + Ok(current) +} + +fn archive_previous_log(dir: &Path, current: &Path) -> Result<(), String> { + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let archive_path = dir.join(format!("owyx-{stamp}.zip")); + let archive_file = + File::create(&archive_path).map_err(|e| format!("Create log archive: {e}"))?; + let mut zip = ZipWriter::new(archive_file); + let opts = SimpleFileOptions::default().compression_method(zip::CompressionMethod::Deflated); + zip.start_file("owyx.log", opts) + .map_err(|e| format!("Zip start: {e}"))?; + let bytes = fs::read(current).map_err(|e| format!("Read previous log: {e}"))?; + zip.write_all(&bytes) + .map_err(|e| format!("Zip write: {e}"))?; + zip.finish().map_err(|e| format!("Zip finish: {e}"))?; + let _ = fs::remove_file(current); + Ok(()) +} + +fn prune_archives(dir: &Path, keep: usize) -> Result<(), String> { + let mut archives: Vec<(u64, PathBuf)> = fs::read_dir(dir) + .map_err(|e| format!("Read logs dir: {e}"))? + .flatten() + .filter_map(|entry| { + let path = entry.path(); + let name = path.file_name()?.to_str()?.to_string(); + if !(name.starts_with("owyx-") && name.ends_with(".zip")) { + return None; + } + let meta = entry.metadata().ok()?; + let modified = meta + .modified() + .ok() + .and_then(|t| t.duration_since(UNIX_EPOCH).ok()) + .map(|d| d.as_secs()) + .unwrap_or(0); + Some((modified, path)) + }) + .collect(); + archives.sort_by(|a, b| b.0.cmp(&a.0)); + for (_m, path) in archives.into_iter().skip(keep) { + let _ = fs::remove_file(path); + } + Ok(()) +} + +pub fn info(message: &str) { + let line = format_line("INFO", message); + eprintln!("{line}"); + append_launcher_line(&line); +} + +pub fn warn(message: &str) { + let line = format_line("WARN", message); + eprintln!("{line}"); + append_launcher_line(&line); +} + +pub fn error(message: &str) { + let line = format_line("ERROR", message); + eprintln!("{line}"); + append_launcher_line(&line); +} + +fn format_line(level: &str, message: &str) -> String { + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + format!("[{stamp}] [{level}] {message}") +} + +fn append_launcher_line(line: &str) { + if let Ok(mut guard) = LAUNCHER_LOG.lock() { + if let Some(file) = guard.as_mut() { + let _ = writeln!(file, "{line}"); + let _ = file.flush(); + } + } +} + +pub fn create_launch_log(pack_id: &str) -> Result<(PathBuf, File), String> { + let stamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0); + let path = logs_dir()?.join(format!("launch-{pack_id}-{stamp}.log")); + let file = OpenOptions::new() + .create(true) + .append(true) + .open(&path) + .map_err(|e| format!("Open launch log: {e}"))?; + Ok((path, file)) +} + +pub fn write_line(file: &mut File, line: &str) -> Result<(), String> { + writeln!(file, "{line}").map_err(|e| format!("Write log: {e}"))?; + file.flush().map_err(|e| format!("Flush log: {e}")) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/main.rs b/legacy/Launcher/apps/launcher/src-tauri/src/main.rs new file mode 100644 index 00000000000..262be0a1312 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + owyx_lib::run() +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/models.rs b/legacy/Launcher/apps/launcher/src-tauri/src/models.rs new file mode 100644 index 00000000000..362ec188fd8 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/models.rs @@ -0,0 +1,83 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PacksResponse { + pub packs: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PackSummary { + pub id: String, + pub name: String, + pub minecraft: String, + pub loader: String, + #[serde(default)] + pub loader_version: Option, + #[serde(default)] + pub summary: Option, + pub manifest_url: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PackManifest { + pub id: String, + pub version: String, + pub minecraft: String, + pub loader: String, + #[serde(default)] + pub main_class: Option, + #[serde(default)] + pub java: Option, + #[serde(default)] + pub asset_index: Option, + pub files: Vec, + #[serde(default)] + pub jvm_args: Vec, + #[serde(default)] + pub game_args: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct JavaRequirement { + pub min_major: u32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ManifestFile { + pub path: String, + pub url: String, + pub sha256: String, + #[serde(default)] + pub size: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PackLocalStatus { + pub pack_id: String, + pub installed: bool, + pub version: Option, + pub ready: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SyncProgress { + pub pack_id: String, + pub phase: String, + pub current_file: Option, + pub done_files: u32, + pub total_files: u32, + pub message: String, + /// Bytes received for the current file (None when not actively streaming). + #[serde(default, skip_serializing_if = "Option::is_none")] + pub file_bytes_done: Option, + /// Expected / Content-Length total for the current file, if known. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub file_bytes_total: Option, +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/modrinth.rs b/legacy/Launcher/apps/launcher/src-tauri/src/modrinth.rs new file mode 100644 index 00000000000..99b35927b2b --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/modrinth.rs @@ -0,0 +1,917 @@ +//! Modrinth Labrinth API client scaffold. +//! Real marketplace polish comes later — this wires HTTPS search so Content can call it. + +use serde::{Deserialize, Serialize}; +use std::collections::HashSet; +use std::time::Duration; + +const MODRINTH_API: &str = "https://api.modrinth.com/v2"; +const USER_AGENT: &str = concat!( + "owyx/", + env!("CARGO_PKG_VERSION"), + " (github.com/ebluffy/Owyx)" +); +/// Hard cap for a single downloaded mod/pack file. +const MAX_FILE_BYTES: u64 = 512 * 1024 * 1024; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthProjectHit { + pub project_id: String, + pub slug: String, + pub title: String, + pub description: String, + pub project_type: String, + pub downloads: u64, + #[serde(default)] + pub icon_url: Option, + #[serde(default)] + pub categories: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthSearchResult { + pub hits: Vec, + pub offset: u32, + pub limit: u32, + pub total_hits: u32, + /// True when this is a local stub (no network / scaffold mode). + #[serde(default)] + pub stub: bool, + #[serde(default)] + pub message: Option, +} + +#[derive(Debug, Deserialize)] +struct ApiSearchResponse { + hits: Vec, + offset: u32, + limit: u32, + total_hits: u32, +} + +#[derive(Debug, Deserialize)] +struct ApiHit { + project_id: String, + slug: String, + title: String, + description: String, + project_type: String, + downloads: u64, + #[serde(default)] + icon_url: Option, + #[serde(default)] + categories: Vec, +} + +fn http_client() -> Result { + let redirect_policy = reqwest::redirect::Policy::custom(|attempt| { + if attempt.previous().len() >= 8 { + return attempt.error("Too many Modrinth redirects"); + } + if assert_modrinth_url(attempt.url().as_str()).is_ok() { + attempt.follow() + } else { + attempt.error("Modrinth redirect left the allowed hosts") + } + }); + reqwest::Client::builder() + .user_agent(USER_AGENT) + .timeout(Duration::from_secs(30)) + .connect_timeout(Duration::from_secs(10)) + .redirect(redirect_policy) + .build() + .map_err(|e| format!("HTTP client: {e}")) +} + +fn assert_modrinth_url(raw: &str) -> Result<(), String> { + let parsed = reqwest::Url::parse(raw).map_err(|e| format!("Bad URL: {e}"))?; + if parsed.scheme() != "https" { + return Err("Only https allowed for Modrinth API".into()); + } + if parsed.username() != "" || parsed.password().is_some() { + return Err("Modrinth URL must not include credentials".into()); + } + let host = parsed + .host_str() + .ok_or_else(|| "Missing host".to_string())? + .to_ascii_lowercase(); + if host != "api.modrinth.com" && !host.ends_with(".modrinth.com") { + return Err(format!("Host not allowed: {host}")); + } + Ok(()) +} + +/// Search Modrinth projects (mods / resource packs / etc.). +/// Empty query returns an empty scaffold result without hitting the network. +pub async fn search_projects( + query: String, + limit: Option, + offset: Option, + loader: Option, + game_version: Option, + category: Option, + project_type: Option, + index: Option, +) -> Result { + let q = query.trim().to_string(); + let limit = limit.unwrap_or(20).clamp(1, 50); + let offset = offset.unwrap_or(0); + let ptype = project_type + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + .unwrap_or("mod"); + let allowed_types = ["mod", "resourcepack", "datapack", "shader", "modpack"]; + if !allowed_types.contains(&ptype) { + return Err(format!("Unsupported project type: {ptype}")); + } + + let mut url = format!( + "{MODRINTH_API}/search?query={}&limit={limit}&offset={offset}", + urlencoding_lite(&q) + ); + if let Some(idx) = index + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + { + // Modrinth indices: relevance, downloads, follows, newest, updated + let allowed = ["relevance", "downloads", "follows", "newest", "updated"]; + if allowed.contains(&idx) { + url.push_str(&format!("&index={}", urlencoding_lite(idx))); + } + } + let mut facets: Vec = vec![format!(r#"["project_type:{ptype}"]"#)]; + if let Some(l) = loader + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty() && *s != "vanilla") + { + // Loader facet applies to mods; shaders use different categories. + if ptype == "mod" || ptype == "modpack" { + facets.push(format!(r#"["categories:{}"]"#, urlencoding_lite(l))); + } + } + if let Some(v) = game_version + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + { + facets.push(format!(r#"["versions:{}"]"#, urlencoding_lite(v))); + } + if let Some(c) = category + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + { + facets.push(format!(r#"["categories:{}"]"#, urlencoding_lite(c))); + } + url.push_str(&format!("&facets=[{}]", facets.join(","))); + assert_modrinth_url(&url)?; + + let http = http_client()?; + let res = http + .get(&url) + .send() + .await + .map_err(|e| format!("Modrinth search: {e}"))? + .error_for_status() + .map_err(|e| format!("Modrinth HTTP: {e}"))?; + assert_modrinth_url(res.url().as_str())?; + + let body: ApiSearchResponse = res + .json() + .await + .map_err(|e| format!("Modrinth JSON: {e}"))?; + + Ok(ModrinthSearchResult { + hits: body + .hits + .into_iter() + .map(|h| ModrinthProjectHit { + project_id: h.project_id, + slug: h.slug, + title: h.title, + description: h.description, + project_type: h.project_type, + downloads: h.downloads, + icon_url: h.icon_url, + categories: h.categories, + }) + .collect(), + offset: body.offset, + limit: body.limit, + total_hits: body.total_hits, + stub: false, + message: None, + }) +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthGalleryImage { + pub url: String, + #[serde(default)] + pub title: Option, + #[serde(default)] + pub description: Option, + #[serde(default)] + pub featured: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthProjectDetail { + pub id: String, + pub slug: String, + pub title: String, + pub description: String, + pub body: String, + pub project_type: String, + pub downloads: u64, + #[serde(default)] + pub icon_url: Option, + #[serde(default)] + pub categories: Vec, + #[serde(default)] + pub loaders: Vec, + #[serde(default)] + pub game_versions: Vec, + #[serde(default)] + pub gallery: Vec, + #[serde(default)] + pub project_url: Option, +} + +#[derive(Debug, Deserialize)] +struct ApiGalleryImage { + url: String, + #[serde(default)] + title: Option, + #[serde(default)] + description: Option, + #[serde(default)] + featured: bool, +} + +#[derive(Debug, Deserialize)] +struct ApiProject { + id: String, + slug: String, + title: String, + description: String, + #[serde(default)] + body: String, + project_type: String, + downloads: u64, + #[serde(default)] + icon_url: Option, + #[serde(default)] + categories: Vec, + #[serde(default)] + loaders: Vec, + #[serde(default)] + game_versions: Vec, + #[serde(default)] + gallery: Vec, +} + +/// Fetch a single Modrinth project by id or slug (detail panel). +pub async fn get_project(project_id: String) -> Result { + let id = sanitize_project_id(&project_id)?; + let url = format!("{MODRINTH_API}/project/{id}"); + assert_modrinth_url(&url)?; + + let http = http_client()?; + let res = http + .get(&url) + .send() + .await + .map_err(|e| format!("Modrinth project: {e}"))? + .error_for_status() + .map_err(|e| format!("Modrinth HTTP: {e}"))?; + assert_modrinth_url(res.url().as_str())?; + let p: ApiProject = res + .json() + .await + .map_err(|e| format!("Modrinth project JSON: {e}"))?; + let project_url = Some(format!("https://modrinth.com/{}/{}", p.project_type, p.slug)); + Ok(ModrinthProjectDetail { + id: p.id, + slug: p.slug, + title: p.title, + description: p.description, + body: p.body, + project_type: p.project_type, + downloads: p.downloads, + icon_url: p.icon_url, + categories: p.categories, + loaders: p.loaders, + game_versions: p.game_versions, + gallery: p + .gallery + .into_iter() + .map(|g| ModrinthGalleryImage { + url: g.url, + title: g.title, + description: g.description, + featured: g.featured, + }) + .collect(), + project_url, + }) +} + +// --------------------------------------------------------------------------- +// Versions + install (MR-1): pick a loader/MC-compatible file and drop it into +// the instance content folder. Ported from Theseus' project-version selection. +// --------------------------------------------------------------------------- + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthVersionFile { + pub url: String, + pub filename: String, + pub primary: bool, + #[serde(default)] + pub size: Option, + #[serde(default)] + pub sha512: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthDependency { + #[serde(default)] + pub project_id: Option, + #[serde(default)] + pub version_id: Option, + #[serde(default)] + pub dependency_type: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ModrinthVersion { + pub id: String, + pub name: String, + pub version_number: String, + pub version_type: String, + pub loaders: Vec, + pub game_versions: Vec, + pub files: Vec, + #[serde(default)] + pub dependencies: Vec, + #[serde(default)] + pub project_id: Option, + #[serde(default)] + pub changelog: Option, + #[serde(default)] + pub date_published: Option, + #[serde(default)] + pub downloads: Option, +} + +#[derive(Debug, Deserialize)] +struct ApiVersion { + id: String, + name: String, + version_number: String, + #[serde(default)] + version_type: String, + #[serde(default)] + loaders: Vec, + #[serde(default)] + game_versions: Vec, + #[serde(default)] + files: Vec, + #[serde(default)] + dependencies: Vec, + #[serde(default)] + project_id: Option, + #[serde(default)] + changelog: Option, + #[serde(default)] + date_published: Option, + #[serde(default)] + downloads: Option, +} + +fn map_api_version(v: ApiVersion) -> ModrinthVersion { + ModrinthVersion { + id: v.id, + name: v.name, + version_number: v.version_number, + version_type: v.version_type, + loaders: v.loaders, + game_versions: v.game_versions, + files: v + .files + .into_iter() + .map(|f| ModrinthVersionFile { + url: f.url, + filename: f.filename, + primary: f.primary, + size: f.size, + sha512: f.hashes.and_then(|h| h.sha512), + }) + .collect(), + dependencies: v + .dependencies + .into_iter() + .map(|d| ModrinthDependency { + project_id: d.project_id, + version_id: d.version_id, + dependency_type: d.dependency_type, + }) + .collect(), + project_id: v.project_id, + changelog: v.changelog, + date_published: v.date_published, + downloads: v.downloads, + } +} + +#[derive(Debug, Deserialize)] +struct ApiDependency { + #[serde(default)] + project_id: Option, + #[serde(default)] + version_id: Option, + #[serde(default)] + dependency_type: String, +} + +#[derive(Debug, Deserialize)] +struct ApiVersionFile { + url: String, + filename: String, + #[serde(default)] + primary: bool, + #[serde(default)] + size: Option, + #[serde(default)] + hashes: Option, +} + +#[derive(Debug, Deserialize)] +struct ApiHashes { + #[serde(default)] + sha512: Option, +} + +/// List a project's versions, optionally filtered by loader + Minecraft version (server-side). +pub async fn list_project_versions( + project_id: String, + loader: Option, + game_version: Option, +) -> Result, String> { + let id = sanitize_project_id(&project_id)?; + let mut url = format!("{MODRINTH_API}/project/{id}/version"); + let mut params: Vec = Vec::new(); + if let Some(l) = loader.as_deref().map(str::trim).filter(|s| !s.is_empty()) { + // Modrinth expects a JSON array: loaders=["fabric"] + params.push(format!("loaders=%5B%22{}%22%5D", urlencoding_lite(l))); + } + if let Some(v) = game_version + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + { + params.push(format!("game_versions=%5B%22{}%22%5D", urlencoding_lite(v))); + } + if !params.is_empty() { + url.push('?'); + url.push_str(¶ms.join("&")); + } + assert_modrinth_url(&url)?; + + let http = http_client()?; + let res = http + .get(&url) + .send() + .await + .map_err(|e| format!("Modrinth versions: {e}"))? + .error_for_status() + .map_err(|e| format!("Modrinth HTTP: {e}"))?; + assert_modrinth_url(res.url().as_str())?; + let raw: Vec = res + .json() + .await + .map_err(|e| format!("Modrinth versions JSON: {e}"))?; + Ok(raw.into_iter().map(map_api_version).collect()) +} + +/// Resolve the best compatible version and install its primary file into the instance. +/// Vanilla instances skip the loader filter (resource/data/shader packs still match by MC). +pub async fn install_to_instance( + instance_id: String, + project_id: String, + loader: String, + game_version: String, + include_optional_dependencies: bool, +) -> Result { + crate::instances::validate_instance_id(&instance_id)?; + let loader = loader.trim().to_ascii_lowercase(); + let loader_filter = if loader.is_empty() || loader == "vanilla" { + None + } else { + Some(loader.clone()) + }; + let mc = if game_version.trim().is_empty() { + None + } else { + Some(game_version.trim().to_string()) + }; + + // Try loader + MC first; fall back to MC-only so resource/data packs still resolve. + let mut versions = + list_project_versions(project_id.clone(), loader_filter.clone(), mc.clone()).await?; + if versions.is_empty() && loader_filter.is_some() { + versions = list_project_versions(project_id.clone(), None, mc.clone()).await?; + } + if versions.is_empty() { + return Err("No compatible version for this loader / Minecraft version".into()); + } + + // Modrinth returns newest first. Use the same dependency-aware path as the + // explicit version picker instead of silently skipping required projects. + let version = versions.into_iter().next().ok_or("No version returned")?; + install_version_inner( + instance_id, + version.id, + true, + include_optional_dependencies, + 0, + &mut HashSet::new(), + loader_filter, + mc, + ) + .await? + .ok_or_else(|| "Selected version was already resolved as a dependency".to_string()) +} + +/// Install a specific Modrinth version and its selected dependency set. +/// Dependency planning follows Theseus' fail-fast behavior: a required project +/// must finish successfully before the requested file is written. +pub async fn install_version_to_instance( + instance_id: String, + version_id: String, + with_dependencies: bool, + include_optional_dependencies: bool, +) -> Result { + crate::instances::validate_instance_id(&instance_id)?; + let (prefer_loader, prefer_mc) = instance_loader_mc(&instance_id); + let mut visited = HashSet::new(); + install_version_inner( + instance_id, + version_id, + with_dependencies, + include_optional_dependencies, + 0, + &mut visited, + prefer_loader, + prefer_mc, + ) + .await? + .ok_or_else(|| "Selected version was already resolved as a dependency".to_string()) +} + +fn instance_loader_mc(id: &str) -> (Option, Option) { + let Ok(list) = crate::instances::list_instances() else { + return (None, None); + }; + list.into_iter() + .find(|i| i.id == id) + .map(|i| { + let loader = i.loader.trim().to_ascii_lowercase(); + let loader = if loader.is_empty() || loader == "vanilla" { + None + } else { + Some(loader) + }; + let mc = i.minecraft.trim(); + let mc = if mc.is_empty() { + None + } else { + Some(mc.to_string()) + }; + (loader, mc) + }) + .unwrap_or((None, None)) +} + +fn resolve_dep_filters( + prefer_loader: Option, + prefer_mc: Option, + version_loaders: &[String], + version_game_versions: &[String], +) -> (Option, Option) { + ( + prefer_loader.or_else(|| version_loaders.first().cloned()), + prefer_mc.or_else(|| version_game_versions.first().cloned()), + ) +} + +pub async fn fetch_version_public(version_id: &str) -> Result { + fetch_version(version_id).await +} + +pub fn assert_download_url_public(url: &str) -> Result<(), String> { + assert_modrinth_download_url(url) +} + +pub async fn download_bytes_public(url: &str, max_bytes: u64) -> Result, String> { + download_capped(url, max_bytes).await +} + +async fn fetch_version(version_id: &str) -> Result { + let id = sanitize_project_id(version_id)?; + let url = format!("{MODRINTH_API}/version/{id}"); + assert_modrinth_url(&url)?; + let http = http_client()?; + let res = http + .get(&url) + .send() + .await + .map_err(|e| format!("Modrinth version: {e}"))? + .error_for_status() + .map_err(|e| format!("Modrinth HTTP: {e}"))?; + assert_modrinth_url(res.url().as_str())?; + let v: ApiVersion = res + .json() + .await + .map_err(|e| format!("Modrinth version JSON: {e}"))?; + Ok(map_api_version(v)) +} + +async fn install_version_inner( + instance_id: String, + version_id: String, + with_dependencies: bool, + include_optional_dependencies: bool, + depth: u8, + visited: &mut HashSet, + prefer_loader: Option, + prefer_mc: Option, +) -> Result, String> { + if depth > 5 { + return Err("Dependency tree too deep".into()); + } + if !visited.insert(version_id.clone()) { + return Ok(None); + } + let version = fetch_version(&version_id).await?; + if with_dependencies { + for dep in &version.dependencies { + let required = dep.dependency_type.eq_ignore_ascii_case("required"); + let optional = dep.dependency_type.eq_ignore_ascii_case("optional"); + if !required && !(optional && include_optional_dependencies) { + continue; + } + let dep_label = dep + .project_id + .as_deref() + .or(dep.version_id.as_deref()) + .unwrap_or("unknown dependency"); + let result = if let Some(vid) = dep.version_id.as_deref().filter(|s| !s.is_empty()) { + Box::pin(install_version_inner( + instance_id.clone(), + vid.to_string(), + true, + include_optional_dependencies, + depth + 1, + visited, + prefer_loader.clone(), + prefer_mc.clone(), + )) + .await + } else if let Some(pid) = dep.project_id.as_deref().filter(|s| !s.is_empty()) { + let (loader, mc) = resolve_dep_filters( + prefer_loader.clone(), + prefer_mc.clone(), + &version.loaders, + &version.game_versions, + ); + let versions = list_project_versions(pid.to_string(), loader, mc).await?; + if let Some(first) = versions.into_iter().next() { + Box::pin(install_version_inner( + instance_id.clone(), + first.id, + true, + include_optional_dependencies, + depth + 1, + visited, + prefer_loader.clone(), + prefer_mc.clone(), + )) + .await + } else { + Err(format!("No compatible version for dependency {pid}")) + } + } else if required { + Err("Required dependency has no project or version id".into()) + } else { + Ok(None) + }; + if let Err(err) = result { + return Err(format!( + "{} dependency {dep_label} failed: {err}", + if required { "Required" } else { "Optional" } + )); + } + } + } + + let file = version + .files + .iter() + .find(|f| f.primary) + .cloned() + .or_else(|| version.files.first().cloned()) + .ok_or("Selected version has no downloadable file")?; + let existing = + crate::instances::find_content_by_file_name(&instance_id, &file.filename)?; + if let Some(ref existing) = existing { + if let Some(on_disk) = + crate::instances::read_content_file(&instance_id, &existing.kind, &existing.file_name)? + { + if existing_file_is_same_version(&on_disk, file.sha512.as_deref()) { + if let Some(pid) = version.project_id.as_deref().filter(|s| !s.is_empty()) { + crate::instances::record_modrinth_project_id( + &instance_id, + &existing.file_name, + pid, + )?; + } + return Ok(Some(existing.clone())); + } + } + } + assert_modrinth_download_url(&file.url)?; + let bytes = download_capped(&file.url, MAX_FILE_BYTES).await?; + if let Some(expected) = file.sha512.as_deref() { + verify_sha512(&bytes, expected)?; + } + let replace = existing.is_some(); + let project_id_for_index = version.project_id.clone(); + let instance_id_for_index = instance_id.clone(); + let file_name_for_index = file.filename.clone(); + let installed = tauri::async_runtime::spawn_blocking(move || { + if replace { + crate::instances::replace_content_from_bytes(&instance_id, &file.filename, bytes, None) + } else { + crate::instances::add_content_from_bytes(&instance_id, &file.filename, bytes, None) + } + }) + .await + .map_err(|e| format!("install join: {e}"))??; + if let Some(pid) = project_id_for_index.as_deref().filter(|s| !s.is_empty()) { + crate::instances::record_modrinth_project_id( + &instance_id_for_index, + &installed.file_name, + pid, + )?; + } else if !file_name_for_index.is_empty() { + // No project id on version payload — skip index (hide-installed stays accurate for recorded files only). + } + Ok(Some(installed)) +} + +/// Skip a re-download only when the on-disk bytes match the Modrinth SHA-512. +/// Same filename + different hash (typical upgrade) replaces the old jar. +/// No hash from the API → do not skip; we cannot prove it is the same version. +fn existing_file_is_same_version(existing_bytes: &[u8], expected_sha512: Option<&str>) -> bool { + match expected_sha512 { + Some(expected) => verify_sha512(existing_bytes, expected).is_ok(), + None => false, + } +} + +fn sanitize_project_id(raw: &str) -> Result { + let id = raw.trim(); + if id.is_empty() || id.len() > 64 { + return Err("Invalid Modrinth project id".into()); + } + if !id + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_')) + { + return Err("Invalid Modrinth project id characters".into()); + } + Ok(id.to_string()) +} + +/// Modrinth serves version files from the CDN; only allow modrinth hosts over https. +fn assert_modrinth_download_url(raw: &str) -> Result<(), String> { + assert_modrinth_url(raw).map_err(|err| err.replace("API", "downloads")) +} + +async fn download_capped(url: &str, max_bytes: u64) -> Result, String> { + use futures_util::StreamExt; + assert_modrinth_download_url(url)?; + let http = http_client()?; + let res = http + .get(url) + .send() + .await + .map_err(|e| format!("Download: {e}"))? + .error_for_status() + .map_err(|e| format!("Download HTTP: {e}"))?; + assert_modrinth_download_url(res.url().as_str())?; + if let Some(len) = res.content_length() { + if len > max_bytes { + return Err(format!("File too large ({len} bytes)")); + } + } + let mut out = Vec::new(); + let mut stream = res.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Download stream: {e}"))?; + if out.len() as u64 + chunk.len() as u64 > max_bytes { + return Err(format!("File exceeded {max_bytes} bytes")); + } + out.extend_from_slice(&chunk); + } + Ok(out) +} + +fn verify_sha512(bytes: &[u8], expected: &str) -> Result<(), String> { + use sha2::{Digest, Sha512}; + let actual: String = Sha512::digest(bytes) + .iter() + .map(|b| format!("{b:02x}")) + .collect(); + if actual.eq_ignore_ascii_case(expected) { + Ok(()) + } else { + Err("Downloaded file failed SHA-512 verification".into()) + } +} + +/// Minimal URL-encode for query strings (alphanumeric + a few safe chars pass through). +fn urlencoding_lite(s: &str) -> String { + let mut out = String::with_capacity(s.len() * 3); + for b in s.bytes() { + match b { + b'A'..=b'Z' | b'a'..=b'z' | b'0'..=b'9' | b'-' | b'_' | b'.' | b'~' => { + out.push(b as char); + } + b' ' => out.push('+'), + _ => { + out.push('%'); + out.push(char::from_digit((b >> 4) as u32, 16).unwrap()); + out.push(char::from_digit((b & 0xf) as u32, 16).unwrap()); + } + } + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn modrinth_urls_require_https_and_allowed_hosts() { + assert!(assert_modrinth_url("https://api.modrinth.com/v2/search").is_ok()); + assert!(assert_modrinth_download_url( + "https://cdn.modrinth.com/data/project/versions/file.jar" + ) + .is_ok()); + assert!(assert_modrinth_url("http://api.modrinth.com/v2/search").is_err()); + assert!(assert_modrinth_url("https://modrinth.com.evil.test/file").is_err()); + assert!(assert_modrinth_url("https://user:pass@api.modrinth.com/v2").is_err()); + } + + #[test] + fn sha512_verification_rejects_changed_content() { + let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\ + 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + assert!(verify_sha512(b"abc", &expected.replace(' ', "")).is_ok()); + assert!(verify_sha512(b"abd", &expected.replace(' ', "")).is_err()); + } + + #[test] + fn dep_filters_prefer_instance_over_version_first() { + let (loader, mc) = resolve_dep_filters( + Some("fabric".into()), + Some("1.20.1".into()), + &["neoforge".into()], + &["1.21.1".into(), "1.20.1".into()], + ); + assert_eq!(loader.as_deref(), Some("fabric")); + assert_eq!(mc.as_deref(), Some("1.20.1")); + } + + #[test] + fn same_filename_skips_only_when_sha512_matches() { + let expected = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a\ + 2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; + assert!(existing_file_is_same_version(b"abc", Some(&expected.replace(' ', "")))); + assert!(!existing_file_is_same_version(b"abd", Some(&expected.replace(' ', "")))); + assert!(!existing_file_is_same_version(b"abc", None)); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/mrpack.rs b/legacy/Launcher/apps/launcher/src-tauri/src/mrpack.rs new file mode 100644 index 00000000000..94864a22c86 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/mrpack.rs @@ -0,0 +1,583 @@ +//! Modrinth `.mrpack` import / export (partial parity). +//! +//! Import: read `modrinth.index.json`, download listed files, extract +//! `overrides/` + `client-overrides/` into a new instance game dir. +//! Export: zip mods/resourcepacks/shaderpacks/datapacks/config as overrides +//! plus a minimal index (files without CDN mirrors stay override-only). +//! +//! Honest gap: no full Theseus content DB / hash cache; export does not upload +//! to Modrinth CDN — local-only pack sharing. + +use crate::config; +use crate::instances::{self, DiskInstance}; +use futures_util::StreamExt; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha512}; +use std::collections::HashMap; +use std::fs::{self, File}; +use std::io::{Read, Write}; +use std::path::{Component, Path, PathBuf}; +use std::time::Duration; +use zip::write::SimpleFileOptions; +use zip::{CompressionMethod, ZipArchive, ZipWriter}; + +const USER_AGENT: &str = concat!( + "owyx/", + env!("CARGO_PKG_VERSION"), + " (github.com/ebluffy/Owyx; mrpack)" +); +const MAX_MRPACK_BYTES: u64 = 512 * 1024 * 1024; +const MAX_FILE_BYTES: u64 = 512 * 1024 * 1024; + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +struct PackFormat { + game: String, + #[allow(dead_code)] + format_version: i32, + #[allow(dead_code)] + version_id: String, + name: String, + #[serde(default)] + summary: Option, + #[serde(default)] + files: Vec, + #[serde(default)] + dependencies: HashMap, +} + +#[derive(Debug, Clone, Deserialize)] +#[serde(rename_all = "camelCase")] +struct PackFile { + path: String, + #[serde(default)] + hashes: HashMap, + #[serde(default)] + downloads: Vec, + #[serde(default)] + file_size: u32, + #[serde(default)] + env: Option>, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +struct ExportPackFormat { + game: &'static str, + format_version: i32, + version_id: String, + name: String, + summary: Option, + files: Vec, + dependencies: HashMap, +} + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MrpackImportResult { + pub instance: DiskInstance, + pub name: String, + pub files_downloaded: u32, + pub overrides_extracted: u32, + pub summary: Option, + /// True when some index files lacked downloads and were skipped. + pub partial: bool, + pub message: String, +} + +fn http_client() -> Result { + reqwest::Client::builder() + .user_agent(USER_AGENT) + .timeout(Duration::from_secs(120)) + .connect_timeout(Duration::from_secs(20)) + .redirect(reqwest::redirect::Policy::limited(8)) + .build() + .map_err(|e| format!("HTTP client: {e}")) +} + +fn assert_https_download_url(raw: &str) -> Result<(), String> { + let parsed = reqwest::Url::parse(raw).map_err(|e| format!("Bad URL: {e}"))?; + if parsed.scheme() != "https" { + return Err("Only https downloads allowed in mrpack".into()); + } + if parsed.username() != "" || parsed.password().is_some() { + return Err("Download URL must not include credentials".into()); + } + let host = parsed + .host_str() + .ok_or_else(|| "Missing host".to_string())? + .to_ascii_lowercase(); + // Modrinth CDN + mirrors commonly used in packs. + let allowed = host == "cdn.modrinth.com" + || host.ends_with(".modrinth.com") + || host == "github.com" + || host == "objects.githubusercontent.com" + || host == "raw.githubusercontent.com" + || host.ends_with(".github.io"); + if !allowed { + return Err(format!("Host not allowed for mrpack download: {host}")); + } + Ok(()) +} + +fn safe_rel(raw: &str) -> Result { + let normalized = raw.replace('\\', "/"); + if normalized.is_empty() || normalized.starts_with('/') || normalized.contains('\0') { + return Err(format!("Unsafe pack path: {raw}")); + } + let path = Path::new(&normalized); + let mut out = PathBuf::new(); + for c in path.components() { + match c { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe pack path: {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err(format!("Empty pack path: {raw}")); + } + Ok(out) +} + +fn hex_sha512(bytes: &[u8]) -> String { + Sha512::digest(bytes) + .iter() + .map(|b| format!("{b:02x}")) + .collect() +} + +fn verify_hashes(bytes: &[u8], hashes: &HashMap) -> Result<(), String> { + if let Some(expected) = hashes.get("sha512") { + let actual = hex_sha512(bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!("SHA-512 mismatch: expected {expected}, got {actual}")); + } + return Ok(()); + } + if let Some(expected) = hashes.get("sha1") { + let actual = crate::install::hex_sha1(bytes); + if !actual.eq_ignore_ascii_case(expected) { + return Err(format!("SHA-1 mismatch: expected {expected}, got {actual}")); + } + return Ok(()); + } + Err("mrpack file missing sha512/sha1 hash — refusing to write unverified content".into()) +} + +fn deps_to_loader(deps: &HashMap) -> Result<(String, String, String), String> { + let mc = deps + .get("minecraft") + .cloned() + .ok_or_else(|| "mrpack missing minecraft dependency".to_string())?; + if let Some(v) = deps.get("fabric-loader") { + return Ok(("fabric".into(), mc, v.clone())); + } + if let Some(v) = deps.get("quilt-loader") { + return Ok(("quilt".into(), mc, v.clone())); + } + if let Some(v) = deps.get("neoforge") { + return Ok(("neoforge".into(), mc, v.clone())); + } + if let Some(v) = deps.get("forge") { + return Ok(("forge".into(), mc, v.clone())); + } + Ok(("vanilla".into(), mc, String::new())) +} + +fn client_side_ok(file: &PackFile) -> bool { + let Some(env) = &file.env else { + return true; + }; + match env.get("client").map(|s| s.as_str()) { + Some("unsupported") => false, + _ => true, + } +} + +async fn download_capped(url: &str, max_bytes: u64) -> Result, String> { + assert_https_download_url(url)?; + let http = http_client()?; + let res = http + .get(url) + .send() + .await + .map_err(|e| format!("Download: {e}"))? + .error_for_status() + .map_err(|e| format!("Download HTTP: {e}"))?; + assert_https_download_url(res.url().as_str())?; + if let Some(len) = res.content_length() { + if len > max_bytes { + return Err(format!("File too large ({len} bytes)")); + } + } + let mut out = Vec::new(); + let mut stream = res.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk.map_err(|e| format!("Download stream: {e}"))?; + if out.len() as u64 + chunk.len() as u64 > max_bytes { + return Err("File too large".into()); + } + out.extend_from_slice(&chunk); + } + Ok(out) +} + +fn read_index_from_zip(bytes: &[u8]) -> Result<(PackFormat, ZipArchive>), String> { + let cursor = std::io::Cursor::new(bytes); + let mut zip = ZipArchive::new(cursor).map_err(|e| format!("Invalid mrpack zip: {e}"))?; + let mut index_raw = String::new(); + { + let mut entry = zip + .by_name("modrinth.index.json") + .map_err(|_| "No modrinth.index.json in mrpack".to_string())?; + entry + .read_to_string(&mut index_raw) + .map_err(|e| format!("Read index: {e}"))?; + } + let pack: PackFormat = + serde_json::from_str(&index_raw).map_err(|e| format!("Invalid modrinth.index.json: {e}"))?; + if pack.game != "minecraft" { + return Err("Pack does not support Minecraft".into()); + } + Ok((pack, zip)) +} + +fn extract_overrides( + zip: &mut ZipArchive>, + game_dir: &Path, +) -> Result { + let mut count = 0u32; + let names: Vec = (0..zip.len()) + .filter_map(|i| zip.by_index(i).ok().map(|e| e.name().to_string())) + .collect(); + for name in names { + let prefix = if name.starts_with("overrides/") { + "overrides/" + } else if name.starts_with("client-overrides/") { + "client-overrides/" + } else { + continue; + }; + if name.ends_with('/') { + continue; + } + let rel = name.trim_start_matches(prefix); + if rel.is_empty() { + continue; + } + let dest_rel = safe_rel(rel)?; + let dest = game_dir.join(&dest_rel); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create override dir: {e}"))?; + } + let mut entry = zip + .by_name(&name) + .map_err(|e| format!("Open override {name}: {e}"))?; + let mut out = File::create(&dest).map_err(|e| format!("Write override: {e}"))?; + std::io::copy(&mut entry, &mut out).map_err(|e| format!("Extract override: {e}"))?; + count += 1; + } + Ok(count) +} + +/// Import a local `.mrpack` into a new instance (create + overlay files). +pub async fn import_mrpack_file(path: String) -> Result { + let path = PathBuf::from(path.trim()); + if !path.is_file() { + return Err("mrpack file not found".into()); + } + let meta = fs::metadata(&path).map_err(|e| format!("Stat mrpack: {e}"))?; + if meta.len() > MAX_MRPACK_BYTES { + return Err("mrpack file too large".into()); + } + let bytes = fs::read(&path).map_err(|e| format!("Read mrpack: {e}"))?; + install_mrpack_bytes(&bytes, None).await +} + +/// Download a Modrinth modpack version (primary `.mrpack`) and import it. +pub async fn import_mrpack_from_modrinth( + project_id: String, + version_id: Option, +) -> Result { + let version = if let Some(vid) = version_id.filter(|s| !s.trim().is_empty()) { + crate::modrinth::fetch_version_public(&vid).await? + } else { + let versions = + crate::modrinth::list_project_versions(project_id.clone(), None, None).await?; + versions + .into_iter() + .next() + .ok_or_else(|| "No modpack versions found".to_string())? + }; + let file = version + .files + .iter() + .find(|f| f.primary || f.filename.ends_with(".mrpack")) + .cloned() + .or_else(|| version.files.first().cloned()) + .ok_or_else(|| "Modpack version has no files".to_string())?; + if !file.filename.ends_with(".mrpack") && !file.filename.ends_with(".zip") { + return Err(format!( + "Expected .mrpack file, got {}", + file.filename + )); + } + crate::modrinth::assert_download_url_public(&file.url)?; + let bytes = crate::modrinth::download_bytes_public(&file.url, MAX_MRPACK_BYTES).await?; + install_mrpack_bytes(&bytes, Some(version.name.as_str())).await +} + +async fn install_mrpack_bytes( + bytes: &[u8], + name_override: Option<&str>, +) -> Result { + let (pack, mut zip) = read_index_from_zip(bytes)?; + let (loader, mc, loader_version) = deps_to_loader(&pack.dependencies)?; + let name = name_override + .map(str::trim) + .filter(|s| !s.is_empty()) + .unwrap_or(pack.name.as_str()); + let instance = instances::prepare_instance(name, &loader, &mc, &loader_version, None)?; + let instance_id = instance.id.clone(); + let result = install_mrpack_into_prepared(&pack, &mut zip, &instance).await; + match result { + Ok(ok) => Ok(ok), + Err(err) => { + let _ = instances::delete_instance(&instance_id); + Err(err) + } + } +} + +async fn install_mrpack_into_prepared( + pack: &PackFormat, + zip: &mut ZipArchive>, + instance: &DiskInstance, +) -> Result { + let game_dir = PathBuf::from(&instance.path).join("game"); + fs::create_dir_all(&game_dir).map_err(|e| format!("Create game dir: {e}"))?; + + let mut downloaded = 0u32; + let mut skipped = 0u32; + for file in &pack.files { + if !client_side_ok(file) { + continue; + } + let rel = safe_rel(&file.path)?; + let dest = game_dir.join(&rel); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create pack dir: {e}"))?; + } + let Some(url) = file.downloads.iter().find(|u| assert_https_download_url(u).is_ok()) else { + skipped += 1; + continue; + }; + let max = if file.file_size > 0 { + (file.file_size as u64) + .saturating_mul(2) + .max(1024) + .min(MAX_FILE_BYTES) + } else { + MAX_FILE_BYTES + }; + let file_bytes = download_capped(url, max).await?; + verify_hashes(&file_bytes, &file.hashes)?; + config::atomic_write_path(&dest, &file_bytes)?; + downloaded += 1; + } + + let overrides = extract_overrides(zip, &game_dir)?; + let partial = skipped > 0; + let message = if partial { + format!( + "Imported {} with {downloaded} files and {overrides} overrides ({skipped} index files skipped — no allowed download URL)", + pack.name + ) + } else { + format!( + "Imported {} with {downloaded} files and {overrides} overrides", + pack.name + ) + }; + + Ok(MrpackImportResult { + instance: instance.clone(), + name: pack.name.clone(), + files_downloaded: downloaded, + overrides_extracted: overrides, + summary: pack.summary.clone(), + partial, + message, + }) +} + +/// Export instance content folders into a local `.mrpack` (override-heavy, partial). +pub fn export_mrpack(instance_id: String, dest_path: String) -> Result { + instances::validate_instance_id(&instance_id)?; + let list = instances::list_instances()?; + let inst = list + .into_iter() + .find(|i| i.id == instance_id) + .ok_or_else(|| "Instance not found".to_string())?; + let game_dir = PathBuf::from(&inst.path).join("game"); + if !game_dir.is_dir() { + return Err("Instance game directory missing".into()); + } + let dest = PathBuf::from(dest_path.trim()); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create export dir: {e}"))?; + } + + let mut dependencies = HashMap::new(); + dependencies.insert("minecraft".into(), inst.minecraft.clone()); + match inst.loader.as_str() { + "fabric" => { + dependencies.insert("fabric-loader".into(), inst.loader_version.clone()); + } + "quilt" => { + dependencies.insert("quilt-loader".into(), inst.loader_version.clone()); + } + "forge" => { + dependencies.insert("forge".into(), inst.loader_version.clone()); + } + "neoforge" => { + dependencies.insert("neoforge".into(), inst.loader_version.clone()); + } + _ => {} + } + + let prefixes = ["mods", "resourcepacks", "shaderpacks", "datapacks", "config"]; + let mut file = File::create(&dest).map_err(|e| format!("Create mrpack: {e}"))?; + let mut zip = ZipWriter::new(&mut file); + let options = SimpleFileOptions::default().compression_method(CompressionMethod::Deflated); + let mut exported_files = 0u32; + + for prefix in prefixes { + let dir = game_dir.join(prefix); + if !dir.is_dir() { + continue; + } + let mut stack = vec![dir.clone()]; + while let Some(current) = stack.pop() { + for entry in fs::read_dir(¤t).map_err(|e| format!("Read dir: {e}"))? { + let entry = entry.map_err(|e| format!("Read entry: {e}"))?; + let ft = entry.file_type().map_err(|e| format!("file type: {e}"))?; + if ft.is_dir() { + stack.push(entry.path()); + continue; + } + if !ft.is_file() { + continue; + } + let path = entry.path(); + let rel = path + .strip_prefix(&game_dir) + .map_err(|_| "Path escaped game dir".to_string())?; + let rel_str = rel.to_string_lossy().replace('\\', "/"); + if rel_str.contains("..") { + continue; + } + let zip_path = format!("overrides/{rel_str}"); + zip.start_file(&zip_path, options) + .map_err(|e| format!("Zip start: {e}"))?; + let mut bytes = Vec::new(); + File::open(&path) + .and_then(|mut f| f.read_to_end(&mut bytes)) + .map_err(|e| format!("Read {}: {e}", path.display()))?; + zip.write_all(&bytes).map_err(|e| format!("Zip write: {e}"))?; + exported_files += 1; + } + } + } + + let index = ExportPackFormat { + game: "minecraft", + format_version: 1, + version_id: format!("owyx-export-{}", inst.id), + name: inst.name.clone(), + summary: Some( + "Exported from Owyx Launcher. Files are in overrides/ (no CDN mirrors).".into(), + ), + files: vec![], + dependencies, + }; + let index_json = + serde_json::to_vec_pretty(&index).map_err(|e| format!("Serialize index: {e}"))?; + zip.start_file("modrinth.index.json", options) + .map_err(|e| format!("Zip index: {e}"))?; + zip.write_all(&index_json) + .map_err(|e| format!("Write index: {e}"))?; + zip.finish().map_err(|e| format!("Finish zip: {e}"))?; + + Ok(format!( + "Exported {} override files to {}", + exported_files, + dest.display() + )) +} + +/// Install mrpack bytes into an existing instance (catalog overlay path). +pub async fn install_mrpack_bytes_into_instance( + instance_id: &str, + bytes: &[u8], +) -> Result<(), String> { + instances::validate_instance_id(instance_id)?; + let (pack, mut zip) = read_index_from_zip(bytes)?; + let game_dir = config::ensure_layout()? + .join("instances") + .join(instance_id) + .join("game"); + fs::create_dir_all(&game_dir).map_err(|e| format!("Create game dir: {e}"))?; + for file in &pack.files { + if !client_side_ok(file) { + continue; + } + let rel = safe_rel(&file.path)?; + let dest = game_dir.join(&rel); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create pack dir: {e}"))?; + } + let Some(url) = file.downloads.iter().find(|u| assert_https_download_url(u).is_ok()) else { + continue; + }; + let file_bytes = download_capped(url, MAX_FILE_BYTES).await?; + verify_hashes(&file_bytes, &file.hashes)?; + config::atomic_write_path(&dest, &file_bytes)?; + } + let _ = extract_overrides(&mut zip, &game_dir)?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deps_fabric() { + let mut d = HashMap::new(); + d.insert("minecraft".into(), "1.21.1".into()); + d.insert("fabric-loader".into(), "0.16.0".into()); + let (l, mc, v) = deps_to_loader(&d).unwrap(); + assert_eq!(l, "fabric"); + assert_eq!(mc, "1.21.1"); + assert_eq!(v, "0.16.0"); + } + + #[test] + fn safe_rel_blocks_traversal() { + assert!(safe_rel("../x").is_err()); + assert!(safe_rel("mods/foo.jar").is_ok()); + } + + #[test] + fn verify_hashes_requires_sha() { + let mut empty = HashMap::new(); + assert!(verify_hashes(b"abc", &empty).is_err()); + empty.insert("sha512".into(), "deadbeef".into()); + assert!(verify_hashes(b"abc", &empty).is_err()); + let good = hex_sha512(b"abc"); + empty.insert("sha512".into(), good); + assert!(verify_hashes(b"abc", &empty).is_ok()); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/ms_auth.rs b/legacy/Launcher/apps/launcher/src-tauri/src/ms_auth.rs new file mode 100644 index 00000000000..a196a85fb52 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/ms_auth.rs @@ -0,0 +1,628 @@ +//! Microsoft account auth — Path A device-code + Xbox + Minecraft when +//! `MICROSOFT_CLIENT_ID` is set; otherwise `unconfigured`. +//! +//! Flow (Azure AD public client / Minecraft launcher-compatible): +//! 1. OAuth2 device code (`consumers` tenant) +//! 2. Poll token endpoint +//! 3. Xbox Live authenticate → XSTS → Minecraft Services login → profile +//! +//! Tokens are stored as an opaque `ms1:` base64 JSON blob on the profile +//! (machine-local file). Windows DPAPI wrapping remains a follow-up. +//! Never invent fake user codes when exchange is unavailable. + +use serde::{Deserialize, Serialize}; +use serde_json::json; +use std::sync::Mutex; +use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +const DEVICE_CODE_URL: &str = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"; +const TOKEN_URL: &str = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"; +const SCOPE: &str = "XboxLive.signin offline_access"; +const XBOX_USER_AUTH: &str = "https://user.auth.xboxlive.com/user/authenticate"; +const XSTS_AUTH: &str = "https://xsts.auth.xboxlive.com/xsts/authorize"; +const MC_LOGIN: &str = "https://api.minecraftservices.com/authentication/login_with_xbox"; +const MC_PROFILE: &str = "https://api.minecraftservices.com/minecraft/profile"; +const USER_AGENT: &str = concat!("owyx/", env!("CARGO_PKG_VERSION"), " (Microsoft auth)"); + +#[derive(Debug, Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MsAuthStatus { + pub phase: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub user_code: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub verification_uri: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub gamertag: Option, + /// Opaque auth blob for profile persistence (Path A success only). + #[serde(skip_serializing_if = "Option::is_none")] + pub auth_blob: Option, +} + +#[derive(Debug, Clone)] +struct PendingSession { + client_id: String, + device_code: String, + user_code: String, + verification_uri: String, + interval: Duration, + expires_at: Instant, + last_poll: Option, + success: Option, + error: Option, +} + +#[derive(Debug, Clone)] +struct SuccessPayload { + gamertag: String, + auth_blob: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct StoredMsTokens { + v: u8, + gamertag: String, + uuid: String, + access_token: String, + #[serde(default)] + refresh_token: Option, + #[serde(default)] + obtained_at: u64, +} + +static STATE: Mutex> = Mutex::new(None); + +fn client_id() -> Option { + std::env::var("MICROSOFT_CLIENT_ID") + .ok() + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) +} + +fn http() -> Result { + reqwest::Client::builder() + .user_agent(USER_AGENT) + .timeout(Duration::from_secs(30)) + .connect_timeout(Duration::from_secs(10)) + .build() + .map_err(|e| format!("HTTP client: {e}")) +} + +fn now_secs() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0) +} + +fn encode_auth_blob(tokens: &StoredMsTokens) -> Result { + let json = serde_json::to_vec(tokens).map_err(|e| format!("Serialize tokens: {e}"))?; + Ok(format!("ms1:{}", b64_encode(&json))) +} + +fn b64_encode(bytes: &[u8]) -> String { + const TABLE: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let mut out = String::with_capacity((bytes.len() + 2) / 3 * 4); + for chunk in bytes.chunks(3) { + let a = chunk[0] as u32; + let b = chunk.get(1).copied().unwrap_or(0) as u32; + let c = chunk.get(2).copied().unwrap_or(0) as u32; + let n = (a << 16) | (b << 8) | c; + out.push(TABLE[((n >> 18) & 63) as usize] as char); + out.push(TABLE[((n >> 12) & 63) as usize] as char); + out.push(if chunk.len() > 1 { + TABLE[((n >> 6) & 63) as usize] as char + } else { + '=' + }); + out.push(if chunk.len() > 2 { + TABLE[(n & 63) as usize] as char + } else { + '=' + }); + } + out +} + +#[derive(Debug, Deserialize)] +struct DeviceCodeResponse { + device_code: String, + user_code: String, + verification_uri: String, + #[serde(default)] + expires_in: u64, + #[serde(default)] + interval: u64, + #[serde(default)] + message: Option, + #[serde(default)] + error: Option, + #[serde(default)] + error_description: Option, +} + +#[derive(Debug, Deserialize)] +struct TokenResponse { + #[serde(default)] + access_token: Option, + #[serde(default)] + refresh_token: Option, + #[serde(default)] + error: Option, + #[serde(default)] + error_description: Option, +} + +#[derive(Debug, Deserialize)] +struct XboxAuthResponse { + #[serde(default, rename = "Token")] + token: Option, + #[serde(default, rename = "DisplayClaims")] + display_claims: Option, +} + +#[derive(Debug, Deserialize)] +struct McLoginResponse { + #[serde(default)] + access_token: Option, +} + +#[derive(Debug, Deserialize)] +struct McProfile { + #[serde(default)] + id: Option, + #[serde(default)] + name: Option, +} + +pub async fn start() -> Result { + let Some(id) = client_id() else { + return Ok(MsAuthStatus { + phase: "unconfigured".into(), + message: Some( + "MICROSOFT_CLIENT_ID is not set. See Launcher/apps/launcher/docs/MICROSOFT_AUTH.md" + .into(), + ), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + }; + + let client = http()?; + let res = client + .post(DEVICE_CODE_URL) + .form(&[("client_id", id.as_str()), ("scope", SCOPE)]) + .send() + .await + .map_err(|e| format!("Device code request failed: {e}"))?; + let status = res.status(); + let body: DeviceCodeResponse = res + .json() + .await + .map_err(|e| format!("Device code JSON: {e}"))?; + if !status.is_success() || body.error.is_some() { + let msg = body + .error_description + .or(body.error) + .unwrap_or_else(|| format!("Device code HTTP {status}")); + // Common when Azure app lacks public-client / device-code: surface clearly. + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some(format!( + "{msg} — ensure the Azure app allows public client device code and Xbox Live sign-in. See docs/MICROSOFT_AUTH.md" + )), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + if body.device_code.is_empty() || body.user_code.is_empty() { + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some("Microsoft returned an empty device code".into()), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + + let expires = if body.expires_in == 0 { + 900 + } else { + body.expires_in + }; + let interval = if body.interval == 0 { 5 } else { body.interval }; + let session = PendingSession { + client_id: id, + device_code: body.device_code, + user_code: body.user_code.clone(), + verification_uri: if body.verification_uri.is_empty() { + "https://www.microsoft.com/link".into() + } else { + body.verification_uri.clone() + }, + interval: Duration::from_secs(interval), + expires_at: Instant::now() + Duration::from_secs(expires), + last_poll: None, + success: None, + error: None, + }; + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + *guard = Some(session); + + Ok(MsAuthStatus { + phase: "waiting".into(), + message: body.message.or(Some("Enter the code at the verification URL".into())), + user_code: Some(body.user_code), + verification_uri: Some(if body.verification_uri.is_empty() { + "https://www.microsoft.com/link".into() + } else { + body.verification_uri + }), + gamertag: None, + auth_blob: None, + }) +} + +pub async fn poll() -> Result { + if client_id().is_none() { + return Ok(MsAuthStatus { + phase: "unconfigured".into(), + message: Some("MICROSOFT_CLIENT_ID is not set".into()), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + + // Snapshot session fields under the lock, then release before network I/O. + let (client_id, device_code, user_code, verification_uri, interval, expired) = { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + let Some(session) = guard.as_mut() else { + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some("No active Microsoft sign-in session".into()), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + }; + if let Some(ok) = session.success.clone() { + return Ok(MsAuthStatus { + phase: "success".into(), + message: Some("Signed in".into()), + user_code: None, + verification_uri: None, + gamertag: Some(ok.gamertag), + auth_blob: Some(ok.auth_blob), + }); + } + if let Some(err) = session.error.clone() { + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some(err), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + if Instant::now() >= session.expires_at { + *guard = None; + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some("Microsoft sign-in timed out".into()), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + if let Some(last) = session.last_poll { + if last.elapsed() < session.interval { + return Ok(MsAuthStatus { + phase: "waiting".into(), + message: Some("Waiting for Microsoft…".into()), + user_code: Some(session.user_code.clone()), + verification_uri: Some(session.verification_uri.clone()), + gamertag: None, + auth_blob: None, + }); + } + } + session.last_poll = Some(Instant::now()); + ( + session.client_id.clone(), + session.device_code.clone(), + session.user_code.clone(), + session.verification_uri.clone(), + session.interval, + false, + ) + }; + let _ = (interval, expired); + + let client = http()?; + let res = client + .post(TOKEN_URL) + .form(&[ + ("grant_type", "urn:ietf:params:oauth:grant-type:device_code"), + ("client_id", client_id.as_str()), + ("device_code", device_code.as_str()), + ]) + .send() + .await + .map_err(|e| format!("Token poll failed: {e}"))?; + let token_body: TokenResponse = res + .json() + .await + .map_err(|e| format!("Token JSON: {e}"))?; + + if let Some(err) = token_body.error.as_deref() { + match err { + "authorization_pending" => { + return Ok(MsAuthStatus { + phase: "waiting".into(), + message: Some("Waiting for Microsoft…".into()), + user_code: Some(user_code), + verification_uri: Some(verification_uri), + gamertag: None, + auth_blob: None, + }); + } + "slow_down" => { + // Azure asks clients to back off (~+5s). + { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + if let Some(s) = guard.as_mut() { + s.interval = s.interval.saturating_add(Duration::from_secs(5)); + } + } + return Ok(MsAuthStatus { + phase: "waiting".into(), + message: Some("Waiting for Microsoft…".into()), + user_code: Some(user_code), + verification_uri: Some(verification_uri), + gamertag: None, + auth_blob: None, + }); + } + "expired_token" | "bad_verification_code" => { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + *guard = None; + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some( + token_body + .error_description + .unwrap_or_else(|| err.to_string()), + ), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + other => { + let msg = token_body + .error_description + .unwrap_or_else(|| other.to_string()); + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + if let Some(s) = guard.as_mut() { + s.error = Some(msg.clone()); + } + return Ok(MsAuthStatus { + phase: "error".into(), + message: Some(msg), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }); + } + } + } + + let ms_access = token_body + .access_token + .ok_or_else(|| "Microsoft token response missing access_token".to_string())?; + let refresh = token_body.refresh_token; + + match exchange_for_minecraft(&client, &ms_access, refresh.as_deref()).await { + Ok(payload) => { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + if let Some(s) = guard.as_mut() { + s.success = Some(payload.clone()); + } + Ok(MsAuthStatus { + phase: "success".into(), + message: Some("Signed in".into()), + user_code: None, + verification_uri: None, + gamertag: Some(payload.gamertag), + auth_blob: Some(payload.auth_blob), + }) + } + Err(err) => { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + if let Some(s) = guard.as_mut() { + s.error = Some(err.clone()); + } + Ok(MsAuthStatus { + phase: "error".into(), + message: Some(err), + user_code: None, + verification_uri: None, + gamertag: None, + auth_blob: None, + }) + } + } +} + +async fn exchange_for_minecraft( + client: &reqwest::Client, + ms_access: &str, + refresh: Option<&str>, +) -> Result { + // Xbox Live user token + let xbox_body = json!({ + "Properties": { + "AuthMethod": "RPS", + "SiteName": "user.auth.xboxlive.com", + "RpsTicket": format!("d={ms_access}") + }, + "RelyingParty": "http://auth.xboxlive.com", + "TokenType": "JWT" + }); + let xbox_res = client + .post(XBOX_USER_AUTH) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .json(&xbox_body) + .send() + .await + .map_err(|e| format!("Xbox auth: {e}"))? + .error_for_status() + .map_err(|e| format!("Xbox auth HTTP: {e}"))?; + let xbox: XboxAuthResponse = xbox_res + .json() + .await + .map_err(|e| format!("Xbox auth JSON: {e}"))?; + let xbox_token = xbox + .token + .ok_or_else(|| "Xbox auth missing Token".to_string())?; + let uhs = xbox + .display_claims + .as_ref() + .and_then(|v| v.get("xui")) + .and_then(|a| a.as_array()) + .and_then(|a| a.first()) + .and_then(|o| o.get("uhs")) + .and_then(|v| v.as_str()) + .ok_or_else(|| "Xbox auth missing user hash".to_string())? + .to_string(); + + // XSTS + let xsts_body = json!({ + "Properties": { + "SandboxId": "RETAIL", + "UserTokens": [xbox_token] + }, + "RelyingParty": "rp://api.minecraftservices.com/", + "TokenType": "JWT" + }); + let xsts_res = client + .post(XSTS_AUTH) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .json(&xsts_body) + .send() + .await + .map_err(|e| format!("XSTS: {e}"))?; + if !xsts_res.status().is_success() { + let status = xsts_res.status(); + let text = xsts_res.text().await.unwrap_or_default(); + return Err(format!( + "XSTS HTTP {status}: {text}. The Azure app may lack Xbox Live permission, or the Microsoft account has no Xbox profile." + )); + } + let xsts: XboxAuthResponse = xsts_res + .json() + .await + .map_err(|e| format!("XSTS JSON: {e}"))?; + let xsts_token = xsts + .token + .ok_or_else(|| "XSTS missing Token".to_string())?; + + // Minecraft login + let mc_body = json!({ + "identityToken": format!("XBL3.0 x={uhs};{xsts_token}") + }); + let mc_res = client + .post(MC_LOGIN) + .header("Content-Type", "application/json") + .header("Accept", "application/json") + .json(&mc_body) + .send() + .await + .map_err(|e| format!("Minecraft login: {e}"))? + .error_for_status() + .map_err(|e| { + format!( + "Minecraft login HTTP: {e}. Account may not own Minecraft Java." + ) + })?; + let mc_login: McLoginResponse = mc_res + .json() + .await + .map_err(|e| format!("Minecraft login JSON: {e}"))?; + let mc_token = mc_login + .access_token + .ok_or_else(|| "Minecraft login missing access_token".to_string())?; + + let profile_res = client + .get(MC_PROFILE) + .header("Authorization", format!("Bearer {mc_token}")) + .send() + .await + .map_err(|e| format!("Minecraft profile: {e}"))? + .error_for_status() + .map_err(|e| format!("Minecraft profile HTTP: {e}"))?; + let profile: McProfile = profile_res + .json() + .await + .map_err(|e| format!("Minecraft profile JSON: {e}"))?; + let gamertag = profile + .name + .filter(|s| !s.is_empty()) + .ok_or_else(|| "Minecraft profile missing name".to_string())?; + let uuid = profile.id.unwrap_or_default(); + + let stored = StoredMsTokens { + v: 1, + gamertag: gamertag.clone(), + uuid, + access_token: mc_token, + refresh_token: refresh.map(|s| s.to_string()), + obtained_at: now_secs(), + }; + let auth_blob = encode_auth_blob(&stored)?; + Ok(SuccessPayload { + gamertag, + auth_blob, + }) +} + +pub fn cancel() -> Result<(), String> { + let mut guard = STATE.lock().map_err(|e| e.to_string())?; + *guard = None; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn auth_blob_roundtrip_prefix() { + let stored = StoredMsTokens { + v: 1, + gamertag: "Test".into(), + uuid: "abc".into(), + access_token: "tok".into(), + refresh_token: None, + obtained_at: 1, + }; + let blob = encode_auth_blob(&stored).unwrap(); + assert!(blob.starts_with("ms1:")); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/owyx.rs b/legacy/Launcher/apps/launcher/src-tauri/src/owyx.rs new file mode 100644 index 00000000000..4d85e1ae826 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/owyx.rs @@ -0,0 +1,406 @@ +// Owyx account login for the launcher. +// +// Talks to the Owyx site API (see owyxsite/LAUNCHER_SITE_CONTRACT.md): +// POST /api/auth/login -> { token } +// GET /api/launcher/me -> { user, serverAccess, cosmetics, ... } +// +// The JWT is stored in the launcher data dir (~/owyx/owyx_auth.json), keyed by +// nickname. It is never returned to the UI or logged. Errors are returned as +// stable codes the frontend maps to localized messages: +// "network" | "invalid_credentials" | "account_inactive" | "server" + +use crate::config; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; +use std::fs; +use std::path::PathBuf; +use std::time::Duration; + +const DEFAULT_BASE: &str = "https://api.owyx.site"; +const TIMEOUT: Duration = Duration::from_secs(20); +pub const CLIENT_KEY_HEADER: &str = "X-Owyx-Client-Key"; + +/// Resolve the API base URL: explicit arg > OWYX_API_BASE_URL env > prod default. +pub fn resolve_base(base_url: Option<&str>) -> String { + if let Some(u) = base_url.map(str::trim).filter(|s| !s.is_empty()) { + return u.trim_end_matches('/').to_string(); + } + match std::env::var("OWYX_API_BASE_URL") { + Ok(v) if !v.trim().is_empty() => v.trim().trim_end_matches('/').to_string(), + _ => DEFAULT_BASE.to_string(), + } +} + +/// Shared secret for api.owyx.site (`LAUNCHER_CLIENT_KEY` on the site). +/// Env `OWYX_CLIENT_KEY` wins; else optional `clientKey` in launcher config dir file +/// `~/owyx/client_key` (one line). Dev against loopback may omit the key. +pub fn resolve_client_key() -> Option { + if let Ok(v) = std::env::var("OWYX_CLIENT_KEY") { + let t = v.trim().to_string(); + if !t.is_empty() { + return Some(t); + } + } + let path = config::app_data_dir() + .unwrap_or_else(|_| PathBuf::from(".")) + .join("client_key"); + if let Ok(raw) = fs::read_to_string(&path) { + let t = raw.trim().to_string(); + if !t.is_empty() { + return Some(t); + } + } + None +} + +fn http_client(base_url: &str) -> Result { + let base = reqwest::Url::parse(base_url).map_err(|_| "network".to_string())?; + let expected_host = base + .host_str() + .ok_or_else(|| "network".to_string())? + .to_ascii_lowercase(); + let expected_scheme = base.scheme().to_string(); + let expected_port = base.port_or_known_default(); + let redirect_policy = reqwest::redirect::Policy::custom(move |attempt| { + if attempt.previous().len() >= 5 { + return attempt.error("Too many redirects"); + } + let next = attempt.url(); + let same_origin = next.scheme() == expected_scheme + && next + .host_str() + .is_some_and(|host| host.eq_ignore_ascii_case(&expected_host)) + && next.port_or_known_default() == expected_port + && next.username().is_empty() + && next.password().is_none(); + if same_origin { + attempt.follow() + } else { + attempt.error("Owyx API redirect changed origin") + } + }); + let mut headers = reqwest::header::HeaderMap::new(); + if let Some(key) = resolve_client_key() { + if let (Ok(name), Ok(val)) = ( + reqwest::header::HeaderName::from_bytes(CLIENT_KEY_HEADER.as_bytes()), + reqwest::header::HeaderValue::from_str(&key), + ) { + headers.insert(name, val); + } + } + reqwest::Client::builder() + .user_agent(concat!("Owyx/", env!("CARGO_PKG_VERSION"))) + .default_headers(headers) + .timeout(TIMEOUT) + .connect_timeout(Duration::from_secs(10)) + .redirect(redirect_policy) + .build() + .map_err(|_| "network".to_string()) +} + +// ---- token store (~/owyx/owyx_auth.json) -------------------------------- + +#[derive(Serialize, Deserialize, Default)] +struct TokenStore { + #[serde(default)] + accounts: HashMap, +} + +#[derive(Serialize, Deserialize, Clone)] +struct StoredAccount { + base_url: String, + token: String, +} + +fn store_path() -> Result { + Ok(config::app_data_dir()?.join("owyx_auth.json")) +} + +fn load_store() -> TokenStore { + let Ok(path) = store_path() else { + return TokenStore::default(); + }; + match fs::read_to_string(&path) { + Ok(raw) => serde_json::from_str(&raw).unwrap_or_default(), + Err(_) => TokenStore::default(), + } +} + +fn save_store(store: &TokenStore) -> Result<(), String> { + let path = store_path()?; + let raw = serde_json::to_string_pretty(store).map_err(|_| "server".to_string())?; + config::atomic_write_path(&path, raw.as_bytes()) +} + +// ---- API shapes --------------------------------------------------------- + +/// What the launcher UI receives after a successful login / me call. +/// The token is intentionally NOT part of this struct. +#[derive(Serialize, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct OwyxSession { + pub nickname: String, + pub email: String, + pub role: String, + pub trust_level: i64, + pub banned: bool, + pub server_access: bool, + pub access_reason: String, + pub skin_url: Option, + pub skin_model: String, + pub base_url: String, +} + +fn parse_me(base: &str, me: &serde_json::Value) -> OwyxSession { + let user = &me["user"]; + let cosmetics = &me["cosmetics"]; + OwyxSession { + nickname: user["nickname"].as_str().unwrap_or_default().to_string(), + email: user["email"].as_str().unwrap_or_default().to_string(), + role: user["role"].as_str().unwrap_or("user").to_string(), + trust_level: user["trustLevel"].as_i64().unwrap_or(0), + banned: user["banned"].as_bool().unwrap_or(false), + server_access: me["serverAccess"].as_bool().unwrap_or(false), + access_reason: me["accessReason"].as_str().unwrap_or("").to_string(), + skin_url: me["skinUrl"].as_str().map(|s| s.to_string()), + skin_model: cosmetics["skinModel"] + .as_str() + .unwrap_or("classic") + .to_string(), + base_url: base.to_string(), + } +} + +/// Login with email + password, then fetch the launcher profile. Stores the JWT. +pub async fn login( + base_url: Option<&str>, + email: &str, + password: &str, +) -> Result { + let base = resolve_base(base_url); + let client = http_client(&base)?; + + let login_resp = client + .post(format!("{base}/api/auth/login")) + .json(&serde_json::json!({ "email": email, "password": password })) + .send() + .await + .map_err(|_| "network".to_string())?; + + let status = login_resp.status(); + if !status.is_success() { + return Err(match status.as_u16() { + 400 | 401 => "invalid_credentials".to_string(), + 403 => "account_inactive".to_string(), + _ => "server".to_string(), + }); + } + + let login_body: serde_json::Value = + login_resp.json().await.map_err(|_| "server".to_string())?; + let token = login_body["token"] + .as_str() + .filter(|s| !s.is_empty()) + .ok_or_else(|| "server".to_string())? + .to_string(); + + let session = fetch_me(&client, &base, &token).await?; + + let mut store = load_store(); + store.accounts.insert( + session.nickname.clone(), + StoredAccount { + base_url: base.clone(), + token, + }, + ); + save_store(&store)?; + + Ok(session) +} + +async fn fetch_me( + client: &reqwest::Client, + base: &str, + token: &str, +) -> Result { + let me_resp = client + .get(format!("{base}/api/launcher/me")) + .bearer_auth(token) + .send() + .await + .map_err(|_| "network".to_string())?; + let status = me_resp.status(); + if !status.is_success() { + // 401/403 = session gone or forbidden — ask the user to sign in again + // instead of a vague "server" error (site+launcher both hold JWTs). + return Err(match status.as_u16() { + 401 | 403 => "no_session".to_string(), + _ => "server".to_string(), + }); + } + let me_body: serde_json::Value = me_resp.json().await.map_err(|_| "server".to_string())?; + Ok(parse_me(base, &me_body)) +} + +/// Refresh the stored session for a nickname (re-fetch /me with the saved token). +pub async fn me(nickname: &str) -> Result { + let store = load_store(); + let account = store + .accounts + .get(nickname) + .cloned() + .ok_or_else(|| "no_session".to_string())?; + let client = http_client(&account.base_url)?; + match fetch_me(&client, &account.base_url, &account.token).await { + Ok(session) => Ok(session), + Err(code) if code == "no_session" => { + // Drop the dead token so the next attempt goes through the login UI. + let _ = logout(nickname); + Err(code) + } + Err(other) => Err(other), + } +} + +/// Drop the stored token for a nickname (logout / delete profile). +pub fn logout(nickname: &str) -> Result<(), String> { + let mut store = load_store(); + if store.accounts.remove(nickname).is_some() { + save_store(&store)?; + } + Ok(()) +} + +fn stored_account(nickname: &str) -> Result { + load_store() + .accounts + .get(nickname) + .cloned() + .ok_or_else(|| "no_session".to_string()) +} + +/// Admin API call using the stored JWT. Path must stay under /api/admin/. +pub async fn admin_request( + nickname: &str, + method: &str, + path: &str, + body: Option, +) -> Result { + let path = path.trim(); + if !path.starts_with("/api/admin/") { + return Err("Admin path must start with /api/admin/".into()); + } + let method = method.trim().to_ascii_uppercase(); + if !matches!(method.as_str(), "GET" | "POST" | "PUT" | "DELETE") { + return Err("Unsupported method".into()); + } + let account = stored_account(nickname)?; + let client = http_client(&account.base_url)?; + let url = format!("{}{path}", account.base_url); + let mut req = match method.as_str() { + "POST" => client.post(&url), + "PUT" => client.put(&url), + "DELETE" => client.delete(&url), + _ => client.get(&url), + }; + req = req.bearer_auth(&account.token); + if let Some(body) = body { + if method != "GET" { + req = req.json(&body); + } + } + let resp = req.send().await.map_err(|_| "network".to_string())?; + let status = resp.status(); + let value: serde_json::Value = resp.json().await.unwrap_or(serde_json::json!({})); + if !status.is_success() { + let msg = value + .get("error") + .and_then(|v| v.as_str()) + .unwrap_or("server"); + return Err(if status.as_u16() == 401 || status.as_u16() == 403 { + "no_session".into() + } else { + msg.to_string() + }); + } + Ok(value) +} + +#[derive(Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct SkinApplyResult { + pub applied: bool, + pub path: Option, + pub model: String, + pub message: String, +} + +/// Download the account skin from /me onto disk (profile + optional instance). +pub async fn apply_skin( + nickname: &str, + instance_id: Option, +) -> Result { + let session = me(nickname).await?; + let Some(url) = session.skin_url.filter(|s| !s.is_empty()) else { + return Ok(SkinApplyResult { + applied: false, + path: None, + model: session.skin_model, + message: "no_skin".into(), + }); + }; + crate::catalog::assert_asset_url(&url, &session.base_url)?; + let client = crate::catalog::http_client(&session.base_url)?; + let response = client + .get(&url) + .send() + .await + .map_err(|_| "network".to_string())? + .error_for_status() + .map_err(|_| "server".to_string())?; + crate::catalog::assert_asset_url(response.url().as_str(), &session.base_url)?; + let bytes = response.bytes().await.map_err(|_| "network".to_string())?; + if bytes.len() < 64 || bytes.len() > 512 * 1024 { + return Err("Skin file size is not a valid PNG skin".into()); + } + if bytes[0] != 0x89 || bytes.get(1) != Some(&b'P') { + return Err("Skin is not a PNG".into()); + } + + let root = config::ensure_layout()?; + let skins = root.join("skins"); + fs::create_dir_all(&skins).map_err(|e| format!("Create skins dir: {e}"))?; + let safe_nick: String = nickname + .chars() + .filter(|c| c.is_ascii_alphanumeric() || *c == '_') + .take(32) + .collect(); + if safe_nick.is_empty() { + return Err("Nickname cannot be used as a skin file name".into()); + } + let dest = skins.join(format!("{safe_nick}.png")); + config::atomic_write_path(&dest, &bytes)?; + + if let Some(id) = instance_id + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + { + crate::instances::validate_instance_id(id)?; + let inst_dir = root.join("instances").join(id).join("game").join("owyx"); + fs::create_dir_all(&inst_dir).map_err(|e| format!("Create instance skin dir: {e}"))?; + config::atomic_write_path(&inst_dir.join("skin.png"), &bytes)?; + config::atomic_write_path( + &inst_dir.join("skin-model.txt"), + session.skin_model.as_bytes(), + )?; + } + + Ok(SkinApplyResult { + applied: true, + path: Some(dest.display().to_string()), + model: session.skin_model, + message: "ok".into(), + }) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/profiles.rs b/legacy/Launcher/apps/launcher/src-tauri/src/profiles.rs new file mode 100644 index 00000000000..6523ff41153 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/profiles.rs @@ -0,0 +1,182 @@ +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::PathBuf; +use std::sync::{LazyLock, Mutex}; +use std::time::{SystemTime, UNIX_EPOCH}; + +use crate::config; + +static PROFILES_LOCK: LazyLock> = LazyLock::new(|| Mutex::new(())); + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct Profile { + pub id: String, + pub kind: String, + pub name: String, + pub nick: String, + #[serde(default)] + pub needs_auth: bool, + /// Opaque auth payload (Microsoft `ms1:` base64 JSON or Owyx). Treat as secret; + /// not OS-encrypted yet (DPAPI/keychain follow-up). Never surface plaintext in UI. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub auth_blob: Option, + pub created_at: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +pub struct ProfilesFile { + #[serde(default)] + pub profiles: Vec, + /// Once true, empty profiles list is intentional (do not revive from config.nick). + #[serde(default)] + pub initialized: bool, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ProfilesState { + pub profiles: Vec, + pub active_profile_id: Option, +} + +fn profiles_path() -> Result { + Ok(config::app_data_dir()?.join("profiles.json")) +} + +fn now_secs() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0) +} + +fn with_profiles_lock(f: impl FnOnce() -> Result) -> Result { + let _guard = PROFILES_LOCK + .lock() + .map_err(|_| "Profiles lock poisoned".to_string())?; + f() +} + +fn load_file() -> Result { + let path = profiles_path()?; + if !path.exists() { + return Ok(ProfilesFile::default()); + } + let raw = fs::read_to_string(&path).map_err(|e| format!("Failed to read profiles: {e}"))?; + serde_json::from_str(&raw).map_err(|e| format!("Invalid profiles.json: {e}")) +} + +fn save_file(file: &ProfilesFile) -> Result<(), String> { + let path = profiles_path()?; + let raw = serde_json::to_string_pretty(file) + .map_err(|e| format!("Failed to serialize profiles: {e}"))?; + config::atomic_write_path(&path, raw.as_bytes()) +} + +pub fn load_state() -> Result { + with_profiles_lock(|| { + let _ = config::ensure_layout()?; + let mut file = load_file()?; + let mut cfg = config::load()?; + + // One-shot migration: legacy nick → offline profile, only if never initialized. + if !file.initialized && file.profiles.is_empty() && !cfg.nick.trim().is_empty() { + let nick = cfg.nick.trim().to_string(); + let id = format!("prof_{}", now_secs()); + file.profiles.push(Profile { + id: id.clone(), + kind: "offline".into(), + name: nick.clone(), + nick, + needs_auth: false, + auth_blob: None, + created_at: now_secs(), + }); + file.initialized = true; + cfg.active_profile_id = Some(id); + save_file(&file)?; + config::save(&cfg)?; + } else if !file.initialized { + file.initialized = true; + let _ = save_file(&file); + } + + if let Some(active) = cfg.active_profile_id.clone() { + if !file.profiles.iter().any(|p| p.id == active) { + cfg.active_profile_id = file.profiles.first().map(|p| p.id.clone()); + config::save(&cfg)?; + } + } + + Ok(ProfilesState { + profiles: file.profiles, + active_profile_id: cfg.active_profile_id, + }) + }) +} + +pub fn save_state( + profiles: Vec, + active_profile_id: Option, +) -> Result { + with_profiles_lock(|| { + for p in &profiles { + if !matches!(p.kind.as_str(), "offline" | "microsoft" | "owyx") { + return Err(format!("Unknown profile kind: {}", p.kind)); + } + if p.nick.chars().count() > 16 { + return Err("Nick must be at most 16 characters".into()); + } + if !p.nick.is_empty() + && !p + .nick + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_') + { + return Err("Nick may only contain letters, numbers, and _".into()); + } + } + + let active = active_profile_id + .filter(|id| profiles.iter().any(|p| &p.id == id)) + .or_else(|| profiles.first().map(|p| p.id.clone())); + + save_file(&ProfilesFile { + profiles: profiles.clone(), + initialized: true, + })?; + + let mut cfg = config::load()?; + cfg.active_profile_id = active.clone(); + if let Some(id) = &active { + if let Some(p) = profiles.iter().find(|p| &p.id == id) { + if p.kind == "offline" { + cfg.nick = p.nick.clone(); + } + } + } else { + cfg.nick.clear(); + cfg.active_profile_id = None; + } + config::save(&cfg)?; + + Ok(ProfilesState { + profiles, + active_profile_id: active, + }) + }) +} + +pub fn active_nick() -> Result { + let state = load_state()?; + let nick = state + .active_profile_id + .as_ref() + .and_then(|id| state.profiles.iter().find(|p| &p.id == id)) + .map(|p| p.nick.clone()) + .filter(|n| !n.is_empty()) + .unwrap_or_else(|| "Player".into()); + Ok(nick) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/skins.rs b/legacy/Launcher/apps/launcher/src-tauri/src/skins.rs new file mode 100644 index 00000000000..80bb09ba27e --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/skins.rs @@ -0,0 +1,474 @@ +//! Local skin library — Modrinth Skins.vue spirit without Mojang equip API. +//! +//! Stores custom PNGs under `{data}/skins/library/`, ships Steve as a default, +//! applies selected texture to `{data}/skins/` + optional instance `game/owyx/`. +//! Owyx account skins continue to use `owyx::apply_skin` (/me → disk). + +use crate::config; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::{Path, PathBuf}; +use std::time::{SystemTime, UNIX_EPOCH}; + +const STEVE_PNG: &[u8] = include_bytes!("../assets/steve.png"); +const MAX_SKIN_BYTES: u64 = 512 * 1024; +const META_NAME: &str = "library.json"; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SkinEntry { + pub id: String, + pub name: String, + /// classic | slim + pub model: String, + /// default | custom | owyx + pub source: String, + /// Absolute path or empty for built-in defaults (texture served via data URL from bytes). + #[serde(default)] + pub path: String, + /// data:image/png;base64,… for UI preview when path is empty / for defaults. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub texture_data_url: Option, + pub is_equipped: bool, + #[serde(default)] + pub created_at: u64, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(rename_all = "camelCase")] +struct LibraryFile { + #[serde(default)] + skins: Vec, + #[serde(default)] + active_id: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct StoredSkin { + id: String, + name: String, + model: String, + file: String, + #[serde(default)] + created_at: u64, +} + +fn now_secs() -> u64 { + SystemTime::now() + .duration_since(UNIX_EPOCH) + .map(|d| d.as_secs()) + .unwrap_or(0) +} + +fn skins_root() -> Result { + let root = config::ensure_layout()?.join("skins"); + fs::create_dir_all(&root).map_err(|e| format!("Create skins dir: {e}"))?; + Ok(root) +} + +fn library_dir() -> Result { + let dir = skins_root()?.join("library"); + fs::create_dir_all(&dir).map_err(|e| format!("Create skins library: {e}"))?; + Ok(dir) +} + +fn meta_path() -> Result { + Ok(library_dir()?.join(META_NAME)) +} + +fn load_library() -> Result { + let path = meta_path()?; + if !path.exists() { + return Ok(LibraryFile::default()); + } + let raw = fs::read_to_string(&path).map_err(|e| format!("Read skin library: {e}"))?; + serde_json::from_str(&raw).map_err(|e| format!("Invalid skin library: {e}")) +} + +fn save_library(file: &LibraryFile) -> Result<(), String> { + let path = meta_path()?; + let raw = serde_json::to_string_pretty(file).map_err(|e| format!("Serialize skins: {e}"))?; + config::atomic_write_path(&path, raw.as_bytes()) +} + +fn validate_png(bytes: &[u8]) -> Result<(), String> { + // PNG signature (8) + IHDR length(4) + type(4) + data(13) + crc(4) = 33 + if bytes.len() < 33 || bytes.len() as u64 > MAX_SKIN_BYTES { + return Err("Skin file size is not a valid PNG skin".into()); + } + const SIG: [u8; 8] = [0x89, b'P', b'N', b'G', 0x0d, 0x0a, 0x1a, 0x0a]; + if bytes[..8] != SIG { + return Err("Skin is not a PNG".into()); + } + let ihdr_len = u32::from_be_bytes([bytes[8], bytes[9], bytes[10], bytes[11]]); + if &bytes[12..16] != b"IHDR" || ihdr_len != 13 { + return Err("Skin PNG missing IHDR".into()); + } + let width = u32::from_be_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]); + let height = u32::from_be_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]); + // Classic 64×32 or modern 64×64 skins only. + if !((width == 64 && height == 64) || (width == 64 && height == 32)) { + return Err(format!( + "Skin must be 64×64 or 64×32 PNG (got {width}×{height})" + )); + } + Ok(()) +} + +fn safe_library_filename(raw: &str) -> Result { + if raw.contains("..") || raw.contains('/') || raw.contains('\\') { + return Err("Unsafe skin library file name".into()); + } + let base = Path::new(raw) + .file_name() + .and_then(|s| s.to_str()) + .unwrap_or(""); + if base.is_empty() || base == "." || base == ".." || base != raw { + return Err("Invalid skin library file name".into()); + } + if !base.ends_with(".png") { + return Err("Skin library file must be .png".into()); + } + if !base + .chars() + .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '_' | '.')) + { + return Err("Unsafe skin library file name".into()); + } + Ok(base.to_string()) +} + +fn png_data_url(bytes: &[u8]) -> String { + format!("data:image/png;base64,{}", b64_encode(bytes)) +} + +fn b64_encode(bytes: &[u8]) -> String { + const TABLE: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + let mut out = String::with_capacity((bytes.len() + 2) / 3 * 4); + for chunk in bytes.chunks(3) { + let a = chunk[0] as u32; + let b = chunk.get(1).copied().unwrap_or(0) as u32; + let c = chunk.get(2).copied().unwrap_or(0) as u32; + let n = (a << 16) | (b << 8) | c; + out.push(TABLE[((n >> 18) & 63) as usize] as char); + out.push(TABLE[((n >> 12) & 63) as usize] as char); + out.push(if chunk.len() > 1 { + TABLE[((n >> 6) & 63) as usize] as char + } else { + '=' + }); + out.push(if chunk.len() > 2 { + TABLE[(n & 63) as usize] as char + } else { + '=' + }); + } + out +} + +fn sanitize_skin_id(raw: &str) -> Result { + let id: String = raw + .chars() + .filter(|c| c.is_ascii_alphanumeric() || *c == '-' || *c == '_') + .take(64) + .collect(); + if id.is_empty() { + return Err("Invalid skin id".into()); + } + Ok(id) +} + +fn detect_model(bytes: &[u8]) -> String { + // Heuristic: arm column alpha at classic slim probe — default classic if unsure. + // Full canvas decode needs image crate; keep classic unless filename hints slim/alex. + let _ = bytes; + "classic".into() +} + +fn default_entries(active_id: Option<&str>) -> Vec { + let steve_url = png_data_url(STEVE_PNG); + let active = active_id.unwrap_or("default:steve"); + vec![SkinEntry { + id: "default:steve".into(), + name: "Steve".into(), + model: "classic".into(), + source: "default".into(), + path: String::new(), + texture_data_url: Some(steve_url), + is_equipped: active == "default:steve", + created_at: 0, + }] +} + +fn bytes_for_skin(lib: &LibraryFile, id: &str) -> Result, String> { + if id == "default:steve" { + return Ok(STEVE_PNG.to_vec()); + } + let stored = lib + .skins + .iter() + .find(|s| s.id == id) + .ok_or_else(|| format!("Unknown skin: {id}"))?; + let file = safe_library_filename(&stored.file)?; + let path = library_dir()?.join(file); + let bytes = fs::read(&path).map_err(|e| format!("Read skin: {e}"))?; + validate_png(&bytes)?; + Ok(bytes) +} + +fn write_equipped(bytes: &[u8], model: &str, instance_id: Option<&str>) -> Result { + let root = skins_root()?; + let dest = root.join("active.png"); + config::atomic_write_path(&dest, bytes)?; + config::atomic_write_path(root.join("active-model.txt").as_path(), model.as_bytes())?; + + if let Some(id) = instance_id.map(str::trim).filter(|s| !s.is_empty()) { + crate::instances::validate_instance_id(id)?; + let inst_dir = config::ensure_layout()? + .join("instances") + .join(id) + .join("game") + .join("owyx"); + fs::create_dir_all(&inst_dir).map_err(|e| format!("Create instance skin dir: {e}"))?; + config::atomic_write_path(&inst_dir.join("skin.png"), bytes)?; + config::atomic_write_path(&inst_dir.join("skin-model.txt"), model.as_bytes())?; + } + Ok(dest.display().to_string()) +} + +/// List defaults + saved custom skins. Marks equipped from library meta. +pub fn list_skins() -> Result, String> { + let lib = load_library()?; + let active = lib.active_id.clone(); + let mut out = default_entries(active.as_deref()); + for s in &lib.skins { + let Ok(file) = safe_library_filename(&s.file) else { + continue; + }; + let path = library_dir()?.join(&file); + let texture = fs::read(&path).ok().and_then(|b| { + validate_png(&b).ok()?; + Some(png_data_url(&b)) + }); + out.push(SkinEntry { + id: s.id.clone(), + name: s.name.clone(), + model: s.model.clone(), + source: "custom".into(), + path: path.display().to_string(), + texture_data_url: texture, + is_equipped: active.as_deref() == Some(s.id.as_str()), + created_at: s.created_at, + }); + } + // If nothing marked equipped but active.png exists, leave defaults as-is. + if out.iter().all(|e| !e.is_equipped) { + if let Some(first) = out.first_mut() { + first.is_equipped = true; + } + } + Ok(out) +} + +/// Copy a PNG into the library and return the new entry. +pub fn import_skin(source_path: String, name: Option) -> Result { + let src = PathBuf::from(source_path.trim()); + if !src.is_file() { + return Err("Skin file not found".into()); + } + let bytes = fs::read(&src).map_err(|e| format!("Read skin file: {e}"))?; + validate_png(&bytes)?; + let stem = src + .file_stem() + .and_then(|s| s.to_str()) + .unwrap_or("skin") + .to_string(); + let display_name = name + .as_deref() + .map(str::trim) + .filter(|s| !s.is_empty()) + .unwrap_or(&stem) + .chars() + .take(48) + .collect::(); + let id = sanitize_skin_id(&format!("custom-{}", now_secs()))?; + let file_name = format!("{id}.png"); + let dest = library_dir()?.join(&file_name); + config::atomic_write_path(&dest, &bytes)?; + + let model = { + let lower = display_name.to_ascii_lowercase(); + if lower.contains("alex") || lower.contains("slim") { + "slim".into() + } else { + detect_model(&bytes) + } + }; + + let mut lib = load_library()?; + lib.skins.push(StoredSkin { + id: id.clone(), + name: display_name.clone(), + model: model.clone(), + file: file_name, + created_at: now_secs(), + }); + save_library(&lib)?; + + Ok(SkinEntry { + id, + name: display_name, + model, + source: "custom".into(), + path: dest.display().to_string(), + texture_data_url: Some(png_data_url(&bytes)), + is_equipped: false, + created_at: now_secs(), + }) +} + +/// Apply a library (or default) skin to disk + optional instance overlay. +pub fn apply_skin(skin_id: String, instance_id: Option) -> Result { + let id = skin_id.trim(); + if id.is_empty() { + return Err("Skin id required".into()); + } + let mut lib = load_library()?; + let bytes = bytes_for_skin(&lib, id)?; + let model = if id == "default:steve" { + "classic".into() + } else { + lib.skins + .iter() + .find(|s| s.id == id) + .map(|s| s.model.clone()) + .unwrap_or_else(|| detect_model(&bytes)) + }; + let path = write_equipped(&bytes, &model, instance_id.as_deref())?; + lib.active_id = Some(id.to_string()); + save_library(&lib)?; + + Ok(SkinEntry { + id: id.to_string(), + name: if id == "default:steve" { + "Steve".into() + } else { + lib.skins + .iter() + .find(|s| s.id == id) + .map(|s| s.name.clone()) + .unwrap_or_else(|| id.to_string()) + }, + model, + source: if id.starts_with("default:") { + "default".into() + } else { + "custom".into() + }, + path, + texture_data_url: Some(png_data_url(&bytes)), + is_equipped: true, + created_at: 0, + }) +} + +pub fn remove_skin(skin_id: String) -> Result<(), String> { + let id = sanitize_skin_id(skin_id.trim())?; + if id.starts_with("default") { + return Err("Cannot remove default skins".into()); + } + let mut lib = load_library()?; + let Some(idx) = lib.skins.iter().position(|s| s.id == id) else { + return Err("Skin not found".into()); + }; + let file = safe_library_filename(&lib.skins[idx].file)?; + let was_active = lib.active_id.as_deref() == Some(id.as_str()); + lib.skins.remove(idx); + if was_active { + lib.active_id = Some("default:steve".into()); + // Keep disk in sync with meta — rewrite equipped texture to Steve. + write_equipped(STEVE_PNG, "classic", None)?; + } + save_library(&lib)?; + let path = library_dir()?.join(file); + let _ = fs::remove_file(path); + Ok(()) +} + +/// Ensure Steve default bytes exist under skins/ for non-Tauri tooling. +#[allow(dead_code)] +pub fn ensure_default_assets() -> Result<(), String> { + let path = skins_root()?.join("defaults").join("steve.png"); + if let Some(parent) = path.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create defaults: {e}"))?; + } + if !path.exists() { + config::atomic_write_path(&path, STEVE_PNG)?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn steve_png_is_valid() { + validate_png(STEVE_PNG).expect("bundled steve"); + assert!(png_data_url(STEVE_PNG).starts_with("data:image/png;base64,")); + } + + #[test] + fn rejects_non_png() { + assert!(validate_png(b"not a png!!!!").is_err()); + } + + #[test] + fn rejects_wrong_dimensions() { + // Minimal IHDR with 32×32 — not a Minecraft skin size. + let mut png = vec![0x89, b'P', b'N', b'G', 0x0d, 0x0a, 0x1a, 0x0a]; + png.extend_from_slice(&13u32.to_be_bytes()); + png.extend_from_slice(b"IHDR"); + png.extend_from_slice(&32u32.to_be_bytes()); + png.extend_from_slice(&32u32.to_be_bytes()); + png.extend_from_slice(&[8, 6, 0, 0, 0]); // bit depth, RGBA, etc. + png.extend_from_slice(&[0, 0, 0, 0]); // fake crc + assert!(validate_png(&png).is_err()); + } + + #[test] + fn safe_library_filename_blocks_escape() { + assert!(safe_library_filename("../evil.png").is_err()); + assert!(safe_library_filename("ok-skin.png").is_ok()); + } + + #[test] + fn remove_equipped_rewrites_active_png() { + let _ = config::ensure_layout().expect("layout"); + let id = format!("custom-test-{}", now_secs()); + let file = format!("{id}.png"); + let dest = library_dir().unwrap().join(&file); + config::atomic_write_path(&dest, STEVE_PNG).unwrap(); + let mut lib = load_library().unwrap(); + lib.skins.push(StoredSkin { + id: id.clone(), + name: "Temp".into(), + model: "classic".into(), + file: file.clone(), + created_at: now_secs(), + }); + lib.active_id = Some(id.clone()); + save_library(&lib).unwrap(); + // Equip a non-steve texture marker by writing different bytes then applying steve copy as "custom" + write_equipped(STEVE_PNG, "classic", None).unwrap(); + // Corrupt active.png to prove rewrite happens on remove. + let active = skins_root().unwrap().join("active.png"); + config::atomic_write_path(&active, b"NOT-STEVE-ACTIVE-TEXTURE").unwrap(); + remove_skin(id).unwrap(); + let after = fs::read(&active).expect("active.png"); + assert_eq!(after, STEVE_PNG); + let lib2 = load_library().unwrap(); + assert_eq!(lib2.active_id.as_deref(), Some("default:steve")); + } +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/sync.rs b/legacy/Launcher/apps/launcher/src-tauri/src/sync.rs new file mode 100644 index 00000000000..f0b6924bbb1 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/sync.rs @@ -0,0 +1,299 @@ +use crate::api::UpdateClient; +use crate::config; +use crate::models::{PackLocalStatus, PackManifest, PackSummary, SyncProgress}; +use sha2::{Digest, Sha256}; +use std::fs; +use std::io::Write; +use std::path::{Component, Path, PathBuf}; +use tauri::{AppHandle, Emitter}; + +pub async fn list_packs(update_base_url: Option) -> Result, String> { + let client = UpdateClient::from_config_url(update_base_url.as_deref())?; + let response = client.fetch_packs().await?; + Ok(response + .packs + .into_iter() + .filter(|p| validate_pack_id(&p.id).is_ok()) + .collect()) +} + +pub fn pack_status(pack_id: &str) -> Result { + validate_pack_id(pack_id)?; + let root = instance_root(pack_id)?; + let meta_path = root.join("meta.json"); + if !meta_path.exists() { + return Ok(PackLocalStatus { + pack_id: pack_id.to_string(), + installed: false, + version: None, + ready: false, + }); + } + let raw = fs::read_to_string(&meta_path).map_err(|e| format!("Read meta.json: {e}"))?; + let manifest: PackManifest = + serde_json::from_str(&raw).map_err(|e| format!("Invalid meta.json: {e}"))?; + + let game_dir = root.join("game"); + // Libraries/assets live in shared meta/ after Theseus-style install — not only under game/. + let ready = manifest.files.iter().all(|file| { + resolve_manifest_path(&game_dir, &file.path) + .ok() + .map(|path| file_ready_on_disk(&path, file.size, &file.sha256)) + .unwrap_or(false) + }); + + Ok(PackLocalStatus { + pack_id: pack_id.to_string(), + installed: true, + version: Some(manifest.version), + ready, + }) +} + +pub async fn sync_pack( + app: AppHandle, + pack_id: String, + update_base_url: Option, +) -> Result { + validate_pack_id(&pack_id)?; + let client = UpdateClient::from_config_url(update_base_url.as_deref())?; + let packs = client.fetch_packs().await?; + let summary = packs + .packs + .into_iter() + .find(|p| p.id == pack_id) + .ok_or_else(|| format!("Pack not found: {pack_id}"))?; + + emit_progress( + &app, + SyncProgress { + pack_id: pack_id.clone(), + phase: "manifest".into(), + current_file: None, + done_files: 0, + total_files: 0, + message: format!("Загрузка манифеста · {}", client.base_url()), + file_bytes_done: None, + file_bytes_total: None, + }, + )?; + + let manifest = client.fetch_manifest(&summary.manifest_url).await?; + if manifest.id != pack_id { + return Err(format!( + "Manifest id mismatch: expected {pack_id}, got {}", + manifest.id + )); + } + + let instance = instance_root(&pack_id)?; + let game_dir = instance.join("game"); + let meta_path = instance.join("meta.json"); + + // Mark install as not ready for the duration of mutation. + if meta_path.exists() { + let _ = fs::remove_file(&meta_path); + } + fs::create_dir_all(&game_dir).map_err(|e| format!("Create game dir: {e}"))?; + + let total = manifest.files.len() as u32; + let mut done = 0u32; + + for file in &manifest.files { + emit_progress( + &app, + SyncProgress { + pack_id: pack_id.clone(), + phase: "download".into(), + current_file: Some(file.path.clone()), + done_files: done, + total_files: total, + message: format!("Скачивание {}", file.path), + file_bytes_done: None, + file_bytes_total: None, + }, + )?; + + let rel = safe_rel_path(&file.path)?; + let dest = game_dir.join(&rel); + if let Some(parent) = dest.parent() { + fs::create_dir_all(parent).map_err(|e| format!("Create parent dir: {e}"))?; + } + + if dest.exists() && file_matches_sha256(&dest, &file.sha256)? { + done += 1; + continue; + } + + let max_bytes = file + .size + .map(|s| s.saturating_add(s / 10).saturating_add(1024)) + .unwrap_or(64 * 1024 * 1024) + .min(512 * 1024 * 1024); + let pack_id_ref = pack_id.as_str(); + let path_ref = file.path.as_str(); + let expected = file.size; + let mut on_prog = |received: u64, content_len: Option| { + emit_progress( + &app, + SyncProgress { + pack_id: pack_id_ref.to_string(), + phase: "download".into(), + current_file: Some(path_ref.to_string()), + done_files: done, + total_files: total, + message: format!("Скачивание {path_ref}"), + file_bytes_done: Some(received), + file_bytes_total: expected.or(content_len), + }, + ) + }; + let bytes = client + .download_bytes_with_progress(&file.url, max_bytes, Some(&mut on_prog)) + .await?; + let hash = hex_sha256(&bytes); + if !hash.eq_ignore_ascii_case(&file.sha256) { + return Err(format!( + "SHA256 mismatch for {}: expected {}, got {}", + file.path, file.sha256, hash + )); + } + + atomic_write_bytes(&dest, &bytes)?; + done += 1; + + emit_progress( + &app, + SyncProgress { + pack_id: pack_id.clone(), + phase: "verify".into(), + current_file: Some(file.path.clone()), + done_files: done, + total_files: total, + message: format!("Проверен {}", file.path), + file_bytes_done: None, + file_bytes_total: None, + }, + )?; + } + + let meta_raw = serde_json::to_string_pretty(&manifest) + .map_err(|e| format!("Serialize meta.json: {e}"))?; + atomic_write_bytes(&meta_path, meta_raw.as_bytes())?; + + emit_progress( + &app, + SyncProgress { + pack_id: pack_id.clone(), + phase: "done".into(), + current_file: None, + done_files: done, + total_files: total, + message: "Сборка готова".into(), + file_bytes_done: None, + file_bytes_total: None, + }, + )?; + + pack_status(&pack_id) +} + +fn instance_root(pack_id: &str) -> Result { + validate_pack_id(pack_id)?; + let root = config::ensure_layout()?.join("instances").join(pack_id); + fs::create_dir_all(&root).map_err(|e| format!("Create instance dir: {e}"))?; + Ok(root) +} + +fn validate_pack_id(pack_id: &str) -> Result<(), String> { + crate::instances::validate_instance_id(pack_id).map_err(|_| "Invalid pack id".into()) +} + +fn safe_rel_path(raw: &str) -> Result { + let path = Path::new(raw); + if path.is_absolute() { + return Err(format!("Absolute paths are not allowed: {raw}")); + } + let mut out = PathBuf::new(); + for comp in path.components() { + match comp { + Component::Normal(part) => out.push(part), + Component::CurDir => {} + _ => return Err(format!("Unsafe path component in {raw}")), + } + } + if out.as_os_str().is_empty() { + return Err("Empty file path".into()); + } + Ok(out) +} + +fn resolve_manifest_path(game_dir: &Path, rel: &str) -> Result { + let preferred = config::resolve_game_or_meta(rel, game_dir)?; + if preferred.is_file() { + return Ok(preferred); + } + // Legacy installs kept libraries/assets under game/. + let legacy = game_dir.join(safe_rel_path(rel)?); + if legacy.is_file() { + return Ok(legacy); + } + Ok(preferred) +} + +/// Prefer size match when known (shared meta); fall back to SHA256 for older manifests. +fn file_ready_on_disk(path: &Path, expected_size: Option, sha256: &str) -> bool { + let Ok(meta) = fs::metadata(path) else { + return false; + }; + if !meta.is_file() { + return false; + } + if let Some(sz) = expected_size { + return meta.len() == sz; + } + file_matches_sha256(path, sha256).unwrap_or(false) +} + +fn hex_sha256(bytes: &[u8]) -> String { + let digest = Sha256::digest(bytes); + digest.iter().map(|b| format!("{b:02x}")).collect() +} + +fn file_matches_sha256(path: &Path, expected: &str) -> Result { + if !path.exists() { + return Ok(false); + } + let bytes = fs::read(path).map_err(|e| format!("Read existing file: {e}"))?; + Ok(hex_sha256(&bytes).eq_ignore_ascii_case(expected)) +} + +fn atomic_write_bytes(path: &Path, bytes: &[u8]) -> Result<(), String> { + let parent = path + .parent() + .ok_or_else(|| "Destination has no parent".to_string())?; + let tmp = parent.join(format!( + ".{}.{}.tmp", + path.file_name() + .and_then(|s| s.to_str()) + .unwrap_or("file"), + std::process::id() + )); + { + let mut file = + fs::File::create(&tmp).map_err(|e| format!("Create temp file: {e}"))?; + file.write_all(bytes) + .map_err(|e| format!("Write temp file: {e}"))?; + file.sync_all() + .map_err(|e| format!("Sync temp file: {e}"))?; + } + fs::rename(&tmp, path).map_err(|e| { + let _ = fs::remove_file(&tmp); + format!("Replace file failed: {e}") + }) +} + +fn emit_progress(app: &AppHandle, progress: SyncProgress) -> Result<(), String> { + app.emit("sync://progress", progress) + .map_err(|e| format!("Emit progress failed: {e}")) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/src/versions.rs b/legacy/Launcher/apps/launcher/src-tauri/src/versions.rs new file mode 100644 index 00000000000..03b01be600e --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/src/versions.rs @@ -0,0 +1,314 @@ +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +const MOJANG_MANIFEST: &str = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json"; +const FABRIC_GAME: &str = "https://meta.fabricmc.net/v2/versions/game"; +const FABRIC_LOADER: &str = "https://meta.fabricmc.net/v2/versions/loader"; +const QUILT_LOADER: &str = "https://meta.quiltmc.org/v3/versions/loader"; +const FORGE_META: &str = + "https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml"; +const NEOFORGE_META: &str = + "https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml"; + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct MinecraftVersion { + pub id: String, + pub version_type: String, + pub release_time: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LoaderKind { + pub id: String, + pub name: String, +} + +fn http() -> Result { + reqwest::Client::builder() + .user_agent(concat!("Owyx/", env!("CARGO_PKG_VERSION"))) + .timeout(std::time::Duration::from_secs(30)) + .connect_timeout(std::time::Duration::from_secs(10)) + .build() + .map_err(|e| format!("HTTP client error: {e}")) +} + +pub fn list_loaders() -> Vec { + vec![ + LoaderKind { + id: "vanilla".into(), + name: "Vanilla".into(), + }, + LoaderKind { + id: "fabric".into(), + name: "Fabric".into(), + }, + LoaderKind { + id: "forge".into(), + name: "Forge".into(), + }, + LoaderKind { + id: "neoforge".into(), + name: "NeoForge".into(), + }, + LoaderKind { + id: "quilt".into(), + name: "Quilt".into(), + }, + ] +} + +pub async fn list_minecraft_versions( + loader: &str, + include_snapshots: bool, +) -> Result, String> { + let loader = loader.to_ascii_lowercase(); + match loader.as_str() { + "vanilla" | "forge" | "neoforge" => list_mojang_versions(include_snapshots).await, + "fabric" => list_fabric_game_versions(include_snapshots).await, + "quilt" => { + // Quilt tracks Mojang games; filter by quilt loaders availability lazily in UI. + list_mojang_versions(include_snapshots).await + } + other => Err(format!("Unknown loader: {other}")), + } +} + +pub async fn list_loader_versions( + loader: &str, + minecraft: &str, +) -> Result, String> { + let loader = loader.to_ascii_lowercase(); + let minecraft = minecraft.trim(); + if minecraft.is_empty() { + return Err("Minecraft version is required".into()); + } + match loader.as_str() { + "vanilla" => Ok(vec![]), + "fabric" => list_fabric_loaders(minecraft).await, + "quilt" => list_quilt_loaders(minecraft).await, + "forge" => list_forge_like_versions(FORGE_META, minecraft, "forge").await, + "neoforge" => list_neoforge_versions(minecraft).await, + other => Err(format!("Unknown loader: {other}")), + } +} + +async fn list_mojang_versions(include_snapshots: bool) -> Result, String> { + let client = http()?; + let manifest: Value = client + .get(MOJANG_MANIFEST) + .send() + .await + .map_err(|e| format!("Mojang manifest fetch failed: {e}"))? + .error_for_status() + .map_err(|e| format!("Mojang manifest HTTP error: {e}"))? + .json() + .await + .map_err(|e| format!("Mojang manifest JSON error: {e}"))?; + + let versions = manifest + .get("versions") + .and_then(|v| v.as_array()) + .ok_or_else(|| "Mojang manifest missing versions[]".to_string())?; + + let mut out = Vec::new(); + for v in versions { + let id = v.get("id").and_then(|x| x.as_str()).unwrap_or_default(); + let ty = v.get("type").and_then(|x| x.as_str()).unwrap_or_default(); + if id.is_empty() { + continue; + } + if !include_snapshots && ty != "release" { + continue; + } + out.push(MinecraftVersion { + id: id.to_string(), + version_type: ty.to_string(), + release_time: v + .get("releaseTime") + .and_then(|x| x.as_str()) + .unwrap_or("") + .to_string(), + }); + } + Ok(out) +} + +async fn list_fabric_game_versions(include_snapshots: bool) -> Result, String> { + let client = http()?; + let games: Value = client + .get(FABRIC_GAME) + .send() + .await + .map_err(|e| format!("Fabric game list failed: {e}"))? + .error_for_status() + .map_err(|e| format!("Fabric game list HTTP error: {e}"))? + .json() + .await + .map_err(|e| format!("Fabric game list JSON error: {e}"))?; + + let arr = games + .as_array() + .ok_or_else(|| "Fabric game list is not an array".to_string())?; + let mut out = Vec::new(); + for v in arr { + let id = v.get("version").and_then(|x| x.as_str()).unwrap_or_default(); + let stable = v.get("stable").and_then(|x| x.as_bool()).unwrap_or(false); + if id.is_empty() { + continue; + } + if !include_snapshots && !stable { + continue; + } + out.push(MinecraftVersion { + id: id.to_string(), + version_type: if stable { + "release".into() + } else { + "snapshot".into() + }, + release_time: String::new(), + }); + } + Ok(out) +} + +async fn list_fabric_loaders(minecraft: &str) -> Result, String> { + let client = http()?; + let url = format!("{FABRIC_LOADER}/{minecraft}"); + let rows: Value = client + .get(url) + .send() + .await + .map_err(|e| format!("Fabric loader list failed: {e}"))? + .error_for_status() + .map_err(|e| format!("Fabric loader HTTP error: {e}"))? + .json() + .await + .map_err(|e| format!("Fabric loader JSON error: {e}"))?; + + let arr = rows + .as_array() + .ok_or_else(|| "Fabric loader list is not an array".to_string())?; + Ok(arr + .iter() + .filter_map(|row| { + row.get("loader") + .and_then(|l| l.get("version")) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + }) + .collect()) +} + +async fn list_quilt_loaders(minecraft: &str) -> Result, String> { + let client = http()?; + let url = format!("{QUILT_LOADER}/{minecraft}"); + let rows: Value = client + .get(&url) + .send() + .await + .map_err(|e| format!("Quilt loader list failed: {e}"))? + .error_for_status() + .map_err(|e| format!("Quilt loader HTTP error: {e}"))? + .json() + .await + .map_err(|e| format!("Quilt loader JSON error: {e}"))?; + + let arr = rows + .as_array() + .ok_or_else(|| "Quilt loader list is not an array".to_string())?; + Ok(arr + .iter() + .filter_map(|row| { + row.get("loader") + .and_then(|l| l.get("version")) + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + }) + .collect()) +} + +async fn list_forge_like_versions( + meta_url: &str, + minecraft: &str, + _kind: &str, +) -> Result, String> { + let client = http()?; + let xml = client + .get(meta_url) + .send() + .await + .map_err(|e| format!("Forge metadata fetch failed: {e}"))? + .error_for_status() + .map_err(|e| format!("Forge metadata HTTP error: {e}"))? + .text() + .await + .map_err(|e| format!("Forge metadata body error: {e}"))?; + + // Versions look like: 1.20.1-47.2.0 + let prefix = format!("{minecraft}-"); + let mut out = Vec::new(); + for line in xml.lines() { + let line = line.trim(); + let Some(inner) = line + .strip_prefix("") + .and_then(|s| s.strip_suffix("")) + else { + continue; + }; + if let Some(rest) = inner.strip_prefix(&prefix) { + if !rest.is_empty() { + out.push(rest.to_string()); + } + } + } + out.reverse(); // maven metadata is usually oldest→newest + Ok(out) +} + +async fn list_neoforge_versions(minecraft: &str) -> Result, String> { + // NeoForge versions often encode MC as maj.min in the version string (e.g. 21.1.x for 1.21.1). + let client = http()?; + let xml = client + .get(NEOFORGE_META) + .send() + .await + .map_err(|e| format!("NeoForge metadata fetch failed: {e}"))? + .error_for_status() + .map_err(|e| format!("NeoForge metadata HTTP error: {e}"))? + .text() + .await + .map_err(|e| format!("NeoForge metadata body error: {e}"))?; + + let mc_parts: Vec<&str> = minecraft.split('.').collect(); + let filter = if mc_parts.len() >= 2 { + // 1.21.1 -> 21.1 + format!("{}.{}", mc_parts[1], mc_parts.get(2).copied().unwrap_or("0")) + } else { + minecraft.to_string() + }; + + let mut out = Vec::new(); + for line in xml.lines() { + let line = line.trim(); + let Some(ver) = line + .strip_prefix("") + .and_then(|s| s.strip_suffix("")) + else { + continue; + }; + // Match "21.1" as a prefix only at a version segment boundary: + // 21.1.77 ok, 21.10.x must not match filter "21.1". + let matched = ver == filter + || ver.starts_with(&format!("{filter}.")) + || ver.starts_with(&format!("{filter}-")) + || ver.contains(&format!("-{minecraft}")); + if matched { + out.push(ver.to_string()); + } + } + out.reverse(); + Ok(out) +} diff --git a/legacy/Launcher/apps/launcher/src-tauri/tauri.conf.json b/legacy/Launcher/apps/launcher/src-tauri/tauri.conf.json new file mode 100644 index 00000000000..ec436b1b3fd --- /dev/null +++ b/legacy/Launcher/apps/launcher/src-tauri/tauri.conf.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://schema.tauri.app/config/2", + "productName": "Owyx", + "version": "0.1.0", + "identifier": "site.owyx.desktop", + "build": { + "beforeDevCommand": "npm run dev", + "devUrl": "http://localhost:1420", + "beforeBuildCommand": "npm run build", + "frontendDist": "../dist" + }, + "app": { + "windows": [ + { + "label": "main", + "title": "Owyx", + "width": 1440, + "height": 900, + "resizable": true, + "decorations": false, + "center": true, + "minWidth": 1024, + "minHeight": 640 + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": [], + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/legacy/Launcher/apps/launcher/src/browse-page.ts b/legacy/Launcher/apps/launcher/src/browse-page.ts new file mode 100644 index 00000000000..bfac867ce77 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/browse-page.ts @@ -0,0 +1,891 @@ +/** + * Dedicated Browse / Project screens (Modrinth App parity). + * Content tab CTA navigates here — no inline Modrinth search as primary UX. + * + * Patterns from modrinth/code: + * - packages/ui/.../browse-tab/layout.vue + sidebar.vue + * - apps/app-frontend/src/pages/Browse.vue + * - apps/app-frontend/src/pages/project/Index.vue + */ + +import { invoke } from "@tauri-apps/api/core"; + +export type BrowseProjectType = "mod" | "modpack" | "resourcepack" | "datapack" | "shader"; + +export type BrowseHit = { + projectId: string; + slug: string; + title: string; + description: string; + projectType: string; + downloads: number; + iconUrl?: string | null; + categories?: string[]; +}; + +export type BrowseInstanceCtx = { + id: string; + name: string; + loader: string; + minecraft: string; +}; + +export type BrowseDeps = { + t: (key: string, vars?: Record) => string; + inTauri: boolean; + isSafeModrinthMediaUrl: (raw: string) => boolean; + friendlyError: (e: unknown) => string; + prettyLoader: (id: string) => string; + onOpenProject: (hit: BrowseHit, projectType: BrowseProjectType) => void; + onBackToContent?: () => void; + setStatus: (msg: string) => void; + getInstalledProjectIds?: () => Promise>; + /** After importing a modpack as a new instance (global Discover). */ + onModpackImported?: (instanceId: string) => void | Promise; +}; + +const PAGE_SIZES = [10, 20, 50] as const; +const SORTS = [ + { id: "relevance", key: "browse.sort.relevance" }, + { id: "downloads", key: "browse.sort.downloads" }, + { id: "follows", key: "browse.sort.follows" }, + { id: "newest", key: "browse.sort.newest" }, + { id: "updated", key: "browse.sort.updated" }, +] as const; + +const TYPE_TABS: Array<{ id: BrowseProjectType; key: string }> = [ + { id: "mod", key: "browse.type.mods" }, + { id: "modpack", key: "browse.type.modpacks" }, + { id: "resourcepack", key: "browse.type.resourcepacks" }, + { id: "datapack", key: "browse.type.datapacks" }, + { id: "shader", key: "browse.type.shaders" }, +]; + +const MOD_CATEGORIES = [ + "", + "optimization", + "technology", + "adventure", + "magic", + "utility", + "decoration", + "library", + "worldgen", + "food", + "equipment", + "storage", + "transportation", +]; + +function formatDownloads(n: number): string { + if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`; + if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`; + return String(n); +} + +export function mountBrowsePage( + root: HTMLElement, + opts: { + deps: BrowseDeps; + instance: BrowseInstanceCtx | null; + projectType: BrowseProjectType; + onProjectTypeChange: (t: BrowseProjectType) => void; + }, +): void { + const { deps, instance } = opts; + let projectType = opts.projectType; + let query = ""; + let sort = "relevance"; + let pageSize: (typeof PAGE_SIZES)[number] = 20; + let offset = 0; + let total = 0; + let category = ""; + let hideInstalled = true; + let filtersLocked = Boolean(instance); + let optionalDeps = false; + let busy = false; + let searchGen = 0; + let installedIds = new Set(); + let searchTimer: number | undefined; + + const loaderLocked = filtersLocked && instance ? instance.loader : ""; + const mcLocked = filtersLocked && instance ? instance.minecraft : ""; + + root.innerHTML = ` +

+ ${ + instance + ? `
+ +
+ + +
+
` + : `
+

${deps.t("browse.discover")}

+

${deps.t("browse.discoverHint")}

+
` + } +
+
+
+
+ + + + +
+
${deps.t("browse.empty")}
+ +
+ +
+
+ `; + + if (instance) { + root.querySelector("#browse-inst-name")!.textContent = instance.name; + root.querySelector("#browse-inst-meta")!.textContent = deps.t("browse.installMeta", { + mc: instance.minecraft, + loader: deps.prettyLoader(instance.loader), + }); + } + + const queryInput = root.querySelector("#browse-query")!; + const sortSel = root.querySelector("#browse-sort")!; + const sizeSel = root.querySelector("#browse-pagesize")!; + const results = root.querySelector("#browse-results")!; + const pager = root.querySelector("#browse-pager")!; + const pageLabel = root.querySelector("#browse-page-label")!; + const lockBox = root.querySelector("#browse-locked")!; + const freeFilters = root.querySelector("#browse-free-filters")!; + const lockMc = root.querySelector("#browse-lock-mc")!; + const lockLoader = root.querySelector("#browse-lock-loader")!; + const catsEl = root.querySelector("#browse-cats")!; + + const typeLabelKey = + projectType === "mod" + ? "browse.type.mods" + : projectType === "modpack" + ? "browse.type.modpacks" + : projectType === "resourcepack" + ? "browse.type.resourcepacks" + : projectType === "datapack" + ? "browse.type.datapacks" + : "browse.type.shaders"; + queryInput.placeholder = deps.t("browse.searchPlaceholder", { + type: deps.t(typeLabelKey), + }); + + for (const s of SORTS) { + const opt = document.createElement("option"); + opt.value = s.id; + opt.textContent = deps.t(s.key); + sortSel.append(opt); + } + for (const n of PAGE_SIZES) { + const opt = document.createElement("option"); + opt.value = String(n); + opt.textContent = String(n); + if (n === pageSize) opt.selected = true; + sizeSel.append(opt); + } + + const syncLockUi = () => { + lockBox.hidden = !filtersLocked || !instance; + freeFilters.hidden = filtersLocked && Boolean(instance); + if (instance && filtersLocked) { + lockMc.textContent = instance.minecraft; + lockLoader.textContent = deps.prettyLoader(instance.loader); + } + }; + syncLockUi(); + + const paintTabs = () => { + const tabs = root.querySelector("#browse-type-tabs")!; + tabs.replaceChildren(); + const visibleTabs = instance + ? TYPE_TABS.filter((tab) => tab.id !== "modpack") + : TYPE_TABS; + for (const tab of visibleTabs) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `tab${projectType === tab.id ? " is-active" : ""}`; + btn.setAttribute("role", "tab"); + btn.setAttribute("aria-selected", projectType === tab.id ? "true" : "false"); + btn.textContent = deps.t(tab.key); + btn.addEventListener("click", () => { + if (projectType === tab.id) return; + projectType = tab.id; + opts.onProjectTypeChange(tab.id); + offset = 0; + paintTabs(); + paintCats(); + queryInput.placeholder = deps.t("browse.searchPlaceholder", { + type: deps.t(tab.key), + }); + void runSearch(); + }); + tabs.append(btn); + } + }; + + const paintCats = () => { + catsEl.replaceChildren(); + const list = projectType === "mod" ? MOD_CATEGORIES : [""]; + for (const id of list) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${category === id ? " is-selected" : ""}`; + btn.setAttribute("role", "option"); + btn.setAttribute("aria-selected", category === id ? "true" : "false"); + btn.textContent = id + ? deps.t(`instance.browseMods.cat.${id}`) + : deps.t("instance.browseMods.cat.all"); + btn.addEventListener("click", () => { + category = id; + offset = 0; + paintCats(); + void runSearch(); + }); + catsEl.append(btn); + } + }; + + const effectiveLoader = (): string => { + if (filtersLocked && instance) return instance.loader; + return root.querySelector("#browse-loader-free")?.value.trim() || loaderLocked || "fabric"; + }; + const effectiveMc = (): string => { + if (filtersLocked && instance) return instance.minecraft; + return root.querySelector("#browse-mc-free")?.value.trim() || mcLocked || ""; + }; + + const paintHits = (hits: BrowseHit[]) => { + results.replaceChildren(); + const filtered = hideInstalled + ? hits.filter((h) => !installedIds.has(h.projectId)) + : hits; + if (!filtered.length) { + results.innerHTML = `

${deps.t("browse.noResults")}

${deps.t("browse.noResultsHint")}

`; + return; + } + for (const hit of filtered) { + const card = document.createElement("article"); + card.className = "browse-card"; + card.innerHTML = ` + +
+ +
+ `; + const icon = card.querySelector(".browse-card-icon")!; + if (hit.iconUrl && deps.isSafeModrinthMediaUrl(hit.iconUrl)) { + icon.style.backgroundImage = `url(${JSON.stringify(hit.iconUrl)})`; + icon.classList.add("has-img"); + } else { + icon.textContent = hit.title.slice(0, 1).toUpperCase(); + } + card.querySelector(".browse-card-title")!.textContent = hit.title; + card.querySelector(".browse-card-desc")!.textContent = hit.description; + card.querySelector(".browse-card-meta")!.textContent = [ + formatDownloads(hit.downloads), + ...(hit.categories ?? []).slice(0, 3), + ].join(" · "); + const installed = installedIds.has(hit.projectId); + const installBtn = card.querySelector(".browse-install")!; + const isModpack = projectType === "modpack" || hit.projectType === "modpack"; + if (installed) { + installBtn.textContent = deps.t("instance.browseMods.installed"); + installBtn.classList.add("is-selected"); + installBtn.disabled = true; + } else if (!instance && !isModpack) { + installBtn.textContent = deps.t("browse.pickInstance"); + installBtn.disabled = true; + installBtn.title = deps.t("browse.pickInstanceHint"); + } else if (!instance && isModpack) { + installBtn.textContent = deps.t("browse.installModpack"); + installBtn.disabled = false; + } + card.querySelector(".browse-card-open")?.addEventListener("click", () => { + deps.onOpenProject(hit, projectType); + }); + installBtn.addEventListener("click", () => { + if (busy || installed) return; + if (isModpack && !instance) { + void installModpack(hit, installBtn); + return; + } + if (!instance) return; + void installProject(hit, installBtn); + }); + results.append(card); + } + }; + + const updatePager = () => { + const page = Math.floor(offset / pageSize) + 1; + const pages = Math.max(1, Math.ceil(total / pageSize)); + pager.hidden = total <= pageSize; + pageLabel.textContent = deps.t("browse.pageOf", { page, pages, total }); + root.querySelector("#browse-prev")!.disabled = offset <= 0; + root.querySelector("#browse-next")!.disabled = offset + pageSize >= total; + }; + + async function runSearch() { + const gen = ++searchGen; + results.textContent = deps.t("browse.searching"); + if (!deps.inTauri) { + results.innerHTML = `

${deps.t("instance.browseMods.stub")}

`; + pager.hidden = true; + return; + } + try { + if (deps.getInstalledProjectIds && instance) { + installedIds = await deps.getInstalledProjectIds(); + } + const loader = effectiveLoader(); + const mc = effectiveMc(); + const res = await invoke<{ + hits: BrowseHit[]; + offset: number; + limit: number; + totalHits: number; + stub?: boolean; + message?: string; + }>("modrinth_search", { + query: query.trim(), + limit: pageSize, + offset, + loader: loader && loader !== "vanilla" && projectType === "mod" ? loader : null, + gameVersion: mc || null, + category: category || null, + projectType, + index: sort, + }); + if (gen !== searchGen) return; + total = res.totalHits ?? 0; + if (res.stub) { + results.innerHTML = `

${escapeHtml(res.message || deps.t("instance.browseMods.stub"))}

`; + pager.hidden = true; + return; + } + paintHits(res.hits ?? []); + updatePager(); + } catch (e) { + if (gen !== searchGen) return; + results.innerHTML = `

${escapeHtml(deps.friendlyError(e))}

`; + pager.hidden = true; + } + } + + async function installModpack(hit: BrowseHit, btn: HTMLButtonElement) { + busy = true; + btn.disabled = true; + const prev = btn.textContent; + btn.textContent = deps.t("instance.browseMods.installing"); + try { + const result = await invoke<{ + instance: { id: string }; + message: string; + partial?: boolean; + }>("import_mrpack_modrinth", { + projectId: hit.projectId, + versionId: null, + }); + installedIds.add(hit.projectId); + btn.textContent = deps.t("instance.browseMods.installed"); + btn.classList.add("is-selected"); + deps.setStatus(result.message || deps.t("browse.modpackImported", { name: hit.title })); + await deps.onModpackImported?.(result.instance.id); + } catch (e) { + btn.disabled = false; + btn.textContent = prev || deps.t("browse.installModpack"); + deps.setStatus(deps.friendlyError(e)); + } finally { + busy = false; + } + } + + async function installProject(hit: BrowseHit, btn: HTMLButtonElement) { + if (!instance) return; + busy = true; + btn.disabled = true; + const prev = btn.textContent; + btn.textContent = deps.t("instance.browseMods.installing"); + try { + await invoke("modrinth_install", { + instanceId: instance.id, + projectId: hit.projectId, + loader: effectiveLoader(), + gameVersion: effectiveMc(), + includeOptionalDependencies: optionalDeps, + }); + installedIds.add(hit.projectId); + btn.textContent = deps.t("instance.browseMods.installed"); + btn.classList.add("is-selected"); + deps.setStatus(deps.t("instance.browseMods.installedMsg", { name: hit.title })); + } catch (e) { + btn.disabled = false; + btn.textContent = prev || deps.t("instance.browseMods.install"); + deps.setStatus(deps.friendlyError(e)); + } finally { + busy = false; + } + } + + root.querySelector("#browse-back")?.addEventListener("click", () => { + deps.onBackToContent?.(); + }); + root.querySelector("#browse-unlock")?.addEventListener("click", () => { + filtersLocked = !filtersLocked; + root.querySelector("#browse-unlock")!.textContent = filtersLocked + ? deps.t("browse.unlock") + : deps.t("browse.lock"); + syncLockUi(); + if (instance && !filtersLocked) { + const lf = root.querySelector("#browse-loader-free")!; + const mf = root.querySelector("#browse-mc-free")!; + lf.value = instance.loader; + mf.value = instance.minecraft; + } + offset = 0; + void runSearch(); + }); + root.querySelector("#browse-hide-installed")!.addEventListener("change", (e) => { + hideInstalled = (e.target as HTMLInputElement).checked; + void runSearch(); + }); + root.querySelector("#browse-optional-deps")!.addEventListener("change", (e) => { + optionalDeps = (e.target as HTMLInputElement).checked; + }); + sortSel.addEventListener("change", () => { + sort = sortSel.value; + offset = 0; + void runSearch(); + }); + sizeSel.addEventListener("change", () => { + pageSize = Number(sizeSel.value) as (typeof PAGE_SIZES)[number]; + offset = 0; + void runSearch(); + }); + queryInput.addEventListener("input", () => { + query = queryInput.value; + window.clearTimeout(searchTimer); + searchTimer = window.setTimeout(() => { + offset = 0; + void runSearch(); + }, 400); + }); + queryInput.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + window.clearTimeout(searchTimer); + offset = 0; + void runSearch(); + } + }); + root.querySelector("#browse-prev")?.addEventListener("click", () => { + offset = Math.max(0, offset - pageSize); + void runSearch(); + }); + root.querySelector("#browse-next")?.addEventListener("click", () => { + offset += pageSize; + void runSearch(); + }); + + paintTabs(); + paintCats(); + void runSearch(); +} + +export type ProjectDetailDeps = BrowseDeps & { + instance: BrowseInstanceCtx | null; + projectType: BrowseProjectType; + onBack: () => void; +}; + +type ProjectDetail = { + id: string; + title: string; + slug: string; + description: string; + body?: string; + downloads: number; + projectType: string; + iconUrl?: string | null; + categories?: string[]; + loaders?: string[]; + gameVersions?: string[]; + gallery?: Array<{ url: string; title?: string | null }>; + projectUrl?: string | null; +}; + +type ProjectVersionRow = { + id: string; + name: string; + versionNumber: string; + versionType: string; + loaders: string[]; + gameVersions: string[]; + downloads?: number; + datePublished?: string; + changelog?: string | null; +}; + +export function mountProjectPage(root: HTMLElement, hit: BrowseHit, deps: ProjectDetailDeps): void { + let activeTab: "description" | "gallery" | "versions" | "changelog" = "description"; + let optionalDeps = false; + let busy = false; + let projectGen = 0; + let versionsGen = 0; + let projectCache: ProjectDetail | null = null; + let versionsCache: ProjectVersionRow[] | null = null; + let versionsLoading = false; + const versionsWaiters: Array<() => void> = []; + + root.innerHTML = ` +
+ +
+ `; + + root.querySelector("#proj-title")!.textContent = hit.title; + root.querySelector("#proj-desc")!.textContent = hit.description; + root.querySelector("#proj-side-type")!.textContent = hit.projectType; + root.querySelector("#proj-side-dl")!.textContent = formatDownloads(hit.downloads); + const icon = root.querySelector("#proj-icon")!; + if (hit.iconUrl && deps.isSafeModrinthMediaUrl(hit.iconUrl)) { + icon.style.backgroundImage = `url(${JSON.stringify(hit.iconUrl)})`; + icon.classList.add("has-img"); + } else { + icon.textContent = hit.title.slice(0, 1).toUpperCase(); + } + + if (!deps.instance) { + const btn = root.querySelector("#proj-install")!; + btn.disabled = true; + btn.title = deps.t("browse.pickInstanceHint"); + } + + const ensureVersions = (afterLoad: () => void) => { + if (versionsCache) { + afterLoad(); + return; + } + if (!deps.inTauri) { + versionsCache = []; + afterLoad(); + return; + } + versionsWaiters.push(afterLoad); + if (versionsLoading) return; + versionsLoading = true; + const gen = ++versionsGen; + const flushWaiters = () => { + versionsLoading = false; + const waiters = versionsWaiters.splice(0, versionsWaiters.length); + for (const w of waiters) w(); + }; + void invoke("modrinth_project_versions", { + projectId: hit.projectId, + loader: deps.instance?.loader ?? null, + gameVersion: deps.instance?.minecraft ?? null, + }) + .then((rows) => { + if (gen === versionsGen) { + versionsCache = rows; + } + // Always flush — stale gen must not leave Changelog stuck on "searching". + flushWaiters(); + }) + .catch(() => { + if (gen === versionsGen) { + versionsCache = []; + } + flushWaiters(); + }); + }; + + const paintPane = () => { + const pane = root.querySelector("#proj-pane")!; + root.querySelectorAll("[data-ptab]").forEach((b) => { + b.classList.toggle("is-active", b.dataset.ptab === activeTab); + }); + if (activeTab === "description") { + const body = projectCache?.body || projectCache?.description || hit.description; + pane.innerHTML = `
${escapeHtml(body).replace(/\n/g, "
")}
`; + } else if (activeTab === "gallery") { + const gallery = (projectCache?.gallery ?? []).filter((g) => + deps.isSafeModrinthMediaUrl(g.url), + ); + if (!gallery.length) { + pane.innerHTML = `

${deps.t("instance.browseMods.galleryEmpty")}

`; + } else { + pane.innerHTML = ``; + } + } else if (activeTab === "changelog") { + if (!versionsCache) { + pane.innerHTML = `

${deps.t("browse.searching")}

`; + ensureVersions(() => { + if (activeTab === "changelog") paintPane(); + }); + return; + } + const entries = versionsCache.filter((v) => (v.changelog || "").trim().length > 0); + if (!entries.length) { + pane.innerHTML = `

${deps.t("instance.browseMods.changelogEmpty")}

`; + return; + } + pane.innerHTML = `
${entries + .slice(0, 40) + .map((v) => { + const title = escapeHtml(v.versionNumber || v.name); + const meta = escapeHtml( + [v.versionType, v.datePublished ? v.datePublished.slice(0, 10) : ""] + .filter(Boolean) + .join(" · "), + ); + const body = escapeHtml(v.changelog || "").replace(/\n/g, "
"); + return `

${title}

${meta}

${body}
`; + }) + .join("")}
`; + } else { + if (!versionsCache) { + pane.innerHTML = `

${deps.t("browse.searching")}

`; + ensureVersions(() => { + if (activeTab === "versions") paintPane(); + }); + return; + } + if (!versionsCache.length) { + pane.innerHTML = `

${deps.t("instance.browseMods.noVersions")}

`; + return; + } + const list = document.createElement("div"); + list.className = "mr-detail-versions"; + for (const v of versionsCache) { + const row = document.createElement("div"); + row.className = "mr-version-row"; + row.innerHTML = ` +
+ + +
+ + `; + row.querySelector("strong")!.textContent = v.versionNumber || v.name; + row.querySelector("small")!.textContent = [ + v.versionType, + v.loaders?.join(", "), + v.gameVersions?.slice(0, 4).join(", "), + v.downloads != null ? formatDownloads(v.downloads) : "", + ] + .filter(Boolean) + .join(" · "); + const btn = row.querySelector("button")!; + btn.textContent = + deps.projectType === "modpack" && !deps.instance + ? deps.t("browse.installModpack") + : deps.t("instance.browseMods.install"); + btn.disabled = busy || (!deps.instance && deps.projectType !== "modpack"); + btn.addEventListener("click", () => void installVersion(v.id, btn)); + list.append(row); + } + pane.replaceChildren(list); + } + }; + + async function installVersion(versionId: string | undefined, btn: HTMLButtonElement) { + if (busy) return; + const isModpack = deps.projectType === "modpack" || hit.projectType === "modpack"; + if (!deps.instance && !isModpack) return; + busy = true; + btn.disabled = true; + const prev = btn.textContent; + btn.textContent = deps.t("instance.browseMods.installing"); + try { + if (isModpack && !deps.instance) { + const result = await invoke<{ + instance: { id: string }; + message: string; + }>("import_mrpack_modrinth", { + projectId: hit.projectId, + versionId: versionId ?? null, + }); + btn.textContent = deps.t("instance.browseMods.installed"); + btn.classList.add("is-selected"); + deps.setStatus(result.message || deps.t("browse.modpackImported", { name: hit.title })); + await deps.onModpackImported?.(result.instance.id); + return; + } + if (!deps.instance) return; + if (versionId) { + await invoke("modrinth_install_version", { + instanceId: deps.instance.id, + versionId, + withDependencies: true, + includeOptionalDependencies: optionalDeps, + }); + } else { + await invoke("modrinth_install", { + instanceId: deps.instance.id, + projectId: hit.projectId, + loader: deps.instance.loader, + gameVersion: deps.instance.minecraft, + includeOptionalDependencies: optionalDeps, + }); + } + btn.textContent = deps.t("instance.browseMods.installed"); + btn.classList.add("is-selected"); + deps.setStatus(deps.t("instance.browseMods.installedMsg", { name: hit.title })); + } catch (e) { + btn.disabled = false; + btn.textContent = prev || deps.t("instance.browseMods.install"); + deps.setStatus(deps.friendlyError(e)); + } finally { + busy = false; + } + } + + root.querySelector("#proj-back")?.addEventListener("click", () => deps.onBack()); + root.querySelector("#proj-install")?.addEventListener("click", (e) => { + void installVersion(undefined, e.currentTarget as HTMLButtonElement); + }); + root.querySelector("#proj-optional")!.addEventListener("change", (e) => { + optionalDeps = (e.target as HTMLInputElement).checked; + }); + root.querySelectorAll("[data-ptab]").forEach((b) => { + b.addEventListener("click", () => { + activeTab = b.dataset.ptab as typeof activeTab; + paintPane(); + }); + }); + + paintPane(); + + if (deps.inTauri) { + const gen = ++projectGen; + void invoke("modrinth_get_project", { + projectId: hit.projectId, + }) + .then((p) => { + if (gen !== projectGen) return; + projectCache = p; + root.querySelector("#proj-title")!.textContent = p.title || hit.title; + root.querySelector("#proj-desc")!.textContent = p.description || hit.description; + root.querySelector("#proj-side-type")!.textContent = p.projectType || hit.projectType; + root.querySelector("#proj-side-dl")!.textContent = formatDownloads(p.downloads ?? hit.downloads); + root.querySelector("#proj-side-loaders")!.textContent = (p.loaders ?? []).join(", ") || "—"; + root.querySelector("#proj-side-mc")!.textContent = + (p.gameVersions ?? []).slice(0, 8).join(", ") || "—"; + root.querySelector("#proj-side-cats")!.textContent = (p.categories ?? []).join(", ") || "—"; + const link = root.querySelector("#proj-modrinth")!; + const href = p.projectUrl || `https://modrinth.com/${p.projectType || "mod"}/${p.slug || hit.slug}`; + link.href = deps.isSafeModrinthMediaUrl(href) ? href : "#"; + if (activeTab === "description" || activeTab === "gallery") paintPane(); + }) + .catch(() => { + /* keep hit data */ + }); + } +} + +function escapeHtml(s: string): string { + return s + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +function escapeAttr(s: string): string { + return escapeHtml(s).replace(/'/g, "'"); +} diff --git a/legacy/Launcher/apps/launcher/src/catalog.ts b/legacy/Launcher/apps/launcher/src/catalog.ts new file mode 100644 index 00000000000..86dde13913c --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/catalog.ts @@ -0,0 +1,142 @@ +// Site catalog client (servers + packs). Browser preview uses the Vite proxy; +// the packaged app goes through Rust so CORS / tauri:// origins do not matter. + +import { invoke } from "@tauri-apps/api/core"; + +export type PackSourceType = + | "http_zip" + | "http_manifest" + | "google_drive" + | "mrpack" + | "sftp" + | "local_ingest"; + +export type CatalogPack = { + id: string; + name: string; + minecraft: string; + loader: string; + iconUrl?: string | null; + description?: string; + sourceType: PackSourceType; + downloadUrl?: string | null; + sha256?: string | null; + manifestUrl?: string | null; + downloadAvailable?: boolean; +}; + +export type CatalogServer = { + id: string; + name: string; + iconUrl?: string | null; + address: string; + port: number; + kind: "owyx" | "community"; + packId?: string | null; + minecraft?: string | null; + loader?: string | null; + requiresAccount: boolean; + status?: { online?: boolean | null; players?: number | null; max?: number | null }; + pack?: CatalogPack | null; +}; + +export type CatalogLoadResult = { + servers: CatalogServer[]; + packs: CatalogPack[]; + error?: string; +}; + +const DEV_PROXY = "/proxy/owyx"; + +async function readJson(res: Response): Promise> { + try { + return (await res.json()) as Record; + } catch { + return {}; + } +} + +export async function loadCatalog(inTauri: boolean): Promise { + if (inTauri) { + try { + return await invoke("catalog_list"); + } catch (e) { + return { servers: [], packs: [], error: String(e) }; + } + } + try { + const [sRes, pRes] = await Promise.all([ + fetch(`${DEV_PROXY}/api/launcher/v1/servers`), + fetch(`${DEV_PROXY}/api/launcher/v1/packs`), + ]); + if (!sRes.ok && !pRes.ok) { + return { servers: [], packs: [], error: "network" }; + } + const sData = sRes.ok ? await readJson(sRes) : {}; + const pData = pRes.ok ? await readJson(pRes) : {}; + return { + servers: Array.isArray(sData.servers) ? (sData.servers as CatalogServer[]) : [], + packs: Array.isArray(pData.packs) ? (pData.packs as CatalogPack[]) : [], + error: sRes.ok ? undefined : "network", + }; + } catch { + return { servers: [], packs: [], error: "network" }; + } +} + +export type CatalogInstallResult = { + instanceId: string; + ready: boolean; + message: string; +}; + +export async function installCatalogServer( + inTauri: boolean, + server: CatalogServer, +): Promise { + if (!inTauri) { + return { + instanceId: `srv-${server.id}`, + ready: false, + message: "browser", + }; + } + return invoke("install_catalog_server", { + serverId: server.id, + name: server.name, + address: server.address, + port: server.port, + packId: server.packId ?? null, + minecraft: server.minecraft ?? server.pack?.minecraft ?? "1.21.1", + loader: server.loader ?? server.pack?.loader ?? "vanilla", + downloadUrl: server.pack?.downloadUrl ?? null, + sha256: server.pack?.sha256 ?? null, + manifestUrl: server.pack?.manifestUrl ?? null, + sourceType: server.pack?.sourceType ?? "http_zip", + }); +} + +export type AdminServerInput = { + name: string; + address: string; + port: number; + kind?: string; + packId?: string | null; + minecraft?: string; + loader?: string; + requiresAccount?: boolean; + published?: boolean; + iconUrl?: string | null; +}; + +export type AdminPackInput = { + name: string; + minecraft: string; + loader: string; + sourceType: PackSourceType; + url?: string; + sha256?: string; + manifestUrl?: string; + description?: string; + published?: boolean; +}; diff --git a/legacy/Launcher/apps/launcher/src/friends.ts b/legacy/Launcher/apps/launcher/src/friends.ts new file mode 100644 index 00000000000..dfbb03fd983 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/friends.ts @@ -0,0 +1,7 @@ +/** + * Friends / control-plane types. Live catalog lives in `catalog.ts`. + * Kept so older imports stay valid. + */ + +export type { CatalogPack as FriendPack, CatalogServer } from "./catalog"; +export { loadCatalog, installCatalogServer } from "./catalog"; diff --git a/legacy/Launcher/apps/launcher/src/i18n.ts b/legacy/Launcher/apps/launcher/src/i18n.ts new file mode 100644 index 00000000000..8f5303673aa --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/i18n.ts @@ -0,0 +1,35 @@ +import en from "./i18n/en.json"; +import ru from "./i18n/ru.json"; + +export type Locale = "en" | "ru"; + +const catalogs: Record> = { + en: en as Record, + ru: ru as Record, +}; + +let locale: Locale = "ru"; + +export function normalizeLocale(value?: string | null): Locale { + return value === "en" ? "en" : "ru"; +} + +export function getLocale(): Locale { + return locale; +} + +export function setLocale(next: Locale) { + locale = next; + document.documentElement.lang = next; +} + +export function t(key: string, vars?: Record): string { + const table = catalogs[locale] ?? catalogs.ru; + let text = table[key] ?? catalogs.en[key] ?? key; + if (vars) { + for (const [k, v] of Object.entries(vars)) { + text = text.replaceAll(`{${k}}`, String(v)); + } + } + return text; +} diff --git a/legacy/Launcher/apps/launcher/src/i18n/en.json b/legacy/Launcher/apps/launcher/src/i18n/en.json new file mode 100644 index 00000000000..6f961db4ee6 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/i18n/en.json @@ -0,0 +1,539 @@ +{ + "splash.boot": "Starting Owyx…", + "splash.config": "Loading config…", + "splash.profiles": "Loading profiles…", + "splash.i18n": "Loading language…", + "splash.ready": "Ready", + "nav.home": "Home", + "nav.library": "Library", + "nav.servers": "Servers", + "nav.stats": "Statistics", + "nav.settings": "Settings", + "nav.create": "New instance", + "nav.back": "Back", + "nav.forward": "Forward", + "status.ready": "Ready", + "status.error": "Error: {message}", + "download.speedUnit": "Mbit/s", + "time.never": "never played", + "time.now": "just now", + "time.minutesAgo": "{n}m ago", + "time.hoursAgo": "{n}h ago", + "time.daysAgo": "{n}d ago", + "wizard.title": "Create a game profile", + "wizard.addTitle": "Add account", + "wizard.subtitle": "You need a profile before you can play Minecraft.", + "wizard.addSubtitle": "Pick an account type. Owyx sign-in works now; Microsoft comes later. Tokens stay encrypted only.", + "wizard.kind.offline": "Offline", + "wizard.kind.offline.desc": "Enter a nick and play without a Microsoft account.", + "wizard.kind.microsoft": "Microsoft", + "wizard.kind.microsoft.desc": "Licensed Minecraft via Microsoft device-code pipeline.", + "wizard.kind.owyx": "Owyx", + "wizard.kind.owyx.desc": "Sign in with your Owyx site account. Play, skin and perks — no application needed.", + "wizard.nick": "Nick", + "wizard.nick.placeholder": "Steve", + "wizard.create": "Create profile", + "wizard.add": "Add", + "wizard.continue": "Continue", + "wizard.authSoon": "Sign-in will be available later. Profile will be saved as pending.", + "wizard.security.microsoft": "Microsoft tokens will be stored only as ciphertext on your PC (Windows DPAPI). The launcher and its author cannot decrypt them on another machine.", + "wizard.security.owyx": "Owyx sessions will be encrypted with a per-user/device key. Plaintext passwords/tokens never go to the server or repo — unlike old cracked-launcher patterns.", + "wizard.needNick": "Enter a nick (letters, numbers, _).", + "wizard.owyx.email": "Email", + "wizard.owyx.email.placeholder": "you@owyx.site", + "wizard.owyx.password": "Password", + "wizard.owyx.signIn": "Sign in", + "wizard.owyx.signingIn": "Signing in…", + "wizard.owyx.needEmail": "Enter the email of your Owyx account.", + "wizard.owyx.needPassword": "Enter your password (at least 6 characters).", + "wizard.owyx.error.network": "Could not reach Owyx. Check your internet, or play offline.", + "wizard.owyx.error.invalid_credentials": "Wrong email or password. Try again.", + "wizard.owyx.error.account_inactive": "This account is inactive. Contact support.", + "wizard.owyx.error.banned": "This account is banned, so it cannot play.", + "wizard.owyx.error.server": "Something went wrong on our side. Try again later.", + "wizard.owyx.error.no_session": "Session expired. Sign in again.", + "home.welcomeBack": "Welcome back", + "home.welcomeNew": "Welcome to Owyx", + "home.subtitleBack": "Jump back in or create a new instance.", + "home.subtitleNew": "Create your first instance with + in the left rail.", + "home.jump": "Jump back in", + "home.jumpEmpty": "Nothing to continue", + "home.jumpEmptyHint": "Create an instance with + — it shows up here and in Library.", + "home.quick.create": "Create instance", + "home.quick.library": "Open library", + "home.quick.servers": "Private servers", + "home.news": "News", + "home.news.launcher": "Launcher", + "home.news.servers": "Servers", + "home.news.brand.title": "Official brand shell", + "home.news.brand.body": "Cyan CTAs, violet selection, nested hex logo — live in this build.", + "home.news.servers.title": "Private servers", + "home.news.servers.body": "Author-hosted hubs land in Phase 2 via the control plane.", + "home.news.profiles.title": "Game profiles", + "home.news.profiles.body": "Offline, Microsoft license, and Owyx accounts — switch anytime from Home.", + "home.news.update.title": "Modrinth-like shell", + "home.news.update.body": "Rail Discover/Skins, Content → Browse content, and project detail match App IA with Owyx branding.", + "profile.title": "Profile", + "profile.playingAs": "Playing as", + "profile.select": "Active profile", + "profile.create": "Create profile…", + "profile.add": "Add account", + "profile.delete": "Delete", + "profile.signInSoon": "Sign in (soon)", + "profile.needsAuth": "Sign-in required before Play", + "profile.none": "No profile selected", + "profile.kind.offline": "Offline", + "profile.kind.microsoft": "License", + "profile.kind.owyx": "Owyx", + "profile.offlineHint": "Offline nick for this profile", + "profile.account.offline": "Offline account", + "profile.account.microsoft": "Minecraft account", + "profile.account.owyx": "Owyx account", + "play.noProfile": "Create a profile first", + "play.needsAuth": "Sign in to this profile before Play", + "play.launching": "Launching…", + "play.browser": "Play works in Owyx.exe / tauri dev", + "play.stop": "Stop", + "play.stopped": "Game stopped", + "play.exited": "Game closed", + "library.title": "Library", + "library.all": "All instances", + "library.modpacks": "Modpacks", + "library.servers": "Servers", + "library.custom": "Custom", + "library.new": "+ New instance", + "library.search": "Search", + "library.empty": "No instances found", + "library.emptyHint": "You haven't created or imported any Minecraft instances yet.", + "library.empty.modpacks": "No modded instances", + "library.empty.servers": "No server packs yet", + "library.empty.custom": "No custom vanilla instances", + "library.emptyHint.filter": "This tab is a filter. Create an instance or download a server pack.", + "library.play": "Play", + "servers.title": "Servers", + "servers.body": "Catalog from the site: download a pack and join by IP. Offline nick works unless the server requires an account.", + "servers.status.planned": "Planned", + "servers.status.beta": "Beta", + "servers.feat.private.title": "Private servers", + "servers.feat.private.body": "Dedicated author-hosted servers and community hubs, launchable straight from Owyx.", + "servers.feat.friends.title": "Friend packs", + "servers.feat.friends.body": "Subscribe to a friend's modpack by manifest and stay in sync as they update it.", + "servers.feat.controlPlane.title": "Control-plane", + "servers.feat.controlPlane.body": "A small hosted API distributes packs and server settings; the launcher just reads them.", + "servers.loading": "Loading catalog…", + "servers.empty.title": "No servers yet", + "servers.empty.body": "An admin has not published cards yet. The site is up — the list is just empty.", + "servers.offline.title": "Site unavailable", + "servers.offline.body": "Could not load the catalog. Check OWYX_API_BASE_URL or play offline from Library.", + "servers.download": "Download", + "servers.update": "Update", + "servers.play": "Play", + "servers.downloading": "Downloading pack…", + "servers.downloaded": "Pack ready", + "servers.needAccount": "This server asks you to sign in with an Owyx account.", + "servers.accountRequired": "Account required", + "servers.online": "Online", + "servers.offline": "Offline", + "servers.players": "{players}/{max} players", + "servers.statusUnknown": "Status not checked", + "servers.packUnavailable": "This pack is not available for download yet.", + "servers.mrpackUnsupported": "mrpack overlay failed — check pack URL / hash.", + "servers.unknownVersion": "version not set", + "servers.admin.add": "Add server", + "servers.admin.name": "Name", + "servers.admin.address": "Address", + "servers.admin.port": "Port", + "servers.admin.minecraft": "Minecraft", + "servers.admin.loader": "Loader", + "servers.admin.packUrl": "HTTP zip of the pack (optional)", + "servers.admin.packCap": "Launcher download cap is 512 MB (not streamed). Larger packs stay in backlog.", + "servers.admin.saving": "Saving…", + "servers.admin.created": "Server added to the catalog", + "servers.admin.needAdmin": "Sign in as an Owyx admin first.", + "skin.applied": "Account skin saved to the profile folder", + "common.cancel": "Cancel", + "common.close": "Close", + "common.save": "Save", + "win.minimize": "Minimize", + "win.maximize": "Maximize", + "win.close": "Close", + "stats.title": "Statistics", + "stats.body": "Launcher-wide and per-instance stats will land here later.", + "stats.soon": "Coming soon", + "settings.appearance": "Appearance", + "settings.java": "Java installations", + "settings.behavior": "Behavior", + "settings.localization": "Localization", + "settings.updates": "Updates", + "settings.java.desc": "Per-major Java path. Detect / Install / Browse — Modrinth-style.", + "settings.java.detect": "Detect", + "settings.java.browse": "Browse", + "settings.java.installRec": "Install recommended", + "settings.java.installing": "Installing Java {n}…", + "settings.java.installed": "Java {n} installed", + "settings.java.location": "Java {n} location", + "settings.java.selectTitle": "Select Java installation", + "settings.java.detecting": "Detecting Java…", + "settings.java.noneMajor": "Java {n} not found. Install or browse to a path.", + "settings.java.select": "Select", + "settings.java.selected": "Selected", + "settings.java.none": "No saved Java yet. Click Detect.", + "settings.java.saved": "Saved: {n}", + "settings.java.detected": "Detected & saved: {n}", + "meta.wait": "Shared libraries/assets are still downloading — wait (may take several minutes)", + "meta.prefetching": "Downloading shared Minecraft libraries…", + "meta.failedContinue": "Meta prefetch incomplete — Play allowed for already-ready instances", + "create.loadingVersions": "Loading versions…", + "instance.settings.groupHint": "Library groups organize instances in the library.", + "instance.settings.newGroup": "New group…", + "instance.settings.createGroup": "Create", + "instance.settings.channel.release": "Stable updates only.", + "instance.settings.channel.beta": "Beta modpack channels.", + "instance.settings.channel.alpha": "Alpha / early builds.", + "instance.settings.platform": "Platform", + "instance.settings.change": "Change", + "instance.settings.changeWarn": "Changing versions after installing content may break mods.", + "instance.settings.changeTitle": "Change installation", + "instance.settings.cancel": "Cancel", + "instance.settings.repair": "Repair", + "instance.settings.repairHint": "Reinstalls this instance's client, libraries and assets.", + "instance.settings.repairBtn": "Repair", + "instance.settings.repairing": "Repairing…", + "instance.settings.javaInstall": "Java installation", + "instance.settings.overrideJava": "Custom Java installation", + "instance.settings.overrideMemory": "Custom memory allocation", + "instance.settings.overrideJvm": "Custom Java arguments", + "instance.settings.overrideEnv": "Custom environment variables", + "instance.settings.envVars": "Environment variables", + "instance.settings.overrideHooks": "Custom launch hooks", + "instance.settings.hooksHint": "Run commands before/after launch and wrap the process.", + "instance.settings.preLaunchPh": "Enter pre-launch command…", + "instance.settings.preLaunchHint": "Ran before the instance is launched.", + "instance.settings.wrapperPh": "Enter wrapper command…", + "instance.settings.wrapperHint": "Wrapper command for launching Minecraft.", + "instance.settings.postExitPh": "Enter post-exit command…", + "instance.settings.postExitHint": "Ran after the game closes.", + "settings.locale.desc": "Language for the launcher UI.", + "settings.locale.ru": "Русский", + "settings.locale.en": "English", + "settings.updates.desc": "Automatic EXE updates will use this channel later.", + "settings.updates.check": "Check for updates", + "settings.updates.stub": "Updater is not wired yet. Channel: {channel}", + "settings.updates.channel": "Channel", + "create.title": "New instance", + "create.name": "Name", + "create.loader": "Loader", + "create.gameVersion": "Game version", + "create.loaderVersion": "{loader} version", + "create.noVersions": "No versions", + "create.snapshots": "Show snapshots", + "create.showAllVersions": "Show all versions", + "create.hideSnapshots": "Hide snapshots", + "create.searchVersion": "Search versions…", + "create.toggleVersions": "Toggle version list", + "create.selectIcon": "Select icon", + "create.removeIcon": "Remove icon", + "create.submit": "Create", + "create.cancel": "Cancel", + "create.needMc": "Choose a Minecraft version", + "create.needLoader": "Choose a loader version", + "create.mcCount": "MC versions: {n}", + "create.preparing": "Creating instance…", + "instance.content": "Content", + "instance.files": "Files", + "instance.worlds": "Worlds", + "instance.logs": "Logs", + "instance.share": "Share", + "instance.play": "Play", + "instance.settings": "Instance settings", + "instance.more": "More", + "instance.openFolder": "Open instance folder…", + "instance.dup": "Duplicate", + "instance.delete": "Delete", + "instance.browseMods": "Browse mods (Modrinth)", + "instance.browseMods.hint": "Search Modrinth and install a compatible file straight into this instance.", + "instance.browseMods.search": "Search mods…", + "instance.browseMods.empty": "Type a query to search Modrinth projects.", + "instance.browseMods.stub": "Search + install work in Owyx.exe / tauri dev (native network).", + "instance.browseMods.install": "Install", + "instance.browseMods.installing": "Installing…", + "instance.browseMods.installed": "Installed", + "instance.browseMods.installedMsg": "Installed {name} into this instance", + "instance.browseMods.versions": "Versions", + "instance.browseMods.noVersions": "No compatible versions", + "instance.browseMods.deps": "{n} deps", + "instance.browseMods.optionalDeps": "Install optional dependencies", + "instance.browseMods.optionalCount": "{n} optional", + "instance.browseMods.conflictCount": "{n} conflicts", + "instance.browseMods.filterLoader": "Loader", + "instance.browseMods.filterMc": "MC", + "instance.browseMods.loadMore": "Load more", + "instance.browseMods.back": "Back to results", + "instance.browseMods.searchBtn": "Search", + "instance.browseMods.searchHint": "Press Enter or Search — typing also searches after a short pause.", + "instance.browseMods.categories": "Categories", + "instance.browseMods.cat.all": "All", + "instance.browseMods.cat.optimization": "Optimization", + "instance.browseMods.cat.technology": "Technology", + "instance.browseMods.cat.adventure": "Adventure", + "instance.browseMods.cat.magic": "Magic", + "instance.browseMods.cat.utility": "Utility", + "instance.browseMods.cat.decoration": "Decoration", + "instance.browseMods.cat.library": "Library", + "instance.browseMods.cat.worldgen": "Worldgen", + "instance.browseMods.cat.food": "Food", + "instance.browseMods.cat.equipment": "Equipment", + "instance.browseMods.cat.storage": "Storage", + "instance.browseMods.cat.transportation": "Transport", + "instance.browseMods.tab.description": "Description", + "instance.browseMods.tab.gallery": "Gallery", + "instance.browseMods.tab.changelog": "Changelog", + "instance.browseMods.tab.versions": "Versions", + "instance.browseMods.galleryEmpty": "No gallery images for this project.", + "instance.browseMods.changelogEmpty": "No version changelogs available for this project.", + "instance.browseMods.sidebar.info": "About", + "instance.browseMods.sidebar.type": "Type", + "instance.browseMods.sidebar.downloads": "Downloads", + "instance.browseMods.sidebar.loaders": "Loaders", + "instance.browseMods.sidebar.mc": "Minecraft", + "instance.browseMods.sidebar.categories": "Categories", + "instance.browseMods.sidebar.openModrinth": "Open on Modrinth", + "instance.browseMods.open": "Open", + "instance.status.pending": "not installed", + "instance.status.installing": "installing", + "instance.status.ready": "ready", + "instance.status.error": "error", + "instance.waitInstall": "Wait for install to finish", + "instance.installing": "Installing…", + "instance.installDone": "Ready", + "instance.installFail": "Install did not finish", + "instance.settings.crumb": "Settings", + "instance.settings.general": "General", + "instance.settings.install": "Installation", + "instance.settings.window": "Window", + "instance.settings.java": "Java & memory", + "instance.settings.launch": "Launch commands", + "instance.settings.name": "Name", + "instance.settings.group": "Group", + "instance.settings.groupPlaceholder": "No group", + "instance.settings.channel": "Update channel", + "instance.settings.channelHint": "UI only for now — install pipeline hooks in later.", + "instance.settings.save": "Save", + "instance.settings.saved": "Saved", + "instance.settings.back": "Back", + "instance.settings.delete": "Delete instance", + "instance.settings.installDesc": "Current platform (version switching after install pipeline).", + "instance.settings.loader": "Loader", + "instance.settings.minecraft": "Minecraft", + "instance.settings.loaderVersion": "Loader version", + "instance.settings.width": "Width", + "instance.settings.height": "Height", + "instance.settings.memory": "Memory (MB)", + "instance.settings.javaPath": "Java path", + "instance.settings.jvmArgs": "JVM arguments", + "instance.settings.preLaunch": "Pre-launch", + "instance.settings.wrapper": "Wrapper", + "instance.settings.postExit": "Post-exit", + "instance.files.loading": "Loading files…", + "instance.logs.source": "Log source", + "instance.logs.filter": "Log level filter", + "instance.logs.filterAll": "All", + "instance.logs.filterError": "Error", + "instance.logs.filterWarn": "Warn", + "instance.logs.filterInfo": "Info", + "instance.logs.search": "Search logs…", + "instance.logs.openFolder": "Open logs folder", + "instance.logs.refresh": "Refresh", + "instance.logs.loading": "Loading log…", + "instance.logs.emptyTitle": "No live output yet", + "instance.logs.emptyHint": "Start the instance with Play to stream console output here.", + "instance.logs.noMatches": "No matching lines.", + "wizard.authBrowser": "Sign in with Microsoft", + "content.enabled": "enabled", + "content.disabled": "disabled", + "common.refresh": "Refresh", + "common.delete": "Delete", + "common.open": "Open", + "error.installRunning": "Another install is already running — please wait", + "error.cantDeleteInstalling": "Can't delete while installing", + "error.cantDupInstalling": "Can't duplicate while installing", + "error.hostNotAllowed": "Downloads from this host are blocked", + "error.fileTooLarge": "File is too large", + "error.notReady": "Instance isn't installed yet — press Play and I'll install then launch it", + "error.contentExists": "This file is already in the instance", + "error.inferType": "Couldn't detect the file type (need a mod/pack jar or zip)", + "error.sourceNotFound": "File not found", + "error.noCompatVersion": "No compatible version for this loader / Minecraft version", + "error.hashFail": "Download failed integrity (SHA-512) check — try again", + "error.noFile": "This project has no downloadable file", + "error.javaMissing": "Compatible Java not found — install or detect Java in Settings", + "error.nickInvalid": "Nick may only contain letters, numbers and _", + "error.mcRequired": "Choose a Minecraft version", + "error.loaderRequired": "Choose a loader version", + "error.unsupportedLoader": "This loader is not supported", + "error.modLoaderInstall": "Mod loader install failed — try another loader version", + "error.noJars": "Instance has no client jars — reinstall it (Repair)", + "error.timeout": "Operation timed out — check your connection and retry", + "error.integrity": "A downloaded file failed verification — retry the install", + "error.network": "Network error — check your connection and retry", + "library.sort.name": "Sort: name", + "library.sort.played": "Sort: last played", + "library.sort.created": "Sort: created", + "library.group.none": "Group: none", + "library.group.group": "Group: group", + "library.group.loader": "Group: loader", + "library.group.ungrouped": "Ungrouped", + "content.search": "Search…", + "content.addFiles": "Upload files", + "content.openMods": "Open mods/", + "content.enableAll": "Enable all", + "content.disableAll": "Disable all", + "content.filter.all": "All", + "content.filter.mods": "Mods", + "content.filter.resourcepacks": "Resource packs", + "content.filter.shaders": "Shaders", + "content.filter.datapacks": "Data packs", + "content.filter.enabled": "Enabled", + "content.filter.disabled": "Disabled", + "content.emptyTitle": "No content yet", + "content.emptyHint": "Click “Add files” or drop mods into game/mods and press Refresh.", + "content.noMatch": "Nothing matches this filter.", + "content.colProject": "Project", + "content.colFile": "File", + "content.colActions": "Actions", + "content.toggleTitle": "Enable/disable", + "content.deleteAria": "Delete mod {name}", + "content.addBrowser": "Adding files works in Owyx.exe / tauri dev", + "content.addDialogTitle": "Add mods / packs", + "content.added1": "File added to the instance", + "content.addedN": "Files added: {n}", + "content.kind.mod": "Mod", + "content.kind.resourcepack": "Resource pack", + "content.kind.datapack": "Data pack", + "content.kind.shader": "Shader", + "share.title": "Share instance", + "share.body": "Profile export / modpack link will appear after the install + sync backend.", + "files.openRoot": "Open instance folder", + "files.openGame": "Open game/", + "files.openBrowser": "Opening folders works only in Tauri", + "files.browser": "The file list is available in the built launcher.", + "files.emptyTitle": "Folder is empty", + "files.emptyHint": "After install, libraries, assets and mods appear here.", + "worlds.search": "Search worlds…", + "worlds.openSaves": "Open saves/", + "worlds.emptyTitle": "No worlds yet", + "worlds.emptyHint": "After playing, saves appear in game/saves. Press Refresh.", + "worlds.noMatch": "Nothing found.", + "worlds.deleteTitle": "Delete from disk", + "worlds.deleteAria": "Delete world {name}", + "instance.logs.browser": "Logs are available in the built launcher (%USERPROFILE%\\owyx\\logs).", + "instance.copying": "Copying instance…", + "instance.copied": "Copy created", + "nav.browse": "Discover", + "nav.skins": "Skins", + "browse.discover": "Discover content", + "browse.discoverHint": "Search Modrinth projects. Install into an instance from Content → Browse content.", + "browse.contentInstall": "Content install", + "browse.installMeta": "Installing content · Minecraft {mc} · {loader}", + "browse.back": "Back to content", + "browse.searchPlaceholder": "Search {type}…", + "browse.sortLabel": "Sort", + "browse.sort.relevance": "Relevance", + "browse.sort.downloads": "Downloads", + "browse.sort.follows": "Followers", + "browse.sort.newest": "Date published", + "browse.sort.updated": "Date updated", + "browse.pageSize": "View", + "browse.filters": "Filters", + "browse.hideInstalled": "Hide content already installed", + "browse.gameVersion": "Game version", + "browse.loader": "Loader", + "browse.unlock": "Unlock", + "browse.lock": "Lock to instance", + "browse.categories": "Categories", + "browse.empty": "Loading projects…", + "browse.searching": "Searching…", + "browse.noResults": "No projects found", + "browse.noResultsHint": "Try another query or unlock filters.", + "browse.prev": "Previous", + "browse.next": "Next", + "browse.pageOf": "Page {page} / {pages} · {total}", + "browse.type.mods": "Mods", + "browse.type.resourcepacks": "Resource packs", + "browse.type.datapacks": "Data packs", + "browse.type.shaders": "Shaders", + "browse.pickInstance": "Pick instance", + "browse.pickInstanceHint": "Open an instance → Content → Browse content to install.", + "content.browseContent": "Browse content", + "content.uploadFiles": "Upload files", + "content.searchN": "Search {n} projects…", + "content.emptyHintBrowse": "Browse Modrinth or upload files to get started.", + "skins.title": "Skin selector", + "skins.subtitle": "Preview, import, and apply skins. Owyx account skins sync from the site.", + "skins.saved": "Saved skins", + "skins.import": "Import PNG", + "skins.add": "Add skin", + "skins.owyx": "Owyx account", + "skins.owyxHint": "Apply the skin from your Owyx profile (/me) to disk for Minecraft.", + "skins.applyOwyx": "Apply Owyx skin", + "skins.apply": "Apply", + "skins.remove": "Remove", + "skins.removed": "Skin removed", + "skins.equipped": "Equipped", + "skins.applied": "Skin applied", + "skins.playingAs": "Playing as {nick}", + "skins.noProfile": "No profile", + "skins.defaultSteve": "Steve", + "skins.needOwyx": "Sign in with an Owyx account first", + "skins.importBrowser": "Import works in the native app", + "skins.imported": "Skin imported to library", + "skins.importedPath": "Selected {path}", + "create.next": "Continue", + "create.back": "Back", + "create.step.loader": "Loader", + "create.step.mc": "Minecraft version", + "create.step.loaderVer": "Loader version", + "create.step.name": "Name", + "create.step.icon": "Icon", + "create.vanillaNoLoader": "Vanilla has no loader version — continue.", + "create.setupTypeHint": "How do you want to set up this instance?", + "create.type.custom": "Custom", + "create.type.customDesc": "Pick loader, Minecraft version, name and icon.", + "create.type.modpack": "Browse modpacks", + "create.type.importMrpack": "Import .mrpack", + "create.type.modpackDesc": "Discover or import a Modrinth pack (game jars still install on Play).", + "create.importMrpackBrowser": "mrpack import works in the native app", + "create.importMrpackWorking": "Importing modpack…", + "browse.installModpack": "Install pack", + "browse.modpackImported": "Imported {name}", + "skins.importPartial": "Capes / Mojang equip API deferred; local library + Owyx /me apply are live.", + "wizard.ms.pipelineTitle": "Starts the Microsoft device-code pipeline", + "wizard.ms.starting": "Starting Microsoft sign-in…", + "wizard.ms.waiting": "Waiting for Microsoft…", + "wizard.ms.unconfigured": "Microsoft client id is not configured", + "wizard.ms.unconfiguredHint": "Owner must set MICROSOFT_CLIENT_ID — see docs/MICROSOFT_AUTH.md", + "wizard.ms.codeHint": "Code {code} — open {uri}", + "wizard.ms.error": "Microsoft sign-in failed", + "wizard.ms.cancel": "Cancel sign-in", + "wizard.ms.cancelled": "Sign-in cancelled", + "wizard.ms.retry": "Retry Microsoft sign-in", + "settings.appearance.desc": "Owyx brand tokens (cyan on deep space). Theme editor comes later.", + "settings.appearance.tokens": "bg #050508 · panel #131319 · accent #00e5ff", + "settings.behavior.desc": "Launcher behavior toggles (stubs match Modrinth settings IA).", + "settings.behavior.closeToTray": "Minimize instead of quit (soon)", + "settings.behavior.keepLogs": "Keep launch logs", + "settings.behavior.stub": "These toggles are reserved; values are not persisted yet.", + "share.localHint": "Modrinth friends/cloud sharing is not ported. Share the instance name or open the folder.", + "share.mrpackHint": "Export a local .mrpack (overrides-based; no Modrinth CDN mirrors).", + "share.exportMrpack": "Export .mrpack", + "share.exportBrowser": "Export works in the native app", + "share.copyName": "Copy instance name", + "share.copied": "Name copied", + "wizard.ms.scaffold": "Microsoft token exchange is not wired yet", + "wizard.ms.scaffoldHint": "CLIENT_ID may be set, but Xbox/Minecraft tokens are not exchanged. See docs/MICROSOFT_AUTH.md — no fake device code is shown.", + "wizard.ms.success": "Microsoft account linked", + "wizard.ms.successHint": "Profile stored with opaque auth blob. Offline and Owyx logins still work separately.", + "wizard.ms.successPending": "Microsoft profile saved as pending auth", + "wizard.ms.successPendingHint": "Token exchange is incomplete — profile keeps needsAuth until real tokens exist.", + "browse.type.modpacks": "Modpacks" +} diff --git a/legacy/Launcher/apps/launcher/src/i18n/ru.json b/legacy/Launcher/apps/launcher/src/i18n/ru.json new file mode 100644 index 00000000000..67a99bca402 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/i18n/ru.json @@ -0,0 +1,539 @@ +{ + "splash.boot": "Запуск Owyx…", + "splash.config": "Загрузка конфигурации…", + "splash.profiles": "Загрузка профилей…", + "splash.i18n": "Загрузка языка…", + "splash.ready": "Готово", + "nav.home": "Главная", + "nav.library": "Библиотека", + "nav.servers": "Серверы", + "nav.stats": "Статистика", + "nav.settings": "Настройки", + "nav.create": "Новая сборка", + "nav.back": "Назад", + "nav.forward": "Вперёд", + "status.ready": "Готово", + "status.error": "Ошибка: {message}", + "download.speedUnit": "Мбит/с", + "time.never": "ещё не запускалась", + "time.now": "только что", + "time.minutesAgo": "{n} мин. назад", + "time.hoursAgo": "{n} ч. назад", + "time.daysAgo": "{n} дн. назад", + "wizard.title": "Создайте игровой профиль", + "wizard.addTitle": "Добавить аккаунт", + "wizard.subtitle": "Без профиля запустить Minecraft нельзя.", + "wizard.addSubtitle": "Выберите тип аккаунта. Вход Owyx уже работает; Microsoft — позже. Токены хранятся только зашифрованными.", + "wizard.kind.offline": "Оффлайн", + "wizard.kind.offline.desc": "Введите ник и играйте без аккаунта Microsoft.", + "wizard.kind.microsoft": "Microsoft", + "wizard.kind.microsoft.desc": "Лицензия Minecraft через pipeline Microsoft.", + "wizard.kind.owyx": "Owyx", + "wizard.kind.owyx.desc": "Вход по аккаунту сайта Owyx. Игра, скин и плюшки — без заявок.", + "wizard.nick": "Ник", + "wizard.nick.placeholder": "Steve", + "wizard.create": "Создать профиль", + "wizard.add": "Добавить", + "wizard.continue": "Продолжить", + "wizard.authSoon": "Авторизация появится позже. Профиль сохранится как ожидающий вход.", + "wizard.security.microsoft": "Токены Microsoft будут храниться только как шифр на вашем ПК (Windows DPAPI). Лаунчер и его автор не смогут их расшифровать на другом устройстве.", + "wizard.security.owyx": "Сессия Owyx будет шифроваться ключом устройства/пользователя. На сервер и в репозиторий plaintext-пароли и токены не попадут — в отличие от схем вроде старых «пиратских» лаунчеров.", + "wizard.needNick": "Введите ник (буквы, цифры, _).", + "wizard.owyx.email": "Email", + "wizard.owyx.email.placeholder": "you@owyx.site", + "wizard.owyx.password": "Пароль", + "wizard.owyx.signIn": "Войти", + "wizard.owyx.signingIn": "Вход…", + "wizard.owyx.needEmail": "Введите email вашего аккаунта Owyx.", + "wizard.owyx.needPassword": "Введите пароль (минимум 6 символов).", + "wizard.owyx.error.network": "Не удалось связаться с Owyx. Проверьте интернет или играйте оффлайн.", + "wizard.owyx.error.invalid_credentials": "Неверный email или пароль. Попробуйте ещё раз.", + "wizard.owyx.error.account_inactive": "Аккаунт неактивен. Обратитесь в поддержку.", + "wizard.owyx.error.banned": "Аккаунт заблокирован — играть нельзя.", + "wizard.owyx.error.server": "Что-то пошло не так на нашей стороне. Попробуйте позже.", + "wizard.owyx.error.no_session": "Сессия истекла. Войдите снова.", + "home.welcomeBack": "С возвращением", + "home.welcomeNew": "Добро пожаловать в Owyx", + "home.subtitleBack": "Продолжите игру или создайте новую сборку.", + "home.subtitleNew": "Создайте первую сборку кнопкой + слева.", + "home.jump": "Продолжить", + "home.jumpEmpty": "Пока нечего продолжать", + "home.jumpEmptyHint": "Создайте сборку через + — она появится здесь и в Библиотеке.", + "home.quick.create": "Создать сборку", + "home.quick.library": "Открыть библиотеку", + "home.quick.servers": "Приватные серверы", + "home.news": "Новости", + "home.news.launcher": "Лаунчер", + "home.news.servers": "Серверы", + "home.news.brand.title": "Официальный бренд", + "home.news.brand.body": "Cyan CTA, violet-выделение, hex-логотип — уже в этом билде.", + "home.news.servers.title": "Приватные серверы", + "home.news.servers.body": "Авторские хабы появятся в Phase 2 через control plane.", + "home.news.profiles.title": "Игровые профили", + "home.news.profiles.body": "Оффлайн, лицензия Microsoft и Owyx — переключение на Главной.", + "home.news.update.title": "Оболочка как у Modrinth App", + "home.news.update.body": "Rail Обзор/Скины, Контент → Найти проекты и карточка проекта — с брендом Owyx.", + "profile.title": "Профиль", + "profile.playingAs": "Играете как", + "profile.select": "Активный профиль", + "profile.create": "Создать профиль…", + "profile.add": "Добавить аккаунт", + "profile.delete": "Удалить", + "profile.signInSoon": "Войти (скоро)", + "profile.needsAuth": "Нужен вход перед Play", + "profile.none": "Профиль не выбран", + "profile.kind.offline": "Оффлайн", + "profile.kind.microsoft": "Лицензия Minecraft", + "profile.kind.owyx": "Аккаунт Owyx", + "profile.offlineHint": "Оффлайн-ник этого профиля", + "profile.account.offline": "Оффлайн-аккаунт", + "profile.account.microsoft": "Аккаунт Minecraft", + "profile.account.owyx": "Аккаунт Owyx", + "play.noProfile": "Сначала создайте профиль", + "play.needsAuth": "Войдите в профиль перед Play", + "play.launching": "Запуск…", + "play.browser": "Play работает в Owyx.exe / tauri dev", + "play.stop": "Остановить", + "play.stopped": "Игра остановлена", + "play.exited": "Игра закрыта", + "library.title": "Библиотека", + "library.all": "Все сборки", + "library.modpacks": "Модпаки", + "library.servers": "Серверы", + "library.custom": "Свои", + "library.new": "+ Новая сборка", + "library.search": "Поиск", + "library.empty": "Сборок нет", + "library.emptyHint": "Вы ещё не создали и не импортировали сборки Minecraft.", + "library.empty.modpacks": "Нет модовых сборок", + "library.empty.servers": "Нет сборок с серверов", + "library.empty.custom": "Нет своих ванильных сборок", + "library.emptyHint.filter": "Это фильтр. Создайте сборку или скачайте пак с вкладки Серверы.", + "library.play": "Играть", + "servers.title": "Серверы", + "servers.body": "Каталог с сайта: скачай сборку и заходи по IP. Offline-ник работает, если сервер не требует аккаунт.", + "servers.status.planned": "Планируется", + "servers.status.beta": "Бета", + "servers.feat.private.title": "Приватные серверы", + "servers.feat.private.body": "Авторские сервера и комьюнити-хабы, запуск прямо из Owyx.", + "servers.feat.friends.title": "Паки друзей", + "servers.feat.friends.body": "Подпишись на модпак друга по манифесту и оставайся в синхроне при обновлениях.", + "servers.feat.controlPlane.title": "Control-plane", + "servers.feat.controlPlane.body": "Небольшой хостед API раздаёт сборки и настройки серверов; лаунчер просто их читает.", + "servers.loading": "Загрузка каталога…", + "servers.empty.title": "Пока нет серверов", + "servers.empty.body": "Админ ещё не опубликовал карточки. Сайт доступен — список просто пустой.", + "servers.offline.title": "Сайт недоступен", + "servers.offline.body": "Не удалось получить каталог. Проверьте OWYX_API_BASE_URL или играйте оффлайн в Библиотеке.", + "servers.download": "Скачать", + "servers.update": "Обновить", + "servers.play": "Играть", + "servers.downloading": "Качаем сборку…", + "servers.downloaded": "Сборка готова", + "servers.needAccount": "Этот сервер просит вход в аккаунт Owyx.", + "servers.accountRequired": "Нужен аккаунт", + "servers.online": "Онлайн", + "servers.offline": "Офлайн", + "servers.players": "{players}/{max} игроков", + "servers.statusUnknown": "Статус не проверен", + "servers.packUnavailable": "Сборка пока недоступна для скачивания.", + "servers.mrpackUnsupported": "Не удалось поставить mrpack — проверь URL / hash.", + "servers.unknownVersion": "версия не указана", + "servers.admin.add": "Добавить сервер", + "servers.admin.name": "Название", + "servers.admin.address": "Адрес", + "servers.admin.port": "Порт", + "servers.admin.minecraft": "Minecraft", + "servers.admin.loader": "Лоадер", + "servers.admin.packUrl": "HTTP zip сборки (необязательно)", + "servers.admin.packCap": "Лимит качки в лаунчере — 512 МБ (без стрима). Большие паки — в backlog.", + "servers.admin.saving": "Сохраняем…", + "servers.admin.created": "Сервер добавлен в каталог", + "servers.admin.needAdmin": "Нужен вход админом Owyx.", + "skin.applied": "Скин аккаунта сохранён в профиль", + "common.cancel": "Отмена", + "common.close": "Закрыть", + "common.save": "Сохранить", + "win.minimize": "Свернуть", + "win.maximize": "Развернуть", + "win.close": "Закрыть", + "stats.title": "Статистика", + "stats.body": "Общая статистика лаунчера и сборок появится здесь позже.", + "stats.soon": "Скоро", + "settings.appearance": "Оформление", + "settings.java": "Установки Java", + "settings.behavior": "Поведение", + "settings.localization": "Язык", + "settings.updates": "Обновления", + "settings.java.desc": "Путь к Java по мажорной версии. Detect / Install / Browse — как в Modrinth.", + "settings.java.detect": "Найти", + "settings.java.browse": "Обзор", + "settings.java.installRec": "Установить рекомендуемую", + "settings.java.installing": "Установка Java {n}…", + "settings.java.installed": "Java {n} установлена", + "settings.java.location": "Расположение Java {n}", + "settings.java.selectTitle": "Выберите установку Java", + "settings.java.detecting": "Поиск Java…", + "settings.java.noneMajor": "Java {n} не найдена. Установите или укажите путь.", + "settings.java.select": "Выбрать", + "settings.java.selected": "Выбрано", + "settings.java.none": "Java ещё не сохранена. Нажмите «Найти».", + "settings.java.saved": "Сохранено: {n}", + "settings.java.detected": "Найдено и сохранено: {n}", + "meta.wait": "Общие библиотеки/ассеты ещё качаются — подождите (может занять несколько минут)", + "meta.prefetching": "Загрузка общих библиотек Minecraft…", + "meta.failedContinue": "Prefetch meta не завершён — Play для уже установленных сборок разрешён", + "create.loadingVersions": "Загрузка версий…", + "instance.settings.groupHint": "Группы помогают сортировать сборки в библиотеке.", + "instance.settings.newGroup": "Новая группа…", + "instance.settings.createGroup": "Создать", + "instance.settings.channel.release": "Только стабильные обновления.", + "instance.settings.channel.beta": "Бета-каналы модпаков.", + "instance.settings.channel.alpha": "Альфа / ранние сборки.", + "instance.settings.platform": "Платформа", + "instance.settings.change": "Изменить", + "instance.settings.changeWarn": "Смена версии после установки контента может сломать моды.", + "instance.settings.changeTitle": "Изменить установку", + "instance.settings.cancel": "Отмена", + "instance.settings.repair": "Исправление", + "instance.settings.repairHint": "Переустановит клиент, библиотеки и ассеты этой сборки.", + "instance.settings.repairBtn": "Исправить", + "instance.settings.repairing": "Исправление…", + "instance.settings.javaInstall": "Установка Java", + "instance.settings.overrideJava": "Своя установка Java", + "instance.settings.overrideMemory": "Своя память", + "instance.settings.overrideJvm": "Свои JVM-аргументы", + "instance.settings.overrideEnv": "Свои переменные окружения", + "instance.settings.envVars": "Переменные окружения", + "instance.settings.overrideHooks": "Свои команды запуска", + "instance.settings.hooksHint": "Команды до/после запуска и обёртка процесса.", + "instance.settings.preLaunchPh": "Команда перед запуском…", + "instance.settings.preLaunchHint": "Выполняется до старта игры.", + "instance.settings.wrapperPh": "Обёртка…", + "instance.settings.wrapperHint": "Команда-обёртка для запуска Minecraft.", + "instance.settings.postExitPh": "Команда после выхода…", + "instance.settings.postExitHint": "Выполняется после закрытия игры.", + "settings.locale.desc": "Язык интерфейса лаунчера.", + "settings.locale.ru": "Русский", + "settings.locale.en": "English", + "settings.updates.desc": "Автообновление EXE позже будет использовать этот канал.", + "settings.updates.check": "Проверить обновления", + "settings.updates.stub": "Апдейтер ещё не подключён. Канал: {channel}", + "settings.updates.channel": "Канал", + "create.title": "Новая сборка", + "create.name": "Название", + "create.loader": "Загрузчик", + "create.gameVersion": "Версия игры", + "create.loaderVersion": "Версия {loader}", + "create.noVersions": "Нет версий", + "create.snapshots": "Показывать снапшоты", + "create.showAllVersions": "Показать все версии", + "create.hideSnapshots": "Скрыть снапшоты", + "create.searchVersion": "Поиск версий…", + "create.toggleVersions": "Открыть список версий", + "create.selectIcon": "Выбрать иконку", + "create.removeIcon": "Удалить иконку", + "create.submit": "Создать", + "create.cancel": "Отмена", + "create.needMc": "Выберите версию Minecraft", + "create.needLoader": "Выберите версию загрузчика", + "create.mcCount": "МС версий: {n}", + "create.preparing": "Создание сборки…", + "instance.content": "Контент", + "instance.files": "Файлы", + "instance.worlds": "Миры", + "instance.logs": "Логи", + "instance.share": "Поделиться", + "instance.play": "Играть", + "instance.settings": "Настройки сборки", + "instance.more": "Ещё", + "instance.openFolder": "Открыть папку сборки…", + "instance.dup": "Дублировать", + "instance.delete": "Удалить", + "instance.browseMods": "Обзор модов (Modrinth)", + "instance.browseMods.hint": "Найди на Modrinth и установи совместимый файл прямо в эту сборку.", + "instance.browseMods.search": "Поиск модов…", + "instance.browseMods.empty": "Введите запрос, чтобы искать проекты на Modrinth.", + "instance.browseMods.stub": "Поиск и установка работают в Owyx.exe / tauri dev (нативная сеть).", + "instance.browseMods.install": "Установить", + "instance.browseMods.installing": "Установка…", + "instance.browseMods.installed": "Установлено", + "instance.browseMods.installedMsg": "{name} установлен в сборку", + "instance.browseMods.versions": "Версии", + "instance.browseMods.noVersions": "Нет совместимых версий", + "instance.browseMods.deps": "ещё {n} зав.", + "instance.browseMods.optionalDeps": "Ставить необязательные зависимости", + "instance.browseMods.optionalCount": "{n} необяз.", + "instance.browseMods.conflictCount": "{n} конфликт.", + "instance.browseMods.filterLoader": "Лоадер", + "instance.browseMods.filterMc": "MC", + "instance.browseMods.loadMore": "Ещё", + "instance.browseMods.back": "К результатам", + "instance.browseMods.searchBtn": "Искать", + "instance.browseMods.searchHint": "Enter или «Искать» — при вводе поиск тоже сработает после паузы.", + "instance.browseMods.categories": "Категории", + "instance.browseMods.cat.all": "Все", + "instance.browseMods.cat.optimization": "Оптимизация", + "instance.browseMods.cat.technology": "Технологии", + "instance.browseMods.cat.adventure": "Приключения", + "instance.browseMods.cat.magic": "Магия", + "instance.browseMods.cat.utility": "Утилиты", + "instance.browseMods.cat.decoration": "Декор", + "instance.browseMods.cat.library": "Библиотеки", + "instance.browseMods.cat.worldgen": "Генерация мира", + "instance.browseMods.cat.food": "Еда", + "instance.browseMods.cat.equipment": "Снаряжение", + "instance.browseMods.cat.storage": "Хранение", + "instance.browseMods.cat.transportation": "Транспорт", + "instance.browseMods.tab.description": "Описание", + "instance.browseMods.tab.gallery": "Галерея", + "instance.browseMods.tab.changelog": "Changelog", + "instance.browseMods.tab.versions": "Версии", + "instance.browseMods.changelogEmpty": "Нет changelog по версиям для этого проекта.", + "instance.browseMods.galleryEmpty": "У проекта нет изображений в галерее.", + "instance.browseMods.sidebar.info": "О проекте", + "instance.browseMods.sidebar.type": "Тип", + "instance.browseMods.sidebar.downloads": "Загрузки", + "instance.browseMods.sidebar.loaders": "Лоадеры", + "instance.browseMods.sidebar.mc": "Minecraft", + "instance.browseMods.sidebar.categories": "Категории", + "instance.browseMods.sidebar.openModrinth": "Открыть на Modrinth", + "instance.browseMods.open": "Открыть", + "instance.status.pending": "не установлена", + "instance.status.installing": "установка", + "instance.status.ready": "готова", + "instance.status.error": "ошибка", + "instance.waitInstall": "Дождись окончания установки", + "instance.installing": "Установка…", + "instance.installDone": "Готово", + "instance.installFail": "Установка не завершена", + "instance.settings.crumb": "Настройки", + "instance.settings.general": "Основные", + "instance.settings.install": "Установка", + "instance.settings.window": "Окно", + "instance.settings.java": "Java и память", + "instance.settings.launch": "Команды запуска", + "instance.settings.name": "Название", + "instance.settings.group": "Группа", + "instance.settings.groupPlaceholder": "Без группы", + "instance.settings.channel": "Канал обновлений", + "instance.settings.channelHint": "Пока только UI — пайплайн установки позже.", + "instance.settings.save": "Сохранить", + "instance.settings.saved": "Сохранено", + "instance.settings.back": "Назад", + "instance.settings.delete": "Удалить сборку", + "instance.settings.installDesc": "Текущая платформа (смена версии — позже).", + "instance.settings.loader": "Загрузчик", + "instance.settings.minecraft": "Minecraft", + "instance.settings.loaderVersion": "Версия загрузчика", + "instance.settings.width": "Ширина", + "instance.settings.height": "Высота", + "instance.settings.memory": "Память (МБ)", + "instance.settings.javaPath": "Путь к Java", + "instance.settings.jvmArgs": "JVM-аргументы", + "instance.settings.preLaunch": "Перед запуском", + "instance.settings.wrapper": "Обёртка", + "instance.settings.postExit": "После выхода", + "instance.files.loading": "Загрузка файлов…", + "instance.logs.source": "Источник лога", + "instance.logs.filter": "Фильтр уровня", + "instance.logs.filterAll": "Все", + "instance.logs.filterError": "Error", + "instance.logs.filterWarn": "Warn", + "instance.logs.filterInfo": "Info", + "instance.logs.search": "Поиск по логу…", + "instance.logs.openFolder": "Открыть папку логов", + "instance.logs.refresh": "Обновить", + "instance.logs.loading": "Загрузка лога…", + "instance.logs.emptyTitle": "Пока нет вывода", + "instance.logs.emptyHint": "Запусти сборку кнопкой «Играть», чтобы здесь появился live-консоль.", + "instance.logs.noMatches": "Нет совпадений.", + "wizard.authBrowser": "Войти через Microsoft", + "content.enabled": "вкл.", + "content.disabled": "выкл.", + "common.refresh": "Обновить", + "common.delete": "Удалить", + "common.open": "Открыть", + "error.installRunning": "Уже идёт другая установка — подожди", + "error.cantDeleteInstalling": "Нельзя удалить во время установки", + "error.cantDupInstalling": "Нельзя дублировать во время установки", + "error.hostNotAllowed": "Загрузка с этого хоста запрещена", + "error.fileTooLarge": "Файл слишком большой", + "error.notReady": "Сборка ещё не установлена — нажми Играть, установлю и запущу", + "error.contentExists": "Такой файл уже есть в сборке", + "error.inferType": "Не удалось определить тип файла (нужен jar/zip мода или пака)", + "error.sourceNotFound": "Файл не найден", + "error.noCompatVersion": "Нет совместимой версии под этот загрузчик / версию Minecraft", + "error.hashFail": "Файл не прошёл проверку целостности (SHA-512) — попробуй ещё раз", + "error.noFile": "У проекта нет файла для скачивания", + "error.javaMissing": "Совместимая Java не найдена — установи или найди Java в Настройках", + "error.nickInvalid": "Ник может содержать только буквы, цифры и _", + "error.mcRequired": "Выберите версию Minecraft", + "error.loaderRequired": "Выберите версию загрузчика", + "error.unsupportedLoader": "Этот загрузчик не поддерживается", + "error.modLoaderInstall": "Установка загрузчика не удалась — попробуй другую версию загрузчика", + "error.noJars": "В сборке нет клиентских jar — переустанови её (Исправить)", + "error.timeout": "Истекло время ожидания — проверь соединение и повтори", + "error.integrity": "Скачанный файл не прошёл проверку — повтори установку", + "error.network": "Ошибка сети — проверь соединение и повтори", + "library.sort.name": "Сортировка: имя", + "library.sort.played": "Сортировка: последний запуск", + "library.sort.created": "Сортировка: создано", + "library.group.none": "Группа: нет", + "library.group.group": "Группа: группа", + "library.group.loader": "Группа: загрузчик", + "library.group.ungrouped": "Без группы", + "content.search": "Поиск…", + "content.addFiles": "Добавить файлы", + "content.openMods": "Открыть mods/", + "content.enableAll": "Включить все", + "content.disableAll": "Выключить все", + "content.filter.all": "Все", + "content.filter.mods": "Моды", + "content.filter.resourcepacks": "Ресурспаки", + "content.filter.shaders": "Шейдеры", + "content.filter.datapacks": "Датапаки", + "content.filter.enabled": "Вкл.", + "content.filter.disabled": "Выкл.", + "content.emptyTitle": "Контент пуст", + "content.emptyHint": "Нажми «Добавить файлы» или положи моды в game/mods и нажми «Обновить».", + "content.noMatch": "Ничего не найдено по фильтру.", + "content.colProject": "Проект", + "content.colFile": "Файл", + "content.colActions": "Действия", + "content.toggleTitle": "Вкл/выкл", + "content.deleteAria": "Удалить мод {name}", + "content.addBrowser": "Добавление файлов работает в Owyx.exe / tauri dev", + "content.addDialogTitle": "Добавить моды / паки", + "content.added1": "Файл добавлен в сборку", + "content.addedN": "Добавлено файлов: {n}", + "content.kind.mod": "Мод", + "content.kind.resourcepack": "Ресурспак", + "content.kind.datapack": "Датапак", + "content.kind.shader": "Шейдер", + "share.title": "Поделиться сборкой", + "share.body": "Экспорт профиля / ссылка на модпак появится после install + sync backend.", + "files.openRoot": "Открыть папку сборки", + "files.openGame": "Открыть game/", + "files.openBrowser": "Открытие папок только в Tauri", + "files.browser": "Список файлов доступен в собранном лаунчере.", + "files.emptyTitle": "Папка пуста", + "files.emptyHint": "После установки здесь появятся libraries, assets, mods…", + "worlds.search": "Поиск миров…", + "worlds.openSaves": "Открыть saves/", + "worlds.emptyTitle": "Миров пока нет", + "worlds.emptyHint": "После игры сейвы появятся в game/saves. Нажми «Обновить».", + "worlds.noMatch": "Ничего не найдено.", + "worlds.deleteTitle": "Удалить с диска", + "worlds.deleteAria": "Удалить мир {name}", + "instance.logs.browser": "Логи доступны в собранном лаунчере (%USERPROFILE%\\owyx\\logs).", + "instance.copying": "Копирование сборки…", + "instance.copied": "Копия создана", + "nav.browse": "Обзор", + "nav.skins": "Скины", + "browse.discover": "Обзор контента", + "browse.discoverHint": "Поиск проектов Modrinth. Установка — из инстанса: Контент → Найти проекты.", + "browse.contentInstall": "Установка контента", + "browse.installMeta": "Установка контента · Minecraft {mc} · {loader}", + "browse.back": "К контенту", + "browse.searchPlaceholder": "Поиск: {type}…", + "browse.sortLabel": "Сортировка", + "browse.sort.relevance": "Релевантность", + "browse.sort.downloads": "Загрузки", + "browse.sort.follows": "Подписки", + "browse.sort.newest": "Дата публикации", + "browse.sort.updated": "Дата обновления", + "browse.pageSize": "На странице", + "browse.filters": "Фильтры", + "browse.hideInstalled": "Скрыть уже установленное", + "browse.gameVersion": "Версия игры", + "browse.loader": "Загрузчик", + "browse.unlock": "Разблокировать", + "browse.lock": "Привязать к инстансу", + "browse.categories": "Категории", + "browse.empty": "Загрузка проектов…", + "browse.searching": "Поиск…", + "browse.noResults": "Ничего не найдено", + "browse.noResultsHint": "Измени запрос или разблокируй фильтры.", + "browse.prev": "Назад", + "browse.next": "Вперёд", + "browse.pageOf": "Стр. {page} / {pages} · {total}", + "browse.type.mods": "Моды", + "browse.type.resourcepacks": "Ресурспаки", + "browse.type.datapacks": "Датапаки", + "browse.type.shaders": "Шейдеры", + "browse.pickInstance": "Выбери инстанс", + "browse.pickInstanceHint": "Открой инстанс → Контент → Найти проекты для установки.", + "content.browseContent": "Найти проекты", + "content.uploadFiles": "Добавить файлы", + "content.searchN": "Поиск по {n} проектам…", + "content.emptyHintBrowse": "Найди проекты на Modrinth или загрузи файлы.", + "skins.title": "Скины", + "skins.subtitle": "Превью, импорт и применение скинов. Скин Owyx-аккаунта — с сайта.", + "skins.saved": "Сохранённые", + "skins.import": "Импорт PNG", + "skins.add": "Добавить скин", + "skins.owyx": "Аккаунт Owyx", + "skins.owyxHint": "Применить скин профиля Owyx (/me) на диск для Minecraft.", + "skins.applyOwyx": "Применить скин Owyx", + "skins.apply": "Применить", + "skins.remove": "Удалить", + "skins.removed": "Скин удалён", + "skins.equipped": "Надет", + "skins.applied": "Скин применён", + "skins.playingAs": "Играешь как {nick}", + "skins.noProfile": "Нет профиля", + "skins.defaultSteve": "Steve", + "skins.needOwyx": "Сначала войди в аккаунт Owyx", + "skins.importBrowser": "Импорт доступен в нативном приложении", + "skins.imported": "Скин добавлен в библиотеку", + "skins.importedPath": "Выбран {path}", + "create.next": "Далее", + "create.back": "Назад", + "create.step.loader": "Загрузчик", + "create.step.mc": "Версия Minecraft", + "create.step.loaderVer": "Версия загрузчика", + "create.step.name": "Имя", + "create.step.icon": "Иконка", + "create.vanillaNoLoader": "У Vanilla нет версии загрузчика — продолжай.", + "create.setupTypeHint": "Как создать сборку?", + "create.type.custom": "Своя", + "create.type.customDesc": "Загрузчик, версия Minecraft, имя и иконка.", + "create.type.modpack": "Обзор модпаков", + "create.type.importMrpack": "Импорт .mrpack", + "create.type.modpackDesc": "Discover или импорт Modrinth-пака (игровые jar ставятся на Play).", + "create.importMrpackBrowser": "Импорт mrpack — в нативном приложении", + "create.importMrpackWorking": "Импорт модпака…", + "browse.installModpack": "Установить пак", + "browse.modpackImported": "Импортирован {name}", + "skins.importPartial": "Плащи / Mojang equip API позже; локальная библиотека + Owyx /me уже работают.", + "wizard.ms.pipelineTitle": "Запускает pipeline Microsoft (device code)", + "wizard.ms.starting": "Запуск входа Microsoft…", + "wizard.ms.waiting": "Ждём Microsoft…", + "wizard.ms.unconfigured": "MICROSOFT_CLIENT_ID не задан", + "wizard.ms.unconfiguredHint": "Владельцу: задай MICROSOFT_CLIENT_ID — см. docs/MICROSOFT_AUTH.md", + "wizard.ms.codeHint": "Код {code} — открой {uri}", + "wizard.ms.error": "Ошибка входа Microsoft", + "wizard.ms.cancel": "Отменить вход", + "wizard.ms.cancelled": "Вход отменён", + "wizard.ms.retry": "Повторить вход Microsoft", + "settings.appearance.desc": "Токены бренда Owyx (циан на глубоком фоне). Редактор темы позже.", + "settings.appearance.tokens": "bg #050508 · panel #131319 · accent #00e5ff", + "settings.behavior.desc": "Переключатели поведения (заготовки как в Modrinth App).", + "settings.behavior.closeToTray": "Сворачивать вместо выхода (скоро)", + "settings.behavior.keepLogs": "Хранить логи запуска", + "settings.behavior.stub": "Пока не сохраняются.", + "share.localHint": "Облачный Share Modrinth не портирован. Можно скопировать имя или открыть папку.", + "share.mrpackHint": "Экспорт локального .mrpack (через overrides; без CDN Modrinth).", + "share.exportMrpack": "Экспорт .mrpack", + "share.exportBrowser": "Экспорт — в нативном приложении", + "share.copyName": "Скопировать имя", + "share.copied": "Имя скопировано", + "wizard.ms.scaffold": "Обмен токенов Microsoft ещё не подключён", + "wizard.ms.scaffoldHint": "CLIENT_ID может быть задан, но Xbox/Minecraft токены не обмениваются. См. docs/MICROSOFT_AUTH.md — фейковый device code не показываем.", + "wizard.ms.success": "Аккаунт Microsoft привязан", + "wizard.ms.successHint": "Профиль сохранён с opaque auth blob. Offline и Owyx работают отдельно.", + "wizard.ms.successPending": "Профиль Microsoft сохранён как pending", + "wizard.ms.successPendingHint": "Обмен токенов неполный — needsAuth остаётся, пока нет реальных токенов.", + "browse.type.modpacks": "Модпаки" +} diff --git a/legacy/Launcher/apps/launcher/src/main.ts b/legacy/Launcher/apps/launcher/src/main.ts new file mode 100644 index 00000000000..d3b12ae8283 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/main.ts @@ -0,0 +1,5397 @@ +import "./styles.css"; +import { invoke } from "@tauri-apps/api/core"; +import { listen } from "@tauri-apps/api/event"; +import { getCurrentWindow } from "@tauri-apps/api/window"; +import { open as openDialog, save as saveDialog } from "@tauri-apps/plugin-dialog"; +import { getLocale, normalizeLocale, setLocale, t } from "./i18n"; +import { startParticles } from "./particles"; +import { mountPlayingAs } from "./playing-as"; +import { createVersionCombobox, type VersionCombobox } from "./version-combobox"; +import { loadCatalog, installCatalogServer, type CatalogServer } from "./catalog"; +import { owyxLogin, owyxLogout, owyxMe, owyxAdminFetch, owyxApplySkin, type OwyxSession } from "./owyx-auth"; +import { + mountBrowsePage, + mountProjectPage, + type BrowseHit, + type BrowseProjectType, +} from "./browse-page"; +import { mountSkinsPage } from "./skins-page"; +import { msAuthStart, msAuthPoll, msAuthCancel } from "./ms-auth"; + +type JavaInstallation = { + path: string; + version: string; + majorVersion: number; + is64Bit: boolean; +}; +type UpdaterConfig = { channel: string; lastCheckAt?: number | null }; +type LauncherConfig = { + nick: string; + updateBaseUrl?: string | null; + javaInstallations?: JavaInstallation[]; + javaVersions?: Record; + locale?: string; + activeProfileId?: string | null; + updater?: UpdaterConfig; + defaultMemoryMb?: number; +}; +type ProfileKind = "offline" | "microsoft" | "owyx"; +type Profile = { + id: string; + kind: ProfileKind; + name: string; + nick: string; + needsAuth?: boolean; + /** Opaque encrypted auth payload — never plaintext tokens. */ + authBlob?: string | null; + createdAt: number; +}; +type ProfilesState = { + profiles: Profile[]; + activeProfileId?: string | null; +}; +type ContentKind = "mod" | "resourcepack" | "shader" | "datapack"; +type ContentItem = { + id: string; + name: string; + author: string; + kind: ContentKind; + version: string; + fileName: string; + enabled: boolean; +}; +type WorldItem = { + id: string; + name: string; + mode: string; + lastPlayedAt: number; + hardcore?: boolean; + /** data: URL of the world's icon.png, when present. */ + icon?: string | null; +}; +type InstanceSettings = { + group: string; + updateChannel: "release" | "beta" | "alpha"; + memoryMb: number; + javaPath: string; + width: number; + height: number; + jvmArgs: string; + overrideMemory: boolean; + overrideJavaPath: boolean; + overrideJvmArgs: boolean; + overrideEnvVars: boolean; + overrideHooks: boolean; + envVars: string; + preLaunch: string; + wrapper: string; + postExit: string; +}; +type Instance = { + id: string; + name: string; + loader: string; + minecraft: string; + loaderVersion: string; + createdAt: number; + lastPlayedAt?: number; + installStatus?: "pending" | "installing" | "ready" | "error"; + installMessage?: string; + /** data: URL when loaded; empty string = none; undefined = not fetched yet */ + iconUrl?: string | null; + hasIcon?: boolean; + content: ContentItem[]; + worlds: WorldItem[]; + settings: InstanceSettings; + catalogServerId?: string; + catalogPackId?: string; + serverAddress?: string; + serverPort?: number; +}; + +type InstallProgress = { + packId: string; + phase: string; + currentFile?: string | null; + doneFiles: number; + totalFiles: number; + message: string; + fileBytesDone?: number | null; + fileBytesTotal?: number | null; +}; + +const LOADERS = [ + { id: "vanilla", name: "Vanilla" }, + { id: "fabric", name: "Fabric" }, + { id: "forge", name: "Forge" }, + { id: "neoforge", name: "NeoForge" }, + { id: "quilt", name: "Quilt" }, +] as const; + +const STORAGE_INSTANCES = "owyx.instances"; +const STORAGE_PROFILES = "owyx.profiles"; +const STORAGE_PROFILES_INIT = "owyx.profilesInitialized"; +const STORAGE_NICK = "owyx.nick"; +const STORAGE_LOCALE = "owyx.locale"; +const STORAGE_ACTIVE_PROFILE = "owyx.activeProfile"; + +const DEFAULT_SETTINGS = (): InstanceSettings => ({ + group: "", + updateChannel: "release", + memoryMb: 4096, + javaPath: "", + width: 1280, + height: 720, + jvmArgs: "", + overrideMemory: true, + overrideJavaPath: false, + overrideJvmArgs: false, + overrideEnvVars: false, + overrideHooks: false, + envVars: "", + preLaunch: "", + wrapper: "", + postExit: "", +}); + +type PrefetchStatus = { + ready: boolean; + minecraft?: string | null; + message: string; + doneFiles: number; + totalFiles: number; +}; + +let metaPrefetch: PrefetchStatus = { + ready: false, + message: "", + doneFiles: 0, + totalFiles: 0, +}; +/** Soft-fail: allow Play for already-ready instances if prefetch never completes. */ +let metaPrefetchFailed = false; +let systemMemoryMb = 16384; +let javaDetectCallback: ((path: string) => void) | null = null; + +const app = document.querySelector("#app"); +if (!app) throw new Error("#app root missing"); +const root = app; + +const inTauri = Boolean( + // @ts-expect-error Tauri injects this in WebView + window.__TAURI_INTERNALS__ ?? window.__TAURI__, +); + +metaPrefetch.ready = !inTauri; + +let instances: Instance[] = loadInstances(); +let selectedInstanceId: string | null = instances[0]?.id ?? null; +let selectedLoader = "fabric"; +let mcRequestId = 0; +let loaderRequestId = 0; +let createRefreshEpoch = 0; +let createVersionsReady = false; +let readySpec: { + loader: string; + minecraft: string; + loaderVersion: string; +} | null = null; +let instanceTab: "content" | "files" | "worlds" | "logs" | "share" = "content"; +let browseProjectType: BrowseProjectType = "mod"; +let browseInstanceId: string | null = null; +let selectedProjectHit: BrowseHit | null = null; +let createWizardStep = 1; // 1 loader → 2 MC → 3 loader ver → 4 name → 5 icon +let owyxSession: OwyxSession | null = null; +let contentFilter: "all" | ContentKind | "enabled" | "disabled" = "all"; +let librarySort: "name" | "played" | "created" = "name"; +let libraryGroup: "none" | "loader" | "group" = "none"; +let libraryFilter: "all" | "modpacks" | "servers" | "custom" = "all"; +let instanceSettingsTab: + | "general" + | "install" + | "window" + | "java" + | "launch" = "general"; +let settingsTab: "java" | "localization" | "updates" | "appearance" | "behavior" = "java"; +let activeInstallId: string | null = null; +let profiles: Profile[] = []; +let activeProfileId: string | null = null; +let launcherCfg: LauncherConfig | null = null; +let shellReady = false; +let wizardAllowClose = false; +let profilesPersistChain: Promise = Promise.resolve(); + +function ensureProfileGate() { + if (!profiles.length) { + openProfileWizard({ allowClose: false }); + return; + } + if (!activeProfileId || !profiles.some((p) => p.id === activeProfileId)) { + activeProfileId = profiles[0]?.id ?? null; + } +} + +type NavEntry = { route: string; instanceId?: string | null }; +const navHistory: NavEntry[] = [{ route: "home" }]; +let navIndex = 0; +let applyingHistory = false; + +const HEX_LOGO = ` + `; + +root.innerHTML = ` + +
+
+ + owyx +
+

+
+
+ + + +
+
+
+ + +
+
+
+ owyx + + +
+
+ +
+ Ready + +
+
+ + + +
+
+
+
+
+
+ + + + + + + + + + +`; + +const main = root.querySelector("#main")!; +const crumb = root.querySelector("#crumb")!; +const topStatusEl = root.querySelector("#top-status")!; +const topStatusTextEl = root.querySelector("#top-status-text")!; +const topProgressTrack = root.querySelector("#top-progress-track")!; +const topProgressFill = root.querySelector("#top-progress-fill")!; +const downloadTipEl = root.querySelector("#download-tip")!; +const downloadTipSizeEl = root.querySelector("#download-tip-size")!; +const downloadTipSpeedEl = root.querySelector("#download-tip-speed")!; +const topStatus = { + get textContent() { + return topStatusTextEl.textContent ?? ""; + }, + set textContent(value: string) { + const v = value ?? ""; + topStatusTextEl.textContent = v; + topStatusEl.title = v; + }, + get dataset() { + return topStatusEl.dataset; + }, +}; + +type DownloadTipMeter = { + fileKey: string; + lastBytes: number; + lastAt: number; + speedMbit: number; +}; +let downloadTipMeter: DownloadTipMeter | null = null; + +function formatBytes(n: number): string { + if (!Number.isFinite(n) || n < 0) return "0 B"; + if (n < 1024) return `${Math.round(n)} B`; + if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`; + if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`; + return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`; +} + +function hideDownloadTip() { + downloadTipEl.hidden = true; + downloadTipEl.setAttribute("aria-hidden", "true"); + downloadTipSizeEl.textContent = ""; + downloadTipSpeedEl.textContent = ""; + downloadTipMeter = null; +} + +function updateDownloadTip(p: InstallProgress) { + const done = p.fileBytesDone; + if ( + done == null || + !Number.isFinite(done) || + p.phase === "done" || + p.phase === "verify" || + p.phase === "resolve" + ) { + hideDownloadTip(); + return; + } + const total = + p.fileBytesTotal != null && Number.isFinite(p.fileBytesTotal) && p.fileBytesTotal > 0 + ? p.fileBytesTotal + : null; + const fileKey = `${p.packId}|${p.currentFile ?? p.message}|${total ?? "?"}`; + const now = performance.now(); + if (!downloadTipMeter || downloadTipMeter.fileKey !== fileKey) { + downloadTipMeter = { fileKey, lastBytes: done, lastAt: now, speedMbit: 0 }; + } else { + const dt = (now - downloadTipMeter.lastAt) / 1000; + const dBytes = done - downloadTipMeter.lastBytes; + if (dt >= 0.15 && dBytes >= 0) { + const instant = (dBytes * 8) / (dt * 1_000_000); + downloadTipMeter.speedMbit = + downloadTipMeter.speedMbit > 0 + ? downloadTipMeter.speedMbit * 0.55 + instant * 0.45 + : instant; + downloadTipMeter.lastBytes = done; + downloadTipMeter.lastAt = now; + } + } + downloadTipSizeEl.textContent = + total != null ? `${formatBytes(done)} / ${formatBytes(total)}` : formatBytes(done); + downloadTipSpeedEl.textContent = `${Math.max(0, downloadTipMeter.speedMbit).toFixed(1)} ${t("download.speedUnit")}`; + downloadTipEl.hidden = false; + downloadTipEl.setAttribute("aria-hidden", "false"); +} + +/** App-wide titlebar: nav/tabs must not overwrite while download/prefetch is busy. */ +let titlebarBusy = false; +let titlebarIdleFallback = ""; + +function showTopProgress(pct: number) { + const clamped = Math.max(0, Math.min(100, pct)); + topProgressFill.style.width = `${clamped}%`; + topProgressTrack.hidden = false; + topStatusEl.classList.add("is-busy"); +} +function hideTopProgress() { + topProgressFill.style.width = "0%"; + topProgressTrack.hidden = true; + topStatusEl.classList.remove("is-busy"); + hideDownloadTip(); +} + +function setTitlebarBusy(message: string, pct: number) { + titlebarBusy = true; + topStatusEl.dataset.kind = "busy"; + topStatus.textContent = message; + showTopProgress(pct); +} + +function clearTitlebarBusy(idleMessage?: string) { + titlebarBusy = false; + hideTopProgress(); + const msg = idleMessage ?? (titlebarIdleFallback || t("status.ready")); + titlebarIdleFallback = msg; + topStatusEl.dataset.kind = "idle"; + topStatus.textContent = msg; +} + +/** Idle / contextual status — ignored while prefetch or install owns the pill. */ +function setTitlebarIdle(message: string) { + titlebarIdleFallback = message; + if (titlebarBusy) return; + topStatusEl.dataset.kind = "idle"; + topStatus.textContent = message; +} + +/** Last N status events for the titlebar queue (P1-E / B-005). */ +const STATUS_EVENT_LIMIT = 6; +const statusEvents: string[] = []; + +function pushStatusEvent(message: string) { + const msg = message.trim(); + if (!msg) return; + statusEvents.unshift(msg); + if (statusEvents.length > STATUS_EVENT_LIMIT) statusEvents.length = STATUS_EVENT_LIMIT; + const shown = + statusEvents.length === 1 ? statusEvents[0]! : statusEvents.slice(0, 3).join(" · "); + setTitlebarIdle(shown); +} + +/** https-only Modrinth media (gallery/icons) — mirrors Rust host allowlist. */ +function isSafeModrinthMediaUrl(raw: string): boolean { + try { + const u = new URL(raw); + if (u.protocol !== "https:") return false; + if (u.username || u.password) return false; + const host = u.hostname.toLowerCase(); + return host === "modrinth.com" || host.endsWith(".modrinth.com"); + } catch { + return false; + } +} + + +function setTitlebarMessage(message: string) { + topStatusEl.dataset.kind = "info"; + topStatus.textContent = message; + pushStatusEvent(message); +} + +function setTitlebarError(message: string) { + titlebarBusy = false; + hideTopProgress(); + topStatusEl.dataset.kind = "error"; + topStatus.textContent = t("status.error", { message }); +} +const recentList = root.querySelector("#recent-list")!; +const modalCreate = root.querySelector("#modal-create")!; +const modalInstSettings = root.querySelector("#modal-inst-settings")!; +const modalAppSettings = root.querySelector("#modal-app-settings")!; +const modalJavaDetect = root.querySelector("#modal-java-detect")!; +const chips = root.querySelector("#loader-chips")!; +const mcHost = root.querySelector("#mc-version-host")!; +const loaderHost = root.querySelector("#loader-version-host")!; +const loaderField = root.querySelector("#loader-version-field")!; +const loaderLabel = root.querySelector("#loader-version-label")!; +const instName = root.querySelector("#inst-name")!; +const createStatus = root.querySelector("#create-status")!; +const btnCreate = root.querySelector("#btn-create")!; +const createIconPreview = root.querySelector("#create-icon-preview")!; +const btnCreateIcon = root.querySelector("#btn-create-icon")!; +const btnCreateIconClear = root.querySelector("#btn-create-icon-clear")!; + +let createShowSnapshots = false; +let createIconPath: string | null = null; +let createIconDataUrl: string | null = null; +let runningPollTimer: ReturnType | null = null; + +const mcCombo: VersionCombobox = createVersionCombobox({ + searchPlaceholder: "…", + showAllToggle: true, + getShowAll: () => createShowSnapshots, + onShowAllChange: (v) => { + createShowSnapshots = v; + void refreshMinecraftVersions(); + }, + onChange: () => { + refreshCreateNameHint(); + syncCreateWizardStep(); + void refreshLoaderVersions(); + }, +}); +const loaderCombo: VersionCombobox = createVersionCombobox({ + searchPlaceholder: "…", + onChange: () => { + refreshCreateNameHint(); + syncCreateWizardStep(); + if (!createVersionsReady || !readySpec) return; + if (readySpec.loader !== selectedLoader || readySpec.minecraft !== mcCombo.getValue()) return; + readySpec = { + ...readySpec, + loaderVersion: selectedLoader === "vanilla" ? "" : loaderCombo.getValue(), + }; + }, +}); +mcHost.append(mcCombo.root); +loaderHost.append(loaderCombo.root); +const histBack = root.querySelector("#hist-back")!; +const histForward = root.querySelector("#hist-forward")!; +const shellEl = root.querySelector("#shell")!; +const splashEl = root.querySelector("#splash")!; +const splashFill = root.querySelector("#splash-fill")!; +const splashLabel = root.querySelector("#splash-label")!; +const modalWizard = root.querySelector("#modal-wizard")!; +const particlesCanvas = root.querySelector("#particles")!; +const modalFocusOrigins = new WeakMap(); + +function modalFocusable(modal: HTMLElement): HTMLElement[] { + return Array.from( + modal.querySelectorAll( + 'button:not([disabled]), a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])', + ), + ).filter((element) => !element.hidden && element.getClientRects().length > 0); +} + +function showModal(modal: HTMLElement, initialSelector?: string) { + const active = document.activeElement; + if (active instanceof HTMLElement && !modal.contains(active)) { + modalFocusOrigins.set(modal, active); + } + modal.hidden = false; + requestAnimationFrame(() => { + const requested = initialSelector + ? modal.querySelector(initialSelector) + : null; + (requested ?? modalFocusable(modal)[0] ?? modal.querySelector(".modal-card"))?.focus(); + }); +} + +function hideModal(modal: HTMLElement) { + if (modal === modalWizard) { + stopMsAuthPoll(); + } + modal.hidden = true; + const origin = modalFocusOrigins.get(modal); + modalFocusOrigins.delete(modal); + origin?.focus(); +} + +function topVisibleModal(): HTMLElement | null { + const visible = Array.from(document.querySelectorAll(".modal")).filter( + (modal) => !modal.hidden, + ); + return visible.at(-1) ?? null; +} + +function closeModalFromKeyboard(modal: HTMLElement) { + if (modal === modalWizard) { + if (wizardAllowClose) hideModal(modalWizard); + } else if (modal === modalCreate) { + closeCreateModal(); + } else if (modal === modalInstSettings) { + hideModal(modalInstSettings); + } else if (modal === modalAppSettings) { + closeAppSettingsOverlay(); + } else if (modal === modalJavaDetect) { + javaDetectCallback = null; + hideModal(modalJavaDetect); + } else if (modal.id === "modal-server-admin") { + const origin = modalFocusOrigins.get(modal); + modal.remove(); + origin?.focus(); + } +} + +document.addEventListener("keydown", (event) => { + const modal = topVisibleModal(); + if (!modal) return; + if (event.key === "Escape") { + event.preventDefault(); + closeModalFromKeyboard(modal); + return; + } + if (event.key !== "Tab") return; + const focusable = modalFocusable(modal); + if (!focusable.length) { + event.preventDefault(); + modal.querySelector(".modal-card")?.focus(); + return; + } + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (event.shiftKey && document.activeElement === first) { + event.preventDefault(); + last.focus(); + } else if (!event.shiftKey && document.activeElement === last) { + event.preventDefault(); + first.focus(); + } +}); + +function sleep(ms: number) { + return new Promise((r) => setTimeout(r, ms)); +} + +function activeProfile(): Profile | null { + return profiles.find((p) => p.id === activeProfileId) ?? profiles[0] ?? null; +} + +function profileReady(p: Profile | null): boolean { + // Offline nick is enough for Play until Microsoft/Owyx auth is implemented. + return Boolean(p && p.nick.trim()); +} + +function ensureCanPlay(): boolean { + const p = activeProfile(); + if (!profileReady(p)) { + setTitlebarMessage(t("play.noProfile")); + openProfileWizard({ allowClose: profiles.length > 0 }); + return false; + } + if (p?.needsAuth) { + setTitlebarError(t("play.needsAuth")); + openProfileWizard({ allowClose: profiles.length > 0 }); + return false; + } + return true; +} + +function animateMain() { + main.classList.remove("is-entering"); + // force reflow + void main.offsetWidth; + main.classList.add("is-entering"); +} + +function applyChromeI18n() { + root.querySelectorAll("[data-route]").forEach((btn) => { + const route = btn.dataset.route!; + const key = + route === "home" + ? "nav.home" + : route === "library" + ? "nav.library" + : route === "browse" + ? "nav.browse" + : route === "skins" + ? "nav.skins" + : route === "servers" + ? "nav.servers" + : route === "stats" + ? "nav.stats" + : route === "settings" + ? "nav.settings" + : ""; + if (key) { + const label = t(key); + btn.title = label; + btn.setAttribute("aria-label", label); + } + }); + root.querySelectorAll("[data-close]").forEach((button) => { + if (button.textContent?.trim() === "✕") button.setAttribute("aria-label", t("common.close")); + }); + root.querySelector("[data-action='create']")!.title = t("nav.create"); + histBack.title = t("nav.back"); + histForward.title = t("nav.forward"); + if ( + shellReady && + topStatusEl.dataset.kind !== "err" && + topStatusEl.dataset.kind !== "busy" && + (topStatus.textContent === "Ready" || + topStatus.textContent === t("status.ready") || + topStatusEl.dataset.kind === "idle") + ) { + // Refresh idle Ready (and previous-locale Ready) after language switch. + if (!titlebarBusy) { + topStatus.textContent = titlebarIdleFallback || t("status.ready"); + } + } + root.querySelectorAll("[data-i18n]").forEach((el) => { + const key = el.dataset.i18n; + if (key) el.textContent = t(key); + }); + root.querySelectorAll("[data-i18n-title]").forEach((el) => { + const key = el.dataset.i18nTitle; + if (!key) return; + const label = t(key); + el.title = label; + if (el.hasAttribute("aria-label")) el.setAttribute("aria-label", label); + }); +} + +async function loadProfilesState(): Promise { + if (inTauri) { + const state = await invoke("get_profiles"); + profiles = state.profiles ?? []; + activeProfileId = state.activeProfileId ?? null; + return; + } + const initialized = localStorage.getItem(STORAGE_PROFILES_INIT) === "1"; + try { + profiles = JSON.parse(localStorage.getItem(STORAGE_PROFILES) ?? "[]") as Profile[]; + } catch { + profiles = []; + } + activeProfileId = localStorage.getItem(STORAGE_ACTIVE_PROFILE); + if (!initialized && !profiles.length) { + const nick = localStorage.getItem(STORAGE_NICK)?.trim() ?? ""; + if (nick) { + const id = `prof_${Date.now().toString(36)}`; + profiles = [ + { + id, + kind: "offline", + name: nick, + nick, + needsAuth: false, + createdAt: Date.now(), + }, + ]; + activeProfileId = id; + localStorage.setItem(STORAGE_PROFILES, JSON.stringify(profiles)); + localStorage.setItem(STORAGE_ACTIVE_PROFILE, id); + } + } + localStorage.setItem(STORAGE_PROFILES_INIT, "1"); +} + +async function persistProfiles(): Promise { + const run = async () => { + if (inTauri) { + const state = await invoke("save_profiles", { + profiles, + activeProfileId, + }); + profiles = state.profiles; + activeProfileId = state.activeProfileId ?? null; + return; + } + localStorage.setItem(STORAGE_PROFILES_INIT, "1"); + localStorage.setItem(STORAGE_PROFILES, JSON.stringify(profiles)); + if (activeProfileId) localStorage.setItem(STORAGE_ACTIVE_PROFILE, activeProfileId); + else localStorage.removeItem(STORAGE_ACTIVE_PROFILE); + const p = activeProfile(); + if (p?.kind === "offline") localStorage.setItem(STORAGE_NICK, p.nick); + else if (!profiles.length) localStorage.removeItem(STORAGE_NICK); + }; + const prev = profilesPersistChain; + let release!: () => void; + profilesPersistChain = new Promise((r) => { + release = r; + }); + await prev; + try { + await run(); + } finally { + release(); + } +} + +function makeProfile(kind: ProfileKind, nick: string): Profile { + const clean = nick.trim().slice(0, 16); + const id = `prof_${Date.now().toString(36)}`; + const needsAuth = kind !== "offline"; + return { + id, + kind, + name: clean || (kind === "microsoft" ? "Microsoft" : kind === "owyx" ? "Owyx" : "Player"), + nick: clean || "Player", + needsAuth, + // Placeholder for future OS-bound ciphertext (DPAPI / keychain). Never plaintext. + authBlob: needsAuth ? "pending:encrypted" : null, + createdAt: Date.now(), + }; +} + +let wizardKind: ProfileKind = "offline"; + +function openProfileWizard(opts?: { allowClose?: boolean }) { + wizardAllowClose = Boolean(opts?.allowClose); + wizardKind = "offline"; + stopMsAuthPoll(); + msWizardUiPhase = "idle"; + showModal(modalWizard, "#wizard-nick"); + const title = modalWizard.querySelector("#wizard-title")!; + const sub = modalWizard.querySelector("#wizard-sub")!; + const hint = modalWizard.querySelector("#wizard-hint")!; + const nickLabel = modalWizard.querySelector("#wizard-nick-label")!; + const btn = modalWizard.querySelector("#btn-wizard")!; + const nickInput = modalWizard.querySelector("#wizard-nick")!; + const nickField = modalWizard.querySelector("#wizard-nick-field")!; + const authField = modalWizard.querySelector("#wizard-auth-field")!; + const authBtn = modalWizard.querySelector("#btn-wizard-auth")!; + const kinds = modalWizard.querySelector("#wizard-kinds")!; + const owyxField = modalWizard.querySelector("#wizard-owyx-field")!; + const emailInput = modalWizard.querySelector("#wizard-email")!; + const passwordInput = modalWizard.querySelector("#wizard-password")!; + const emailLabel = modalWizard.querySelector("#wizard-email-label")!; + const passwordLabel = modalWizard.querySelector("#wizard-password-label")!; + const adding = profiles.length > 0; + title.textContent = adding ? t("wizard.addTitle") : t("wizard.title"); + sub.textContent = adding ? t("wizard.addSubtitle") : t("wizard.subtitle"); + nickLabel.textContent = t("wizard.nick"); + nickInput.placeholder = t("wizard.nick.placeholder"); + authBtn.textContent = t("wizard.authBrowser"); + authBtn.title = t("wizard.authSoon"); + authBtn.setAttribute("aria-describedby", "wizard-hint"); + emailLabel.textContent = t("wizard.owyx.email"); + passwordLabel.textContent = t("wizard.owyx.password"); + emailInput.placeholder = t("wizard.owyx.email.placeholder"); + hint.textContent = ""; + modalWizard.querySelector("#wizard-status")!.textContent = ""; + + const primaryLabel = () => { + if (wizardKind === "owyx") return t("wizard.owyx.signIn"); + return adding ? t("wizard.add") : t("wizard.create"); + }; + + const syncWizardKindUi = () => { + const offline = wizardKind === "offline"; + const owyx = wizardKind === "owyx"; + nickField.hidden = !offline; + owyxField.hidden = !owyx; + // Microsoft runs the ms_auth pipeline (path B); Owyx uses the form. + authField.hidden = offline || owyx; + const authBtn = modalWizard.querySelector("#btn-wizard-auth")!; + authBtn.disabled = false; + authBtn.removeAttribute("disabled"); + authBtn.textContent = t("wizard.authBrowser"); + authBtn.title = t("wizard.ms.pipelineTitle"); + btn.textContent = primaryLabel(); + if (wizardKind === "microsoft") hint.textContent = t("wizard.security.microsoft"); + else if (owyx) hint.textContent = t("wizard.security.owyx"); + else hint.textContent = ""; + }; + + const paintKinds = () => { + kinds.replaceChildren(); + for (const kind of ["offline", "microsoft", "owyx"] as const) { + const card = document.createElement("button"); + card.type = "button"; + card.className = `wizard-kind${wizardKind === kind ? " is-selected" : ""}`; + card.innerHTML = ``; + card.querySelector("strong")!.textContent = t(`wizard.kind.${kind}`); + card.querySelector("span")!.textContent = t(`wizard.kind.${kind}.desc`); + card.addEventListener("click", () => { + wizardKind = kind; + paintKinds(); + syncWizardKindUi(); + }); + kinds.append(card); + } + syncWizardKindUi(); + }; + paintKinds(); + nickInput.value = ""; + emailInput.value = ""; + passwordInput.value = ""; + if (wizardKind === "offline") nickInput.focus(); +} + +/** Map an owyx-auth error code to a friendly, localized message. */ +function owyxAuthMessage(codeOrError: unknown): string { + const code = typeof codeOrError === "string" ? codeOrError : String(codeOrError); + const key = `wizard.owyx.error.${code}`; + const msg = t(key); + // If there is no specific translation, fall back to a generic one. + return msg === key ? t("wizard.owyx.error.server") : msg; +} + +async function finishOwyxWizard() { + const status = modalWizard.querySelector("#wizard-status")!; + const btn = modalWizard.querySelector("#btn-wizard")!; + const emailInput = modalWizard.querySelector("#wizard-email")!; + const passwordInput = modalWizard.querySelector("#wizard-password")!; + const email = emailInput.value.trim(); + const password = passwordInput.value; + + if (!email || !/^\S+@\S+\.\S+$/.test(email)) { + setStatus(status, t("wizard.owyx.needEmail"), "err"); + return; + } + if (!password || password.length < 6) { + setStatus(status, t("wizard.owyx.needPassword"), "err"); + return; + } + + btn.disabled = true; + setStatus(status, t("wizard.owyx.signingIn"), "muted"); + try { + const session = await owyxLogin(inTauri, null, email, password); + if (session.banned) { + setStatus(status, t("wizard.owyx.error.banned"), "err"); + // Do not create a playable profile for a banned account. + await owyxLogout(inTauri, session.nickname).catch(() => {}); + return; + } + // Real, authenticated Owyx profile: no more needsAuth, Play is unlocked. + const profile: Profile = { + id: `prof_${Date.now().toString(36)}`, + kind: "owyx", + name: session.nickname || "Owyx", + nick: session.nickname || "Player", + needsAuth: false, + authBlob: "owyx:session", + createdAt: Date.now(), + }; + profiles = [profile, ...profiles.filter((p) => p.id !== profile.id)]; + activeProfileId = profile.id; + owyxSession = session; + await persistProfiles(); + void applyAccountSkin(session.nickname); + hideModal(modalWizard); + if (shellReady) { + applyingHistory = true; + const route = currentNav().route === "instance" ? "home" : currentNav().route || "home"; + routeTo(route); + applyingHistory = false; + } + } catch (e) { + setStatus(status, owyxAuthMessage(e), "err"); + } finally { + btn.disabled = false; + } +} + +type MsWizardUiPhase = "idle" | "starting" | "waiting" | "scaffold" | "error" | "unconfigured"; + +let msAuthPollTimer: ReturnType | null = null; +let msAuthPollInFlight = false; +let msWizardUiPhase: MsWizardUiPhase = "idle"; + +function stopMsAuthPoll() { + if (msAuthPollTimer) { + clearInterval(msAuthPollTimer); + msAuthPollTimer = null; + } + msAuthPollInFlight = false; + void msAuthCancel(); + if (msWizardUiPhase === "waiting" || msWizardUiPhase === "starting") { + msWizardUiPhase = "idle"; + } + const authBtn = modalWizard.querySelector("#btn-wizard-auth"); + if (authBtn && !modalWizard.hidden) { + authBtn.disabled = false; + if (msWizardUiPhase === "idle") { + authBtn.textContent = t("wizard.authBrowser"); + } + } +} + +function paintMsAuthButton() { + const authBtn = modalWizard.querySelector("#btn-wizard-auth"); + if (!authBtn) return; + authBtn.disabled = false; + if (msWizardUiPhase === "waiting" || msWizardUiPhase === "starting") { + authBtn.textContent = t("wizard.ms.cancel"); + } else if (msWizardUiPhase === "scaffold" || msWizardUiPhase === "unconfigured" || msWizardUiPhase === "error") { + authBtn.textContent = t("wizard.ms.retry"); + } else { + authBtn.textContent = t("wizard.authBrowser"); + } +} + +/** Single click source for #btn-wizard-auth (no onclick mixing). */ +async function onMicrosoftAuthButtonClick() { + if (msWizardUiPhase === "waiting" || msWizardUiPhase === "starting") { + stopMsAuthPoll(); + msWizardUiPhase = "idle"; + const status = modalWizard.querySelector("#wizard-status")!; + setStatus(status, t("wizard.ms.cancelled"), "muted"); + paintMsAuthButton(); + return; + } + await startMicrosoftAuthFromWizard(); +} + +async function startMicrosoftAuthFromWizard() { + const status = modalWizard.querySelector("#wizard-status")!; + const hint = modalWizard.querySelector("#wizard-hint")!; + const authBtn = modalWizard.querySelector("#btn-wizard-auth")!; + stopMsAuthPoll(); + msWizardUiPhase = "starting"; + authBtn.disabled = true; + authBtn.textContent = t("wizard.ms.starting"); + setStatus(status, t("wizard.ms.starting"), "muted"); + hint.textContent = t("wizard.security.microsoft"); + + const started = await msAuthStart(); + if (started.phase === "unconfigured") { + msWizardUiPhase = "unconfigured"; + setStatus(status, t("wizard.ms.unconfigured"), "err"); + hint.textContent = t("wizard.ms.unconfiguredHint"); + paintMsAuthButton(); + return; + } + if (started.phase === "scaffold" || started.phase === "not_implemented") { + msWizardUiPhase = "scaffold"; + setStatus(status, t("wizard.ms.scaffold"), "muted"); + hint.textContent = started.message || t("wizard.ms.scaffoldHint"); + paintMsAuthButton(); + return; + } + if (started.phase === "error") { + msWizardUiPhase = "error"; + setStatus(status, started.message || t("wizard.ms.error"), "err"); + paintMsAuthButton(); + return; + } + if (started.phase !== "waiting") { + msWizardUiPhase = "error"; + setStatus(status, started.message || t("wizard.ms.error"), "err"); + paintMsAuthButton(); + return; + } + + // Real device-code waiting (only when Rust returns waiting + codes). + msWizardUiPhase = "waiting"; + if (started.userCode && started.verificationUri) { + hint.textContent = t("wizard.ms.codeHint", { + code: started.userCode, + uri: started.verificationUri, + }); + } else { + hint.textContent = started.message || t("wizard.ms.waiting"); + } + setStatus(status, t("wizard.ms.waiting"), "muted"); + paintMsAuthButton(); + + msAuthPollTimer = setInterval(() => { + if (msAuthPollInFlight) return; + msAuthPollInFlight = true; + void (async () => { + try { + const st = await msAuthPoll(); + if (st.phase === "success") { + stopMsAuthPoll(); + msWizardUiPhase = "idle"; + const profile = makeProfile("microsoft", st.gamertag || "Player"); + if (st.authBlob && st.authBlob.startsWith("ms1:")) { + profile.needsAuth = false; + profile.authBlob = st.authBlob; + profiles = [profile, ...profiles.filter((p) => p.id !== profile.id)]; + activeProfileId = profile.id; + await persistProfiles(); + setStatus(status, t("wizard.ms.success"), "ok"); + hint.textContent = t("wizard.ms.successHint"); + paintMsAuthButton(); + hideModal(modalWizard); + if (shellReady) { + applyingHistory = true; + const route = currentNav().route === "instance" ? "home" : currentNav().route || "home"; + routeTo(route); + applyingHistory = false; + } + return; + } + // No real blob — keep needsAuth (should not happen on Path A). + profile.needsAuth = true; + profile.authBlob = "pending:encrypted"; + profiles = [profile, ...profiles.filter((p) => p.id !== profile.id)]; + activeProfileId = profile.id; + await persistProfiles(); + setStatus(status, t("wizard.ms.successPending"), "muted"); + hint.textContent = t("wizard.ms.successPendingHint"); + paintMsAuthButton(); + return; + } + if (st.phase === "scaffold" || st.phase === "not_implemented") { + stopMsAuthPoll(); + msWizardUiPhase = "scaffold"; + setStatus(status, t("wizard.ms.scaffold"), "muted"); + hint.textContent = st.message || t("wizard.ms.scaffoldHint"); + paintMsAuthButton(); + return; + } + if (st.phase === "error" || st.phase === "unconfigured") { + stopMsAuthPoll(); + msWizardUiPhase = st.phase === "unconfigured" ? "unconfigured" : "error"; + setStatus(status, st.message || t("wizard.ms.error"), "err"); + paintMsAuthButton(); + } + } finally { + msAuthPollInFlight = false; + } + })(); + }, 2000); +} + +async function finishWizard() { + const nickInput = modalWizard.querySelector("#wizard-nick")!; + const status = modalWizard.querySelector("#wizard-status")!; + const nick = nickInput.value.trim(); + + // Owyx account: real sign-in against the site API. + if (wizardKind === "owyx") { + await finishOwyxWizard(); + return; + } + + if (wizardKind === "offline") { + if (!nick || !/^[A-Za-z0-9_]+$/.test(nick)) { + setStatus(status, t("wizard.needNick"), "err"); + return; + } + } + const profile = makeProfile(wizardKind, wizardKind === "offline" ? nick : nick || "Player"); + profiles = [profile, ...profiles.filter((p) => p.id !== profile.id)]; + activeProfileId = profile.id; + try { + stopMsAuthPoll(); + await persistProfiles(); + hideModal(modalWizard); + if (shellReady) { + applyingHistory = true; + const route = currentNav().route === "instance" ? "home" : currentNav().route || "home"; + routeTo(route); + applyingHistory = false; + } + } catch (e) { + setStatus(status, String(e), "err"); + } +} + +function setSplash(progress: number, key: string) { + splashFill.style.width = `${Math.max(0, Math.min(100, progress))}%`; + splashLabel.textContent = t(key); +} + +async function boot() { + setLocale(normalizeLocale(localStorage.getItem(STORAGE_LOCALE))); + setSplash(8, "splash.boot"); + await sleep(180); + setSplash(28, "splash.config"); + try { + if (inTauri) { + launcherCfg = await invoke("get_config"); + setLocale(normalizeLocale(launcherCfg.locale)); + } else { + setLocale(normalizeLocale(localStorage.getItem(STORAGE_LOCALE))); + } + } catch { + /* keep default locale */ + } + await sleep(160); + if (inTauri) { + try { + systemMemoryMb = await invoke("system_memory_mb"); + } catch { + systemMemoryMb = 16384; + } + // Kick off shared meta prefetch during splash (Modrinth-like), not only on Play. + try { + metaPrefetch = await invoke("meta_prefetch_status"); + if (!metaPrefetch.ready) { + void invoke("prefetch_shared_meta") + .then((s) => { + metaPrefetch = s; + if (s.ready) { + metaPrefetchFailed = false; + if (!activeInstallId) clearTitlebarBusy(t("status.ready")); + } + }) + .catch((e) => { + metaPrefetchFailed = true; + if (!activeInstallId) { + titlebarBusy = false; + hideTopProgress(); + setTitlebarMessage( + `${t("meta.failedContinue")} (${String(e).slice(0, 80)})`, + ); + } + }); + } + } catch { + /* ignore */ + } + } + + setSplash(55, "splash.profiles"); + await loadProfilesState(); + await refreshOwyxSession(); + await sleep(140); + setSplash(78, "splash.i18n"); + applyChromeI18n(); + await sleep(140); + setSplash(100, "splash.ready"); + await sleep(220); + + splashEl.classList.add("is-done"); + shellEl.classList.remove("is-booting"); + shellReady = true; + startParticles(particlesCanvas); + await hydrateInstancesFromDisk(); + + if (inTauri && !metaPrefetch.ready && !metaPrefetchFailed) { + setTitlebarBusy( + t("meta.prefetching"), + metaPrefetch.totalFiles > 0 + ? (metaPrefetch.doneFiles / metaPrefetch.totalFiles) * 100 + : 5, + ); + } else { + setTitlebarIdle(t("status.ready")); + } + + updateHistoryButtons(); + renderRecent(); + applyingHistory = true; + routeTo("home"); + applyingHistory = false; + updateHistoryButtons(); + ensureProfileGate(); +} + +function currentNav(): NavEntry { + return navHistory[navIndex] ?? { route: "home" }; +} + +function sameNav(a: NavEntry, b: NavEntry) { + return a.route === b.route && (a.instanceId ?? null) === (b.instanceId ?? null); +} + +function updateHistoryButtons() { + histBack.disabled = navIndex <= 0; + histForward.disabled = navIndex >= navHistory.length - 1; +} + +function pushHistory(entry: NavEntry) { + if (sameNav(currentNav(), entry)) { + updateHistoryButtons(); + return; + } + navHistory.splice(navIndex + 1); + navHistory.push(entry); + navIndex = navHistory.length - 1; + updateHistoryButtons(); +} + +function applyNav(entry: NavEntry) { + applyingHistory = true; + routeTo(entry.route, entry.instanceId ?? undefined); + applyingHistory = false; + updateHistoryButtons(); +} + +function goBack() { + if (navIndex <= 0) return; + navIndex -= 1; + applyNav(currentNav()); +} + +function goForward() { + if (navIndex >= navHistory.length - 1) return; + navIndex += 1; + applyNav(currentNav()); +} + +function normalizeInstance(raw: Partial & Pick): Instance { + return { + id: raw.id, + name: raw.name, + loader: raw.loader, + minecraft: raw.minecraft, + loaderVersion: raw.loaderVersion ?? "", + createdAt: raw.createdAt ?? Date.now(), + lastPlayedAt: raw.lastPlayedAt, + content: Array.isArray(raw.content) ? raw.content : [], + worlds: Array.isArray(raw.worlds) ? raw.worlds : [], + settings: { ...DEFAULT_SETTINGS(), ...(raw.settings ?? {}) }, + installStatus: raw.installStatus, + installMessage: raw.installMessage, + hasIcon: raw.hasIcon, + iconUrl: raw.iconUrl, + catalogServerId: raw.catalogServerId, + catalogPackId: raw.catalogPackId, + serverAddress: raw.serverAddress, + serverPort: raw.serverPort, + }; +} + +function loadInstances(): Instance[] { + try { + const raw = localStorage.getItem(STORAGE_INSTANCES); + if (!raw) return []; + const parsed = JSON.parse(raw) as Partial[]; + if (!Array.isArray(parsed)) return []; + return parsed + .filter((i) => i && typeof i.id === "string" && typeof i.name === "string") + .map((i) => normalizeInstance(i as Instance)); + } catch { + return []; + } +} + +function saveInstances() { + const slim = instances.map(({ iconUrl: _iconUrl, ...rest }) => rest); + localStorage.setItem(STORAGE_INSTANCES, JSON.stringify(slim)); +} + +type DiskInstance = { + id: string; + name: string; + loader: string; + minecraft: string; + loaderVersion: string; + createdAt: number; + status: string; + ready: boolean; + path: string; + hasIcon?: boolean; + catalogServerId?: string; + catalogPackId?: string; + serverAddress?: string; + serverPort?: number; +}; + +function createdAtMs(value: number): number { + if (!value) return Date.now(); + return value < 1e12 ? value * 1000 : value; +} + +function statusFromDisk(d: DiskInstance): Instance["installStatus"] { + if (d.status === "installing") { + // Stale "installing" after crash/restart must not trap UI — only live install stays installing. + return activeInstallId === d.id ? "installing" : "pending"; + } + if (d.status === "error") return "error"; + if (d.ready || d.status === "ready") return "ready"; + return "pending"; +} + +async function hydrateInstancesFromDisk(): Promise { + if (!inTauri) return; + try { + const disk = await invoke("list_instances"); + const prevById = new Map(instances.map((i) => [i.id, i])); + const merged = disk.map((d) => { + const prev = prevById.get(d.id); + return normalizeInstance({ + id: d.id, + name: d.name || prev?.name || d.id, + loader: d.loader || prev?.loader || "vanilla", + minecraft: d.minecraft || prev?.minecraft || "", + loaderVersion: d.loaderVersion || prev?.loaderVersion || "", + createdAt: createdAtMs(d.createdAt) || prev?.createdAt || Date.now(), + lastPlayedAt: prev?.lastPlayedAt, + content: prev?.content ?? [], + worlds: prev?.worlds ?? [], + settings: prev?.settings ?? DEFAULT_SETTINGS(), + installStatus: statusFromDisk(d), + installMessage: + prev?.installMessage || + (d.ready ? t("instance.installDone") : d.status === "error" ? t("instance.installFail") : undefined), + hasIcon: d.hasIcon ?? prev?.hasIcon, + iconUrl: d.hasIcon ? prev?.iconUrl : null, + catalogServerId: d.catalogServerId, + catalogPackId: d.catalogPackId, + serverAddress: d.serverAddress, + serverPort: d.serverPort, + }); + }); + const diskIds = new Set(disk.map((d) => d.id)); + const localOnly = instances.filter( + (i) => + !diskIds.has(i.id) && + (i.installStatus === "pending" || i.installStatus === "installing"), + ); + instances = [...merged, ...localOnly]; + if (selectedInstanceId && !instances.some((i) => i.id === selectedInstanceId)) { + selectedInstanceId = instances[0]?.id ?? null; + } + saveInstances(); + } catch (e) { + console.warn("hydrateInstancesFromDisk", e); + } +} + +async function deleteInstanceEverywhere(inst: Instance): Promise { + if (inTauri) { + try { + await invoke("delete_instance", { id: inst.id }); + } catch (e) { + topStatus.textContent = friendlyError(e); + return; + } + } + instances = instances.filter((i) => i.id !== inst.id); + saveInstances(); + selectedInstanceId = instances[0]?.id ?? null; + routeTo("library"); +} + +function prettyLoader(id: string) { + return LOADERS.find((l) => l.id === id)?.name ?? id; +} + +function applyInstanceIcon(el: Element, inst: Instance) { + const node = el as HTMLElement; + node.classList.toggle("has-image", Boolean(inst.iconUrl)); + node.replaceChildren(); + if (inst.iconUrl) { + const img = document.createElement("img"); + img.src = inst.iconUrl; + img.alt = ""; + node.append(img); + } else { + node.textContent = inst.name.slice(0, 1).toUpperCase(); + } + if (inst.hasIcon && inst.iconUrl == null && inTauri) { + void invoke("get_instance_icon", { id: inst.id }) + .then((url) => { + inst.iconUrl = url; + inst.hasIcon = Boolean(url); + if (node.isConnected) applyInstanceIcon(node, inst); + }) + .catch(() => { + inst.iconUrl = null; + inst.hasIcon = false; + }); + } +} + +function stopRunningPoll() { + if (runningPollTimer) { + clearInterval(runningPollTimer); + runningPollTimer = null; + } +} + +function startRunningPoll(inst: Instance) { + stopRunningPoll(); + if (!inTauri) return; + runningPollTimer = setInterval(() => { + void (async () => { + if (selectedInstanceId !== inst.id) { + stopRunningPoll(); + return; + } + try { + const running = await invoke("is_pack_running", { packId: inst.id }); + if (!running) { + stopRunningPoll(); + setTitlebarIdle(t("play.exited")); + await refreshPlayButton(inst); + } + } catch { + /* ignore */ + } + })(); + }, 1200); +} + +function setStatus(el: HTMLElement, text: string, kind: "ok" | "err" | "muted" = "muted") { + el.textContent = text; + el.dataset.kind = kind; +} + +function beginCreateRefresh() { + createRefreshEpoch += 1; + createVersionsReady = false; + readySpec = null; + btnCreate.disabled = true; + syncCreateWizardStep(); + return createRefreshEpoch; +} + +function setCreateReady(epoch: number, ready: boolean) { + if (epoch !== createRefreshEpoch) return; + createVersionsReady = ready; + btnCreate.disabled = !ready; + if (ready) { + readySpec = { + loader: selectedLoader, + minecraft: mcCombo.getValue(), + loaderVersion: selectedLoader === "vanilla" ? "" : loaderCombo.getValue(), + }; + } else { + readySpec = null; + } + syncCreateWizardStep(); +} + +function isProfileGateOpen(): boolean { + return !modalWizard.hidden && !wizardAllowClose; +} + +/** Map content route → rail highlight (Modrinth-like active states). */ +function railRouteFor(route: string): string { + if (route === "instance") return "library"; + if (route === "project") return browseInstanceId ? "library" : "browse"; + if (route === "browse") return "browse"; + if (route === "skins") return "skins"; + if (route === "stats") return "home"; + return route; +} + +function setRailHighlight(route: string) { + const railRoute = railRouteFor(route); + root.querySelectorAll(".rail-btn[data-route]").forEach((btn) => { + const active = btn.dataset.route === railRoute; + btn.classList.toggle("is-active", active); + if (active) btn.setAttribute("aria-current", "page"); + else btn.removeAttribute("aria-current"); + }); +} + +function contentRailRoute(): string { + return railRouteFor(currentNav().route); +} + +/** + * Settings is a modal overlay — not a content-route in history (P0-A / P1-F). + * Rail highlights Settings while open; close restores the underlying content route. + */ +function openAppSettingsOverlay() { + if (isProfileGateOpen()) return; + setRailHighlight("settings"); + void openAppSettingsModal(); +} + +function closeAppSettingsOverlay() { + hideModal(modalAppSettings); + setRailHighlight(contentRailRoute()); +} + +function routeTo(route: string, instanceId?: string) { + if (isProfileGateOpen()) return; + // Settings stays an overlay; never push it into content history. + if (route === "settings") { + openAppSettingsOverlay(); + return; + } + if (!modalAppSettings.hidden) hideModal(modalAppSettings); + if (route === "browse") { + browseInstanceId = instanceId ?? null; + if (instanceId) selectedInstanceId = instanceId; + } else if (route === "project") { + if (instanceId) { + browseInstanceId = instanceId; + selectedInstanceId = instanceId; + } + } else if (route !== "project" && route !== "instance") { + // leave browseInstanceId when returning via history + } + const entry: NavEntry = { + route, + instanceId: + route === "instance" || route === "browse" || route === "project" + ? (instanceId ?? selectedInstanceId ?? browseInstanceId) + : null, + }; + if (!applyingHistory) pushHistory(entry); + + setRailHighlight(route); + if (instanceId && (route === "instance" || route === "browse" || route === "project")) { + selectedInstanceId = instanceId; + } + paintCurrentRoute(route, instanceId); +} + +/** Re-render the visible content route without pushing history (locale hot-reload). */ +function paintCurrentRoute(route?: string, instanceId?: string) { + const nav = currentNav(); + // Skip leftover "settings" history entries — paint underlying content instead. + let r = route ?? nav.route; + let id = instanceId ?? nav.instanceId ?? undefined; + if (r === "settings") { + for (let i = navIndex - 1; i >= 0; i--) { + const prev = navHistory[i]; + if (prev && prev.route !== "settings") { + r = prev.route; + id = prev.instanceId ?? undefined; + break; + } + } + if (r === "settings") r = "home"; + } + animateMain(); + if (r === "home") renderHome(); + else if (r === "library") { + void hydrateInstancesFromDisk().finally(() => renderLibrary()); + } else if (r === "servers") renderServers(); + else if (r === "stats") renderStats(); + else if (r === "skins") renderSkins(); + else if (r === "browse") { + if (id) browseInstanceId = id; + void hydrateInstancesFromDisk().finally(() => renderBrowse()); + } else if (r === "project") { + if (id) browseInstanceId = id; + void hydrateInstancesFromDisk().finally(() => renderProject()); + } else if (r === "instance") { + if (id) selectedInstanceId = id; + void hydrateInstancesFromDisk().finally(() => renderInstance()); + } + renderRecent(); + updateHistoryButtons(); +} + +/** Modrinth-like library kind: origin/link, not loader. */ +function instanceLibraryKind(inst: Instance): "server" | "modpack" | "custom" { + if (inst.catalogServerId) return "server"; + if (inst.catalogPackId) return "modpack"; + return "custom"; +} + +function renderRecent() { + const recent = [...instances] + .sort((a, b) => (b.lastPlayedAt ?? b.createdAt) - (a.lastPlayedAt ?? a.createdAt)) + .slice(0, 6); + recentList.replaceChildren(); + for (const inst of recent) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `recent-btn${inst.id === selectedInstanceId ? " is-active" : ""}`; + btn.title = `${inst.name} · ${prettyLoader(inst.loader)} ${inst.minecraft}`; + const hue = Math.abs(hashHue(inst.id)) % 360; + btn.style.setProperty("--recent-hue", String(hue)); + btn.textContent = inst.name.slice(0, 1).toUpperCase(); + btn.addEventListener("click", () => { + selectedInstanceId = inst.id; + instanceTab = "content"; + routeTo("instance", inst.id); + }); + recentList.append(btn); + } +} + +function hashHue(s: string) { + let h = 0; + for (let i = 0; i < s.length; i++) h = (h * 31 + s.charCodeAt(i)) | 0; + return h; +} + +function formatRelative(ts?: number) { + if (!ts) return t("time.never"); + const diff = Date.now() - ts; + const min = Math.floor(diff / 60000); + if (min < 1) return t("time.now"); + if (min < 60) return t("time.minutesAgo", { n: min }); + const hrs = Math.floor(min / 60); + if (hrs < 48) return t("time.hoursAgo", { n: hrs }); + const days = Math.floor(hrs / 24); + return t("time.daysAgo", { n: days }); +} + +function renderHome() { + crumb.textContent = ` / ${t("nav.home")}`; + setTitlebarIdle(t("status.ready")); + const recent = [...instances] + .sort((a, b) => (b.lastPlayedAt ?? b.createdAt) - (a.lastPlayedAt ?? a.createdAt)) + .slice(0, 8); + main.innerHTML = ` +
+
+
+
+

${recent.length ? t("home.welcomeBack") : t("home.welcomeNew")}

+

${recent.length ? t("home.subtitleBack") : t("home.subtitleNew")}

+
+
+

${t("home.jump")}

+
+
+ + + +
+
+
+ +
+
+

${t("home.news")}

+
+
+ ${t("home.news.launcher")} +

${t("home.news.brand.title")}

+

${t("home.news.brand.body")}

+
+
+ ${t("home.news.servers")} +

${t("home.news.servers.title")}

+

${t("home.news.servers.body")}

+
+
+ ${t("home.news.launcher")} +

${t("home.news.profiles.title")}

+

${t("home.news.profiles.body")}

+
+
+ ${t("home.news.launcher")} +

${t("home.news.update.title")}

+

${t("home.news.update.body")}

+
+
+
+
+ `; + + mountPlayingAs(main.querySelector("#home-profile-slot")!, { + getProfiles: () => profiles, + getActiveId: () => activeProfileId, + setActiveId: (id) => { + activeProfileId = id; + }, + setProfiles: (next) => { + profiles = next; + }, + persist: async () => { + await persistProfiles(); + await refreshOwyxSession(); + }, + openWizard: openProfileWizard, + setStatus, + onRemove: (p) => { + // Forget any stored Owyx session when its profile is deleted (logout). + if (p.kind === "owyx") void owyxLogout(inTauri, p.nick); + }, + }); + + if (!profiles.length) { + window.setTimeout(() => ensureProfileGate(), 0); + } + + const jumpList = main.querySelector("#jump-list")!; + main.querySelector("#home-qa-create-2")?.addEventListener("click", () => { + openCreateModal(); + }); + main.querySelector("#home-qa-library-2")?.addEventListener("click", () => routeTo("library")); + main.querySelector("#home-qa-servers-2")?.addEventListener("click", () => routeTo("servers")); + if (!recent.length) { + jumpList.innerHTML = ` +
+

${t("home.jumpEmpty")}

+

${t("home.jumpEmptyHint")}

+
+ + + +
+
`; + jumpList.querySelector("#home-qa-create")?.addEventListener("click", () => { + openCreateModal(); + }); + jumpList.querySelector("#home-qa-library")?.addEventListener("click", () => routeTo("library")); + jumpList.querySelector("#home-qa-servers")?.addEventListener("click", () => routeTo("servers")); + main.querySelector("#home-quick-row")?.classList.add("is-hidden"); + return; + } + main.querySelector("#home-quick-row")?.classList.remove("is-hidden"); + for (const inst of recent) jumpList.append(jumpBackRow(inst)); +} + +function jumpBackRow(inst: Instance) { + const row = document.createElement("div"); + row.className = "jump-row"; + row.innerHTML = ` + +
+ + +
+ `; + applyInstanceIcon(row.querySelector(".instance-icon")!, inst); + row.querySelector("strong")!.textContent = inst.name; + row.querySelector("small")!.textContent = + `${formatRelative(inst.lastPlayedAt)} · ${prettyLoader(inst.loader)} ${inst.minecraft}`; + + const open = () => { + selectedInstanceId = inst.id; + instanceTab = "content"; + routeTo("instance", inst.id); + }; + row.querySelector(".jump-open")?.addEventListener("click", open); + row.querySelector("[data-open]")?.addEventListener("click", open); + row.querySelector(".btn-play")?.addEventListener("click", () => { + if (!ensureCanPlay()) return; + inst.lastPlayedAt = Date.now(); + saveInstances(); + renderRecent(); + void tryLaunch(inst); + const jumpList = main.querySelector("#jump-list"); + if (jumpList && main.querySelector(".home-page")) { + jumpList.replaceChildren(); + const recent = [...instances] + .sort((a, b) => (b.lastPlayedAt ?? b.createdAt) - (a.lastPlayedAt ?? a.createdAt)) + .slice(0, 8); + for (const item of recent) jumpList.append(jumpBackRow(item)); + } + }); + return row; +} + +function instanceRow(inst: Instance) { + const row = document.createElement("div"); + row.className = "instance-row"; + row.innerHTML = ` + +
+ +
+ `; + applyInstanceIcon(row.querySelector(".instance-icon")!, inst); + row.querySelector("strong")!.textContent = inst.name; + row.querySelector("small")!.textContent = + `${prettyLoader(inst.loader)} ${inst.minecraft}` + + (inst.loaderVersion ? ` · ${inst.loaderVersion}` : "") + + ` · ${formatRelative(inst.lastPlayedAt)}`; + + const open = () => { + selectedInstanceId = inst.id; + instanceTab = "content"; + routeTo("instance", inst.id); + }; + row.querySelector(".instance-open")?.addEventListener("click", open); + row.querySelector(".btn-play")?.addEventListener("click", (e) => { + e.stopPropagation(); + if (!ensureCanPlay()) return; + inst.lastPlayedAt = Date.now(); + saveInstances(); + renderRecent(); + void tryLaunch(inst); + }); + return row; +} + +function renderLibrary() { + crumb.textContent = ` / ${t("library.title")}`; + setTitlebarIdle(t("status.ready")); + main.innerHTML = ` +
+
+
+

${t("library.title")}

+
+ + + + +
+
+ +
+
+ +
+ +
+
+ +
+
+
+
+ `; + const list = main.querySelector("#lib-list")!; + const search = main.querySelector("#lib-search")!; + const sortSel = main.querySelector("#lib-sort")!; + const groupSel = main.querySelector("#lib-group")!; + sortSel.value = librarySort; + groupSel.value = libraryGroup; + + const matchesFilter = (inst: Instance) => { + const kind = instanceLibraryKind(inst); + if (libraryFilter === "servers") return kind === "server"; + if (libraryFilter === "modpacks") return kind === "modpack"; + if (libraryFilter === "custom") return kind === "custom"; + return true; + }; + + const paint = () => { + list.replaceChildren(); + librarySort = sortSel.value as typeof librarySort; + libraryGroup = groupSel.value as typeof libraryGroup; + const q = search.value.trim().toLowerCase(); + let filtered = instances.filter( + (i) => matchesFilter(i) && (!q || i.name.toLowerCase().includes(q)), + ); + filtered = [...filtered].sort((a, b) => { + if (librarySort === "played") { + return (b.lastPlayedAt ?? 0) - (a.lastPlayedAt ?? 0); + } + if (librarySort === "created") return b.createdAt - a.createdAt; + return a.name.localeCompare(b.name, "en"); + }); + if (!filtered.length) { + const emptyTitle = + libraryFilter === "servers" + ? t("library.empty.servers") + : libraryFilter === "modpacks" + ? t("library.empty.modpacks") + : libraryFilter === "custom" + ? t("library.empty.custom") + : t("library.empty"); + const emptyHint = + libraryFilter === "all" ? t("library.emptyHint") : t("library.emptyHint.filter"); + list.innerHTML = ` +
+

${emptyTitle}

+

${emptyHint}

+ +
`; + return; + } + + const appendGroup = (title: string | null, items: Instance[]) => { + if (title) { + const h = document.createElement("h3"); + h.className = "group-title"; + h.textContent = title; + list.append(h); + } + for (const inst of items) list.append(instanceRow(inst)); + }; + + if (libraryGroup === "none") { + appendGroup(null, filtered); + return; + } + const map = new Map(); + for (const inst of filtered) { + const key = + libraryGroup === "loader" + ? prettyLoader(inst.loader) + : inst.settings.group.trim() || t("library.group.ungrouped"); + const bucket = map.get(key) ?? []; + bucket.push(inst); + map.set(key, bucket); + } + for (const [title, items] of [...map.entries()].sort((a, b) => a[0].localeCompare(b[0], "en"))) { + appendGroup(title, items); + } + }; + search.addEventListener("input", paint); + sortSel.addEventListener("change", paint); + groupSel.addEventListener("change", paint); + main.querySelectorAll("[data-lib-filter]").forEach((btn) => { + btn.addEventListener("click", () => { + libraryFilter = (btn.dataset.libFilter ?? "all") as typeof libraryFilter; + main.querySelectorAll("[data-lib-filter]").forEach((b) => { + b.classList.toggle("is-active", b === btn); + }); + paint(); + }); + }); + paint(); +} + +function isOwyxAdmin(): boolean { + return owyxSession?.role === "admin"; +} + +async function refreshOwyxSession(): Promise { + const p = activeProfile(); + if (!p || p.kind !== "owyx" || !p.nick) { + owyxSession = null; + return; + } + try { + owyxSession = await owyxMe(inTauri, p.nick); + void applyAccountSkin(p.nick); + } catch (e) { + owyxSession = null; + if (String(e) === "no_session") { + p.needsAuth = true; + await persistProfiles().catch(() => {}); + } + } + if (currentNav().route === "servers") renderServers(); +} + +async function applyAccountSkin(nickname: string): Promise { + try { + const res = await owyxApplySkin(inTauri, nickname, selectedInstanceId); + if (res.applied) { + setTitlebarIdle(t("skin.applied")); + } + } catch { + /* skin is optional */ + } +} + +function renderServers() { + crumb.textContent = ` / ${t("nav.servers")}`; + setTitlebarIdle(t("status.ready")); + main.innerHTML = ` +
+
+
+

${t("servers.title")}

+

${t("servers.body")}

+
+
+ + ${isOwyxAdmin() ? `` : ""} +
+
+

${t("servers.loading")}

+
+ `; + main.querySelector("#btn-servers-refresh")?.addEventListener("click", () => void paintServersList()); + main.querySelector("#btn-servers-add")?.addEventListener("click", () => openServerAdminModal()); + void paintServersList(); +} + +async function paintServersList() { + const box = main.querySelector("#servers-list"); + if (!box) return; + box.innerHTML = `

${t("servers.loading")}

`; + const catalog = await loadCatalog(inTauri); + if (catalog.error && !catalog.servers.length) { + box.innerHTML = ` +
+ +

${t("servers.offline.title")}

+

${t("servers.offline.body")}

+
+ + +
+
`; + box.querySelector("#btn-servers-retry")?.addEventListener("click", () => void paintServersList()); + box.querySelector("#btn-servers-to-library-off")?.addEventListener("click", () => routeTo("library")); + return; + } + if (!catalog.servers.length) { + box.innerHTML = ` +
+ +

${t("servers.empty.title")}

+

${t("servers.empty.body")}

+
+ + +
+
`; + box.querySelector("#btn-servers-retry-empty")?.addEventListener("click", () => void paintServersList()); + box.querySelector("#btn-servers-to-library")?.addEventListener("click", () => routeTo("library")); + return; + } + box.replaceChildren(); + for (const server of catalog.servers) { + const inst = instances.find((i) => i.catalogServerId === server.id); + const card = document.createElement("article"); + card.className = "server-card"; + const address = `${server.address}:${server.port}`; + const version = [server.minecraft || server.pack?.minecraft, server.loader || server.pack?.loader] + .filter(Boolean) + .join(" · "); + const status = server.status?.online; + const statusLabel = + status === true + ? server.status?.players != null && server.status?.max != null + ? `${t("servers.online")} · ${t("servers.players", { players: server.status.players, max: server.status.max })}` + : t("servers.online") + : status === false + ? t("servers.offline") + : t("servers.statusUnknown"); + const unavailable = + server.pack != null && + (server.pack.downloadAvailable === false || + server.pack.sourceType === "sftp"); + const unavailableReason = t("servers.packUnavailable"); + card.innerHTML = ` + +
+

+

+

+
+ + ${server.requiresAccount ? `` : ""} +
+
+
+ + +
`; + card.querySelector("h3")!.textContent = server.name; + card.querySelector(".tiny")!.textContent = version || t("servers.unknownVersion"); + card.querySelector(".server-addr")!.textContent = address; + card.querySelector(".server-status")!.textContent = statusLabel; + if (server.iconUrl) { + try { + const iconUrl = new URL(server.iconUrl); + if (iconUrl.protocol === "https:" || iconUrl.protocol === "http:") { + const img = document.createElement("img"); + img.src = iconUrl.toString(); + img.alt = ""; + img.loading = "lazy"; + card.querySelector(".server-card-icon")!.append(img); + } + } catch { + // Keep the branded fallback when an admin supplied a bad icon URL. + } + } + const dl = card.querySelector("[data-act=download]")!; + const play = card.querySelector("[data-act=play]")!; + dl.textContent = inst?.installStatus === "ready" ? t("servers.update") : t("servers.download"); + play.textContent = t("servers.play"); + dl.disabled = unavailable; + play.disabled = unavailable; + if (unavailable) { + dl.title = unavailableReason; + play.title = unavailableReason; + } + dl.addEventListener("click", () => { + if (dl.disabled) return; + dl.disabled = true; + void downloadCatalogServer(server).finally(() => { + const current = instances.find((i) => i.catalogServerId === server.id); + dl.disabled = unavailable; + dl.textContent = current?.installStatus === "ready" ? t("servers.update") : t("servers.download"); + }); + }); + play.addEventListener("click", () => { + if (play.disabled) return; + void playCatalogServer(server); + }); + box.append(card); + } +} + +async function downloadCatalogServer(server: CatalogServer): Promise { + if ( + server.pack && + (server.pack.downloadAvailable === false || server.pack.sourceType === "sftp") + ) { + setTitlebarError(t("servers.packUnavailable")); + return null; + } + if ( + server.requiresAccount && + (activeProfile()?.kind !== "owyx" || + activeProfile()?.needsAuth || + owyxSession?.serverAccess !== true) + ) { + setTitlebarError(t("servers.needAccount")); + openProfileWizard({ allowClose: true }); + return null; + } + if (!inTauri) { + setTitlebarMessage(t("play.browser")); + const id = `srv-${server.id}`; + const inst = upsertCatalogInstance(server, id, "pending"); + return inst; + } + setTitlebarBusy(t("servers.downloading"), 8); + try { + const res = await installCatalogServer(inTauri, server); + const inst = upsertCatalogInstance(server, res.instanceId, res.ready ? "ready" : "error"); + inst.installMessage = res.message; + saveInstances(); + await hydrateInstancesFromDisk(); + const found = instances.find((i) => i.id === res.instanceId) ?? inst; + found.catalogServerId = server.id; + found.catalogPackId = server.packId ?? undefined; + found.serverAddress = server.address; + found.serverPort = server.port; + saveInstances(); + clearTitlebarBusy(t("servers.downloaded")); + return found; + } catch (e) { + setTitlebarError(friendlyError(e)); + return null; + } +} + +function upsertCatalogInstance(server: CatalogServer, id: string, status: Instance["installStatus"]): Instance { + const prev = instances.find((i) => i.id === id || i.catalogServerId === server.id); + const inst = normalizeInstance({ + id, + name: server.name, + loader: server.loader || server.pack?.loader || "vanilla", + minecraft: server.minecraft || server.pack?.minecraft || "1.21.1", + loaderVersion: prev?.loaderVersion || "", + createdAt: prev?.createdAt ?? Date.now(), + settings: prev?.settings ?? DEFAULT_SETTINGS(), + content: prev?.content ?? [], + worlds: prev?.worlds ?? [], + installStatus: status, + catalogServerId: server.id, + catalogPackId: server.packId ?? undefined, + serverAddress: server.address, + serverPort: server.port, + }); + instances = [inst, ...instances.filter((i) => i.id !== inst.id && i.catalogServerId !== server.id)]; + saveInstances(); + return inst; +} + +async function playCatalogServer(server: CatalogServer) { + if ( + server.requiresAccount && + (activeProfile()?.kind !== "owyx" || + activeProfile()?.needsAuth || + owyxSession?.serverAccess !== true) + ) { + setTitlebarError(t("servers.needAccount")); + openProfileWizard({ allowClose: true }); + return; + } + let inst = instances.find((i) => i.catalogServerId === server.id) ?? null; + if (!inst || inst.installStatus !== "ready") { + inst = await downloadCatalogServer(server); + } + if (!inst) return; + inst.serverAddress = server.address; + inst.serverPort = server.port; + saveInstances(); + await tryLaunch(inst); +} + +function openServerAdminModal() { + const existing = document.querySelector("#modal-server-admin"); + existing?.remove(); + const modal = document.createElement("div"); + modal.id = "modal-server-admin"; + modal.className = "modal"; + modal.setAttribute("role", "dialog"); + modal.setAttribute("aria-modal", "true"); + modal.setAttribute("aria-labelledby", "server-admin-title"); + modal.innerHTML = ` + `; + document.body.append(modal); + showModal(modal, 'input[name="name"]'); + modal.querySelectorAll("[data-close]").forEach((btn) => { + btn.addEventListener("click", () => { + const origin = modalFocusOrigins.get(modal); + modal.remove(); + origin?.focus(); + }); + }); + modal.querySelector("#server-admin-form")?.addEventListener("submit", (e) => { + e.preventDefault(); + void submitServerAdmin(modal); + }); +} + +async function submitServerAdmin(modal: HTMLElement) { + const form = modal.querySelector("#server-admin-form")!; + const status = modal.querySelector("#server-admin-status")!; + const nick = activeProfile()?.nick; + if (!nick || !owyxSession || owyxSession.role !== "admin") { + status.textContent = t("servers.admin.needAdmin"); + return; + } + const fd = new FormData(form); + const name = String(fd.get("name") || "").trim(); + const address = String(fd.get("address") || "").trim(); + const port = parseInt(String(fd.get("port") || "25565"), 10); + const minecraft = String(fd.get("minecraft") || "1.21.1").trim(); + const loader = String(fd.get("loader") || "vanilla").trim(); + const packUrl = String(fd.get("packUrl") || "").trim(); + status.textContent = t("servers.admin.saving"); + try { + let packId: string | undefined; + if (packUrl) { + const pack = await owyxAdminFetch(inTauri, nick, "POST", "/api/admin/packs", { + name: `${name} pack`, + minecraft, + loader, + sourceType: "http_zip", + source: { type: "http_zip", config: { url: packUrl } }, + published: true, + }); + packId = String((pack.pack as { id?: string } | undefined)?.id || ""); + } + await owyxAdminFetch(inTauri, nick, "POST", "/api/admin/servers", { + name, + address, + port, + kind: "owyx", + packId: packId || null, + minecraft, + loader, + requiresAccount: false, + published: true, + }); + modal.remove(); + setTitlebarIdle(t("servers.admin.created")); + void paintServersList(); + } catch (e) { + status.textContent = owyxAuthMessage(e); + } +} + +function renderStats() { + crumb.textContent = ` / ${t("nav.stats")}`; + setTitlebarIdle(t("status.ready")); + main.innerHTML = ` +
+
+ +

${t("stats.title")}

+

${t("stats.body")}

+ ${t("stats.soon")} +
+
+ `; +} + +function renderInstance() { + const inst = instances.find((i) => i.id === selectedInstanceId); + if (!inst) { + routeTo("library"); + return; + } + crumb.textContent = ` / ${inst.name}`; + setTitlebarIdle(`${prettyLoader(inst.loader)} ${inst.minecraft}`); + main.innerHTML = ` +
+
+
+
+
+

+

+
+
+
+ + + +
+
+
+ + + + + +
+
+
+ `; + applyInstanceIcon(main.querySelector(".instance-icon")!, inst); + main.querySelector("h1")!.textContent = inst.name; + main.querySelector("#inst-sub")!.textContent = + `Minecraft ${inst.minecraft} · ${prettyLoader(inst.loader)}` + + (inst.loaderVersion ? ` ${inst.loaderVersion}` : "") + + (inst.installStatus ? ` · ${t(`instance.status.${inst.installStatus}`)}` : ""); + + if (inst.installMessage) { + setTitlebarIdle(inst.installMessage); + } + + const tabs = main.querySelectorAll("#inst-tabs .tab"); + tabs.forEach((tabBtn) => { + tabBtn.classList.toggle("is-active", tabBtn.dataset.tab === instanceTab); + tabBtn.addEventListener("click", () => { + instanceTab = tabBtn.dataset.tab as typeof instanceTab; + renderInstance(); + }); + }); + + const panel = main.querySelector("#inst-panel")!; + if (instanceTab === "content") renderContentPanel(panel, inst); + else if (instanceTab === "files") renderFilesPanel(panel, inst); + else if (instanceTab === "worlds") renderWorldsPanel(panel, inst); + else if (instanceTab === "share") renderSharePanel(panel, inst); + else renderLogsPanel(panel, inst); + + main.querySelector("#btn-play")?.addEventListener("click", () => { + void onPlayClick(inst); + }); + main.querySelector("#btn-inst-settings")?.addEventListener("click", () => { + instanceSettingsTab = "general"; + renderInstanceSettings(inst); + }); + void refreshPlayButton(inst); + + const moreBtn = main.querySelector("#btn-inst-more")!; + const moreMenu = main.querySelector("#inst-more-menu")!; + moreBtn.addEventListener("click", (e) => { + e.stopPropagation(); + moreMenu.hidden = !moreMenu.hidden; + }); + moreMenu.addEventListener("click", (e) => e.stopPropagation()); + moreMenu.querySelectorAll("[data-more]").forEach((btn) => { + btn.addEventListener("click", () => { + moreMenu.hidden = true; + const action = btn.dataset.more; + if (action === "open-folder") { + if (!inTauri) { + setTitlebarMessage(t("files.openBrowser")); + return; + } + void invoke("open_instance_dir", { id: inst.id, which: "root" }).catch((e) => { + setTitlebarError(friendlyError(e)); + }); + } else if (action === "settings") { + instanceSettingsTab = "general"; + renderInstanceSettings(inst); + } else if (action === "dup") { + void duplicateInstanceOnDisk(inst); + } else if (action === "delete") { + void deleteInstanceEverywhere(inst); + } + }); + }); +} + +window.addEventListener("click", () => { + document.querySelectorAll(".menu").forEach((m) => { + m.hidden = true; + }); +}); + +function kindLabel(kind: ContentKind) { + if (kind === "mod") return t("content.kind.mod"); + if (kind === "resourcepack") return t("content.kind.resourcepack"); + if (kind === "datapack") return t("content.kind.datapack"); + return t("content.kind.shader"); +} + +function browseDepsBase() { + return { + t, + inTauri, + isSafeModrinthMediaUrl, + friendlyError, + prettyLoader, + setStatus: (msg: string) => { + setTitlebarMessage(msg); + }, + }; +} + +function renderBrowse() { + const inst = browseInstanceId + ? instances.find((i) => i.id === browseInstanceId) ?? null + : null; + if (inst) { + crumb.textContent = ` / ${inst.name} › ${t("browse.contentInstall")}`; + setTitlebarIdle( + t("browse.installMeta", { + mc: inst.minecraft, + loader: prettyLoader(inst.loader), + }), + ); + } else { + crumb.textContent = ` / ${t("nav.browse")}`; + setTitlebarIdle(t("status.ready")); + } + main.replaceChildren(); + mountBrowsePage(main, { + deps: { + ...browseDepsBase(), + onOpenProject: (hit, projectType) => { + selectedProjectHit = hit; + browseProjectType = projectType; + routeTo("project", inst?.id ?? browseInstanceId ?? undefined); + }, + onBackToContent: () => { + if (inst) { + selectedInstanceId = inst.id; + instanceTab = "content"; + routeTo("instance", inst.id); + } else { + routeTo("home"); + } + }, + getInstalledProjectIds: async () => { + const ids = new Set(); + if (!inst || !inTauri) return ids; + try { + const rows = await invoke< + Array<{ id: string; name: string; modrinthProjectId?: string | null }> + >("list_content", { id: inst.id }); + for (const r of rows) { + const pid = r.modrinthProjectId?.trim(); + if (pid) ids.add(pid); + } + } catch { + /* ignore */ + } + return ids; + }, + onModpackImported: async (instanceId) => { + await hydrateInstancesFromDisk(); + selectedInstanceId = instanceId; + routeTo("instance", instanceId); + }, + }, + instance: inst + ? { id: inst.id, name: inst.name, loader: inst.loader, minecraft: inst.minecraft } + : null, + projectType: browseProjectType, + onProjectTypeChange: (pt) => { + browseProjectType = pt; + }, + }); +} + +function renderProject() { + if (!selectedProjectHit) { + routeTo("browse", browseInstanceId ?? undefined); + return; + } + const inst = browseInstanceId + ? instances.find((i) => i.id === browseInstanceId) ?? null + : null; + const hit = selectedProjectHit; + crumb.textContent = inst + ? ` / ${inst.name} › ${hit.title}` + : ` / ${t("nav.browse")} › ${hit.title}`; + setTitlebarIdle(hit.title); + main.replaceChildren(); + mountProjectPage(main, hit, { + ...browseDepsBase(), + instance: inst + ? { id: inst.id, name: inst.name, loader: inst.loader, minecraft: inst.minecraft } + : null, + projectType: browseProjectType, + onOpenProject: () => {}, + onBack: () => routeTo("browse", inst?.id ?? browseInstanceId ?? undefined), + onModpackImported: async (instanceId) => { + await hydrateInstancesFromDisk(); + selectedInstanceId = instanceId; + routeTo("instance", instanceId); + }, + }); +} + +function renderSkins() { + crumb.textContent = ` / ${t("nav.skins")}`; + setTitlebarIdle(t("status.ready")); + const prof = activeProfile(); + main.replaceChildren(); + mountSkinsPage(main, { + t, + inTauri, + activeNick: prof?.nick ?? null, + owyxSkinUrl: owyxSession?.skinUrl ?? null, + setStatus: (msg, kind) => { + if (kind === "err") setTitlebarError(msg); + else setTitlebarMessage(msg); + }, + listSkins: async () => invoke("list_skins"), + applySkin: async (id) => { + await invoke("apply_local_skin", { + skinId: id, + instanceId: selectedInstanceId, + }); + }, + removeSkin: async (id) => { + await invoke("remove_skin", { skinId: id }); + }, + onApplyOwyxSkin: async () => { + const nick = prof?.nick; + if (!nick) throw new Error(t("skins.needOwyx")); + await applyAccountSkin(nick); + }, + onImportFile: async () => { + if (!inTauri) { + setTitlebarMessage(t("skins.importBrowser")); + return; + } + try { + const selected = await openDialog({ + multiple: false, + title: t("skins.import"), + filters: [{ name: "PNG", extensions: ["png"] }], + }); + if (typeof selected !== "string") return; + await invoke("import_skin", { path: selected, name: null }); + setTitlebarMessage(t("skins.imported")); + } catch (e) { + setTitlebarError(friendlyError(e)); + } + }, + }); +} + +function renderContentPanel(panel: HTMLElement, inst: Instance) { + panel.innerHTML = ` +
+ + + + + +
+
+
+ + + +
+
+ `; + + panel.querySelector("#btn-browse-content")?.addEventListener("click", () => { + browseProjectType = "mod"; + browseInstanceId = inst.id; + routeTo("browse", inst.id); + }); + + const filters = panel.querySelector("#content-filters")!; + const table = panel.querySelector("#content-table")!; + const search = panel.querySelector("#content-search")!; + const count = panel.querySelector("#content-count")!; + let items: ContentItem[] = []; + + const filterDefs: Array<{ id: typeof contentFilter; label: string }> = [ + { id: "all", label: t("content.filter.all") }, + { id: "mod", label: t("content.filter.mods") }, + { id: "resourcepack", label: t("content.filter.resourcepacks") }, + { id: "shader", label: t("content.filter.shaders") }, + { id: "datapack", label: t("content.filter.datapacks") }, + { id: "enabled", label: t("content.filter.enabled") }, + { id: "disabled", label: t("content.filter.disabled") }, + ]; + + const paintFilters = () => { + filters.replaceChildren(); + for (const f of filterDefs) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${contentFilter === f.id ? " is-selected" : ""}`; + btn.textContent = f.label; + btn.addEventListener("click", () => { + contentFilter = f.id; + paint(); + }); + filters.append(btn); + } + }; + + const load = async () => { + if (!inTauri) { + items = inst.content; + paint(); + return; + } + try { + const rows = await invoke< + Array<{ + id: string; + name: string; + kind: ContentKind; + fileName: string; + enabled: boolean; + size: number; + }> + >("list_content", { id: inst.id }); + items = rows.map((r) => ({ + id: r.id, + name: r.name, + author: "disk", + kind: r.kind, + version: "—", + fileName: r.fileName, + enabled: r.enabled, + })); + inst.content = items; + saveInstances(); + } catch (e) { + topStatus.textContent = friendlyError(e); + items = []; + } + paint(); + }; + + const paint = () => { + paintFilters(); + table.replaceChildren(); + const q = search.value.trim().toLowerCase(); + const rows = items.filter((item) => { + if ( + contentFilter === "mod" || + contentFilter === "resourcepack" || + contentFilter === "shader" || + contentFilter === "datapack" + ) { + if (item.kind !== contentFilter) return false; + } else if (contentFilter === "enabled" && !item.enabled) return false; + else if (contentFilter === "disabled" && item.enabled) return false; + if (!q) return true; + return ( + item.name.toLowerCase().includes(q) || item.fileName.toLowerCase().includes(q) + ); + }); + count.textContent = `${rows.length} / ${items.length}`; + search.placeholder = t("content.searchN", { n: items.length }); + + if (!items.length) { + table.innerHTML = ` +
+

${t("content.emptyTitle")}

+

${t("content.emptyHintBrowse")}

+ +
`; + table.querySelector("#content-empty-browse")?.addEventListener("click", () => { + browseProjectType = "mod"; + browseInstanceId = inst.id; + routeTo("browse", inst.id); + }); + return; + } + if (!rows.length) { + table.innerHTML = `

${t("content.noMatch")}

`; + return; + } + + const head = document.createElement("div"); + head.className = "content-head"; + head.innerHTML = `${t("content.colProject")}${t("content.colFile")}${t("content.colActions")}`; + table.append(head); + + for (const item of rows) { + const row = document.createElement("div"); + row.className = `content-row${item.enabled ? "" : " is-disabled"}`; + row.innerHTML = ` +
+ +
+ + +
+
+
+ + +
+
+ + +
+ `; + row.querySelector(".content-icon")!.textContent = kindLabel(item.kind).slice(0, 1); + row.querySelector(".content-project strong")!.textContent = item.name; + row.querySelector(".content-project small")!.textContent = + `${kindLabel(item.kind)}${item.author && item.author !== "disk" ? ` · ${item.author}` : ""}`; + row.querySelector(".content-version strong")!.textContent = item.fileName; + row.querySelector(".content-version small")!.textContent = item.enabled + ? t("content.enabled") + : t("content.disabled"); + const delBtn = row.querySelector("[data-del]")!; + delBtn.setAttribute("aria-label", t("content.deleteAria", { name: item.name })); + const toggle = row.querySelector("input[type=checkbox]")!; + toggle.checked = item.enabled; + toggle.addEventListener("change", () => { + void (async () => { + if (!inTauri) { + item.enabled = toggle.checked; + saveInstances(); + paint(); + return; + } + try { + await invoke("set_content_enabled", { + id: inst.id, + kind: item.kind, + fileName: item.fileName, + enabled: toggle.checked, + }); + await load(); + } catch (e) { + toggle.checked = item.enabled; + topStatus.textContent = friendlyError(e); + } + })(); + }); + row.querySelector("[data-del]")?.addEventListener("click", () => { + void (async () => { + if (!inTauri) return; + try { + await invoke("delete_content", { + id: inst.id, + kind: item.kind, + fileName: item.fileName, + }); + await load(); + } catch (e) { + topStatus.textContent = friendlyError(e); + } + })(); + }); + table.append(row); + } + }; + + const setAll = async (enabled: boolean) => { + if (!inTauri) return; + for (const item of items) { + if (item.enabled === enabled) continue; + try { + await invoke("set_content_enabled", { + id: inst.id, + kind: item.kind, + fileName: item.fileName, + enabled, + }); + } catch (e) { + topStatus.textContent = friendlyError(e); + break; + } + } + await load(); + }; + + const addFiles = async () => { + if (!inTauri) { + topStatus.textContent = t("content.addBrowser"); + return; + } + try { + const selected = await openDialog({ + multiple: true, + title: t("content.addDialogTitle"), + filters: [ + { name: "Minecraft content", extensions: ["jar", "zip"] }, + { name: "All", extensions: ["*"] }, + ], + }); + if (!selected) return; + const paths = Array.isArray(selected) ? selected : [selected]; + let added = 0; + for (const path of paths) { + if (typeof path !== "string" || !path) continue; + try { + await invoke("add_content_from_path", { id: inst.id, path, kind: null }); + added += 1; + } catch (e) { + topStatus.textContent = friendlyError(e); + } + } + if (added > 0) { + topStatus.textContent = + added === 1 ? t("content.added1") : t("content.addedN", { n: added }); + } + await load(); + } catch (e) { + topStatus.textContent = friendlyError(e); + } + }; + + search.addEventListener("input", paint); + panel.querySelector("[data-open-mods]")?.addEventListener("click", () => { + if (!inTauri) { + setTitlebarMessage(t("files.openBrowser")); + return; + } + void invoke("open_instance_dir", { id: inst.id, which: "mods" }).catch((e) => { + setTitlebarError(friendlyError(e)); + }); + }); + panel.querySelector("#btn-add-content")?.addEventListener("click", () => void addFiles()); + panel.querySelector("#btn-enable-all")?.addEventListener("click", () => void setAll(true)); + panel.querySelector("#btn-disable-all")?.addEventListener("click", () => void setAll(false)); + panel.querySelector("#btn-reload-content")?.addEventListener("click", () => void load()); + void load(); +} + +function renderSharePanel(panel: HTMLElement, inst: Instance) { + panel.innerHTML = ` +
+

${t("share.title")}

+

${t("share.body")}

+

${t("share.mrpackHint")}

+

${inst.name} · ${prettyLoader(inst.loader)} ${inst.minecraft}

+
+ + + +
+
+ `; + panel.querySelector("#share-export-mrpack")?.addEventListener("click", () => { + if (!inTauri) { + setTitlebarMessage(t("share.exportBrowser")); + return; + } + void (async () => { + try { + const dest = await saveDialog({ + title: t("share.exportMrpack"), + defaultPath: `${inst.name.replace(/[^\w\- ]+/g, "_")}.mrpack`, + filters: [{ name: "mrpack", extensions: ["mrpack"] }], + }); + if (typeof dest !== "string") return; + const msg = await invoke("export_mrpack", { + instanceId: inst.id, + destPath: dest, + }); + setTitlebarMessage(msg); + } catch (e) { + setTitlebarError(friendlyError(e)); + } + })(); + }); + panel.querySelector("#share-copy-name")?.addEventListener("click", () => { + void navigator.clipboard?.writeText(inst.name).then( + () => setTitlebarMessage(t("share.copied")), + () => setTitlebarMessage(inst.name), + ); + }); + panel.querySelector("#share-open-folder")?.addEventListener("click", () => { + if (!inTauri) { + setTitlebarMessage(t("files.openBrowser")); + return; + } + void invoke("open_instance_dir", { id: inst.id, which: "root" }).catch((e) => { + setTitlebarError(friendlyError(e)); + }); + }); +} + +function renderFilesPanel(panel: HTMLElement, inst: Instance) { + panel.innerHTML = ` +
+ + + + +
+

+
+ `; + const list = panel.querySelector("#files-list")!; + const pathEl = panel.querySelector("#files-path")!; + let rel = ""; + let loadSeq = 0; + + const openWhich = async (which: string) => { + if (!inTauri) { + topStatus.textContent = t("files.openBrowser"); + return; + } + try { + await invoke("open_instance_dir", { id: inst.id, which }); + } catch (e) { + topStatus.textContent = String(e); + } + }; + + panel.querySelectorAll("[data-open]").forEach((btn) => { + btn.addEventListener("click", () => void openWhich(btn.dataset.open || "game")); + }); + + const paint = async () => { + const seq = ++loadSeq; + pathEl.textContent = rel ? `game/${rel}` : "game/"; + list.innerHTML = `

${t("instance.files.loading")}

`; + if (!inTauri) { + list.innerHTML = `

${t("files.browser")}

`; + return; + } + try { + const entries = await invoke< + Array<{ name: string; path: string; isDir: boolean; size?: number | null }> + >("list_instance_dir", { id: inst.id, relative: rel || null }); + if (seq !== loadSeq) return; + list.replaceChildren(); + if (!entries.length) { + list.innerHTML = `

${t("files.emptyTitle")}

${t("files.emptyHint")}

`; + return; + } + if (rel) { + const up = document.createElement("button"); + up.type = "button"; + up.className = "content-row"; + up.style.width = "100%"; + up.textContent = "↑ .."; + up.addEventListener("click", () => { + const parts = rel.split("/").filter(Boolean); + parts.pop(); + rel = parts.join("/"); + void paint(); + }); + list.append(up); + } + const frag = document.createDocumentFragment(); + for (const entry of entries) { + const row = document.createElement("button"); + row.type = "button"; + row.className = "content-row"; + row.style.width = "100%"; + row.style.textAlign = "left"; + const size = + entry.isDir || entry.size == null + ? "" + : entry.size < 1024 + ? `${entry.size} B` + : entry.size < 1024 * 1024 + ? `${Math.round(entry.size / 1024)} KB` + : `${(entry.size / (1024 * 1024)).toFixed(1)} MB`; + row.innerHTML = ` `; + row.querySelector("strong")!.textContent = `${entry.isDir ? "📁 " : "📄 "}${entry.name}`; + row.querySelector("span")!.textContent = size; + row.addEventListener("click", () => { + if (entry.isDir) { + rel = entry.path; + void paint(); + } + }); + frag.append(row); + } + list.append(frag); + } catch (e) { + if (seq !== loadSeq) return; + list.replaceChildren(); + const err = document.createElement("p"); + err.className = "muted"; + err.textContent = String(e); + list.append(err); + } + }; + + panel.querySelector("#files-refresh")?.addEventListener("click", () => void paint()); + void paint(); +} + +type LogSource = { + id: string; + name: string; + source: string; + filename: string; + size: number; + modifiedAt: number; + live: boolean; +}; + +function renderLogsPanel(panel: HTMLElement, inst?: Instance) { + panel.innerHTML = ` +
+ + + + + +
+
+ `; + const sourceEl = panel.querySelector("#logs-source")!; + const levelEl = panel.querySelector("#logs-level")!; + const searchEl = panel.querySelector("#logs-search")!; + const consoleEl = panel.querySelector("#logs-console")!; + + let sources: LogSource[] = []; + let rawText = ""; + let selectedId = "live"; + let pollTimer: ReturnType | null = null; + let disposed = false; + let loadSeq = 0; + + const stopPoll = () => { + if (pollTimer) { + clearInterval(pollTimer); + pollTimer = null; + } + }; + + const lineLevel = (line: string): "error" | "warn" | "info" | "other" => { + const lower = line.toLowerCase(); + if ( + lower.includes("/error]") || + lower.includes("[error]") || + lower.includes(" exception") || + lower.includes("caused by:") || + /\berror\b/.test(lower) + ) { + return "error"; + } + if (lower.includes("/warn]") || lower.includes("[warn]") || /\bwarn(ing)?\b/.test(lower)) { + return "warn"; + } + if (lower.includes("/info]") || lower.includes("[info]") || /\binfo\b/.test(lower)) { + return "info"; + } + return "other"; + }; + + const paintConsole = () => { + const q = searchEl.value.trim().toLowerCase(); + const level = levelEl.value; + const lines = rawText.split(/\r?\n/); + const frag = document.createDocumentFragment(); + let shown = 0; + const maxPaint = 4_000; + for (const line of lines) { + if (!line && lines.length > 1) continue; + const lvl = lineLevel(line); + if (level === "error" && lvl !== "error") continue; + if (level === "warn" && lvl !== "warn" && lvl !== "error") continue; + if (level === "info" && lvl !== "info") continue; + if (q && !line.toLowerCase().includes(q)) continue; + const row = document.createElement("div"); + row.className = `log-line log-${lvl}`; + row.textContent = line || " "; + frag.append(row); + shown += 1; + if (shown >= maxPaint) break; + } + consoleEl.replaceChildren(frag); + if (!shown) { + const empty = document.createElement("div"); + empty.className = "logs-empty"; + if (selectedId === "live" && !rawText.trim()) { + empty.innerHTML = `

${t("instance.logs.emptyTitle")}

${t("instance.logs.emptyHint")}

`; + } else { + empty.innerHTML = `

${t("instance.logs.noMatches")}

`; + } + consoleEl.append(empty); + } else { + consoleEl.scrollTop = consoleEl.scrollHeight; + } + }; + + const fillSources = () => { + const prev = selectedId; + sourceEl.replaceChildren(); + for (const s of sources) { + const opt = document.createElement("option"); + opt.value = s.id; + opt.textContent = s.name; + sourceEl.append(opt); + } + if (sources.some((s) => s.id === prev)) { + sourceEl.value = prev; + selectedId = prev; + } else { + sourceEl.value = sources[0]?.id ?? "live"; + selectedId = sourceEl.value; + } + }; + + const loadSelected = async (opts?: { quiet?: boolean }) => { + if (!inst || !inTauri) { + rawText = ""; + paintConsole(); + return; + } + const seq = ++loadSeq; + const current = sources.find((s) => s.id === selectedId) ?? sources[0]; + if (!current) { + rawText = ""; + paintConsole(); + return; + } + if (!opts?.quiet) { + consoleEl.innerHTML = `

${t("instance.logs.loading")}

`; + } + try { + const text = await invoke("read_instance_log", { + packId: inst.id, + source: current.source, + filename: current.filename, + maxBytes: 512_000, + }); + if (disposed || seq !== loadSeq) return; + rawText = text; + paintConsole(); + } catch (e) { + if (disposed || seq !== loadSeq) return; + if (current.live) { + rawText = ""; + paintConsole(); + } else { + consoleEl.replaceChildren(); + const err = document.createElement("p"); + err.className = "muted"; + err.textContent = String(e); + consoleEl.append(err); + } + } + }; + + const refreshList = async () => { + if (!inst) { + sources = [{ id: "live", name: "Live Log", source: "live", filename: "", size: 0, modifiedAt: 0, live: true }]; + fillSources(); + rawText = ""; + paintConsole(); + return; + } + if (!inTauri) { + consoleEl.innerHTML = `

${t("instance.logs.browser")}

`; + return; + } + try { + sources = await invoke("list_instance_logs", { packId: inst.id }); + if (!sources.length) { + sources = [{ id: "live", name: "Live Log", source: "live", filename: "", size: 0, modifiedAt: 0, live: true }]; + } + fillSources(); + await loadSelected(); + } catch (e) { + consoleEl.replaceChildren(); + const err = document.createElement("p"); + err.className = "muted"; + err.textContent = String(e); + consoleEl.append(err); + } + }; + + const ensurePoll = () => { + stopPoll(); + const current = sources.find((s) => s.id === selectedId); + if (!current?.live || !inst || !inTauri) return; + pollTimer = setInterval(() => { + void loadSelected({ quiet: true }); + }, 1200); + }; + + panel.querySelector("#logs-open")?.addEventListener("click", () => { + if (!inTauri || !inst) { + setTitlebarMessage(t("files.openBrowser")); + return; + } + void invoke("open_instance_dir", { + id: inst.id, + which: "logs", + }).catch((e) => { + topStatus.textContent = String(e); + }); + }); + + panel.querySelector("#logs-refresh")?.addEventListener("click", () => { + void refreshList().then(() => ensurePoll()); + }); + + sourceEl.addEventListener("change", () => { + selectedId = sourceEl.value; + void loadSelected().then(() => ensurePoll()); + }); + levelEl.addEventListener("change", () => paintConsole()); + searchEl.addEventListener("input", () => paintConsole()); + + // Cleanup when panel is replaced (tab switch rewrites innerHTML of parent). + const observer = new MutationObserver(() => { + if (!panel.isConnected || !panel.contains(consoleEl)) { + disposed = true; + stopPoll(); + observer.disconnect(); + } + }); + observer.observe(panel.parentElement ?? document.body, { childList: true, subtree: true }); + + void refreshList().then(() => ensurePoll()); +} + +function renderWorldsPanel(panel: HTMLElement, inst: Instance) { + panel.innerHTML = ` +
+ + + +
+
+ `; + const list = panel.querySelector("#world-list")!; + const search = panel.querySelector("#world-search")!; + let worlds: WorldItem[] = []; + + const paint = () => { + list.replaceChildren(); + const q = search.value.trim().toLowerCase(); + const rows = worlds.filter((w) => !q || w.name.toLowerCase().includes(q)); + if (!worlds.length) { + list.innerHTML = ` +
+

${t("worlds.emptyTitle")}

+

${t("worlds.emptyHint")}

+
`; + return; + } + if (!rows.length) { + list.innerHTML = `

${t("worlds.noMatch")}

`; + return; + } + for (const world of rows) { + const row = document.createElement("div"); + row.className = "world-row"; + row.innerHTML = ` +
+
+ + +
+ + `; + const delWorld = row.querySelector("[data-del]")!; + delWorld.setAttribute("aria-label", t("worlds.deleteAria", { name: world.name })); + const iconEl = row.querySelector(".world-icon")!; + if (world.icon) { + iconEl.classList.add("has-image"); + const img = document.createElement("img"); + img.src = world.icon; + img.alt = ""; + iconEl.append(img); + } else { + iconEl.textContent = "♣"; + } + row.querySelector("strong")!.textContent = world.name; + row.querySelector("small")!.textContent = + `${world.mode} · ${new Date(world.lastPlayedAt).toLocaleString()}`; + row.querySelector("[data-del]")?.addEventListener("click", () => { + void (async () => { + if (!inTauri) return; + try { + await invoke("delete_world", { id: inst.id, worldId: world.id }); + await load(); + } catch (e) { + topStatus.textContent = friendlyError(e); + } + })(); + }); + list.append(row); + } + }; + + const load = async () => { + if (!inTauri) { + worlds = inst.worlds; + paint(); + return; + } + try { + const rows = await invoke< + Array<{ + id: string; + name: string; + mode: string; + lastPlayedAt: number; + hardcore?: boolean; + icon?: string | null; + }> + >("list_worlds", { id: inst.id }); + worlds = rows.map((w) => ({ + id: w.id, + name: w.name, + mode: w.hardcore ? "Hardcore" : w.mode, + lastPlayedAt: w.lastPlayedAt < 1e12 ? w.lastPlayedAt * 1000 : w.lastPlayedAt, + hardcore: Boolean(w.hardcore), + icon: w.icon ?? null, + })); + inst.worlds = worlds; + saveInstances(); + } catch (e) { + topStatus.textContent = friendlyError(e); + worlds = []; + } + paint(); + }; + + search.addEventListener("input", paint); + panel.querySelector("#btn-open-saves")?.addEventListener("click", () => { + if (!inTauri) { + setTitlebarMessage(t("files.openBrowser")); + return; + } + void invoke("open_instance_dir", { id: inst.id, which: "saves" }).catch((e) => { + setTitlebarError(friendlyError(e)); + }); + }); + panel.querySelector("#btn-reload-worlds")?.addEventListener("click", () => void load()); + void load(); +} + +function friendlyError(e: unknown): string { + const raw = String(e); + if (/install is already running/i.test(raw)) return t("error.installRunning"); + if (/Cannot delete instance while install/i.test(raw)) return t("error.cantDeleteInstalling"); + if (/Cannot duplicate while install/i.test(raw)) return t("error.cantDupInstalling"); + if (/(Download host not allowed|host not allowed|Only https)/i.test(raw)) return t("error.hostNotAllowed"); + if (/(File too large|too large)/i.test(raw)) return t("error.fileTooLarge"); + if (/Pack is not ready/i.test(raw)) return t("error.notReady"); + if (/Content file already exists/i.test(raw)) return t("error.contentExists"); + if (/Unable to infer content type/i.test(raw)) return t("error.inferType"); + if (/Source file not found/i.test(raw)) return t("error.sourceNotFound"); + // Modrinth install (MR-1) + if (/No compatible version/i.test(raw)) return t("error.noCompatVersion"); + if (/SHA-?512 verification/i.test(raw)) return t("error.hashFail"); + if (/no downloadable file/i.test(raw)) return t("error.noFile"); + // Launch / install / create + if (/Java \d+\+? not found/i.test(raw) || /Java .* -version probe/i.test(raw)) return t("error.javaMissing"); + if (/Nick (is required|may only)/i.test(raw)) return t("error.nickInvalid"); + if (/Minecraft version is required/i.test(raw)) return t("error.mcRequired"); + if (/Loader version is required/i.test(raw)) return t("error.loaderRequired"); + if (/Unsupported loader|is not supported/i.test(raw)) return t("error.unsupportedLoader"); + if (/(module-path|--launchTarget|installer (failed|timed out))/i.test(raw)) return t("error.modLoaderInstall"); + if (/No \.jar files in manifest/i.test(raw)) return t("error.noJars"); + if (/(timed out|timeout)/i.test(raw)) return t("error.timeout"); + if (/(SHA1 mismatch|Size mismatch|integrity check failed)/i.test(raw)) return t("error.integrity"); + if (/error sending request|dns error|connect|network|failed to lookup/i.test(raw)) return t("error.network"); + return raw.replace(/^Error:\s*/i, "").slice(0, 240); +} + +async function duplicateInstanceOnDisk(inst: Instance): Promise { + if (inst.installStatus === "installing") { + setTitlebarIdle(t("instance.waitInstall")); + return; + } + const newId = `inst_${Date.now().toString(36)}`; + const newName = `${inst.name} (copy)`.slice(0, 48); + if (!inTauri) { + const copy = normalizeInstance({ + ...structuredClone(inst), + id: newId, + name: newName, + createdAt: Date.now(), + lastPlayedAt: undefined, + }); + instances = [copy, ...instances]; + saveInstances(); + selectedInstanceId = copy.id; + routeTo("instance", copy.id); + return; + } + try { + setTitlebarMessage(t("instance.copying")); + const disk = await invoke("duplicate_instance", { + id: inst.id, + newId, + newName, + }); + await hydrateInstancesFromDisk(); + const found = instances.find((i) => i.id === disk.id); + if (found) { + found.settings = { ...structuredClone(inst.settings) }; + found.name = newName; + saveInstances(); + } + selectedInstanceId = disk.id; + setTitlebarIdle(t("instance.copied")); + routeTo("instance", disk.id); + } catch (e) { + setTitlebarMessage(friendlyError(e)); + } +} + +function renderInstanceSettings(inst: Instance) { + showModal(modalInstSettings); + modalInstSettings.querySelector("#inst-settings-title")!.textContent = + `${inst.name} · ${t("instance.settings.crumb")}`; + const nav = modalInstSettings.querySelector("#inst-settings-nav")!; + const pane = modalInstSettings.querySelector("#inst-settings-pane")!; + let installEditing = false; + + const tabs: Array<{ id: typeof instanceSettingsTab; label: string }> = [ + { id: "general", label: t("instance.settings.general") }, + { id: "install", label: t("instance.settings.install") }, + { id: "window", label: t("instance.settings.window") }, + { id: "java", label: t("instance.settings.java") }, + { id: "launch", label: t("instance.settings.launch") }, + ]; + + const paintNav = () => { + nav.replaceChildren(); + for (const tab of tabs) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `settings-link${instanceSettingsTab === tab.id ? " is-active" : ""}`; + btn.textContent = tab.label; + btn.addEventListener("click", () => { + instanceSettingsTab = tab.id; + installEditing = false; + void paint(); + }); + nav.append(btn); + } + }; + + const persistSettings = () => { + saveInstances(); + }; + + const paint = async () => { + paintNav(); + pane.replaceChildren(); + if (instanceSettingsTab === "general") { + const groups = [ + ...new Set( + instances + .map((i) => i.settings.group.trim()) + .filter(Boolean) + .concat(inst.settings.group.trim() ? [inst.settings.group.trim()] : []), + ), + ].sort((a, b) => a.localeCompare(b)); + pane.innerHTML = ` +

${t("instance.settings.general")}

+
+
+
+ + +
+
+ + +
+
+ +
+ ${t("instance.settings.group")} +

${t("instance.settings.groupHint")}

+
+
+ + +
+
+
+ ${t("instance.settings.channel")} +
+

+
+
+ +
+

+ `; + const rename = pane.querySelector("#rename")!; + const status = pane.querySelector("#iset-status")!; + rename.value = inst.name; + applyInstanceIcon(pane.querySelector("#iset-icon")!, inst); + rename.addEventListener("change", () => { + inst.name = (rename.value.trim() || inst.name).slice(0, 48); + persistSettings(); + setStatus(status, t("instance.settings.saved"), "ok"); + renderRecent(); + applyInstanceIcon(pane.querySelector("#iset-icon")!, inst); + }); + pane.querySelector("#iset-pick-icon")?.addEventListener("click", () => { + void (async () => { + if (!inTauri) { + setStatus(status, t("play.browser"), "muted"); + return; + } + const picked = await openDialog({ + multiple: false, + filters: [{ name: "Image", extensions: ["png", "jpg", "jpeg", "webp", "gif", "bmp"] }], + }); + const path = typeof picked === "string" ? picked : Array.isArray(picked) ? picked[0] : null; + if (!path) return; + try { + await invoke("set_instance_icon", { id: inst.id, path }); + const url = await invoke("get_instance_icon", { id: inst.id }); + inst.hasIcon = Boolean(url); + inst.iconUrl = url; + applyInstanceIcon(pane.querySelector("#iset-icon")!, inst); + const clearBtn = pane.querySelector("#iset-clear-icon"); + if (clearBtn) clearBtn.disabled = !inst.hasIcon; + setStatus(status, t("instance.settings.saved"), "ok"); + if (selectedInstanceId === inst.id) renderInstance(); + renderRecent(); + } catch (e) { + setStatus(status, friendlyError(e), "err"); + } + })(); + }); + pane.querySelector("#iset-clear-icon")?.addEventListener("click", () => { + void (async () => { + if (!inTauri) return; + try { + await invoke("set_instance_icon", { id: inst.id, path: null }); + inst.hasIcon = false; + inst.iconUrl = null; + applyInstanceIcon(pane.querySelector("#iset-icon")!, inst); + const clearBtn = pane.querySelector("#iset-clear-icon"); + if (clearBtn) clearBtn.disabled = true; + setStatus(status, t("instance.settings.saved"), "ok"); + if (selectedInstanceId === inst.id) renderInstance(); + renderRecent(); + } catch (e) { + setStatus(status, friendlyError(e), "err"); + } + })(); + }); + + const groupBox = pane.querySelector("#group-chips")!; + const paintGroups = () => { + groupBox.replaceChildren(); + for (const g of groups) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${inst.settings.group === g ? " is-selected" : ""}`; + btn.textContent = (inst.settings.group === g ? "✓ " : "") + g; + btn.addEventListener("click", () => { + inst.settings.group = inst.settings.group === g ? "" : g; + persistSettings(); + paintGroups(); + }); + groupBox.append(btn); + } + }; + paintGroups(); + pane.querySelector("#add-group")?.addEventListener("click", () => { + const input = pane.querySelector("#new-group")!; + const name = input.value.trim().slice(0, 32); + if (!name) return; + if (!groups.includes(name)) groups.push(name); + inst.settings.group = name; + input.value = ""; + persistSettings(); + paintGroups(); + }); + + const channelHint = pane.querySelector("#channel-hint")!; + const channelBox = pane.querySelector("#channel-chips")!; + const channelDesc: Record = { + release: t("instance.settings.channel.release"), + beta: t("instance.settings.channel.beta"), + alpha: t("instance.settings.channel.alpha"), + }; + for (const ch of ["release", "beta", "alpha"] as const) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${inst.settings.updateChannel === ch ? " is-selected" : ""}`; + btn.textContent = + (inst.settings.updateChannel === ch ? "✓ " : "") + + ch[0]!.toUpperCase() + + ch.slice(1); + btn.addEventListener("click", () => { + inst.settings.updateChannel = ch; + persistSettings(); + channelHint.textContent = channelDesc[ch] ?? ""; + void paint(); + }); + channelBox.append(btn); + } + channelHint.textContent = channelDesc[inst.settings.updateChannel] ?? ""; + + pane.querySelector("#dup-inst")?.addEventListener("click", () => { + void duplicateInstanceOnDisk(inst); + }); + pane.querySelector("#delete-inst")?.addEventListener("click", () => { + void deleteInstanceEverywhere(inst); + }); + } else if (instanceSettingsTab === "install") { + if (!installEditing) { + pane.innerHTML = ` +

${t("instance.settings.install")}

+
+
+
${t("instance.settings.platform")}
+
${t("instance.settings.minecraft")}
+
${t("instance.settings.loaderVersion")}
+
+ +

${t("instance.settings.changeWarn")}

+
+

${t("instance.settings.repair")}

+

${t("instance.settings.repairHint")}

+ +

+ `; + pane.querySelector("#i-loader")!.textContent = prettyLoader(inst.loader); + pane.querySelector("#i-mc")!.textContent = inst.minecraft; + pane.querySelector("#i-lv")!.textContent = + inst.loader === "vanilla" ? "—" : inst.loaderVersion || "—"; + pane.querySelector("#btn-change-install")?.addEventListener("click", () => { + installEditing = true; + void paint(); + }); + pane.querySelector("#btn-repair")?.addEventListener("click", () => { + void (async () => { + const status = pane.querySelector("#iset-status")!; + if (!inTauri) { + setStatus(status, t("play.browser"), "muted"); + return; + } + if (!metaPrefetch.ready && !metaPrefetchFailed) { + setStatus(status, t("meta.wait"), "err"); + return; + } + setStatus(status, t("instance.settings.repairing"), "muted"); + try { + hideModal(modalInstSettings); + await runInstall(inst); + } catch (e) { + setStatus(status, friendlyError(e), "err"); + } + })(); + }); + } else { + let editLoader = inst.loader; + let editShowSnapshots = false; + pane.innerHTML = ` +

${t("instance.settings.changeTitle")}

+
+ ${t("instance.settings.platform")} +
+
+
+ ${t("instance.settings.minecraft")} +
+
+
+ ${t("instance.settings.loaderVersion")} +
+
+ +

+ `; + const lvField = pane.querySelector("#edit-lv-field")!; + const lvLabel = pane.querySelector("#edit-lv-label")!; + const status = pane.querySelector("#iset-status")!; + const chipsBox = pane.querySelector("#edit-loader-chips")!; + const editMcHost = pane.querySelector("#edit-mc-host")!; + const editLvHost = pane.querySelector("#edit-lv-host")!; + + const editMcCombo = createVersionCombobox({ + searchPlaceholder: t("create.searchVersion"), + showAllToggle: true, + showAllLabel: t("create.showAllVersions"), + hideAllLabel: t("create.hideSnapshots"), + getShowAll: () => editShowSnapshots, + onShowAllChange: (v) => { + editShowSnapshots = v; + void refreshEditVersions(); + }, + onChange: () => { + void (async () => { + if (editLoader === "vanilla") return; + const loaders = await tauriOrBrowserLoaderVersions( + editLoader, + editMcCombo.getValue(), + ); + editLvCombo.setOptions(loaders, loaders[0]); + })(); + }, + }); + const editLvCombo = createVersionCombobox({ + searchPlaceholder: t("create.searchVersion"), + }); + editMcHost.append(editMcCombo.root); + editLvHost.append(editLvCombo.root); + + const refreshEditVersions = async () => { + setStatus(status, t("create.loadingVersions"), "muted"); + lvField.hidden = editLoader === "vanilla"; + lvLabel.textContent = t("create.loaderVersion", { loader: prettyLoader(editLoader) }); + try { + const ids = await tauriOrBrowserMcVersions(editLoader, editShowSnapshots); + editMcCombo.setOptions( + ids, + ids.includes(inst.minecraft) ? inst.minecraft : ids[0], + ); + if (editLoader === "vanilla") { + editLvCombo.setOptions([]); + } else { + const loaders = await tauriOrBrowserLoaderVersions( + editLoader, + editMcCombo.getValue(), + ); + editLvCombo.setOptions( + loaders, + loaders.includes(inst.loaderVersion) ? inst.loaderVersion : loaders[0], + ); + } + setStatus(status, "", "muted"); + } catch (e) { + setStatus(status, String(e), "err"); + } + }; + + const paintLoaderChips = () => { + chipsBox.replaceChildren(); + for (const loader of LOADERS) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${loader.id === editLoader ? " is-selected" : ""}`; + btn.textContent = (loader.id === editLoader ? "✓ " : "") + loader.name; + btn.addEventListener("click", () => { + editLoader = loader.id; + paintLoaderChips(); + void refreshEditVersions(); + }); + chipsBox.append(btn); + } + }; + paintLoaderChips(); + await refreshEditVersions(); + + pane.querySelector("#cancel-install")?.addEventListener("click", () => { + installEditing = false; + void paint(); + }); + pane.querySelector("#save-install")?.addEventListener("click", () => { + void (async () => { + const minecraft = editMcCombo.getValue(); + const loaderVersion = editLoader === "vanilla" ? "" : editLvCombo.getValue(); + if (!minecraft) { + setStatus(status, t("create.needMc"), "err"); + return; + } + if (editLoader !== "vanilla" && !loaderVersion) { + setStatus(status, t("create.needLoader"), "err"); + return; + } + try { + if (inTauri) { + await invoke("update_instance_installation", { + id: inst.id, + loader: editLoader, + minecraft, + loaderVersion, + }); + } + inst.loader = editLoader; + inst.minecraft = minecraft; + inst.loaderVersion = loaderVersion; + inst.installStatus = "pending"; + inst.installMessage = undefined; + persistSettings(); + installEditing = false; + setStatus(status, t("instance.settings.saved"), "ok"); + void paint(); + if (selectedInstanceId === inst.id) renderInstance(); + } catch (e) { + setStatus(status, friendlyError(e), "err"); + } + })(); + }); + } + } else if (instanceSettingsTab === "window") { + pane.innerHTML = ` +

${t("instance.settings.window")}

+
+
+ + +
+
+ + +
+
+ +

+ `; + const w = pane.querySelector("#w")!; + const h = pane.querySelector("#h")!; + const status = pane.querySelector("#iset-status")!; + w.value = String(inst.settings.width); + h.value = String(inst.settings.height); + pane.querySelector("#save-window")?.addEventListener("click", () => { + inst.settings.width = Math.min(7680, Math.max(640, Number(w.value) || 1280)); + inst.settings.height = Math.min(4320, Math.max(480, Number(h.value) || 720)); + persistSettings(); + setStatus(status, t("instance.settings.saved"), "ok"); + }); + } else if (instanceSettingsTab === "java") { + const maxMem = Math.max(512, systemMemoryMb); + const quickGb = [2, 3, 4, 6, 8, 10, 12, 16].filter((gb) => gb * 1024 <= maxMem); + pane.innerHTML = ` +

${t("instance.settings.javaInstall")}

+ +
+ + + +
+

${t("instance.settings.memory")}

+ +
+
+ +
+ 512 + ${maxMem} +
+
+
+ ${quickGb + .map( + (gb) => + ``, + ) + .join("")} +
+
+ + MB +
+
+

${t("instance.settings.jvmArgs")}

+ + +

${t("instance.settings.envVars")}

+ + +

+ `; + const ovJava = pane.querySelector("#ov-java")!; + const ovMem = pane.querySelector("#ov-mem")!; + const ovJvm = pane.querySelector("#ov-jvm")!; + const ovEnv = pane.querySelector("#ov-env")!; + const jpath = pane.querySelector("#jpath")!; + const memRange = pane.querySelector("#mem-range")!; + const mem = pane.querySelector("#mem")!; + const jvm = pane.querySelector("#jvm")!; + const env = pane.querySelector("#env")!; + const status = pane.querySelector("#iset-status")!; + ovJava.checked = inst.settings.overrideJavaPath; + ovMem.checked = inst.settings.overrideMemory; + ovJvm.checked = inst.settings.overrideJvmArgs; + ovEnv.checked = inst.settings.overrideEnvVars; + jpath.value = inst.settings.javaPath; + const initialMem = Math.min(maxMem, Math.max(512, inst.settings.memoryMb || 4096)); + mem.value = String(initialMem); + memRange.value = String(initialMem); + jvm.value = inst.settings.jvmArgs; + env.value = inst.settings.envVars; + + const syncDisabled = () => { + jpath.disabled = !ovJava.checked; + pane.querySelectorAll("#java-path-row button").forEach((b) => { + (b as HTMLButtonElement).disabled = !ovJava.checked; + }); + mem.disabled = !ovMem.checked; + memRange.disabled = !ovMem.checked; + pane.querySelectorAll(".memory-quick-btn").forEach((b) => { + b.disabled = !ovMem.checked; + }); + jvm.disabled = !ovJvm.checked; + env.disabled = !ovEnv.checked; + }; + const paintQuick = () => { + const cur = Number(mem.value) || 0; + pane.querySelectorAll(".memory-quick-btn").forEach((b) => { + const mb = Number(b.dataset.mb); + b.classList.toggle("is-selected", mb === cur); + }); + }; + const autosaveJava = () => { + inst.settings.overrideJavaPath = ovJava.checked; + inst.settings.overrideMemory = ovMem.checked; + inst.settings.overrideJvmArgs = ovJvm.checked; + inst.settings.overrideEnvVars = ovEnv.checked; + inst.settings.javaPath = jpath.value.trim(); + inst.settings.memoryMb = Math.min(maxMem, Math.max(512, Number(mem.value) || 4096)); + inst.settings.jvmArgs = jvm.value.slice(0, 2000); + inst.settings.envVars = env.value.slice(0, 2000); + mem.value = String(inst.settings.memoryMb); + memRange.value = String(inst.settings.memoryMb); + persistSettings(); + paintQuick(); + setStatus(status, t("instance.settings.saved"), "ok"); + }; + const setMemory = (mb: number) => { + const clamped = Math.min(maxMem, Math.max(512, mb)); + mem.value = String(clamped); + memRange.value = String(clamped); + autosaveJava(); + }; + syncDisabled(); + paintQuick(); + [ovJava, ovMem, ovJvm, ovEnv].forEach((el) => + el.addEventListener("change", () => { + syncDisabled(); + autosaveJava(); + }), + ); + memRange.addEventListener("input", () => { + mem.value = memRange.value; + paintQuick(); + setMemory(Number(memRange.value)); + }); + mem.addEventListener("input", () => { + memRange.value = mem.value; + paintQuick(); + }); + mem.addEventListener("change", () => setMemory(Number(mem.value))); + pane.querySelectorAll(".memory-quick-btn").forEach((btn) => { + btn.addEventListener("click", () => setMemory(Number(btn.dataset.mb))); + }); + jpath.addEventListener("change", () => autosaveJava()); + jvm.addEventListener("change", () => autosaveJava()); + env.addEventListener("change", () => autosaveJava()); + pane.querySelector("#btn-browse-java")?.addEventListener("click", () => { + void (async () => { + const picked = await openDialog({ multiple: false }); + if (typeof picked === "string") { + jpath.value = picked; + autosaveJava(); + } + })(); + }); + pane.querySelector("#btn-detect-java-inst")?.addEventListener("click", () => { + openJavaDetectModal(17, jpath.value, (path) => { + jpath.value = path; + autosaveJava(); + }); + }); + } else { + pane.innerHTML = ` +

${t("instance.settings.launch")}

+ +

${t("instance.settings.hooksHint")}

+
+ + +

${t("instance.settings.preLaunchHint")}

+
+
+ + +

${t("instance.settings.wrapperHint")}

+
+
+ + +

${t("instance.settings.postExitHint")}

+
+ +

+ `; + const ov = pane.querySelector("#ov-hooks")!; + const pre = pane.querySelector("#pre")!; + const wrap = pane.querySelector("#wrap")!; + const post = pane.querySelector("#post")!; + const status = pane.querySelector("#iset-status")!; + ov.checked = inst.settings.overrideHooks; + pre.value = inst.settings.preLaunch; + wrap.value = inst.settings.wrapper; + post.value = inst.settings.postExit; + const sync = () => { + pre.disabled = !ov.checked; + wrap.disabled = !ov.checked; + post.disabled = !ov.checked; + }; + sync(); + ov.addEventListener("change", sync); + pane.querySelector("#save-launch")?.addEventListener("click", () => { + inst.settings.overrideHooks = ov.checked; + inst.settings.preLaunch = pre.value.slice(0, 500); + inst.settings.wrapper = wrap.value.slice(0, 500); + inst.settings.postExit = post.value.slice(0, 500); + persistSettings(); + setStatus(status, t("instance.settings.saved"), "ok"); + }); + } + }; + + void paint().then(() => { + modalInstSettings.querySelector("#rename")?.focus(); + }); +} + +function openJavaDetectModal( + major: number, + currentPath: string, + onSelect: (path: string) => void, +) { + showModal(modalJavaDetect, "[data-close='java-detect']"); + modalJavaDetect.querySelector("#java-detect-title")!.textContent = t( + "settings.java.selectTitle", + ); + const list = modalJavaDetect.querySelector("#java-detect-list")!; + list.innerHTML = `

${t("settings.java.detecting")}

`; + javaDetectCallback = onSelect; + + void (async () => { + try { + let found: JavaInstallation[] = []; + if (inTauri) { + found = await invoke("find_java_for_major", { major }); + if (!found.length) { + found = await invoke("detect_java"); + found = found.filter((j) => j.majorVersion === major); + } + } + list.replaceChildren(); + if (!found.length) { + list.innerHTML = `

${t("settings.java.noneMajor", { n: major })}

`; + return; + } + for (const j of found) { + const row = document.createElement("div"); + row.className = "java-detect-row"; + const selected = j.path === currentPath; + row.innerHTML = `
`; + row.querySelector("strong")!.textContent = `Java ${j.version}`; + row.querySelector("code")!.textContent = j.path; + const btn = row.querySelector("button")!; + btn.textContent = selected ? t("settings.java.selected") : t("settings.java.select"); + btn.addEventListener("click", () => { + javaDetectCallback?.(j.path); + hideModal(modalJavaDetect); + javaDetectCallback = null; + }); + list.append(row); + } + } catch (e) { + list.replaceChildren(); + const err = document.createElement("p"); + err.className = "status is-err"; + err.textContent = String(e); + list.append(err); + } + })(); +} + +async function openAppSettingsModal() { + + showModal(modalAppSettings, "[data-close='app-settings']"); + modalAppSettings.querySelector("#app-settings-title")!.textContent = t("nav.settings"); + const nav = modalAppSettings.querySelector("#app-settings-nav")!; + const pane = modalAppSettings.querySelector("#app-settings-pane")!; + + const tabs: Array<{ id: typeof settingsTab; label: string }> = [ + { id: "appearance", label: t("settings.appearance") }, + { id: "java", label: t("settings.java") }, + { id: "localization", label: t("settings.localization") }, + { id: "behavior", label: t("settings.behavior") }, + { id: "updates", label: t("settings.updates") }, + ]; + + const paintNav = () => { + nav.replaceChildren(); + for (const tab of tabs) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `settings-link${settingsTab === tab.id ? " is-active" : ""}`; + btn.textContent = tab.label; + btn.addEventListener("click", () => { + settingsTab = tab.id; + void paint(); + }); + nav.append(btn); + } + }; + + const paint = async () => { + paintNav(); + pane.replaceChildren(); + if (settingsTab === "appearance") { + pane.innerHTML = ` +

${t("settings.appearance")}

+

${t("settings.appearance.desc")}

+ +

${t("settings.appearance.tokens")}

+ `; + return; + } + if (settingsTab === "behavior") { + pane.innerHTML = ` +

${t("settings.behavior")}

+

${t("settings.behavior.desc")}

+ + +

${t("settings.behavior.stub")}

+ `; + return; + } + if (settingsTab === "java") { + pane.innerHTML = ` +

${t("settings.java")}

+

${t("settings.java.desc")}

+
+

+ `; + const box = pane.querySelector("#java-majors")!; + const status = pane.querySelector("#settings-status")!; + const majors = [25, 21, 17, 8]; + const paths: Record = {}; + for (const m of majors) { + paths[m] = launcherCfg?.javaVersions?.[String(m)] ?? ""; + } + + const renderMajors = () => { + box.replaceChildren(); + for (const major of majors) { + const section = document.createElement("div"); + section.className = "java-major-block"; + section.innerHTML = ` +

${t("settings.java.location", { n: major })}

+
+ +
+
+ + + +
+ `; + const input = section.querySelector("input")!; + input.value = paths[major] ?? ""; + input.addEventListener("change", () => { + void (async () => { + const path = input.value.trim(); + paths[major] = path; + if (!inTauri) return; + try { + launcherCfg = await invoke("set_java_version", { + major, + path: path || null, + }); + setStatus(status, t("instance.settings.saved"), "ok"); + } catch (e) { + setStatus(status, String(e), "err"); + } + })(); + }); + section.querySelector(`[data-java-detect="${major}"]`)?.addEventListener("click", () => { + openJavaDetectModal(major, paths[major] ?? "", (path) => { + input.value = path; + paths[major] = path; + void (async () => { + if (!inTauri) return; + launcherCfg = await invoke("set_java_version", { major, path }); + setStatus(status, t("instance.settings.saved"), "ok"); + })(); + }); + }); + section.querySelector(`[data-java-browse="${major}"]`)?.addEventListener("click", () => { + void (async () => { + const picked = await openDialog({ multiple: false }); + if (typeof picked !== "string") return; + input.value = picked; + paths[major] = picked; + if (!inTauri) return; + launcherCfg = await invoke("set_java_version", { + major, + path: picked, + }); + setStatus(status, t("instance.settings.saved"), "ok"); + })(); + }); + section.querySelector(`[data-java-install="${major}"]`)?.addEventListener("click", () => { + void (async () => { + if (!inTauri) { + setStatus(status, t("play.browser"), "muted"); + return; + } + setStatus(status, t("settings.java.installing", { n: major }), "muted"); + try { + const installed = await invoke("install_java", { major }); + input.value = installed.path; + paths[major] = installed.path; + launcherCfg = await invoke("get_config"); + setStatus(status, t("settings.java.installed", { n: major }), "ok"); + } catch (e) { + setStatus(status, friendlyError(e), "err"); + } + })(); + }); + box.append(section); + } + }; + renderMajors(); + } else if (settingsTab === "localization") { + pane.innerHTML = ` +

${t("settings.localization")}

+

${t("settings.locale.desc")}

+
+

+ `; + const box = pane.querySelector("#locale-chips")!; + const status = pane.querySelector("#settings-status")!; + for (const loc of ["ru", "en"] as const) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${getLocale() === loc ? " is-selected" : ""}`; + btn.textContent = (getLocale() === loc ? "✓ " : "") + t(`settings.locale.${loc}`); + btn.addEventListener("click", () => { + void (async () => { + setLocale(loc); + localStorage.setItem(STORAGE_LOCALE, loc); + if (inTauri) { + launcherCfg = await invoke("set_locale", { locale: loc }); + } + applyChromeI18n(); + // Re-paint content under the modal (settings is not a content-route). + paintCurrentRoute(); + settingsTab = "localization"; + setRailHighlight("settings"); + await openAppSettingsModal(); + setStatus( + modalAppSettings.querySelector("#settings-status") ?? status, + "OK", + "ok", + ); + })(); + }); + box.append(btn); + } + } else { + const channel = launcherCfg?.updater?.channel ?? "stable"; + pane.innerHTML = ` +

${t("settings.updates")}

+

${t("settings.updates.desc")}

+

${t("settings.updates.channel")}: ${channel}

+ +

+ `; + const status = pane.querySelector("#settings-status")!; + pane.querySelector("#btn-check-updates")?.addEventListener("click", () => { + void (async () => { + try { + if (inTauri) { + launcherCfg = await invoke("check_updates"); + } + setStatus(status, t("settings.updates.stub", { channel }), "muted"); + } catch (e) { + setStatus(status, String(e), "err"); + } + })(); + }); + } + }; + + await paint(); +} + +async function onPlayClick(inst: Instance) { + if (!ensureCanPlay()) return; + if (inTauri) { + try { + const running = await invoke("is_pack_running", { packId: inst.id }); + if (running) { + await invoke("stop_pack", { packId: inst.id }); + setTitlebarIdle(t("play.stopped")); + await refreshPlayButton(inst); + return; + } + } catch { + /* ignore */ + } + } + if (inst.installStatus === "installing" && activeInstallId === inst.id) { + setTitlebarIdle(t("instance.waitInstall")); + return; + } + inst.lastPlayedAt = Date.now(); + saveInstances(); + renderRecent(); + void tryLaunch(inst); +} + +async function refreshPlayButton(inst: Instance) { + const btn = document.querySelector("#btn-play"); + if (!btn) return; + btn.classList.remove("btn-stop", "is-launching"); + if (inst.installStatus === "installing" && activeInstallId === inst.id) { + btn.disabled = true; + btn.textContent = `… ${t("instance.installing")}`; + stopRunningPoll(); + return; + } + btn.disabled = false; + if (inTauri) { + try { + const running = await invoke("is_pack_running", { packId: inst.id }); + if (running) { + btn.classList.add("btn-stop"); + btn.textContent = `■ ${t("play.stop")}`; + startRunningPoll(inst); + return; + } + } catch { + /* ignore */ + } + } + stopRunningPoll(); + btn.textContent = `▶ ${t("instance.play")}`; +} + +function shortProgressFile(file: string, max = 40): string { + if (file.length <= max) return file; + return `…${file.slice(-(max - 1))}`; +} + +function progressPct(p: InstallProgress): number { + if ( + p.fileBytesDone != null && + p.fileBytesTotal != null && + p.fileBytesTotal > 0 && + Number.isFinite(p.fileBytesDone) && + Number.isFinite(p.fileBytesTotal) + ) { + const fileFrac = Math.min(1, Math.max(0, p.fileBytesDone / p.fileBytesTotal)); + if (p.totalFiles > 0) { + // Blend file index with in-file bytes so large jars (client.jar) don't look stuck at 0/N. + return Math.min(99, ((p.doneFiles + fileFrac) / p.totalFiles) * 100); + } + return Math.min(99, fileFrac * 100); + } + if (p.totalFiles > 0) { + return Math.min(100, (p.doneFiles / p.totalFiles) * 100); + } + return 8; +} + +function updatePlayProgress(p: InstallProgress) { + updateDownloadTip(p); + if (p.packId === "__meta_prefetch__") { + metaPrefetch = { + ready: p.phase === "done", + message: p.message, + doneFiles: p.doneFiles, + totalFiles: p.totalFiles, + minecraft: metaPrefetch.minecraft, + }; + if (p.phase !== "done" && !activeInstallId) { + // Keep prefetch visually distinct from instance install (create must not look like install). + const file = p.currentFile ? shortProgressFile(p.currentFile) : ""; + const counts = p.totalFiles > 0 ? ` ${p.doneFiles}/${p.totalFiles}` : ""; + const detail = file ? ` · ${file}${counts}` : counts; + setTitlebarBusy(`${t("meta.prefetching")}${detail}`, progressPct(p)); + } + if (p.phase === "done") { + metaPrefetch.ready = true; + if (!activeInstallId) clearTitlebarBusy(t("status.ready")); + } + return; + } + // Global install progress — keep showing even when user navigates away. + const file = p.currentFile || p.message; + const short = shortProgressFile(file, 36); + const counts = p.totalFiles > 0 ? ` ${p.doneFiles}/${p.totalFiles}` : ""; + if (p.phase === "done") { + clearTitlebarBusy(p.message || t("status.ready")); + } else { + setTitlebarBusy(`${t("instance.installing")} ${short}${counts}`, progressPct(p)); + } +} + +function ensureMetaReady(inst?: Instance): boolean { + if (metaPrefetch.ready || !inTauri) return true; + if (inst?.installStatus === "ready") return true; + if (metaPrefetchFailed) { + setTitlebarIdle(t("meta.failedContinue")); + return true; + } + setTitlebarBusy(t("meta.wait"), metaPrefetch.totalFiles > 0 + ? Math.min(100, (metaPrefetch.doneFiles / metaPrefetch.totalFiles) * 100) + : 8); + return false; +} + +function launchOverrides(inst: Instance) { + const extraJvm = inst.settings.overrideJvmArgs + ? inst.settings.jvmArgs + .split(/\s+/) + .map((s) => s.trim()) + .filter(Boolean) + : []; + const envVars = inst.settings.overrideEnvVars + ? inst.settings.envVars + .trim() + .split(/\s+/) + .filter(Boolean) + .map((pair) => { + const i = pair.indexOf("="); + if (i <= 0) return null; + return [pair.slice(0, i), pair.slice(i + 1)] as [string, string]; + }) + .filter((x): x is [string, string] => Boolean(x)) + : []; + return { + memoryMb: inst.settings.overrideMemory ? inst.settings.memoryMb : undefined, + width: inst.settings.width, + height: inst.settings.height, + jvmArgs: extraJvm, + javaPath: inst.settings.overrideJavaPath ? inst.settings.javaPath || undefined : undefined, + envVars: envVars.length ? envVars : undefined, + preLaunch: inst.settings.overrideHooks ? inst.settings.preLaunch || undefined : undefined, + wrapper: inst.settings.overrideHooks ? inst.settings.wrapper || undefined : undefined, + postExit: inst.settings.overrideHooks ? inst.settings.postExit || undefined : undefined, + serverAddress: inst.serverAddress || undefined, + serverPort: inst.serverPort || undefined, + }; +} + +async function tryLaunch(inst: Instance) { + if (!ensureCanPlay()) return; + if (!inTauri) { + setTitlebarMessage(t("play.browser")); + return; + } + if (!ensureMetaReady(inst)) return; + const btn = document.querySelector("#btn-play"); + // Modrinth-like: Play installs when needed, then launches — never dead-end on "install first". + if (inst.installStatus !== "ready") { + await runInstall(inst); + } + if (inst.installStatus !== "ready") return; + + const invokeLaunch = () => + invoke<{ message: string; pid: number }>("launch_pack", { + packId: inst.id, + overrides: launchOverrides(inst), + }); + + try { + if (btn) { + btn.disabled = true; + btn.classList.add("is-launching"); + btn.textContent = `… ${t("play.launching")}`; + } + setTitlebarMessage(t("play.launching")); + let res: { message: string; pid: number }; + try { + res = await invokeLaunch(); + } catch (e) { + // Stale "ready" marker / missing shared jars — repair once then retry launch. + if (!/Pack is not ready/i.test(String(e))) throw e; + setTitlebarBusy(t("instance.installing"), 5); + await runInstall(inst); + if (inst.installStatus !== "ready") { + // Button was already set to launching; restore Play CTA on failed repair. + await refreshPlayButton(inst); + return; + } + if (btn) { + btn.disabled = true; + btn.classList.add("is-launching"); + btn.textContent = `… ${t("play.launching")}`; + } + setTitlebarMessage(t("play.launching")); + res = await invokeLaunch(); + } + clearTitlebarBusy(res.message || `PID ${res.pid}`); + await refreshPlayButton(inst); + } catch (e) { + titlebarBusy = false; + hideTopProgress(); + setTitlebarMessage(friendlyError(e)); + await refreshPlayButton(inst); + } +} + +async function runInstall(inst: Instance) { + if (!inTauri) { + inst.installStatus = "ready"; + inst.installMessage = t("play.browser"); + saveInstances(); + return; + } + if (!ensureMetaReady(inst)) return; + activeInstallId = inst.id; + inst.installStatus = "installing"; + inst.installMessage = t("instance.installing"); + saveInstances(); + setTitlebarBusy(t("instance.installing"), 5); + if (document.querySelector(".instance-page") && selectedInstanceId === inst.id) { + renderInstance(); + } + try { + const status = await invoke<{ ready: boolean; version?: string }>("install_instance", { + id: inst.id, + name: inst.name, + loader: inst.loader, + minecraft: inst.minecraft, + loaderVersion: inst.loaderVersion, + }); + inst.installStatus = status.ready ? "ready" : "error"; + inst.installMessage = status.ready + ? `${t("instance.installDone")}${status.version ? ` · ${status.version}` : ""}` + : t("instance.installFail"); + saveInstances(); + await hydrateInstancesFromDisk(); + clearTitlebarBusy(inst.installMessage); + if (selectedInstanceId === inst.id && document.querySelector(".instance-page")) { + renderInstance(); + } + } catch (e) { + inst.installStatus = "error"; + inst.installMessage = friendlyError(e); + saveInstances(); + setTitlebarError(inst.installMessage); + if (document.querySelector(".instance-page") && selectedInstanceId === inst.id) { + renderInstance(); + } + } finally { + if (activeInstallId === inst.id) activeInstallId = null; + } +} + +function suggestedInstanceName(): string { + const minecraft = mcCombo.getValue() || readySpec?.minecraft || ""; + const loader = selectedLoader || readySpec?.loader || "vanilla"; + if (!minecraft) return prettyLoader(loader); + if (loader === "vanilla") return `Vanilla ${minecraft}`; + return `${prettyLoader(loader)} ${minecraft}`; +} + +function refreshCreateNameHint() { + instName.placeholder = suggestedInstanceName(); +} + +function paintCreateIconPreview() { + createIconPreview.replaceChildren(); + createIconPreview.classList.toggle("has-image", Boolean(createIconDataUrl)); + if (createIconDataUrl) { + const img = document.createElement("img"); + img.src = createIconDataUrl; + img.alt = ""; + createIconPreview.append(img); + } else { + createIconPreview.textContent = (instName.value.trim() || suggestedInstanceName() || "?").slice(0, 1).toUpperCase(); + } + btnCreateIconClear.disabled = !createIconPath; +} + +async function pickCreateIcon() { + if (!inTauri) { + setStatus(createStatus, t("play.browser"), "muted"); + return; + } + const picked = await openDialog({ + multiple: false, + filters: [{ name: "Image", extensions: ["png", "jpg", "jpeg", "webp", "gif", "bmp"] }], + }); + const path = typeof picked === "string" ? picked : Array.isArray(picked) ? picked[0] : null; + if (!path) return; + try { + const dataUrl = await invoke("read_image_data_url", { path }); + createIconPath = path; + createIconDataUrl = dataUrl; + paintCreateIconPreview(); + } catch (e) { + setStatus(createStatus, friendlyError(e), "err"); + } +} + +function clearCreateIcon() { + createIconPath = null; + createIconDataUrl = null; + paintCreateIconPreview(); +} + +async function createInstance() { + // Prefer live select values; fall back to readySpec when still syncing. + const minecraft = mcCombo.getValue() || readySpec?.minecraft || ""; + const loader = selectedLoader || readySpec?.loader || "vanilla"; + const loaderVersion = + loader === "vanilla" + ? "" + : loaderCombo.getValue() || readySpec?.loaderVersion || ""; + + if (!minecraft) { + setStatus(createStatus, t("create.needMc"), "err"); + return; + } + if (loader !== "vanilla" && !loaderVersion) { + setStatus(createStatus, t("create.needLoader"), "err"); + return; + } + + const name = instName.value.trim() || suggestedInstanceName(); + setStatus(createStatus, t("create.preparing"), "muted"); + + try { + let disk: DiskInstance | null = null; + if (inTauri) { + disk = await invoke("prepare_instance", { + name, + loader, + minecraft, + loaderVersion, + iconPath: createIconPath, + }); + } + const id = + disk?.id ?? + `inst_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 7)}`; + const inst = normalizeInstance({ + id, + name: (disk?.name || name).slice(0, 48), + loader: disk?.loader || loader, + minecraft: disk?.minecraft || minecraft, + loaderVersion: disk?.loaderVersion || loaderVersion, + createdAt: disk ? createdAtMs(disk.createdAt) : Date.now(), + content: [], + worlds: [], + settings: DEFAULT_SETTINGS(), + installStatus: "pending", + installMessage: undefined, + hasIcon: disk?.hasIcon ?? Boolean(createIconDataUrl), + iconUrl: createIconDataUrl ?? (disk?.hasIcon ? undefined : null), + }); + instances = [inst, ...instances.filter((i) => i.id !== id)]; + saveInstances(); + selectedInstanceId = id; + instanceTab = "content"; + closeCreateModal(); + routeTo("instance", id); + } catch (e) { + setStatus(createStatus, friendlyError(e), "err"); + } +} + +const CREATE_STEP_KEYS = [ + "", + "create.step.loader", + "create.step.mc", + "create.step.loaderVer", + "create.step.name", + "create.step.icon", +] as const; + +function createMaxStep(): number { + return 5; +} + +function syncCreateWizardStep() { + const max = createMaxStep(); + if (createWizardStep < 1) createWizardStep = 1; + if (createWizardStep > max) createWizardStep = max; + for (let i = 1; i <= 5; i++) { + const panel = modalCreate.querySelector(`#create-step-${i}`); + if (panel) panel.hidden = createWizardStep !== i; + } + modalCreate.querySelectorAll("[data-cstep]").forEach((el) => { + const n = Number(el.dataset.cstep); + el.classList.toggle("is-active", n === createWizardStep); + el.classList.toggle("is-done", n < createWizardStep); + }); + const label = modalCreate.querySelector("#create-step-label"); + if (label) label.textContent = t(CREATE_STEP_KEYS[createWizardStep] || "create.title"); + const vanillaSkip = modalCreate.querySelector("#create-vanilla-skip"); + if (vanillaSkip) vanillaSkip.hidden = !(createWizardStep === 3 && selectedLoader === "vanilla"); + const loaderField = modalCreate.querySelector("#loader-version-field"); + if (loaderField) loaderField.hidden = selectedLoader === "vanilla"; + const nextBtn = modalCreate.querySelector("#btn-create-next")!; + const submitBtn = modalCreate.querySelector("#btn-create")!; + const backBtn = modalCreate.querySelector("#btn-create-back")!; + backBtn.hidden = createWizardStep <= 1; + const last = createWizardStep >= max; + nextBtn.hidden = last; + submitBtn.hidden = !last; + if (!last) { + nextBtn.disabled = !canAdvanceCreateStep(); + } else { + submitBtn.disabled = !canAdvanceCreateStep(); + } +} + +function canAdvanceCreateStep(): boolean { + if (createWizardStep === 1) return Boolean(selectedLoader); + if (createWizardStep === 2) return Boolean(mcCombo.getValue()); + if (createWizardStep === 3) { + if (selectedLoader === "vanilla") return true; + return Boolean(loaderCombo.getValue()); + } + if (createWizardStep === 4) return Boolean(instName.value.trim()); + if (createWizardStep === 5) return true; // icon optional + return false; +} + +function advanceCreateStep() { + if (!canAdvanceCreateStep()) return; + if (createWizardStep === 1) { + beginCreateRefresh(); + void refreshMinecraftVersions().then(() => { + syncCreateWizardStep(); + }); + } + if (createWizardStep === 2) { + void refreshLoaderVersions().then(() => syncCreateWizardStep()); + } + if (createWizardStep >= createMaxStep()) return; + createWizardStep += 1; + // Skip loader-version step content is still shown with vanilla skip hint + syncCreateWizardStep(); + if (createWizardStep === 4) { + refreshCreateNameHint(); + instName.focus(); + } + if (createWizardStep === 5) paintCreateIconPreview(); +} + +function retreatCreateStep() { + if (createWizardStep <= 1) return; + createWizardStep -= 1; + syncCreateWizardStep(); +} + +function openCreateModal() { + createWizardStep = 1; + showModal(modalCreate, "#loader-chips"); + instName.value = ""; + selectedLoader = "vanilla"; + createShowSnapshots = false; + clearCreateIcon(); + mcCombo.close(); + loaderCombo.close(); + mcCombo.setLabels({ + showAll: t("create.showAllVersions"), + hideAll: t("create.hideSnapshots"), + placeholder: t("create.searchVersion"), + toggle: t("create.toggleVersions"), + empty: t("create.noVersions"), + }); + loaderCombo.setLabels({ + placeholder: t("create.searchVersion"), + toggle: t("create.toggleVersions"), + empty: t("create.noVersions"), + }); + beginCreateRefresh(); + renderChips(); + refreshCreateNameHint(); + paintCreateIconPreview(); + syncCreateWizardStep(); + void refreshMinecraftVersions().then(() => { + refreshCreateNameHint(); + paintCreateIconPreview(); + syncCreateWizardStep(); + }); +} + +function closeCreateModal() { + mcCombo.close(); + loaderCombo.close(); + hideModal(modalCreate); + clearCreateIcon(); +} + +function renderChips() { + chips.replaceChildren(); + for (const loader of LOADERS) { + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = `chip${loader.id === selectedLoader ? " is-selected" : ""}`; + btn.textContent = (loader.id === selectedLoader ? "✓ " : "") + loader.name; + btn.addEventListener("click", () => { + selectedLoader = loader.id; + renderChips(); + refreshCreateNameHint(); + syncCreateWizardStep(); + void refreshMinecraftVersions().then(() => syncCreateWizardStep()); + }); + chips.append(btn); + } +} + +async function tauriOrBrowserMcVersions(loader: string, includeSnapshots: boolean) { + if (inTauri) { + const rows = await invoke>("list_minecraft_versions", { + loader, + includeSnapshots, + }); + return rows.map((r) => r.id); + } + if (loader === "fabric") { + const res = await fetch("/proxy/fabric/v2/versions/game"); + const data = (await res.json()) as Array<{ version: string; stable: boolean }>; + return data.filter((v) => includeSnapshots || v.stable).map((v) => v.version); + } + const res = await fetch("/proxy/mojang/mc/game/version_manifest_v2.json"); + const data = (await res.json()) as { versions: Array<{ id: string; type: string }> }; + return data.versions + .filter((v) => includeSnapshots || v.type === "release") + .map((v) => v.id); +} + +async function tauriOrBrowserLoaderVersions(loader: string, minecraft: string) { + if (loader === "vanilla") return [] as string[]; + if (inTauri) return invoke("list_loader_versions", { loader, minecraft }); + if (loader === "fabric") { + const res = await fetch(`/proxy/fabric/v2/versions/loader/${encodeURIComponent(minecraft)}`); + if (!res.ok) return []; + const data = (await res.json()) as Array<{ loader: { version: string } }>; + return data.map((r) => r.loader.version); + } + if (loader === "quilt") { + const res = await fetch(`/proxy/quilt/v3/versions/loader/${encodeURIComponent(minecraft)}`); + if (!res.ok) return []; + const data = (await res.json()) as Array<{ loader: { version: string } }>; + return data.map((r) => r.loader.version); + } + if (loader === "forge") { + const res = await fetch("/proxy/forge/net/minecraftforge/forge/maven-metadata.xml"); + const xml = await res.text(); + const prefix = `${minecraft}-`; + return [...xml.matchAll(/([^<]+)<\/version>/g)] + .map((m) => m[1]) + .filter((v) => v.startsWith(prefix)) + .map((v) => v.slice(prefix.length)) + .reverse(); + } + if (loader === "neoforge") { + const res = await fetch("/proxy/neoforge/releases/net/neoforged/neoforge/maven-metadata.xml"); + const xml = await res.text(); + const parts = minecraft.split("."); + const filter = parts.length >= 2 ? `${parts[1]}.${parts[2] ?? "0"}` : minecraft; + return [...xml.matchAll(/([^<]+)<\/version>/g)] + .map((m) => m[1]) + .filter( + (v) => + v === filter || + v.startsWith(`${filter}.`) || + v.startsWith(`${filter}-`), + ) + .reverse(); + } + return []; +} + +async function refreshMinecraftVersions() { + const epoch = beginCreateRefresh(); + const requestId = ++mcRequestId; + ++loaderRequestId; // drop any in-flight loader apply + setStatus(createStatus, t("create.loadingVersions"), "muted"); + const needsLoader = selectedLoader !== "vanilla"; + loaderField.hidden = !needsLoader; + loaderLabel.textContent = t("create.loaderVersion", { loader: prettyLoader(selectedLoader) }); + try { + const ids = await tauriOrBrowserMcVersions(selectedLoader, createShowSnapshots); + if (requestId !== mcRequestId || epoch !== createRefreshEpoch) return; + const preferred = ids.find((id) => id === "1.20.1") ?? ids[0] ?? ""; + mcCombo.setOptions(ids, preferred); + await refreshLoaderVersions({ nested: true, epoch }); + if (requestId !== mcRequestId || epoch !== createRefreshEpoch) return; + const ready = + Boolean(mcCombo.getValue()) && + (selectedLoader === "vanilla" || Boolean(loaderCombo.getValue())); + setCreateReady(epoch, ready); + refreshCreateNameHint(); + setStatus( + createStatus, + ids.length ? t("create.mcCount", { n: ids.length }) : t("create.noVersions"), + ids.length ? "ok" : "err", + ); + } catch (e) { + if (requestId !== mcRequestId || epoch !== createRefreshEpoch) return; + mcCombo.setOptions([]); + loaderCombo.setOptions([]); + setCreateReady(epoch, false); + setStatus(createStatus, String(e), "err"); + } +} + +async function refreshLoaderVersions(opts?: { nested?: boolean; epoch?: number }) { + const epoch = opts?.nested ? opts.epoch! : beginCreateRefresh(); + const requestId = ++loaderRequestId; + if (selectedLoader === "vanilla") { + loaderCombo.setOptions([]); + if (!opts?.nested) setCreateReady(epoch, Boolean(mcCombo.getValue())); + return; + } + const mc = mcCombo.getValue(); + if (!mc) { + loaderCombo.setOptions([]); + if (!opts?.nested) setCreateReady(epoch, false); + return; + } + try { + const loaders = await tauriOrBrowserLoaderVersions(selectedLoader, mc); + if (requestId !== loaderRequestId || epoch !== createRefreshEpoch) return; + loaderCombo.setOptions(loaders, loaders[0]); + if (!opts?.nested) { + setCreateReady(epoch, Boolean(mcCombo.getValue() && loaderCombo.getValue())); + } + } catch (e) { + if (requestId !== loaderRequestId || epoch !== createRefreshEpoch) return; + loaderCombo.setOptions([]); + if (!opts?.nested) setCreateReady(epoch, false); + setStatus(createStatus, String(e), "err"); + } +} + +root.querySelectorAll(".rail-btn[data-route]").forEach((btn) => { + btn.addEventListener("click", () => { + if (isProfileGateOpen()) return; + const r = btn.dataset.route!; + if (r === "browse") { + browseInstanceId = null; + selectedProjectHit = null; + routeTo("browse"); + return; + } + routeTo(r); + }); +}); +root.querySelectorAll("[data-close='inst-settings']").forEach((el) => { + el.addEventListener("click", () => { + hideModal(modalInstSettings); + }); +}); +root.querySelectorAll("[data-close='app-settings']").forEach((el) => { + el.addEventListener("click", () => { + closeAppSettingsOverlay(); + }); +}); +root.querySelectorAll("[data-close='java-detect']").forEach((el) => { + el.addEventListener("click", () => { + hideModal(modalJavaDetect); + javaDetectCallback = null; + }); +}); +modalInstSettings.addEventListener("click", (e) => { + if (e.target === modalInstSettings) hideModal(modalInstSettings); +}); +modalAppSettings.addEventListener("click", (e) => { + if (e.target === modalAppSettings) closeAppSettingsOverlay(); +}); +modalJavaDetect.addEventListener("click", (e) => { + if (e.target === modalJavaDetect) { + hideModal(modalJavaDetect); + javaDetectCallback = null; + } +}); +root.addEventListener("click", (e) => { + const el = (e.target as HTMLElement | null)?.closest?.("[data-action]") as HTMLElement | null; + if (!el || !root.contains(el)) return; + const action = el.getAttribute("data-action"); + if (action === "create" || action === "create-empty") { + e.preventDefault(); + if (isProfileGateOpen()) return; + openCreateModal(); + } else if (action === "accounts") { + e.preventDefault(); + if (isProfileGateOpen()) return; + openProfileWizard({ allowClose: true }); + } +}); +root.querySelectorAll("[data-close='create']").forEach((el) => { + el.addEventListener("click", closeCreateModal); +}); +root.querySelector("#btn-create-next")?.addEventListener("click", () => { + advanceCreateStep(); +}); +root.querySelector("#btn-create-back")?.addEventListener("click", () => { + retreatCreateStep(); +}); +root.querySelector("#create-type-modpack")?.addEventListener("click", () => { + closeCreateModal(); + browseProjectType = "modpack"; + browseInstanceId = null; + routeTo("browse"); +}); +root.querySelector("#create-import-mrpack")?.addEventListener("click", () => { + void (async () => { + if (!inTauri) { + setTitlebarMessage(t("create.importMrpackBrowser")); + return; + } + try { + const selected = await openDialog({ + multiple: false, + title: t("create.type.importMrpack"), + filters: [{ name: "mrpack", extensions: ["mrpack", "zip"] }], + }); + if (typeof selected !== "string") return; + closeCreateModal(); + setTitlebarMessage(t("create.importMrpackWorking")); + const result = await invoke<{ + instance: DiskInstance; + message: string; + partial: boolean; + }>("import_mrpack", { path: selected }); + await hydrateInstancesFromDisk(); + setTitlebarMessage(result.message); + selectedInstanceId = result.instance.id; + routeTo("instance", result.instance.id); + } catch (e) { + setTitlebarError(friendlyError(e)); + } + })(); +}); +histBack.addEventListener("click", goBack); +histForward.addEventListener("click", goForward); +root.querySelector("#btn-wizard")?.addEventListener("click", () => void finishWizard()); +root.querySelector("#btn-wizard-auth")?.addEventListener("click", () => void onMicrosoftAuthButtonClick()); +modalWizard.addEventListener("click", (e) => { + if (e.target === modalWizard && wizardAllowClose) hideModal(modalWizard); +}); +btnCreateIcon.addEventListener("click", () => void pickCreateIcon()); +btnCreateIconClear.addEventListener("click", () => clearCreateIcon()); +instName.addEventListener("input", () => { + if (!createIconDataUrl) paintCreateIconPreview(); + syncCreateWizardStep(); +}); +btnCreate.addEventListener("click", () => void createInstance()); +modalCreate.addEventListener("keydown", (event) => { + if (event.key !== "Enter" || event.shiftKey) return; + if (event.target instanceof HTMLTextAreaElement) return; + event.preventDefault(); + if (createWizardStep < createMaxStep()) { + advanceCreateStep(); + return; + } + if (btnCreate.disabled) return; + void createInstance(); +}); +modalCreate.addEventListener("click", (e) => { + if (e.target === modalCreate) closeCreateModal(); +}); + +if (inTauri) { + const win = getCurrentWindow(); + const bindWin = (minId: string, maxId: string, closeId: string) => { + root.querySelector(minId)?.addEventListener("click", () => void win.minimize()); + root.querySelector(maxId)?.addEventListener("click", () => void win.toggleMaximize()); + root.querySelector(closeId)?.addEventListener("click", () => void win.close()); + }; + bindWin("#win-min", "#win-max", "#win-close"); + bindWin("#splash-min", "#splash-max", "#splash-close"); + + void listen("install://progress", (event) => { + const p = event.payload; + updatePlayProgress(p); + if (p.packId === "__meta_prefetch__") return; + const inst = instances.find((i) => i.id === p.packId); + if (!inst) return; + if (inst.installStatus === "ready" || inst.installStatus === "error") return; + if (p.phase === "done") { + inst.installMessage = p.message; + saveInstances(); + return; + } + const progress = p.totalFiles > 0 ? ` ${p.doneFiles}/${p.totalFiles}` : ""; + inst.installStatus = "installing"; + inst.installMessage = `${p.message}${progress}`; + saveInstances(); + if (selectedInstanceId === inst.id) { + void refreshPlayButton(inst); + } + }); + + void listen<{ packId: string; pid: number }>("process://finished", (event) => { + const packId = event.payload.packId; + // Ignore exits for other instances so we don't stop B's poll / idle titlebar. + if (selectedInstanceId !== packId) return; + const inst = instances.find((i) => i.id === packId); + stopRunningPoll(); + setTitlebarIdle(t("play.exited")); + if (inst) void refreshPlayButton(inst); + }); +} + +void boot(); diff --git a/legacy/Launcher/apps/launcher/src/ms-auth.ts b/legacy/Launcher/apps/launcher/src/ms-auth.ts new file mode 100644 index 00000000000..9512f9b90eb --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/ms-auth.ts @@ -0,0 +1,60 @@ +/** + * Microsoft account auth pipeline (Path A when MICROSOFT_CLIENT_ID is set). + * + * Phases from Rust: + * - unconfigured — no CLIENT_ID + * - waiting — real Azure device-code (userCode + verificationUri) + * - success — Minecraft profile + opaque authBlob + * - error — Azure / Xbox / Minecraft failure + */ + +import { invoke } from "@tauri-apps/api/core"; + +export type MsAuthPhase = + | "idle" + | "starting" + | "waiting" + | "scaffold" + | "not_implemented" + | "success" + | "error" + | "unconfigured"; + +export type MsAuthStatus = { + phase: MsAuthPhase; + message?: string; + userCode?: string; + verificationUri?: string; + gamertag?: string; + /** Opaque ms1:… blob from Path A success */ + authBlob?: string; +}; + +export async function msAuthStart(): Promise { + try { + return await invoke("ms_auth_start"); + } catch (e) { + const msg = typeof e === "string" ? e : (e as { message?: string })?.message || String(e); + if (/MICROSOFT_CLIENT_ID|not configured|unconfigured/i.test(msg)) { + return { phase: "unconfigured", message: msg }; + } + return { phase: "error", message: msg }; + } +} + +export async function msAuthPoll(): Promise { + try { + return await invoke("ms_auth_poll"); + } catch (e) { + const msg = typeof e === "string" ? e : (e as { message?: string })?.message || String(e); + return { phase: "error", message: msg }; + } +} + +export async function msAuthCancel(): Promise { + try { + await invoke("ms_auth_cancel"); + } catch { + /* ignore */ + } +} diff --git a/legacy/Launcher/apps/launcher/src/owyx-auth.ts b/legacy/Launcher/apps/launcher/src/owyx-auth.ts new file mode 100644 index 00000000000..cc562789f5b --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/owyx-auth.ts @@ -0,0 +1,241 @@ +// Owyx account sign-in for the launcher UI. +// +// Two paths, same contract (see owyxsite/LAUNCHER_SITE_CONTRACT.md): +// - Tauri app: call the Rust commands (owyx_login/owyx_me/owyx_logout). The +// JWT is stored securely in the launcher data dir and never touches the UI. +// - Browser dev preview (npm run dev): go through the Vite proxy /proxy/owyx +// to avoid CORS. The token is kept in localStorage (dev only). +// +// login() rejects with a stable error CODE that the UI maps to a localized, +// foolproof message: "network" | "invalid_credentials" | "account_inactive" +// | "server" | "no_session". + +import { invoke } from "@tauri-apps/api/core"; + +export type OwyxSession = { + nickname: string; + email: string; + role: string; + trustLevel: number; + banned: boolean; + serverAccess: boolean; + accessReason: string; + skinUrl: string | null; + skinModel: string; + baseUrl: string; +}; + +// Vite dev proxy target (configured in vite.config.ts) -> backend :3001. +const DEV_PROXY = "/proxy/owyx"; +const DEV_SESSION_PREFIX = "owyx.session."; + +function code(e: unknown): string { + const s = typeof e === "string" ? e : (e as { message?: string })?.message || String(e); + return s || "server"; +} + +async function readJson(res: Response): Promise> { + try { + return (await res.json()) as Record; + } catch { + return {}; + } +} + +function statusToCode(status: number): string { + if (status === 400 || status === 401) return "invalid_credentials"; + if (status === 403) return "account_inactive"; + return "server"; +} + +function normalizeMe(data: Record, baseUrl: string): OwyxSession { + const user = (data.user ?? {}) as Record; + const cosmetics = (data.cosmetics ?? {}) as Record; + return { + nickname: String(user.nickname ?? ""), + email: String(user.email ?? ""), + role: String(user.role ?? "user"), + trustLevel: Number(user.trustLevel ?? 0), + banned: Boolean(user.banned), + serverAccess: Boolean(data.serverAccess), + accessReason: String(data.accessReason ?? ""), + skinUrl: (data.skinUrl as string) ?? null, + skinModel: String(cosmetics.skinModel ?? "classic"), + baseUrl, + }; +} + +/** Sign in with email + password, then load the launcher profile. */ +export async function owyxLogin( + inTauri: boolean, + baseUrl: string | null, + email: string, + password: string, +): Promise { + if (inTauri) { + try { + return await invoke("owyx_login", { baseUrl, email, password }); + } catch (e) { + throw code(e); + } + } + + // Browser dev path via the Vite proxy. + const base = DEV_PROXY; + let loginRes: Response; + try { + loginRes = await fetch(`${base}/api/auth/login`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ email, password }), + }); + } catch { + throw "network"; + } + if (!loginRes.ok) throw statusToCode(loginRes.status); + + const loginData = await readJson(loginRes); + const token = String(loginData.token ?? ""); + if (!token) throw "server"; + + let meRes: Response; + try { + meRes = await fetch(`${base}/api/launcher/me`, { + headers: { Authorization: `Bearer ${token}` }, + }); + } catch { + throw "network"; + } + if (!meRes.ok) throw "server"; + + const session = normalizeMe(await readJson(meRes), base); + try { + localStorage.setItem( + `${DEV_SESSION_PREFIX}${session.nickname}`, + JSON.stringify({ token, baseUrl: base }), + ); + } catch { + /* ignore storage errors in dev */ + } + return session; +} + +/** Refresh a stored session (used when switching to an Owyx profile). */ +export async function owyxMe(inTauri: boolean, nickname: string): Promise { + if (inTauri) { + try { + return await invoke("owyx_me", { nickname }); + } catch (e) { + throw code(e); + } + } + const raw = localStorage.getItem(`${DEV_SESSION_PREFIX}${nickname}`); + if (!raw) throw "no_session"; + const { token, baseUrl } = JSON.parse(raw) as { token: string; baseUrl: string }; + let res: Response; + try { + res = await fetch(`${baseUrl}/api/launcher/me`, { + headers: { Authorization: `Bearer ${token}` }, + }); + } catch { + throw "network"; + } + if (!res.ok) { + if (res.status === 401 || res.status === 403) { + try { + localStorage.removeItem(`${DEV_SESSION_PREFIX}${nickname}`); + } catch { + /* ignore */ + } + throw "no_session"; + } + throw "server"; + } + return normalizeMe(await readJson(res), baseUrl); +} + +/** Admin API using the stored JWT. Path must start with /api/admin/. */ +export async function owyxAdminFetch( + inTauri: boolean, + nickname: string, + method: string, + path: string, + body?: Record | null, +): Promise> { + if (inTauri) { + try { + return await invoke>("owyx_admin_request", { + nickname, + method, + path, + body: body ?? null, + }); + } catch (e) { + throw code(e); + } + } + const raw = localStorage.getItem(`${DEV_SESSION_PREFIX}${nickname}`); + if (!raw) throw "no_session"; + const { token, baseUrl } = JSON.parse(raw) as { token: string; baseUrl: string }; + let res: Response; + try { + res = await fetch(`${baseUrl}${path}`, { + method, + headers: { + Authorization: `Bearer ${token}`, + "Content-Type": "application/json", + }, + body: body && method !== "GET" ? JSON.stringify(body) : undefined, + }); + } catch { + throw "network"; + } + const data = await readJson(res); + if (!res.ok) { + if (res.status === 401 || res.status === 403) throw "no_session"; + throw String(data.error ?? "server"); + } + return data; +} + +export type SkinApplyResult = { + applied: boolean; + path?: string | null; + model: string; + message: string; +}; + +export async function owyxApplySkin( + inTauri: boolean, + nickname: string, + instanceId?: string | null, +): Promise { + if (inTauri) { + try { + return await invoke("apply_owyx_skin", { + nickname, + instanceId: instanceId ?? null, + }); + } catch (e) { + throw code(e); + } + } + return { applied: false, path: null, model: "classic", message: "browser" }; +} + +/** Forget a stored session (logout / profile delete). Never throws. */ +export async function owyxLogout(inTauri: boolean, nickname: string): Promise { + if (inTauri) { + try { + await invoke("owyx_logout", { nickname }); + } catch { + /* ignore */ + } + return; + } + try { + localStorage.removeItem(`${DEV_SESSION_PREFIX}${nickname}`); + } catch { + /* ignore */ + } +} diff --git a/legacy/Launcher/apps/launcher/src/particles.ts b/legacy/Launcher/apps/launcher/src/particles.ts new file mode 100644 index 00000000000..ac7e75b99a5 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/particles.ts @@ -0,0 +1,71 @@ +type Particle = { x: number; y: number; vx: number; vy: number; r: number; a: number; hue: number }; + +export function startParticles(canvas: HTMLCanvasElement) { + const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + if (reduced) { + canvas.hidden = true; + return () => undefined; + } + + const ctx = canvas.getContext("2d"); + if (!ctx) return () => undefined; + + let raf = 0; + let w = 0; + let h = 0; + const particles: Particle[] = []; + + const resize = () => { + const dpr = Math.min(window.devicePixelRatio || 1, 2); + w = window.innerWidth; + h = window.innerHeight; + canvas.width = Math.floor(w * dpr); + canvas.height = Math.floor(h * dpr); + canvas.style.width = `${w}px`; + canvas.style.height = `${h}px`; + ctx.setTransform(dpr, 0, 0, dpr, 0, 0); + }; + + const spawn = (n: number) => { + for (let i = 0; i < n; i++) { + particles.push({ + x: Math.random() * w, + y: Math.random() * h, + vx: (Math.random() - 0.5) * 0.25, + vy: -0.15 - Math.random() * 0.35, + r: 0.6 + Math.random() * 1.8, + a: 0.15 + Math.random() * 0.35, + hue: Math.random() > 0.55 ? 188 : 262, + }); + } + }; + + const tick = () => { + ctx.clearRect(0, 0, w, h); + for (const p of particles) { + p.x += p.vx; + p.y += p.vy; + if (p.y < -4) { + p.y = h + 4; + p.x = Math.random() * w; + } + if (p.x < -4) p.x = w + 4; + if (p.x > w + 4) p.x = -4; + ctx.beginPath(); + ctx.fillStyle = `hsla(${p.hue} 90% 65% / ${p.a})`; + ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2); + ctx.fill(); + } + raf = requestAnimationFrame(tick); + }; + + resize(); + spawn(42); + window.addEventListener("resize", resize); + raf = requestAnimationFrame(tick); + + return () => { + cancelAnimationFrame(raf); + window.removeEventListener("resize", resize); + }; +} diff --git a/legacy/Launcher/apps/launcher/src/playing-as.ts b/legacy/Launcher/apps/launcher/src/playing-as.ts new file mode 100644 index 00000000000..3b74be19b0d --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/playing-as.ts @@ -0,0 +1,185 @@ +import { t } from "./i18n"; + +export type ProfileKind = "offline" | "microsoft" | "owyx"; +export type Profile = { + id: string; + kind: ProfileKind; + name: string; + nick: string; + needsAuth?: boolean; + authBlob?: string | null; + createdAt: number; +}; + +type Deps = { + getProfiles: () => Profile[]; + getActiveId: () => string | null; + setActiveId: (id: string | null) => void; + setProfiles: (next: Profile[]) => void; + persist: () => Promise; + openWizard: (opts?: { allowClose?: boolean }) => void; + setStatus: (el: HTMLElement, text: string, kind?: "ok" | "err" | "muted") => void; + /** Called when a profile is removed, e.g. to forget a stored Owyx session. */ + onRemove?: (profile: Profile) => void; +}; + +function accountLabel(kind: ProfileKind) { + return t(`profile.account.${kind}`); +} + +function fillAvatar(el: HTMLElement, nick: string) { + const letter = (nick || "?").slice(0, 1).toUpperCase(); + el.replaceChildren(); + el.textContent = letter; + const img = document.createElement("img"); + img.alt = ""; + img.width = 40; + img.height = 40; + img.src = `https://mc-heads.net/avatar/${encodeURIComponent(nick || "Steve")}/40`; + img.addEventListener("load", () => el.replaceChildren(img)); + img.addEventListener("error", () => { + el.textContent = letter; + }); +} + +let closer: ((e: MouseEvent) => void) | null = null; + +export function mountPlayingAs(host: HTMLElement, deps: Deps) { + if (closer) { + window.removeEventListener("click", closer); + closer = null; + } + + host.innerHTML = ` +
+
${t("profile.playingAs")}
+
+ + +
+

+
+ `; + + const trigger = host.querySelector("#playing-as-trigger")!; + const panel = host.querySelector("#playing-as-panel")!; + const status = host.querySelector("#home-status")!; + const avatar = host.querySelector("#playing-as-avatar")!; + + const close = () => { + panel.hidden = true; + trigger.classList.remove("is-open"); + trigger.setAttribute("aria-expanded", "false"); + }; + + const openAdd = (allowClose: boolean) => { + close(); + // Defer so the same click does not immediately dismiss the modal. + window.setTimeout(() => deps.openWizard({ allowClose }), 0); + }; + + const active = () => + deps.getProfiles().find((p) => p.id === deps.getActiveId()) ?? + deps.getProfiles()[0] ?? + null; + + const paintTrigger = () => { + const p = active(); + fillAvatar(avatar, p?.nick || p?.name || "Steve"); + host.querySelector("#playing-as-name")!.textContent = p?.name ?? t("profile.none"); + host.querySelector("#playing-as-kind")!.textContent = p ? accountLabel(p.kind) : "—"; + if (p?.needsAuth) deps.setStatus(status, t("profile.needsAuth"), "muted"); + else setStatusEmpty(); + }; + + const setStatusEmpty = () => deps.setStatus(status, "", "muted"); + + const paintPanel = () => { + panel.replaceChildren(); + for (const p of deps.getProfiles()) { + const wrap = document.createElement("div"); + wrap.className = "playing-as-item"; + + const pick = document.createElement("button"); + pick.type = "button"; + pick.className = `playing-as-row${p.id === deps.getActiveId() ? " is-active" : ""}`; + pick.innerHTML = ` + + + + `; + fillAvatar(pick.querySelector("[data-avatar]")!, p.nick || p.name); + pick.querySelector("strong")!.textContent = p.name; + pick.querySelector("small")!.textContent = accountLabel(p.kind); + pick.addEventListener("click", (e) => { + e.stopPropagation(); + deps.setActiveId(p.id); + void deps.persist().then(() => { + paintTrigger(); + paintPanel(); + close(); + }); + }); + + const del = document.createElement("button"); + del.type = "button"; + del.className = "playing-as-del"; + del.title = t("profile.delete"); + del.innerHTML = ``; + del.addEventListener("click", (e) => { + e.stopPropagation(); + deps.onRemove?.(p); + const next = deps.getProfiles().filter((x) => x.id !== p.id); + deps.setProfiles(next); + if (deps.getActiveId() === p.id) deps.setActiveId(next[0]?.id ?? null); + void deps.persist().then(() => { + paintTrigger(); + paintPanel(); + if (!next.length) openAdd(false); + else close(); + }); + }); + + wrap.append(pick, del); + panel.append(wrap); + } + + const add = document.createElement("button"); + add.type = "button"; + add.className = "playing-as-add"; + add.innerHTML = ` ${t("profile.add")}`; + add.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + openAdd(deps.getProfiles().length > 0); + }); + panel.append(add); + }; + + trigger.addEventListener("click", (e) => { + e.preventDefault(); + e.stopPropagation(); + if (panel.hidden) { + paintPanel(); + panel.hidden = false; + trigger.classList.add("is-open"); + trigger.setAttribute("aria-expanded", "true"); + } else close(); + }); + panel.addEventListener("click", (e) => e.stopPropagation()); + + closer = (e: MouseEvent) => { + const target = e.target as Node | null; + if (target && host.contains(target)) return; + close(); + }; + window.addEventListener("click", closer); + paintTrigger(); +} diff --git a/legacy/Launcher/apps/launcher/src/skins-page.ts b/legacy/Launcher/apps/launcher/src/skins-page.ts new file mode 100644 index 00000000000..902a88dd5c8 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/skins-page.ts @@ -0,0 +1,237 @@ +/** + * Skins screen — Modrinth Skins.vue spirit + Owyx /me skin-to-disk. + * List / preview / apply / import / remove against Rust skin library. + */ + +export type SkinEntry = { + id: string; + name: string; + model: string; + source: string; + path: string; + textureDataUrl?: string | null; + isEquipped: boolean; + createdAt?: number; +}; + +export type SkinsDeps = { + t: (key: string, vars?: Record) => string; + inTauri: boolean; + activeNick: string | null; + owyxSkinUrl: string | null; + listSkins: () => Promise; + applySkin: (id: string) => Promise; + removeSkin: (id: string) => Promise; + onApplyOwyxSkin: () => Promise; + onImportFile: () => Promise; + setStatus: (msg: string, kind?: "ok" | "err" | "muted") => void; +}; + +function escapeHtml(s: string): string { + return s + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} + +/** CSS face crop from a 64×64 Minecraft skin texture. */ +function faceStyle(textureUrl: string | null | undefined): string { + if (!textureUrl) return ""; + const safe = JSON.stringify(textureUrl); + return `background-image:url(${safe});background-size:800% 800%;background-position:12.5% 12.5%;`; +} + +export function mountSkinsPage(root: HTMLElement, deps: SkinsDeps): void { + root.innerHTML = ` +
+
+

${deps.t("skins.title")}

+

${deps.t("skins.subtitle")}

+
+
+ +
+
+
+

${deps.t("skins.saved")}

+ +
+
+
+
+

${deps.t("skins.owyx")}

+
+
+
+
+

${deps.t("skins.owyxHint")}

+ +
+
+
+
+
+
+
+ `; + + const previewLabel = root.querySelector("#skins-preview-label")!; + const figure = root.querySelector("#skins-preview-figure")!; + const face = root.querySelector("#skins-preview-face")!; + const grid = root.querySelector("#skins-grid")!; + const applyBtn = root.querySelector("#skins-apply-selected")!; + const removeBtn = root.querySelector("#skins-remove-selected")!; + const owyxThumb = root.querySelector("#skins-owyx-thumb")!; + + let skins: SkinEntry[] = []; + let selectedId: string | null = null; + + const nick = deps.activeNick || deps.t("skins.noProfile"); + previewLabel.textContent = deps.t("skins.playingAs", { nick }); + figure.textContent = nick.slice(0, 1).toUpperCase(); + + if (deps.owyxSkinUrl) { + owyxThumb.style.cssText = faceStyle(deps.owyxSkinUrl); + owyxThumb.classList.add("has-img"); + } + + function paintPreview(skin: SkinEntry | undefined) { + if (!skin) { + face.removeAttribute("style"); + face.classList.remove("has-img"); + figure.style.display = ""; + return; + } + const tex = skin.textureDataUrl || null; + if (tex) { + face.style.cssText = faceStyle(tex); + face.classList.add("has-img"); + figure.style.display = "none"; + } else { + face.removeAttribute("style"); + face.classList.remove("has-img"); + figure.style.display = ""; + figure.textContent = skin.name.slice(0, 1).toUpperCase(); + } + previewLabel.textContent = `${skin.name} · ${skin.model}`; + applyBtn.disabled = skin.isEquipped; + applyBtn.textContent = skin.isEquipped ? deps.t("skins.equipped") : deps.t("skins.apply"); + const canRemove = skin.source === "custom"; + removeBtn.hidden = !canRemove; + } + + function renderGrid() { + const tiles = skins + .map((s) => { + const selected = s.id === selectedId ? " is-selected" : ""; + const equipped = s.isEquipped ? `${deps.t("skins.equipped")}` : ""; + const thumb = s.textureDataUrl + ? `` + : `${escapeHtml(s.name.slice(0, 1).toUpperCase())}`; + return ``; + }) + .join(""); + grid.innerHTML = ` + ${tiles} + + `; + grid.querySelectorAll("[data-skin-id]").forEach((btn) => { + btn.addEventListener("click", () => { + selectedId = btn.dataset.skinId || null; + paintPreview(skins.find((s) => s.id === selectedId)); + renderGrid(); + }); + }); + grid.querySelector("#skins-add-tile")?.addEventListener("click", () => { + void deps.onImportFile().then(() => void reload()); + }); + } + + async function reload() { + try { + skins = deps.inTauri ? await deps.listSkins() : defaultBrowserSkins(deps); + selectedId = skins.find((s) => s.isEquipped)?.id ?? skins[0]?.id ?? null; + paintPreview(skins.find((s) => s.id === selectedId)); + renderGrid(); + } catch (e) { + deps.setStatus(String(e), "err"); + skins = defaultBrowserSkins(deps); + selectedId = skins[0]?.id ?? null; + paintPreview(skins[0]); + renderGrid(); + } + } + + root.querySelector("#skins-import")?.addEventListener("click", () => { + void deps.onImportFile().then(() => void reload()); + }); + applyBtn.addEventListener("click", () => { + if (!selectedId) return; + void (async () => { + try { + await deps.applySkin(selectedId!); + deps.setStatus(deps.t("skins.applied"), "ok"); + await reload(); + } catch (e) { + deps.setStatus(String(e), "err"); + } + })(); + }); + removeBtn.addEventListener("click", () => { + if (!selectedId) return; + void (async () => { + try { + await deps.removeSkin(selectedId!); + deps.setStatus(deps.t("skins.removed"), "ok"); + await reload(); + } catch (e) { + deps.setStatus(String(e), "err"); + } + })(); + }); + root.querySelector("#skins-apply-owyx")?.addEventListener("click", () => { + void (async () => { + try { + await deps.onApplyOwyxSkin(); + deps.setStatus(deps.t("skins.applied"), "ok"); + await reload(); + } catch (e) { + deps.setStatus(String(e), "err"); + } + })(); + }); + + void reload(); +} + +function defaultBrowserSkins(deps: SkinsDeps): SkinEntry[] { + return [ + { + id: "default:steve", + name: deps.t("skins.defaultSteve"), + model: "classic", + source: "default", + path: "", + textureDataUrl: deps.owyxSkinUrl, + isEquipped: true, + }, + ]; +} diff --git a/legacy/Launcher/apps/launcher/src/styles.css b/legacy/Launcher/apps/launcher/src/styles.css new file mode 100644 index 00000000000..fb16a07779c --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/styles.css @@ -0,0 +1,2494 @@ +@import url("https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,400;0,9..40,500;0,9..40,600;0,9..40,700;1,9..40,400&display=swap"); + +:root { + color-scheme: dark; + /* Owyx Official — Stitch Library etalon */ + --bg: #050508; + --bg-glow: radial-gradient(1000px 520px at 12% -8%, rgba(139, 92, 246, 0.1), transparent 55%), + radial-gradient(900px 480px at 100% 0%, rgba(0, 229, 255, 0.07), transparent 50%); + --panel: #131319; + --panel-2: #14141c; + --line: #2a2b30; + --text: #f3f4f6; + --muted: #9aa0a8; + --accent: #00e5ff; + --accent-ink: #041018; + --accent-violet: #8b5cf6; + --danger: #ff5c6c; + --ok: #5eead4; + --rail: #0e0e14; + --font: "DM Sans", "Segoe UI", sans-serif; + font-family: var(--font); + background: var(--bg); + color: var(--text); +} + +* { box-sizing: border-box; } +html, body, #app { + margin: 0; + height: 100%; + overflow: hidden; +} +body { + min-height: 100%; + background: var(--bg); + background-image: var(--bg-glow); +} + +.shell { + display: grid; + grid-template-columns: 4rem 1fr; + height: 100%; + min-height: 0; + overflow: hidden; +} + +.rail { + background: var(--rail); + border-right: 1px solid var(--line); + display: flex; + flex-direction: column; + padding: 0.5rem; + padding-top: 0; + height: 100%; + min-height: 0; + overflow: hidden; +} + +.rail-stack { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.25rem; + flex: 1; + min-height: 0; +} + +.rail-nav, .recent-list { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.25rem; +} + +.recent-list { + width: 100%; + flex: 0 1 auto; + max-height: min(28vh, 200px); + overflow-y: auto; + overflow-x: hidden; + scrollbar-width: thin; + gap: 0.45rem; + padding: 2px 0; +} +.recent-list:empty { + display: none; +} +.recent-list:empty + .rail-sep { + display: none; +} + +.rail-spacer { + flex: 1 1 auto; + width: 1px; + min-height: 12px; +} +.rail-footer { + margin-top: auto; + flex-shrink: 0; + display: flex; + flex-direction: column; + align-items: center; + gap: 0.25rem; + padding-bottom: 0.25rem; +} + +.rail-sep { + display: block; + width: 28px; + height: 1px; + margin: 12px 0; + background: color-mix(in srgb, var(--line) 85%, #fff); + flex-shrink: 0; +} + +.logo { + width: 3rem; + height: 3rem; + border-radius: 0; + background: transparent; + color: var(--accent); + display: grid; + place-items: center; + margin: 0.65rem 0 0.45rem; + padding: 0; + border: 0; +} +.logo svg { + width: 2rem; + height: 2rem; + display: block; +} + +.rail-btn { + position: relative; + width: 3rem; + height: 3rem; + border-radius: 999px; + border: 0; + background: transparent; + color: var(--muted); + cursor: pointer; + display: grid; + place-items: center; + padding: 0; + transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease; +} +.rail-btn svg { + width: 1.35rem; + height: 1.35rem; + fill: currentColor; +} +.rail-btn:hover { background: var(--panel-2); color: var(--text); } +.rail-btn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} +.rail-btn.is-active { + color: var(--accent); + background: color-mix(in srgb, var(--accent) 14%, transparent); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); +} +.rail-btn.is-active::before { display: none; } + +.rail-plus { + color: var(--muted); + background: var(--panel-2); + border: 1px solid var(--line); + margin-top: 2px; +} +.rail-plus:hover { background: color-mix(in srgb, var(--panel-2) 80%, #39383f); color: var(--accent); } + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} + +.no-instance { + min-height: 40vh; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; +} + +.recent-btn { + width: 34px; + height: 34px; + border-radius: 999px; + border: 1px solid color-mix(in srgb, hsl(var(--recent-hue, 140) 40% 45%) 45%, var(--line)); + background: linear-gradient( + 145deg, + color-mix(in srgb, hsl(var(--recent-hue, 140) 45% 40%) 35%, var(--panel-2)), + var(--panel-2) + ); + color: var(--text); + font-weight: 700; + font-size: 0.82rem; + cursor: pointer; +} +.recent-btn.is-active { + border-color: var(--accent); + color: var(--accent); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); +} + +.stage { + display: flex; + flex-direction: column; + min-width: 0; + min-height: 0; + height: 100%; + overflow: hidden; + background: transparent; +} + +.topbar { + height: 48px; + flex-shrink: 0; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 10px 0 18px; + border-bottom: 1px solid var(--line); + background: color-mix(in srgb, #0c0c0e 92%, transparent); + backdrop-filter: blur(10px); + -webkit-app-region: drag; + app-region: drag; + user-select: none; +} +.topbar-left { + display: flex; + align-items: center; + gap: 12px; + min-width: 0; +} +.topbar-right { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; + -webkit-app-region: no-drag; + app-region: no-drag; +} +.download-tip { + display: flex; + flex-direction: column; + align-items: flex-end; + justify-content: center; + gap: 1px; + min-width: 0; + max-width: min(168px, 24vw); + padding: 1px 2px; + font-size: 0.68rem; + font-weight: 600; + font-variant-numeric: tabular-nums; + letter-spacing: 0.02em; + line-height: 1.15; + white-space: nowrap; + overflow: hidden; +} +.download-tip[hidden] { + display: none !important; +} +.download-tip-size { + color: color-mix(in srgb, var(--accent) 78%, #e8fffb); +} +.download-tip-speed { + color: var(--muted); + opacity: 0.92; +} +.brand { + color: var(--accent); + font-size: 0.95rem; + font-weight: 700; + letter-spacing: -0.02em; + text-transform: lowercase; +} +.nav-history { + display: flex; + gap: 4px; + -webkit-app-region: no-drag; + app-region: no-drag; +} +.hist-btn { + width: 28px; + height: 28px; + border-radius: 8px; + border: 1px solid var(--line); + background: var(--panel); + color: var(--muted); + cursor: pointer; +} +.hist-btn:hover:not(:disabled) { color: var(--text); background: var(--panel-2); } +.hist-btn:disabled { opacity: 0.35; cursor: default; } + +.win-controls { + display: flex; + align-items: stretch; + margin-left: 4px; +} +.win-controls[hidden] { display: none !important; } +.win-btn { + width: 42px; + height: 32px; + border: 0; + background: transparent; + color: var(--muted); + font-size: 0.85rem; + line-height: 1; + cursor: pointer; + border-radius: 6px; +} +.win-btn:hover { background: var(--panel-2); color: var(--text); } +.win-btn.win-close:hover { background: #e81123; color: #fff; } +.crumb { + color: var(--muted); + font-size: 0.9rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.pill { + position: relative; + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--muted); + border-radius: 999px; + padding: 6px 12px; + font-size: 0.75rem; + font-weight: 600; + letter-spacing: 0.04em; + display: inline-flex; + align-items: center; + gap: 8px; + max-width: min(420px, 42vw); + overflow: hidden; +} +.pill::before { + content: ""; + width: 8px; + height: 8px; + flex-shrink: 0; + border-radius: 999px; + background: var(--accent); + box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 55%, transparent); +} +.pill[data-kind="error"] { + border-color: color-mix(in srgb, var(--danger) 55%, var(--line)); + color: var(--text); +} +.pill[data-kind="error"]::before { + background: var(--danger); + box-shadow: 0 0 8px color-mix(in srgb, var(--danger) 55%, transparent); +} +.pill[data-kind="busy"]::before { + animation: status-pulse 1.2s ease-in-out infinite; +} +@keyframes status-pulse { + 50% { opacity: 0.45; } +} +.top-status-pill { + padding-bottom: 7px; +} +.top-status-pill.is-busy { + padding-bottom: 8px; +} +.top-status-pill #top-status-text { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.pill-progress { + position: absolute; + left: 8px; + right: 8px; + bottom: 0; + height: 2px; + border-radius: 999px; + background: color-mix(in srgb, #fff 8%, transparent); + overflow: hidden; + pointer-events: none; +} +.pill-progress[hidden] { + display: none !important; +} +.pill-progress-fill { + height: 100%; + width: 0%; + border-radius: inherit; + background: linear-gradient(90deg, var(--accent), #5eead4); + transition: width 0.2s ease; +} + +.main { + flex: 1; + min-height: 0; + padding: 16px 22px 36px; + overflow: auto; +} + +.home-page { + width: 100%; + max-width: none; +} +.home-main { min-width: 0; display: flex; flex-direction: column; gap: 8px; } +.home-aside { + display: grid; + gap: 14px; + position: sticky; + top: 8px; + align-self: start; +} +.home-aside .card { max-width: none; width: 100%; } +.section-title { + margin: 0 0 12px; + padding-bottom: 8px; + border-bottom: 1px solid var(--line); + font-size: 1rem; + font-weight: 600; + letter-spacing: -0.02em; +} +.home-section { margin-top: 8px; } + +.jump-list { display: grid; gap: 8px; max-width: none; } +.jump-row { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 12px; + border-radius: 12px; + border: 1px solid var(--line); + background: linear-gradient(90deg, color-mix(in srgb, var(--panel) 96%, #000), var(--panel)); +} +.jump-open { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 12px; + border: 0; + background: transparent; + color: inherit; + text-align: left; + padding: 0; + cursor: pointer; +} +.jump-actions { display: flex; align-items: center; gap: 8px; flex-shrink: 0; } +.btn-play { padding: 9px 14px; } +.jump-empty { + border: 1px dashed color-mix(in srgb, var(--line) 88%, var(--accent) 12%); + border-radius: 14px; + background: + radial-gradient(380px 140px at 50% 0%, color-mix(in srgb, var(--accent) 9%, transparent), transparent 70%); + padding: 28px 16px; +} +.home-quick-actions.home-quick-always.is-hidden { display: none; } + +.account-card .account-head { + display: flex; + gap: 12px; + align-items: center; + margin-bottom: 4px; +} +.skin-preview { + width: 56px; + height: 56px; + border-radius: 12px; + border: 1px solid var(--line); + background: + linear-gradient(135deg, #2a2d34 25%, transparent 25%) -8px 0 / 16px 16px, + linear-gradient(225deg, #2a2d34 25%, transparent 25%) -8px 0 / 16px 16px, + linear-gradient(315deg, #2a2d34 25%, transparent 25%) 0 0 / 16px 16px, + linear-gradient(45deg, #2a2d34 25%, #1a1b1e 25%) 0 0 / 16px 16px; + display: grid; + place-items: center; + color: var(--muted); + font-weight: 700; +} +.account-meta { display: grid; gap: 2px; min-width: 0; } +.account-label { + color: var(--muted); + font-size: 0.68rem; + font-weight: 600; + letter-spacing: 0.08em; + text-transform: uppercase; +} +.account-meta strong { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.news-list { + list-style: none; + margin: 0; + padding: 0; + display: grid; + gap: 12px; +} +.news-list li { display: grid; gap: 4px; } +.news-list strong { font-size: 0.92rem; } +.news-card h3 { margin: 0; font-size: 1rem; } + +@media (max-width: 960px) { + .home-top { grid-template-columns: 1fr; } + .home-aside { position: static; } +} + +.page-head h1, .instance-hero h1, .card h2 { + margin: 0; + font-size: 1.6rem; + font-weight: 700; + letter-spacing: -0.03em; +} +.page-head h1 + .tabs { margin-top: 14px; } + +.page-head { margin-bottom: 18px; } +.page-head.row, .instance-hero { + display: flex; + justify-content: space-between; + gap: 16px; + align-items: flex-start; + margin-bottom: 16px; +} + +.muted, .hint { color: var(--muted); font-size: 0.9rem; } +.hint { margin: 0; } +code { color: var(--accent); } + +.card { + background: color-mix(in srgb, var(--panel) 92%, #000); + border: 1px solid var(--line); + border-radius: 14px; + padding: 18px; + display: grid; + gap: 12px; + max-width: none; + width: 100%; +} +.card.grow { max-width: none; flex: 1; width: 100%; min-width: 0; } + +.tabs { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 12px; + margin-bottom: 16px; +} +.page-head .tabs { margin-bottom: 0; } +.instance-page > .tabs { + margin-top: 4px; + margin-bottom: 18px; +} +.tab { + border: 0; + border-radius: 999px; + padding: 8px 14px; + background: var(--panel-2); + color: var(--muted); + font: 600 0.88rem/1 var(--font); + cursor: pointer; + transition: background 0.15s ease, color 0.15s ease; +} +.tab.is-active { + background: color-mix(in srgb, var(--accent) 14%, var(--panel-2)); + color: var(--accent); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 35%, transparent); +} +.tab:disabled { opacity: 0.45; cursor: not-allowed; } + +.toolbar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; } +.browse-mods-panel { + margin: 10px 0 14px; + padding: 12px; + border-radius: 12px; + border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--line)); + background: color-mix(in srgb, var(--accent) 6%, var(--panel-2)); +} +.tiny-hint { font-size: 0.82rem; margin: 6px 0 0; } +.browse-mods-more { margin-top: 10px; } +.mr-hit .mr-icon.has-image { padding: 0; overflow: hidden; } +.mr-hit .mr-icon img { width: 100%; height: 100%; object-fit: cover; display: block; } +.muted.tiny { font-size: 0.8rem; } +.lib-toolbar { margin-top: 4px; margin-bottom: 14px; } + +/* Modrinth-like filled controls (StyledInput filled / rounded) */ +input:not([type]), +input[type="text"], +input[type="number"], +input[type="search"], +input[type="password"], +input[type="email"], +input[type="url"], +select, +.search { + -webkit-appearance: none !important; + appearance: none !important; + box-sizing: border-box; + width: 100%; + min-height: 42px; + margin: 0; + border: 0 !important; + border-radius: 999px !important; + background: #2c2b33 !important; + color: var(--text) !important; + padding: 10px 16px !important; + font: 500 0.95rem/1.2 var(--font) !important; + outline: none !important; + box-shadow: inset 0 0 0 1px color-mix(in srgb, #fff 6%, transparent); + transition: box-shadow 0.15s ease, background 0.15s ease, color 0.15s ease; +} +input:not([type]):focus, +input[type="text"]:focus, +input[type="number"]:focus, +input[type="search"]:focus, +input[type="password"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +select:focus, +.search:focus { + background: #32313a !important; + box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent); +} +input::placeholder, +.search::placeholder { + color: #8b8994 !important; + opacity: 1; +} +textarea { + -webkit-appearance: none !important; + appearance: none !important; + box-sizing: border-box; + width: 100%; + min-height: 96px; + margin: 0; + border: 0 !important; + border-radius: 14px !important; + background: #2c2b33 !important; + color: var(--text) !important; + padding: 12px 16px !important; + font: 500 0.95rem/1.4 var(--font) !important; + outline: none !important; + resize: vertical; + box-shadow: inset 0 0 0 1px color-mix(in srgb, #fff 6%, transparent); +} +textarea:focus { + background: #32313a !important; + box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent); +} +textarea::placeholder { color: #8b8994 !important; opacity: 1; } + +.search { max-width: 420px; } +.lib-toolbar .search { flex: 1; max-width: none; min-width: 180px; } +.select-wrap.slim { min-width: 190px; max-width: 240px; } +.select-wrap { position: relative; } +.select-wrap::after { + content: "▾"; + position: absolute; + right: 14px; + top: 50%; + transform: translateY(-50%); + color: var(--muted); + pointer-events: none; + z-index: 1; +} +select { padding-right: 36px !important; } + +.instance-list { display: grid; gap: 10px; max-width: 960px; } +.instance-row { + display: flex; + gap: 14px; + align-items: center; + width: 100%; + text-align: left; + border: 1px solid var(--line); + background: var(--panel); + border-radius: 14px; + padding: 14px 16px; + color: var(--text); + cursor: default; + transition: background 0.15s ease, border-color 0.15s ease; +} +.instance-row:hover { + background: var(--panel-2); + border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); +} +.instance-row:hover .instance-meta strong { color: var(--accent); } +.instance-open { + flex: 1; + min-width: 0; + display: flex; + align-items: center; + gap: 14px; + border: 0; + background: transparent; + color: inherit; + text-align: left; + padding: 0; + cursor: pointer; + font: inherit; +} +.instance-actions { + display: flex; + align-items: center; + gap: 8px; + flex-shrink: 0; +} +.instance-icon { + width: 52px; height: 52px; border-radius: 10px; + display: grid; place-items: center; + background: var(--bg); + font-weight: 700; + font-size: 1.1rem; + border: 1px solid var(--line); + flex-shrink: 0; + overflow: hidden; +} +.instance-icon.has-image { padding: 0; background: transparent; } +.instance-icon img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.instance-icon.lg { width: 68px; height: 68px; font-size: 1.45rem; border-radius: 14px; } +.instance-meta { display: grid; gap: 4px; min-width: 0; } +.instance-meta strong { + font-size: 1rem; + font-weight: 600; + transition: color 0.15s ease; +} +.instance-meta small { color: var(--muted); font-size: 0.82rem; } + +.instance-hero-left { display: flex; gap: 14px; align-items: center; } +.instance-hero-actions { display: flex; gap: 8px; align-items: center; } + +.btn { + border: 0; + border-radius: 10px; + padding: 10px 14px; + font: 700 0.92rem/1.1 var(--font); + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 8px; + transition: filter 0.15s ease, transform 0.15s ease; +} +.btn:hover:not(:disabled) { filter: brightness(1.05); } +.btn:active:not(:disabled) { transform: translateY(1px); } +.btn-primary { + background: var(--accent); + color: var(--accent-ink); + box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 22%, transparent); +} +.btn-ghost { background: var(--panel-2); color: var(--text); border: 1px solid var(--line); } +.btn-danger { background: #3a1519; color: #ff9aa5; border: 1px solid #6a2430; } +.btn:disabled { opacity: 0.45; cursor: not-allowed; } +.icon-btn { + width: 40px; height: 40px; border-radius: 10px; + border: 1px solid var(--line); background: var(--panel-2); color: var(--text); cursor: pointer; + display: inline-flex; align-items: center; justify-content: center; + flex: 0 0 40px; + padding: 0; + font-size: 1.05rem; + line-height: 1; +} +.icon-btn-square { + width: 40px; + height: 40px; + min-width: 40px; + min-height: 40px; + box-sizing: border-box; +} +.instance-hero-actions .icon-btn { + width: 40px; + height: 40px; +} + +.chips { display: flex; flex-wrap: wrap; gap: 8px; } +.chips.tiny { margin-top: 4px; } +.chip { + border-radius: 999px; + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--text); + padding: 9px 12px; + font: 600 0.9rem/1 var(--font); + cursor: pointer; +} +.chip.is-selected { + border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); + color: var(--accent); + background: color-mix(in srgb, var(--accent) 12%, var(--panel-2)); +} +.chip.static { cursor: default; opacity: 0.85; } + +.field { display: grid; gap: 8px; } +.field[hidden] { display: none !important; } +.field-compact { max-width: 420px; } +.label, label { font-weight: 600; font-size: 0.9rem; } +.check { display: inline-flex; gap: 8px; align-items: center; color: var(--muted); } +.check-row { + display: inline-flex; + align-items: center; + gap: 7px; + color: var(--muted); + font-weight: 500; +} +.check-row input { accent-color: var(--accent); } + +.status { margin: 0; min-height: 1.15em; font-size: 0.86rem; color: var(--muted); } +.status[data-kind="ok"] { color: var(--ok); } +.status[data-kind="err"] { color: var(--danger); } + +.settings-split { + display: grid; + grid-template-columns: 200px minmax(0, 480px); + gap: 16px; + min-height: 0; + align-items: start; + justify-content: start; + width: 100%; + max-width: 720px; + flex: 1; +} +.settings-split > .card, +.settings-split #settings-pane, +.settings-split #inst-settings-pane { + max-width: 480px; + width: 100%; + min-width: 0; + flex: none; + align-self: start; + height: fit-content; +} +.settings-split .card.grow { + flex: none; + max-width: 480px; +} +#settings-pane, +#inst-settings-pane { + display: grid; + gap: 10px; + align-content: start; +} +#inst-settings-pane { + gap: 8px; +} +#inst-settings-pane > h2 { + margin: 8px 0 0; + font-size: 0.95rem; + font-weight: 700; +} +#inst-settings-pane > h2:first-child { + margin-top: 0; +} +#inst-settings-pane > .check, +#inst-settings-pane > .java-path-row, +#inst-settings-pane > .memory-row, +#inst-settings-pane > .memory-block, +#inst-settings-pane > textarea { + margin: 0; +} +#inst-settings-pane > .modal-actions { + margin-top: 4px; +} +#settings-pane .field, +#inst-settings-pane .field, +#settings-pane .field-row, +#inst-settings-pane .field-row, +#settings-pane .info-grid, +#inst-settings-pane .info-grid, +#settings-pane > h2, +#inst-settings-pane > h2, +#settings-pane > p, +#inst-settings-pane > p, +#settings-pane .modal-actions, +#inst-settings-pane .modal-actions { + max-width: none; + width: 100%; +} +.settings-nav { + background: var(--panel); + border: 1px solid var(--line); + border-radius: 14px; + padding: 10px; + display: grid; + gap: 4px; + align-content: start; + width: 200px; + max-width: 200px; +} +.settings-link { + text-align: left; + border: 0; + background: transparent; + color: var(--muted); + border-radius: 10px; + padding: 10px 12px; + font: 600 0.9rem/1.2 var(--font); + cursor: pointer; +} +.settings-link.is-active { + background: color-mix(in srgb, var(--accent-violet) 22%, transparent); + color: var(--accent); +} +.settings-link:disabled { opacity: 0.4; cursor: not-allowed; } + +.java-list { display: grid; gap: 10px; } +.java-row { + display: flex; + justify-content: space-between; + gap: 12px; + align-items: center; + padding: 12px; + border-radius: 10px; + border: 1px solid var(--line); + background: var(--panel-2); +} +.java-row code { display: block; margin-top: 4px; font-size: 0.8rem; word-break: break-all; } +.ok-dot { color: var(--accent); font-weight: 700; } + +.group-title { + margin: 12px 0 4px; + font-size: 0.82rem; + font-weight: 700; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.menu-wrap { position: relative; } +.menu { + position: absolute; + right: 0; + top: calc(100% + 6px); + min-width: 170px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 10px; + padding: 6px; + display: grid; + gap: 2px; + z-index: 20; + box-shadow: 0 12px 30px rgba(0,0,0,0.35); +} +.menu[hidden] { display: none !important; } +.menu button { + border: 0; + background: transparent; + color: var(--text); + text-align: left; + border-radius: 8px; + padding: 9px 10px; + font: 600 0.88rem/1.2 var(--font); + cursor: pointer; +} +.menu button:hover { background: var(--panel-2); } +.menu button.danger { color: #ff9aa5; } + +.modal { + position: fixed; inset: 0; + background: rgba(0,0,0,0.58); + backdrop-filter: blur(8px); + display: grid; place-items: center; + padding: 20px; + z-index: 40; +} +.modal[hidden] { display: none !important; } +.modal-card { + width: min(440px, 100%); + background: var(--panel); + border: 1px solid var(--line); + border-radius: 16px; + padding: 18px; + display: grid; + gap: 14px; + box-shadow: 0 24px 60px rgba(0,0,0,0.45); + /* Tall modals (create, settings) must scroll instead of overflowing off-screen. */ + max-height: calc(100vh - 40px); + overflow-y: auto; +} +.wizard-card { width: min(420px, 100%); } +.modal-card.create-card { + width: min(480px, 100%); + max-height: calc(100vh - 40px); +} +.create-card .modal-actions { + position: sticky; + bottom: 0; + z-index: 4; + background: var(--panel); + padding-top: 8px; + margin-bottom: 0; +} +.create-icon-row { + display: flex; + gap: 14px; + align-items: center; +} +.create-icon-actions, +.iset-icon-actions { + display: flex; + flex-direction: column; + gap: 8px; +} +.create-icon-preview { flex-shrink: 0; } + +/* Modrinth-like searchable version combobox */ +.vcombo { + position: relative; + width: 100%; + z-index: 1; +} +.vcombo.is-open { + z-index: 30; +} +.vcombo-trigger { + position: relative; + display: flex; + align-items: center; +} +.vcombo-input { + width: 100% !important; + padding-right: 36px !important; +} +.vcombo.is-open .vcombo-input { + box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent) !important; +} +.vcombo-chevron { + position: absolute; + right: 4px; + top: 50%; + transform: translateY(-50%); + width: 32px; + height: 32px; + border: 0; + border-radius: 8px; + background: transparent; + color: var(--muted); + font: inherit; + line-height: 1; + cursor: pointer; + display: grid; + place-items: center; + transition: transform 0.15s ease, color 0.15s ease; +} +.vcombo-chevron:hover { color: var(--text); } +.vcombo.is-open .vcombo-chevron { transform: translateY(-50%) rotate(180deg); } +/* display:flex must not override [hidden] — that left the list always visible over Create */ +.vcombo-menu { + position: absolute; + left: 0; + right: 0; + top: calc(100% + 6px); + z-index: 35; + display: none; + flex-direction: column; + max-height: min(280px, 40vh); + border-radius: 12px; + border: 1px solid var(--line); + background: var(--panel-2); + box-shadow: 0 16px 40px rgba(0, 0, 0, 0.45); + overflow: hidden; +} +.vcombo.is-open .vcombo-menu:not([hidden]) { + display: flex; +} +.vcombo-menu[hidden] { + display: none !important; +} +.vcombo-list { + overflow-y: auto; + overscroll-behavior: contain; + max-height: inherit; +} +.vcombo-option, +.vcombo-empty { + display: block; + width: 100%; + text-align: left; + border: 0; + background: transparent; + color: var(--text); + padding: 10px 14px; + font: inherit; + cursor: pointer; +} +.vcombo-option:hover, +.vcombo-option.is-active, +.vcombo-option.is-selected { + background: color-mix(in srgb, var(--accent) 16%, transparent); +} +.vcombo-empty { color: var(--muted); cursor: default; } +.vcombo-footer { + border: 0; + border-top: 1px solid var(--line); + background: transparent; + color: var(--muted); + width: 100%; + padding: 12px 14px; + font: 600 0.9rem/1.2 var(--font); + cursor: pointer; + text-align: center; + flex-shrink: 0; +} +.vcombo-footer:hover { color: var(--text); background: color-mix(in srgb, #fff 4%, transparent); } +.settings-modal-card { + width: min(720px, 100%); + max-height: min(860px, calc(100vh - 40px)); + overflow: auto; +} +.settings-split-modal { + display: grid; + grid-template-columns: 180px minmax(0, 1fr); + gap: 14px; + max-width: none; + width: 100%; + align-items: start; +} +.settings-split-modal .settings-nav { + width: 180px; + max-width: 180px; +} +.settings-split-modal .settings-pane { + display: grid; + gap: 12px; + align-content: start; + min-width: 0; +} +.play-stack { + display: grid; + gap: 6px; + min-width: 168px; +} +.btn-play-main { + min-height: 42px; + width: 100%; +} +.btn-play-main.btn-stop { + background: #e85d75; + color: #fff; +} +.btn-play-main.is-launching { + opacity: 0.92; +} +.play-progress { + display: none; +} +.btn-warn { + background: transparent; + color: var(--text); + border: 1px solid var(--line); +} +.btn-warn:hover { + border-color: var(--accent); + color: var(--accent); +} +.iset-name-row { + display: flex; + gap: 14px; + align-items: center; + flex-wrap: wrap; +} +.iset-name-row .grow { flex: 1; min-width: 0; } +.iset-icon { flex-shrink: 0; } +.card-inset { + padding: 14px; + border-radius: 14px; + border: 1px solid var(--line); + background: color-mix(in srgb, var(--panel-2) 92%, #000); + display: grid; + gap: 10px; +} +.danger-zone { + margin-top: 24px; + padding-top: 16px; + border-top: 1px solid color-mix(in srgb, #e85d75 35%, var(--line)); +} +.memory-row, .java-path-row { + display: flex; + gap: 10px; + align-items: center; + flex-wrap: wrap; +} +.memory-block { + display: grid; + gap: 10px; +} +.memory-slider-wrap { + display: grid; + gap: 4px; +} +.memory-slider-wrap input[type="range"] { + width: 100%; + min-width: 0; +} +.memory-scale { + display: flex; + justify-content: space-between; + font-size: 0.75rem; + color: var(--muted); + font-variant-numeric: tabular-nums; +} +.memory-quick { + display: flex; + flex-wrap: wrap; + gap: 6px; +} +.memory-quick-btn { + font-size: 0.78rem; + padding: 4px 10px; +} +.memory-quick-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} +.memory-row input[type="range"] { flex: 1; min-width: 140px; } +.memory-row input[type="number"] { width: 96px; } +.java-path-row input { flex: 1; min-width: 160px; } +.java-majors { display: grid; gap: 18px; } +.java-major-block h3 { + margin: 0 0 8px; + font-size: 1rem; +} +.java-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 8px; +} +.java-detect-card { max-width: 560px; width: min(560px, 92vw); } +.java-detect-list { display: grid; gap: 8px; max-height: 360px; overflow: auto; } +.java-detect-row { + display: flex; + gap: 12px; + align-items: center; + justify-content: space-between; + padding: 10px 12px; + border-radius: 12px; + border: 1px solid var(--line); + background: var(--panel-2); +} +.java-detect-row code { + display: block; + font-size: 0.75rem; + color: var(--muted); + word-break: break-all; +} +#inst-settings-pane h3 { + margin: 18px 0 6px; + font-size: 1rem; +} +.modal-head { display: flex; justify-content: space-between; align-items: center; } +.modal-head h2 { margin: 0; font-size: 1.2rem; } +.modal-actions { display: flex; flex-wrap: wrap; gap: 8px; } + +.placeholder-card { max-width: 640px; } + +.content-card { max-width: none; } +.content-tools { + display: flex; + flex-wrap: wrap; + gap: 12px; + align-items: center; +} +.linkish { + border: 0; + background: transparent; + color: var(--accent); + font: 600 0.85rem/1 var(--font); + cursor: pointer; + padding: 0; +} +.linkish:hover { text-decoration: underline; } + +.content-table { display: grid; gap: 6px; } +.content-head, .content-row { + display: grid; + grid-template-columns: minmax(180px, 1.4fr) minmax(140px, 1fr) auto; + gap: 12px; + align-items: center; +} +.content-head { + color: var(--muted); + font-size: 0.78rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.04em; + padding: 4px 8px; +} +.content-row { + padding: 10px 8px; + border-radius: 10px; + border: 1px solid var(--line); + background: var(--panel-2); +} +.content-project, .content-version { display: flex; gap: 10px; min-width: 0; } +.content-project > div, .content-version { display: grid; gap: 2px; } +.content-project strong, .content-version strong { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.content-project small, .content-version small { + color: var(--muted); + font-size: 0.8rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.content-icon, .world-icon { + width: 36px; + height: 36px; + border-radius: 8px; + background: #232428; + display: grid; + place-items: center; + font-weight: 700; + color: var(--accent); + flex-shrink: 0; + overflow: hidden; +} +.world-icon.has-image { background: transparent; } +.world-icon img { + width: 100%; + height: 100%; + object-fit: cover; + border-radius: 8px; + image-rendering: pixelated; /* MC world icons are tiny — keep them crisp */ +} +.content-actions { display: flex; gap: 8px; align-items: center; justify-content: flex-end; } + +.switch { + position: relative; + width: 40px; + height: 22px; + display: inline-block; +} +.switch input { opacity: 0; width: 0; height: 0; } +.switch span { + position: absolute; + inset: 0; + border-radius: 999px; + background: #3a3b40; + cursor: pointer; + transition: 0.15s background; +} +.switch span::after { + content: ""; + position: absolute; + width: 16px; + height: 16px; + left: 3px; + top: 3px; + border-radius: 50%; + background: #fff; + transition: 0.15s transform; +} +.switch input:checked + span { background: var(--accent); } +.switch input:checked + span::after { transform: translateX(18px); } +.switch input:focus-visible + span { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +.icon-btn.sm { width: 34px; height: 34px; font-size: 0.9rem; } + +.world-list { display: grid; gap: 8px; } +.world-row { + display: flex; + gap: 12px; + align-items: center; + padding: 12px; + border-radius: 10px; + border: 1px solid var(--line); + background: var(--panel-2); +} +.world-meta { flex: 1; display: grid; gap: 2px; min-width: 0; } +.world-meta small { color: var(--muted); } + +.empty-state { + text-align: center; + padding: 32px 16px; + border-radius: 14px; +} +.empty-state h3 { margin: 0 0 8px; letter-spacing: -0.02em; } +.empty-state.no-instance, +.empty-state:not(.servers-empty):not(.jump-empty) { + border: 1px dashed color-mix(in srgb, var(--line) 90%, var(--accent) 10%); + background: + radial-gradient(420px 160px at 50% 0%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 70%), + color-mix(in srgb, var(--panel-2) 80%, transparent); +} +.empty-state .home-quick-actions, +.empty-state .btn { margin-top: 4px; } + +.roadmap-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); + gap: 14px; + margin-top: 16px; +} +.roadmap-tile { + position: relative; + border: 1px solid var(--line); + background: var(--panel-2); + border-radius: 12px; + padding: 16px; + display: grid; + gap: 8px; + align-content: start; +} +.roadmap-tile h3 { margin: 0; font-size: 1.05rem; } +.roadmap-tile p { margin: 0; } +.roadmap-badge { justify-self: start; } + +.page-head-actions { display: flex; gap: 8px; align-items: center; } +.server-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 14px; +} +.server-card { + border: 1px solid var(--line); + background: var(--panel); + border-radius: 12px; + padding: 16px; + display: grid; + grid-template-columns: 44px 1fr; + gap: 10px 12px; +} +.server-card-icon { + width: 44px; + height: 44px; + border-radius: 10px; + background: linear-gradient(160deg, rgba(0, 229, 255, 0.22), #14141c); + border: 1px solid var(--line); + overflow: hidden; +} +.server-card-icon img { + width: 100%; + height: 100%; + object-fit: cover; +} +.server-card-body h3 { margin: 0 0 4px; font-size: 1.05rem; } +.server-card-body p { margin: 0; } +.server-card-meta { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-top: 8px; +} +.server-status, +.server-account { + display: inline-flex; + align-items: center; + min-height: 24px; + padding: 3px 7px; + border: 1px solid var(--line); + border-radius: 7px; + color: var(--muted); + font-size: 0.75rem; +} +.server-status[data-online="true"] { + border-color: color-mix(in srgb, var(--ok) 45%, var(--line)); + color: var(--ok); +} +.server-status[data-online="false"] { + border-color: color-mix(in srgb, var(--danger) 45%, var(--line)); + color: #ff9aa5; +} +.server-account { + border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); + color: var(--text); +} +.server-card-actions { + grid-column: 1 / -1; + display: flex; + gap: 8px; + justify-content: flex-end; +} +.form-grid { display: grid; gap: 10px; } +.form-grid label { display: grid; gap: 4px; font-size: 0.85rem; color: var(--muted); } +.mr-hit { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto auto auto; + gap: 8px; + align-items: center; +} +.mr-hit-main { + display: grid; + gap: 2px; + text-align: left; + background: transparent; + border: 0; + padding: 0; + color: inherit; + font: inherit; + cursor: pointer; + min-width: 0; +} +.mr-hit-main:hover strong { color: var(--accent); } +.mr-hit .mr-version-box { grid-column: 1 / -1; } +.mr-version-box { grid-column: 1 / -1; display: grid; gap: 6px; padding: 8px 0 0; } +.mr-version-row { + grid-template-columns: minmax(0, 1fr) auto !important; +} +.mr-cat-row { + display: flex; + flex-wrap: wrap; + gap: 6px; + margin-bottom: 10px; +} +.mr-cat-chip { + font-size: 0.78rem; +} +.mr-detail { + display: block; + padding: 0; + border: 1px solid var(--line); + border-radius: 12px; + background: var(--panel-2); + margin-bottom: 10px; + overflow: hidden; +} +.mr-detail-shell { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(180px, 240px); + gap: 0; + min-height: 320px; +} +.mr-detail-main { + display: grid; + grid-template-rows: auto auto minmax(0, 1fr); + gap: 0; + border-right: 1px solid var(--line); + min-width: 0; +} +.mr-detail-head { + display: grid; + grid-template-columns: auto auto minmax(0, 1fr) auto; + gap: 10px; + align-items: center; + padding: 12px 14px; + border-bottom: 1px solid var(--line); +} +.mr-detail-title { margin: 0; font-size: 1.1rem; letter-spacing: -0.02em; } +.mr-detail-tabs { + display: flex; + gap: 2px; + padding: 0 10px; + border-bottom: 1px solid var(--line); + background: color-mix(in srgb, var(--panel) 70%, transparent); +} +.mr-detail-tabs .tab { + appearance: none; + border: 0; + background: transparent; + color: var(--muted); + padding: 10px 12px; + font: inherit; + font-size: 0.85rem; + cursor: pointer; + border-bottom: 2px solid transparent; + margin-bottom: -1px; +} +.mr-detail-tabs .tab.is-active { + color: var(--text); + border-bottom-color: var(--accent); +} +.mr-detail-pane { + padding: 14px; + min-height: 200px; + max-height: min(52vh, 480px); + overflow: auto; +} +.mr-detail-body { + max-height: none; + overflow: visible; + white-space: pre-wrap; + font-size: 0.9rem; + line-height: 1.5; +} +.mr-detail-sidebar { + padding: 14px; + display: grid; + gap: 12px; + align-content: start; + background: color-mix(in srgb, var(--panel) 55%, transparent); +} +.mr-detail-sidebar h4 { + margin: 0; + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--muted); + font-weight: 600; +} +.mr-side-dl { + margin: 0; + display: grid; + gap: 10px; +} +.mr-side-dl > div { + display: grid; + gap: 2px; +} +.mr-side-dl dt { + font-size: 0.72rem; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.04em; +} +.mr-side-dl dd { + margin: 0; + font-size: 0.86rem; + word-break: break-word; +} +.mr-gallery { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + gap: 8px; +} +.mr-gallery-item { + display: block; + border-radius: 8px; + overflow: hidden; + border: 1px solid var(--line); + aspect-ratio: 16 / 10; + background: var(--panel); +} +.mr-gallery-item img { + width: 100%; + height: 100%; + object-fit: cover; + display: block; +} +.mr-detail-versions { + padding: 0; +} +.mr-detail-versions-label { + margin: 0; + font-size: 0.85rem; + color: var(--muted); + text-transform: uppercase; + letter-spacing: 0.04em; +} +.home-quick-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 12px; +} +.home-quick-always { + margin-top: 14px; + padding-top: 12px; + border-top: 1px solid color-mix(in srgb, var(--line) 80%, transparent); +} +.servers-empty { + min-height: 220px; + place-items: center; + text-align: center; + padding: 28px 16px; + border: 1px dashed color-mix(in srgb, var(--line) 90%, var(--accent) 10%); + border-radius: 14px; + background: + radial-gradient(420px 180px at 50% 0%, color-mix(in srgb, var(--accent) 10%, transparent), transparent 70%); +} +.servers-empty-art { + width: 64px; + height: 64px; + margin: 0 auto 10px; + border-radius: 16px; + border: 1px solid var(--line); + background: + linear-gradient(145deg, color-mix(in srgb, var(--accent) 18%, transparent), transparent 60%), + var(--panel-2); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 12%, transparent); +} +.top-status[data-kind="idle"] { + max-width: min(52vw, 560px); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.coming-soon { + min-height: calc(100vh - 48px - 70px); + display: grid; + place-items: center; +} +.coming-soon-card { + max-width: 420px; + text-align: center; + display: grid; + gap: 14px; + justify-items: center; +} +.coming-soon-card h1 { + margin: 0; + font-size: 1.55rem; + font-weight: 700; + letter-spacing: -0.03em; +} +.coming-soon-icon { + width: 88px; + height: 88px; + border-radius: 18px; + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--accent); + display: grid; + place-items: center; + box-shadow: 0 0 30px color-mix(in srgb, var(--accent-violet) 12%, transparent); +} + +.field-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} +.info-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); + gap: 12px; + margin: 12px 0 18px; +} +.info-grid > div { + display: grid; + gap: 4px; + padding: 12px; + border-radius: 10px; + background: var(--panel-2); + border: 1px solid var(--line); +} + +@media (max-width: 900px) { + .settings-split { grid-template-columns: 1fr; max-width: none; } + .settings-split > .card, + .settings-split #settings-pane, + .settings-split #inst-settings-pane, + .settings-split .card.grow, + .settings-nav { + max-width: none; + width: 100%; + } + .page-head.row, .instance-hero { flex-direction: column; } + .content-head, .content-row { grid-template-columns: 1fr; } + .mr-hit { + grid-template-columns: auto minmax(0, 1fr); + } + .mr-hit .mr-downloads { grid-column: 2; } + .mr-hit .mr-versions, + .mr-hit .mr-install { + justify-self: start; + } + .mr-detail-head { + grid-template-columns: auto minmax(0, 1fr); + } + .mr-detail-shell { + grid-template-columns: 1fr; + } + .mr-detail-main { + border-right: 0; + border-bottom: 1px solid var(--line); + } + .field-row { grid-template-columns: 1fr; } + .home-top { grid-template-columns: 1fr; } + .news-grid { grid-template-columns: 1fr; } +} + +/* Splash */ +.splash { + position: fixed; + inset: 0; + z-index: 100; + display: grid; + place-items: center; + background: #050508; + background-image: + radial-gradient(800px 420px at 20% 0%, rgba(139, 92, 246, 0.16), transparent 55%), + radial-gradient(700px 380px at 90% 10%, rgba(0, 229, 255, 0.1), transparent 50%); + transition: opacity 0.35s ease, visibility 0.35s ease; +} +.splash.is-done { + opacity: 0; + visibility: hidden; + pointer-events: none; +} +.splash-card { + display: grid; + justify-items: center; + gap: 14px; + width: min(360px, 86vw); + text-align: center; +} +.splash-logo svg { width: 64px; height: 64px; } +.splash-brand { + color: var(--accent); + font-size: 1.35rem; + letter-spacing: -0.03em; + text-transform: lowercase; +} +.splash-bar { + width: 100%; + height: 6px; + border-radius: 999px; + background: var(--panel-2); + border: 1px solid var(--line); + overflow: hidden; +} +.splash-fill { + height: 100%; + width: 0%; + background: linear-gradient(90deg, var(--accent-violet), var(--accent)); + transition: width 0.25s ease; +} +.splash-label { margin: 0; color: var(--muted); font-size: 0.9rem; } +.splash-win { + position: absolute; + top: 10px; + right: 10px; +} + +.shell.is-booting { visibility: hidden; } + +/* Particles */ +.particles { + position: fixed; + inset: 0; + z-index: 0; + pointer-events: none; +} +.shell { position: relative; z-index: 1; } +.modal { position: fixed; z-index: 50; } +.splash { z-index: 100; } + +:is( + button, + a[href], + input, + select, + textarea, + [tabindex]:not([tabindex="-1"]) +):focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; +} + +/* Page fill + motion */ +.page { + min-height: 100%; + width: 100%; + display: flex; + flex-direction: column; +} +.page.home-page { + display: flex; + flex-direction: column; + gap: 16px; + flex: 1; +} +.home-top { + display: grid; + grid-template-columns: minmax(0, 1fr) 280px; + gap: 16px; + align-items: start; + width: 100%; +} +.news-section.news-full { + width: 100%; + margin-top: 0; +} +.page.settings-split { + display: grid; + flex: 1; + align-content: start; + justify-content: start; +} +.main.is-entering { + animation: pageIn 0.2s ease; +} +@keyframes pageIn { + from { opacity: 0; transform: translateY(6px); } + to { opacity: 1; transform: translateY(0); } +} +@media (prefers-reduced-motion: reduce) { + .main.is-entering { animation: none; } + .pill[data-kind="busy"]::before { animation: none; } + .particles { display: none; } +} + +/* News — denser list rhythm (Modrinth-inspired), not card spam */ +.news-section { margin-top: 12px; flex: 1; } +.news-grid { + display: grid; + grid-template-columns: 1fr; + gap: 0; + border-top: 1px solid var(--line); +} +.news-tile { + border: 0; + border-bottom: 1px solid var(--line); + background: transparent; + border-radius: 0; + padding: 14px 4px; + display: grid; + gap: 6px; + min-height: 0; + transition: background 0.12s ease; +} +.news-tile:hover { + background: color-mix(in srgb, var(--panel-2) 55%, transparent); + transform: none; +} +.news-tile h3 { margin: 0; font-size: 0.98rem; letter-spacing: -0.01em; } +.news-tile p { margin: 0; font-size: 0.88rem; } +.news-tag { + width: fit-content; + font-size: 0.68rem; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; + color: var(--accent); + background: color-mix(in srgb, var(--accent) 12%, transparent); + border-radius: 6px; + padding: 3px 7px; +} +@media (min-width: 900px) { + .news-grid { + grid-template-columns: 1fr 1fr; + column-gap: 28px; + } +} + +/* Playing-as profile dropdown */ +.playing-as { + display: grid; + gap: 8px; + width: 100%; +} +.playing-as-label { + color: var(--muted); + font-size: 0.85rem; + font-weight: 500; +} +.playing-as-menu { + position: relative; + width: 100%; +} +.playing-as-trigger { + width: 100%; + display: flex; + align-items: center; + gap: 12px; + text-align: left; + border: 1px solid var(--line); + background: var(--panel); + color: var(--text); + border-radius: 12px; + padding: 10px 12px; + cursor: pointer; + font: inherit; +} +.playing-as-trigger:hover { + border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); +} +.playing-as-trigger.is-open { + border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +.playing-as-avatar { + width: 40px; + height: 40px; + border-radius: 8px; + border: 1px solid var(--line); + background: + linear-gradient(135deg, #2a2d34 25%, transparent 25%) -8px 0 / 16px 16px, + linear-gradient(225deg, #2a2d34 25%, transparent 25%) -8px 0 / 16px 16px, + linear-gradient(315deg, #2a2d34 25%, transparent 25%) 0 0 / 16px 16px, + linear-gradient(45deg, #2a2d34 25%, #1a1b1e 25%) 0 0 / 16px 16px; + display: grid; + place-items: center; + font-weight: 700; + flex-shrink: 0; + overflow: hidden; +} +.playing-as-avatar img { + width: 100%; + height: 100%; + object-fit: cover; + image-rendering: pixelated; +} +.playing-as-meta { + flex: 1; + min-width: 0; + display: grid; + gap: 2px; +} +.playing-as-meta strong { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.playing-as-meta small { color: var(--muted); font-size: 0.8rem; } +.playing-as-chevron { + color: var(--muted); + font-size: 0.75rem; + transition: transform 0.15s ease; +} +.playing-as-trigger.is-open .playing-as-chevron { transform: rotate(180deg); } +.playing-as-panel { + position: absolute; + left: 0; + right: 0; + top: 100%; + z-index: 30; + background: var(--panel); + border: 1px solid var(--line); + border-top: 0; + border-radius: 0 0 12px 12px; + padding: 8px; + display: grid; + gap: 6px; + box-shadow: 0 16px 40px rgba(0,0,0,0.4); +} +.playing-as-panel[hidden] { display: none !important; } +.playing-as-item { + display: flex; + align-items: center; + gap: 6px; + min-width: 0; +} +.playing-as-item .playing-as-row { + flex: 1; + min-width: 0; + width: auto; +} +.playing-as-row { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + border: 0; + background: transparent; + color: var(--text); + border-radius: 10px; + padding: 8px; + cursor: pointer; + font: inherit; + text-align: left; +} +.playing-as-row:hover { background: var(--panel-2); } +.playing-as-row.is-active { background: color-mix(in srgb, var(--accent-violet) 14%, transparent); } +.playing-as-radio { + width: 14px; + height: 14px; + border-radius: 999px; + border: 2px solid var(--muted); + flex-shrink: 0; +} +.playing-as-row.is-active .playing-as-radio { + border-color: #3ecf8e; + box-shadow: inset 0 0 0 3px #3ecf8e; +} +.playing-as-del { + width: 32px; + height: 32px; + border-radius: 999px; + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--muted); + cursor: pointer; + flex-shrink: 0; + display: grid; + place-items: center; + padding: 0; +} +.playing-as-del svg { + width: 14px; + height: 14px; + fill: currentColor; +} +.playing-as-del:hover { color: #ff9aa5; border-color: #6a2430; } +.playing-as-add { + width: 100%; + border: 0; + border-radius: 10px; + background: color-mix(in srgb, var(--panel-2) 80%, #39383f); + color: var(--text); + padding: 12px; + font: 600 0.92rem/1 var(--font); + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; +} +.playing-as-add:hover { filter: brightness(1.08); } + +.instance-list { max-width: none; } +.lib-toolbar { max-width: none; } +.log-view { + margin-top: 12px; + max-height: 420px; + overflow: auto; + padding: 12px; + border-radius: 12px; + border: 1px solid var(--line); + background: var(--panel-2); + font: 500 0.78rem/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + white-space: pre-wrap; + word-break: break-word; +} + +.logs-toolbar { + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + margin-bottom: 10px; +} +.logs-select { + min-width: 180px; + max-width: min(360px, 100%); + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--text); + border-radius: 10px; + padding: 8px 10px; + font: 600 0.85rem/1.2 var(--font); +} +.logs-select-sm { min-width: 110px; max-width: 140px; } +.logs-search { + flex: 1 1 160px; + min-width: 140px; +} +.logs-console { + min-height: 280px; + max-height: min(58vh, 560px); + overflow: auto; + padding: 10px 12px; + border-radius: 12px; + border: 1px solid var(--line); + background: color-mix(in srgb, var(--panel-2) 88%, #0a0a0c); + font: 500 0.78rem/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + white-space: pre-wrap; + word-break: break-word; +} +.log-line { margin: 0; padding: 1px 0; } +.log-line.log-error { color: #ff8e8e; } +.log-line.log-warn { color: #e6c07b; } +.log-line.log-info { color: color-mix(in srgb, var(--text) 82%, #8ec7ff); } +.log-line.log-other { color: color-mix(in srgb, var(--text) 78%, #aab); } +.logs-empty { + display: grid; + place-content: center; + min-height: 220px; + text-align: center; + gap: 6px; + padding: 24px; +} +.logs-empty h3 { margin: 0; font: 700 1.05rem/1.3 var(--font); color: var(--text); } + +/* Wizard */ +.wizard-modal .wizard-card { width: min(560px, 100%); } +.wizard-kinds { + display: grid; + gap: 10px; +} +.wizard-kind { + text-align: left; + border: 1px solid var(--line); + background: var(--panel-2); + color: var(--text); + border-radius: 12px; + padding: 12px 14px; + display: grid; + gap: 4px; + cursor: pointer; +} +.wizard-kind.is-selected { + border-color: color-mix(in srgb, var(--accent) 55%, var(--line)); + background: color-mix(in srgb, var(--accent) 12%, var(--panel-2)); + box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent); +} +.static-pill { justify-self: center; } + +.rail-sep { + display: block !important; + width: 28px; + height: 1px; + margin: 12px 0; + background: color-mix(in srgb, var(--line) 90%, #fff); + flex-shrink: 0; +} + +/* --- Modrinth App parity: browse / project / skins / create wizard --- */ +.create-steps { + display: flex; + align-items: center; + gap: 8px; + margin: 0 0 14px; +} +.create-step { + width: 28px; + height: 28px; + border-radius: 8px; + display: grid; + place-items: center; + background: var(--panel-2); + color: var(--muted); + font-size: 12px; + font-weight: 600; +} +.create-step.is-active { + background: var(--accent); + color: var(--accent-ink); +} +.create-step.is-done { + background: color-mix(in srgb, var(--accent) 35%, var(--panel-2)); + color: var(--text); +} +.create-step-sep { + flex: 1; + height: 1px; + background: var(--line); +} +.create-alt-row { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 8px 12px; + margin: 0 0 14px; +} +.create-step-panel { + min-height: 120px; +} +.mr-changelog { + display: grid; + gap: 16px; +} +.mr-changelog-entry h3 { + margin: 0 0 4px; + font-size: 15px; +} +.create-setup-types { + display: grid; + gap: 10px; + margin: 12px 0 18px; +} +.browse-page { display: flex; flex-direction: column; gap: 14px; min-height: 0; } +.browse-install-header { + display: flex; + align-items: center; + gap: 12px; + padding: 10px 12px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 12px; +} +.browse-install-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; } +.browse-type-tabs { display: flex; flex-wrap: wrap; gap: 6px; } +.browse-layout { + display: grid; + grid-template-columns: minmax(0, 1fr) 260px; + gap: 16px; + align-items: start; +} +.browse-toolbar { flex-wrap: wrap; } +.browse-search { flex: 1; min-width: 180px; } +.browse-sidebar { + position: sticky; + top: 8px; + display: grid; + gap: 12px; + padding: 12px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 12px; +} +.browse-locked { display: grid; gap: 8px; } +.browse-locked-row { display: flex; justify-content: space-between; gap: 8px; font-size: 13px; } +.browse-side-title { margin: 4px 0 0; font-size: 13px; color: var(--muted); font-weight: 600; } +.browse-results { display: grid; gap: 10px; } +.browse-card { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 12px; + align-items: center; + padding: 12px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 12px; +} +.browse-card-open { + display: grid; + grid-template-columns: 56px minmax(0, 1fr); + gap: 12px; + text-align: left; + background: transparent; + border: 0; + color: inherit; + cursor: pointer; + padding: 0; +} +.browse-card-icon { + width: 56px; + height: 56px; + border-radius: 10px; + background: var(--panel-2); + display: grid; + place-items: center; + font-weight: 700; + background-size: cover; + background-position: center; +} +.browse-card-body { display: grid; gap: 4px; min-width: 0; } +.browse-card-title { font-size: 1rem; } +.browse-card-desc { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + font-size: 13px; +} +.browse-card-meta { font-size: 12px; } +.browse-pager { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 8px; } +.project-page .mr-detail-shell { margin-top: 0; } +.project-icon-lg { + width: 64px; + height: 64px; + border-radius: 12px; + background: var(--panel-2); + display: grid; + place-items: center; + font-size: 1.4rem; + font-weight: 700; + background-size: cover; + background-position: center; + flex-shrink: 0; +} +.content-row.is-disabled { opacity: 0.55; } +.skins-page { display: grid; gap: 16px; } +.skins-layout { + display: grid; + grid-template-columns: 240px minmax(0, 1fr); + gap: 20px; +} +.skins-preview-panel { + position: relative; + padding: 16px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 14px; + text-align: center; +} +.skins-preview { + position: relative; + width: 160px; + height: 220px; + margin: 0 auto 10px; +} +.skins-preview-figure { + width: 160px; + height: 220px; + border-radius: 12px; + background: linear-gradient(180deg, #1a1a24, #0c0c12); + display: grid; + place-items: center; + font-size: 2.5rem; + font-weight: 700; + color: var(--accent); + background-size: cover; + background-position: center; +} +.skins-preview-face { + position: absolute; + inset: 36px 40px 80px; + border-radius: 8px; + image-rendering: pixelated; + background-repeat: no-repeat; + display: none; +} +.skins-preview-face.has-img { display: block; } +.skins-preview-actions { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; + margin-top: 10px; +} +.skins-preview-actions [hidden] { + display: none !important; +} +.skins-section { margin-bottom: 20px; } +.skins-section-head { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 10px; +} +.skins-section h2 { margin: 0; font-size: 1rem; } +.skins-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + gap: 10px; +} +.skins-tile { + position: relative; + display: grid; + gap: 8px; + justify-items: center; + padding: 12px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 12px; + color: inherit; + cursor: pointer; + transition: border-color 0.15s ease, transform 0.15s ease; +} +.skins-tile:hover { transform: translateY(-1px); } +.skins-tile.is-selected { border-color: var(--accent); } +.skins-tile-badge { + position: absolute; + top: 6px; + right: 6px; + font-size: 0.65rem; + color: var(--accent-ink); + background: var(--accent); + padding: 2px 6px; + border-radius: 6px; +} +.skins-tile-icon { + width: 48px; + height: 48px; + border-radius: 10px; + background: var(--panel-2); + display: grid; + place-items: center; + font-weight: 700; + image-rendering: pixelated; + background-repeat: no-repeat; +} +.skins-tile-icon.has-img { background-color: #0c0c12; } +.skins-owyx-card { + padding: 14px; + background: var(--panel); + border: 1px solid var(--line); + border-radius: 12px; +} +.skins-owyx-row { + display: flex; + gap: 14px; + align-items: flex-start; +} +.skins-owyx-thumb { + width: 56px; + height: 56px; + border-radius: 10px; + background: var(--panel-2); + flex-shrink: 0; + image-rendering: pixelated; + background-repeat: no-repeat; +} +.skins-owyx-thumb.has-img { background-color: #0c0c12; } +.settings-token-swatches { + display: flex; + gap: 8px; + margin: 12px 0; +} +.settings-token-swatches span { + width: 36px; + height: 36px; + border-radius: 8px; + border: 1px solid var(--line); +} +.rail-avatar { margin-top: auto; } +@media (max-width: 960px) { + .browse-layout { grid-template-columns: 1fr; } + .browse-sidebar { position: static; } + .skins-layout { grid-template-columns: 1fr; } +} diff --git a/legacy/Launcher/apps/launcher/src/version-combobox.ts b/legacy/Launcher/apps/launcher/src/version-combobox.ts new file mode 100644 index 00000000000..fe49aaa02c2 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/version-combobox.ts @@ -0,0 +1,332 @@ +/** Modrinth-like searchable version combobox (compact dropdown below the field). */ + +export type VersionComboboxOptions = { + placeholder?: string; + searchPlaceholder?: string; + toggleLabel?: string; + emptyLabel?: string; + /** Footer toggle for snapshots / all versions (Minecraft picker). */ + showAllToggle?: boolean; + showAllLabel?: string; + hideAllLabel?: string; + getShowAll?: () => boolean; + onShowAllChange?: (showAll: boolean) => void; + maxHeight?: number; + onChange?: (value: string) => void; +}; + +export type VersionCombobox = { + root: HTMLElement; + getValue: () => string; + setValue: (value: string, silent?: boolean) => void; + setOptions: (options: string[], selected?: string) => void; + setLabels: (labels: { + showAll?: string; + hideAll?: string; + placeholder?: string; + toggle?: string; + empty?: string; + }) => void; + close: () => void; + focus: () => void; + destroy: () => void; +}; + +let comboboxSequence = 0; + +export function createVersionCombobox(opts: VersionComboboxOptions = {}): VersionCombobox { + const maxHeight = opts.maxHeight ?? 220; + let allOptions: string[] = []; + let value = ""; + let open = false; + let filter = ""; + let showAllLabel = opts.showAllLabel || "Show all versions"; + let hideAllLabel = opts.hideAllLabel || "Hide snapshots"; + let toggleLabel = opts.toggleLabel || "Toggle version list"; + let emptyLabel = opts.emptyLabel || "No versions"; + let showAll = opts.getShowAll?.() ?? false; + let onChange = opts.onChange; + let activeIndex = -1; + /** Skip the next focus→open when we closed via Escape / outside click. */ + let suppressOpenOnFocus = false; + + const root = document.createElement("div"); + root.className = "vcombo"; + + const trigger = document.createElement("div"); + trigger.className = "vcombo-trigger"; + + const input = document.createElement("input"); + input.type = "text"; + input.className = "vcombo-input"; + input.autocomplete = "off"; + input.spellcheck = false; + input.setAttribute("role", "combobox"); + input.setAttribute("aria-expanded", "false"); + input.setAttribute("aria-autocomplete", "list"); + input.setAttribute("aria-haspopup", "listbox"); + input.placeholder = opts.searchPlaceholder || opts.placeholder || "Search…"; + + const chevron = document.createElement("button"); + chevron.type = "button"; + chevron.className = "vcombo-chevron"; + chevron.setAttribute("aria-label", toggleLabel); + chevron.tabIndex = -1; + chevron.textContent = "▾"; + + trigger.append(input, chevron); + + const menu = document.createElement("div"); + menu.className = "vcombo-menu"; + menu.hidden = true; + menu.setAttribute("role", "listbox"); + const listId = `vcombo-list-${++comboboxSequence}`; + menu.id = listId; + input.setAttribute("aria-controls", listId); + + const list = document.createElement("div"); + list.className = "vcombo-list"; + list.style.maxHeight = `${maxHeight}px`; + + menu.append(list); + + let footer: HTMLButtonElement | null = null; + if (opts.showAllToggle) { + footer = document.createElement("button"); + footer.type = "button"; + footer.className = "vcombo-footer"; + menu.append(footer); + } + + root.append(trigger, menu); + + const filtered = () => { + const q = filter.trim().toLowerCase(); + if (!q) return allOptions; + return allOptions.filter((o) => o.toLowerCase().includes(q)); + }; + + const paintFooter = () => { + if (!footer) return; + const showing = opts.getShowAll?.() ?? showAll; + showAll = showing; + footer.textContent = showing ? hideAllLabel : showAllLabel; + }; + + const paintList = () => { + list.replaceChildren(); + const items = filtered(); + if (!items.length) { + activeIndex = -1; + input.removeAttribute("aria-activedescendant"); + const empty = document.createElement("div"); + empty.className = "vcombo-empty"; + empty.textContent = emptyLabel; + list.append(empty); + return; + } + if (activeIndex < 0 || activeIndex >= items.length) { + const selectedIndex = items.indexOf(value); + activeIndex = selectedIndex >= 0 ? selectedIndex : 0; + } + items.forEach((item, index) => { + const btn = document.createElement("button"); + btn.type = "button"; + btn.id = `${listId}-option-${index}`; + btn.tabIndex = -1; + btn.className = `vcombo-option${item === value ? " is-selected" : ""}${index === activeIndex ? " is-active" : ""}`; + btn.setAttribute("role", "option"); + btn.setAttribute("aria-selected", item === value ? "true" : "false"); + btn.textContent = item; + btn.addEventListener("mousemove", () => { + if (activeIndex === index) return; + activeIndex = index; + paintList(); + }); + btn.addEventListener("mousedown", (e) => { + e.preventDefault(); + setValue(item); + close({ blur: true }); + }); + list.append(btn); + }); + input.setAttribute("aria-activedescendant", `${listId}-option-${activeIndex}`); + }; + + const openMenu = () => { + if (open) return; + open = true; + root.classList.add("is-open"); + menu.hidden = false; + input.setAttribute("aria-expanded", "true"); + filter = ""; + input.value = value; + activeIndex = Math.max(0, allOptions.indexOf(value)); + paintFooter(); + paintList(); + }; + + const close = (optsClose: { blur?: boolean } = {}) => { + if (!open) { + if (optsClose.blur) input.blur(); + return; + } + open = false; + root.classList.remove("is-open"); + menu.hidden = true; + input.setAttribute("aria-expanded", "false"); + input.removeAttribute("aria-activedescendant"); + filter = ""; + input.value = value; + if (optsClose.blur) { + suppressOpenOnFocus = true; + input.blur(); + } + }; + + const toggle = () => { + if (open) close(); + else { + openMenu(); + input.focus(); + input.select(); + } + }; + + const setValue = (next: string, silent = false) => { + value = next; + if (!open) input.value = value; + if (!silent) onChange?.(value); + if (open) paintList(); + }; + + const setOptions = (options: string[], selected?: string) => { + allOptions = options.slice(); + const pick = + selected && options.includes(selected) + ? selected + : options.includes(value) + ? value + : (options[0] ?? ""); + setValue(pick, true); + activeIndex = Math.max(0, allOptions.indexOf(value)); + input.value = value; + if (open) paintList(); + }; + + input.addEventListener("focus", () => { + if (suppressOpenOnFocus) { + suppressOpenOnFocus = false; + return; + } + openMenu(); + input.select(); + }); + input.addEventListener("click", () => { + if (!open) openMenu(); + }); + input.addEventListener("input", () => { + if (!open) openMenu(); + filter = input.value; + activeIndex = 0; + paintList(); + }); + input.addEventListener("keydown", (e) => { + if (e.key === "Escape") { + e.preventDefault(); + e.stopPropagation(); + close({ blur: true }); + return; + } + if (e.key === "ArrowDown" || e.key === "ArrowUp") { + e.preventDefault(); + if (!open) openMenu(); + const items = filtered(); + if (items.length) { + const direction = e.key === "ArrowDown" ? 1 : -1; + activeIndex = (activeIndex + direction + items.length) % items.length; + paintList(); + list + .querySelector(`#${listId}-option-${activeIndex}`) + ?.scrollIntoView({ block: "nearest" }); + } + return; + } + if (e.key === "Home" || e.key === "End") { + e.preventDefault(); + if (!open) openMenu(); + const items = filtered(); + if (items.length) { + activeIndex = e.key === "Home" ? 0 : items.length - 1; + paintList(); + } + return; + } + if (e.key === "Enter") { + e.preventDefault(); + const items = filtered(); + const exact = items.find((i) => i.toLowerCase() === input.value.trim().toLowerCase()); + const pick = exact ?? items[activeIndex] ?? items[0]; + if (pick) { + setValue(pick); + close({ blur: true }); + } + } + }); + + chevron.addEventListener("mousedown", (e) => { + e.preventDefault(); + e.stopPropagation(); + toggle(); + }); + + footer?.addEventListener("mousedown", (e) => { + e.preventDefault(); + const next = !(opts.getShowAll?.() ?? showAll); + showAll = next; + opts.onShowAllChange?.(next); + paintFooter(); + }); + + const onDocPointer = (e: Event) => { + if (!open) return; + const t = e.target as Node | null; + if (t && root.contains(t)) return; + close(); + }; + document.addEventListener("pointerdown", onDocPointer, true); + + const onDocKey = (e: KeyboardEvent) => { + if (!open) return; + if (e.key === "Escape") { + e.preventDefault(); + close({ blur: true }); + } + }; + document.addEventListener("keydown", onDocKey, true); + + return { + root, + getValue: () => value, + setValue, + setOptions, + setLabels: (labels) => { + if (labels.showAll) showAllLabel = labels.showAll; + if (labels.hideAll) hideAllLabel = labels.hideAll; + if (labels.placeholder) input.placeholder = labels.placeholder; + if (labels.toggle) { + toggleLabel = labels.toggle; + chevron.setAttribute("aria-label", toggleLabel); + } + if (labels.empty) emptyLabel = labels.empty; + if (open) paintFooter(); + }, + close: () => close(), + focus: () => input.focus(), + destroy: () => { + document.removeEventListener("pointerdown", onDocPointer, true); + document.removeEventListener("keydown", onDocKey, true); + root.remove(); + }, + }; +} diff --git a/legacy/Launcher/apps/launcher/src/vite-env.d.ts b/legacy/Launcher/apps/launcher/src/vite-env.d.ts new file mode 100644 index 00000000000..11f02fe2a00 --- /dev/null +++ b/legacy/Launcher/apps/launcher/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/legacy/Launcher/apps/launcher/tsconfig.json b/legacy/Launcher/apps/launcher/tsconfig.json new file mode 100644 index 00000000000..6abfffe03a1 --- /dev/null +++ b/legacy/Launcher/apps/launcher/tsconfig.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/legacy/Launcher/apps/launcher/vite.config.ts b/legacy/Launcher/apps/launcher/vite.config.ts new file mode 100644 index 00000000000..25bd885eba4 --- /dev/null +++ b/legacy/Launcher/apps/launcher/vite.config.ts @@ -0,0 +1,59 @@ +import { defineConfig } from "vite"; + +const host = process.env.TAURI_DEV_HOST; + +export default defineConfig(async () => ({ + clearScreen: false, + server: { + port: 1420, + strictPort: true, + // Force IPv4: binding only ::1 makes http://localhost:1420 fail when + // the browser resolves localhost → 127.0.0.1 (ERR_CONNECTION_REFUSED). + host: host || "127.0.0.1", + hmr: host + ? { + protocol: "ws", + host, + port: 1421, + } + : undefined, + watch: { + ignored: ["**/src-tauri/**"], + }, + // Browser UI preview without Tauri: proxy official metas (avoid CORS). + proxy: { + // Owyx site API for the browser dev preview of Owyx account sign-in. + // In the packaged app this goes through Rust (reqwest), not this proxy. + "/proxy/owyx": { + target: process.env.OWYX_API_BASE_URL || "http://127.0.0.1:3001", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/owyx/, ""), + }, + "/proxy/mojang": { + target: "https://piston-meta.mojang.com", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/mojang/, ""), + }, + "/proxy/fabric": { + target: "https://meta.fabricmc.net", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/fabric/, ""), + }, + "/proxy/quilt": { + target: "https://meta.quiltmc.org", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/quilt/, ""), + }, + "/proxy/forge": { + target: "https://maven.minecraftforge.net", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/forge/, ""), + }, + "/proxy/neoforge": { + target: "https://maven.neoforged.net", + changeOrigin: true, + rewrite: (p) => p.replace(/^\/proxy\/neoforge/, ""), + }, + }, + }, +})); diff --git a/legacy/Launcher/docs/minecraft-meta.md b/legacy/Launcher/docs/minecraft-meta.md new file mode 100644 index 00000000000..405e0eaf86f --- /dev/null +++ b/legacy/Launcher/docs/minecraft-meta.md @@ -0,0 +1,40 @@ +# Minecraft / Loader meta sources + +Официальные списки версий (не наш backend). Используем их для экрана «Настройка установки». + +## Minecraft client JARs + +1. Манифест всех версий: + `https://piston-meta.mojang.com/mc/game/version_manifest_v2.json` +2. У нужной версии взять поле `url` → JSON этой версии. +3. Client jar: `downloads.client.url` (+ `sha1`, `size`). + **Owyx / Theseus layout:** store under shared + `%USERPROFILE%/owyx/meta/versions/{id}/{id}.jar` (+ `{id}.json`), + **not** under `libraries/com/mojang/minecraft/client.jar`. + Libraries: `libraries[]` → обычно `https://libraries.minecraft.net/...` → `meta/libraries/` + Assets: `assetIndex` → `https://resources.download.minecraft.net/...` → `meta/assets/` + +Документация: [wiki.vg Game files](https://wiki.vg/Game_files), [Minecraft Wiki version_manifest](https://minecraft.wiki/w/Version_manifest.json). + +Старый хост `launchermeta.mojang.com` ещё отвечает, канонический — **piston-meta**. + +## Loaders + +| Loader | Meta | +|--------|------| +| Fabric | `https://meta.fabricmc.net/v2/versions/game`, `.../loader/{mc}` | +| Quilt | `https://meta.quiltmc.org/v3/versions/loader/{mc}` | +| Forge | Maven metadata `https://maven.minecraftforge.net/net/minecraftforge/forge/maven-metadata.xml` (версии вида `1.20.1-47.2.0`) | +| NeoForge | `https://maven.neoforged.net/releases/net/neoforged/neoforge/maven-metadata.xml` | +| Vanilla | только Mojang version manifest | + +## CurseForge packs (future) + +Импорт zip/папки: `manifest.json` (projectID/fileID модов) + `overrides/` (`config`, `kubejs`, …) + иногда HTML index со ссылками. +Скачивание модов — через CurseForge API / mirror (нужен API key на backend). Не в MVP главного меню. + +## Owyx control-plane backend (future) + +Docker на mini-PC → FRPC → публичный IP:port VPS. +Админский лаунчер пишет настройки, игровые лаунчеры читают. +Дружеский лист сборок — **после** классического install/play flow. diff --git a/legacy/Launcher/docs/modrinth-reference.md b/legacy/Launcher/docs/modrinth-reference.md new file mode 100644 index 00000000000..02b28c64f4c --- /dev/null +++ b/legacy/Launcher/docs/modrinth-reference.md @@ -0,0 +1,19 @@ +# Modrinth reference (local) + +Clone path (sibling of this repo): + +`Z:\!Others\!Dev\modrinth-code` + +Remote: https://github.com/modrinth/code + +Sparse checkout of launcher-relevant packages: + +- `apps/app` — Tauri shell +- `apps/app-frontend` — Vue UI +- `packages/app-lib` — Theseus (instances / Java / launch) +- `packages/ui`, `packages/assets` + +**Phase 1:** port behavior and UI structure into Owyx (`apps/launcher`) as a working Modrinth-like reference. +**Phase 2:** Owyx brand, colors, logos, private servers, own login, possible layout redesign. + +Do not commit the Modrinth clone into this git repo. diff --git a/legacy/Launcher/docs/update-api-v1.md b/legacy/Launcher/docs/update-api-v1.md new file mode 100644 index 00000000000..8f73e8553ed --- /dev/null +++ b/legacy/Launcher/docs/update-api-v1.md @@ -0,0 +1,25 @@ +# Update API v1 + +Base URL comes from `config.json` → `updateBaseUrl`. +If empty, the launcher uses built-in **mock://local** fixtures (Stage 2 MVP). + +## Endpoints + +### `GET /v1/packs` +Returns `{ "packs": [ PackSummary, ... ] }`. + +### `GET /v1/packs/{id}/manifest` +Returns pack manifest with `files[]` (`path`, `url`, `sha256`, `size`). + +## Local layout + +```text +%USERPROFILE%\owyx\ + config.json + instances\{pack_id}\game\... + instances\{pack_id}\meta.json + cache\ + logs\ +``` + +Product name / binary: **Owyx**. diff --git a/legacy/Launcher/legacy/README.md b/legacy/Launcher/legacy/README.md new file mode 100644 index 00000000000..aa97622c956 --- /dev/null +++ b/legacy/Launcher/legacy/README.md @@ -0,0 +1,10 @@ +# Legacy C# prototype (reference only) + +This folder is **not built** and is **not** part of Owyx Launcher. + +It keeps selected source from the old WinForms prototype so we can reuse *ideas* +(server ping, Java discovery, launch args, logging) while rewriting in Rust + Tauri. + +- Do not add secrets here. +- Do not restore SFTP passwords or production hosts into committed files. +- See root [PLAN.md](../../PLAN.md). diff --git a/legacy/Launcher/legacy/csharp/ConfigManager.cs b/legacy/Launcher/legacy/csharp/ConfigManager.cs new file mode 100644 index 00000000000..3bb0dae482b --- /dev/null +++ b/legacy/Launcher/legacy/csharp/ConfigManager.cs @@ -0,0 +1,214 @@ +using System; +using System.IO; +using System.Text.Json; +using System.Threading.Tasks; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + public class ConfigManager + { + private const string CONFIG_FILE_NAME = "launcher_config.json"; + private const string PROFILES_FILE_NAME = "launcher_profiles.json"; + private readonly string configDirectory; + private readonly string configFilePath; + private readonly string profilesFilePath; + + public ConfigManager() + { + configDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ".owyxlauncher"); + configFilePath = Path.Combine(configDirectory, CONFIG_FILE_NAME); + profilesFilePath = Path.Combine(configDirectory, PROFILES_FILE_NAME); + + EnsureConfigDirectoryExists(); + } + + /// + /// Загрузить конфигурацию лаунчера + /// + /// Конфигурация лаунчера + public async Task LoadConfig() + { + try + { + if (!File.Exists(configFilePath)) + { + var defaultConfig = CreateDefaultConfig(); + await SaveConfig(defaultConfig); + return defaultConfig; + } + + var jsonContent = await File.ReadAllTextAsync(configFilePath); + var config = JsonSerializer.Deserialize(jsonContent); + return config ?? CreateDefaultConfig(); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при загрузке конфигурации: {ex.Message}"); + return CreateDefaultConfig(); + } + } + + /// + /// Сохранить конфигурацию лаунчера + /// + /// Конфигурация для сохранения + public async Task SaveConfig(LauncherConfig config) + { + try + { + var options = new JsonSerializerOptions + { + WriteIndented = true + }; + + var jsonContent = JsonSerializer.Serialize(config, options); + await File.WriteAllTextAsync(configFilePath, jsonContent); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при сохранении конфигурации: {ex.Message}"); + throw; + } + } + + /// + /// Загрузить профиль игры + /// + /// Профиль игры + public async Task LoadGameProfile() + { + try + { + if (!File.Exists(profilesFilePath)) + { + var defaultProfile = CreateDefaultProfile(); + await SaveGameProfile(defaultProfile); + return defaultProfile; + } + + var jsonContent = await File.ReadAllTextAsync(profilesFilePath); + var profile = JsonSerializer.Deserialize(jsonContent); + return profile ?? CreateDefaultProfile(); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при загрузке профиля: {ex.Message}"); + return CreateDefaultProfile(); + } + } + + /// + /// Сохранить профиль игры + /// + /// Профиль для сохранения + public async Task SaveGameProfile(GameProfile profile) + { + try + { + var options = new JsonSerializerOptions + { + WriteIndented = true + }; + + var jsonContent = JsonSerializer.Serialize(profile, options); + await File.WriteAllTextAsync(profilesFilePath, jsonContent); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при сохранении профиля: {ex.Message}"); + throw; + } + } + + /// + /// Получить путь к директории игры + /// + /// Путь к директории игры + public string GetGameDirectory() + { + return configDirectory; + } + + /// + /// Убедиться что директория конфигурации существует + /// + private void EnsureConfigDirectoryExists() + { + try + { + if (!Directory.Exists(configDirectory)) + { + Directory.CreateDirectory(configDirectory); + } + + // Создать поддиректории + var subdirectories = new[] { "versions", "mods", "assets", "logs" }; + foreach (var subdir in subdirectories) + { + var path = Path.Combine(configDirectory, subdir); + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при создании директорий: {ex.Message}"); + throw; + } + } + + /// + /// Создать конфигурацию по умолчанию + /// + /// Конфигурация по умолчанию + private LauncherConfig CreateDefaultConfig() + { + return new LauncherConfig + { + ServerUrl = "http://yourserver.com", + LauncherVersion = "1.0.0", + AutoUpdate = true, + CheckUpdatesOnStartup = true, + GameDirectory = configDirectory + }; + } + + /// + /// Создать профиль по умолчанию + /// + /// Профиль по умолчанию + private GameProfile CreateDefaultProfile() + { + return new GameProfile + { + Name = "Default", + GameDirectory = configDirectory, + MinecraftVersion = "1.20.1", + LauncherVersion = "1.0.0", + IsDefault = true + }; + } + } + + /// + /// Конфигурация лаунчера + /// + public class LauncherConfig + { + public string ServerUrl { get; set; } = string.Empty; + public string LauncherVersion { get; set; } = "1.0.0"; + public bool AutoUpdate { get; set; } = true; + public bool CheckUpdatesOnStartup { get; set; } = true; + public string GameDirectory { get; set; } = string.Empty; + public DateTime LastUpdateCheck { get; set; } = DateTime.Now; + public bool EnableDiscordRPC { get; set; } = true; + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/CustomTitleBar.cs b/legacy/Launcher/legacy/csharp/CustomTitleBar.cs new file mode 100644 index 00000000000..0bf03baf71d --- /dev/null +++ b/legacy/Launcher/legacy/csharp/CustomTitleBar.cs @@ -0,0 +1,155 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; +using System.Windows.Forms; + +namespace MinecraftLauncher +{ + /// + /// Кастомный Title Bar для borderless формы + /// + public class CustomTitleBar : Panel + { + private Label titleLabel; + private Button minimizeButton; + private Button maximizeButton; + private Button closeButton; + private Form parentForm; + private bool isDragging = false; + private Point dragStart; + + // Цвета Owyx + private readonly Color BackgroundColor = Color.FromArgb(24, 24, 32); + private readonly Color ButtonHoverColor = Color.FromArgb(40, 40, 50); + private readonly Color CloseHoverColor = Color.FromArgb(200, 50, 50); + private readonly Color TextColor = Color.FromArgb(240, 240, 245); + + public CustomTitleBar(Form parent) + { + parentForm = parent; + InitializeComponent(); + SetupDragHandlers(); + } + + private void InitializeComponent() + { + this.Height = 35; + this.Dock = DockStyle.Top; + this.BackColor = BackgroundColor; + + // Заголовок + titleLabel = new Label + { + Text = parentForm.Text, + ForeColor = TextColor, + Font = new Font("Segoe UI", 10F, FontStyle.Bold), + Location = new Point(15, 8), + Size = new Size(400, 20), + AutoSize = false + }; + this.Controls.Add(titleLabel); + + // Кнопки управления + int buttonX = parentForm.ClientSize.Width - 135; + + minimizeButton = CreateControlButton("─", buttonX); + minimizeButton.Click += (s, e) => parentForm.WindowState = FormWindowState.Minimized; + + maximizeButton = CreateControlButton("□", buttonX + 45); + maximizeButton.Click += MaximizeButton_Click; + + closeButton = CreateControlButton("✕", buttonX + 90); + closeButton.Click += (s, e) => parentForm.Close(); + closeButton.MouseEnter += (s, e) => closeButton.BackColor = CloseHoverColor; + closeButton.MouseLeave += (s, e) => closeButton.BackColor = BackgroundColor; + + this.Controls.Add(minimizeButton); + this.Controls.Add(maximizeButton); + this.Controls.Add(closeButton); + + // Обновить позиции при изменении размера формы + parentForm.Resize += (s, e) => UpdateButtonPositions(); + } + + private Button CreateControlButton(string text, int x) + { + var button = new Button + { + Text = text, + ForeColor = TextColor, + BackColor = BackgroundColor, + FlatStyle = FlatStyle.Flat, + Size = new Size(45, 35), + Location = new Point(x, 0), + Font = new Font("Segoe UI", 10F), + Cursor = Cursors.Hand + }; + + button.FlatAppearance.BorderSize = 0; + button.FlatAppearance.MouseOverBackColor = ButtonHoverColor; + button.FlatAppearance.MouseDownBackColor = ButtonHoverColor; + + return button; + } + + private void MaximizeButton_Click(object sender, EventArgs e) + { + if (parentForm.WindowState == FormWindowState.Maximized) + { + parentForm.WindowState = FormWindowState.Normal; + maximizeButton.Text = "□"; + } + else + { + parentForm.WindowState = FormWindowState.Maximized; + maximizeButton.Text = "❐"; + } + } + + private void UpdateButtonPositions() + { + int buttonX = parentForm.ClientSize.Width - 135; + minimizeButton.Location = new Point(buttonX, 0); + maximizeButton.Location = new Point(buttonX + 45, 0); + closeButton.Location = new Point(buttonX + 90, 0); + } + + private void SetupDragHandlers() + { + this.MouseDown += TitleBar_MouseDown; + this.MouseMove += TitleBar_MouseMove; + this.MouseUp += TitleBar_MouseUp; + titleLabel.MouseDown += TitleBar_MouseDown; + titleLabel.MouseMove += TitleBar_MouseMove; + titleLabel.MouseUp += TitleBar_MouseUp; + } + + private void TitleBar_MouseDown(object sender, MouseEventArgs e) + { + if (e.Button == MouseButtons.Left) + { + isDragging = true; + dragStart = e.Location; + } + } + + private void TitleBar_MouseMove(object sender, MouseEventArgs e) + { + if (isDragging) + { + Point currentScreenPos = PointToScreen(e.Location); + parentForm.Location = new Point(currentScreenPos.X - dragStart.X, currentScreenPos.Y - dragStart.Y); + } + } + + private void TitleBar_MouseUp(object sender, MouseEventArgs e) + { + isDragging = false; + } + + public void UpdateTitle(string title) + { + titleLabel.Text = title; + } + } +} diff --git a/legacy/Launcher/legacy/csharp/DiscordRPCManager.cs b/legacy/Launcher/legacy/csharp/DiscordRPCManager.cs new file mode 100644 index 00000000000..107dce9d349 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/DiscordRPCManager.cs @@ -0,0 +1,220 @@ +using System; +using DiscordRPC; +using DiscordRPC.Logging; + +namespace MinecraftLauncher +{ + /// + /// Менеджер Discord Rich Presence для отображения активности в Discord + /// + public class DiscordRPCManager : IDisposable + { + private DiscordRpcClient client; + private bool isInitialized = false; + + // Discord Application ID (нужно создать приложение на https://discord.com/developers/applications) + private const string APPLICATION_ID = "1433150569010167980"; // ЗАМЕНИТЬ на реальный ID + + // Иконки (нужно загрузить в Discord Developer Portal -> Rich Presence -> Art Assets) + private const string LARGE_IMAGE_KEY = "owyx_logo"; + private const string SMALL_IMAGE_KEY = "minecraft_icon"; + + public DiscordRPCManager() + { + try + { + Initialize(); + } + catch (Exception ex) + { + // Discord может быть не установлен или не запущен + Console.WriteLine($"Не удалось инициализировать Discord RPC: {ex.Message}"); + } + } + + /// + /// Инициализация Discord RPC клиента + /// + private void Initialize() + { + client = new DiscordRpcClient(APPLICATION_ID); + + // Настройка логирования (опционально) + client.Logger = new ConsoleLogger() { Level = LogLevel.Warning }; + + // События подключения + client.OnReady += (sender, e) => + { + Console.WriteLine($"Discord RPC подключен к пользователю {e.User.Username}"); + }; + + client.OnPresenceUpdate += (sender, e) => + { + Console.WriteLine("Discord RPC обновлен"); + }; + + // Подключение + if (client.Initialize()) + { + isInitialized = true; + SetIdleState(); + } + } + + /// + /// Установить статус "В меню лаунчера" + /// + public void SetIdleState() + { + if (!isInitialized) return; + + try + { + client.SetPresence(new RichPresence() + { + Details = "В меню лаунчера", + State = "Выбирает профиль", + Assets = new Assets() + { + LargeImageKey = LARGE_IMAGE_KEY, + LargeImageText = "Owyx Launcher", + SmallImageKey = SMALL_IMAGE_KEY, + SmallImageText = "Minecraft" + }, + Timestamps = Timestamps.Now + }); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при обновлении Discord RPC: {ex.Message}"); + } + } + + /// + /// Установить статус "Играет на сервере" + /// + /// Название сервера + /// Количество игроков + /// Максимальное количество игроков + public void SetPlayingState(string serverName, int playerCount, int maxPlayers) + { + if (!isInitialized) return; + + try + { + client.SetPresence(new RichPresence() + { + Details = $"Играет на {serverName}", + State = $"Игроков: {playerCount}/{maxPlayers}", + Assets = new Assets() + { + LargeImageKey = LARGE_IMAGE_KEY, + LargeImageText = "Owyx Launcher", + SmallImageKey = SMALL_IMAGE_KEY, + SmallImageText = "Minecraft" + }, + Party = new Party() + { + ID = "chiwawa_server", + Size = playerCount, + Max = maxPlayers + }, + Timestamps = Timestamps.Now + }); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при обновлении Discord RPC: {ex.Message}"); + } + } + + /// + /// Установить статус "Обновление игры" + /// + /// Прогресс обновления (0-100) + public void SetUpdatingState(int progress) + { + if (!isInitialized) return; + + try + { + client.SetPresence(new RichPresence() + { + Details = "Обновление игры", + State = $"Прогресс: {progress}%", + Assets = new Assets() + { + LargeImageKey = LARGE_IMAGE_KEY, + LargeImageText = "Owyx Launcher", + SmallImageKey = SMALL_IMAGE_KEY, + SmallImageText = "Minecraft" + }, + Timestamps = Timestamps.Now + }); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при обновлении Discord RPC: {ex.Message}"); + } + } + + /// + /// Установить статус "В настройках" + /// + public void SetSettingsState() + { + if (!isInitialized) return; + + try + { + client.SetPresence(new RichPresence() + { + Details = "Настраивает лаунчер", + State = "В меню настроек", + Assets = new Assets() + { + LargeImageKey = LARGE_IMAGE_KEY, + LargeImageText = "Owyx Launcher", + SmallImageKey = SMALL_IMAGE_KEY, + SmallImageText = "Minecraft" + }, + Timestamps = Timestamps.Now + }); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при обновлении Discord RPC: {ex.Message}"); + } + } + + /// + /// Очистить Discord Rich Presence + /// + public void ClearPresence() + { + if (!isInitialized) return; + + try + { + client.ClearPresence(); + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при очистке Discord RPC: {ex.Message}"); + } + } + + /// + /// Освобождение ресурсов + /// + public void Dispose() + { + if (client != null) + { + ClearPresence(); + client.Dispose(); + isInitialized = false; + } + } + } +} diff --git a/legacy/Launcher/legacy/csharp/FabricInstaller.cs b/legacy/Launcher/legacy/csharp/FabricInstaller.cs new file mode 100644 index 00000000000..57d49222fbf --- /dev/null +++ b/legacy/Launcher/legacy/csharp/FabricInstaller.cs @@ -0,0 +1,278 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Net.Http; +using System.Threading.Tasks; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + /// + /// Компонент для автоматической установки Fabric Mod Loader + /// + public class FabricInstaller : IDisposable + { + private readonly HttpClient httpClient; + private readonly string gameDirectory; + + // URLs для загрузки Fabric + private const string FABRIC_INSTALLER_URL = "https://maven.fabricmc.net/net/fabricmc/fabric-installer/1.0.1/fabric-installer-1.0.1.jar"; + private const string FABRIC_VERSIONS_API = "https://meta.fabricmc.net/v2/versions/loader"; + + public FabricInstaller(string gameDirectory) + { + this.gameDirectory = gameDirectory; + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromMinutes(5); + } + + /// + /// Проверить, установлен ли Fabric для указанной версии Minecraft + /// + /// Версия Minecraft (например, "1.20.1") + /// True если Fabric установлен + public bool IsFabricInstalled(string minecraftVersion) + { + try + { + var versionsDir = Path.Combine(gameDirectory, "versions"); + if (!Directory.Exists(versionsDir)) + return false; + + // Ищем папку с Fabric версией + var fabricVersionPattern = $"fabric-loader-*-{minecraftVersion}"; + var directories = Directory.GetDirectories(versionsDir, fabricVersionPattern); + + return directories.Length > 0; + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при проверке Fabric: {ex.Message}"); + return false; + } + } + + /// + /// Установить Fabric для указанной версии Minecraft + /// + /// Версия Minecraft (например, "1.20.1") + /// Путь к Java исполняемому файлу + /// Callback для отслеживания прогресса + /// True если установка успешна + public async Task InstallFabric(string minecraftVersion, string javaPath, Action? progressCallback = null) + { + try + { + progressCallback?.Invoke("Проверка Fabric..."); + + // Проверить, установлен ли уже + if (IsFabricInstalled(minecraftVersion)) + { + progressCallback?.Invoke("Fabric уже установлен"); + return true; + } + + progressCallback?.Invoke("Загрузка Fabric Installer..."); + + // Скачать Fabric Installer + var installerPath = await DownloadFabricInstaller(); + if (string.IsNullOrEmpty(installerPath)) + { + progressCallback?.Invoke("Ошибка загрузки Fabric Installer"); + return false; + } + + progressCallback?.Invoke("Установка Fabric..."); + + // Запустить установку Fabric + var success = await RunFabricInstaller(installerPath, minecraftVersion, javaPath, progressCallback); + + // Удалить временный файл установщика + try + { + if (File.Exists(installerPath)) + File.Delete(installerPath); + } + catch { } + + if (success) + { + progressCallback?.Invoke("Fabric успешно установлен!"); + } + else + { + progressCallback?.Invoke("Ошибка при установке Fabric"); + } + + return success; + } + catch (Exception ex) + { + progressCallback?.Invoke($"Ошибка: {ex.Message}"); + Console.WriteLine($"Ошибка при установке Fabric: {ex.Message}"); + return false; + } + } + + /// + /// Скачать Fabric Installer + /// + /// Путь к загруженному файлу + private async Task DownloadFabricInstaller() + { + try + { + var tempPath = Path.Combine(Path.GetTempPath(), "fabric-installer.jar"); + + // Если уже есть, использовать его + if (File.Exists(tempPath)) + { + var fileInfo = new FileInfo(tempPath); + // Если файл не старше 7 дней, использовать его + if ((DateTime.Now - fileInfo.LastWriteTime).TotalDays < 7) + return tempPath; + } + + // Скачать новый + var response = await httpClient.GetAsync(FABRIC_INSTALLER_URL); + response.EnsureSuccessStatusCode(); + + var content = await response.Content.ReadAsByteArrayAsync(); + await File.WriteAllBytesAsync(tempPath, content); + + return tempPath; + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при загрузке Fabric Installer: {ex.Message}"); + return string.Empty; + } + } + + /// + /// Запустить Fabric Installer + /// + /// Путь к fabric-installer.jar + /// Версия Minecraft + /// Путь к Java + /// Callback для прогресса + /// True если успешно + private async Task RunFabricInstaller(string installerPath, string minecraftVersion, + string javaPath, Action? progressCallback) + { + try + { + var startInfo = new ProcessStartInfo + { + FileName = javaPath, + Arguments = $"-jar \"{installerPath}\" client -mcversion {minecraftVersion} -dir \"{gameDirectory}\" -noprofile", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using var process = new Process { StartInfo = startInfo }; + + // Читать вывод в реальном времени + process.OutputDataReceived += (sender, e) => + { + if (!string.IsNullOrEmpty(e.Data)) + { + Console.WriteLine($"Fabric: {e.Data}"); + progressCallback?.Invoke(e.Data); + } + }; + + process.ErrorDataReceived += (sender, e) => + { + if (!string.IsNullOrEmpty(e.Data)) + { + Console.WriteLine($"Fabric Error: {e.Data}"); + } + }; + + process.Start(); + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + await process.WaitForExitAsync(); + + return process.ExitCode == 0; + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при запуске Fabric Installer: {ex.Message}"); + return false; + } + } + + /// + /// Получить название Fabric профиля для указанной версии Minecraft + /// + /// Версия Minecraft + /// Название профиля или null + public string? GetFabricProfileName(string minecraftVersion) + { + try + { + var versionsDir = Path.Combine(gameDirectory, "versions"); + if (!Directory.Exists(versionsDir)) + return null; + + var directories = Directory.GetDirectories(versionsDir, $"fabric-loader-*-{minecraftVersion}"); + + if (directories.Length > 0) + { + return Path.GetFileName(directories[0]); + } + + return null; + } + catch + { + return null; + } + } + + /// + /// Установить Fabric и обновить GameProfile + /// + /// Игровой профиль + /// Путь к Java + /// Callback для прогресса + /// True если успешно + public async Task InstallAndSetupFabric(GameProfile profile, string javaPath, + Action? progressCallback = null) + { + try + { + // Установить Fabric + var success = await InstallFabric(profile.MinecraftVersion, javaPath, progressCallback); + + if (success) + { + // Обновить профиль с Fabric версией + var fabricProfileName = GetFabricProfileName(profile.MinecraftVersion); + if (!string.IsNullOrEmpty(fabricProfileName)) + { + profile.MinecraftVersion = fabricProfileName; + progressCallback?.Invoke($"Профиль обновлен: {fabricProfileName}"); + } + } + + return success; + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при установке и настройке Fabric: {ex.Message}"); + return false; + } + } + + public void Dispose() + { + httpClient?.Dispose(); + } + } +} diff --git a/legacy/Launcher/legacy/csharp/GameUpdater.cs b/legacy/Launcher/legacy/csharp/GameUpdater.cs new file mode 100644 index 00000000000..f99cb145516 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/GameUpdater.cs @@ -0,0 +1,179 @@ +using System; +using System.IO; +using System.Net.Http; +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Threading.Tasks; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + public class GameUpdater : IDisposable + { + private readonly HttpClient httpClient; + private const string SERVER_VERSION_URL = "http://yourserver.com/api/version"; + + public GameUpdater() + { + httpClient = new HttpClient(); + httpClient.Timeout = TimeSpan.FromMinutes(5); + } + + /// + /// Получить информацию о версии с сервера + /// + /// Информация о сервере + public async Task GetServerVersion() + { + try + { + var response = await httpClient.GetAsync(SERVER_VERSION_URL); + response.EnsureSuccessStatusCode(); + + var jsonContent = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize(jsonContent); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при получении версии сервера: {ex.Message}"); + return null; + } + } + + /// + /// Загрузить файл с сервера + /// + /// URL файла + /// Путь для сохранения + /// Прогресс загрузки + public async Task DownloadFile(string url, string localPath, IProgress? progress = null) + { + try + { + // Создать директорию если не существует + var directory = Path.GetDirectoryName(localPath); + if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory)) + { + Directory.CreateDirectory(directory); + } + + using var response = await httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); + response.EnsureSuccessStatusCode(); + + var totalBytes = response.Content.Headers.ContentLength ?? -1L; + var downloadedBytes = 0L; + + using var contentStream = await response.Content.ReadAsStreamAsync(); + using var fileStream = new FileStream(localPath, FileMode.Create, FileAccess.Write, FileShare.None); + + var buffer = new byte[8192]; + int bytesRead; + + while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0) + { + await fileStream.WriteAsync(buffer, 0, bytesRead); + downloadedBytes += bytesRead; + + if (totalBytes > 0 && progress != null) + { + var percentage = (int)((downloadedBytes * 100) / totalBytes); + progress.Report(percentage); + } + } + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при загрузке файла {url}: {ex.Message}"); + throw; + } + } + + /// + /// Вычислить SHA256 хеш файла + /// + /// Путь к файлу + /// SHA256 хеш в виде строки + public string CalculateFileHash(string filePath) + { + try + { + if (!File.Exists(filePath)) + return string.Empty; + + using var sha256 = SHA256.Create(); + using var fileStream = File.OpenRead(filePath); + var hashBytes = sha256.ComputeHash(fileStream); + return Convert.ToHexString(hashBytes).ToLowerInvariant(); + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при вычислении хеша файла {filePath}: {ex.Message}"); + return string.Empty; + } + } + + /// + /// Проверить локальные файлы на соответствие серверным + /// + /// Информация о версии сервера + /// True если все файлы валидны + public async Task ValidateLocalFiles(ServerInfo serverInfo) + { + try + { + var gameDirectory = GetGameDirectory(); + + // Проверить файлы клиента + foreach (var file in serverInfo.ClientFiles) + { + var localPath = Path.Combine(gameDirectory, "versions", serverInfo.MinecraftVersion, file.Name); + if (!File.Exists(localPath)) + return false; + + var localHash = CalculateFileHash(localPath); + if (localHash != file.Hash.ToLowerInvariant()) + return false; + } + + // Проверить моды + foreach (var mod in serverInfo.Mods) + { + var localPath = Path.Combine(gameDirectory, "mods", mod.Name); + if (!File.Exists(localPath)) + return false; + + var localHash = CalculateFileHash(localPath); + if (localHash != mod.Hash.ToLowerInvariant()) + return false; + } + + return true; + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при проверке локальных файлов: {ex.Message}"); + return false; + } + } + + /// + /// Получить директорию игры + /// + /// Путь к директории игры + private string GetGameDirectory() + { + var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + return Path.Combine(appDataPath, ".owyxlauncher"); + } + + public void Dispose() + { + httpClient?.Dispose(); + } + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/JavaDetector.cs b/legacy/Launcher/legacy/csharp/JavaDetector.cs new file mode 100644 index 00000000000..9ec057c191d --- /dev/null +++ b/legacy/Launcher/legacy/csharp/JavaDetector.cs @@ -0,0 +1,263 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading.Tasks; + +namespace MinecraftLauncher +{ + /// + /// Класс для обнаружения установленных версий Java + /// + public class JavaDetector + { + public class JavaInstallation + { + public string Path { get; set; } = string.Empty; + public string Version { get; set; } = string.Empty; + public int MajorVersion { get; set; } + public bool Is64Bit { get; set; } + public string DisplayName => $"Java {Version} ({(Is64Bit ? "64-bit" : "32-bit")})"; + } + + /// + /// Найти все установленные версии Java + /// + public async Task> FindAllJavaInstallations() + { + var installations = new List(); + var foundPaths = new HashSet(); + + // Проверить JAVA_HOME + await CheckJavaHome(installations, foundPaths); + + // Проверить PATH + await CheckPathEnvironment(installations, foundPaths); + + // Проверить стандартные расположения + await CheckCommonLocations(installations, foundPaths); + + // Проверить реестр Windows + await CheckWindowsRegistry(installations, foundPaths); + + return installations.OrderByDescending(j => j.MajorVersion).ToList(); + } + + /// + /// Найти последнюю (самую новую) версию Java + /// + public async Task FindLatestJava() + { + var installations = await FindAllJavaInstallations(); + return installations.FirstOrDefault(); + } + + /// + /// Найти рекомендуемую версию Java для Minecraft + /// + public async Task FindRecommendedJava(string minecraftVersion = "") + { + var installations = await FindAllJavaInstallations(); + + // Для Minecraft 1.17+ рекомендуется Java 17 + // Для Minecraft 1.16 и ниже - Java 8 + var recommendedMajor = 17; + + // Попытаться найти рекомендуемую версию + var recommended = installations.FirstOrDefault(j => j.MajorVersion == recommendedMajor); + if (recommended != null) return recommended; + + // Если не найдена, взять последнюю совместимую + return installations.FirstOrDefault(j => j.MajorVersion >= 8); + } + + private async Task CheckJavaHome(List installations, HashSet foundPaths) + { + var javaHome = Environment.GetEnvironmentVariable("JAVA_HOME"); + if (!string.IsNullOrEmpty(javaHome)) + { + var javaBin = Path.Combine(javaHome, "bin", "java.exe"); + if (File.Exists(javaBin) && !foundPaths.Contains(javaBin)) + { + var info = await GetJavaInfo(javaBin); + if (info != null) + { + installations.Add(info); + foundPaths.Add(javaBin); + } + } + } + } + + private async Task CheckPathEnvironment(List installations, HashSet foundPaths) + { + var pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? Array.Empty(); + foreach (var dir in pathDirs) + { + if (string.IsNullOrEmpty(dir)) continue; + + var javaBin = Path.Combine(dir, "java.exe"); + if (File.Exists(javaBin) && !foundPaths.Contains(javaBin)) + { + var info = await GetJavaInfo(javaBin); + if (info != null) + { + installations.Add(info); + foundPaths.Add(javaBin); + } + } + } + } + + private async Task CheckCommonLocations(List installations, HashSet foundPaths) + { + var commonPaths = new[] + { + @"C:\Program Files\Java", + @"C:\Program Files (x86)\Java", + @"C:\Program Files\Eclipse Adoptium", + @"C:\Program Files\Eclipse Foundation", + @"C:\Program Files\Microsoft", + @"C:\Program Files\BellSoft", + @"C:\Program Files\Amazon Corretto", + @"C:\Program Files\Zulu", + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", "Eclipse Adoptium") + }; + + foreach (var basePath in commonPaths) + { + if (!Directory.Exists(basePath)) continue; + + try + { + var javaDirs = Directory.GetDirectories(basePath, "*", SearchOption.TopDirectoryOnly); + foreach (var javaDir in javaDirs) + { + var javaBin = Path.Combine(javaDir, "bin", "java.exe"); + if (File.Exists(javaBin) && !foundPaths.Contains(javaBin)) + { + var info = await GetJavaInfo(javaBin); + if (info != null) + { + installations.Add(info); + foundPaths.Add(javaBin); + } + } + } + } + catch + { + // Игнорировать ошибки доступа к директориям + } + } + } + + private async Task CheckWindowsRegistry(List installations, HashSet foundPaths) + { + try + { + // Проверить HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment + // Проверить HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Development Kit + // Это требует работы с реестром, что может быть ограничено правами + // Пока пропустим, так как основные методы уже покрывают большинство случаев + await Task.CompletedTask; + } + catch + { + // Игнорировать ошибки доступа к реестру + } + } + + /// + /// Получить информацию о версии Java + /// + private async Task GetJavaInfo(string javaPath) + { + try + { + var startInfo = new ProcessStartInfo + { + FileName = javaPath, + Arguments = "-version", + UseShellExecute = false, + RedirectStandardError = true, + RedirectStandardOutput = true, + CreateNoWindow = true + }; + + using var process = Process.Start(startInfo); + if (process == null) return null; + + var output = await process.StandardError.ReadToEndAsync(); + output += await process.StandardOutput.ReadToEndAsync(); + + await process.WaitForExitAsync(); + + if (string.IsNullOrEmpty(output)) return null; + + // Парсинг версии из вывода + // Формат: java version "1.8.0_XXX" или openjdk version "17.0.X" + var version = ParseJavaVersion(output); + if (string.IsNullOrEmpty(version)) return null; + + var majorVersion = GetMajorVersion(version); + var is64Bit = output.Contains("64-Bit") || output.Contains("64-bit"); + + return new JavaInstallation + { + Path = javaPath, + Version = version, + MajorVersion = majorVersion, + Is64Bit = is64Bit + }; + } + catch + { + return null; + } + } + + private string ParseJavaVersion(string output) + { + // Ищем строку с версией + var lines = output.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var line in lines) + { + if (line.Contains("version")) + { + var start = line.IndexOf('"'); + var end = line.LastIndexOf('"'); + if (start >= 0 && end > start) + { + return line.Substring(start + 1, end - start - 1); + } + } + } + return string.Empty; + } + + private int GetMajorVersion(string version) + { + try + { + // Для версий типа "1.8.0_XXX" major version = 8 + // Для версий типа "17.0.X" major version = 17 + var parts = version.Split('.'); + if (parts.Length > 0) + { + if (parts[0] == "1" && parts.Length > 1) + { + return int.Parse(parts[1].Split('_')[0]); + } + return int.Parse(parts[0]); + } + } + catch + { + // Игнорировать ошибки парсинга + } + return 0; + } + } +} diff --git a/legacy/Launcher/legacy/csharp/Logger.cs b/legacy/Launcher/legacy/csharp/Logger.cs new file mode 100644 index 00000000000..33504ae0abf --- /dev/null +++ b/legacy/Launcher/legacy/csharp/Logger.cs @@ -0,0 +1,180 @@ +using System; +using System.IO; +using System.Text; + +namespace MinecraftLauncher +{ + /// + /// Компонент для записи логов лаунчера + /// + public class Logger + { + private readonly string logDirectory; + private readonly string currentLogFile; + private static Logger instance; + private readonly object lockObject = new object(); + + public enum LogLevel + { + Info, + Warning, + Error, + Debug + } + + private Logger(string gameDirectory) + { + logDirectory = Path.Combine(gameDirectory, "logs"); + Directory.CreateDirectory(logDirectory); + + // Создать файл лога с датой и временем + var timestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss"); + currentLogFile = Path.Combine(logDirectory, $"launcher_{timestamp}.log"); + + // Записать заголовок + WriteToFile($"=================================================="); + WriteToFile($"Owyx Launcher - Log Started at {DateTime.Now:yyyy-MM-dd HH:mm:ss}"); + WriteToFile($"=================================================="); + } + + /// + /// Получить экземпляр логгера (Singleton) + /// + public static Logger GetInstance(string gameDirectory) + { + if (instance == null) + { + instance = new Logger(gameDirectory); + } + return instance; + } + + /// + /// Записать информационное сообщение + /// + public void Info(string message) + { + Log(LogLevel.Info, message); + } + + /// + /// Записать предупреждение + /// + public void Warning(string message) + { + Log(LogLevel.Warning, message); + } + + /// + /// Записать ошибку + /// + public void Error(string message, Exception ex = null) + { + var fullMessage = message; + if (ex != null) + { + fullMessage += $"\nException: {ex.GetType().Name}\nMessage: {ex.Message}\nStackTrace:\n{ex.StackTrace}"; + } + Log(LogLevel.Error, fullMessage); + } + + /// + /// Записать отладочное сообщение + /// + public void Debug(string message) + { + Log(LogLevel.Debug, message); + } + + /// + /// Основной метод логирования + /// + private void Log(LogLevel level, string message) + { + try + { + var timestamp = DateTime.Now.ToString("HH:mm:ss.fff"); + var levelString = level.ToString().ToUpper().PadRight(7); + var logMessage = $"[{timestamp}] [{levelString}] {message}"; + + // Записать в файл (thread-safe) + WriteToFile(logMessage); + + // Также вывести в консоль (если запущено в режиме отладки) + Console.WriteLine(logMessage); + } + catch (Exception ex) + { + // Если не удалось записать лог, вывести в консоль + Console.WriteLine($"Failed to write log: {ex.Message}"); + } + } + + /// + /// Записать строку в файл (thread-safe) + /// + private void WriteToFile(string message) + { + lock (lockObject) + { + try + { + File.AppendAllText(currentLogFile, message + Environment.NewLine, Encoding.UTF8); + } + catch + { + // Игнорировать ошибки записи лога + } + } + } + + /// + /// Очистить старые логи (оставить только последние N дней) + /// + public void CleanOldLogs(int daysToKeep = 7) + { + try + { + var files = Directory.GetFiles(logDirectory, "launcher_*.log"); + var cutoffDate = DateTime.Now.AddDays(-daysToKeep); + + foreach (var file in files) + { + var fileInfo = new FileInfo(file); + if (fileInfo.LastWriteTime < cutoffDate) + { + File.Delete(file); + Info($"Deleted old log file: {Path.GetFileName(file)}"); + } + } + } + catch (Exception ex) + { + Error("Failed to clean old logs", ex); + } + } + + /// + /// Получить путь к текущему файлу лога + /// + public string GetCurrentLogFile() + { + return currentLogFile; + } + + /// + /// Получить все файлы логов + /// + public string[] GetAllLogFiles() + { + try + { + return Directory.GetFiles(logDirectory, "launcher_*.log"); + } + catch + { + return Array.Empty(); + } + } + } +} diff --git a/legacy/Launcher/legacy/csharp/MainForm.cs b/legacy/Launcher/legacy/csharp/MainForm.cs new file mode 100644 index 00000000000..d87965dc96a --- /dev/null +++ b/legacy/Launcher/legacy/csharp/MainForm.cs @@ -0,0 +1,371 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using System.Windows.Forms; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + public partial class MainForm : Form + { + private GameUpdater updater; + private MinecraftStarter starter; + private ConfigManager configManager; + private ServerStatusChecker serverChecker; + private DiscordRPCManager discordRPC; + private Logger logger; + private ModDownloader modDownloader; + private bool isUpdating = false; + private CustomTitleBar titleBar; + private SettingsPanel settingsPanel; + private System.Windows.Forms.Timer serverRefreshTimer; + + private const string SERVER_ADDRESS = "play.chiwawa.site"; + private const int SERVER_PORT = 32062; + + // SFTP настройки для модов + private const string SFTP_HOST = "192.168.1.52"; + private const int SFTP_PORT = 22; + private const string SFTP_USERNAME = "root"; + private const string SFTP_PASSWORD = ""; // stripped — use env/secrets, never commit + private const string SFTP_MODS_PATH = "/opt/MCMods/mods"; + + public MainForm() + { + InitializeComponent(); + InitializeServices(); + SetupForm(); + } + + /// + /// Инициализация сервисов + /// + private void InitializeServices() + { + updater = new GameUpdater(); + starter = new MinecraftStarter(); + configManager = new ConfigManager(); + serverChecker = new ServerStatusChecker(SERVER_ADDRESS, SERVER_PORT); + discordRPC = new DiscordRPCManager(); + + // Инициализировать Logger + var gameDirectory = configManager.GetGameDirectory(); + logger = Logger.GetInstance(gameDirectory); + logger.Info("=== Owyx Launcher Started ==="); + logger.CleanOldLogs(7); // Удалить логи старше 7 дней + + // Инициализировать ModDownloader для SFTP + modDownloader = new ModDownloader(SFTP_HOST, SFTP_PORT, SFTP_USERNAME, SFTP_PASSWORD, SFTP_MODS_PATH, logger); + logger.Info($"ModDownloader initialized for SFTP: {SFTP_HOST}:{SFTP_PORT}"); + + // Таймер для авто-обновления сервера каждую минуту + serverRefreshTimer = new System.Windows.Forms.Timer(); + serverRefreshTimer.Interval = 60000; // 60 секунд + serverRefreshTimer.Tick += async (sender, e) => await RefreshServerStatus(); + } + + /// + /// Настройка формы + /// + private async void SetupForm() + { + // Добавить CustomTitleBar + titleBar = new CustomTitleBar(this); + titleBar.Location = new System.Drawing.Point(0, 0); + this.Controls.Add(titleBar); + titleBar.BringToFront(); + + // Загрузить профиль и создать SettingsPanel + var profile = await configManager.LoadGameProfile(); + settingsPanel = new SettingsPanel(configManager, profile); + settingsPanel.Visible = false; + settingsPanel.Location = new System.Drawing.Point(0, 40); // Под title bar + settingsPanel.Size = new System.Drawing.Size(this.ClientSize.Width, this.ClientSize.Height - 40); + settingsPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + this.Controls.Add(settingsPanel); + settingsPanel.BringToFront(); + + // Form properties are now set in Designer + // Just set initial status + statusLabel.Text = "Готово к игре"; + statusDetailLabel.Text = ""; + progressBar.Value = 0; + + // Автоматическая проверка статуса сервера при запуске + await RefreshServerStatus(); + + // Запустить таймер авто-обновления + serverRefreshTimer.Start(); + } + + /// + /// Обновить статус сервера + /// + private async Task RefreshServerStatus() + { + try + { + refreshServerButton.Enabled = false; + serverOnlineLabel.Text = "👥 Проверка..."; + serverVersionLabel.Text = "📦 Версия: Загрузка..."; + serverPingLabel.Text = "📡 Пинг: -- ms"; + logger.Debug("Refreshing server status..."); + + var status = await serverChecker.GetServerStatus(); + + if (status.IsOnline) + { + serverOnlineLabel.Text = $"👥 Онлайн: {status.OnlinePlayers}/{status.MaxPlayers}"; + serverOnlineLabel.ForeColor = System.Drawing.Color.FromArgb(100, 200, 100); + serverVersionLabel.Text = $"📦 Версия: {status.Version}"; + serverPingLabel.Text = $"📡 Пинг: {status.Ping} ms"; + logger.Info($"Server online: {status.OnlinePlayers}/{status.MaxPlayers}, Version: {status.Version}, Ping: {status.Ping}ms"); + + // Обновить Discord RPC с информацией о сервере + discordRPC?.SetPlayingState("ChiwawaMine", status.OnlinePlayers, status.MaxPlayers); + } + else + { + serverOnlineLabel.Text = "❌ Сервер оффлайн"; + serverOnlineLabel.ForeColor = System.Drawing.Color.FromArgb(200, 100, 100); + serverVersionLabel.Text = "📦 Версия: Недоступно"; + serverPingLabel.Text = "📡 Пинг: -- ms"; + logger.Warning("Server is offline"); + } + } + catch (Exception ex) + { + serverOnlineLabel.Text = "⚠️ Ошибка проверки"; + serverOnlineLabel.ForeColor = System.Drawing.Color.FromArgb(200, 150, 100); + logger.Error("Failed to check server status", ex); + Console.WriteLine($"Ошибка при проверке статуса сервера: {ex.Message}"); + } + finally + { + refreshServerButton.Enabled = true; + } + } + + /// + /// Обработчик кнопки обновления статуса + /// + private async void RefreshServerButton_Click(object sender, EventArgs e) + { + await RefreshServerStatus(); + } + + /// + /// Обработчик нажатия кнопки "Играть" + /// + private async void PlayButton_Click(object sender, EventArgs e) + { + if (isUpdating) return; + + try + { + isUpdating = true; + playButton.Enabled = false; + playButton.Text = "Обновление..."; + logger.Info("Play button clicked - starting game launch sequence"); + + await CheckForUpdates(); + + // Загрузить профиль и запустить игру + UpdateDetailedStatus("Загрузка профиля игры..."); + var profile = await configManager.LoadGameProfile(); + logger.Info($"Game profile loaded: {profile.Name}, Version: {profile.MinecraftVersion}"); + + UpdateDetailedStatus("Запуск Minecraft..."); + var success = await starter.StartMinecraft(profile); + + if (success) + { + UpdateProgress(100, "Игра запущена!"); + UpdateDetailedStatus("Minecraft успешно запущен"); + logger.Info("Minecraft started successfully"); + + // Обновить Discord RPC - игрок в игре + var serverStatus = await serverChecker.GetServerStatus(); + if (serverStatus.IsOnline) + { + discordRPC?.SetPlayingState("ChiwawaMine", serverStatus.OnlinePlayers, serverStatus.MaxPlayers); + } + + this.WindowState = FormWindowState.Minimized; + } + else + { + UpdateProgress(0, "Ошибка при запуске игры"); + UpdateDetailedStatus("Не удалось запустить Minecraft"); + logger.Error("Failed to start Minecraft"); + } + } + catch (Exception ex) + { + UpdateProgress(0, $"Ошибка: {ex.Message}"); + UpdateDetailedStatus("Критическая ошибка при запуске"); + logger.Error("Exception during game launch", ex); + MessageBox.Show($"Ошибка при запуске игры:\n{ex.Message}", "Ошибка", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + finally + { + isUpdating = false; + playButton.Enabled = true; + playButton.Text = "⚡ ИГРАТЬ"; + } + } + + /// + /// Обработчик кнопки настроек + /// + private async void SettingsButton_Click(object sender, EventArgs e) + { + try + { + // Показать/скрыть панель настроек + settingsPanel.Visible = !settingsPanel.Visible; + if (settingsPanel.Visible) + { + settingsPanel.BringToFront(); + settingsButton.Text = "❌ Закрыть настройки"; + discordRPC?.SetSettingsState(); + } + else + { + settingsButton.Text = "⚙️ Настройки"; + discordRPC?.SetIdleState(); + } + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка при открытии настроек:\n{ex.Message}", "Ошибка", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Обработчик кнопки открытия папки + /// + private void OpenFolderButton_Click(object sender, EventArgs e) + { + try + { + var gameDirectory = configManager.GetGameDirectory(); + + if (!Directory.Exists(gameDirectory)) + { + Directory.CreateDirectory(gameDirectory); + } + + Process.Start(new ProcessStartInfo + { + FileName = gameDirectory, + UseShellExecute = true, + Verb = "open" + }); + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка при открытии папки:\n{ex.Message}", "Ошибка", + MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + /// + /// Проверка обновлений + /// + private async Task CheckForUpdates() + { + UpdateProgress(10, "Проверка версии..."); + UpdateDetailedStatus("Подключение к серверу обновлений..."); + logger.Info("Starting update check"); + + var profile = await configManager.LoadGameProfile(); + var minecraftVersion = profile.MinecraftVersion; + + UpdateProgress(30, "Проверка локальных файлов..."); + UpdateDetailedStatus("Сканирование установленных файлов..."); + logger.Info($"Minecraft version: {minecraftVersion}"); + + // Скачать моды через SFTP + UpdateProgress(50, "Загрузка модов..."); + UpdateDetailedStatus("Подключение к серверу модов через SFTP..."); + logger.Info("Starting mod download"); + + var gameDirectory = configManager.GetGameDirectory(); + var modsPath = Path.Combine(gameDirectory, "mods"); + + var modDownloadSuccess = await modDownloader.DownloadModsForVersion( + minecraftVersion, + modsPath, + (message, progress) => + { + var totalProgress = 50 + (progress * 40 / 100); + UpdateProgress(totalProgress, "Загрузка модов..."); + UpdateDetailedStatus(message); + }); + + if (!modDownloadSuccess) + { + logger.Warning("Mod download failed, continuing anyway"); + UpdateDetailedStatus("Не удалось скачать моды (продолжаем без них)"); + } + + UpdateProgress(100, "Готово к игре"); + UpdateDetailedStatus("Все файлы актуальны"); + logger.Info("Update check completed"); + } + + /// + /// Обновление прогресса и статуса + /// + /// Процент выполнения + /// Статус операции + private void UpdateProgress(int percentage, string status) + { + if (InvokeRequired) + { + Invoke(new Action(UpdateProgress), percentage, status); + return; + } + + progressBar.Value = Math.Min(Math.Max(percentage, 0), 100); + statusLabel.Text = status; + logger?.Info($"Progress: {percentage}% - {status}"); + } + + /// + /// Обновление детального статуса (под прогресс-баром) + /// + /// Детальное описание + private void UpdateDetailedStatus(string detail) + { + if (InvokeRequired) + { + Invoke(new Action(UpdateDetailedStatus), detail); + return; + } + + statusDetailLabel.Text = detail; + logger?.Debug($"Detail: {detail}"); + } + + /// + /// Освобождение ресурсов + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + components?.Dispose(); + updater?.Dispose(); + discordRPC?.Dispose(); + serverRefreshTimer?.Dispose(); + logger?.Info("=== Owyx Launcher Closed ==="); + } + base.Dispose(disposing); + } + } +} diff --git a/legacy/Launcher/legacy/csharp/MinecraftStarter.cs b/legacy/Launcher/legacy/csharp/MinecraftStarter.cs new file mode 100644 index 00000000000..259fdec16e0 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/MinecraftStarter.cs @@ -0,0 +1,205 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + public class MinecraftStarter + { + /// + /// Запустить Minecraft с указанным профилем + /// + /// Профиль игры + /// True если запуск прошел успешно + public async Task StartMinecraft(GameProfile profile) + { + try + { + var javaPath = await FindJavaPath(); + if (string.IsNullOrEmpty(javaPath)) + { + throw new Exception("Java не найдена на системе"); + } + + var gameDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ".owyxlauncher"); + var minecraftJar = Path.Combine(gameDirectory, "versions", profile.MinecraftVersion, $"minecraft-{profile.MinecraftVersion}.jar"); + + if (!File.Exists(minecraftJar)) + { + throw new Exception($"Файл Minecraft не найден: {minecraftJar}"); + } + + var arguments = BuildMinecraftArguments(profile, gameDirectory, minecraftJar); + + var processStartInfo = new ProcessStartInfo + { + FileName = javaPath, + Arguments = arguments, + WorkingDirectory = gameDirectory, + UseShellExecute = false, + CreateNoWindow = false + }; + + using var process = Process.Start(processStartInfo); + + // TODO: Мониторинг процесса + return process != null; + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при запуске Minecraft: {ex.Message}"); + return false; + } + } + + /// + /// Найти путь к Java на системе + /// + /// Путь к java.exe или null если не найдена + private async Task FindJavaPath() + { + try + { + // Проверить JAVA_HOME + var javaHome = Environment.GetEnvironmentVariable("JAVA_HOME"); + if (!string.IsNullOrEmpty(javaHome)) + { + var javaBin = Path.Combine(javaHome, "bin", "java.exe"); + if (File.Exists(javaBin)) + return javaBin; + } + + // Проверить PATH + var pathDirs = Environment.GetEnvironmentVariable("PATH")?.Split(';') ?? Array.Empty(); + foreach (var dir in pathDirs) + { + if (string.IsNullOrEmpty(dir)) continue; + + var javaBin = Path.Combine(dir, "java.exe"); + if (File.Exists(javaBin)) + return javaBin; + } + + // Проверить стандартные расположения + var commonPaths = new[] + { + @"C:\Program Files\Java\", + @"C:\Program Files (x86)\Java\", + @"C:\Program Files\Eclipse Adoptium\", + @"C:\Program Files\Microsoft\jdk-" + }; + + foreach (var basePath in commonPaths) + { + if (!Directory.Exists(basePath)) continue; + + var javaDirs = Directory.GetDirectories(basePath); + foreach (var javaDir in javaDirs) + { + var javaBin = Path.Combine(javaDir, "bin", "java.exe"); + if (File.Exists(javaBin)) + return javaBin; + } + } + + return null; + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при поиске Java: {ex.Message}"); + return null; + } + } + + /// + /// Построить аргументы командной строки для запуска Minecraft + /// + /// Профиль игры + /// Директория игры + /// Путь к jar файлу Minecraft + /// Строка аргументов + private string BuildMinecraftArguments(GameProfile profile, string gameDirectory, string minecraftJar) + { + var args = new List(); + + // JVM аргументы + args.Add("-Xmx2G"); // Максимальная память + args.Add("-Xms1G"); // Начальная память + args.Add($"-Djava.library.path={Path.Combine(gameDirectory, "versions", profile.MinecraftVersion, "natives")}"); + args.Add($"-cp \"{minecraftJar}\""); + + // Главный класс Minecraft + args.Add("net.minecraft.client.main.Main"); + + // Minecraft аргументы + args.Add($"--gameDir \"{gameDirectory}\""); + args.Add($"--assetsDir \"{Path.Combine(gameDirectory, "assets")}\""); + args.Add($"--version \"{profile.MinecraftVersion}\""); + args.Add("--username Player"); + args.Add("--uuid 00000000-0000-0000-0000-000000000000"); + args.Add("--accessToken null"); + args.Add("--userType offline"); + + return string.Join(" ", args); + } + + /// + /// Проверить доступность Java + /// + /// True если Java доступна + public async Task IsJavaAvailable() + { + var javaPath = await FindJavaPath(); + return !string.IsNullOrEmpty(javaPath); + } + + /// + /// Получить версию Java + /// + /// Версия Java или null + public async Task GetJavaVersion() + { + try + { + var javaPath = await FindJavaPath(); + if (string.IsNullOrEmpty(javaPath)) + return null; + + var processStartInfo = new ProcessStartInfo + { + FileName = javaPath, + Arguments = "-version", + UseShellExecute = false, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using var process = Process.Start(processStartInfo); + if (process == null) return null; + + var output = await process.StandardError.ReadToEndAsync(); + await process.WaitForExitAsync(); + + // Парсинг версии из вывода + var lines = output.Split('\n'); + if (lines.Length > 0) + { + return lines[0].Trim(); + } + + return null; + } + catch (Exception ex) + { + // TODO: Логирование ошибки + Console.WriteLine($"Ошибка при получении версии Java: {ex.Message}"); + return null; + } + } + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/ModDownloader.cs b/legacy/Launcher/legacy/csharp/ModDownloader.cs new file mode 100644 index 00000000000..743c488149f --- /dev/null +++ b/legacy/Launcher/legacy/csharp/ModDownloader.cs @@ -0,0 +1,261 @@ +using System; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using System.Collections.Generic; +using Renci.SshNet; +using Renci.SshNet.Sftp; + +namespace MinecraftLauncher +{ + /// + /// Компонент для скачивания модов через SFTP + /// + public class ModDownloader : IDisposable + { + private readonly string sftpHost; + private readonly int sftpPort; + private readonly string sftpUsername; + private readonly string sftpPassword; + private readonly string remoteModsPath; + private Logger logger; + + public ModDownloader(string host, int port, string username, string password, string remotePath, Logger logger) + { + sftpHost = host; + sftpPort = port; + sftpUsername = username; + sftpPassword = password; + remoteModsPath = remotePath; + this.logger = logger; + } + + /// + /// Скачать все моды для указанной версии Minecraft + /// + /// Версия Minecraft (например, "1.20.1") + /// Локальная папка для модов + /// Callback для прогресса + /// True если успешно + public async Task DownloadModsForVersion(string minecraftVersion, string localModsPath, + Action? progressCallback = null) + { + try + { + logger?.Info($"Starting mod download for Minecraft {minecraftVersion}"); + progressCallback?.Invoke("Подключение к серверу модов...", 0); + + // Создаем ConnectionInfo с несколькими методами аутентификации + var connectionInfo = new Renci.SshNet.ConnectionInfo(sftpHost, sftpPort, sftpUsername, + new Renci.SshNet.PasswordAuthenticationMethod(sftpUsername, sftpPassword), + new Renci.SshNet.KeyboardInteractiveAuthenticationMethod(sftpUsername)); + + // Обработчик для keyboard-interactive + var keyboardAuth = connectionInfo.AuthenticationMethods.OfType().FirstOrDefault(); + if (keyboardAuth != null) + { + keyboardAuth.AuthenticationPrompt += (sender, e) => + { + foreach (var prompt in e.Prompts) + { + if (prompt.Request.IndexOf("Password", StringComparison.InvariantCultureIgnoreCase) != -1) + { + prompt.Response = sftpPassword; + } + } + }; + } + + using var client = new SftpClient(connectionInfo); + + await Task.Run(() => client.Connect()); + + if (!client.IsConnected) + { + logger?.Error("Failed to connect to SFTP server"); + progressCallback?.Invoke("Ошибка подключения к серверу", 0); + return false; + } + + logger?.Info($"Connected to SFTP server {sftpHost}:{sftpPort}"); + progressCallback?.Invoke("Получение списка модов...", 10); + + // Путь к модам для конкретной версии + var versionPath = $"{remoteModsPath}/{minecraftVersion}"; + + if (!client.Exists(versionPath)) + { + logger?.Warning($"Mods directory not found: {versionPath}"); + progressCallback?.Invoke($"Моды для версии {minecraftVersion} не найдены", 0); + return false; + } + + // Получить список модов + var files = client.ListDirectory(versionPath); + var modFiles = new List(); + + foreach (var file in files) + { + if (file.IsRegularFile && file.Name.EndsWith(".jar")) + { + modFiles.Add(file); + } + } + + if (modFiles.Count == 0) + { + logger?.Info("No mods found for this version"); + progressCallback?.Invoke("Моды не найдены", 100); + return true; + } + + logger?.Info($"Found {modFiles.Count} mods to download"); + progressCallback?.Invoke($"Найдено {modFiles.Count} модов", 20); + + // Создать локальную папку модов + Directory.CreateDirectory(localModsPath); + + // Очистить старые моды (опционально) + CleanOldMods(localModsPath); + + // Скачать каждый мод + int downloaded = 0; + foreach (var modFile in modFiles) + { + var localFilePath = Path.Combine(localModsPath, modFile.Name); + + // Проверить, нужно ли скачивать (сравнить размер) + if (File.Exists(localFilePath)) + { + var localFileInfo = new FileInfo(localFilePath); + if (localFileInfo.Length == modFile.Length) + { + logger?.Debug($"Skipping {modFile.Name} (already exists)"); + downloaded++; + continue; + } + } + + progressCallback?.Invoke($"Скачивание {modFile.Name}...", 20 + (downloaded * 70 / modFiles.Count)); + logger?.Info($"Downloading {modFile.Name} ({modFile.Length / 1024 / 1024:F2} MB)"); + + await Task.Run(() => + { + using var fileStream = File.Create(localFilePath); + client.DownloadFile(modFile.FullName, fileStream); + }); + + downloaded++; + logger?.Info($"Downloaded {modFile.Name}"); + } + + client.Disconnect(); + + progressCallback?.Invoke($"Скачано {downloaded} модов", 100); + logger?.Info($"Successfully downloaded {downloaded} mods"); + return true; + } + catch (Exception ex) + { + logger?.Error("Failed to download mods via SFTP", ex); + progressCallback?.Invoke($"Ошибка: {ex.Message}", 0); + return false; + } + } + + /// + /// Получить список доступных версий Minecraft с модами + /// + public async Task> GetAvailableVersions() + { + var versions = new List(); + + try + { + using var client = new SftpClient(sftpHost, sftpPort, sftpUsername, sftpPassword); + await Task.Run(() => client.Connect()); + + if (!client.IsConnected) return versions; + + if (!client.Exists(remoteModsPath)) return versions; + + var directories = client.ListDirectory(remoteModsPath); + + foreach (var dir in directories) + { + if (dir.IsDirectory && !dir.Name.StartsWith(".")) + { + versions.Add(dir.Name); + } + } + + client.Disconnect(); + logger?.Info($"Found {versions.Count} available mod versions"); + } + catch (Exception ex) + { + logger?.Error("Failed to get available versions", ex); + } + + return versions; + } + + /// + /// Проверить подключение к SFTP серверу + /// + public async Task TestConnection() + { + try + { + using var client = new SftpClient(sftpHost, sftpPort, sftpUsername, sftpPassword); + await Task.Run(() => client.Connect()); + + var connected = client.IsConnected; + + if (connected) + { + client.Disconnect(); + logger?.Info("SFTP connection test successful"); + } + else + { + logger?.Error("SFTP connection test failed"); + } + + return connected; + } + catch (Exception ex) + { + logger?.Error("SFTP connection test failed", ex); + return false; + } + } + + /// + /// Очистить старые моды из папки + /// + private void CleanOldMods(string modsPath) + { + try + { + if (!Directory.Exists(modsPath)) return; + + var files = Directory.GetFiles(modsPath, "*.jar"); + foreach (var file in files) + { + File.Delete(file); + logger?.Debug($"Deleted old mod: {Path.GetFileName(file)}"); + } + } + catch (Exception ex) + { + logger?.Warning($"Failed to clean old mods: {ex.Message}"); + } + } + + public void Dispose() + { + // Cleanup if needed + } + } +} diff --git a/legacy/Launcher/legacy/csharp/Models/GameProfile.cs b/legacy/Launcher/legacy/csharp/Models/GameProfile.cs new file mode 100644 index 00000000000..7908dd94980 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/Models/GameProfile.cs @@ -0,0 +1,24 @@ +using System; + +namespace MinecraftLauncher.Models +{ + public class GameProfile + { + public string Name { get; set; } = string.Empty; + public string GameDirectory { get; set; } = string.Empty; + public string MinecraftVersion { get; set; } = string.Empty; + public string JavaPath { get; set; } = string.Empty; + public string LauncherVersion { get; set; } = "1.0.1"; + public DateTime LastUsed { get; set; } = DateTime.Now; + public bool IsDefault { get; set; } = true; + + // Расширенные настройки + public int AllocatedMemoryMB { get; set; } = 2048; // 2GB по умолчанию + public string JvmArguments { get; set; } = string.Empty; + public string GameArguments { get; set; } = string.Empty; + public bool AutoDetectJava { get; set; } = true; + public int WindowWidth { get; set; } = 854; + public int WindowHeight { get; set; } = 480; + public bool Fullscreen { get; set; } = false; + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/Models/ServerInfo.cs b/legacy/Launcher/legacy/csharp/Models/ServerInfo.cs new file mode 100644 index 00000000000..5a8c508393d --- /dev/null +++ b/legacy/Launcher/legacy/csharp/Models/ServerInfo.cs @@ -0,0 +1,44 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MinecraftLauncher.Models +{ + public class ServerInfo + { + [JsonPropertyName("minecraft_version")] + public string MinecraftVersion { get; set; } = string.Empty; + + [JsonPropertyName("mods_hash")] + public string ModsHash { get; set; } = string.Empty; + + [JsonPropertyName("client_files")] + public List ClientFiles { get; set; } = new List(); + + [JsonPropertyName("mods")] + public List Mods { get; set; } = new List(); + } + + public class ClientFile + { + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; + + [JsonPropertyName("hash")] + public string Hash { get; set; } = string.Empty; + } + + public class ModFile + { + [JsonPropertyName("name")] + public string Name { get; set; } = string.Empty; + + [JsonPropertyName("url")] + public string Url { get; set; } = string.Empty; + + [JsonPropertyName("hash")] + public string Hash { get; set; } = string.Empty; + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/Program.cs b/legacy/Launcher/legacy/csharp/Program.cs new file mode 100644 index 00000000000..214b59c7588 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/Program.cs @@ -0,0 +1,20 @@ +using System; +using System.Windows.Forms; + +namespace MinecraftLauncher +{ + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } + } +} \ No newline at end of file diff --git a/legacy/Launcher/legacy/csharp/ServerStatusChecker.cs b/legacy/Launcher/legacy/csharp/ServerStatusChecker.cs new file mode 100644 index 00000000000..0b4d132f376 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/ServerStatusChecker.cs @@ -0,0 +1,256 @@ +using System; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; +using System.IO; +using System.Text.Json; + +namespace MinecraftLauncher +{ + /// + /// Класс для проверки статуса Minecraft сервера + /// + public class ServerStatusChecker + { + public class ServerStatus + { + public bool IsOnline { get; set; } + public int OnlinePlayers { get; set; } + public int MaxPlayers { get; set; } + public string Version { get; set; } = string.Empty; + public string Description { get; set; } = string.Empty; + public string Protocol { get; set; } = string.Empty; + public int Ping { get; set; } + } + + private readonly string serverAddress; + private readonly int serverPort; + + public ServerStatusChecker(string address, int port = 25565) + { + serverAddress = address; + serverPort = port; + } + + /// + /// Получить статус сервера + /// + public async Task GetServerStatus() + { + var status = new ServerStatus { IsOnline = false }; + + try + { + var startTime = DateTime.Now; + + using var client = new TcpClient(); + var connectTask = client.ConnectAsync(serverAddress, serverPort); + + // Таймаут 5 секунд + if (await Task.WhenAny(connectTask, Task.Delay(5000)) != connectTask) + { + return status; + } + + if (!client.Connected) + { + return status; + } + + using var stream = client.GetStream(); + + // Отправить handshake packet + await SendHandshake(stream); + + // Отправить status request + await SendStatusRequest(stream); + + // Прочитать ответ + var response = await ReadResponse(stream); + + var ping = (int)(DateTime.Now - startTime).TotalMilliseconds; + + if (!string.IsNullOrEmpty(response)) + { + status = ParseServerResponse(response); + status.Ping = ping; + } + + return status; + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при проверке статуса сервера: {ex.Message}"); + return status; + } + } + + private async Task SendHandshake(NetworkStream stream) + { + using var ms = new MemoryStream(); + using var writer = new BinaryWriter(ms); + + // Packet ID (0x00 для handshake) + WriteVarInt(writer, 0x00); + + // Protocol version (-1 для status ping) + WriteVarInt(writer, -1); + + // Server address + WriteVarInt(writer, serverAddress.Length); + writer.Write(Encoding.UTF8.GetBytes(serverAddress)); + + // Server port + writer.Write((byte)(serverPort >> 8)); + writer.Write((byte)(serverPort & 0xFF)); + + // Next state (1 для status) + WriteVarInt(writer, 1); + + var packet = ms.ToArray(); + + // Отправить длину пакета + using var packetStream = new MemoryStream(); + using var packetWriter = new BinaryWriter(packetStream); + WriteVarInt(packetWriter, packet.Length); + packetWriter.Write(packet); + + var finalPacket = packetStream.ToArray(); + await stream.WriteAsync(finalPacket, 0, finalPacket.Length); + } + + private async Task SendStatusRequest(NetworkStream stream) + { + // Status request - просто packet ID 0x00 с длиной 1 + var packet = new byte[] { 0x01, 0x00 }; + await stream.WriteAsync(packet, 0, packet.Length); + } + + private async Task ReadResponse(NetworkStream stream) + { + // Читаем длину пакета + var length = await ReadVarInt(stream); + if (length <= 0) return string.Empty; + + // Читаем packet ID + var packetId = await ReadVarInt(stream); + if (packetId != 0x00) return string.Empty; + + // Читаем длину JSON строки + var jsonLength = await ReadVarInt(stream); + if (jsonLength <= 0) return string.Empty; + + // Читаем JSON данные + var buffer = new byte[jsonLength]; + var totalRead = 0; + while (totalRead < jsonLength) + { + var read = await stream.ReadAsync(buffer, totalRead, jsonLength - totalRead); + if (read == 0) break; + totalRead += read; + } + + return Encoding.UTF8.GetString(buffer, 0, totalRead); + } + + private void WriteVarInt(BinaryWriter writer, int value) + { + uint unsigned = (uint)value; + do + { + byte temp = (byte)(unsigned & 0x7F); + unsigned >>= 7; + if (unsigned != 0) + { + temp |= 0x80; + } + writer.Write(temp); + } while (unsigned != 0); + } + + private async Task ReadVarInt(NetworkStream stream) + { + int numRead = 0; + int result = 0; + byte read; + + do + { + var buffer = new byte[1]; + var bytesRead = await stream.ReadAsync(buffer, 0, 1); + if (bytesRead == 0) return -1; + + read = buffer[0]; + int value = (read & 0x7F); + result |= (value << (7 * numRead)); + + numRead++; + if (numRead > 5) + { + throw new Exception("VarInt is too big"); + } + } while ((read & 0x80) != 0); + + return result; + } + + private ServerStatus ParseServerResponse(string json) + { + var status = new ServerStatus { IsOnline = true }; + + try + { + using var document = JsonDocument.Parse(json); + var root = document.RootElement; + + // Версия + if (root.TryGetProperty("version", out var versionElement)) + { + if (versionElement.TryGetProperty("name", out var nameElement)) + { + status.Version = nameElement.GetString() ?? string.Empty; + } + if (versionElement.TryGetProperty("protocol", out var protocolElement)) + { + status.Protocol = protocolElement.GetInt32().ToString(); + } + } + + // Игроки + if (root.TryGetProperty("players", out var playersElement)) + { + if (playersElement.TryGetProperty("online", out var onlineElement)) + { + status.OnlinePlayers = onlineElement.GetInt32(); + } + if (playersElement.TryGetProperty("max", out var maxElement)) + { + status.MaxPlayers = maxElement.GetInt32(); + } + } + + // Описание + if (root.TryGetProperty("description", out var descElement)) + { + if (descElement.ValueKind == JsonValueKind.String) + { + status.Description = descElement.GetString() ?? string.Empty; + } + else if (descElement.ValueKind == JsonValueKind.Object) + { + if (descElement.TryGetProperty("text", out var textElement)) + { + status.Description = textElement.GetString() ?? string.Empty; + } + } + } + } + catch (Exception ex) + { + Console.WriteLine($"Ошибка при парсинге ответа сервера: {ex.Message}"); + } + + return status; + } + } +} diff --git a/legacy/Launcher/legacy/csharp/SettingsPanel.cs b/legacy/Launcher/legacy/csharp/SettingsPanel.cs new file mode 100644 index 00000000000..939ff4cc422 --- /dev/null +++ b/legacy/Launcher/legacy/csharp/SettingsPanel.cs @@ -0,0 +1,723 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using System.Threading.Tasks; +using System.Linq; +using MinecraftLauncher.Models; + +namespace MinecraftLauncher +{ + /// + /// Панель настроек внутри главного окна + /// + public class SettingsPanel : Panel + { + private ConfigManager configManager; + private JavaDetector javaDetector; + private GameProfile currentProfile; + + // Цвета Owyx дизайна + private readonly Color BackgroundColor = Color.FromArgb(18, 18, 24); + private readonly Color SecondaryBackgroundColor = Color.FromArgb(24, 24, 32); + private readonly Color AccentColor = Color.FromArgb(138, 43, 226); + private readonly Color AccentHoverColor = Color.FromArgb(148, 53, 236); + private readonly Color TextColor = Color.FromArgb(240, 240, 245); + private readonly Color SecondaryTextColor = Color.FromArgb(150, 150, 160); + private readonly Color BorderColor = Color.FromArgb(60, 60, 70); + + public event EventHandler SettingsClosed; + public event EventHandler SettingsSaved; + + public SettingsPanel(ConfigManager config, GameProfile profile) + { + configManager = config; + currentProfile = profile; + javaDetector = new JavaDetector(); + + InitializeComponent(); + SetupDesign(); + LoadSettings(); + } + + private void InitializeComponent() + { + this.Dock = DockStyle.Fill; + this.BackColor = BackgroundColor; + this.Visible = false; + } + + private void SetupDesign() + { + this.Controls.Clear(); + + // Создать скроллируемую панель + var scrollPanel = new Panel + { + Dock = DockStyle.Fill, + AutoScroll = true, + BackColor = BackgroundColor + }; + this.Controls.Add(scrollPanel); + + var contentPanel = new Panel + { + Location = new Point(0, 0), + Size = new Size(760, 800), + BackColor = BackgroundColor, + AutoSize = true + }; + scrollPanel.Controls.Add(contentPanel); + + int yPos = 20; + + // Заголовок + var titleLabel = new Label + { + Text = "⚙️ НАСТРОЙКИ", + Font = new Font("Segoe UI", 18, FontStyle.Bold), + ForeColor = TextColor, + Location = new Point(30, yPos), + Size = new Size(700, 40) + }; + contentPanel.Controls.Add(titleLabel); + yPos += 60; + + // Кнопка закрытия + var closeButton = new Button + { + Text = "←", + Font = new Font("Segoe UI", 16, FontStyle.Bold), + ForeColor = TextColor, + BackColor = SecondaryBackgroundColor, + FlatStyle = FlatStyle.Flat, + Size = new Size(50, 50), + Location = new Point(contentPanel.Width - 80, 20), + Cursor = Cursors.Hand + }; + closeButton.FlatAppearance.BorderSize = 0; + closeButton.Click += (s, e) => Hide(); + contentPanel.Controls.Add(closeButton); + + // Панель настроек Java + yPos = CreateJavaSettingsPanel(contentPanel, yPos); + yPos += 20; + + // Панель настроек памяти + yPos = CreateMemorySettingsPanel(contentPanel, yPos); + yPos += 20; + + // Панель настроек окна игры + yPos = CreateGameWindowSettingsPanel(contentPanel, yPos); + yPos += 20; + + // Панель аргументов + yPos = CreateArgumentsPanel(contentPanel, yPos); + yPos += 20; + + // Панель Discord RPC + yPos = CreateDiscordRPCPanel(contentPanel, yPos); + yPos += 20; + + // Кнопка сохранения + var saveButton = new Button + { + Text = "💾 Сохранить настройки", + Location = new Point(30, yPos), + Size = new Size(700, 50), + BackColor = AccentColor, + ForeColor = TextColor, + Font = new Font("Segoe UI", 12, FontStyle.Bold), + FlatStyle = FlatStyle.Flat, + Cursor = Cursors.Hand + }; + saveButton.FlatAppearance.BorderSize = 0; + saveButton.Click += SaveButton_Click; + saveButton.MouseEnter += (s, e) => saveButton.BackColor = AccentHoverColor; + saveButton.MouseLeave += (s, e) => saveButton.BackColor = AccentColor; + contentPanel.Controls.Add(saveButton); + + contentPanel.Height = yPos + 70; + } + + private int CreateJavaSettingsPanel(Panel parent, int yPos) + { + var panel = CreateSectionPanel(parent, yPos, 120, "☕ Java"); + + var autoDetectCheckBox = new CheckBox + { + Name = "autoDetectJavaCheckBox", + Text = "Автоматически определять Java", + ForeColor = TextColor, + Location = new Point(15, 40), + Size = new Size(300, 25), + Checked = currentProfile.AutoDetectJava + }; + autoDetectCheckBox.CheckedChanged += AutoDetectJava_CheckedChanged; + panel.Controls.Add(autoDetectCheckBox); + + var javaPathLabel = new Label + { + Text = "Путь к Java:", + ForeColor = SecondaryTextColor, + Location = new Point(15, 70), + Size = new Size(100, 20) + }; + panel.Controls.Add(javaPathLabel); + + var javaPathTextBox = new TextBox + { + Name = "javaPathTextBox", + Location = new Point(120, 68), + Size = new Size(470, 23), + BackColor = BackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle, + Text = currentProfile.JavaPath, + Enabled = !currentProfile.AutoDetectJava + }; + panel.Controls.Add(javaPathTextBox); + + var browseButton = new Button + { + Name = "browseJavaButton", + Text = "📁", + Location = new Point(595, 67), + Size = new Size(60, 25), + BackColor = SecondaryBackgroundColor, + ForeColor = TextColor, + FlatStyle = FlatStyle.Flat, + Enabled = !currentProfile.AutoDetectJava, + Cursor = Cursors.Hand + }; + browseButton.FlatAppearance.BorderColor = BorderColor; + browseButton.Click += BrowseJava_Click; + panel.Controls.Add(browseButton); + + var detectButton = new Button + { + Name = "detectJavaButton", + Text = "🔍", + Location = new Point(660, 67), + Size = new Size(60, 25), + BackColor = AccentColor, + ForeColor = TextColor, + FlatStyle = FlatStyle.Flat, + Cursor = Cursors.Hand + }; + detectButton.FlatAppearance.BorderSize = 0; + detectButton.Click += DetectJava_Click; + panel.Controls.Add(detectButton); + + // Показать версию Java + var javaVersionLabel = new Label + { + Name = "javaVersionLabel", + Text = "Определяем версию Java...", + ForeColor = SecondaryTextColor, + Font = new Font("Segoe UI", 9, FontStyle.Italic), + Location = new Point(120, 95), + Size = new Size(600, 20) + }; + panel.Controls.Add(javaVersionLabel); + + // Асинхронно определить версию Java + Task.Run(async () => + { + var version = await GetJavaVersion(currentProfile.JavaPath); + if (javaVersionLabel.IsHandleCreated) + { + javaVersionLabel.Invoke(new Action(() => + { + javaVersionLabel.Text = version; + })); + } + }); + + return yPos + 150; + } + + private int CreateMemorySettingsPanel(Panel parent, int yPos) + { + var panel = CreateSectionPanel(parent, yPos, 100, "💾 Память (RAM)"); + + var memoryLabel = new Label + { + Text = "Выделено памяти:", + ForeColor = SecondaryTextColor, + Location = new Point(15, 45), + Size = new Size(120, 20) + }; + panel.Controls.Add(memoryLabel); + + var memoryTrackBar = new TrackBar + { + Name = "memoryTrackBar", + Location = new Point(140, 40), + Size = new Size(320, 45), + Minimum = 512, + Maximum = 16384, + TickFrequency = 512, + Value = currentProfile.AllocatedMemoryMB + }; + memoryTrackBar.ValueChanged += MemoryTrackBar_ValueChanged; + panel.Controls.Add(memoryTrackBar); + + // TextBox для ручного ввода (рядом со слайдером) + var memoryTextBox = new TextBox + { + Name = "memoryTextBox", + Location = new Point(470, 43), + Size = new Size(80, 23), + BackColor = SecondaryBackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle, + Text = currentProfile.AllocatedMemoryMB.ToString(), + MaxLength = 5, + TextAlign = HorizontalAlignment.Center + }; + memoryTextBox.KeyPress += (s, e) => + { + if (!char.IsControl(e.KeyChar) && !char.IsDigit(e.KeyChar)) + { + e.Handled = true; + } + }; + memoryTextBox.Leave += (s, e) => + { + if (int.TryParse(memoryTextBox.Text, out int value)) + { + if (value < 512) value = 512; + if (value > 16384) value = 16384; + memoryTextBox.Text = value.ToString(); + + var trackBar = FindControl("memoryTrackBar"); + if (trackBar != null && trackBar.Value != value) + { + trackBar.Value = value; + } + } + else + { + memoryTextBox.Text = currentProfile.AllocatedMemoryMB.ToString(); + } + }; + panel.Controls.Add(memoryTextBox); + + var memoryValueLabel = new Label + { + Name = "memoryValueLabel", + Text = $"{currentProfile.AllocatedMemoryMB} MB ({currentProfile.AllocatedMemoryMB / 1024.0:F1} GB)", + ForeColor = TextColor, + Font = new Font("Segoe UI", 10, FontStyle.Bold), + Location = new Point(560, 45), + Size = new Size(160, 20) + }; + panel.Controls.Add(memoryValueLabel); + + return yPos + 100; + } + + private int CreateGameWindowSettingsPanel(Panel parent, int yPos) + { + var panel = CreateSectionPanel(parent, yPos, 100, "🖥️ Окно игры"); + + var fullscreenCheckBox = new CheckBox + { + Name = "fullscreenCheckBox", + Text = "Полноэкранный режим", + ForeColor = TextColor, + Location = new Point(15, 45), + Size = new Size(200, 25), + Checked = currentProfile.Fullscreen + }; + fullscreenCheckBox.CheckedChanged += Fullscreen_CheckedChanged; + panel.Controls.Add(fullscreenCheckBox); + + var widthLabel = new Label + { + Text = "Ширина:", + ForeColor = SecondaryTextColor, + Location = new Point(250, 48), + Size = new Size(60, 20) + }; + panel.Controls.Add(widthLabel); + + var widthTextBox = new TextBox + { + Name = "widthTextBox", + Text = currentProfile.WindowWidth.ToString(), + Location = new Point(315, 45), + Size = new Size(80, 23), + BackColor = BackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle, + Enabled = !currentProfile.Fullscreen + }; + panel.Controls.Add(widthTextBox); + + var heightLabel = new Label + { + Text = "Высота:", + ForeColor = SecondaryTextColor, + Location = new Point(420, 48), + Size = new Size(60, 20) + }; + panel.Controls.Add(heightLabel); + + var heightTextBox = new TextBox + { + Name = "heightTextBox", + Text = currentProfile.WindowHeight.ToString(), + Location = new Point(485, 45), + Size = new Size(80, 23), + BackColor = BackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle, + Enabled = !currentProfile.Fullscreen + }; + panel.Controls.Add(heightTextBox); + + return yPos + 100; + } + + private int CreateArgumentsPanel(Panel parent, int yPos) + { + var panel = CreateSectionPanel(parent, yPos, 100, "⚡ Дополнительные аргументы"); + + var jvmArgsLabel = new Label + { + Text = "JVM аргументы:", + ForeColor = SecondaryTextColor, + Location = new Point(15, 42), + Size = new Size(110, 20) + }; + panel.Controls.Add(jvmArgsLabel); + + var jvmArgsTextBox = new TextBox + { + Name = "jvmArgsTextBox", + Text = currentProfile.JvmArguments, + Location = new Point(130, 40), + Size = new Size(590, 23), + BackColor = BackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle + }; + panel.Controls.Add(jvmArgsTextBox); + + var gameArgsLabel = new Label + { + Text = "Аргументы игры:", + ForeColor = SecondaryTextColor, + Location = new Point(15, 72), + Size = new Size(110, 20) + }; + panel.Controls.Add(gameArgsLabel); + + var gameArgsTextBox = new TextBox + { + Name = "gameArgsTextBox", + Text = currentProfile.GameArguments, + Location = new Point(130, 70), + Size = new Size(590, 23), + BackColor = BackgroundColor, + ForeColor = TextColor, + BorderStyle = BorderStyle.FixedSingle + }; + panel.Controls.Add(gameArgsTextBox); + + return yPos + 100; + } + + private int CreateDiscordRPCPanel(Panel parent, int yPos) + { + var panel = CreateSectionPanel(parent, yPos, 80, "💬 Discord Rich Presence"); + + var enableDiscordCheckBox = new CheckBox + { + Name = "enableDiscordRPCCheckBox", + Text = "Показывать активность в Discord", + ForeColor = TextColor, + Location = new Point(15, 45), + Size = new Size(300, 25), + Checked = false // TODO: Загрузить из конфига + }; + panel.Controls.Add(enableDiscordCheckBox); + + return yPos + 80; + } + + private Panel CreateSectionPanel(Panel parent, int yPos, int height, string title) + { + var panel = new Panel + { + Location = new Point(30, yPos), + Size = new Size(700, height), + BackColor = SecondaryBackgroundColor + }; + parent.Controls.Add(panel); + + var titleLabel = new Label + { + Text = title, + Font = new Font("Segoe UI", 12, FontStyle.Bold), + ForeColor = AccentColor, + Location = new Point(15, 10), + Size = new Size(300, 25) + }; + panel.Controls.Add(titleLabel); + + return panel; + } + + private async void LoadSettings() + { + // Загрузить настройки из конфига + var config = await configManager.LoadConfig(); + + // Загрузить Discord RPC + var discordCheckBox = FindControl("discordRPCCheckBox"); + if (discordCheckBox != null) + { + discordCheckBox.Checked = config.EnableDiscordRPC; + } + + // Загрузить другие настройки + if (currentProfile.AutoDetectJava && string.IsNullOrEmpty(currentProfile.JavaPath)) + { + await AutoDetectJavaPath(); + } + } + + private async void AutoDetectJava_CheckedChanged(object sender, EventArgs e) + { + var checkBox = sender as CheckBox; + if (checkBox == null) return; + + var javaPathTextBox = FindControl("javaPathTextBox"); + var browseButton = FindControl + + + + + \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/delete_instance_confirmation_modal/screen.png b/legacy/Launcher/stitch_owyx_launcher/delete_instance_confirmation_modal/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..8784d61c366bb338f648606ee7c1937e0e73b53e GIT binary patch literal 136824 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

aYnS0cJn%~sC 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≫2i5}25o(oU}uowdi7su|I$txon{auTMXc0PCQiIvtHLGv(w z!kATH9^cGHZm{8@n2FxG^#!g(p=7Q)Svwv?QQ!OJ#5{1dKkWu?fm0~AGU!3Jnm5%dRpV# zxh)^&_O${P2Wyvb_Jq}Q;hUrx|0nmczm(b;%r=L~u6b<2VAdEI0s(^5)GmI@Qje9Z zNEjQ9P+P&Mwf^#R8%OMKuY06OG;qN)zBR$XATWm#e8L!*HV}0l-QFCCthz?QRC485 zT+QHlaG&@+TqXtYYw!-iQ03cfc})4Ex56&pevKn5T6Gp7`>&h$xO4W#t)Cla32Un& z=^jx;m@j*aa+eFlk4yL@rVA+(OVt)oMX>yAp*rr~J5?RVa#U2>GCi!YY{3o3g&A-# z<{SFkGKPLib_LmPF1xu&Bx3gXYkCp|VL<+F92K#%hr%_@9uF}woU=d}8-th2UaflI zr{WWakv^-2C~dXOBn^6bC8_3leoz6JRwr;MI1M(`*z~~uzqxOcS`hTr(x1kLx{O|@|Aq2^y%XvZ`m|vHe`137A=UH$ zR+0f=VK{)J05$!;I$a1l<^MJmi~!s~#?7`qB(5(tiwJ|5fZP~SB%&PlPk_cRd~}|i_MF~= z&#P0ERe_iY`6aqZnC8iXWR#$I-g+@uK-(wt3&kMaS&Ko&Sj=li8Lbe>aWN20Jp-=_bOay{Xv=Z)7i(cA4MucY;ZirF$QUFnK)NRNAP42l#E~)H`@+m^?lZSg$n?l zT&{NT5ix9*aI_`8X83 zL(tejIw}BooQ;tdj|R{c+%UZTZyPJ^V0UW^G!Y%L+R#)qewr7kvG?>^3MTnla{_^O~ z7@Y~=&uQ4+$Q&jLA&}(|KsuU)_2(&Q1}cwWYAqe~Ua+B<^- + Dark desktop Minecraft launcher UI (Windows / Tauri WebView). Phase 1 mirrors + Modrinth App information architecture and green-accent dark chrome; Phase 2 + will rebrand to Owyx individuality. Product is a native-feeling desktop app, + not a marketing website — design for ~1280×800 and larger desktop windows. +colors: + bg: "#09090b" + surface: "#121214" + surface-raised: "#1a1b1e" + rail: "#0b0b0d" + border: "#2a2b30" + text: "#f3f4f6" + text-muted: "#9aa0a8" + primary: "#1bd96a" + on-primary: "#042313" + danger: "#ff5c6c" + danger-surface: "#3a1519" + ok: "#7dcea0" + overlay: "rgba(0,0,0,0.58)" + focus-ring: "#1bd96a" +typography: + display: + fontFamily: DM Sans + fontSize: 26px + fontWeight: 700 + lineHeight: 1.15 + letterSpacing: -0.03em + headline: + fontFamily: DM Sans + fontSize: 20px + fontWeight: 700 + lineHeight: 1.2 + letterSpacing: -0.02em + title: + fontFamily: DM Sans + fontSize: 16px + fontWeight: 600 + lineHeight: 1.3 + body: + fontFamily: DM Sans + fontSize: 15px + fontWeight: 500 + lineHeight: 1.45 + body-sm: + fontFamily: DM Sans + fontSize: 13px + fontWeight: 500 + lineHeight: 1.4 + label: + fontFamily: DM Sans + fontSize: 12px + fontWeight: 600 + lineHeight: 1.2 + letterSpacing: 0.04em + brand: + fontFamily: DM Sans + fontSize: 15px + fontWeight: 700 + lineHeight: 1 + letterSpacing: -0.02em +rounded: + sm: 8px + md: 10px + lg: 14px + xl: 16px + full: 9999px +spacing: + xs: 4px + sm: 8px + md: 12px + lg: 16px + xl: 24px + xxl: 32px + rail-width: 64px + topbar-height: 48px + page-padding: 24px +components: + button-primary: + backgroundColor: "{colors.primary}" + textColor: "{colors.on-primary}" + rounded: "{rounded.md}" + padding: 10px 14px + height: 40px + button-ghost: + backgroundColor: "{colors.surface-raised}" + textColor: "{colors.text}" + rounded: "{rounded.md}" + padding: 10px 14px + button-danger: + backgroundColor: "{colors.danger-surface}" + textColor: "#ff9aa5" + rounded: "{rounded.md}" + rail-button: + backgroundColor: transparent + textColor: "{colors.text-muted}" + rounded: "{rounded.full}" + width: 48px + height: 48px + rail-button-active: + backgroundColor: "color-mix(in srgb, #1bd96a 16%, transparent)" + textColor: "{colors.primary}" + input: + backgroundColor: "{colors.surface-raised}" + textColor: "{colors.text}" + rounded: "{rounded.md}" + padding: 11px 12px + chip: + backgroundColor: "{colors.surface-raised}" + textColor: "{colors.text}" + rounded: "{rounded.full}" + padding: 9px 12px + chip-selected: + backgroundColor: "color-mix(in srgb, #1bd96a 12%, #1a1b1e)" + textColor: "{colors.primary}" + tab: + backgroundColor: "{colors.surface-raised}" + textColor: "{colors.text-muted}" + rounded: "{rounded.full}" + padding: 8px 14px + tab-active: + backgroundColor: "color-mix(in srgb, #1bd96a 18%, #1a1b1e)" + textColor: "{colors.primary}" + card: + backgroundColor: "{colors.surface}" + textColor: "{colors.text}" + rounded: "{rounded.lg}" + padding: 18px + modal: + backgroundColor: "{colors.surface}" + rounded: "{rounded.xl}" + padding: 18px + switch-on: + backgroundColor: "{colors.primary}" + switch-off: + backgroundColor: "#3a3b40" + status-pill: + backgroundColor: "{colors.surface}" + textColor: "{colors.text-muted}" + rounded: "{rounded.full}" + padding: 6px 12px +--- + +# Owyx Launcher — DESIGN.md + +## Overview + +**Owyx** is a custom **desktop Minecraft launcher** (Windows first, Tauri + WebView). The UI must feel like a **native desktop app**, not a marketing landing page and not a mobile app. + +**Phase 1 visual direction:** close to **Modrinth App** — near-black chrome, single bright green accent for primary actions and selection, circular left rail icons, pill tabs, dense but readable lists. This is intentional: we are building a working Modrinth-like reference before an Owyx rebrand. + +**Phase 2 (later, do not invent yet in generated screens unless asked):** unique Owyx branding, colors, logos, private-server emphasis, custom login site — may change layout. + +**Personality:** quiet, technical, gamer-tool. Confident green CTAs. Minimal decoration. No purple gradients, no neon glow spam, no emoji as UI chrome, no newspaper/serif editorial look. + +**Audience:** Minecraft players installing and launching instances (Vanilla / Fabric / Quilt / Forge / NeoForge), managing mods later, and (later) joining author private servers. + +**Language in UI for Phase 1 mockups:** English labels matching Modrinth patterns (`Home`, `Library`, `New instance`, `Play`, `Settings`). Product name in chrome: lowercase **owyx**. + +**Window:** frameless-feeling content under a thin app top bar (brand + breadcrumb + status pill). Design **desktop Web** layouts at **1280×800** and **1440×900**. Always show the **left rail**. + +## Colors + +Near-black foundation with one Modrinth-like green accent. + +- **Background (`#09090b`):** App canvas. Optional very subtle green/cool radial wash — never loud. +- **Surface (`#121214`) / Raised (`#1a1b1e`):** Panels, cards, inputs, rail. +- **Border (`#2a2b30`):** 1px separators and control outlines. +- **Text (`#f3f4f6`) / Muted (`#9aa0a8`):** Primary vs secondary copy. +- **Primary / Accent (`#1bd96a`):** Play, New instance, selected tabs/chips, active rail, toggles on. Ink on green: `#042313`. +- **Danger (`#ff5c6c`):** Delete only — never for primary navigation. +- **OK (`#7dcea0`):** Success / valid Java path checkmarks. + +One accent color only. Do not introduce purple, pink, or rainbow accents. + +## Typography + +**DM Sans** for everything (UI sans). No serif. No Inter-as-default marketing stack feel — DM Sans is the brand type for Phase 1. + +- Page titles: ~26px / 700 / tight tracking. +- Section titles: ~16–20px / 700. +- Body / inputs: 14–15px / 500. +- Meta lines under instance names: 12–13px muted. +- Rail has no text labels — icons + tooltips only. + +## Layout + +**Shell grid (always):** + +1. **Left rail** — fixed **64px** (`4rem`) width. Vertical stack. +2. **Stage** — topbar 48px + scrollable main content with ~24px padding. + +**Left rail order (top → bottom), Modrinth-shaped:** + +1. Small circular **O** logo mark (green gradient). +2. Nav icons (circular 48×48 hit targets): **Home**, **Discover**, **Library**, **Private Servers**. +3. **Recent instances** — up to ~6 circular avatar buttons (initial letter). Expands with content; **collapses when empty** (no empty gap). +4. **+** create instance (same circular control style). +5. **Flex spacer** pushing settings down. +6. **Settings** gear at the very bottom. + +Important: **+ is NOT next to Settings by default.** Settings alone sits at the bottom. + sits directly under recent (or under nav when recent is empty). + +**Top bar:** left — `owyx` brand + optional back/forward (can be disabled) + breadcrumb (` / Home`); right — status pill (`No active instances` / install progress / play status). + +**Home:** two columns on desktop — main (Welcome + Jump back in list) + right sticky column (~300px) for **Account** (nick, skin placeholder, Microsoft login disabled) and **News**. + +**Library:** header row with pill tabs (`All instances` active; Modpacks/Servers/Custom disabled) + green **+ New instance**; search + sort/group; instance rows OR centered empty state. + +**Instance detail:** hero (icon, name, MC/loader meta, **Play**, gear, ⋮ menu) + pill tabs: Content | Files | Worlds | Logs | Share. + +**Settings (launcher):** split view — left settings nav (~220px), right content card (Java installations first). + +**Modals:** centered card on dimmed blurred overlay; max width ~560px for create; instance settings can be full-page split instead of modal (both are valid — prefer **modal for create**, **page for instance settings** and **app settings**). + +Spacing rhythm: 4 / 8 / 12 / 16 / 24 px. + +## Elevation & Depth + +Mostly **flat tonal layers**: background → surface → raised. Borders over drop shadows. + +- Soft shadow only on **dropdown menus** and **modals** (`0 12–24px` dark translucent). +- Modal backdrop: dark scrim + light blur. +- Active rail: filled tint, **no** left accent bar required (Modrinth-style selected fill). +- Avoid multi-layer neon glows. + +## Shapes + +- Rail buttons / recent avatars / tabs / chips / status pill: **fully rounded** (`9999px`). +- Cards, inputs, primary buttons, modal: **10–16px** radius. +- Instance icons: ~10–14px radius squares. +- Consistency: pills for filters/tabs; rounded-rect for forms and cards. + +## Components + +### Buttons + +- **Primary:** solid `#1bd96a`, dark green text, 10px radius, bold. Used for Play, New instance, Create, Find projects (when enabled). +- **Ghost:** raised fill + border. Secondary actions (Detect, Add files, Cancel). +- **Danger:** dark red surface — Delete instance only. +- **Icon button:** 40×40, raised, border — settings, overflow, close. + +### Rail / NavButton + +Circular, icon-only, 48×48. Hover: raised fill. Active: green tint + green icon. + +### Inputs & selects + +Full-width-friendly, raised background, 10px radius, muted placeholder. Selects with custom chevron. + +### Chips & tabs + +Pill shaped. Selected = green text + light green wash. Used for loader pick (Fabric/Forge/…) and library/instance filters. + +### Lists + +- **Jump-back / instance rows:** horizontal bar — leading icon, title + meta, trailing Play (home) or chevron. +- **Content table:** columns Project | Version | Actions (toggle, trash). +- **Java rows:** path + green check. + +### Switch + +Track 40×22; on = primary green; off = gray. + +### Modal (Create instance) + +Fields top to bottom: Title → Platform chips → Game version select → Loader version select (hidden for Vanilla) → Snapshots checkbox → status line → Create / Cancel. + +### Instance settings page + +Left nav: General | Installation | Window | Java & memory | Launch commands. Right pane forms; General includes rename, group, update channel pills (Release/Beta/Alpha), Duplicate, Delete, Back. + +### Empty states + +Centered, muted, one short headline + one sentence + optional primary CTA. Library empty: **No instances found** + Create new instance. + +## Do's and Don'ts + +**Do** + +- Keep the left rail visible on every primary screen. +- Use green only for primary CTA and selection states. +- Design desktop density (Modrinth App), not mobile-first cards stacked for phones. +- Show install/play status in the top-right pill when relevant. +- Match Modrinth IA: Home / Discover / Library / Servers / + / Settings. +- Prefer icon+label clarity; English UI strings for Phase 1 mocks. + +**Don't** + +- Don’t put + and Settings in the same bottom cluster as the default layout. +- Don’t use purple/indigo AI-default themes, cream+serif terracotta, or broadsheet newspaper layouts. +- Don’t invent a marketing landing page; this is an **app shell**. +- Don’t overload the first viewport with stats strips, badge clutter, or floating promo stickers on heroes. +- Don’t hide Play behind nested menus — Play stays prominent on instance and jump-back rows. +- Don’t redesign Owyx brand colors in Phase 1 generations — stick to this green/black system until Phase 2 brief. diff --git a/legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/code.html b/legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/code.html new file mode 100644 index 00000000000..fa7efcca3c4 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/code.html @@ -0,0 +1,323 @@ + + + +Owyx - Home + + + + + + + + + + + +

+ +
+
+
owyx
+/ +Home +
+
+
+
+System Stable +
+
+
+ +
+ +
+
+

Welcome back

+
+
+

Jump back in

+ +
+
+
+Vanilla +
+
+Vanilla 1.21.1 +Played 2h ago • Survival +
+
+ +
+ +
+
+
+Fabric +
+
+Fabric SMP +Played yesterday • Multiplayer +
+
+ +
+
+
+ + +
+ + + \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/screen.png b/legacy/Launcher/stitch_owyx_launcher/home_official_canon_v1/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..0983ea1f48feb4ade8258417e312539324732971 GIT binary patch literal 158277 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/code.html b/legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/code.html new file mode 100644 index 00000000000..c845a367a53 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/code.html @@ -0,0 +1,320 @@ + + + + + +Owyx - Instance Detail + + + + + + + + + + + +
+ +
+ +
+owyx +chevron_right +Library +chevron_right +Fabric Exploration +
+ +
+
+
+Ready +
+
+
+ +
+ +
+ +
+Fabric Exploration Icon +
+ +
+

Fabric Exploration

+
+Minecraft 1.21.1 + +Fabric 0.16.0 + +schedule Last played 2 days ago +
+
+ +
+ + + + +
+
+ +
+ + + + + +
+ + +
+ +
+
Mod Name
+
Version
+
Author
+
+
+ +
+
+
+
+extension +
+Sodium +
+
mc1.21.1-0.6.0
+
CaffeineMC
+
+ +
+
+
+
+
+extension +
+Lithium +
+
mc1.21.1-0.13.0
+
CaffeineMC
+
+ +
+
+
+
+
+extension +
+Iris Shaders +
+
mc1.21.1-1.7.3
+
Iris Team
+
+ +
+
+
+
+
+
+ +
+ +
+ + + +
+ +
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_actions_menu/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..fafa1fd84fbefedf75d7a05906277ad2cd482297 GIT binary patch literal 135535 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
+M!VVrXq$>g1j6GLT`(VKIW0b(4tVEG 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 + + +Owyx - Instance Detail + + + + + + + + + + + +
+ +
+ owyx +
+
+ +
+
+
+ Ready +
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+

Fabric Exploration

+

+Minecraft 1.21.1 + +Fabric 0.16.0 +

+
+ +
+ + + +
+
+ +
+ +
+ + + + + +
+ +
+ +
+ + + +
+ +
+
+search + +
+ + +
+
+ +
+
4 items total
+
+ + +
+
+ +
+ +
+
Project
+
Version
+
Actions
+
+ +
+ +
+
+
+ +
+Iris Shaders +
+
+1.7.2+1.21.1 +
+
+ +
+ + +
+ +
+
+ +
+
+
+ +
+Sodium +
+
+0.5.11+1.21.1 +
+
+
+ + +
+ +
+
+ +
+
+
+ +
+Lithium +
+
+0.13.0+1.21.1 +
+
+
+ + +
+ +
+
+ +
+
+
+ +
+Starlight +
+
+1.1.2+1.21.1 +
+
+
+ + +
+ +
+
+
+
+
+ +
+
+
+
+ + + \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_content_tab/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_content_tab/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..af34394a9356d3f92855dc3843d6a73150ce1646 GIT binary patch literal 179911 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/code.html b/legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/code.html new file mode 100644 index 00000000000..3652fd3fff4 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/code.html @@ -0,0 +1,321 @@ + + + + + +Owyx - Instance Detail + + + + + + + + + +

+ +
+ +
+
+owyx +/ +Library +/ +Fabric Exploration +
+
+
+
+Ready +
+
+
+ +
+
+ +
+
+ +
+
+
+

Fabric Exploration

+
+videogame_asset Minecraft 1.21.1 + +extension Fabric 0.16.0 + +42 Mods +
+
+
+ + + +
+
+ +
+ + + + + +
+ +
+ +
+
+
Name
+
Size
+
Modified
+
+
+ +
+ +
+folder +mods +-- +Oct 24, 2023 + +
+
+folder +config +-- +Oct 24, 2023 + +
+
+folder +resourcepacks +-- +Oct 22, 2023 + +
+
+folder +saves +-- +Oct 25, 2023 + +
+
+folder +screenshots +-- +Sep 15, 2023 + +
+
+folder +logs +-- +Oct 26, 2023 + +
+ +
+description +options.txt +12 KB +Oct 24, 2023 + +
+
+description +servers.dat +4 KB +Oct 20, 2023 + +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_files_tab/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..6ea6972b9b8e79fdefa94323778a43293d221ba5 GIT binary patch literal 180776 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
*$WAjUslP(8RYb z6g-_KUolaX`t`Al}ZfSsAhkj0fEf$T6aN#ZL7aeJ%sWO zY-~~(;>-9{ctYN-AG_1rBJ>QsdAz=;DQP)3vI(h5^H#CO*jTI{qs#~0Z}C_yfJX#| z(cNNid;#)n^D(6z+3XVC)<*&Wi^akfUn{p9`m%5jfj+M2$ z^4HsLq1(Swij@K}T~GJyPvhcGwkkWFh#1tLt0AuUy&&=P;-JT%C%M-ZM6m~lx2Aer z@w?D+)q?vswfi&wOEQ&AOMN_*=r{7#@v*xwM^p(OV9&-8*(d3-i5c{u8~Cy(*GGjTc7COKd#c@;7?USX2~YhAURol|6f6U<>h}_#a-{DaotlR0 z&+C4l%=1;Ul)mdV8FvVSeagt>X#IO9Z_nLT+atN)cMXvCp!~vRj|&SH2kr(BTDjTq zU=0iJ9x;StVtMPpDzhyu_$OO|P=jbfPBnN}QuNRL#2IJj2ie(@kt%=cm3mHV>I;Jgf?SS31T^NFXF1ub&$!oOH>LYbfI z+m;~euK|~rm$BecPdw=E?o%OOJT)Ju!I(XIk^#tq&YaI4Y}q$F;7-zIxoLMBE21u) zI}qEX)A&Y?OU3Z|S0~vt?ub-U8w5(W-_0s@|78#IbacEo(t(8(@9m}sZJ4|qXSwa= zKTJo)LH^gonM)SP%Lu!clu?QLW^8AUt#=H)s#%mr>nu3OVR!-)-tg3 zl(}0te$c+RaA$npkcm~q*PgX$h(c%$Smk8c7I73hJ|D2%=IasSK4>Uuj-^zn`mWIa zVTrjlg`s)^TAjwEcJ;H+P}7cw+_W=!X@qA)wny(=X#ssCsH>gG-xR-~dw9Fy%s198 z-fG|$St;R2@Plr=T*^dzEsDG)>h-+_4zsa+nEK{JsckFhD@!JAMt8o*OY-HsRT~B7 z{{GVJ_qhro#!B3B)zx)7aqpL>@S`IbRh(e}b`vexjp5KpV}GNzJRNrl4-@?OqD5}^ z*(c@C_!;(lroBI)dDtu$s=V(3!O5CP{|;PHekb{@Hw<7?r{p=|VTvU2yBzJWW%EE4 zW_<4;#DnTww?kYHC#uhNTdhJ?a8> z7VhHXHAp+j!%KC>kZGpQnG&{i4F`6mi}7U6&wd{p9wuPujD3K50h9=EL4GM5THBCA zP4fpco~W;QQTR+Ux@SKE{z|DP zfhUJmla)eej2ldG)J-#-i;n1IOC_zE7_w^Kcm4x1clPml*`42*fg3AVC2J47_oyEq zSF{DGSg`;o3mXuk8d0o0RZn?mR|jmyE0~2fK1N-(wP`H{ePiQQ~)?{eSIBv zc>RGG2o8Vte}9GwItiIiv(68+6Ci!)daYD@E?V&AU+Q2+S~}@jPO;u_Y!x7|#-pa9 z{-zX@riry0OyzplJ+an19X2GFAh?UD*={G8Y4iMw6R7)EbobVC%Dl(|c50*IJ zIfi%nM4kcs?^OsB3%-jX8{AUp=~b<@`8WBU`?4yn%vEYuN^}S-RwDKJwh+rWJO zL(j+07sY@k1z@nMTSqv3g81RW?ltLtB2|f!2SiDr)j+lcYA+P8?RFMJWYjd%ff?Y* z&&ow+cx514E7s$%*v0)VUWR+q_SjT@ ze>Xzzo3yDJ-6?@`n|+=hM|^=O)dl{Y)+pzH08jjEDb0@lQm7c5l+B~Sp#m|;0^-vv z5PaC;L5~hi^U+5CF5V(-yrymA{%N5rR=aN1jt(iMA5bq@1HaQ{n}KgT&5=DRSeq5s z)2Qh&>wP#M5T6+lO*bF#oE~Hfc^8(a?tPW1lXdo;pRHRbl&EO5w^zf%a%6^hQBpu% zx(33_s3%R0-fs`+0V>^}Ckzh<2cvls&~zzfe#i;^moDrVTbe?yIgSjx5;xKVZi?dT z$~QyW?m-0)LAU3YKg3ft`hHeuq12jmCtJM-=pn#bEFQpjGfzrJcOP1nD6v2{G`T#%$&1Q2OG^@m_@| zSSDdE%+3uhFug2)ws@n&zVQY%qs8QhM$^WP&2VWIal9zU)`1?QlljSDWJZS2$w{3% z0+|t$pz3r*BX8HNI#KZi!6AMNR_PKCFGoC1saBiCX8(0SZM`RHj-~wZ6hF5)?37n3 zUo;twB>_Up!Og_AbJK(wkAlW8y?3jI9U-GXy?GMK(5E}&Rh$%n2kB%(m*27Po_|L56hTlpb09!QjdXNEDtsX5_R9E#zy$wHR1X2Q zBTY|WtcAAkzd6Icu39WB{q#~sZV>pA9h-A(yujvmiW`VaU8u-}_Kn=9L_V1PT3L)yT%Y)vL?ir;fyAC=60_DA$e`9|yi_hz{xZG99du!B;==Pi zgr8g%2!gYJBUHR^`A#CE-mn_;sd{kwz-S3g!`- zY?v>#5t>h!L^BwR_k}d_z0Y*#$z2wBZ(n0M(~r(H^WFOEum>rKdq?~Efm&EBG|$~n zn&-f(r!rE6w7*@)g{}|DREPrzk_;>XCKjJVp-={yA)={UZ!T9@aq_bKy>T)<#Z3X_ zwy`)%b0b6%`rNWNwUdgFvWs33fmG$ee*Z>&(C_vwt!i7Vc3mg!ku^i73_`-PbVf8P zZdtPqs1qOIXe{%y=gM_8Ug}tyL}D&OKHY}Em~%(dfKr-3G(z7`3$DTN?4zS|&%tz% z<=OOx_MV_aQ-4XN&M2|0#9PT%y4jlOuMq(PXMu;`kR8iEm?gPt{zzsDBavR#eN$-y z2!6eb4Dx<`y}qS@WBd%d9Ccn-DI>b8eP7VIw{fCujBkyl(cl&p1+a-iuV@2$eACwj z%4IdkD`YpyrdjdD^`29{j~hHOh8VkucnP%tv9XC`14{>i!WR7OCSm8(0x`-}FenD!+quJdN_&uIK;gOtr@@`#ZIGVAlO(0#1<$YO@LVGnkv1YPJ#)|?4YA80dw zW^Zpp9h+pS|1!x9cbZiLyNFy7GsCyu2I~~l5(DDt$l4(L%>Ew(`uF|7gjvX6DspOb zsCoJ$0Yb<5_HIl>IN~oEahkKI@aejWw0u7SAUF$V2B-gh4a?+x{-iwu!X`^j|Hwp6 zYkt7#QAPB$bf3$#jctx{3*RSZd6hS)b+7F#(rCMQnz_Np+{e2=35KkA zu>fdrk~tBOk<&P>yc}?kS1?RZI?=uSMxE(5CB5hDbN_ALR9)xmiGU-6G>uUY(Me5u z0OhA9coc6nl-`au6j)ds0LRIo!2&TX!fbjLAPXt8$7Pp9TaJb#$BHL-w6qj8nuxkO|J{_? z_o~#I#3^pF|8;av4A*--1K)xG0bY+Mr!mC(CF`@@Ck(n-C%&HRvUx9G8V>a%Bq0ss zz~U0cO53AT!gB2?Y#QyE!%}|P*;JO7l!OJ)_O6*zCxfYFZeP6Q{*|Qf(mki(YFM}d z_5V{F@tdMpP5zxJP8sxHg%lSXPEt%lTlt!Doi|O#-x&TwlcdY~eYQ)>Y6PH$ z1*jD;sgse;!(=)skbo|JdyHx@w>@oc{ZpHRG))O;tx&1ei`K`1l3iVE!YOaYmFu`l z4GtceVXIdOF)Y`zV^KD$F5fcq`f-Suz41Q`0nw-6pg+SL*$YbP%X6omQ?PX`?2*rb z;~a-KKi;&0hrkOOfQbc6MMqZoR1KS&=rj5ZmM)?VS)wMGx?^p-kKeH+t)k))W!3t6 z+^#SD7fwD~|9NQFxDkfd`lMY5D8VXAPQsREB#?Ib-fMh1k2FX*d+KUh+bBtCgYvgb z5O)3ji>v0&56#FRIXcPbBX(f|8Iu$Kciwfc{stbfKK2r#h;YAFa4s17x;E}?@pQQtsKWEo@bq2*>E`B z+6-G3s{G!hlf_+s1@`38kYt4{BB=+__$mTuu!JG)O3}Fg5lrT6bG%BYD2dimLA{%Ss zj@n*R4DtQS%y<6zKJC?xdF>u&f~~&oUC#mC?AW#w0&u3!*wzhHn5a;9wjYni(J&0^ zEO@Lk68*gSf*!kr9af`T#n%o73I5l==Tvjt4Rf-o4?KE}AxW(l1A2^+vlR`n1arB` z8il2Frv#*94WAiFR~p;~GVIrU_s+NERP!oHR|f{=vK7<9du}c+j*DPBRp;ld)DJKNqtq_T zY0SCyUKs4`54c+cosp8IvP30KEo_-5_d1TXSkg>~^RFTWx~3HbG=3x3x%-G!iXR zwvzH#ZqDz9fT7-ol-g9$+33N~oqv2zPrmuDH{INizX@4y4N&?#>voyz8G4Hh!Aj^FL{K z3f8H`V{*Ov+g$xFqI&h(9*X<*(shJ{{4`f2St(Q|`nI5O{0as@E0^@Xf!9KFol`-RX zRvxiZLZeR#pM5XEY0W`ul+=1<+q=^+AG00J%)=H&0gelnmth7TKq-A}(73SIZBnFw z^gy1A^^Xfs2q{BXuuQdWSh8C`dEotj9{j%#=a4o%SRF9mOVgCkZh#01p!??X?fyHM zL?NV)G=IA=(ika0Bxaq)Z|_P%z?l~m`*w{k4+sO6;aujYOzjXgO|jJYUv}_I{bW^5 zEO=OMZ387^eQbhQHnNr2vyB^G{~8K7)r8uwwRV!Z4VyJLe-Ub=wW+7J#5`N!47BN1 zEc!C0hevLbt!WD+s^ZJ8?&~6(8V65~1NscV0fw8492a3$k`-X#RVU{(m`e=@lep86 z%6RF2De}%rV^izdX3`}mRsQjTRulB80&HpfXtPYpI5rhOl`rkP=P~TUYoI7B%NkYB zpJ)gIv(B1@(sJqD4}Ak^8;nWX16z_Qh-Yg34i^>3WG!ni+YC#1LM{U6)3^NsISX>M zvy-ZDAi(iXMX`R-r-tAdmR|=32X9WGdGo?p^%+?MFHfYU4phiJY+r2Nkou;RM zlTEF@?Kd{hg$s0Dr}u@szQ{52iylN){+JJ`>pC!6)qL2a4%d(khm| zRcWQHo2lOetP2@YaKSut7TAk%ASww^REeR3R55OTwk8)F7hR}o%o~(YvioM~V-c42 zoF#m!=xZb!Y$$``k#xG+B&ukMQwrIj)?5^5T0OkVZ?+!&EFj)$SdGaz5h9V&LYjkx zl^GG}G!z0pSsiCSu0yZ!Tjc_CHW^^s*W12d8~sl#B|?i(*(~y+;>jHg*eBmBW3*%| z_*l6TAs5X63V}imW_iv8{gT9fM23ca<|BLVdCntVL2&)2OY zM_KoK;v2I;Imj4ddoG(-PnAx;5sHQY?eRLu%{nNljlqH~gpJb;i=!j&r(7(EzR2hO zpx1Q$?%+}jBhRdY(q`#mV8G||=GaQm%D5AmCJY0Tz}jjYs^v8svv;Kn zKuIP}93~_(X$M=VYmpArjTClC0T;D2YU`=L9z46-n|rg$IOTWv@@yjDD#R~pID)?n zuH9-+(cGHwOaXQ}c8H3$cN0cfbSNn)yd;pD1)f2hiP3JX#Y3%` z_}k8R7#?JGlxX-jk*Y|Aj!57=L1Iod7W|K-*3>GDG_{F*0;YMUG=(ssQqPWuRA!HI zxyoM&9zqFSetSkz!kDC@fvyj;--^o#ZG4Z0ElyBP?%G$52$Ba6cg&lZdl`L<9X;CA z$%r)+4H7<-xXN!)A{JaloQ8fkL!UHifDlU($I0OOTK?OW-)z-KXAWO85!#sgVf;xP zv;&HxvKl$n&myLFv~kPewfsfQ;fKSO{w|7!66Y)RHgOLO*thd$1J|uMtvSj#g6t*&y$LHts>*Ev>J3pNmCFtvfEqbsu?pde5ryY zqiX~blZr()b<%E0_?27SlIcqA9wEe1iRu&FC8Y^Frzvu9qq~EBb5rx7O*3mg!rFI2 z*FhO-q$s#ihA^JVj+RhBMc?;~l8`j!n6@l+M3#w|s)ppl(8{CUqaf-VaclY81cPnl!?(Xg`rMLz67K#-2;1Jy1xjgs1&v)PN z{E?Ncm6ers&Tr1_nb~_L7QrNgVWr3aX)IGJOIJDlbEieoj|KL!R_K>ZA?@ z!AF)vVp>d@`jX+9^B2&-9!@aiLOT2XX#1;RC`A29p&lz95es7ZM*rIeqhm4acrwxW zPEbXI;bZ^IbM}3nM{;N#vi}egA$xR!1Qh^?`~;IOr_@DmaB#R)Q*k?D+XifEiU<}> zh6hw5@xja@6QYL-bd^7+(6Tmpf6@z6S@+Oqf{#-g1NC|S5?9yK!@Epz2G~ckc*;J6S_?Ia;Hab2m|wo5X6eX=BR<-VV6%Qu#}Mr5!iuR^%_*> z&V@g17WB|ER_(D>6;wWiGP& zUM|WxMQwchYu1<{E%rXH`5>M3Gr003FO?PU3vdhw@} z|3bxvV%F0kRv^*>+}o@HESVnJo8}S=fBMATKmt1(V^PLtjLICn#KVD-prDka_X82f z3Ea$JVc+IV?viS1(P=5CdE>*HdeE=dFm3F7%wY4o-r;irc)EIyL!CO?6CXcFYsU3! zHEzqIDz%ZzBornbb6iqk)RqJ5$xkgAD)A+Kl%L1hwoI(CX+Fr?oPp;p%3P9O3!Vl~L)6%15Eu$5so$ek`0IIntv8;__xS%K! zq0JF{VV$IMl|M^&etnzIR35;rfIQkT5tv^<0s`JU35)kJ#`_DF(C22t$#&%Sj_mbr za=>Lqxm2v6iKF~bWr2MVj1NfAz#-o&VBX;2_)x&Kpi=4~G%@i|D2v2y^fM$zdoXNZ z={vuN{L+|5ms2T)H)dn&)}O=*I%xV597xX5r_kzD@;H|VaV%PfxY0aTiK$4K$t3eE zYqUR8(_dQjMj%KjmVfM{Vc??`%(O}Grn;&Sp@?2V|t z5QpN;@GCJ7orY2%(Tmzv%Q2QlG>tPLG}BB1gGsrFS9%}&$pKD-1OsTlb2A|OoR%8K z|7+7&qP+b9Ys$;5el zhW>X}HPs(9<(uUlO{BwL3TOv2?K(^?Jod{CPjRKQ*Y8<8g;3b6t7nJG$xHzv+XL`laLJ@GV zly2!WiisDGYCCovjnIlndt}A3oo8@g{q;vcD^;uiUgW#){-iuM#sgg4q);fa!TJ3I zS0X75jH>=Y-md7?N8N~ZY-{D|g%~OjaRRd*zF~{J8FfKBV&22-zq~;3W|8T;8<4PL zF5UQJtaR7wCm}x04Ct>qA_rV^_BZNHYPVtpM7*=TDJrdCB#i;YI_0ZVpkkuN_;r4s z=s3uua)lxzqbTe%HmZP&`U>e{zIqEm+uGZY25~rY^r5OYRjJ~X zQLQm%;+A|4!g~;35&134V%-X@BC0~(VFA4D&KVm$Eo+MJsI6y=rGZ>#A2g!0>Z9aT zf4Y|@Rb^GCM76AYHBRVG>QD|{xWdtI!cBBFY5eiMXdj>pm6ysw&Xf-{7f=?6;Vw{v ze$qXGot^l#0E8hglr|RqS!-A=r{T-Tc-8Smix)8y&aO_iqnkT>cmHg>F`PHs+2e=A>0Zlt6Ga`C%RO;LZ99tlkO{ccUGoKZH_sm&BAe= zquI&Q!_R|7&PW|o3Zg$U3(kdq>=VzZcIvFgvoL^sZBy*L+!MFXx*j@7s9Pqk^ zn!BJP?zzZ$Q1u-RY>=O!09sPxBg}aYH7DWee+K~iJ~1$MSAUWQ&P>1sG$%P1Fm2I* zM2;3bN+|Y?KN-;C(|=T9fPW&4-^_h2OSkz(`L<#+w_~w~TvJ_U?E@9nC{`bJW_7E1 zwEGJxx^k3Lb6wN%!Tj>lpxJmbgMbnuw`F1q9s38pviD&u8CODoaWL*Kfx)Sb6sb&c z5*5?~Q^OTu5iP=-QG>@{?Yj4LLGotVdSf2EMX3`4ct_2^G&^?6@WLaYNyn;!`S1-^ zBBfOv4WrTiZM#{=T`MTHh6jd%8q;Yq;?`Pe*`dO)DYIwRA>`x(P2aE~;~^;5M@*8U z#olts1n2penWyGx>4g95C@MB)D32L~QjlT7-7$HLIqMH6;52N>6X8AZF8SKVpk6$v zTc7&}4HdNHn4;rsEx~c^wAZ`99lA94S{kLHBiSeuhzW-EcF`AWpV07RaUP<0R* zH`I)z{E>C()h~P@Jz0Kt%f7qIF3xfW2t{B0f+1YurGDUKb21xl(Xl`?@Wcr{<7nS< zQTISgMqaCLt}q#1X#J|)1nWAee}@jcU7#bw8j>2tuIk*0=h5CU*DMc5qfv<;LEPQWJyIb^r83%5fW?u5hx2drCJ?VGjjmvxgx@_MuYJ?oZoSlW4er;Jbj$3JP?EuBe0@1#-bILX0_|T^|L&O z-}y3Jq?OZ%^#@gC8-zw~@&vE5(6aHsW<($kV_Lk38?91g6CmoQg=D;bDQ!jAz_U^m zn8zFO?d_r#>A!6h_3j_kmdu?zv7zkYUyzbOBPn{!$QXRj_;FwJ1-48vR7@OJS#4K3 zESVfi_G9iJ#vLi*TP01lw0EJsz8iAjYqFkf|(G(mOV9QB*lj4c{U*cKz)=7I;Cy1 zgBCZpv$OnfM`7a1MyQjGq9&qpzyvc9wo=*1EcAk@8z5kQiHDUi{}D3~kq|wYg+7pn zMh&|KsV$|y@%WSHYIDcdJc@O^<5a4NiX31%hOsH0sg?m#I=T@QTlv?a983b%N;m9d zn5TBlNz$v<$VNeUD_K9(-)uHd@yvRks(18HThbap!V` z*o(p$d`foHT|a?aa-Y}kzSEkj4chn&_jQp(R>&e6L~%H?8fRI#i|N=QT$@7Ao51A`+U3!knox05TyBzagbQ?tfVE@W#g;;;@^G zlq(y3&$_V(I;Ll6%WQAR{!Xx)Mt6~N=-C|5G1^x1hnl+93xV95_8OAMydaKAO1OS@R@W*d~f98n}ufCMR$FDeN&iXzOMavC~5ni(3pEQC}86U#mU8B_L7kN-o%vW=6#RWF)bRY!O$(Z7*=n3D7_^cze9 zQgV=I;jJXBWR~m$92s%|L`Gor^?^@OK&g*7m{ipo5L;FdO5ebgDpe8d; zN`-G)p}iFvmdfL?jzmlD#^CCTkMGBUzvmif^`u3Ky)Y7cy1s1fPCcN(m?zux&Dz9$ zf=c?!*=&wqG_&Ki6~tXHS2n`*Sq%mk4aTM+u07v*v-@gTui*+g{n=f z$ML%k4&uQozZ_GaBk{pXEr-wDcF62QH4AffPEMkYXyl>?q;KdenTRVGeQ$3sQ=77g z?$AX3>BGrVy9GGC`#zLhmUkfvmf@6_Z{jXl2j@tuw!Yth)&`E8(o)ZuJ)!8#1zbQ; z(@ajayk9R4-QS%xM>dRsgn%0|82CTo|5pzApfp%f|8xIqYVFB97&eV?V$Pl%kxtP7 zQ86>P_?13~Zp^m@$Kr@U-ClqF7cslPe6@4Z2J4>o;d*#`K3Di;P$_Ei6;zSI1q<&c zz_kUZ`n}<0*7inU_^h3D@41j)tU9F=k@nu~A9P8rpf}`TEOFbm#IKs=hA~6pK^vjLY=6Pu7mz6;mIQN_58URL#L@j&rW=ksIkgn4=IjH8^yJ zw#)J1@n;SIHZUoHFB?W23l3<5Wy6TdjVYmlr?B;h5r=8WbtF|s%zkJmjS-!ROxRF$ zHX4jpQRRj9b$5QGdMqg|4>bB)a3-s5%VX(XsVQ z_YvBo0Rqx>f$k=G$=I`u&A&J9S3C~5>Brx-YCUfs2(kf0VlWs17iL1J^}I20)Av8T zre`*+42Rb*^^P0KU?}U35xNv84H!~oh6XWovm)4Hn&*jDDYE4(68mu~7G(I~z9cL5zJgdNh@Pqv+C- zlnn?Dob~@`O%D6Z?}XeM@L>r}t%TzEc6Vazbjg2`6=xKg>PybZ?Zx-Q8n4vOS@9uu zU1f(KhCkx1M^CFk5xNgK`DBC+Jl@y?rG-;lhic$a?~F36oBi2uh*@8WS)cOGm_vrA z#W_zTK~@k3YHIiI=Db*0a6*3rON{gW3Z~ms%;+!<2T+hV+E0H>vHWdnE0C;xT4Mn6 zyqNFUs$K6d0V;E+AfKMAe)sY*vGlmJcxo4GzwgTa5*D{Nv;QmA8x)cHVApf6+rjlS zL{(Ch9ts$z$Fx{(rL1Gv*I-Xg%>bJ%BiGa}_?f3!Na=U~O6G<9_vW^d#7{OwW6x=S z$!@X*li;D})9dQq=rC&NV~`jD!D~OM#-v173tZ9*$r5v1@yt|Y zc)~5;L}Zi62Zz-hxT9OL06#IJP0{5MslTt*(f)2b0)-h)K811 z2f~Yi!v2B94mu0i((-mjnjF_;FkxVZ!;#Uc$j>ua1NkaZYTzyhD@m`j;^*6xhyy<2$wlyDWuXQ1#r&FCnm(;6pD||i(|T+?wZz>k@?Fx zSNUy$Kl8QZMh!S=mYOeF>pFDR2;EI;YD=!xxqb_iqYqMD9#8gAiTn0!M)qLU!m-P% zT%w_cJVs#X;bc^fj}tD9MUhN(iy~#LSk^x+FU8L9&@naHMfzbONXIEoo_-n&(6}2c z8S;|BC@DFOmAL{ zSBwDYx>mmf#=eGoBEJtQJ_XGoz@v+b3ZL%Dub>$!Dak=n_(SEiGnmN}cpCFIp6b!8c~_Zt1D){GEyY*j^IbP=^I)b^JiV^>&g8_Vj8-2 z$qfyQQ=?Gp$=L4Brus5{5JhE!q_*mGwu3>&syi3-Sp#Z)P3`AbW{BPwFRx}IPne1N zTo*&?pWa?yc$N!N^v-c@M&0cvK7p|$>r*1tMnD;7&I`NUwOmKgr(T2D_UqYCk9VD9 zBB7El!Ybib?Ya4My(j!m z6rT*Rf=kYwLv^vI=Bg5L_I>yhq4RHCIPg0(rTfwS5l$N>qlZF-g8~3}=}$kXG(va` z{Jtl9WLmGmqRD^aKy#{}^68mf^j*UNK5=N%r^iz$xqL8ZG?@FT{(1^@4*a8ASrV%80t4f`{fKejHB}lu^PpcYQ$=7@P-=9G;#<@ zp3aopg?C_D6RQr;xX)(e(4Ao51eTU%-4EYzfSoyZenP zAvw-*fFTP5px^*h2VVSD4NS#&e14q{0i;3tVcsfe#~pS}jasEC?rs@S3H()GH=n{H zQWVFp@Ux@cQ1^ndD#9B5u8m6g*3EhL#5w+NRpy)w5fdiB>*@{Op;J5F95EpHv8$zC z6p0Z5tBkbm%eQS){aU)A==y5Va+6=)T*qwC*PJ< zD_(R;jRVC-2;TG5L4_f!TXd*$3umXNg12A2_i>5=opp)kmrl2#9jf#NBX5JG%JfkS zq!KP?2U*ZmMDz)TNsTTsfDiP<`+qJr5Vbd|g!eij@HVKy5GMuJx=k>jMA zZf8}Zu&(CJRUJ;L7qb#S^du#&`oKmWTObz*tCU5dH}PGDeEM-~bYid85DEY#n+Z(2 z3gBX**h=rYP%56$leHVXKltSNa)t1^6{LVJ{wprof4k$ggooeb$kXxu&)avRi0l4C z8Fbk$XaL${5ZS;(fh0ed@I#JvC%+K`rpv8m>9yFL(F(+0+I#)YtmZ;N5Kgz>*}K$6G^=5{_yJ7 z4Frl z58_J`Fm_rrEp6BcM6QgbbWnq$Nik-bzvK_B{?{B3pmQ{Gk7-bP~ zJ{+6gLiSwIpz2O#+;zz%xBjeEGI?`gZ$h7rHAc#JIm?L7!o#o%a2Hb4X&?JQ7X#Nw+Nc6#VSF zGJI)=iGQ!$Z4f&=AGW+c!1!O75#I=rOA0pIt&{m*V?Wgjmf#3(TNyPyO%FY99vO}w zh>sVi40n%`y{*4q!lc=+*T(!N$QJV2@$^5HvYp{(Lh~{m8rOc^&6X}ZEa__i@O2!t zvpVjw3-UH4+2xs7E_uEg-R9=MKC9=y=>tUJReZ)>ja+}fitXh5$2$)Mhj^SJjFx~z z80rFUiFw~PC6^~4l37VKKHq+cuOgJtD^2UO^oT3$WiF)T8fOXGs+{-#6JJ;vLmj3! ztiF61TM=23>28+16Pp!)Dx!%65Hp8GsM${Q>@{@;g^+-4xQRmb<0wQat4#SU6w?kT z?e$QlD81{)@CokprEzE@Pue#YJ=V-}qIE)`98(0zej#2Wg)zfQ%BxkB$`>Jq{78-Z zQi~taiVtrH1|`oDF$k>INT>W^+NjY`LqzQO#w#aaP`@0fm6jePS|mxnlc!B0A55jA zyXrn?w&&;8>U+pFfP)p;)_+>PolN>P-qJmz8WSI*WZ=wZ16pn&Q<~N&+pICrYwtRp z?&t90GyTXd<=pRUNb>QpOpPK$%<-!a)6l9%p;OsXrV+57AaNvwAy>-qhSnKFD9yg- zO#V^Pe9Q}HZ5wE)5y1seJX`5HO7cB?ecca1v|(!YVk={#4^b4OCr3%?r0XFOe1g=j zcs~@rhs(yOq)*8cRa!Dxe@ju0CNEqbND$DMSbEmO8gpPMu>gU)_~(e@=+zoLdzr*; ziM!AJMJ1C>ez>-oI%yp=$`%WUDxK$TlqWr1xB4K*GYjpt?^jBLA^(BLn?qt}d;oOa z!??|$qW8B>uRY$_iAP>081`YF8$$?U@&|i@?d$QBFr+uM-%Q?NtpxOk>6-ERx(L98 z7CV9|eoZsU*x@pPglIJvIVA?AHURb)uPg;oE@+wy!Utha9&x#JUTG+(^DbZgke1ZS zB}A!}-KMtW(xpL{HX%2`{6Ujil~@WAgfGu;+8CFl$HZEnd{!z~1XuDAx3nag{QB$X zy>@a<)<~5c!PPvY2=Iw~8=^de_-KP_8AD<@|Ei8WY*m`ilta+(%)gh-z?`2hd}nj= z(Vy4V+`8gWo0E1Ro{qU|>}qWX9U@;BskKcuH}aJJf6v6Mb!xi30F1oJ0EgQ zJisc#1aocX5y_>(%e8ToBzSilHLU`xfv=I3-4B0j?I@|Fj^rMEZ)}xtLSFrYn^+ju zIJso!hZ?mkuu=S*wSa+I0Nt|@8Oys+#SPKpyJ_IEwZ05JpXag`zGJUo)2&7 z0s&z|q`gj*qYbkX=^tN3zsS2f2$4gLHdHD7DQ!~~ocw>Tcz={MLRWX$c)-iS`xY00 zI*76_XHwu>ijfq^C41or*MMT@eu8gxMWP=saL z43?OlQybsYBph76z|ZR9MHRClx93aKm`;+nGa#xcRa@#d!$)~%sWpLbhS_WN1)aCi zb#cPF)vHsNtDW|0A}fFoS4Piq#0+8<)}xRPY4p?9i>r0n(~LwL9aemO2NI#SKPy2= zS?re1{?E?ZTvp11VtO48RBrXa8%9mmbbOm-6rc@(s%0kS>Sx27Tx}S%XbuJ3YNgBe zy5?^3V423-LQg%F6}Mbs%=W+YBmKl{>ci~NQCz;?fGULN=-oHW-Yi|u^b`JtNA-hh zN8A1v4z2eT>#np`Np!74l5B(b#}~zbUPY1lD^VL0D2H`_W3M}p>ON<3BNj*EfIol@ zvbERo{0GQqjj-rdEuYo$T3ue(>BZXrWY3;kcQCe|$Sl6WiUQgYu5CgWfj!kS(2~FS z{K@?pX$Kc2N)dz*N$-&iWn%(vR0Eu9&wBkTHnKWXLk%|{uL2s1%Kc&~Yz7Hhm_^Hw zxGuTm+=xl}+`YUOPAL#nXieR1#;NTc*H7$oH$EtYGM%ihbwS2+j@oNrVx+`$=Ku?z{89 zf}7~9W$*oZWI{{m1fCavS!49uJ$$>&mKgZdvf}iDW^`X=VKBBs56e6^w01?C|5)j{ zKJ+8J4s-KUoKU=X(Mc;Xa6VJV_tYqg>GXNd|E<<@<+`g&Tk!Te@za9Oz9WHypL^N= z^@3qCB=H$4cVSl>P&K=s94^TAp+pW<&Y>F~pyyXrZa4Sw+FDokf@a$8PI*LN0sNJe zqdvMNNUHQ`KSa5-nTBj~Gxd0Ve+p}@f2lkGx9RA!oDkHKt~ih0#l@U`+>;1>E?muR zqh`%V2ytlCt(hMl+N`!@)wW$c-4-0WhFLG0f71rYW4Qx_xH|2t zSc1pVEq4obq!#kMR=Ois_2O22w72I8qr4(USktwZ4gP2*BB~9)5IZS=I<7odY~o|_ zJ&ui?Gp=0c&mEk+f zfA!7oY(I+ctc=IS$SP#6f&ESw@RQwB1oCO~I5~)%?qYLvx-ljeqa9t@eLXMFgbWU&8{V3ZS?W#my0Upd~f{q6LUtf#lN>!~u?eV)GKcx^f$C zWF(7-h)@W5Rehj9G!$9&o`{$d*)|IpD7L?R3kAo(&2W)+NWF@WX;XVr8T}}J@x$(9 zjhoky&NP~QDRGPzX7ktEXMGlkx9s>L*W9P$i!lw0oLMX=KB>_s3s#>)D3x zq-vKEC%wRJKP3qued+IH|3|5GA;`~z+>ViElZC7HllhUAOt547#mw28E5+86rl#Rr z$D7$YMEgT*Tv*rI)Gb2PDwjB*!8!^h3*^2H)uf5{celm=?Wiz zbE+)s-|@W8tJ~V=_4tW=L0i2wm`9}azk{cvH9n6Moo+th+o^+U4kbJ*l?hUT$EBW^ zqur7IV7<^|-KB9);?C;>);2HOq4CFG8Z`;%-d*#T(-#5`Z@;|Pu&+NZ$x=^GtG-yg ztvj}M8 z@C2VS;M*;u-|NP9KAWI0pCJ3vdkZ*0A=mq-&jwfV{*@EmO-)IN_wO^~cMty{Vn~Xe z|Bm-H-yH|v8a{;NKWC<&wjE!ZmS)imkMyr3>iOModUk7~Sd8GJ{lC;um<%JnN-rg} zR0;Pl7NWmbU&8S*`Jg3?UtYZ=VY5WBD>U3;nltvL;7Lu(oP?r&R|Q77h?MizJ?97{ zC6JHyLW`E-P#$I1Con=Q7i{79I-c&=J79#`05eze+=7ZflYy^FB&w;ER{vD&uGSak zVbqv0Mu*0FG)!M8JWwGfD=%F5E}=*=s(z2(bFIfRq43W#8MZ7QC_SiH{-x7Ax6fSL zl&;Nh!_*7Xr4&QdP(y(F&5l3j!UVk$8kBwIH56YOeWfVs*AzF_Uzq6C#+EY5Ix$i0 zCceAeCST~ZA!_3Cyldwui%*oMR$!VoafjnnF3JM6ed^TgchEPOsJ?Q=XHv%@qj*tA zoAQ;hd8B&fI!(P?r6pTwkP9PFi+5kJmFMWFIrvC3=Z;EZ^$NsfbByU^Vad@47Jkhf z&GVX@v`(G(Vy0w+pLlH3?!MOcyV8I@y;UM`GcL!zK!^V{|W2! zfWX=#B>rVvT4WaVf?#xO=g6et1K4lgR^)%^Mf?1IVi=ST#S{3z< zvS#?vpov%C6UO}eeZHaRjLh=&IpU8D@U(8BjJbgJQiHGkb>kDzim&b4O%0Y z8%x`_Aup^{k0$@3gGZyF`TO z>}>-(?QvX)Bjn-IJn3&uMz-rbEy4#Za?Au_ei=NL14mf zjocb-!WUvEe6e=tbLe|kpHVHQEhFuJi`HXE!eRqw_ZO=)0KfaSd8wms%jqTkO$fX0 zAFIi~&MB9J%jq-tO!m5;-|f3C=e*&6G3R(J=w?%qH4$R*9&NQ(pKJC!lr7}=Dlss- zwq2qay^ZSK*?$W9kxkn3GM|g^;q~#&Z{Z$fL;MT}!2IWDS$wC}Uyl^>{n=U2|EIou z?zGX5q63>HyIi$@g&B_P+c7c;PYK<%2Jg_@>k`_{tubhyB}tVPc`E6mtA;<-FQeJ& zV#Ir}PGJgoF${tI$U$;gwd;{01%ff>)6r#LAqV6I5EPgiLy;%$#!$!tSVHNvqAIY4 zCdTd!`z$>eOu??xspHS}>cx7rda<_&)5h#pKfBxOruk=FNruM1uP(u5mVx%lOo~Fz zne^P2xil1kxf;m^3?O+41r!5wmntAZ-j9=2PCx5)SWKx%WUu-dQ;HBt*np)^<&aG3 zv=C=Ab{&I4C%8z3(MV|UIBtt#%$LcoZJ8Ffi9H_e!k>yUsE+xqCs#)4T{TibI*4|- zR86n_DS$S6Z>VxR{Fb$vCzzZ*Mg>+TK7hudqo}bc=$l@(-yC&ER$}W_S$0m51TawT z$J51$t|5U%Xo#e&r08P26Rj~KtSk}hcx;h2jowtdPy*t@!cJiT;Iy>c(QIzw@%d$%_=WD50sM0s3vfbi!=eWFSQs08W_J2U`8s+w$O&^!QEzB)Y& z2{T^N@ohWaZ>xdUh+a(4^P^_N`nt;rN7iEZ&F8g;xN7gau9pSB10Q6H&-0YAe(}G|?m-3s8R$cCoRoJpK~?}jrN{)JAOr_G1@`a4XG_|fncA1% zpI?@Yc9Cn6$fs}cHL;$39EJ*C7HXv5&f{AA_D|ki?R}+^u8n|!M*`Y{CkGSWH%Fa0 z$?iM)`Q{d9lI}WZ- z@jQZba;K>0KyNWtXY6S;VY%2S(;Co(h!1@vR8F&;!K+PESbb=d?l{;H1Wd~sj_Y3(s{9~OS-xyU{1-jRz}F#`YwMN2r;qcJkK`6Uae?)lE}{m;-} zAuwl}TU9ws)yD5`hchlql##g<765i8fTd_Jio5{oNsK`DmIwy7EncM00Jz)ImPcP9)gb*FMaF2`;c&t zy!5Fs07lD+z017Hvc`6-`082&^Wk&G6N7QGJPe?|Koql1;wa zZ#VUNj;}jL-Fw~f`iw|`o-1vC?+s_|98MxcV>CR<51WLnzBXrF{!h1WmkOR|Ko_z~ za>-8ni9joZmxi(Qa73VbR!OG39p4AD43hI`{{!uA_rE=UdkXn7<3Efd6^Q0qZtie4 zeR~K)BJ!_S@Vhse9dBG6XuR1!P-+6@23t>bvP54*ZpQ`2qb|L+C%%`jg1V-nBPa`` zF>#3)Jc?<4)SJd8E@GQ;r4ht(f5hhgh$0;u#VkD~$)$y5Cc#AKkuZMR(6z#Im3Q@I zw!7A)r=uDf)blVR+oY_L~Om^TD+U;NTC-C zZ$V9}bpFQ=O)>H}3YLTqRI+1+W~LZoqEzq0LiahO$EqT-AoMNuzYX?XIwD+;3FCFK*}>$9mG#G}I{Gh1z1lEkCd zm3oAXjGVBs(OSIh0){w_4ksnwLKHc*H0Qb-c)Hr@ZI|d66?nKkc({P5jJvJJ^d^@a zBUeRH(-pUulCuU4DT?I{B@r|2W>N~^%Q7y74hq$uRYjC0g)di9C$*gl(qSu9cG|e< z=?faMBwfSP@oR<+PP#8!Qf#P0O*&155zTn1aP&4esH~%5gq0t^rfJAC+0t%FQ<)1{4vpvWv z^I5$2rfGlJxHQ_EuJ>9m?j!x>S&=Yu5Dy!G!m{!?cz)5N#o)~M( zqrcE|?~H$2wk*lTRsI>@P2C{{Of!NBPAZLZ`}wpLY3op}vI%BJ{qQ0)c^!#cQ<-+H zejo7j+}y3F+SbeU$PsAO{`0z4G0tIn^|#x?%n6ZeQE!PEit?B1UK?7?4?j)Ns@ctF zlvuKy*HcCEKrHV=%}D$n-PC5hdn7|{(`JvK&fp7BB^tf^HW6MWsdbV8t^5-B+D9SS9haSlGcI+vy>#WuuO-X%%*SD68gwLn( zOCAcQq}e#TNY932%i8Q)2DkT2ZL357PL1s>v%$r&#NCV8U`*2C&zJJty1haXhH5&q zFvJfT9?v=Nt!`hI{5MARLs8B;hnhCpRN?u7V6u*rGy#?u>uJyHnR+Q)L!Wy&kie zR?o+={(l_|4eov!wD2Wb|D81PRu)<@nrUJ?V!Z=#b0@tssD9`B%)Whp*=b<>3BLe) znA+c&z9;y$FQKyL4o(?}7v5OhZdvyx!_X=IQMI45zW%NMR&Q6)HPnmHG*X8q)%T)a zrsn>F3$PBhh@Yu_UB$x&T~XW36d8OF-0u_7XB>O6E2H>#y`kG!>wF&>p1E7KB2zhf z7N23uds*l??K}dh4lJMRqC=+zAX!#4%hhwjk_TG8rQaB10&w`B#|%^qkySjDvOvKt5)?!&UtJZ@i6HJ5NT5HAcD{+d&QaU`Z|6SA0Zs+0E~J> zdTPqNBXNLKcjNoZ$hr_AG83?ozNk^R;Y5dPI#ZdRLp0@NKY|(y{%E|Nro5~_N?PkP zm&^&>l2%na$3da}_gs7W8PzEr*kQL>HqL`4W%m-!%%Y;A`7}ImRO_(0x}CzT$Fb#T z1F=QnuP6}XPXeB%#=^F%6Hj0oYx%7Qfi5Qdh`hp2TdaD?*i8AF=g#H|CBiUuHOoxo zTsgHcjJ9(}!U7Inn)!1@RaAf&$GeQx|;60}hwN^?u#5g5-8vl;P(*_^LF z%Y=?4RdPwj$me3p`%FfjGK(;)4|OxAPyYEM$|5UMki$GV`FgssMgh*PlNlU-Tm z9iNqzMI}O%kU+#)25^+&F*~ewq>J?I)bvQ3emODu^8-^`=vq=w z;VQ!(G@sYg-M!rqO?0Sr{axR}_@F#mdCBGp1d{e2ju~ambAI@JH}T}Ov&igowOo)0 z<0)`I=`Zr2^ES6=Qrm@6$?o1*@R2c%<@vmNVcq|w8O1Ss(@rtX{&|1Q)d#9_f$-KB zH%j3r6WGD#EB4#p2eIJWKE6AdDGlv~4J+Qrn z<+;iDb+Vg~Au`{WrE>4tx;s(*&qB@3UhrHx;f5T+kV`KCeMEHceQCz zdqXE3-mr%UPwk`i@ZJeYje#0oNZ9Jkav%sxs7km5u#{^E})!5gLq z?R6l%SQkMX=>?jnVs|F=!1ifFTVi7374}Bp5^Q8-wzWXr_(yXi)9R6Esy!wGne&~qW{h7e9dg)1@hyHxP1OcBi68~%|{=9_a- zoF@;;zIeUe6Tx-ZZ$H2%^LFb$RX2@nU7u^6=|;H4t4rxWOl|(hK!O!5vH&S2?GBGU zDk9(auho4gEINOD+bAne_kSG*hU5GT0xxrElihV)xt4Ft-g*OJ3?^_fM;kV*mc35j zKcTe9mvW4##&y**pi@pSwo<;?Oa0zx4m)>X@?nOGrp{&yPnF?;!)Y8UqF^$3kXR|z zgL@RKeXYs~6ZQM7p8%x-D}{k&YMP)%6_-eW18(EH`X1h*@nwQHI~Ka7W9);6L5O&E;bgN&=BvKIBys$Wnql9BILl~Vx63Z+4 zbg601$6u}8%v`l%YAvUv`;z39s>FZMs*F>Qv7*>%UPl;fd8oa3;$UE>@WmNP>__C7t3ol}CeSt##Z7(h_*|2yHE1<*^GjX@<<_t>TGv<^}PQ`cG0H z0*BfD%w&%9%(Ku&6@!vbt*;iD8CYmPW#K99|10YJhEC5HWT ze<7*V^i}l62Wn085|iTRkDIx~e}f3kI64A);lF0)NEggKXCB`#_=^ z-O(%qy&vm&Zesx^11(GLRwsRt($Dd11Hbywh1>6cR3J;AMM0^;3xB_Z>7l5{m~qSV zzVBA|^VO}gE_oAXt*koqM}^G6JXVB}sR-YN`p2%>RewHZD$5f&!x@hgOvaBKIrK=rDD#{8RIMiZ3@gK7*E$O6ula?z_dh@$v zpE+*#f%Q7we2N!&D@rsQiU?zqjw4y{rY$+2>ii7#ewXB>4GwlvG_+QAR<+aM)QSIR z@yL6L=v;r`E#ziGKaiq1a^Nuiv1ig3?g$lGRKyz)b?HL+czmVe3HHSb*vrr5^n2FA zg+Krtge_fN*!u*Z9Rvn?@uSo2V?L(U8m{_m+drLo0s@vM1bugxW_mb3&THe>=`={~ zMyOd~2k7Wy23p_3!LTK88pBmcbjQre_~VI^uj5O!0ji8^go4BZf^KJGa0o5N%V2Hq z(!Q2_)KX@Gg3H3$8>nlaKgVTxBRUumR7=RG#t0G{QH@H$<4Kt&|NE8hcOJr2m`Q^* zqbc8oY*kfLwMVnfGR~DOSD*gvJZ))l7#=!{qaJWUt)ra_@003qg2~_JO0*NaRO#G6 zm`}{HnII33W)k;h?OME(@A3j5`$#6= z1sY{W8Wf{(biBvLpzDvfpaukhA6Lh--s_wAoxl&b#7rKDUFtB7a^0yZWOtVleTGhxEe;(t|1B?q<0*&KiG|9$(s+qX_jGzZA=(v@L%9^6M4vp@NBm= zbno#JA*l*Giio9pdF0k45l}>VeWN#*AifMf92Y)%B=O9+9?W)Jd8cz3`5Y|S4CNj3 zVp0M@U)y@dM>H!zD=v(*SbPr4!~R`o??mrK&*l1|le(7=wLKThaw2)V8XpecFo?)w zV;SEW@w*fVZ@pYffNs>}<9j2vLz7j!xV2G~Z|6%GaquPwN zEzsazTwC1Tp}2+O?(SAxi)#xhP^7p!6nB^4P~6>$TX5HxbMHOxz5OR68Oa{s&i1+H zToaqXj3A^Y7$Fm_^EkaQ5+Ou&zEUj)5Dc|56TLFx*hMmh362X_p9_{6J*QlagP=t`rmXl}+DYik^A2*Q(1Zkk&azDAqB#$lS#yaK~% z{o(g2#kyX6u${zc(3MF-?#`$S|3skOGh_R+WD-Z>vQp3vZ$_S5gs#O>rk$RV)^68C z)>KEE6D!hTj90r`*~?Vj#tAa_H_x&Jv-E&(h<9Yl;JxF7zY(95SSZ?mN#hGXF zwQ0kP+0;wVz$N|i^t;M243hsnAY8qpB2<(Ot~<%&0Y4u0? zIQ<s<9hc60z8*Xz^Vu6gV7RYkGV}9`TH48h?etgp zOJ>_2lC2)WWKAsgGcgHgnU|z;4^K?61bs@WeIrx_u(y$V-D6Z!fO_O^0ThWVC4+Uc zwHG8!)I<_k-7B>-;CI90b_Oa?4Us%2e1)*IwX~&sA>#luUzIRRWusYYSOj_vtNrEn zKx?v`$NSRB9X3OpD1EDiHLT*OnKh_JOqvYao^JL^7(<$Z6QfT9gg2l#>tNW03M|I* zTL#&AdKDMe_c18<<60fv6D~Fv%OhcMD78E64lfKS*bh3yJKD?4xn^0u_D1YGZ_i zOzSn%;HUs2N7bu>6A2diFji|4LuITN!X$RRnpSJQZKRBv>ibl;>5MpZw34lUr$y)g zv0Aa3|D{0aZcsl__%i2J*@z0YV$1ji7sAMHb6erMNZP8cm)G6YD6!*{Mm-_;EyIZ3 zo*ipn)c*t`^L8^7)1>`QT@kokM_k=;1kB{ks^$0+y_|pVCYICgdl6?UB}tcc?2cIh zUIQ0lc$UL<>SHN3o@y`K{6x~?h(kIqII`b4*(YtJFK(nz8J@pQ&5{r65paF@CWl> zh4o=gheCO0D|Ca(yB7>FMwlE`g!)uS(7&V-kEx=1j_L?M3~g5HcBtB8NQ@poDOkUF z?k;iKs|tY4dyK%eI9L*Tp1c5vH3sto?e~&;tNF0}THP-0=D>l-u5UM4E}{|N|ED;t zrK&a?M{MJ~9kHw8ozOGvD2V44&)=Mv_`Os}1$Ajt7Mr9qTMWX+y;Sq{p`<(yT=Pu1 zp0C$~7*4EL1y>ZJ6b56-C&wHe9nYaufgP0>5u8f+iwE4GP0QV3$L8gxmKN`q7FXch z%F6NQ7{}H7jewy*B<0HvDt8O+2QcUTFGh{KD^lI6lde13XA3^duA2aM)2K-KEG6VG zTb-eI^W}zfjRbe3dR?qh*KaH+p)~^JziE5lOjvNFEKlPdnQLFF8tI^^A z9V`%tlC_c^sA@msGVA@WR={^FOxRVoZLgwwSZ9Rt$5dYOYF+D5tf$Z$mHh>W zWC=VdUU2$iQ`ZYS8=aiI)HL7WhHo`PV4tPj=2)3ksdQ@PL07;9b?s$MQ=&~-WcLdQ zoGr=uox!wh2{O0r(oJ?Xf^cm~uEoqN8Pg50p!Bgs4Nyg*tE?9HI1Q?OIjQ@>@o7mu z4H3@{iBXOep!lccc+Zx!oxbj_5z0U4#W_$G)$PHKMsn!1XY!*C%)lJwXnlV$0 zCJmnA1<}~&!zdG)K<5LJnKeFie`2SZE~Hd~$73zN1QDwgly~35E}fjft6w(nkAwB^ z6(l?@DjF(e*65r531%4%`)x-ZRRxYTz`l?Q|DG+5v9v+Ey z)z>nEN_38bmX6(&=Cu#q?$4juxDnAmwk(>7jhqjWw+6?4K3V&H71^;dr`b&4r!VE$ z{55(rPzKNA?<3dtLi_1HnquLUX8YHFtJe#!Jk2Y1DI*d|k8uxaK`n3725%R~Vmbah zX+d3=r(#ggNm6mX?fTJcO z%hOh;r&z&%&nC_!*q(hwgDSDb{3bFt%)(mtKhy!cQ#+l6q8I!A6$k!fm|(z?I8+%$ zyCSr3l>tQfgYlLE*~DXIEr%X57Ft|)e%hWHxCi<4_|)fQW&O1jeLbB;W9!%&w)l`G zbPqn#loFih_;wZ)E9`sxgV3bK`>#1{=hI3#p^@9awdQ@CX=oKCIlkHoqh*cc&QkgL z<`<65o5Cl5_5NBir74PXp8OQDS<_eJd{`x0eEK)qHUB-gjLLwKOV7}Zbz4CpJ6M_r z_}mu4?y$GZ^x&iWip}%s=>&<25J;g9MAO|us3YKxDjzP3bdcuY(`C#!Y^i1UYV=Oh5`F?V;wY3s_9D`H{@|g5xi&M)>M%G1xcZKfOk)j_`^EX8@e(SZ|k!fCOIF^FzFob0l(XTo8#!Us| zRcx{SQNthxF2&WSmdc&1r#3I`s1?DPktV9?Cd(B~I_b=!obd?t-fUYPVN7EJNz))F zAWm=tT9!4)iXNSL8z%dpNL@~PgcAcfbOL>`MBM<7Dr9!=v^Ne5u zXkY|g3+Ani7K{^3%(_QH-+dj+n)$Mkxf7^Z7K)H=Cw{7-;-}Xz7 zEW?p2I9*334mN#tl<^@y?_7@ebaF1r6-3xG$R8!>vwUZMfW4@iOkDc9myu4VgLp-~ zAxV$boj96O7QJMCZ@c_Dc3!Umuq{`4Lr5P!4z`A$elrQ6Z4W0Vd!|WdVCryOHAqJ_ z>D=8w3U?B8P|~pHtFF2(=mH>HRQJV7N;p0X943`~N^v-+K|oeqP4(KS9z3sc5A6F_ zFqG}`Ht^;s_dTZRW{2C!e(e=!Ps1EFq{o(wP>-))KewZAuGI!g0LL9VJ^q zogATp7SDQX5#L@p8O%+~tz8j1k+=Rnz}@QkRuucoxK)brV^~-a{FZa<_?l~pBN93> zG>~*Ic6A5`&Fp9t5YTC*H>;ABz4>nt7F$abUG(}?gMZ!sus8!#=p^%8IaH|20gW=s zfOvUDT}`afh++)OHl&7Q&ypTl;f+#d>$woLuvD9f38spRtF~ekM`OfM$3kRQ4<2%0 z8oAD*#Cl>g$QH!yE4fV8ndcrZ*C7LfH^kWfG(QMnP#P?KXfCQVi z!<)4EN$QzKAc}2`RcuwXg62R6Q>~L1%?`-Q-Y#<~RvUKD@ zQkV#Tt&Auj4v!PA9{7^RW$wjNrDxB<1E(5^$H<@2$hulbN-33qGHPhFidD%FtF5g` zJUCJ`YGG{Pqt+mrW<}SRczhi4OV7#HR?|t_K1El`54Kob-u#0#CEl)}t~(jOhn-rh z`Tl!x#|3@^$E_3h*zE^`Vk`W9h%*CLo?m-1uIt;&cKQ9=S=r!ITMzXYGQrnqwVlCA z5gCx0x|;9c{35B_6(jk$UsU3XZwZu|L~gfS%?q{Fr#YFU(fxs>C) z{B>qRnP*$Y*mnwr9+QOg>c8RIDzEOPlp^`&-GYuAk|2!kyS*E^g52;um6X&%0CbrWbDT0h!MQ5`E5=b-dDl z#{Pr%#+u%@^@a9$Re0q&fq$V9D>=&j>B1-rG@z|B@-6|KXeQK|g&OcArbJ_$g5ghPqBrc46=E3>4C zbUc|=LWdv?$ygvrh?`mJ(J?(e4NuyFbCg3+P>2SS9y8v1kqQ{9)BBt;&NOQ-$(KOf zHE=lo1s&0Qf?h#`QN(oakTS!0`f7Oy;#pqjId0tn`o1=}527iE=TcbBT5)uA;v|hw zWKK}_Q7$Y9Y~`YUYk3(}1Tf;L^jT2jgnZevE`UZJE1m9E(xrV6d(QE-!Wrf5KxS#h zq>ZN_yYytU{v<6?7uEg-!p__M5V18#+Tw;B?g%30S0}r#j!w0*5*|}U!`UXlP}{Q+ zwZz^J5t(01v>ou!w52m)>nIyCfSko^Z%dEfadP59;-i~7b)US<55O7fnpd#r` z(=j1uj{J%l9)cg0Y#cOU2SB$n=6>xzhjg6OjDNAiyv%=)BYd@9FlxTl&h?*6w9}&= ziXr9=L~kP;=a@F!^xk2gFi!c}!S`G`WV04Hr)LvJ0Xy3C#i{o3k81{;DaO7jL4+cc z`*RWDw!#SL{PjL*aHV)=#7zv*{$dzAWvr#3v6Nd4=l(oxp813cX>M0Z_iVu86h2F%Ez-$u72o7hpRS;jA7a9@)Xfqp?t{;8jk%8GT0+#9AH zj^Z@v2byT-1&AD=8jg*s`+wo`k4*5vCGVg5WXeW^l2p5NWZY9rF5d5emQnqQ9gJ4;UY#H_%=2Srgq0fBmt z`qu6%Q&2!;$)SGQCd-vJ_@ndNtW8dUv7X+gBj(rF3tD|-y}F`1*#{K%Kqvf$%`+KO zg59?FQ0s0APf#04ttCc~TlL-orXbeq89g*snQLg02O_`@e$7q8@q-^7yv*iC?`xup z*-0&y0|x2`Oe|=a!u$@^mfRIuzWU`z0mDee#gICniuZWk6MxWFn8<~}o^WJqU(Yhj zBdhD@l$<&+>qNKHs&{8NQ7kZz-8heQz4<<=z`mGBNX}{1Zq&REMbv)HElYh{4?Kr7 z(^>xZZ2U``Q>;^AYpnl#_wsF1_o4@BG`S>I(1@BkUWt#?QLt$rJprXC(TvH8p-7go zM!QgaDmz?#d^ClZ?ZvSDC_i1IHeVfL*H@D%J6GdClx!u#vRa!T4|L7{Q_)e@;MN^n z7T<^D2p(^tRuO-)HLCv!=vdW$dvj1s)-W+38|#dc2lTjv*o}$E?8F_iuCZ!%_M3z4w)z zrA^2B{pGnlr_XsX?-`PpAj(FY#Gs)m%0;ixZMYc=xYMn@m}Tc}G-3)r(=`nM5C4927fUPa^X)UFF6( zXFq_S(#wDUr3r?+TMatzEN*C=|3xn5djHqYvVOVS4-OmIK6Q837I43O z5*%=k6sJg6-L+q4QA}!VsBYn)8UOg#(zpKt8*|eCaH=$dRPeS&hRok~YOCk(oNo-~ zTa)f0Gv&qhK8L~p&_gs{gua;rE!glYKFu&kF@+#V@At2x;=!igu5}}SnLRr(0_;9@~F`CD=D{lEtk>akCm1YzG%1!4Uv zkO2Y$>|j~sH$JQn$5ZnU1Y^?3Rt)A|vy95L^_7s|rSQ-aVpyuh(XWt@AC2_+5@Xw) z+~=M2WI_9{t>>7`tQns>d{1+?7v`BUAW8kW)4D&C7``zfF5&aWUrE%KQT{CJsoh2u z!r{%!(5e1vbeG1?&O`(s4Af1q4!x?Ml1ptM7@tbdNcSvWZ(yB`Wa8pYvy>T=9gFFQ z$O@ChuEu-2QW@*1Y2r1me$*afUGbP3&L25$YPetSWv^SNp;2H#vEhF1_TP+2Fo};;9KCPOJH<{{t^^iFrcn%eT+m7cFjQvl~Nm(70-&#IoGW-YoTn!BP_e16l z8quq6Gt*6m==P{Rz3zOjaroFBZ?Ld>L^=rfUJ1CfX~;G0R>f=OthD|7%+}5`zh^6pA^rGccG~0Ak)P7reFfN)Iel4+ zXZ2K@2TZbG_PAAnCfhf0;>Hl#ly7Cz2>~h2b{&*$ zzU+;R5(HgA5uIX;(QvcvtoM$m610h|=U#4%@?&bw&)7>b7BX#vr#f%_CmPwWKFIu6i|J?T;dFwLk{NeC|z1zMeR|Pid@yOTy-YU z{u?6=c^P-U4Nxz(TDE?xBe8FL{l74(CZ@*n=2vNwNFvz)LvMXGzTz3MaGC_>T8~ zfWxfT3nJLoeLBF+7No%+1#e5D^MwT<@CF}E)YwCtUqSCM%EbKfro`a=VzT5tFEP|~ zAaV~tciyBROm=>W%tm$T?Z54{3e)pdzBEYmHCAl>DWa}U;%@M+-imA4Wn$T8VGhb# z<6fMb%e=pK|D9D1hPYOeFVy}}MYgWxWwB|!f{3q7YDPSSq8^YS{rJNSt6*KV_=W#gynW+i>`RH0w4=TNo8QV(rr#UW^w}VN5RRKUH1(IbP&`0BrS0BLwd97RWl_yHDu#i#orXv)J zj||f!gqy8!GG~3wcz=sH59qLUQS!0UTaKh1rCFvlr3y>5@@8uoHU1K1jcjAI&r*8^ zkRUEpeVlYw+tn;Zub|| zM%Lwn9Ib@XF-AX$xTO*ecH9#PUvHNu7k#4LZtEx0OPnI5v(cV?RZ{$Q*9fH%`Xy>i@6z?UgZ5YWWxV^Yx%fCd!tK&0B}{ zaLr?N7njWfRI!#E_%y8$enrEaST~q@jUt{Uoe#RayT#)T1)CV@kpDLe=Q^fUX$sO;y1pZ`n7n=9XJ}fd(uh=N(}GXFQGTOo=rghe3U;b0$KMP z-wQaKt)n{cyqXD-YS;7e)7c5xG&>RN~ z)~R%?2C(8JAG^^jy)%A#OsU<>h20FB?CGS;(C19$RKezAihV%j`#?VY)OY2V=W9mv zg=PkVG)(c)CX9gSO{`8C%00Chq%asjFyCUr8ZT^6_<(IHB1WNCkM{^s1d zs$A??Szt*KO8#;K^&atq*xz^Jl!Jb=q$6S1`{K`CZ;{ZutYjd!#(MT+Xh zy2Z%oR-lPEYC&9`e!!EMGcrM3P9*8ZAvATLXLnQuy#ieZjcyWiO zwW_Cy_l}nV2>9LJy2X-Fv$V4kvCPPx7&pqI;+3=q#!@JHe`yu9Fdyd$DZK>hP0d zlfajMDda&*CVz&ZRDrU~B4uIl!Sem4$n#sf->F$8>d|6QW0%uo!naoeu)osGZc3ZY zf0yYlJ!HhVySa*pc~9^_ol4xFX)sv2_){?Orrb`dZe96_Fr~L4G&n&QURO#HA0~^@ za~0#bEegi;gj7u*b+)&z2oOra3NsRE36?r6MVi-$y+jc!I(S17Fa8ugZPDel@q(zh z;JK=QGVvK=gG6=_V9keaaj``S*zmbu*JQFz3DzMQ)KAMR>#C&?Z>9bu$s6WFxlC>`Awyd#yyLkV4loe8tzVH|Bv4Nx)AJ+ zbpJOJ%7^b*Ay}M!IgiSqI1VHa?`v>I47X(9@xVD;h}@BAbxEKYkdw^4p(I|%ffi8Tawrm2eZxk)7*9@>nQ>P|F> zeN|OuS6nFc33qD_ObL7rGAssb=sr$7*7eDXe2&2U>1{V=HFF|5n^|L~BuD2NM)9;> zJwSGe$RygJE%frw#HA=D%}Q^qkFA1-KU6^b^G}NMSLGA}!lY!)BJQ-sP5+bEA5je;-0mtChLOxC`eui&+8SF)r0xvaxKZpGWY#+=jUXogmX z%>5>*Ogwoa>4)#n_8V4ig1>Y%~ zBsLBkGV&-d4C;M_VV<7S6{m8~eJehrZo=Pt7ZfSHM9N@0gY8yR>odmS5ZP3{p7U_r z@olTbyzjE#d8CNHG}Zt50V%`j%a389#9@^0ulq}r@K28u#1IT0V|VC4H>*zXsHAs? z4yl_!A@q;&&SWzNQjN0YJlU7a5saFApx`mpSkT~4QPD=uEtz5wy zrTSJWBa!_vek5a8c41oM|C0sbTp3BNzsdN%i!{ueJ+I%U9gHTvil11hgV%PA>_fz( z2oVh&xJaZ445z@G#ZN!h?-6OXUxxhV1%}Ge0$~{(n(GypE`=PxU!C-Q2KE-uYM;pf zP~h*Z&3=#<{Om}jR+K1DQ>OfS^s|@C=W6$Vkj%qF@5=$g;;f4V?~akC%H-ta9hJ{l zp(e&|SAWG~hPM5bmY)|1-|w!N*-9%u)h+Beeb&_0X47kXiLO^h!1|>fXfwxL5e0=c zQQSZGV0pJ{t4=8BhU6#NlYK|F*ITKBbwM&UUCfBNn7+=jrTI9`_+X9^5xHnOD>yd0 z(fCFuzQuF(3}I09551wLBA`UoM;mVuXjwM^o}?e&R$?)z`OFu#bIn(WQyJCCIYpU5 z(>E>_5OLuBtnm^ti&abrh%%(OWWai?Ljz2c04;T?D5S?Ej5TRU#;xn*8KrM7LlIPq zC0z13!#@}IWS8p!8Kr4*kGFv=B-JO1wFgXncm4Q#$SBw>(!lV|5!py8>+gw?gZWL4 z(xl}KB<}U4nhL9g%qap*ojV^^KZbXjKaN1NcnrF-tk%gbT?>m~Igtzu!_Z^H_`kRl^yP6=;{BBnkR2$R}w}=9H#`R^0LI*HkKFPdwT*kSR+yqjojn&2+oOw?W!sxE2+z6 z_2m28Jtm1NH$|2_SlH%6a7@g+IOi0i>C+KC1iVR!+q6DdSJAxb^KBs^7WVKIXk$|o zk#aC5uzzR~g(J=tW*hY-Ki z`=eC{!Cah;(12Titem`M{^u8yz=zTjvOq3y0`jRZPmbH=&3IQc?}@RKG!>++8QOAW zFG*)DO2Tx~VXWVyf#zn?@}CO+1W4t;Yqsq-j!JZOA|Y7kilVUCYMOSBsC=gn=K?Sk z>B3VLQuJ=O0*FU0jI;|WSR`J>>Eg6h_4w7bdWiWmP5}T!3G||dJK6XnT`VdD_5>1P zZ(AdUdOH~mGXzSU$!iipq3v4l{6a(dk*_H%F|_hTg@92W-X$)Fz6SJBH!5u^f+)RY zxjMIjI?I3nDSLNmEiE~{h_!NJJ7NAjtOFY(R(Hh9YZI; z!ix_o?s8V@_DN%6P_J4-sC}e}d&oOCfxB`nHrm!3ez!-K@MBXWy8Q2SzIsP|m-DEW zdKg2qTqKQ$S*z}x)P$;i4W9IV(3HfXgi&TVO@P4$S$=d@#z9zBR|`SL*C&R))KoggQBc@d%t7S3d}ycDkE9;n&%%_3GRUAYuV!Q-qII2Ve9ycm+jfBnVFF*uJM_C!6xO>4lJ&QUV2+Ag((cd6YwWt zK?|S0XCEO}S1USTjSy!l&x0A=?JN2Fp?#{|*=#_4*)cMDon*{+!;KT|PD-5QW}6%E zFe8@V@FKJ(cBr8*c+s@#{M6GE;eYP8s+jrNwY;*4iHQj({`mNK)9@)H3{&v%No=jg zw1*znK_KwjJ;>{R@cE42Zbo@p76{zPc;AR_cVcB-9X{3h|1nSruRaJo zKmq8Spo3@w{wlU%-dZmtf_S^KKgiUCt7m?-p&lpQ*mw_W@TN6)!YZp{ol^h4YO@;F z)%ez&6`5l9j9dQ7)(AtClagqNcg{zFjfFR*q{YI4>DR=jQlPn>N4@+dE&;DKIWVK- zae}|SQAE7&ivm}GjR0{2*g;U*=(tYRR~ruqV~AT9ffVRi_At1}KoXjKRCIZGIzWYl zJkfAldam%~d?AG@RM{Grr#K|HicOEB1f;J0qot<3GPm~hmp&&ki9iTH>C2o~!jVHp zh8&&Pk%P0XVI?pBw?ch`RiIzEBZG7}LM1N`OyR(_l_0jY*=$`y$!jV8bE>;4JPpko zheRg1pxi`Na(T(__M-cb%O8I{Z8uN7@ZAW@WU7`{_&z*Na9zhPioFj@jp;MaFRY<= zb3huM{u{Eysl(n0QF%r{#DEX_RdYv%tg1~WoPATkmX?f8vep;_D5fmnOPbC=te<=C zVft|bP|a;Vn65wqTo@yD7oLCh_amF-3GTn7f7@Me-sDjlb^WyHDfYITz&aGmE{_N4 zycb1-LU5JMfiR}Wn1PM=#(p;SdQ`qaJy60LxrV;_NQKCx&|zEwdi@*^AKi1({Mt>GcTK+qPNc%ZF-n({g}PLU#l0kzV{DmZ4_%~2~3geFQVs-#ip zeBNP7pFR^OY5;JA107-q7RB=*+Hb>yXTX+C?#V{Aq&-g0k5}CqpaNm-89E^B_w@D=yv(2EKkiZg z>3%ClUBsL(e+TPoTfPMy;IVNk9kiQ`|G#^)9yL1prAnvKJzn3q&IbDTJQ8Xq>Y$VH z44XJE)tF@;@bdGU1VHBR*Mk-}{77BKre~XSK3|GezaZH%F|RWiDL9V>Sd1ig`XeQu zv{iS$tu%||-wv)AAS*>anc&@6$lW(Dwu$yF=ASi0u{~{6wI3UI@&OaaEdx2XTor7m@lxnVIeLdnQ=x-kL%vI=>V0=FnVt_gFerxyeX+Fi*wHW^#>s~cyH8p5CgEAY2v6z{l0>SKfmU2tptAW`-Mg@hOjLy zJs;HRJUBTaiWDj#0AqhRMM?GhZ{d0SdsTk^@j-UbW9vZ<8NU;3JRaeqfBVk+S4~ay zF34TR&@WQ(e|EB~o70l>OjmoTa?07y@Fb$K8H;3OBxrq}A=Q8aAu1%4@#?9#*4*?q zH$JJ8yGDGtc=5$)1jS~i04*B!{=;5GTL_qvc&@TQ;5erQ*%x;SFc z{t~tOG2Shucyu5!c76oKERnlz5AG_g0H*a$h{86ouqu)B(qiT>X5MjKHUpJP-#6&J z6$@tR{1#U{6^>r3C*}n#D6}eJY8|9=dM|?L#Q67C!Of}L=-{x`*ya4E_|{%OCly%p z;=B8|l3k|8!Swqi2d!Lh{4%|~ivM?+!NIBPk<7J<+Pe>m_YNHjIv3g$)&=e8q7kxA zk3Bv>HNQN3yck3rE~A$QRaK4%TWwV!=qE5PpH^K*Laqj)Qb@w<-eWtTW8Cxgp8;>e zHrDD*{3Ggx_e>PXs7%sr6kfGPr@mUJOV6EM$N0A^*sAARwfAn-#(spVsz3?xlnnAopTVN}<~z$Dpw`wb_SRGX=WJ+74I!SY zpY8h(g6FA$dlY``ybNf*K~FQQ8PLDq=m(aX8lJrlReE@yFFZW17@^fQ^U!Ci9z~ut z^IY2JM7HR$ukH(SynB{)1kL6Z`YH{md06%;($VK#do9`~hCH}>weviiYTxMJ>GL^@ z#`1`eW1>+$7%Fq@g_>E;wlIF8!~^0^E&Ud?Z=&8=1D5kC0yvnJaPI!?YhMwtj{L5C z!B!*i&l{ULZIpQ`3E5f0QdRL!!qN|OJ#8B%qyCO133Y0Z+qDcO3i|#x1^{D9_q@1A zaNso*p^AWj&=>K6Us0+FWFB1_sjsTKWjJ`^dEQCc1Pfdf({EZ_aKU6jfNBOmS(Mk1 zV8SRlrLS=aq=@_!HMu-1BM;K-!2pmjK-}w2P;0(oR%!z%@ie8W+36MufQ7a!#jpxX zt_lTV>;@-lXdZnzviSVRbmYA9XGgLisH3<|{@c1Whxq_K4*NP1VE9LT zKj~U!veKnqZao&`zuiXQM?6+p`3t~j4f^N?RNM(T0s{^Fp9|d+P4F&w4EZ9Pkl(aI z{dLANO9g|&-+|FQss{^*t0=l2AIezp++%vk7(nHu`j0;#WAjNIGToHzskp>`b78XxuiXmB*O^LD_&$aMWSj&eU36=!*Xh+e+9 ze*?d>n15BrClDw7$b6D@D);?rYH4=UyaX^PsuC_$=bBifkOFjwU^#)N!=E7${Y~>l zokP#q$^?#MCSZdJ;$~?R zb4$NHUXCBCc#+5d*Az=~afx}+${s+}k+5yhee=Gez!ggadzek*dlh#K4uzm!grV>r zQLy^+gd$O9QUaw-^g!QIj#U)R0i1RumeCYP*xyg4u1?3{F?Vr$h9Z=B#SOX&yfP^q zLQ22?sqC5w!ToNwFj-QLpAxM@4qdHWu-YSBY1EC;^N1%Jt@4ii#NFyZ;~(k6YOihD zz^J_&6z?}>++1%u64P+HT+u5Ehx;SgGxPT^b}Aq|ppT~#H0IOL!ZA(*b^-ifXJFM$ z+PA=t;_(7Z@uz`OKjAOcCGVPFxh|f+G8s<6Q26qWkZkc<;k&9}_kIxF*4cl6;S@|7 zCy7Pj#c)#2_`R%ENW`Q*sv)%cQ^&r^a`z1$V+(Ri0elYm`G5pjbwZ)W%7Fuh&ZJ~ggg<0T{!T#v4|fi;M%X_L4~@=$iuBYl&yYH9T%^+%q|so zn(r4Qm5I=JJHJD8|5IN^V7c%_`cy>l^zH!m-qI0%Ff|@7XXi-e59$=!XrMSORbI+Y zjBKM}Wx39ZABEtf#!|cFTgs>_>d*=_#bZGArv%E%PaG1x)-sy$WTwB?i#)Lw{&-uW zQL%^ol<$JBZ2vpQXYxs=;S>(rh&7=Jy7I;0;VrdMVYRDin4SJ4k+o9n^jVQ-x}M;- zJ_<+;#@g`0C)v_7{V6Zfoz)?p zogYzahmUbVr`9;D7#^#&x6r}PK^sUGHY=Rhgs?qLctN)Qv`S))sgdnvA|JDi*CkW{ zA@dM{*l7@pASDiVrd^uFNx=`R8ky&%*1Y(?zyAswC7r%|thbq$m$hM)Vt@SKR#=KH zng;(c{O(CMm58^zwdy28OD-+`0Tvrb18@y2T@;t*AOr6={iL599iFh8^W4O0F>^Ak z-!EEC@sgWtJi}q|`(1x{D*b2<0x)33A9Z{IapW%~j;oOU8kNkvhT9>-ijie(I%UAY zMkxK0W$g$D33GCuh%=pM)zdSuC4Se%K)hBiTP_9!&AQe$ls3DamMb zPgf||-Po*wJlP^D%gQ4D?fedeb6Rw04dIL|m*t8-nnysZW?^OYdEA@?1Q+|P_^SR- z-&BSN;&0~gT-u(wBY{idHqQBL5O@tk5I~g1X|S!sSOQWour0jq>|C2;X_P?w5cosW zU2Dt0&h7eU9bq)A%@d}7Q7{z21|d~hGw%2)^%dPrYw;S0djKpz9HkThdpikZLd8L7 zxRsH9e}Di@n#{=s0i%Q?enD*-$iQX5`J0I{w1$h0puRBtzg&Pv@F9;Xc00krq}M@x zYC4^ttTt<+%N(tAH4(BGEg=#!ai48F6Skhs%b;G?!H%!ivW|8`j?QG4oJS7z;cr5H z#TIg0H|;-Wr)7X(cXyM=C2Vc6>V5>F-fRN&+!KlLvV6X6YIAljr7(9m3AM(-FY}Vf z6*~zb?riWjilv>w?m9HOW)Qd81$ub?=$eJc#;2~ zHyVX(K;zk9n-?|!876$XAwgoX50GnD^@WX`UvfeqSk~JxGirboVWM>_ldm&Ykx z5_yoQu8_e%!MhlR@-sj20>7+461Yl3Gmv1h9_}RXL;|qT(I*3)ISt9d00i8(7?nFt zWGvg65a29N#=U`3hIn}Ka$$AE^DAOgVK_LBf&r$0VszffS_T9NrF1isq0+9VeI$<# zEHYI@APi69QSl`~ce=1jMH5K>v*JFt`&##cTDcr{#ap>L*2Nl(6upitU;hnQE(z@8 zsC455?Q+zqN5beXqvK9dE!Ib!zS|~nM7i{C{%SGlYd*AE?SkCPns{H{o&fzB*4$AysiS%hkSb`mRnfUQkD;ec*3fXG-m7I z4?@JXG){U?r4SoqqITXM3b5RHehKmqaiCM8+jHV}SGbqollb{%rBwvbBMA({YXA`r z!W(h76N-J6x4wKR^{W=mQ~hH)^kJk1+KV*t+v{;TDliLg0GP;c{ARAuZq#*qnYXau z7*w3KeK|M%Pe)b^`twRlJ@ge%R$5cJQDR~L05zx}5wvQP!Xj%fu`Lzi* za5neFiHPbr??Nde+u8b9@z*Ee^3>rfe+hU3R&X6GFHkk~ODm;6s&7U!q5enM^kPcp zfo|+VWWbhWu=pUJ7Vj@#UvB{~3&WiY_&vN|AGI3B@xNHm!%SnT0{|{V9zbI1FJG_; z@lmj|Oo{v)yHW*FV7fVcr2s(G?x~GBS&DszbNP;<38feo%>%{=*H$eL3F4Z0t%Ra7 z5@f81!3HG~RYR~pytX_`Z<~4T{C*$_LSdph4%uRum>D#SZ`W)Zg z!~%ZjwTrFwpp&Je+=yh>_11vry#qE?l3T{_7*qi%ALu__t;q3j4yAl8pWz+ zcrf{u5>9qvJ|90kUh`L&ygzIQE!ihWY(-zQ5phC+b?1(^&2Jkk_Vss)vsk9aeygMf zL%$LZ9KD=2Y{&y{)@En{95-9o2_=)CEl+g^btzP@C(5fUysdqDYl*)chK^RBirL2P z^rCg+S?xh3OwYSJC^_aNW`N7?1eMO$m2wqfm!L5Eu)GteZ!03P!kNk0fvb&+4jT`C zJNLh^HK2Ee89tkqDkPcMk3lalkG#CRn45ko zu4Z|~tsWwu-NsrHCO%U$3kl(&R=)c{3hp-vb=(-fbBtX`jb@jkz*oJV{AeSKp;LlI zr}j9?Kk>VV+&{{YcV4}K(_ND{8XrQkR+~-SFA-Q9i=dmxaJI$Az`d+%gZ=7fxmEM- zK$FFX0c=h@)YdgNFqrPq9`QRMMF9;VObNB-?i|BG@7L2nR^F)1sTXq^2n15hMH%br zCkU`^%4?}&eQ!SdLOmJxKI9KI@)RUg12UP{B~pbL`3 zgMIlz*+=u%ZVo@oL9B7A@FGAai4}?#a+v9wz>z4~9@J6~msIbVXdzgF|2EHG3}3lP z>i%KJSXeNgec#DmNhuAFxVeIQtn5VZ&QjWA!X6uk)4tOW%Zp>scOjKq`3av}(OA;Cg^?Gw7BV zaOnF-CZ|hAG5cjSR;=>nuDk`OOo&kIv+tT&WIn;^N@*((crxx^lo=5;OCx>C2NJ=C zhL$BABN6Y13qSIJ(>nKwH^=o!z{TlD=f?A?>7Cp3a63%##W3oj=+4LYGuQTYM#j=| zD45|4wfr80PC!AQr|9FdGMCTr!2>^jNVlWy76dsx!NGjTYU5b>cF5s*m${f7#94u~ zGin155I+xm4gVyZUs2c}V~;Pr+~I0r#Ll|uy4>0dt@jr(6IHmRX!B55G_PH9RTUBv z#z)tK*C-L=$tqHz-hVF8U%$OgNmUEqug%7aQDHju7MK#{MOAfJPoU6iYH8w~ZLCv@ zy+h3+<|<_-+nu|niAB8*m-d>T&mi;7&T3|6u4ZQU*&@%FB+&W2DOA;t2-vd&^Z(7d zPC;Y;^x0C@RZUG^9u=^7yR~~%U)6C`Y^pSVX4EdYe{lctbB)2I@#5R9&P*p4lnTuCA*Ez;Kx`&O#4@^diSz&CIee3=v^o-IpkyD zkIRG=U%WzEqTr8<{DH1OZCvEt-F-&+*}zT*+{j)-HXS=Hs~z^b1{Eh$Pb~u@=`uAK z0$8;40m1V!Mq?lw7FH@2msG93tHG}|>~<^9*6Xp8Sn%mkUIgi}?d1BFeQxOq69ogy zZ)3fB#Ga>|^?T?>Y(_u@%OHpeKaRsJqaY9Zf2e!Qu&TbTZG2JECEcM&HwXwDknVKT zDJ7tQq%_i!N;lH5>5^{gQo6g@fONxu`8&@!=XtOHr}yLgg^O#|UUSVcN8IBcbC6<$ zjE(Vxg}Z)s%6O)C%7a3Z)~m(dJ)9k0?h+PlpUr#pOT~tK&zNIvn?#1S6fcKJw^CZM z@>=E23*sqPqUCv2Z}D_7qNr9ODP!hR_)`2JwN@zANSee6i|2<72!_zO$ArExBCV#~ z7J;xs@CvP4koEqN_}23!&sQ$HbA5pA^v8MohP^%PeP4O5`vE@earjiu_Kbz#AsH{5Z~VG6te_sTQbv^JNE@oX@Uv%b z(8)A6&mu2B|DnNpyj0s50jN5(Y+vbM91_DuF1x#6HN<^oTvuPQGn{Cg!S^9$B`x)L zTPZAIQVLj|CH(C8wMfZb9ZL zcLg*)T*^)-XS@DK2W=0E%8I9-S_Wx6;n$n0vu-viy?hb2j~?H=N5kC2{(OSyHq1&l zxxFxm#sfFwIw>KDy43FGV<@p5)gN8c^3HZbxGr>(FhfddJioM zEHfe3J({{=(%oSxR$t4izKzI>wg=BHh2 z&GD$X`Q|3bUKC<3GBU0eOBSv}qZ=F3R32w5XEIYpuefNyE@9&Qa0j|GGAilfIIA{h zvKe#6Xawrtxe!Rdo3tY*A(A4kw7&*4bwf%@E~&lNmvKc=OkOr0GL`CUF}_KHd!pd& z76$dH1#4B|D5^Y1mJ0sPR2WAgEEvcw^x_pmVBg*3X!L zmy4t-`&Sx_4JOam#EYeMH?)+B;#|g!nue)fe++n){iUMQrkSEFhb_s4}AirO8x zx+Fr1xQ|EL-=P!tM9t!ytl3m$moo*n2*5illg@@4oJ#tGFWz?~3B{>kXc9utuVMQ9 zpAW^}Ie@OI_wjLWcTf`o9VG^H7_8gXZ!K-#BZ*m|_ikjJQ3Wpc=~wW1+k_DjeL{Sk zxuwPME7zr_@)pEzKJ(kgKPu`ger-C=GOnGw-Fq*l@Y}c6yuHiqCwQUKx*sf!$52U+pYDc8)Igz$-q$ZuwZCaw;=7ra%wZRM5t+w%m6Srf=>voEjZux zz$0^vMGZJt7L@*J2tsp53zJK@=Eb`{NFTI)iKcq7B+8*x4 zc~wPxeiLag-L!j$KX`n@qhD38zdrOt2_+g8F)QEi9N!*&br^VdmL}dF@-F^JIpgJh zh<#hj<&RVgNj^hd1IH<{a-XYX>+OtFa6P}uDeIv`8)=jd&+^|EKGlSr2G>CXLW}7FxWuw*zn*cLoM&u5QyE zYsttOWT_x7>-KHuyVI&1FK|2H>nfx!J2N#AXEE8?ZbrWM+mo#6*X#XO4;H^FOpWXZ zE=qkxKV2@van%fQRg#4~;aBM3W~qK;5LNLjd@01Tdtyl&k9tE6jYXASEFZs~ZuY0`WNNSQ)zY)hc3Bn~x!-7g^ZO zO@_?O%uSfCNy@YB36nFwP+y<#>hsjtu{hD8^&oE>pdp(B{s`OtbUMCohaUR-9 z4AQ5=qTz-Orv-A`&#qlMZTfzaBGMw6pX?KxDXFkvrSgkh15QurC z{5Zv~uUZ6*gq`ock+2!mKO|;89wnrv4N{7JJh?-`T=LnRT=vlwFkSoED600gGA6ro z+1F6up->)F@CkI&{Z<@;g`St&nLZw%MY`zSguD0VebQX=vhHrDle8L2#{@#6Xp9YY zlVcMFJm7-S0v6Y1xPy0ZS6u{D(joc|>RNg{?{+GFhfrNi^NudmniaE^HeSJOEvbcZ z5e5bapI}qGys79?>blywcSA5)`I^PMO|5UBBj_>(hc7I|FZ&}@QSXA6=$Eegy>@3t`AG7Dz<&_nMJ*MFN#agAGEU)X2WzY8JNq}H#uZnD@;?~>4 zJYQYrC-egmC9WQMutTCzHsj+V$60N;>41QcXgOtNc2;&2AfE{XhAte{PXrrgpR}HC z^|rA|u}RwqDqZXpAiX&7#YW3FkeN=|nVqSRz zCM2!>CFXZOnG+4XT|6u;b**=Q;XlJ66DX7PDPW|&LIoV?JT8xfT`t(VxUjlNMIAQ^ zE6t9YS8r;IeE>h*-jVeeG$QYHLhkN3MXyPL7s{!Jm)9BYaP)C38qX8vf{a>PUg4(P zdO==Zr;Q|TP$f1TMa{4IH>(&n(sx-ziv)hxajE;>e0~yMkm+P+X-Nz?*s+A|iC~KNTrOpBU)HZalYN57Z|rk(4C=!7Zim~Qf_po=eKT{D#Xw2;)4o`z{e)qN z$NBD5&gc|71x4~88r>V{pl#x|tEXgEO3d2Ru3xFnd=}=-pyDhphCP5%W!HFXbW11w z(Xera?K;4~YE;x)aQo!b>_#|u&s3=)1x65#@JXLVw5S$T7X#2<@(Qp{Di?WNh;&VP$DjY5SQ{*jrOvS z>;2@_7tN8Tv#Js}JZ5cep}F}X0JR`LA3l6&54s6*ggh4$NNW{eyyo5m0~Hsq(frz% zeBvRuOeW(#IhGMnEog3jzNLA-ww6{%Eaw`&K|Q1_V(1J88-NWAQ zA=ahFQ=ihILzH|&>JJ3>;o+(K98{LY8{sbn_AlJC_&XU9l*lV8T7|M9l1ZXAb&<&2 zc+qi%8n|-1_V0)>#WqXf3MGE=MO&jO#fDqGzO${IA&Fd|@qWIF`Pw|MHZ$YXAGPHz zK~&w*7Zaz^wP@jSx6&EyT#lcT-bV8~_GO1e)8*&qO-@YwnaWUm0RRRZB)~@P;QrT4 zdu?;6uy-a~3+|G^*kYg}C(8dB6#tPB>V3MISj@u8pk#t4v}3pGY*V&_3KEqeXJ3^mUY;F@nfyL*lc1VBO?~-Z zPF}g?W=sDDn>>aqm_XuF^HNZFnQ^oEE|Ovbqz1kVMvHnzHHT}(WzG$YE6ERkP31Db>Y!=9zo?9j5;5J|*iPUW9vEp|sS0vT&r*8_eo9-dQay*e zFLj1aL_kuoDS2=|HXwKacS?p0kqfL&=#E=O(bOG`vR6k5KYXnW={3Zy^zOyUQbPma z>-4@{%Dn6l$TQy5)4B6zL_lMF9NVyM{Q{&dW?+->C3fxx@( zS^EfW%dN5x$M`rQ{K^N5<*H`U$iTK`!ALr9wWElgs->0+_&))5iHZao(7N+Oc-{?u zHPMAD313Fw>LKjTgK_jEiFldy(zLp-_mqp>{=5#U_1<%^^SN4TniXo;HuOLTC?|5J z3nhE)=IU3)>|0D__o}0XO%J~?et0ljKkLGQSZvh{jzU75d?q6WTn^{D__}zbA$Fh# zCR}GPwqL)#J(?lpdodIj7dJGd5X9FWZf5VFj*H!024aa z@-R#wu8p$m;SvE&ZYq2!#Jr5SZ zfg=WC8xa`e)u^uGEiNv0Jy@7(c0m1huuwU?T|6={qVxk>%CE+`;qzpZt6lfY7L&IG z`HOT+2xbMwqw-EJ$b^)BpZkLlX-Ult0Hl#p<0>Jv(4n|$j4ycmcRj(5+`#Q^&g2pX z8KM~z=R*%3sedOPK2dN))*kK=4rx#?Y}(d)a0s) z%D?y-)*7c&o(+Bb&1ztky4nF#Va3{p`@@Dz=h#98wI3jB<=5@ar&8i(mCFavp*=u2L z?h2pSZ4p@diu=MVESt%`^^6B7gx%J;*t(Ix_kMBv{>;kJ_P#y;^DRfj=xCqSNYHWM zjk%5?^!&DbKRA+9$ogjJvE}iwBd0gl%KYxUgclGW7uomKb(+SWw%Xnrc&Ai$y*O>8 z|8VsTFqw2pcN>A(w^6@xd}C*1WcvE`>fxecqYJ8^(ft#yo}^A%p3ftE9sB3>Zxw7< z`0|8t>9ex|zcN%@QS+gQhTey(E?oPzn<`i%MMLll{4~&B42S`MI22mfo3o!K(*_pJ zof~hbzj~~V7KJa?(Ey~4Wj!j-ER?|Byy2rwXJH^V=?zNm{W7~4BRMu#&#R5?!49S{ z4UIQ!G}pJv0w1o;oJL#kardT58yjsvS3V#Zdw;69_omjC)J*LDZ2Z~fJ&hTQ*}zFJ z&F)n3_EpXcP@HcH;+J`Qd~{F8A$5yvz3mO@l*iobFP!^EeeGt)D#*U3I`n4mKf$5W zFw!EvoMudceH{1GL*5R{Zd^D-rooZ0;~%tLZY`;Cet_%dbz7u2x-=Y@wNbeZFoXSg zmf=6%aU_O2*-a^=Aa92jHl#W%2yIhGPup;I2lcLRrU|sNjdK0fzhV|!LvBXi=VJD4 z>YktbT!;jLh5J!iP0ewOk@$)g74=Dy1kQA!%b8~dl-|o!bq|~Vm=NkwC&k29iDWMw z;{+Hs%dOIJraT=E7$5If>NQn`Pj>o8*$sI>bh^me8dD{Sk%pa<6|%iSAZl!8NLrZP zEJBH~c-m*S?0b41y<9GG6i0v{ZmRqc8T)rFlck`ZRXEN$zxTMxe=a?V;d=1L;!U0X^6&lg9n)u&I8Gzd6#SyH!C1+I z2aXMVU0km48R9?Jgn8F(%*@06XOwpA=Q&MD%`VF*8POk<-MM0Ej4jov3xW*{Gl$d%HT`0{cmn%HSyB@>&f5rkQaIQ z-!O6YYy+iiL*=dB7Er$;4p-4a27b;2{mRf!tjK}h4L2@Z9-ksp*t|3zRiMP~rW}9B z7VB$fwp;$GY%Tqn-nHD{rL{+tlRN<(;8K3ZSdd;mSFoSef@gvN&_Db+5Qrxtk_^V> zWSXh98&09pufrkbxm#l`ALt)$S`7P(m$yGF2~r z6`kfGOqJ?le)F5vhE6spYL`!A0#vUyQ-eQ_=0x}ZxJLw+&+z8J@F0?3RQjvkRW7M9 z2IbR|y9-;u(NJ!*flacLv8k<>UNdDt4yPz5zk)576IjZ#}ViyeZrx{!dV*JV1GNZUJp zkpYdwx)(JzAaEmNx7gm`F!1n}vCJ1>KoR$u%Z3#KexdU}-hbny%RISlJO|SweFOan zKybawAaUpqm*_1uNtq}v>>LoM_Q@*Mf0$|9#4RKe)PibxG&2Jx#+0$CF90UkUU3-* z^IZCOBT@vQGwW;F{!!btC^&SL!wcd+O;4f$N+=f5H(JlC zU;_%qE-sc@t~NF{3SqM9P-*pxhYnd_oKJZiE6AULVH4cHTH+6cQ(40Nv)|Dudumm6 zwWh|nhDJ+R_VeFQeyFdz7UXA$Gqtnfl-V9p4XCXvp(1?48bppm2>F5tkf9+bW9i%v z>>Dsjoe~kJ%Q9yAW6Y7eD&z2FShdU~hpmpnv56A{n{u66iilf6+>ltrGj*4}5* zgOb1zLU}30%C}ACv%)+YH9c<+BXQH8M&^FLT~laWd&Vv6(^GM={xMz&-3T^oFWxJY zUHux0)Df_*zFJSF%|o1cHaT}D*Mo+Zc6xDe%C9{C!-dy&jqq^mTmNh|s2kX}w&EOXek#*1hQKiuAZg z6JAI1Blq=l5iJl2+AaEZiV79tHVr<2HyN^Z(}^y_@30zYR|@Ti$n^kHMJ zZ6v|1^`T95e=y$MrYDF}^&UO04Ao+pb@r3b+5{Piv9}8sUXt&S5>Qxt$KqHd_M4_T^;;y*&bF1_b{`eLiMxuSG{nvDK4uuVqvN4Q@J3rJ{nZDRzLFnMs-e$Xe98gqD%6`XTTPX7M@{=adnZvJZ*%ca!mz1s(>Q-r<9o34| zi6p&z4WghoH$FBFrd63TsoX+0Q)?Pw3b-M4?{ARkhnsC|{DZR!@(N~e4?q{(@Y6Ms zq-;cBp5g{gOEA7;gUF)C+1WMB_iAgfN1KQ_OixQMCN_02$tFcc*ScsdaJlPeyuhNP zS~NB7&%`zz?dU0&MZO68Df_Fn_2}}3D@6D0^l%z-VV}FUL=N4PUjboju*U_TtuMVj z%7SYkREah4j4#Zg*dEVCuRg<^0{Ea6h~CvnKKf*7Dy+u0Fwya z-2(^{j3kG3ja z<3{eC(~*ke1dAoUwb-p+y)|{JnX}4FaK!y!?}QrMEi4!$LR*eyWbgp$XaQc~f_ImP z+lid4EDMX3nk03-h8l0Kj`9@whHIVXrvkvqy7i)t?oA$>TnFJza&8Z2CQ`54+G%qB zP^p*qm8P8={j#I4w%U%G8IBq*eh3HRT`v11c1Whav`gZ$9%GnhyV-`g4Kl6LsIv7B z4746a2~Ry%Ye+5t7a_k2U0*yFOSrsYtQsMW|GP3z-k!Q{!v>}ixX;pVWm(c#zS z2JPim^ytokqgE;rud5-mXv4ZKS$90yDC&dbPYNYmN}&%U zl{C%Qjb3Yc;lwVWyKbz?j^NjmNXXqYFra{l(6;5cyXwHDGoJerb=l`QsJwA*sd82A zsxPMi1aVuA$HFP-g-@4yGf4T&clJ5UbikDZn53A#W0Lrb7=V~oo87@&rj|F&!7ls}OE`J@*O}ZpeHx=uT$35r!2rFP737Nzf++j83=w9r4$34-=RP3^~H_>@- z;d)}0S1|C=b=_sr^8!BG8kq@yyM{QeBpra_K!~XRM3**4G7d$zk6u^HTr{mBPKxWPK{3UVFIc2?e(kCnP#Z zFX97jVZQZ<*e#quMT`nxkR&veME`a69go*ZvK8WYyv|L>B5RPd9eI_$z7CJbHFete&kC55kvq%1Mc}Rzgz^}v z4X|9E8|(|VJE-1E} zJx4RBUb%SK?P?NPFaUUNcnH8I5sNsHN%P%8+jfTY3BhQaj=ENU;Xom`nZQHqLzmmK z>y~ZG*6h`MIp@RvY@3nyaOvg3ZEx^0euZ}k4&>(S`p=?U+ci9vG1IrGEa%T%Re?;j z@cXIeb)3DWoELa~eM4{ohm}1VpDXXhxx<#5h2!X3p>3-n$RP+s891GOz$7sgaKCXL z=NjYX0hs}3r>bHc?mM6J9~}Mq{5wp*MK_UCWSs$`W>>|kVy;UUptSeRtfu$(5mhG6ClEec=5CXEc0$N2hstRyDTE zOWKC)su|dAWfU$uS*jwBYbj7xUY=?X@HV>xa$3-)feDsKJ|`R&$;9QE&-`qIi?LY) z9mwJ+N;nv3I6x?qnoeY3ATW!juhXV4OKz%&#>PX%ruR7r2>sq?UvHA9jX`25?XWJI zVkG}pSJt+GeU}UyDQnDnUnZN*ei)M0L@dgOSd-e01MFP!+pV?bKBVZ7dWT51hR9$^i2UC_u{AYCbxmf@0XgMloo{1_m&IKi9Bu z3`}gvI&BSgbtAnu&&$bBfoTJ;j%6B;PgjNCB*a1c_2;n3SpPVUjr6z6X>d^DlF#xz zQV5Qulu-9>G9!&K-`MaT9;GTK{im)r9xQdY-)FRKCluCGW zzBY4JjftOq*yk-sH?fcw0`3~Fqu~p17h5ePF5vL;HXIZ4-pBY}mc8R!N2A%i%vW&R zrTe3hsxI|TRxCt6Jb&(~GP8oU#U`6b0Qg?j++0&H_XASZKbwB}crb!VV#Mt@l(oPo z=J9y%Z`hSr9Jt>=3lfI<;6pMoFwHl7dK0!S+3^d#AbqO9*jGsU z{0l0z*XnM;_s=`P@BAU=vGE`!*CnAuO!UZZ?~#q_OcVq`a+h z7skrbd>2OD;xWkexc+!2I})upL(}3jESmC>4s?-OSqEB-?Coxw)93F|&qewUJ|4|g z25?W6TB$ZfWOH3-xHP{4#D5J&rYbwrvkP!T~9!U+)}Zgwoe*vC*5*7yqhMuqH@KOUqzXdYWGo(bMug@xvkthB0^Mbu8Nqbz0_XOQ6;DrY9y|p3Y6COtDOp z+m4wKN*^q2(k3d-H(%p+p)o7fQX@DJQVaQpwvc7M{ds8<<}LSgiwn=XjOO;862)oY z_&&XujwUH;M+@Mt|mps!!ZROC0d3aab>Ns$Mm!lmQ5n4 ze{rv|@cQ?;+5%(FDV5%I_+N4jww2;T;IscB)R)iZ0GI%Bl0?!0B&XRX0pLL1_7A{A ztjDShJa6edJZ2T|OAw_kacGZ1AO)m2c+k*>8XstRq!`}4A)NAxE~MwP8q?B1(Qy>X zw{|`p<9`OJ&aJ7he^-}XSovAb-)Lck4R)w_Da5$cZDCrgHD2HG$|nN5GcEd6DonqQ zpw$jOTu=1F%pm$(vd1c#1(pqqf*ey!UlkM$%0LdLg(j101(PLQ(Uq&dxO)H`sj}QR!V0+_rNAk_z-XkRZRIc_8iAvU;U3I9>&FwQbv~aura?thR;H4~6 z(6KAu!};pgrIzu221DHCdJ&Rwi`OFd}P9;?s?VgdkO;#%ekI&2+*J1-DZ1 zrQ=t0`yL44t!By0m_U<+k^>kQ=vmqs2`3IhLDgGDs^@X zGd4c7D3l25 z7hbaa5`pccJP4iTB-(+GT+-N*F43?0o?G~Vd1Y%5pN*mt&dbexg7~lp8wfkmpcCZL zk{xtJ#b-9{oHJFGEb(WyqSK}lu+4kJ;}xdV8!kehhWf_HPeX-ID%8M<)k77|CMV0a zRZl`enrpZggm=rNQ%duU}(3{o2JEE14QcTU-0%tQyOSnbk6IqbJzQmJ3J#_iE2h;| zJxrymO$cAJFuwDxYXsc#NxdPQ{B=GMR&`RPp_@dM>@__>&o(Ad2o*|L;el(e;~gszzs1&;0jDu5}?l|Nl%iD7x}C zgeLfZOE>?Dap2cn83f}0cTd{rO%91*bB?)RJEx3+v##2jPFe zrzdjdhq)q6zuLr_NrV^wIX*kB4*Sn%#gm93N74DuIlAXX>V6;*>E8$buTB<~R%%EJ zuoQ<~Ixr-Y9lR-p2LES;;7MH2v1j6uHGcaR|M5C<8k>@5W}}(RR*h7@?qb^lS4jwW-tKNV1xdf!7Hh$pL*+m|9xa%Yo1GSnurlDAOf~H1PMh~N5V%U4!tc!$wobU&1a_8)}IBs z=V6lnORjGdURCE3o9^^J*4Zwrgl@etp?mvL{r7q}iSNVmC{NY6zSsY{#hj*7 z&nxoPrQ7aYt>LZfszZ_hqq*Za z^^lFN&CsPRW%`ap*}S-zu~sD5001U!8F&C-{d;w&IP7^|TTH&Eq0 zPmc^TGSO>qNn)y2y|aY4mR%Iyq3Ck0%FW%|Ixl*?<4R4lSk^Ij+@#m z@wmWcP4XfaBsNI_EuY6tvBUZt+eU+LcNC!oF{4<8Bof@U|QYU*y6 zu=#e^ZpgV>DVV(d;c_?FV293#>}kBI5!D(Ig3;5bC=!4q%Io>T9Q>0t+_1f44+D<6 zd}|o2fiDpT`#@F1AA%<_4N5mQq=Z6-i4ZHKbAj($Wy_5+HRaL=&KuM*Nj;BXT0C*7uk#` z_(V`{WnR*f<6G}|qD{{OMYfRd%(R-j2{}0O>L(f#BFK{~{FGQYjp%d){w@%KYqQcD zSDI`^`AcyeB&Y>7f@M1sdJ;ok&m4{v0ZSPk^-KUNDfcPLg<{ z=f593J7@NeA)?4AI+(dAR7suC5I0C7D=f^htvrQJ@`nKZocEfh^d#T#ri4@v;a?=` ziLDJwF$9M0ax_t}*pF{_>m zr!@+G47@5M?roouQd30x7G(+-CpR2f2?484(>bD7S}ijJ%OS$^n^4L1~7AA+p9p&>Sa z3#+it{la;jyRuX4_r{%HeeW)pY$Rw@4K&@?~ zCnIC2#YD)$%6bmfo^^`&pAZ;pq+$M`-*%dVfg#=rKsnGEi!@{P@?-{z&C)c_ZUm;>?jt&it4BKwIHX(gZfeqLg z3Zxm&;H25xNrXDc;i7bfb&43dxw@)YYH7*Ke{|PHH&X~dLX|{@KDieu$SpQ>US;K< z4$2~LNA93>QACsI*g3dgj~$sKM*u=40Dz=jQjOUEDHoAIu2n?_q%j`JaTHcjDsX4K*|j zpt@NsdYJY*t#?IlQ}UNd{@j8kkNE`!E{6*YE0-jMaF7*{U2|jM^v@USYgJKsxdXzY z9x}n!CwnZ$T%?G=t@g@2JiLc`u6SAVf^=(ZtL{nxsWl}P7wO$%&6qliv6Od+i+Ld7${uJC*eDab6olP=|Q3{@~WznU8_{W zb^BRricnsRm0&bC7v;SbQ5}*8jE4{$A~bRg!f&ApBXK_nSn=;?zdeW>e$mq3H29)I z9pTwN2SRa7lwY18Vh|!albBmnE|KRS;@sCm?!<@;XC$WCiPCKC+!99&`4fv9=e93V za0;JNbfC~$TIRcJHcvw1QBayTWM2=Kc(q->!EZ;==4a=9rtD-*L}Y=|Oe|uvk6N4wg6c+O>xs0jab~{R(wqko69fcGz!tT(_(ZCxPQHn5w?nnD8 ztZ;*9jy_!G@dItF!pK0$%_!4tprmYH5N$asD$n#&<{2T$T`l6Jdj2zF2}~u%jkJQ? zeAm5+Sw44Y-YDNN(&-S1L?J9CJ(dUu)$RTKfd1NO@cogdbSqH{bH>@(1V}3FTtxZ$ zbJOe}JDQ7~od0dQOj1R~j*IjJifUf4_=9?)wf7+-J4AB6&VEzmi)&6yOw7`h*^J^F zsIt5~GYgwsusf54L*n3gsi&%WNlD3?-#yMUtrVfb!~`;bA}b?fq7yaR)y4C!rzW(d z_sv$8))0lW+ShC{YJmWPp9C5nlO&s!KT*SyO|~!KH+}yu<}Sbm+sIF;lzx|DKpF)R zt++WMD2wO4)^@`a3zineNE!qa)x8R(@uB|y;n5>X915aMC@szc7b3pUHV9qw^D_uD z_8y(42DdVLN;(`m>SwZS-VPRE(9`;t?XOm3q^HNHBxvdC;>4N$%NpvWoq|~O>B-!+ z_vbyEWd#1N9E<)V<}4E~hQH66J~};E1t(MrL5l)UqTV2b!w`4PATAM#o?!rWmq$ea zGjw>GI$Ex-f`k|$lEd?6i1k2A<|SKnjHXT5WF3xmQxQsI;{7w4rj+#JrU+eh!Yu+vzGiYMAi@U6#th#Qp_&RvX)H zWkp3ru(SR|p|5n=D|lGJ3wCanS_#WX0>hS5O6YV3)aCa@otNdRB>`H9|K+)+4Nsa4T&cvL)X zQb|P&Swe-~%*XgNK~hgAU%IqiXbqYoi0T?9TNsw&AqYL`T1YHCpWVt_=48Z`dsaklC7s(t{5yRt3fmh7F$rrfBmr+~@Mp2tqe#GY4UVQh|%r)w-O zuC6B4P2#4eK1&!!A}!T{5^rb@MK&)`lLD{OPe>kWUGmI4efVhg!a6lqURZhT!mGdF zd93c?LUKd$w!pT~sGQ(kB=UtF6R`qy^!)y5_pA9JwI8O-N%@t%fnP%Fi>aY_>Uvf0 zNqyRkr_Y^PI*t@c%_6vaNCCOQFd2%@Z^240^!pNjj?6r`Y!pRkhB4IjZl2x>3(td< zKZlWPfNdXs|HpO4LKty0WAH~_SD8?qJ`ySw2p$?k<5M7@xPz-maO9(TfSF$6u^oC- zg>XxZc!hlMB$eU0QmMnVeC10+Hzd!y(Xye=!?Q3v76x5n;sGs=Y*qD+c)n$lfc^^j zmhXCxGDxqbR%OAE#Z9I4(nvG5{ntg|}cuMss#qF(e4mDIL|QpqW>x6oIm8qE$;D0eaAukJ0WK8 zrvsSCDN@6_H8`|a&R`FCxw+=_yN;d`S$*Gon1vC=+9g9m-wfk_dAU*LK3Ekj+_a!8 z&pf^xF}i(uizMY}LPC$eMI9BZJYco^3^_06x8HLKfIcR^lQsMBhBYQ$u3#*mDp>3j zY&o$-A28=Hiiw|%nPe(%)Xz;fRnO~c=^L{NI3b{9)aUyJC@SpYBHy)&zlx{p{~~#W zSNVp=u>oXMk$tk~q95afJpItOiILF2>il7uMQUghBi}TNn%C8>zU`l(lyD|kyyTA_ zdjp9d_#@m!g^Z8YHL#8G`&~f(Ue_%?52_A06cAv_jca(HVQe^$g+FMKqr)UaLH|R(Sn~i7FMC9Q1U7z zb4p;z;o*HPkrH+_(6kPK%765b5=qT_vxtv}NQbwka)J_=D(kQ~t2KJ7l`f~F|Fu#t z3%Y16t`n%DNen)r6hY*h{D3%ZE{jcq(>%i0=a@lnY4OycF2%kSp>pGV<?((Yj^Uw?boGC#f=hy z9XI}59IpVjpM&2v$oZ9bCE4OfUO>d`bxNy?=wsqOhb>W^VOkp#Ce z<=f{nZX_=M;6Z=>aqWBgG7tMW*R4WQ9z$eIrKHts`nMdZu}?c!ceJ{6b%kI$d9Ut= z4_#EFlw89~nQWLyXR~PP|E{ZuO8n5!G?lvE^?pky;T;!3D#Psi7XC@lFaD0E>sMW=# zS@aT^EJ6;`q6Ars#FZ3m$HAf3Ufh&8b}m*=U+bjXs5eBQ*9?}!7-Zsq!hT%PzG3_| zsYUT~2{)+n?e@&pamEwX^YA4 zr=0h`zdTqpPl(u%m0z7XL~V3MMgI){;vYJB7YuxZbC|{-;i3C|t%yLE-z;pjAGj+Y zJAx2P2&RpcmAxv_d5zrQ-1^SheGyxwu1oYcPpOpSGXNQB7^Wrkov5nYfP2eDK+quS z^KwZ|uGr4BGf2t6t8k}bv6inJJvetKI1bc(>9*t5qEWeV>`~~=>iY%1;amuY zr%s=d@D&|JmibxhZ&7;EVCKBD>-$}$7~9)_DP~S7yE=XK35nL{u0z77pSG^{(OcR%Qd>HHI%ieNPGh1oYTR^hNBMylPb|oj@D9xT-4W_5V6}H zA|O)VKqY$bHC${9L5`5OH^XyGeLIaIuOyu)Xr}%qr##cCEnE> z>U(SQUUDAV3)Ur5N-XA^EhJRyuukfr$sxaU`%!lav&pa^$%U@5BeL`*DMm6C;>*Ev z5@O|^Na7DxDRnJ8gwj#li(STqTT(i-BemV$w>=)mOdq{eX2m-(z8|(_=r>;Skd^f; z$S+Pdw|j_@R24j*Aj!DxZE;&9h?IHaxG6OeKl3NZ*4~av_+ozAfZ}Lp0nVwZ{kChC z#QUKA`qcMv-}Aw7IkW5c%EeNqD6L7Q4u+t&U0s0=+eN&R3k?(l6o8-W6r8tflV&}U zx5Mdf-pw|V`L^@E>B4$hYL2fcB_hu1BmY@`lZnrFFFu8JpWrk;d}2HP!aFK@xfafE zn5dDUn1_Tbbd_MdB}-o#aPucAbnW;&vvFmu0hI>s+<+0(*_PqG)!K9vCZ)$d zD53cH@S#rhVMVg;Zl&q>&JLBc+a7XwP)t`=6C^_-i;L~vRIr^KLu%vrQxM*!V}p^R zXV2UHD9H6$_2V{T`SdhVbhq$&N6BlIF+;n$PXXI0DM3xXY#>ehU`&I5|ylAz};AeIf{E zx$FdWmr<_bk+=Xon1wb4lry?QzTlI!9B@yN+46jBENN$_&@hpcROA3NvB4{&>`LbI zViP8QRsYa^-6GlV)EnFhWjX#MZp*E^WU76FeBCdefofPe$iMRTVA;%4Pru{6kBC#u z;~^EFZ)Eg*LJjFGQRpC=J4I&Y*A;)qIjIv~jfNmk$bCp)Mm1xQi|wr}lb~^P?=xPL z%doFrWzH1VIC{2Q85Omi;WdGI_?|~#AMBt^^|DQesk!cLce$^REZ>|455c(Ap_tPJ zTx{V~-;iv9;{^3C%YhW%!u}N5(9Vq(?-x~LAk}%|Qvk>^co~RiR9>Dbh6RaYkx3VI zj`37U5wsp4%v`pL8~R2Af};&@PHtOL$`TcYD~=KVaXcxkL;DUcHk^W}&ZvK7?G{N@ zRp+cH_dY)KJB|9>Z)!J-8uNSu{5o0>B6_DEkFW)(n@wJqR6m=YoaFI13(CBQ|Lphl zy=67VxJp$JdPa)z%CL;eQD6_Fc%3kMI&l*MgM^eh zv<~BC5d@}87zgfrm$5x_!XQr^ME6~ol0v&w=)(|2TFD_1@@E1GxGECBLMixUo&1h1*`vmq(us>XH54BDvu_QQtB2DTjb_9=9pw*p=)N37$(*S&$&Ctz^y$@k=yHzlB2h5>8tvkcR2!% z@lc(OlTCtIKl|MK;^dU*G}hOfzj_V)j;_;l1L+K7$m@(w3JTN0#n=3VAL9YSt-E|w zNTLR$?&;Nnr=!>Unw0LF=24+doQU3&&%VdYuD8q36veI4ma7SCE(Vaa&!tNDf&(VwZ6_6VPwl1FAJgd#SQF8xnWQd*S z?YL(Y*Z;s^=OMAz!pGuV8GpuXj1A6qQXOxs)S1Y+v z*}l{!O$oWRPBV#?{>`=SG1kP#?Pte^eml|6My)$2x^T)}856tNKEV}f4^F@mp5=6i zDMo3G8|qSnBU>E?FTk(K6xG$ac5kNA`Ss%n9J}7jyT#g&3mLCZjW!X3$h>~G1BxEc z^Xjni5+77U^l90(T84Q=4+~UQ6*IWi^4oScmO`LOk1g=mim&I&O|ns*wo0nW=%+im zS+|Df)xgVY_QwfLGOQi!uJiMph&3;k+QGgP0GTQI*40%w-S=UB$H&c{B{`J2>RQKD zu3W;iLg)H(Ht&7UT6pWX=CHj8QmhE18_b$LKeb&$&K$tIUBF{Ct&NRf*Y=nLMBGS1fY4U3*rK&F=;bbbh9wP;A`^oL6mu0lMUJg^^#l<$%)@c8xTLuZT0C>A78MzQzRgef7b{+>&VM&;d) zPQw*jk~ins7p?tLlp>G6dOL&-3(EIvyM(WXq95IM*WM9oyg8Gi@b58}V)5Cl?dmvN zioRBDpXKoFxR?+HqF#I;RD`OeBvp(x&{)ev;70OrTd0w`3t_#9?a0CS$ZX=~TSg$1PG0;NfxBiVw$iPvM5EB`3(sI=9 zIoEbo?h5`dUTwPbQar_9KK^e@l-LO|u}WOKv~Q0&oY&LYI)K~ppM3``AwqX2*TvhE z`&Ga5#?^=4qpb%Rayp1%6P~DK=y{lw!P@)kip%5bTe=5_{k(HTUhiy&ve?^i)-f*~ zPe`2~7t59No-lo%$ps-BrLqP!X}!h-fmTXsWPhEA$)z80`Ht!;bu_FWZZ&cZj=1mW zogYqCefoy?w2!w51+sR(Jx0o9Juy~wD?atQ2t*mMHe;znA0y-D(c<5EPecK?xdHx9 z@m;+&^K*?cynG(}gahx0X$=!;5OT2uGOef~c91f1K|)=Qy0~NK%|c{J?hI$E`}EKy zFfrMvWO90bzBb@+p-_n*0fejnwO=ZmDs=8s069oLyY@2G@OH0syt2$}V%Key&uFIa zYjT&%^|V1Qv*tI-PPbja_z_ZgZ&LUw>OGze3OUkcfBhzCG(hxtxlpV!Qf7t=Dpt&G zGQRhLSc^DT-L2YglY3b4WHqwbu4dlGQt%$_4YO65a?=#yM|GOl*X8Va0V*Q=_NT4V z6Y(5*PS2|(b4|TdbM?1)`ucB66p~dfxH4arYa(@T8Q!Q4|D1tprY~+}zP<&izkNJz z(k&cci9$dft4e>1Z*HkAnE1zYwHJXXs}X?q+Q@PmKKAAZ?uB3$AG9g8=*@5+b`Tu< z{qnGXgLxogsn}2p2H{I;-+zu66TEPHxqke}PaugP?a{w+JC^PG*<4fb{tB;Lqw{v# zmc8?Q;kPm$l^O~NW_8ymgst2DrE~n=VuXat<8C_LkSsPXu75_~XKNamixmSeo0qq^ zdEhD;`QSXO_0o-Lp<)f~4t@ozmofS0!d(#4?S zFrSWAmSLOct3R=kF~Sf*X9pFbutaGFvWr2J>=!v6+Z-=)Ki%}I4{whM9hTA=ULO## zFtT^-4axW_A%ljK!j0wM3trzPkKSyK%XQtfuy5AQqeRDBIlTXI`HH;x$9GLbzp@N= zzg@0$N)F%0$2Nek3TURUpZq$Ngk+iP{H?AKJA1a%8Q_}vu=4$7l^RP{xOvL( zeL*xPbXh3!$fMzd3SyaT$eOw2V@LQndbPguRzLFEK+t)jw6`~|>6NY0^%7m>%NHv0 zV;L^%ePyN;?HjX$F|lM66NZ7?xd0(URCj45+j!L6?SO_SiN@t~nFNe8UR_-@6qPx3 z75DteZqn*@CT01|Cib8Y0)aWbyM8ydU6l_`bTa%$n@YHwI~1JNdQ9wrr>vl>Z>hPC z9)vf;G>Kb3xI?T3-rBOlSzI-0|8s(Wb?QV_%dsdb^Z9BOvvhWP>s#Q%@ar7 z)@(h)3a60~KT98;x-6YoO~cueJL$YIgVc_HJbS*Aojhz2&wteokOJ)eRx;FLA=G3s z4A_z+lF#(%&hb_7`5BM>p>7jai2eF!tfoPxpgVkZQERXS8GOzanej(U4x^ZkLHoCi z#pc?H+fEI&we^MmyJD`2f(IEQcYE;^xosZda-*MqeQ80xyCLfOPJUzX_OeQ0e;*Zs z2=wEf&p-tOj_8OUe_bp(wB7QSmsVe61Z@pOUc$g}RR?=%Qnnq=|9L?^y zoYHQQrvL%y>B&P@2cpYagNGfF z9KY6<#w{Q!X3C=ND-680_1%G6nVs3Pi>x*ozZ*WxdFhQ^Z-*EJhr@{N?Y^hx(fdWG zkx@oL4ScV+dgHWwHpd6qwb~CVXAOZyqXySehBQ17RjAkgId4wj1-ifopW6{$9Ou1& z+wEvZkW7o?{FGm6es~LuNd2<{;4^rM)ns=hr z#|z$tR4=^@oX^Y^xaec2@UL9cb+Rs>E5ml#~}x8r=^+H{`!K{l`G&VHk`rn=zW_F z9MZFEPSLZ=zxD-=>~y<~9}2=Qw)1hwNf$dWrycJ$c3-$_UQTv%e|uiP9s8WuqhEK} z@&5Dqnz9_@tba zp&3FyW&EP*0Cjh@F9g_vUdCO%xQL&P3d%7-?MLB{otNR(#Ge5ckB8Hvh%mp0pm*Cj z{%droBZhA0=IMI3Ew*kYs@07wc_c>82!#K{sB=f}(5A?7jKqrQ9Lz%*)Z`{pbKXhj zOPAt9ySt?>$F0sji`?zPquC#iG^_RNZO${CH`rU(>sKGfNAx3~dDsU-`m(A!FAkF9 z=V`VGhF76M^QdEtDM|T1O3T?gHy6eNy+_-x0l&wOKYP#W*os_WpwmK9CCBUMn&Hy# z!YVD6?4b)T3nlY~{l@4goIn!N3u6r@aRNTbWCsF?8?hxbZ(=&cllolHAqG*zuJ(+> zjEQY$yBxcoa<2tm8?xt|eVuGy+1m?+F|XbNGtv)c&3Llx)zu>=Yt7j#zMO6PUo^>| zmg2>U?1gR|l8{k{PHx%QIaKKDw%5B$-xhvSQ@$xErQ=)7NdY%eqA6n zFS}orz0m)i&E7BYyEc~8v2(MWz2nO5UAcDxY2$Tg}?m;rV zjI!Fh%hXhNKZ65QGn>+}>T8Jts_?pPbmJ$8gl1*Y1H(ruZ@pMS4Kdd01h2AXf%Xe= zPpkczs>6eyR#tY%$_Vn%m_bu=a{DzW(=nn%uVsXV>Dd-1`? zLa=j1SYP&ebYIHONTGmeZ`&T%H**WmpIowP7|72{hM^fU7a1 zM*{)TWy>S3v#vgVuJd+HAIYk>TUnw*9Tm3g^6v`R+Cd85-lJ=^=RmKlJ6cR@uGeo9 zSNYf=Up^M|6hT%)HVA_XKG;0sNWq&4<+~FEi-^kEQ<#YC$oJ#Ier=5T8;gm)X31kg zV>tEa)BTaIBn1Eb>RGq%hWZYr5DzydDaGTtfBr!Dv7p;!;tR@Lrp=qxpd0}N-+4NZ zkauXMK{|D+_helP!zmN+ji>Cl)OWw`AK~wPzR8qGk&>)LX}xP9M`Om_TQ0K? zZ-8uM?kNAm&)$p0%O=VPX_YBpyFOp%UhA<6uLJ-?by3*=i~;Rsh%e=r{ac@spq@JhAvi~%k^pqdi+2`Wg!_EAfoxavLR|tT^CkohR&HlQ z*l8k8tNvRq-hdz3=4c*`xzL;P4qMl6pk=4Qe$MNzN8+DtJNVJkazO9+aimV0-2R-` zqIv`MFiKf|k~m~++_xWLMp+a(+_0w}5dy<{bvEc5h>8Z#bCU#d5$X~}SMKjEIL#H9 z1JPAeSxaW#elPY)dfHu&W>=29L&M-SFhF;LAinzU7!|1{)g-^v`h9OcDd(2*eOJrA zFm>P3JM60Lwe_*UliTLy+S$!ri^?#ei}KpwzgPe@LH+8da%hsW zE!LK$3RFR2+QByG3GbBU4D(z*{LImWfz+Z;_v*t0R5u(0elh2Fw--rGE8Z+!I&|%> z1s>JUCXMziYOeY%N>IAzxSULbYAO9s?uaO_vtInLBAZnWH#wfwY#W}UnQrKk=sp^_ z&=Tr~6xb*?!?zn8(7MN{xTyi=+=Uw`JPw96U z#a!Kfg_zsSL17r!|H|<8ej`w1t$_>SM-!#Nj+)Fa(bmCGJX&D$l49& z(4UG4N8s4!;y7NsQC(xKgd77JoQm@7^KFmoqgI36Zsty|=eMsf?yoyV1kbPD zVL$E$)5O2N3DQOn<~%8by?!|lF9_QNUK%=HbuaE$ zI%)((2tCe{>r97;isK-vy{q$IA%|LPtIA3ego~Z?53~r5ZaH?Qj99!-%KrU1@Zoe_ zBsVTp_i$$g=pg^+cPmi@!-l@R#J|&U%T`zY$IJ~|_W~V11&r*e!{LgVJeBtMH(6c2 zg@Xhm1i!O7kU=07DhvUFoBiWQuQf~dwxiqGzy==z#25-*#kcAZRkf}BRl$GyvDt)g z7@B7%JB>G}F^NDu(T{!xLDiSB6oLxs&rF$f?SR0<#I^MUk>11eUIw6+Kam8~U-~w% zA6lw~(0@<}7~4@B&Y7;~SbhjJpidRPs=3~uCHEh^45aVAy)vYDeX*G=;{N#>Aksw+ zdWV$-xaGZV!>cFWO?7(1-RQx^#!i0y|449?fLJduksPhUux;7kXDeZR|CsPmG6NOa zN*X;e;MK)nKJ1ll#0!|Mh3E!c@4EvGcuym+GklFS1wD2Yn%mA^>U2CSDn~lCr11S+ zfjO${bHI`B^kvIqER)x9BmBIzs+W+)M?n)o)jxK=FtJtL2%Vax+<|osH5#cRKL}=C zc;L>*yRX?O1Z1spSMN4bkMA!JqS=;Qt2+*~6&*V+ZYo7SIgdox7LE^?be>(ivUeOw zt!B56sZrPHF+E;X87_P8$I~Rvc(n_qj{rHw=Ua6J8pTvaxL>_2Ez7i2)%%Hl2|j#B z8Xp)y!WQy6o2#X$M*V#M&M`nJcbHwT&MQ9B7Y_GXUG{uD7~~BLDFlhS!r}m5kpJy6 zKWqBP06+ild6uBbL-)>`^b8QPlcLqesl_yNtRn*|p+ zY$bZ`Oq9hnsZpn^i>)36&SjP=Z79X8!GLp)6;jG+lC~>A+Og_qqyYzNbG9 zY?Z=8f?rVjUxmI^vUjxg-3lYZ>HpaAf?as8ROp35>t4@T$7L?BL+eBMhT?Uf*eNzj zP+U{fvETJV>^}cpzCljtq9~dgevul}vnIU1)wo4(YLi+mQK+QKQ&TCz4H`5M-VkCR zkCH#yRaU3h*BwQX%NXwn@)<#!6y=nihlfkl$172$#NQ}_b?x)Y3)a|0uJccWI(^Qg z4DSyvfYht!uMm_L`3ui3fHdH1GW}5_5y0MRU_Z3-9?;P}R{DJ}4%86IVUIQUD=pUd#QUVGZ;wHin=m&sT zSWXqNBC+6{ev-$4Q#!dm22)%YI#i?4y$JjdoOnuP)D`HAFdxI~gm(G{nv?cJt5dsj-_yriA z5FV3tj1=1YeFDW6)Y@YLUsr~wMJ&}#KA%M`fS8tybf|{Yu)_yI5tH?!nA&s@@LeG=BDx|B{TN$9armNyhsL$V`PSM z9FBZY!lgF}85=5SDrc+_kquHOFoXi2L5gPr)Tm9w$v_}(P;bEN&H6Au4y+%p`$v8) zkfyd064KX|MqTWx?DI# z)g|<=iN39ocfAW0ihP+pG{r2>G4zIkq;qX13+?AwVcMB{)1-+1N|C0)bz9r<^=|Ae zwv&-Ad4}idrvkQkJReHgK~NOPhkF5Sy7{MrlxyeI6DrV0|7}*Ov+t%c^;;PoY&aaa z&l;N@zkPfw@jb{+PA~WsK8_@PvV)bK%WLu$y?g`qm(ZtD@1O{bbRn3{8Q4WOHr)I= zI!Q2PpnD>waC{`aVDYXo0w=cVLQo7192=LWnnZh9JPS}?SP-qcyre|C%?rS*fQe25 zv7KoxRRWd2;@y+ER>cNy%ZA+?|5^tb4qAQ(J>!S zDKRWlBg%-s>q^vT5dyiQZfz zEnVh7lWx3JGHJ%G3d)&hC^TQuk;LK#H?Z)+#jo~S3%d`U38GPkId7tBp8v_e zu%U;2vEWR!l3+@FQ{=E=JN%Mm`1iH{Y{2m?&_?4;A;XD}fh1a%Kza3Q5y=&lpgO~U zIOjtuE5&M3gy&oP1X@C+vuvfxMo2zY46%q;c(lRIIHnb~rYR4b zw9E!yWqlNa28lz@`~z=dZ4sVmspH4|ye;T%OR0j3oTPs&e;^66 znS4@Cr|XI7MM{%6;TzjJ;up=`EE>WsS%8bb`4t z*}#H;T#K_!Cw|!?)fT8tnNGr_Ld2A_UBNIixF zfPA3tMsYuEI8${`h5P&&2v#$4+eH}#QIj0`__iIH`fqaU2^g~<5mfq~X@3e;P9?R` zcDD2PL^Kejd3@;!yZ>;y@ya&farpLKumR-bgS~FS)MLWOOWk=6QxE-FxgwyBU1s~` zrITQo(-$65pN@x_aZ{6Q{WR;7AX@>jii9b5mJBeexbsm=IGC1U>{oy=`{HB+h72_o zl}u_&Xi`vKUBbKju01{RpAV=;$srZlm*b1H?R%q@OpoOid|H_jT9xe~L*K-p$oOc| zR@crUn4~L1%b|IfuL8eYXluyrTLCbhdGJordeaaaYYep4R>UBA%<}fp?47ia|HI6T zu`qm&U_65TwFeNFylHI82tWC@n&bET1eGRnT;K@d1tfm(@T65l@7j>D1?6wX&mjUf z5St4M`U-^`AjRqsfpg3I>wLcU<8Wv)A-JL30k9y_X(VtkoM}A#*NwYv{XDm((cwCd zBu^G2K8A1??|3R%m1>GU64<-L0rEV4u=%|)4Vuh%?SM9!RT0ywst+2hJ$07TV8oDR z%&efAnI-tdc1Mz#yNH=URho_Txt1nQTi55K$Pl9)4dq>5b=~NM?RfN(f>RhI$(_w|y-BNJ7WoyAo=6TBEmA&iM!kCi-LC~x6| zOEq)b0=)ck)HsdbYmi%>bN#9QW}~`$G{rv`Qk-pcnXee;>pg-%ic-=JHdyIV^syw% zEHM+aq2?cwMl8aaI}iaV4Iv$F?e@0Da(=4Zz|mz)H7V51cj>EHff^IT&`fSGVxz~# zD%jpJHzT1qRobQ!k1$v?<$_zhO$>j2JZ+i2d@%Jp+ohAeMqs1NTI#)N(P`?>=QiN? z0UxZs_(hyVbsH3iIR-GpicF}J6;VR+@03T}7G=PRRkm>W0RJM8#kIQ^kA$|jw3vIv zGr@jhdn2?H`NS1CX{ zJLoV^R_%7@`~w8F5#`E8f0(&`&u5D25Z6$M3GTDBDoa4qq5%$B?9dBA#D!OQsGJomQ)! z#fu*tF2W7O?fw&`EUKzi*4Ik_#JR(bS?$j$2%(#ow-{l5oGN2^PNYsjuRf}&N4t9< z28sOGBAVl&f;12Ay1iaMnai{I&G_@+r6Idkwiw5AgmJb8aTWV3TKGw9=@V^GqaLd5 zbzEt{GtZlbL&MazntuIvvVLJODx>5xjDs0X7;+G`d3DJ2ym4p#S;v)8HMYK{;I`ZA zWr`Ofr@oTN!9hwP2M2b??)}M~3~<8z15r?*QS+A?97de8)Zs0!3RBcqkdGF8^iqv6?wGrlyVtAg6%Ai}s{qdG>#0lil0dbupo z>5wN{>RV>!6ZI|$(Ir99g14IO*Sy;*b$BHX7&#anx$5-D%R*pACPxYipW+m=3DWYu7tE&>2v z8OU%DXDjdLj&yjJbo>71MDPl}e4I4M9osm;k1jIKUTwlmQoZprsGjXGzHjvlaN0;A z4+et2a9EM53KcM5i?PT$L+}YHnm`9e*t>bVR{xD~doLU?KHh{k^L(ii(GLc(bn-E^ zC!eJof0yrF*Gkz;(;UsW?BIH=M$3+<(@nusQjN{a#M+Ki^NtpnF<>%^;G3FX(!nzr z#Am8G;tcb41Nj1X!9gl)x`dWm1kg>7wsr$YO~ILIg2nK(O&Cz(LypqFEft3bbOH65 z3d80mH6|>_bIyMb2V&CK6T50u#4fEL`b`pH>7`ZiLwx;!KJnv4UP){5M2PUMOyxpsc#eL%x$@(1=pASj1WhNA0$7vTYc!l$f8t_YWt!R2E&((g!aPW4q9Dosj_jQ z*nxj!ZSG4jtXMm)pT8%ubasc8G~8Uftw(olO_{s|S%|_@aE8NWf_ZKfWc$hIqx~YD zGZaNjxw03MWRSbM>y}ac6@@X28bS@F`r+A<4Vdprd!&N8dtd3i_a(8`rv6%4n*@cd zobun!GsLyzYHiN7OzI&Ota}xG#fH7*U9r0l&u!E-r{j)NjpXK77Y|!f*{m>_-_m9r z?>wd?mp2z)zMaW`Bw`XA`)1YPp|$u~tN&P>sdn1r zu8lSMp%WiQmF911Y_k(3gpi$E&8Z?+0Z(Va>B-E%i@9T?!*P-mjexKl1 zsE9Z<9lPpE#nw>Bvo&co^=Un}+~LhgG^cci=X<1Ja3ZiUxqzik8|r_yKT8xHc9Vv$ zownuHqNC%nUKrI;NTwJuyFcSDlq}P1zr;}V)xY}Bwrh#Nq-E!)1eu7Rg2m{QSqY;+ zHMa5!bIv}`OYG*9nKq>sfSNpokql$jd!S(u4HLY$xPZC{GVgn$rOaxEi5zlawDR(s zc&E|(Vr!j?=N=L1I){<8q2Gbjt{Y!=YYJz!qPs@}()T#xPq-Pl^3}v53mmJJJSpb< z>;liEGnGsGwfyaON3Rm*+CK3U)ioPJ%6?3A9}|wW{@NO8YU~f(wu%MWE8AjWx%o;X z8cCQYuTtWO1Ljb*){M9~1(zwSmFsAGWIAUN4ljjoy9m5ecm;HO9m|&_fdptZ7k1;A z)D$AYDk}I95}thIaCnMr(P&(gpKzBeiql_sC$S8p`!d+x3V>Uws@7@&0Mayb8M%;U z#LQJqtVup|0efG75~$I68)q^6qJ!pjcbyEQ3ZVUaCtiXS)j+SjaoUjia7wYcPI1G> zSDRZ75@KliaDY@lipfoXR&6>*BW=V2S6{zK)fhFM1y^hy5>?7Ya#lvsh=MT0nU$VR zXvWIP%Alis;2kh`7XiM6uOQmjMo!~NGn6v_P*Ya#-Y0z4`U_WdbO~_zcpW;+@k|2K zeiMpQY@If2-utqMQDK;qHQHk#c))|?!g+{iu?l4Sg7Y^LOIC`itQ;C0u07E38&!Y? z#qX(-C9Wzq6-d$Fl!4L~(V5pO1J!7*VY++(cv;>VB1L1v0 zE7J!wnlqI4Y_yMz(S)gV#7Sl{^b4`+Z?{Q6$~ee;;q*C$L%oh=t%YT^^SdsL;&V#A z)ZquOl>-}JG||?vFel3lnr2^M`Y}Ax#@rP~rPO)gzkJG-Do=}hvRBw;+j;ia*5TBw z#>iP;`voiW9XRnFo}gf;d2EcrY0N&W*Hu%JDSW&tUO6^N+~=EVgd(3CpslgqpuPGNgH5tPBm3Q|_4`q|qk zbfKcAg0DV}FDVurRe(Y5F=QzmOvh?1V=W_-W}Fh)ROHhT_huU~%PhmfPo)`IdtV+X zKK8b${}oM5lR%>?>sFyo0IC76I}K3n)PJ+WXa2)u#Q2)6I{@){F@lkr(jxlcFC_KX zPIGkBy&a72qewtFUpf1Rr(|9VzBP|{5&}%kj`FXL@HT}jfqEH8Q(rtN-ZvaSM8g<> zZs!d&Vfd8Cvm=&3fxq#wA~KjjvXRAFyJ*jvW;6R&4YBq{O7I5A7P`odyW*Xr(H3e` z*L&+veCD-%dQ{CN41f6-_&Hg;uYDr0mW>@aGxBGh|NQfY8|!Z~<=>@;4g7^c{QU#c zalY=q;`Zl#X-H7D{(STI?V%eWUTzXu+wg+sa_@IG}IL#Sx5hnr*)U^!)=ji*mPU;J5sKYv=A{RQi3 zjZH0Zz_{>d!{Hi;EEP|*rpN&b4Q-Y*j4(l*snI`<_}|x>!$PltNi#&v9!`*B>CY-m zrl?wQYFlfkHGE7FP0f%+qgG~s1Lb}{VMhjh7ScB@THm%#Cz9G!W6a+VI5{HzajX6W z-X1FI_FfLnotl>Edfx36&5O@K{U#h)BY;`fPQytJKZz#}uvt;d7f*4HjR$$jx&aJqB$e>)&R1ND3CI>wRQbLJhh4asNuS_=pfTNiG^*bZhG&>eSj zd(W26Jf2!Q=7EJLsWKDLZtaL}ZB^iS9z3*K_I;rj>{ z|6PK`d3(oYB5>Jz5_=dfIDt$gAl{1wK#qp@5{)VqxoSNtu4%2K!WE0xP|iv*w{LM4 zCoUczACH7Ri+u(!b|Gc_ulUw3KYIfyY`X4&ek_%x#pQTPlPOP9oT=!6Xa%A#%?WqP zYn~5*B72Z)m}7!)g5dhKH}IO@xA*Uh`!}428=CU5qG4o;Qrsl|zSsNjw}}t>|ETL< zt#X>LVhj~GV!-EoN|OkX_qZuU^EAv!s`s#!!>i=bK%$|kbSS*L7MW|PzE4u4AHM;tLpim7B2eR`3BL^NfuB;SxCcY_vu7M+hz%9Ra8WvH>PB|u2X=AlL`AlEv#vu~6k^1MY}Iv}wj5)HCJdx91! z4lYVsJNG8XLgjV)8$SNCwTt9-awvpAHpQTqJFEZ^L46iClwv%UToygc`d=&nTRx6i z`rG+1tpb;An+kIYkSHz0H&Z;pir0J4=9&;f4U$Cw)~}yiK7RHs3tUOm^9$q0*c1=e>Z09St}wYxI?(wTE}Wf&ch8Qbv`7ul?f^uOvN0giAIG} zhASmQWvs*uMMi{#urig|lu$32>rX8YlP4f&q@DS66scPKdV>CIHHb;)pJ)b4LR+ht z;Wml*sTBK&Dq=XQ15oMHv%UvZty(AQ$eWNuR3@hgoun&AXNVSK`D=_4K|cR z1_L1u^-oYF7Z$k*J1Xbb=lx8Dvm#T;KtmDHf!Z%RlnR$22!;cEfyI(i#Pf_Z*qYn4 zSe#${!8!dE2mQGph%D5haCk8-e!;{gymf(UzF$jxu4L{lCi6ZzQwY8aQ#zjF@#~!t zmG;-^G`A0XCbM$-lwG;Ap>*8HAT=9FO%IjS&^^|<7n)TB38CW1p&!fOIE!@&kpC^x zqV`k3@XOWlf#%Voe4dQLx9OyEt-iC?Wwu2#e~(d!Jw0J56yO)^U$NTRw4D zKEDljTID!qd$ihm8+r9Urng)ck(veC?=Xo4lLm>V>LNgJQ#*B~5o=gvRKluki&QhC z|BvE$sJ|=kcKOKTkZwjl6v57-#xA`w0ylp-op$U6UEv*95{4g$M!~ z=VZ5T4srf#p*VQzp0ahTs`YcTPH}?-q~K@OxZ-)DqGD9iR1ApfDyj|Z87G$HyoS+F zB)5ee9nRsgWiV_tbx%w>6{b|#tvVTT0=#XnL3#2Gwze+!Yk{}L0yrvYV$kU)haQ8M zvQ6suPr`80v^5BdI(-{{%6|5o>d{W;`EHh(xPb}mMMNWO`}8v;h3OL ze|5$7y8{3nUVA9bk+t$O2%}JzteEr;2Th6Zz>Ew%gT|pZ?d6597E+YNE!)<iDB|DDdQ=%~&aiNk z6Cftk5J_?I98Ckx-1JJAT8FwTjZpNET*O%%sfgK>mSpGZib)pK?%>zjbxx`fU0YZ< zTcA|x&FxZNmKMG)bc&_YgvR)F8csCl02-K?CLGGa-2ambfQ9_I=Hl$%@ODL1(+$Uh_os7tlq4kih z`0~mqHXWU^Rsw43{BB|kV~U^lDZ%{gHfKyW7Sy;LVAoC+(PD87P!>2r&?a6LT*RNM?Jij9mg3mj6*ZNQlq)) zm~JAjUij2tboq_7o_3obl#un845svnPA|Y5kc<$N|2(CJe6fc5Xdt78kcq_)qn=Iz z0tuF;GU>ab6@H!`v+o^Di5$!^kN}31`M%Q7(|(_QZ#1nl-E?)RF6;{t`*9n5jM7PT zB^=3(TQ?BHYD}T!l%VCz_az%j`ys|WW`3#~{XY)^*-7$LgncLOm5u1v?173K%cSAR zQ1w7%uUW$9hp7$5h;vgI&(wWdU1|Gh6{_~Pd`|maw8Kyx&#*Yr z@zCqh7{Pdo3nr@K5GegihHijV=g$Rfk1{587FA6HfijIQ25JRnGBtQzbPmQ@@RWJ{ zeF2BV@pnAWLch2bA33dW_QPag3={1a}@ooDn`f3?7lV&uI$mlbl zN}3LwB0&JCw#|c}c5A4Dk#t+9ZiU*4mv8XNJ2h^ScuAe^WoM85Z0>Px04q2Vaj zI`ciHpQRC64nCG+sbVf_J?`po^VU=nE>LI6j^T?l*NsY5m7mgzO_0e5&5)7j!<7r| zK{y6n3iMl4BoU)VePk{1iHtargxP=J($0b`jgG@{gg~5>(1_!0rABoBdN?eDn+p%+ zTarStobr?vjNXc8&uTttRMO+3p9oeKe*0E|&t*#o2rA<+{fh!J z=9dF0m;q&d*A$bha??>4dRTtCeYFRrMJ93f+B&s$y`bSbmLk|Zi~};1v5j+Sfy;nP zXch_JIxHEhrfqZ=FtW>XG3nZXbtN&m4wKjdETGHq;Zh5 zvwL-PxFD*G>HAf>qG#(P$WcStN2 zZ1@-wG~f%NEhwTze^iR<0;f)LQz!unWT2#*YXGl*p!N&j!USQmq#0wsNkz?`?0!wC zT&PxG0x?ZrMG7t$*SO$~`b3`Apr??A9t(bR5|OjSb5oPrt6yt0+Rnnc>;$s1w%Y@X z=5o2@|Jkww7(CUcNN;58cbOW0GEfy}9ZqL2(}}XAe#Q(?B5>${PJ6DA=UFkym2f zQOv1PFuQ1kG+1Q+df}V+Dh=CfJp(9|DuYgr zaMp%koAraS{kL8&*A_jF0hlfgSmRqC^i3oKE>AFLu(_YTpE;CES7#BBTxNR7@W>Xh zmos1Q5)9b{5tqhzIrVA7I69coqW{}B@y+NHy)ojqjG9ef&xSIz1Yi4nQv}4Oq%Gp* z(Z3&~iPP9*a&lRpDfLbKJR_mfQ1{#st2xanm#Mt)YI&r5C5eVO2UoH&n6)QZDR?Yg zjqfI^S4>-+R$Lw_ab(Y12|_C_4#CCZG&EgTub+_Zt8SBZcI=$B+a+?Kfx*lLdLyu_ zQA4d*N@ zo8@+D*2Jh<^a9G?Z~pth8n#M+#b^KL!2ubM-R`<%!`4JbY;Gq$4=!i98RvYPolK<; zHH4#B#hR`{8(eR!`VIe$&YChaH8sW}7Al0fz=D0f`w7LFC{;TgGF4O?!vXpvz`!MmxH27zq=KWO;S3|=nN z4@pj22rji`I4n}D)(U+;J_8ntDx9#r#Jna(U=1;0B#7njH>p))v9I4vrA=lWuJdX2 zO)&V6x$Wi&&Aj!wHVI+Qh{ zt=eN6<8j^Qr0;)~gd_sSlq6DP-`zB{&#FJ%&9!*|wS338a)rtyW6mU!7FX=Y<+kts zc`FH8bCW*AL|da#XK^4G^*=X0fMt9=ZU5 z8;*;{suuxU$&?7gi+n@A7};N7A^J&)7>Ha+es~*n7*tQ&I4l>v@m#xjTVtj@v$sX~ z?@gLmA!+9JWmcw>s9O0iec`jqKFj77MJY`UstXefbu5*Q3CLnNSAfqpfE-LoJW0IX zDYT`5WajG!%pm-8)gT#fv#Mv;w;)z1b2V}dAfM;8_%G)%-4QeXt6ZQ8^V268Qb%hbJ;?u(nV?RX|Qi|x1SVQ0U){RUj7x!*??%ipm55KQS+Rnp)A z;Q?oMhmMrId#z%5OI-NmpNEo)#eAyTZ>gHlpk3z<9OWLEf}cA@bI{)*xc?$=EV3WO z5~-Ti;DVcvA~_PRLJ6=JR$ce261(d@e0fgT1U#plkMp7HMV!l$kv?SVfMrDUuYrIR{*!)r+O#REut>(&>MY^uKi@Lfx zx;`4`Q%sG&EHT08h(J5D*6QVIrofBrA#SdUZtM_I4-%0kgG%@61B?DhGrzf?YxG+8 z^O+=TauI@p)bDfr4bi>GAO^S7_zPm>5d^5(zBkHr|oes_i6Pxd;b;f|FQLzaZz>M+cqEy z3=Im%&@h02bO{cPAl*5Hba#vj$j~C)3IfvIF-S^F#}G<)Hv{t?@8{${sN{63`7O1V7!ucQ`LV1dw{?4BMHpbQTh40L$cg8zAaN$FLvE4z^n zu+#rsI}HcxQkk%H#5q^hFeyV{1$zKg*5YM0(Fqsuz@AE5fW!o+e8IJ^QJpqv=AMC! zWT&iAGiQd81T;_miM52W%*R`}e7K-Ib#LUwvV-!pT@4ep&sGnOFMpanKDwpgKAHcO zP4wHNuK8wkn&4q(88hfS-C^p)Ji$oJJC{ot=o%77k57!OyMvuKcYZ|<(CE9oF4Aqf z?qS2A_wN322eWE#utXcAE~X zSDOBMpfQ$7IE$7yCuSOk$9xsP-p{A; z+YMAx5?VhRNrr{Al_z+t^f&As8X*Ln^kg_177i5kQdA?HsWh$EGo_3~Ptm$f7CN=* z(;F{}p#zwcr98FO=JRo>)zq=Zr_7{>!B4M$C}$jYs0+CrNBN`AUY*L&t?M>n8WoV$ ztH4RO+gst%S$^kpQn+O3lWC)?!)!~nyz0F-G47}cMBsPLBGQY?)xPB85w>Qkum+5rwOBR#+Let4hX${;Peb$P-O8!5&`oLUoJv4(D1lRW7mirNHM-tOEZeQS zU=sJ=;Eba2ZST&w%HRy)>Nl#f>GfX2KQ+7@p`nMp`scCudgVj7mR0jgYEJ8N)9bf8 zH)FaX{-XH85Z|_-e(+P5c*PuDo+OyE$bPgBji=8}p=VJ$#Y(B|Tc?`?J{m*U_k!Nds{napWboV5ki;glPXLx<@ z*^nm$HFtd!qs(Dg`v#~o^bF&!4ti`Yk$OM=XZFHa;tmr0FB^F9L>x~F`5n&3O7MlY zepy}axD4?l{in-hK+)!?JlCEOX$12`)5i8xMU{C7f-46$S(?@vq2_>mwL}!MdQntF zL3n=H7DZ0oA#J%v}(JS{{^J&}Y2R zyGhJ!?biwIEBEugV5aSA)T)xOl%5WtzXt}!S#AgBme#G9YMz@ziX41j6d-0y4?86`?7 z&AYL)xr4sj9j-zskw7ksh2n-C-m7&890_gsfd^VVq@Ux@K$UPI_<$`TR5F zp)WjNj<>ve)->J2rNI^#*PEc6&b?e4qr^h$!dtV~W>ZX;DRoHpqG9hOS!|ZvWmXwp zZM%+ktrzuWLLY@UZnN)GWB#bg1Grlgx4VD=cJlAb5=lotV(Y)hW z2q>&Siljg>hmO=vE*C{Mka4(n7k{$4;?)1r?q|WRQUi(mq_&KIF#COdHFJ(_iDkl6 zj(a~wPQ};GEiu*O{=i_SIIkSI{%9^H|D_*3J0j;tBc}V41~qfe?PXnfV(P|ypsuH)S4~*Yd3dyX;vDonsr`lj zCQGGRI3w9zJMcYG;ob82_gL3EKV+`YhkK($_gVmvgA7G_g=KWT2M||sebH(oCv%nq zg*yEDE*g;O=|(vyP;U@#ToD4{z!ffAM+Rs7F8j{}U2Hm_?d^=%*Lw}~e(RZGVvbAE zr}KVYKZ5-nfdvG_F5`g|hiz^v(^?xD%iP^d_+>9F#FKG`&_d5)Fp0-$qFcuQtP~65 zIH4;OC8cNRxv>lcfVYr(6txd>e?!4$`x&^%ZfekfU8KuN+vzLP@vx*=juAC3ssih) z^gB79i<@B1POLL5Fo2JZ^^$U^5bM||D|B3+oWj_A3=7gbFT~>ul#+4;`z6$v}5Q`?faWPVs-uX;L zCIV$X!Q!I?xWY_Ax{rSmP+RHS8_McZPOj|zCfA^t{K6i6h8Z6DTNHg)q$o6d{j15t zZ*w6m1AbveD|8XKh=h;DC7|a?HeZ))R0)C7T&Jz1`=%^?W4p`KB#`T5A)The%Bi)z z?Q)AuN|fSGrd@j`m@1|_Pm~ad#KiNWB!|Z1&L<5@Y4w+eBjSLWr%q1hF()gIC$c{Q z64^MiN`7PGxSk+eS9e^rewg)(DZyDJP>v|J#NqLZyL3u0@~~yrLlNb( zdrITAbl>PQo-0S^!}jHE&~|kfb++pM?>2lDbXj7kis17(Mb?IFWR3EuP$tGXgV&#qL%;mxz8*dntBAkTK^kOTjE#8 z^}*izG|Ek9QMtOhAE~{MKp7&Ng{Sa6#EymmvUy`Q;1o!jXBRx+PHs6xSJw@@;LH_n z30lp3oAXcyBk#ObFL{>iT4arQ^iMQ@2A(bPfLTS@fgeU9K7b=IZ~q06Ve!$nDbxr2hi z2-)_-Mip46>m#a>D(j)&ZRq78nXU*LakuG8bA|Ysla$TV^!+(Enq19-68*A7Ede0+ z?T88K#~cBMyk)$(Fg`Q1D4lT`r_htV0AyeWYr74rCwiR`H1N^=E{{m^=JA1S)oVYR zv)^Jo7L7a(JDkn%`_Zf<597BVrRP|;LsA=lJq}gGBNC4OPE>|z7{uZGXootTJ8#HR z5->r3lPlg7J6 z%pL|&gQriMm|Pz{;e*f3)HyUYr^}e*X(j7&!?{2#MX3l_-?SYwv>lqhdVK0ec5xAc zkn4!qUwIfHsmh@~^F_M|1fp_3ijI~w>nLYP`R#Ull8?6K0|w9hJ9@LAxOwl1kpg|p zvT73I&LYu}1klztKjE=YhOs;;)M_&rtoyw{Bz`eeF^Czi;b=DAt2y_vN1AtD&ha}P zEQ!xKVS$P?`~eW`TNNXiHUV*mc0NKkvXiyquRVo{v&RlP*i_d?fhFVnrZEU93*=Y!Yo3plB{ru}ci=ud3W zs`|G@RY6`5JyAw*{eH3yCy+%iE5z%=mj}n|ukdRy{u3-}Q9{@EP}M++pXFkh;?gQ3 z=8f)V%GJ}Q_WS*#Q%SOL^w&USQx45@=c6^81|=~-8c?baJ^QHgMjxGy6o6- z-7;{dYyDM77q!Um-vK~a$Eq4HjQs@k1LQt>!sXoEdcVT5DOu4XPBln!zIPDmxa8Ee zEn@NkmK!2#QxwMtR_JnQyhtAS(`E=?)&Td1#*LepNVjJv z(1r~^-F8%1W#!k@(HCBd(!ELR$j89^OH`!$xx ztChZ_Zm1BY+|lXD^O12k$mm?giZ0dRJRyS5fi>R4mj5KpnBB zB*hRJQz$f?3p_kyd6@Q!p3=&}A>;glt@>(S>4iv%nE6JfhJitxyjxeuHV}{dK+!OU zl(C9qUC}L8AkDGsVkLI|!%7=~1o7{ZM^rL*#97l6?Fv`vdDtA^0cES&^*yc5Dv?s5 zPg1grwEU+6r-ziJRW?h`_{e~Ps4D=WJHiiQ9L+}1?qp5}4;}%x5#Gq_9ZfX}WsLRQBp1+eA zx5K(BpWR%MT#rKhc^M$6OQ6IUlc&xdW94R0V_2faNM(mcxFafuhq)O`YO1(2H)$?`D$l4#mK}& zLbruhp*9GB==MGH)blg9@&5fCW31{BfEZ)iQ*FuK%No~%Im{j$OyRfO7|mbqm61t#(2*5wrJE~s| zk4vHLJ^d2*3x0cFTv8Bth*k$VtH}9SvAK&jRq!QrbiRSwF zIQpSNxh4_NEztonDIz6O;g}ei6QhsmUh;81uven|*95n!S)R}sQ_$IM>wtm6WUT5R zX@;%3odqde;sO%31fB{_Z%2`iK5)TZW|Pd)w9>kWHc1H16a2PIf*4JqjNZo-LY2HJ z-KR@BU$OriW^idVfSr9)m7_H*H7;9?C+yaoIKDIQ0s++B8&x55lp%q4i&|UcTj8G1 zHYf$&9G3jhdtis%R@C`meY?M=245~GCfgJzBJgIA!XF}VN}==sdIKwCX?Q*9a@q|f zNaKb4G7*%3_W0FR2-I}d!2P_d0^_+^Bv`#j5JXGtpg31KE}Gcp-a-57qj#}Z$wait zjWgMvj$+^mZU|ZK=u${gtf^)s70!n*ZPOJmifH9FqS@r6UjUBHPYK0I-hji#IZ%b8KA2(m_j6Hq)P1=kh zMviM{jlz~ga8lsmP|K}CxVdpzYgG+%c4&vBo}LecxhRr&A73B zL4rVXL<-S1w(7-4@91-+MKUemfOQ*fySaA7?T5-4nyy5zf($LHq+L5~=yf7et<#=b z&w8@;RV3B|(WYR`j9aH^M{R zr(Najz13yLoJhJx!9-)l-g7awXGKRGyx!(tHOGwHQ7`2s0FD@7ADnO z{p?Q@Ee9wNWWRZz5CPH~&L%P6-fx0a!k`yfzGO%x+<^gPleeyxg zZNQZUK*32BNqzp8{fJJ(w9}K;@%R@!6fgv$bxTf`i>Qp8NXZdD!!S{-`z4eCfK+Yb z=pOr1c^boYV6i^6aY?;#^57)brwxW4H6i7U^QW(k$Nf2OoLf(jHapG^rMI!qUwDU& zFyvFTmSO7gs2ZGM*lzn30ue;aW@^C*%6$KIOEUQZiH1|{!53@jYZD{d0*UpsPh0>` zGM>RiS_%SAUu7wRDB$1I*%~*nvl=`F_H+OP8S@<|DieuSOZ`$bo{neMU(9EH? zBGmJ$OaSLAe!SlBR45pK)+*OZev{0|mxDAc1`J{ZF@pa{t4g)^eGClI(VqMyTQTwJ z!A3!=pRDX72EzRiBF2-WB~pm53<@tKvE>oPaI}@(u^+s9xWk_yP;RQYK?%SZyVU{t zx%wTxPlmjEFB2GU%v)_9wnFh_T=IJ?*r=vM=ClMGqM$st?k6b?^?X)CIZE_4P!<%N ztpx_4YW5EwN9`D&($r>!sZwg%d!gWCM00vr9onJQBd7Q%x>GXH5m!)%7%5hD!#r9BV`2h z5J;<#Tj2!3qp|su@5n(De@1F|B51k6jGr6@B^hbyOw=-?JCg%HLTx&P-n^e%;=IA( zZ`q3S(YFw)%5xRSe?qmLkEZTuHU7cJ-zASx{021}%P%%bYuhLmwiz$9&Xx|} zextw}ZMx)vx!UkhPfpI_C#^_I|7 zGc=E@S00f>%-dB{0k$5seEg^Z4Eo%H8*9p_qKgv)GNmgdexljhmzjuQe*O*d^V28G zSY(J1a3sV3uE}KEm+v|h-*bIboZ8+dAO1=l*K>8bgX}_|<9@`aDPm`vh}qPg0*Lhr z**(MA3bCf9cv$)>+Mh_MvrQaliG!mjd^)$)A#s)C3JDMmU6q$7zXFZiue^)gWPO~Z z(n-Q(ML?&1;&Jj;7B$qy?}TsM(%lw_VT#5G2J8=>;PtTr!`UMBeBDj!>{j_W1qO@! zu>w20DOQCe0>s7JAVuhWtd zpeI$D4#|gG^#LNj|GNNU*@Fk#odhxD$yX~+{=6wbqSxhmt3?ONxFTT{*@^^-Ezc`p z!tZGU^Wtb}O)V@yBj1}$?TIZwARHnJ9*+V2j=pyJf@ga{b(M`#+Odv#B}%#!M4ueL zz5#z$EhCQTs5Jk2>%SdYxLSfe(Dp-1`F0DDMOa+^L_w3E6qqDTT9>C=L)0&69QuOt zF_u0rTVY^e5Tcb3Qbw;I?P&aL{AKW0f|&TyVxZs@2af)-Q)Ws;-totgot99XAUkf{ zcFLXL-v5^_*Tdj&u(UOtUF9SkbbYAC_fJtb(X$>-&|xpbeM?!F;U+aDk97u45R%4`QK9vlFgKPIt;=c5pkDx0c{ z=8@CwoppfrQ@lE6UG@4{_g}-_YSBcXraxY-`mkk}+f7+#Q#-|~y2HQDmlZkpD?sVW zw7=;WlXL5?|G2LbQJTLmM^^#H!-56H=|rT+vSq6i+%xR2pu;O;UTAszlMo<3^}{G( zh@b9HnFzaA5B}t0(h<RaRDR(zF~6`**i(;WO`D zVXgd1qTNhG4ugbUUObd%>*#SaP>^dfENU17&bJ`A*Vp%FA;9J%FIaMBjoy~nG~_w{ zH*H1&SYjf{d2<)ke^P&q2xwal@FtWCcLIZ8iodZ632<)qbK4p|2tXPA%L;=sDv}#P z;^W!%>_4=G2voxw-1wuzebT!^JFtmB6|~kb@c34$M>e8D5VAo@>M$~pW+%DDxGs^3 zaX6Tv^OH%@6f+L2jm{%$4duQx{s;6Zl(}b1MKJsX6*3I`d+Q#qm8PX)h4w< z^(;{D5T8wUDz+iK0wbKZo`TefL@Ky%oN!WzR=qk)3!SH#MKs)-3v{u$__z5nNtVtL%K3W>A=vZ z5gm};js8>c4Y}vmF_YlhO+AWHFVNV2 zYrzLJ4YdB02Y5t5+Omm(4^-KrOYsT>NfaIwsgmD|z=M)n-!q0v(n}Cjz<>-9iKMAO z-K-7wr%x!1hhEarvc+{*t2h+v7V$}Dzb|etg@3B$x(ZF9)u?6uLm8}l__H7WpgN4J zOj{(Sn>4ILK09-?(^c#y!)&R3yLcA@Rt18;xq@DjqGsN;b6uriCId{7J4rEDFMrIs zPG1_(-1v7oUU}7+5bywRVj8S*ii{(l?Li>!a%r!z7S=!;f=oBQVoQEH({Bv3!_&zC zCCJauZ|&)gD^3nI7CbEcq?)hIT<=!HJF)=<`!zK+?{bwyc8=ranEk?POz)3Sj?j)D zOYWYmP8&QOx8WVVA$i@}ddK&gzP<0*8<5Fk%l`O?D%su&v=~NCTj3od!Tt2w2d=v>^_b%qFbMKAwqP ze>Pfj6Ai1aV(x20+xv6@Vr1Uf#?adr(TWU&EHK3?-MletiQi$^IC3x@NkWjRg((o1 zWU_!3Y3dUkQrsXQyxn_0j4-(70mmA#`1I}NZk4T+NA^|ayRAlyat9W^K3|?&5EJ;k{`b!CXti>|bimHBm3Yd279$s-fJBs`w-r_~)x~I`k{8N>x zQ6QhaqNX~-S5H&0 zf*);*VjW^7t`|SayA40zhT}E|OChJ3l7nQSa%McZcwKxN7^T&04?t2epE)xi>|Pq~2+Qz18}e0lctLHKzK0bhYSOx7 zpvJxqkO@SADl%E0!KZ=W@(-&iQus@;VGt0`2LR3hDrnUN#d9XcLYlQq^2KwHLzqHX z{CkgwcKytcr876890~#8cq~R-bvddKlTJb;x`b$_kWsCUsZQg3Z)%RJuCk~9Uv4MN zH+cN8BYhXWM0QDaW{7g~b~%q9*91>nc7{8o!>#g=v9@y8mjJtV_d)dAQQ2pV+H7q- z%bLDtqdZEOqa>=fk0city4*fYw8_KWxslV$1u3#E5fjO;C4=ry zd&?~vcm0geOI^Bp!PbCqcHFA}a(R~c(N}GhFk>Yw17)JtY~~ z>Iv!fS4EjEG*8R~y4Bkzo!2JvxKjvj(a!+0zN8{fJ;UiK@lD8mQ#9ssE;f(fvuw># z14b_b!0Xtiy^BKAPO;0*@Pv`=&YNQOiMjXR-$3|1$ZKOB4ZM<~PuR5IS@fQ3@D=)J z#g+DRbrOe)A{)0)v7S2bE#iy1{@Q6s+q*uc;*GxbB}4a)WnhjC{MWUjym!OfPG&a;qeO%NYEgzE9A-41uU~w* zhM(p-io?`+GOU2L&9#i6xV%0|n1~=3-MG{;K%pkaGIqt$Yl}((%ds7}q)!`HM`3s~ znA`-T=x&RWrsWgKGRu*sy;~_{`C8Q;@+#Fl2N5o54yg^-RHjqSmUGXGbmVFpdxP`G zH;6i;o(#`jkB$ri=MSSl1t{&VttFnGG|taE;ey=UBgOulExJ=yj0~GA0Oz6RTxTrrt?Y1u`Qc7N{RpLGwW zxfeh)i~r%eS)=QzU+ZLAC(uej%AxCt+V;3V^o&#wPWQiwv`z5#X=rx5mJ*Jl!7Ra| zu70N&;Wq4rb0N`FQ4o~S&bOH6{i|L7%>`T_$vU>gGEt_y4z;!`>)ds_WQe7 z@CgH;c1VK~m6&tjCjpRU$@=9)epSaInJ_2?;X5CdR~zkVwe@@~43&F~L7Uhyq`Y=-V z`i%`E^hKvpb=70skpkR7a{02B z@9}579lw^-ar;+RrYpA9hYdzo7EKEq*i(^qKid~^EU0UjoTQ_u^wxHf7c$~+?I`4- z)5DQU*XU51*^^&1^A(4l;ET3xkL&ABlt@XswcL2Yu_w6r!8CQn)Ye^(>wQ4Wn+z|7 zBhH0JZ2J&c+@i4E%0hg3h2VFOq?)Teg-eW(A40Dy&7Q&oibiPPq=(WL;dvbhg zaNX2v{-3v^Rn z>lTcwcAxAC^gX?I+lk;cG-;}+0a^(JZsc)i-<}HeoBDv!{$auJ`jK);Ex2(6DQ;(R z;%9^^WS4;=W?n^!4WC}=lr%|0fsP&d?2+P4LKT-BpK^w}w?npE!(y)3p!>}-wyoz! z+4BCF0Hy7xTnp(adtCfju!Cyh6L@ruB2N}dLzGeguo`$RiE-Dj5 z<8s#j{v)$Px4@L{i*883tQ8KX`K=^n;M^^Yf^QL(X>YCQIn*DOZ>UkV$^{g&vw z;R5)a2PM(TMB0kkua=qs=*Cc{6tZdE8z2sKB*b$X8A3=AkkR(PZz)@Eo$F?-EYr`^ z(>(a@Mqu~p7pViBHDQ3HcO_0{lq{c{vW%AB?^$NsXj9Y3pc(z6Vg`$jmVU0A}8 zoTCa2G8KtNK2_3Z1=S|zFoO5ZDJ#C~@0Ljs?wsnDzKgU9=Y7~qY8ySh~RtzQ*JbX|%UV>Q5Pv#ZP%R|4dX28zu zzs^m5BPG|85t$$)LGU5yy{yXQj^nQoN)hweZlG)v?1Derax!xXvyE1U(UGaJQ&*iMg zZgr7fXOurzU2gGaeGXBya(t9Q&R&L@V6KyUfu#}UGTSE_4xaFDSUHzBXrN3uJqSkBT-Vg!G5UC?WpAEpOvG+g#hy%`l(+pI1NqRbh z$-`AeitoLWNa@!snbS}TRwIzAdwGKOL3+_>aMF=k9o^KmsN1+?(`|gV3sWAgt(V@` zts;@C!^~kB`dy7hiCy3N2i9#_?%eK4JQ^34j!~J2iq+wgZfALlC!DsPmEo7p^|kg+ z7*~!>aK&#Nz%b@#p+1p0_b5<)WtNUK(m#5o` z&31w(2^^olgRbcM1)XYsdqSu=4jxmTt1hlg&2#7qIJKUci5D7wH$F;nK-r!g#Ig2k zqaTBu2Db6ACeF7U;{EuXh8sC8uJt}L^a^U^k9#_|1LBAmJ*9u3_1&h!ZdbqG&)!BN z73<1*ZTM%ZV7X%!v|yxoiA$6rG&aG-Oy0JItaNG{)}{QDIp%o(a+mYU+prw^<;{s( zbCzDx!SXyMkC0awWEEZJ=d-xAqGf2{H%QX}GXBAEoAZ~WKbI*};;!G)10`rM9u+uK z-9dL>T1rlU%Dtwy$mXKh;1Z9FcrAGcc#*}^(?7S_*Dc^(E;;0qh8n>|Yx=9EriyeU zDJ~D9*x-&rX;D|JWh?!9Sg)cF-A@1RJzt=NP+HOmlAfUVlJJAx-9s$&ZE1Qr)8_;S zmyxsTJpDjTk@EDaF!*ed8k%gP#3&0Q;}Qp#rSGtjIo=x zSCDmLF5_A*n>DVh>G?sJat{5jmZaPoafty^0(i3CxDrF(!rpC_SkGTH&&i_=e`Mb# z(ROr7YQC~Jc}`wv*yP>h{hHri--fSY6uK6VM)~ZtFu$8F!m=Jl*z~SBhi_RgaOo-4%~vMYPZe&UCm~(jgCc9 zfJREqVwQH<35)5bW zOPGZ(I5Fs;c+b;nC@n2(-lE(m*-Ea@FWm>cP){6KwaOL}cr1&rP3m6eq}XqZ{CpH6rnYKjPyg4~$8o2I4c3QP^(!w?JGDO*IU-n11xaNM1s$#+0V-@;dJnnFq?(bx zMY~$o$N8CczRtvF*n0f-XxD}IJAxCNuRXkjz%uk|`y*yKnQ_L%w{)FmY;W>gGR_b6iwDr2kpXFtV9t9;6E z_!Jo{wq9>vA*5^Mk=AcN!CN$F;K8(7_`Fl{{qJ_1MGBZ^h0oSr^r`5DV*}nc%I)nS zf`lXpsaNZWULzAtSIpq7@!I5DW>uG^C)^ftl^u9v65avZZ}Y0tK7gNv3xRbG%kda&*=_#(jUIr*c^XN1vRG3S$?g6UN@X6kw?mBpE)Qx9JS<3&)M z_DtZeGFrY>K3}_A(BV8ddpbM(XI!bqZ6%dP!14FC$9(;6I#&1tI#8WHg|awL`=Wad z@;tt#Q#o<3^WK1$zyCFAx3SLZ@M1~s@4~wEo0}H#0hPuD1pE-9&L>GIYksFRtX41R zl4}mbd?|VO$H32?rh9%+GoIWaSa67}DT|?l5U@Lor1$M-8A0sZ4bj!D+sBY(Vfc?3 z3Z}**@p(VbCLR8ox6;t=Z+V(c^+?PKDyp}6pSr&eszOh9yy=XRQ+g}MwYs__dj9J! zps{Pg_5S=JK8eGzcSSnQ!P?;~CC@uq6Djggqk-h><-&ESW+olGW@=>Rl5Xg&gnJ@7 z3izZrM7gr_J`1y#2k`2&3lDE=N|uL*8J=-dBPL0_Hl6YPDf|vo^z!cDa+DhU>UcuS z=m`<_J!m%vwv05dRZp;CiN|iUsJqWYSl_Zd{7f9*cDg*zIlHGlFTS>7+0rZ_eYQYjUc zg(v=VrN)1JziItr;RIRKwa`1w_-xNDB*ysrjeu{fEs7Ti`OH(vv%DA#rTx4 zt@*jvwN2?Gl!^x;^7?rixnH}@uC2$P%9T><15MXwb!jv&&YUEK)&j#mz4q&8MBTuuTGzc77iFFcFTrbhGb@%c?jBd z>k%`69+D6Yl_}h&UZ-4>C+naq!g4j>g!BooC`#{&lddoy0d1YBXv5E2qy;R*kS{R9 zJi%2lqn&Q$|G^oKDvks9Rbrtm;{2RbR}X&^Iyg7Izf1BA$CZv{xPDrzc99t=;7rUNe zV|WzY8n&P(F{!Kc8K3?!`YnC^a4v%pQ~5jVBrOyIySGVKXKVq@J`3=}2d(wR!l`&! z-Lk0ytEq=?Uywcuy!T%2^Y?ZVrBtque9pNMTnA?5^VQ`327Zje4a2ff5X(O|ZSiU+ zCt@gkhvUdNpkVPsP(1l1SIGpOd}fZ-(A!kRJ&C>U>!k&!56_-U7()T2jm$O2>BkQO zGTXyiqqQL)A8l50NuMm*#QtxDw{CH`t%|fPK>GkF%$6k>pNw1jhcUuMRimo5IFw6s z<{S|@Kt1}R=oi_iN1w+`Bmec_f|NOB<^Cf>2>aDcSwo z2bT^6*)FGdfV+RuA zL`1g;f=JnJ(4<;)YQRHCz>nW2wQgxd6CpT?0+!jTAD*?toWQ0Zj9)4Dw(Zs{ic7@u<{bb(T9`58=II2M?ES>?F7iXN2ektX0q?P; zv~TQ}5XSQeump>H%E+>;(!OvFOb91qFyqaO0YLlbUnJ)i2azSAvD3h7#+X@q{IdYS zT8CU|_h8`y9`*XtS)l);UM~NB#8wK?R1hg{UnDbm{ZdK)^EYC>hj;$Z@IR97YeR@3 z56=R~vNMEWlFa0Mlo1vc6#w1hWu6BkPAs!r>R}iOHJ5bgXN1&ZCcQ!I%~)==1i4P% zj;EKSj=F3ed@2(Etkn29aYQ@E&VN4f`;I^pm~o(P%5?mN#>6oXUev>fcm&byPdQ2! z`vzVD^lHZE?{V^zpGk(_K!WnEDuw-0++;{}@tP*Dn;XMfzLg3&p+m#&yjRK39tu5y`);x3{AX};pp(K+UGJZiI z`QO72Zyw!&46qPC+Pu)YFI^A3vgB-DOr-`Q)HN7P8DntvZ$QA8EbjHV=leW*wR^tC z;X!RCuQi5l-#E(`V&RAv@)K@RT`{H=d!MX-qdFT8;q>2g$ByqnG(q>9-)kShW(*MUE_yj;Eg+EkFDR+PKC;e z93QY1yL3N0ZaAGIZYVnY9{Aa@ZnnNytFC;b316I1-t@rzJ&qt2et(MC=_n5n+PlqM z1-9!1>pr~ukNEP%RVd^*DE3YT3etMs(icwbD1dSmz!>r5g_XW< z7;`9){-pCpWFLqdsVg#z_??1f4 zKWbX6MH%_PRoil2Hz)IY90)H)p<o7CmH%a{~#?RCVL(^RiPIKyEW!lWz;7%9k@G@BydeVj$8yz=x z3w0Xkx2PDiZqmLh(Bz!24H*zjv%A-Z;Br3^#G_-x{*Z4-xvT|U-HN>X?^pESlJO1- zG-+TjI!URFR)iZblxeG|s7R^|tk9>rgpCz$dW(?C(BH(lH=${UzyT=0o**SLqGUze z3NO$7)}MZIevqwjiUyv$N2DT#00e_X%LcwODcrmvV7;kNGkn(}Sfd^8-f*>Na^6>L zS)O?9u;@_s{qsVptmP1XIe#T!#xSBOI~M6I*G}61nAiHON)3-fxk&MX zvZ5zD^8FW5QMQ_lrN++?=K(k7%bv5+GG?$!_8tn&5TJnEU=Zy{Ke%zhTQVvqg;aFAuu4G zN`w=^wSX2GSXao=Qc9pBekcV7NeCRy{L{z(_r@ITmT~vEfaouyzUJ?sZ0 zc!^*T!Vu!89HqMK95svj=Gv(-W(2c_xg*QJ^Nzug-agyZr5H=hj zc$|f}3<&a5J`U%SQX!FI`Ggx=3&y_l_2g#Ge>=Mk+$p3Zhe6BU#=6X!cxXc`bWVs? zKeQlZC%pDegJdizsab{>QgbIEq+vl^Ir-N59Q0t`uUY2*nbv$qA4?kwZ5ND^&K!~* zHGb}BKnG6frK5P1pDas1>iAuD!p$ah%ovb;`JIY|mKcyDWMH6<>NJ(tmuR?|@msP& zoVQ7-*b7xPc+ay2S7RQ1W)21NjAEAo29;+Ep@do*yi-}C1laVw<^N}@mt}_}##F&B z#qDuRr{QI0`WlT@0%ek}H`~*#uDX}ENw4TqB{l#1SMDA5;Tzk1fdcQiH@?I``QLtf zi+PB^_~t_|L)`x)*S2|e2?n)&3sf%cPLsIPD*x}dYUycPSlI=bj5taXipGm&;Cg?e z%e2*#xsp9Usy1O}TGdUfllwarc&CZFb$-Zu`_JEk%k;OL2FXwz#`%aS!g0LWSVPi{=4} z6fGJc1WGATyupG64;G|Y@UZVbec$(6```Mr_P3A4AC4me$(;8+=N#iY$2ICz&F{U# zEHPLN`Rbg_oQs*HN2jhFKQt@ruoLrl%{MRA<2pqQZt|O`voa7pkB+=no@yLgxJ@tus<$cb8!yxOR5yDa#uerjqkizdGN zh-Lx|bK8sC@G%nsHMn)v$^`fy2iNi7DE}Gp1x8>Kc@o&vPZ!2vSmqWW@l0V+?#@H? zYyqT;zlknaiTCZH=3qP&au@3Wgw!^QhVJ?;h;9 zko(n~v`@*9$j2tT59`XN88bDmiJWB?nKpHFlQ7WKx30Fxmv!UjQVZD<{$-Yh#psP6 z;(@<z%UV%4US*H^?+bbk87K&54oaY!s^~Ia^?GY& z;w^R z7wcUVTd;nBk=Y*;q>~5`$yBd#8gr{L2agVhNd^dI3Eb5AfXO+h530~hq$iJMrhPa= zm*7t)ap(rNeaTM~_a0317`VE64U6us$$uX-)clSx>E-oyG^S^83R%-|o?#dPwX2z3 z?H$cL962(s6EQ`Fuk=f^-cVuEHyL8b>k4l-(Fti}*f$48$-k8LFXy6o|BZO4nd>}Z zXLE25YZ3{z-W8n-O;g@Nme=*WZlhuFo|K@&j)i<}B!A}z`zhA` zw&kint3y#-6}CgWBSfzR<`gnGa_j!|SmpS}^n^Rj*y&P=mdixt`P>>q*SOP56{dg* z{mNhK=LyC_Ly2v>zfQfYw>>*q4;=llqy0u7OTLr#SYU=ic2(G-(;KQh<^|vigXK9M z$7rI5t4bxi%(woEib@QtbUAX_U;ImBR7=1C%6lv;2QAlureA?KR8 zBJPtvi!HZl>as%*=g#dpQ^EG%;P3FQuX#P?qRb?Z)@wk=JFc6k<|2awloDbE7dUt6 zYs#nZxkDfL`T#H=D9U~Efpt`9i+K5ql4k3hu4StRgMc7lebnS(>u;7XmJG&K>VFpS zI`dhB3OZ`k&FIA|`GhH`ynT5~6dkBmY3fIqT<^HMGh71J{GQTPUuzyXs)0Jcf9X0= z)tYZ{F5$Q7l?$3`3EB|7Z(ilApaYa2WTa&lVOySj2|l7ODk^5t>Zg?SUH_SfxTDTu zTN~VHiB{w`tv_s%mJGPeghGcYqYIjR)~Z@B{(5tLIP~{Q{d(l{7e3I>Wi9gL}+jltA{_-5B9;e&xOw zI6|trRF>t}m&(~6O{3BMUL(7wpe78Cqtdv|sB19J7?{h08o8wx{R2CgjLDf7aW69| z;URX;Vu@iS?)4sur;`+RN7|f@6d9CTG2gwCc*T^Nl~!)tVWj+_=aN%>SA zjp(qZ+VGPC?WTn(9o~{j-PPfon)UuEOHg{TOJQEnNcLu>L3{XG9%5A!YFPF1)*GbQ ztAW5mJJGB-wRX$ND!KE+0d+>*W)~He-r>PZ?^Q0w+M+xqf-4u^kf} z^=#1k1CWBIO+4dBsx^$Xtd)W7oHT>J6om zXa%=lcXr;$@mVq-7mDDI?Go5Isu?DtiIFk+XXhf=uYNJx0 z-1P|Pep|x}bDL@GOB+YzRlJ-+l?J6myt$1kGZLjGFwxU(Io=j@?@Qfa&|)cYR17me zjo~an{@6x@p!xs48g@m=Otx2}QWfM2*rr>%HQhbb*=m;9pCsEUi!f@wf3asg%OxF#XzNQ12yqrriks?%I9eL*`4~XLNC{thQJ`s#GZrkxaI@L zP|fcUHgl$cjicv^h7*bX>5qvh|6Y-M?H6Rd^*xqQ^|sAlxrL~5Wu{f{j3D<}*UU^4 zwR9f5O*cj46T)@bFDlC{bq)jVh;w(5Y*E^D$Ki`Ig;;V){N&zF$gW~x5ca*9AYsg_1NXk-h!{nYNTzXJq(Pp+xRztA@zl_%qgF*j+Lu(+{nNQRM3l=fyj zUN}NEVu8doP_COtdnW(lMMP(kzsH{xM5=Xd4tQ(dN2S-}MQzT(@MTKwd!8RZ7ojfcArK z^i$jC$T{##+AR`g5u;5&Sp~BP{p^hzq|`Go5aQDj@E(dz#Y)arlx>2tMTm7y2{79a zqYBvM^=C)XtM%JxcrI2-SUMgeB>X~M3s*v<6goI_H~@6`#EpIKO@SjkG)C1~`hQYH zrB&2_Pnq9xA$eCBg`2bn@94$Z|&WTpM-_y45omo-qI#IbXRqndqJ#|3NbLQe< zXgG!21_9y%9(`jMH2rBK;>Mj8|J}R{pmct9;L>IPLyU zf_=e2Zjs0M!_KA&JI+xSr7oFT`Kf`K#hr@AJTzBlR_1`z**IP{e-qjH|%JnPD z7;+(BDPt8GePp0DjwoCdG<15$lPo}zr`YbrFo0qe^QIvDGDDsa_Xv_e4R^8=FC2W_MmN(~kEo%07DM*< zvK7Y)=N1+R^F{Of+ilC{Mt$3lt!~d$W{X_~XNJaZA7F4zKGucBgMjS->?{gXBId0l zrOSsoz*t(8hreObXmp>Fa6B6$i=DA)$Qnq0c?!BLOCC0`K_``1BDLt3*L&qki|+4MVJvysyDvR^FI?xX=vAO{Bw>oR;U)n?V9ppDfh@?)f)yxn4&+l| zS4~+NNzx06qLT97tqYsgf$#uaJHCbH>=-V}x&|y$Xl=x_K{m{dMg7-rgU}|aCJU;R zx!@irfz7idB4Mg$OJonDa)%C)!!pAkwap{CC`W|{?f3~;@y294%>PZ6!f=i5T#Z6y z41!Nu&1o|8lp+Vj{Pzi=pS=#YKos0LVy{AL84UUK`OXGm?jj+ls%Z{f`1cU8HDD64 zp*YcgnQSrVISRom?oQyy!C~MkC2k|nMIL59>B)$;Zhu*AMJ=1RAPY5AlDc~c~#dE-J*v|lVv)H@b2YetCK0jN5}7RJ?z9C-gNOmw-$U zm6Z8|J1?`ShXzW;LN;_W`la2z`_wsT&F}R9vB*S$f*NBohE}DPSO+lAh*w-@kh~IO zeYSV%t%MN6b<=p9d0`TF5m$Nr82!|f{l~H=mqEs%zj4ZieL&}Zk|&mu%v2NDeJxeS z5;Q$>>i{e464=QNQ_qp{!Nfc+%X)M(UuSd+U-_uRAVB|=Yy_D$*eIl|4npb0 zgLm^R9O{Z(t1b78-8!|fT!wYzW4McEHNA!{kxB)XS$N2Ca?t%;dRAiRGV*w~6o-K- z2r2Zv=TSC}=Fsa5YpJ`qsdYf7%z&bk;fi?6FQt9O^&N;A5; z2$NiE-HsOpj^lg%nSw@FU(BD3YQX&Ie|^2d0}C0Cd2FO#?Qbwh{rzLHb9s98WXor3 zv{pH_u&YG)h$LqQ@9^+orE!t!V2fY4NjtuTA^kD$r@PwU023^qZZ|J!k(CVxjk;>* zkZm|fE7a?d6Gt|Kt&T4@+%6k;H5|;6mS*lcz)3Dw!*OSZ+-70Y;NCDI!UFno|g;%|jp(g-XJPDYiyoVm>8*t{O|H+pZ zrOl-AJA6NonL>RIfrZcqLwtrH1<3VpK?n0xf^)C5?Bjr#gI88?>9bBJXvdevR{hc2 zN*d8{2``(79PClCq;$e>P^MH54loR1J8h2RF&F@$WAp|ZfIez!K5!RyK_&DoKgbq# zoox-;^8-K&xLfbHWyYsaUKGGm#P{-;s?KD4DEI$h`!Ou4tfUI{wSbw>RaV1?9AMb2 ziM1+tN{Tk6ZT@r5rMG)={N+>9{wF`q>BE{VqHx<1^^V_TV!q9Dn~MP(3%yqHaK=ol zU$*yS4knUlAZfrvQ^ME1RCBV}I$N17!kZ&%mP`mBBi67vL^NQJ(}Kycf>Iu8@8>u1 zwUfQBdwZ>%Or=e^i!lzOS&h~X(_>^jmsh#-R5I#(){m?r@(_(jhDi*?+ z^aFGSJDSiGm8AWA`wh_e2|gR%UvO()*kg7D#+@Av!G?de=0GylyFEV=-YzW0 zZyylokj3A&^&;ZZA$!nsp)8-wL`B$bC-yk@v}JDY5)R5}L3^kq3kV3BH8`FAkW2KK zZrz*4nz2x5%Jhf)Ny;*3J|O_Y7yvI})uaU3d6c8S`_bQBBTgF4WKkg@ruuJS6;ja7 z{})zK@;`x9D0{ydO-eUcBVI^;&FZ?*!T4&4Y$HUgHN;A@BuR1Ov-2mm0q~N6gH|jm zyTSRO7zZ<#UB^f1>FJ5Ces@_?0Yl=dt^@NLsu+&&K}5qyJOIC22mm%6shBzu`N2z5`kBLX}_q)UW9t^}nv>6UBC zrSx8mSBNKDOEFW)@5?QzkY69Znobob7E(M8(Tea6z zQ^A*aO!_>BG#vC?TsG4O+bIc)?}q|yQ!L?{Zz3Zj1G&Q6HU%-X4aZ>-ua?=y{malp zv0egU@PUZ~32(=r%}y4X%B39(i%Sf22|}IoK9_;!;{IiScP%xVUb$4~ZLtS#3F_&P zZ|7`Pt8l zsP#lfwgDt1%kUqmhD}H8w|-WT3eC>g3cuxfueqt2ApfuO!(Vo)dh^E@^9~J$h|yd^ zwwpJWT0h$z=cND!`v8ly@-(T}PAC)a7X_ww6{1c+Ag%dmVL_XJTl~1F&0rqeTg^Ugrw$Q4 zDbdU#|NH?!6%xPu0^h_@e!2YqHFy3E1b9;aW@%!@uH7`IxVtus@%An`up#=lQn~t_Lt?BvKyFBxsBH6e@ zn_YI#{~As#6r$N{2aWugu1~}4U1yb?P17t0lOD?7kpR~Xp4O!vys!Our%W*pSS~)`W%%;qST&wM_U%zI9T&}v} zHe4BK+-mGBwut{((NcX~UOu=<6wq9#)uo!Yt?BrQEp+{BgtH!t=^&3<3`T$Gt2jzu zgY1@nK{!`!&S(Wj_(7J?-lyRE_Cc8a$JyZ~yGIUreG{Za#s6FgT5F!~T_kf%co>KP3MA&?jyq#hw@EVyN$6Ct-je>?UJ4DIdTxz3&T-sk zO_N62PK{ZyQNDUTn&Ylx^^$Y|m4ZJ(@1rICC1-JZVCCyPJU7XU?!cxYNk^kZgS@gw zsCap#5v$S;?W64p>An`|$q$H!M~JN|G`lzD^mrpmTNhH`#7Ftv=lB)z@7wA*d%89W zpqs>2Bc>`0)ZQSC+0Ju#D2RoJhUoDpql?ccSL<^x2y=W4km?R~L&8<1nc}6DC7RkhwVThCvk)=FXM<|WOe!3)caHE zHV|^e@terZmO9q~A)qdh9{hVA#7E7n(&vFb>%fOuRQc+Vg|*Ep>xPk^%}%>u40w;(i)aj(OKrS-dWnPAA2C?9Z$Gg}6m~82+g56ut)qP@M4k~A zZZIySkzxP*_}ycCd1ZoBg%z~rpyoe`efX59SnEr;Bq=l zEdAjIm*pZKedzDLzl`wo7Bv{RYv!Xj5?hOSZk+B@fSkNH%+=opwlvit>DkgQ-3Z<* zUdgoeQb74lt;x0|Rya?4u`cG^iB#xXi@sPU7VG5`^BTHpc`+(vg6o&LvU;Y@WGBA6 zUUS-$@XunnP+Ncv=F|T*H@3k&ZCU5r5h>#5>etffH*?#s?PMhdi0|5tPnEocv$RQi zbA=5!Q^R^?KiMJ!_vU8-XtRONWk{^&rtsF=r` z+?KUsl!QJ@*TLafL)1h$>MO=~XRgliXcLN`Z63r*3(#n$-><3&wy$%@4X<#7y^40ud- z!la_^AkAG%Bgo=*xqU^(ym-`<|PiqGhq$VD`c2hX3+m7K`vSh5aiBh{s?lcT)oj`dlhldp!~E} ze!kO;3T;<1c>EEnAtY#^A7we(=(Wt!VeNT&<`?DtusnLf4AdGhQ<+Qq@Q&A#JfMM! zJ8bm}I%pmQ*V#eaf$)c+_58&S-bfr0;nYbB!AoP1U&GJ^4r_!t6yQq4}h|^(ESnMG*al;&nSveF%U@KERP7 z+!Rsf3NyRa0Ynvk7RToYR^c1tRTdyEHI20#(zSEkZpdb42|0Jx?w;LQXfrESw^yPM zoBpqka|XZd&~pax*2#W(bMkt8*M%BIC7@^Ivq8QCiWhn$e;Iv@^9d2Sbz$_+xif>* z0u^2Aj|lE~zED)6IORTPN5uZ((dAfI}fT1sy)QW zYKuSl?#?()r?QXA=BdjM$DK9pKQ@vtOqvNfZn1rS1w~bbeF0llv&TZ@b?SrSbEjuN zYTI;ytJIR8PC<+XD7g$b<{R_)IBepAq%sSkbo7aA1<{0xZ!}xRv%XPEni4xyXg7QF zJqiq&rOXh_g~+Q2#WadqQj7X^%mRg##K;_H!D6kvEamUpnr2eeuwvtPg`@O9MU|1@ z>JW5KocLLRXVPpD>IRjGi7by94kY&%Tf`%43wlb)J;pc55g(tg?HsA9uw@mar`Cp2 zQ&Z`HA-g=@jMT*mL9W!LjN5-Y6QcX|w5g@k7dL!kLu(u3kq+-dz3;CkRP8TkAv z0ug+KY?3+Lcq*R?RLaB@l)3CF3uzdT5Ufdwr)e3CI|*f>xw84wp-`CXag_x;fK+Fg zJ`5UaQ(A=`m4S-5;s!Ry%YpKvU$`oCLCrd;7QV;MKaJPOZ}y{+1rO?N0851hT#@Wu z#~b>Vz4tUd?KoUv;sYKTpMG-g*qCoVYlA@Or>3abT}cOWpK2X3~$(@KH{svtJhfDxe?Q4!*Lp4+>WQ$ye-juhsdzfQo7E(c&op87pc^r z$}Rb7t0|sl0xmuGbXXR3g+B+Iz+a(uC6yl1P3QZR&`A2{i2F@z%~wMdZ2iq#_NC&0 zIxvXyDjCplF`83ezs>{gZU%dl#74k6#gS9W5W1gJRu*%cMOAS~JjpvOD%-%|(tVVL zk;5v#6}_lU_6`yg(lV3NhzNoC1a ztJjX|Z0QS71v<5b1Ne;iKyOHYnpb!@(X};tKsM{4w53lh2^rpToxner_YdJ9ZUD_c zr6jCJR4I5vLG5O=(em`?!yk5F0avGMJ&;m$Ln;Lw#nuxWz7Md&>{~U)^*`Ywd?KClW{?|+NZD#g7Nl(#A%#n9-YH9 zigC1Un#Y}C%M7Y3EGy5X10I}sj!3dHC<3NYxcR5Uhg)7fbBK@~TE5q8ZgoZH zp%MF-K2l_hpDQ`>MiDPC>rAGNct3txd-e^ZH-k*~WT=||46 zn&Xu@D1#b`y68qh%&Q22x@B(+2hvGD znGn>9_umKKRnYMr5)>577IjT0{POY1)*J#mj0@G+yzZngso1uxV8 zEaCZeq1K)Rta61}PkJWz{(*J^0?hk6J@d7bSsS<&fSX+n zgv1;1!3dpp=fN`#SHsN)AQW3Tk`(U-4m7mH7_I7k$W!D-3%+~6#E)94#;zlB(A8-5 z>Q?w}Wx%t$&g040xG0U?A=5#ig#J1{3?Me} z2dAy=a~}{2v1Iq&eb-G)<2W+@Y_*$?$;qL`fK%9Ae%G*4pwg-3?|6IH1%8Tw`9cgT0Zr!e*9 z1^)T(mk$R4a4=ZAsLiAn?O}kwcU#W1QllKX>DyAQk%hUMCRO04B=m0Os9v#dOMaZe zW5rVN@gpT8$=iAd4Ku{v8B^?dpHGfzQL=sJGC=xLA(xBPW(%oKp*53}#wy7?mMzNi z4hMrr0q%`W0gl6CE)8@u0cB<|nVy=)O6U#>c9puJ2XmisXzv&Jr*mPVNIA3rVonfs zrDC!Np2sdunI*BuR-{LrN-}|;r}_@LtvZQ9rKJyS(c;&mMT1bq?gp+7oeI0?=_8tL zHMDz;S*nIib-VWB5)z5bq(W6&TqFXROW!HCne1@Ai7dWt})Qq^{7J z!MHw3a$X%a9M1)dMt(4CwVN_xRsVI`I@;Z?$>e-ws*)Uz-$?G?;LCPG2k?lFGy_v2~A6a^=^t|8I3dXvAzEtEC9yiG_a{ZxYRuBx5uiUFMjhW)@q&_ zey)7JxHaX{%bu9V9(Ed~2F!N;Ya*wU5@#?TJnSpI#Q;{blQDDrHvGvBdU;y?=;21IGIGoFFCgSy7?b-TH|KaaoPHI{# z?;t45q+Nc0If;mtiTbu+Pz6 ze(NbWD~f+5jW~(Ce`hRL{&3sqGe=sP+dBgJPg_45)!+dX;W_5j{*C=|@&!!2Ob4_| z@;p(TVD9kh`IP04{2+YFV3xaagUeE>5#-0B^03z$e$fz=VDxCD_HD(*t-e~WyUy;C zzIkkEzANHV+x^bwSowK0l+P+5oZxPM7*vKp5j=gbtfj&!xP(|9EI%K+6B( z3Gr#DWrL~3CuJQ*Z@9G0kI~kkgUQLs`g%$A;m>@Oz9sEfJkrk)0FN;&bvYoptH}!d ziK!-?*yGg!A2C{CT@GSogDZ-|P~By`cKqx?d8;LivX5P__}kA8L4@UQ9Lyom=N4l! z^JmZew;7g!N82W&5MTK=YCr+5$lN*#PNb7nls72Gc`xEa3M4tXEQ33n z4bUuo#Hub|38qHl;)%Oi2B|}{gBO~shV9{KQkDea%mO#V{;1tyQR?^<7A;i`bY50V z?#J!@cY6Ft{;Msu-!jOfIkCLu6G=y1j>lTQCBg{{N!BnW(0r@RXP2~YZZjU^Htzrz z7dEmLu_~ANmG3c+AMVP20YVqI#-;ypd=hR1jl)tg3_w$IbE${{3`TKqL$74q{e!xEb$qyG zH3}*bb|%x709+v*Y4Wqhzo3qS}SB>B;Z z2xX}!v-xkMm6~4fNh&Qz6h;f%voZl;u;G{&W*PmMJ%{ zhf2Y!=-_uGB#|A~h2-3+q<6YM&abs6C53OEL~~;e%k?*buU3y8c}IB=j9^U+KkoZG zzfW%u)FyNdOm&{9e!$gVYgiH=6C)9{RBBpznc+%w`x3*c4=g-~=NDH$OKy;knA70y zxQ_D;eJswF*aypMv-C+^q}as@XoVUyoLHRE?B02yeD2muQJE#%aCk6$`@u%`@kFxy z)S~j$uQy%XS+F<=pMHk z9-~LJuwmKmzcgL$=4R3SsNbURjLF0W)*f%q%v9OZU_xxx7btq-!nY5POMJY&b(8f{ zYu-MLvfXV1yy{#*B0Z)0txrB3?Fd_sl^42;NcMOYP)d01e~-944>{UGtS{esrj+=k zAVjDW*r%?(ljxk|EQ%50Xgh&;+M~Wm1%^k+tFTPdD)S(q*}4>>L<^dAxJonAxcim% zA2ImXJd=v9q2X;}=a1voBYnwR`*x3#rf4fKoLB*`ll7q?CdNXZ>1Fr}c@FYdjS3uQ zX{4F0e;q)T*nA4+Yb@c?czUzw^<`n~Tde4NqIFkT7qW6xPKPXa2phnuecH2o6yi-M zZztR%m>^yo-rIhJ+EDT+(a|LE*tUMsXCU(NSz%fo(d(5PQ2I@V(gGkRI&Cfb;d&j%`%zWM6 zh-NFmXk$kjo~mUAe6nnizwhoiLg8RFsaV-09W>j7-^mGRkSJ6vWMRza-nl%j8xkXjLFIDG3>Nn{X2aS27Qcn57-gtaC(FTox!D%LD_xxyQ?? zD}#3Dr1eS=nZP|@X5|H!4xd_s=81%>pE2~h7$#m!6Akk@&2#S{_WmUC0D zkenGTkCW&)o<ITG?=2h4P5neBKG|} z7J~3ZV1(tbE)_R1WYey%CARyzF|uZIA|QkTJx>=&;Q_@bBWijf*EtwNDT*t;b&>@pfR@6 zGbuDbjE>xyNs}ZcSt(Ea0D~pw_iI7FLzsLyOIpd`+0S~cG$K{mSC5M3TC;1pBxyw< z9z#eEzDaqN{qr2v;G?L)lS|T&gR^_1Gw$S!1UDn6rZR(iHht3}cQ1Dt{+Mz|vDI?< zNL4Qxphg8N+RglFpA6*RA)jS!6dNBoZQRv*+sBNA4*U><#ah8q)p6~amc&VDkEgY> zUZlf5$C_&Kif{G|Q++bN74Fs;R2rfU!|~a{xrWtn*KL-e~GUP{)ei zzaF@%Z||HxIQar8IMwc|vtlpeY3!*n7hw$XCN_x?4P zM9eph6A4UMlv;99X*rn1Wt+rfI+4SFazezv`$Xi)U2 z3%UMGh0G|d(VR>!p#RIu{139ClU1(AB#CLsOdBJK6o%nA6+EQx>D_x>G5*^#{SL6$ zg23%QOoN(Hc|)ygWkI&HMR2*JL@L{n@mu7{=y0w#$`FNGu8n1$>1{fE8D^UB9v6O_}n+%?prI>*6?)+`G)rgJRzJ1P6X3Ai z$DOw^JLS|uMa19zSNK(N8W!!rTGA}{nz_HW-)|ZHj=`u@pPh_gPl}h+pvo|8?BI=i zqZnXjH(P32xcb3JF_p_=dfT^5m^w{0%^bG#fga73PMNnxmvFeIl;DhPtTZe?3PMOA z@V&)@Ee-BP$Zl^b*1OJ^Q1EAssE5G_;Jg7OQ)wEUkTpRm*3U~OO2PB=ule3aBN(36 zs>|07Jt6JI1p-|GYR(oBaR(0NLl=KbglYP127pV3QGm(0l3;RAC@;>5{&<+s^CUAh*9poRx3n6*Ihzp$RTQ2c6=R7xy8@qaPJ|8@Y~waT5hly?S@vp)5XS_!FG$kzn%Tf3mDW~3RMl_ zdsJajrG7Bo+d#q~YE~Kco-iHsa6aWeg~pRimkiFri*eP^))$x<57>c+b5ds#eyJ4I zm(JV16Z<&6%qXZpbp#J;tF+{_Ur>8Sn{fDAwiFX@JC{RC!yp@UIJw%8LSs-}Ym3bQ zVm9zvp@Qa`--{+>!FJu?Oucyci6`RIzD9C6_@d(?^4`0W!7$nW%th}eYFJRO4T{Qo+@e7Z$Z8a-TT5;FICOgUxXgg^iPFJzAxQN-c(t8`DLOFJBV3 z&x0?%*U(8eav0G-*qCB?){fG-r^z@?2W)CA+q{D|YSRid$FP3KF8u#2ky56$wF0*v zfQ#%t>%tq|v+-xHeQZ)H$ub{>^@q+DXQP}WwQ3NOiZCxyb(i$Fgom2szrER@C>U_Y z72o#>>Cy-kwUjCxd~6b9B3j&p+h^ruG8;v?BI$Oe2dsI+YqM>_4XSAzQaz;4pu?zIg>sq87BfKf zu#Nm6^7s7DImCHta78LpZ(P!oyZ0%0Lw)+N4X(_*roX&QgH5|s?O#4ER4wwB5Ij4k z5%Bu<>0oUbRb`Y5$r5oEc3D~f6r<8tBQ7p38L+)Ifp{}cttJo5oC&BM)u1N&xSFxx z1LfvuxfX&|S12p{9>t%j+hw`QsITt%IQ56Do?r3G6S@pr7^0oXkYSSRFu!7UECPD zVY|HCj&2sL?zpx{bbSJR!#2RuPP>Su8yR-i>fP)y5On+o0JwIh;Er?WyCz)e*Dr53 zx}1(-ms#5J-IRcXdYq-dF->s~@Vp0`!|Z=g_2 z5Lh5Wf4I~oQXZQoUcZq*FBZBtn@Fk@?}BX9NHMH5y6yt$yeRH-}gYQwRtt?>N#zwX@ z9%tliXTm}tHC12&RF{Tbh!H>5WOIv&BfR;Se5z;(9O>5Tjj7=3)!|3VGrf=e&SW1R ztX1`_$g-y?^49OQlFXyQ3~J3zFnwu>vZoNpLpq5Iz_QiO5gx6-PWn4f{mbgv-Ir^Y zh?op6b~H6m4Sle>T6G%Qg^6{HLP$)LQDutG5ckv^T8$Wn)~Xk+?!ot7v8w34Wq(kfhZ+^kn1QO)2n^FJ@v=$AEd`e{0Jro|O5TV|@N8u9H`wM9!XexUcZ z1~q@dY);OzJGiVkoxYP7w`{jor@_fN+r%sgK}kwNH;eYCyJT=rB;&&u>zBTc8LV$0 zXAeU5GBtA*HEBgL4afj^+t7iiq`ElmhJBwwnK|MtGo@sL%ZfT5w)x<8r6!d5!l8`= zgWyoHk$;;6q3roAmH@eEyGAVRF+P%%Del;<@7e~5;ok?;o=7PcHBYNn_LT(!*{w4j>bQ(J0p{y*%!Wmwd0{3q&T2MQxdiNw&If=CGr zUDDm%of3jdhqSbm2*WVa&4_eMcSt&PH_YDnJkS3B*Ezd;_Bz)&Z+7<$FBB$zasR&e zCxc+VVbo@e--J8UySVL$1TV|`oAj#E6Egd)E@w&~ZQBC}%TYuR{?X=ok`|)E_)Ok) zZDi%eNX5b6#pz)NhtDbygknL&p*?^h2_<0cbxhSl(8Pp%q6_sjE{!7LovLz-U6z}) zIdRgJc9LczeBtr?8pN`k8zBxKM1x0H0%lDDuf>3^eTM;h>NH6cuXV92gNy^Y4c^te z{;v#Pq5SRZ_eR<>yg?-&I5BgmR;v)*7v|~W@aUYB=|V!vm<}-3_OL6rMjD5AtpUe% zEKCtTx_H6zA&3Au&&g3_dN0z5T4tzd)PE^Io>X4muL!+nCN$jILAD&LLODCw=b zbJmv%b&~tFTr0h$x6XWg6(Ws?nt9;4R9j;;rj1jYJS)IT{aUhM^4m`C1A=KymQJ1y zytWrlrmZ9Bg(VsFO4i}HG{@dEmJ9l{F=bu|Dk&jA>@K)fCyx> zvW=ff!5jm2k3w8|b;M&WTMMhf#Uhjhwk}^>r9UT7znE~dQvdAmi+3=O?&z+_1h#pf znvA?>p)9&fNC&KP*tfi2HTmHF5BS#L>(#uGQ3TBL1)ugWk_P3HpUcqUC%$I#?VTED zh<~~D)NrK;S*K^eHB%o<$6l;sX11JKy#*uO@I_G)VtMeVXZB&!>y*9v!(G!pVbQ9w z2)X_tw7E{m&z~a-tUcCi0@0~Dd58N%%Bbm!h;bWVbW5U=(rQhqGuc$>9|H&WwKiu# zB&$rjlPPb!5b$0()euHYx76y6%S&9!X_7|WK@VpGn|97bnOVe)!S4Zho}`|zr1GVc z(=$;$B8X-2y8N^hY}PlvKqBf^AWxAKSqOs*`VT`_ku2dwZln zjpv1YZaHkI!dODWY&p~CtgJv%Sn@%~{P|J_KC_<9@>5*Yu}kr8Re=9z*d>sRH-qr$Z^Dg@( z3LUT-;)RVC>B2SG^HsalfShU9Yubn|Pd4ek=$*cOuX@gz!`u0sP6TeYYaZk;(rYJQF~^6}{ty|CVyYGJ0{oSf zDxAx1+^KOlzE)XTG?To|QPrC2if;74__u7K%u8F+gx+{7SXmv!#r5On=~R0w<_!uB zR+rAM@YNlCp81SBJ-_sTpylHy9V82K9;s7PW;=~v+9L}ylH6aujbEgpo8z&AD-jhK z&?wAWUr1$cE}u40>x>QYsW+AY+wc(ko|n$2cpdvLdGZ|n1GmD0>57f28imD zm*5CDMo34=y2A@EY|=xUM3zj0?YVRT1$VnXM}FhQqdRd8x?#&b`3b2yaN&15gEKV_ zn}tkWz*xhqlG7d-&v@ih8b)b5m^X1q^5Uma`KFW{vtrHALWpSyyCUAvy0m~R|K8k; zfU5P#r*emxP2Jj}ygUMWJ^o^&57|MFHZIJ}XGB7;89w?8e~OI1O}E;M0t(GCi%1^K zlZQ`|Ck5+0y{OYe3b~$^l|+rM4X+)5oT^iY#y3=hyQbFC0%{CYfpMldq#RUC~1=u?yoRuAI@4>|chH+rpnFrlt-QTJCk==0$mKJb`jMpK6yYSs^uRUkY3> zK$g7fLrlReN0QrbC3t3|m@=|qWMnioK5pKdI*f*rP2v7+L&RLEbpA7=*;&#ZT&K5{ z;JUUVm+{0h)F@mmIqOSg5}VWRS`WBe!yQT7SI3H}AK;tZN4vcVAIGou**h(H(wR4e z7%f+r709pUM(T>0&_FA@h6`=iN|w67bjkqgV`QW{;O=`9<$RU4AzWhh0*;;Aj@fHG zc2gjyuXPM8tK3CeKJ&GrFcp;L!tb%M?zPe3f)w2hDk%T4;`&5wlv8N) z|68h4I1Kc!_4!d!UJUKvYL6h)@`rqa9$Aj&K44!y@KPYX*o+qzjnA8(_4B`WdEKq@ z2@WZH36r(!#MiH1V`(D`h9~^04-J0mH;62Ccgv#sFxWmX*(iF-4gJ2UJzNO4tjVXu z9NjR@Dr^#xs-W9zR#y$1%|-3_Zl9d<@#5KBI~wsb8Dwkb;z5y-r2+FwjUWV;b0dpVbVwW z`m|~f;xnDk3GLGS!Cv0-$55G?n&LzUYCfbvFm-eWyft$!lXfkom0-hhF*ko4tw^x3 zGffT}w%I1_^e_om6m1_P8^-bj2kq&zHC4AR#_^n}o_eXJ1l2`0akCPqHI&;dOBEvYswf-wv}oF>GDJlxv=YYZ)wwP{Zwi z8ml*ob`iQfri^}RPp=91zO%y~%}1GHdumqYS~ORIyASYv47l6aT0PQ}df0E=KG+=3 z)-TR#@kqzMc^(u+GE-+NFu-`VM!v<6M=pTrOfx~W@gr4GaC8rGmoML7l2&%bA{7U;{+bJfZNYSN*m3aJV(?*GopSLOB0Bw*+vzKq z?QSvnsMP_$C-8E~rA*2%zcl)JR85mA0MId{8M+JQe;ahy%i!Yalli2lJJiH&8_o>*D6^b7U;Rl-q~J3Zs8OQF6@$-gNbyf;BWz=ejyj zLhOSfz8ODH>*eg>Mab)Fs?%5^q7}EDwS<_C%cDU?=zzu0k)#;28E!N^MgTQ?LK-BI z4BcdZb|z5t@#?q%K^O>Wm%{V$Cm&#Zi@NsLNOk~wNlWn{?eOfz8Do%kR!CdQ-)}xg z)=apds__@@9P*Xf&RxTB*~%mPe~hBnJjSMjD2)GpMeq|t^8X7(@V^3cbwzV*lL7vS zN-Dhg&h)=F=eI(_fUHU&Gq`~R7$+0W3XSfP@$=75|2@FldF=Pz&vi%u#+$9TWP`(`R8LKLfK0A zU*mK=j`@G`-+<%%`#%4RQ-%MZU6#rMzi)rPpzK=QdHvlvNNz-9{y)6dqW8dUB$Ch( z%|c5Z)JY35KH+9t-YZaJf;w~MZ#!XJ13t<(Pj2*M*HHX(iZHyAT%=DT_pfMtM^5?) z$z6M%5Rar!W^8*i%aiFgGa>WZKn~jZNN7{@n}42DOK~neaGS zKAPEzrAOi>kc38dZA^%A6PB&WLol`KsqCFj+Yih$!$t%;IKT95d-}lD{8+j;&g94{ zg@kbi;{4VRkIzQ`&TTl3Fd(N38TwVN*CLYuk{c$Lx)=p7rwoQLh6(#9-1k_}eAhGi zVn@d}N~mhDof2_4dZHFJZWW!I;&b2Q38qJ#k2Ss4q0-9~FnI&o0)v^b{5EKKYX%^~ zs+VLW%o2JXIN#sDC7StmEY}_NW9Ps+q~J5EkcL6+6xi) z^^-;-=i1L1pELKod6S!@N_Uw^pOrL9hGWSH4#+(_SxbY>RN^lQjt)*1)hCvt_M)p} ziiBf>i+bAeCH$TzdoJdyu6|_LcbCR_UzRR#dbl}!lzofLcNcx#+xE|?KgXq#axyn> zIO-Sx)7y#{zt=l|cC~sn1i{&1$=6NL_Y_24wlS73Hdz6rVpLM6Cld;J3MBN9jIl4G zK~>jLm%ZxnVIoU(TNFu&wegltB<00Pw6Rv1EqvI@M-M5F^eeF}wX@Z>EGs7I3!&&= zYGB_QGzD_#K#@!XHVf_)cwSC-lHkHvCM9>RF3v#u=2*GRmR|ABj$PiMP5H>1-Hxc` z?&;zsnUrakyGhIwf`bTqRKSM^e5EDb_+7Yi$xJ5}jmb+HzrgVkzx$2!UlL1kW+j>m z9dtC$Ki)u_9L+Q>So1NM@WB)MO}M7Qk*vG#0quUJQ2X^pgNjLEDhLE(Uo5_ZN)r+! z#Hya=*|ke%W-rjzr^x*H+o?LD^=^dthTF<}k@4H_RFNpp9SWdB*{+Sls9GuK(9c(- zzxIE{2DqCM=Cl^8UieF-N&1Rz(Nh=)#FEP_TQNf&r~_CkC9tMbZ_OHfLmy1k{V(3=sapxRGdi@wGD1%mx#);EXc6L^XBo62>Ofp`d zIry_ue$R-B2N6!YWdk9mqeu;Q>rN^tvCstqB+o{sa4$rt>#LPK)lBfI7Bsa<3*;f{ zL8a^5JpYTG3XL_P6E#ZU08xBDQ!r?~r@x*^|M7JWUE5ehI96ECm-C5AiODSEti14N zD9`Co@19@lhqXEC0oh`c<|&ny&ga{|67OJ>XQkf=bXfzA#;GIyXBZM~l*A-><{^>r&2XXBdepbu&r&2IBzScco))Jf zmEE7t@9Djk_;imnO-Uq)Nul*5_yv0N_b;0m(2~yT})-SCHB(y|f%>nMSv8E>zxp2=j zK$boM#xR|F;)N=*-t_5u>ma919IW@D2~1yxEwQ&|mCMZ#V8<4gwLhKNG@HS1)yHGd zViuuYW3W>@NTZO(*=H72<7uvf*9R{$&w)S`AkZb8{LNylIN3{)d-tp&%r^HmiQ}cR zhe1tVu433SyCZ;TT=e`ZoGUq&9%HYMbAk&*dT#`&r8d9QmMm~E)Xqbr@Qg>iZyemy zhdnYO?RHT>d^y+_MXUBz5+DLpS*av_n?t(7yfWjbP2jMR{5st*3BYY#{{fCAE;DC@hl36c`~B5%AAmHE6zVRx)lQVzfdwtE@6+za zrfzjLm(A~OKnUT{y?&h#!rs~4eGc4xxU><<0i?o`))P6yU!${u22m=en{a7yaeb=1 zRQu?Wnss59t1i9g(rP?ScD~fYmvC^Nh=@SoT5^L!{~f@L0{;2Ox5S`_J~L*e9UP7% zYs1+`$M+VvZS_(TsXI#e&s(Bd>t9R}8pfG)tn7idzVnvE+dv-@z5rmZOP?St;ukL{ zDEx!jp%Mwk!v#-};a(w0!|6Por0pp(^0T&c|4R}yQvTD>XGLR#JOS1%Rfgdr+ez9; zuW_poSM%B5m>+x}!tln=4n{%ZTfFHw4kViTu63ec@$tKAPoaLIwm3cYlRGAO@^nrD zl-W)PtGZ|V+%Q;`ZV|G=Zo0(oVA^+Vvar}X0in@gVafKJCn*BhHgF8v^$j`(qSp3L z`}?rje;0PPw@E4wy@_2JDo{sC78}9v3y`3{I=$P&jk&dTj`Fk_ zj~<8+OC)eCb>?Dr9{?6o;u`i-FrPjQpZ1Ivj!!0(IHLD-|9>R<>SwHq@jc!wPXZ6l zWQE^JODOA$$hGlo^#iM6b%X}S=4|AOod!s%Q;$jO*ufeR0jqAE2l_EYV6^-Q&KlK? z$C20b$?Nye%ou8!N9#gg)uU!u60HwYE6ZNW{1Txym-p*3D(+6>Ir{E@!Qc0gl&kD2 zn|a1}>qFx0mH4U8dhb$GQ%75)1l%`eYt8w}YzN(r!ze-OFF7IB!0Y1ebi0bodA6!9kSFb%+arB1^f(AA#} zYv4*X)zmvYDFJDNY6vBSd6XWA+k9ebIrJMs;CsH4rfIJZ9DQ2DR+AX}vkwo1aEyV{ zr{2B(_sAbwEAieBSLjX!U%VZYr_9=7BFbHee@GT`cr=@=`qe^Y zU7jz9iNE_0e3JrUopJe)m`AV#^L-_ZK&E8hrA_{TSm5Nx*Wyl(CIfPVaIRs?}C(?Nbm>%Qv}lAgEU3lGN-p zqq8+S>Au`kolds!f*p^F22HsSTkLSn8CoM$|2DUpD--|BXntNK69=-y%=A?aKIP;^ zhZo95Y;1J@tWK}>6N^Y2;e+EFusA>-B`MRQ)k=U1)RZ?B5Rb^$)g_=u#muxP(9Z6<{x7a6)X z^SEp^>zT8F3d3--lzpMr1utad zIJ7r|4}+$aN#?O;f77e&o8i3wH3{?xfoObU=RG>DTDzs_ceKPqepy}zTHsSCZsLhK z&M)4BtFh8%VJ3^87uy&`L&X4Eva+B+fTO6QvLDZwIFlyuF1W(CS~zboxd*@I;8$<3 zRLTCyuIYjvnHb26unmih+#IOZ-q3Q5y9Reh3PwjS18;u)6$K8g{f9D%tPOi3wYKS2 zd{+Cx8NTvQ`8MMU%Ib!Q)S)F-oXCzWO|Ewh4a3*-s=ggrc%vw9DnxZ zo*v!3lh7^#kkRH^M$e(t!28($MPx1}reZ$Ul;L?4)*9qp1_C4osT)v$|53D_WnZ^RZ;VUoB(>|8(H{M-)u!+5t;``sR z%#uUHs7KJ<9_z(Qyw$vGBZy3GANP7azf$~%A;AljaZWEH`TQ=YeiyS!h>OFA3#N4R zMMUxex4FN+KT&Qqny)NzGIZospZS_D-zdgOrP!zi*af6>eUH+P;u3CN|4S-iVSZl8 zYDDEaQ{;m03@JP|xhNZRg+OeB@gCekTp?Jq@>RA_iO&^82oJlxo{2k{45bsFqY24$Lj0L%d@;$k}++x4Xk z?0tH$TG6TZ_UFteUFzO-E-hh+thmtwTj~h46@eSP=|Tm69!8g;uXbXnyVMJ)LU{NL z*;`F(b#FI`L%sOf`|+Pp&vsV4h~!CTc^^Qb*Yb;JjPg|sl^@+CS*I^1EvZu=b~Z^F zE_`t!lX$c>z@8~71@FPP$ zRYOH(XwWvJ1EUJL{{bjDprC+j*uwRt?jTLi?iP8d5gXy+vHt90rx^F9n!dhN456`A zd~&cy{LWG|CFoG~1}X0kp4c(VD777?xp^P>^`TzS+4EO(D2yTQp@FQUyH@ktEB-de zbdo3`92Kpi_U<~0E+=%GOqziEYNWzM{aVWwE!cRz{cjSuzEuq;|7rpL?_};&#dj|L zaKHn=2q#?M^rx)pmdxF#6%d@m4)=8YO=~?Oba=er!g<3;#BBM?FxYdH6$$A9bCpE zQ)Ab6GP*NRK7%!Nyrl!aCm+~HJ}ZXlVk$MO2N!ztHS-$e^SUHuy6}7}G#AbVQM7IB zR`V&tN-^#>(RKKEOK**!ACgyq6jEXOWRvR!!F~dk^(u zZA8BQWl7<3J@Y6sU?At~TS>?*F&w;`!d~ilAN6vN$jRlugc-1--1gAR>MUpsjg zqdHOrJ{~Ojnjsgq*jppk{5V?n%Y)mXM(pQ?o8J&>3siD*O%Otz%uj+zU^yyDTX6Jr z{>N9a=HgA!J4Y2lRf)kfn*-SnzkVRO{mNClMkFFHIs6*egX)Zzdne+e9b;EK5o&pZ zR+rlzOYU|>&8@8vQBc+tFR5xn$5>}9*rwkgu|=>@b%iyZ`@xK&XIGA@1bFpL2*sfg z87iYhPMNAVk(ALIRK9bci?{23@#;}M9<>~j%zVw1T2A+-jx%!M$7~Z)w|35D%-DJ9 z)NUqqy}YJjcEwDqCU}wm)=lA`7UdoBj2BK0QM0Siteg_LEN1pM?i*RPvH2u7p_!PU znb%p%Y+m)Fg^*XevFG&{mfN^=== zP7UZj53fzSu7V)rD2x-^xxO%xC%DCE64BjuxOUqk6vv=(0b-9o@E$EWbJfxdUf5V@j$w1-Z01G0F@pjIZbB zW`H>Jqs>7~?iTiM%)z;sbpp#Ek;?%wPlrC3`?eBx@yMZ%g9+Z#Fl$LtDWyDDhL1k? z%JpO;JYUbo-mm!`w4Okb^$@P+>V39h`G8G$-#)6)#c5r=`SmA{9wgBmTSYOU29p&!C%@M!~oy|CNr)m3NFIdPm!xKB?Xp7@{1$A5P{gzp2=| z^qnr~6?nttU7aM2sBv2g4Te1Ts7~rJ)8%*n(rDmGOm_Rb@dvO6#x9n0Sz7f3PVao9 z+~Vvu6=b{!?41xAp~9e$CMXBHpZlvRN-$rAJ=Y8|G1!oP(DIdCtK4j$dFKOAvVgj) z8-t8B&VI%t>q*Aq5f|V3B&^~O;YeC=4sF`!G672R^35d^q+{t+LFkN$I@c*XFhT;0 z>NKEzdqI9DA0%PT zm?iu#etbStWA}h|0c1KY&_;q(oP#;x45{1!u`mKN6a?NQ4P)hblO*|K?`-R-GLP+a z#X|Ji-{6K{fMK|J*Lz4t81;OpDtw>l1si`^dwLolL3e8I@F!EJaqL-SR970jC&k|P z{N#0r%IblK8taMO@=%9(c8gt~0ZcYwu-ta=h zrRVAW53A2DA2*m75Yo(HPjyNPxt`~A;PLq$zy6@4nQb@yI9K`s6;6NpGrl~9^enaH z5}hJ(Wk{W0GLtDOF9+)MxXn(m`YiH(_=*>^Gzk!)i25w4Zf8<`AG zo-ef0iDMt1G2VwAHjR2J$N3(&#Z)W*)+fRC_4~e1eDTdwJ>;!+5YA4Qejbr^p~31YSO)w zgI029+f7k#>IOMqG9(j1{W%axK<;|s;(&2rhd)R7UeGiNVX`EDIW$qXZuCx|{Pf`! zJ#t?(QkX9;nZcVmn=#v5N{5|1SoZl@NdWPg^81VH>Sxa`1VKKWA))Z+LZ(r7 znM7~??WS$g8~&f=;c5JiO5-IJj>I1PJ-lZ4GCM(@_A=on5C)6U_9|s z#W~Luu(6U2^hj9{uX^Pn*hpdAn#iPmSngH6Mf97y)_Bgx#H^I}T)wcv1e6P;H z{R<>o+%|#H1ZGk>VOL39t58*;8CgiaLIWitdS^llWv72=)}()Nd5v^#e3{`rz6R^# z)-@Xcx@WbwwcPPYxy06*wt=%2i{sHGs_?A{1@;FQWZlRrf@fkWvajbs!03WrrQrp7 zug2?=9u^uKTj?}v({hJ zudr==A&eFJO$ni0q;o)}=HpY=2w=#c-Y0yRkSd^&ZOkOJHK}m)F!NxP2SLhfUA2TVRA=SOSWPa~Rvf^M8I4kLa&OW*VZLVEYkf@p- zQFq2)l%d;JtW38Y#eAgSOtV?Vd@oMb%9E>gYck*<7YSG)&@yN=HVTbrN;f<`xT&4R zb)RooRLn$DGC23*>Up|SKrp9LctkNDIdWY4Bkj7ko|J6%GvgE~4r483= zu#5ZFe5O0wCUWn_Z1DK`H^XQ4xM3|vbYMjcy%fKlqn^zWRmNba)K$tD34n z0;1fE)5P{4e%6yc**&c8|M0W^pHuWdbzREs7BXIoiX#6wDJOh%1D}YQO60%#S^I#W zmG!#SD(_~sp=z2&Tu`9Lp_mTnDQc4_y zdO91l&6!iEolzB(ba|-oi^Y|ZMRT!OEmUw42+uMDuzzR$4=h)Ly zoZ95M*UQ;z5nP>D(fEq3%hsov8==Oi$aY>Tk4qgd}FQ`}7(N z4}7n?f$gJ(Pm-QzaizSNBcQ8=BzzZd^Wv+c{;IM&s}OzMppa_VZim~Ke!i7rQCwIn z2Ok0H$eK0hz-==X`A@e(`V;Qvm%5dDKJ}sv=eNqd>PHtY7fuhToz3&{Zs(rb>lWM% z0BfZNlMyKwY1nYGTE10JNk_*Qy3%Q@=~Cy>9ZI2;p5kA*ByGGTJd>_oeD?k~0}WZy zgc56d6^2>Avzgpcgn9VB|` zNjdRXJ}#*8`t&q5hCN!6Dq0eT)jIj-{(oyugNIdJ!h!m9Y?^DOn#++iZ8i853#LLr zZE7*AFeP6pj`ZBezbS0+E>$OU?w0&q^&1W*`16h7if0qJo>|*ih8ctMl zjqRXW>^RfifF?)hSiekqcF~i!e@d8ZdS97!;!RK8w4`0Iy(gvA;lCi94N z+cFlPdC{qQc14*k9t7pAj%6ju+Cf6Z)U35CXUMqi2gUPMK<^GhUL7eFTM_Z}eL$#$ ziPbg8E#amIFdP7Te7y;6Bq8wq*q^mNskzsa7&F@|C68g@b)8+<*PQqC%O#$&wvS=H zm{s$a#MwkQN@n6%mw%b|)ZmRo<-HwU>C^mfRj!HPMvnTe*xq|&uIBbv2J1E}*2>O#OiYSF&ZlNTn*D}y8Z#b zT+e*C3#CEDwmPC9QK!OC`h)7Mk2(`QdJvLri(S23GCm+g_@c@~X<)*%YmGV)u3NP4 zpW#NUo6#F8J5b8v!0gN7@D5c1&66JE&Jz| z{Uwfj%Wc?XMT#%;g{61v(46yo%S4>6$S4T2rapi zzA)>|cXoOkW!(5~3`Qu{m(jtp#k&;srlMX#Rc{9t$KHhUe7c!-DYZUp)pJ!*USWLc zeM^Mt&F)YLvo`mti=tBgzPx`~z^yPfDa&Y9KmYyxvaUo{$URWiWL19QwOlB|QaV1s zn5Uv3%LK6wDIG_w@z_+kZ3K*y98p>Qy}b4D)e2;r&t3vk$V|0q*I4GeruuD<^bA4I zIv9f|_!kOeai2>^p;F#nL)Z4j(9<5`73SC9*LFx|{N}omv~piQy=GJ4DmE#a+PQv@ zqq4B2cyr`5-BqLD%f2ga{S%m zQgx?q4;H6VQ`Uth;Wc=#X8b6Mg8Fd?*!vGTX2VAc;1l_ry15AQ`MkDSoosu*6!ALgLU^$Vc7n6IM{~Dei>7I z7kIl)xHvV3gI=LdI@gSFSw4(SbLRRj9r=~fg*M`Sb{JJcu&Gf`T=W7#UXc`?%BNs8 zR?P;N-uc%6-m|{m@Kze}cp80Z!I8wxq+e=x;ts=tR11u#Pab@0ZrPYArmQ=nJ@&lD zF9@U!PYIVBW3i-jnuC9Lq$2ACQ8PF^j^{bY$2!^-c6t@wz>$V#q0L>x^yaKW!3&RK#VRA7%rqOF!)!~!eDKEMd$O0*48$pR^5v_$L#TT z$5fpnlH-<-{3m_Z{En@hS@s3%#Ujax1lZBhkvZS7+W=XIj|(&`*459{UwwQYhlkz-LLX|w}o@d z?>s~;uZwg;lFDcRBdIOu7Xo7t4?L(_@YF+q)(z>P>BH~WHH(}!JO$GAA8ig=W&OCg(?l3pEpSA} zYEq5Rmp$dcyYGv#6Nr8vJiL0q)HPx|bUbk4Y@NuwbSu;C-EC6_m1BqBZIpK&dTXdZ zEW>I?h(X%mYZpx;B6;P(@5uoRl|E+C7 zv)1kTv?b%4!}a|7v%~tC!-K~m)SGcePHy^mk_N$$uof8Js7>suiZbQ<=o5~Xuk)eZ7+xSpwmRqE0$la!iAd;_@ zVS?1AMn-wniBdu5N0~8pJEwBg((#>7GG=3!JPjxd*#LwlB3&*_DKW-@@R>#DDki}m z7q@L3de$e`&MJDiF-2>n#xHg1O>gYq)EJ$5V!iLxlxW=cm>pUi9K5dfRN=386lUMg z1e&N5ZN`S&+vgN!wwyVcMQIW*CTID+$AX}zbi5Bgs1mzGGY!5x=Unkl97XC=`j=@j zLlBeSmO$Jmfh--D*-#Eb$c9C^#^$2tVbN@r@BVK{pdut%BMZ$lmpxPO1!yY)_jL7} z>GqSS2ey-bzb}Lp%66{W*4_qz*}oKZDo&HQbH4E=7fY1t4gQr(d0#ASYuvbncHbBANMACYNhI(1fT@$@9WL6Y)!?y70{Jk> zqlvJ5R4c$Dm?#eKa557p+yyhCNaj45-(~ge)>BRsItZ(Jr)N6K@gipMS9?64Abb8) zODTa0F*Ssjgot^fj4~^{Y*N=KjXO^q{*1@7fLeX(oQSi+PUoqexIyKFR^1GPdOE*; z#Iq;9Emm@T?#r?t;yPKMFgl$~f$i6}&i8x7>3FDFe5{)}9Mvt4W%gHacJJN0*Zi?< zfdZQD+>NX0ZV6jeJzQLeGLXJ}v8!2)$0uaZ-v!9Li8+;YL+T?ESKN~^0 zdqS5fLaV}eFMAJ{=Xzg%7rK|^5cPG-C|yaeOZc02=c zf*Vb2u$TzAI-_dAVH%&~VyV{P59}z=RfCau`OdJf=ozf+%^6DwOsUR93VNTwqQ7A{ zZhTM4N~OoC2Ivqx{cjda!eH_#oGW_Zxi)G1^r$DiCW08DU+r}K{ql;{dZVNFLE7GC&1&7%eeQ|zt%jMGe<{AsV~h?szjy13f3scur6eE>8MS8Sl-iOmasq5uEmbX>CXP)QHn`EjPE$MPPI+&+G*44oL6Jd>v zd^S5)|K{ks!dY)J=yhjePq=;X6yG<$ozvI;YIVUG2V|w>`JAjY6oM;Y5lQJm@u{a@ zTX{5|MZd^*@Jnez(O9W9L02FQs(2DgACfCgD(K*_S%#GRGFECHxiwwR2zVETz^EFh zlPr-;Z-j2`+gU%4S&Cfg#_FoB6;>yvM5XK+4QPWCdLW@ZWxsN(#97eZ;c!>=ApSh@|WeVUQO8f`In#Tb)4e$ zE`+pDPD?ep@NhFq$kl#*yr%BVx9f0Y{Pk~;O@gejW_}z(6nNd=pvrbM)xM$NV~kR+ z8iK-@CKYoLPJXwXn5#RDb@ucL;~}O@8MgaBAjhr(YbPozy>mlj&HYNvS9(*>Xz;Ng z%f$2V?)9BT&fS*zR}0`f5iJl6ef1uM$SH)1SRQ}ddb_w7T5dIx#J1V>i?X!^Mk|}d zUkseGpr0{G!2C8uRX*RSSVJRWW1u>0db7%5C*b=7aNyvS$TFRazRJfF6S>`!q4=lTh2l1jB##3Ot6 z=~`>^)#P}X7u1P2EkdhKiJzVx=WZNaB_BMC$Is++OU>F6hC-xWq|}0!95H9J2mj_q3b!2T!G|ldH5aJ(DBWl3GGBkyi>3Kh ztVS4k@AyU~$AH2!p<>Goh7j1qLA@SgqLMan=fs;fiezJUuYMajkM?_Y4RdGNkdwU5 z;HL0L#zmk(qg5b@mR?fu+{%1So^LV^1k-PYw%_+Y3V+^HefjFEv{+9S`xWSL8G1eX zV%v2FFPH4H*klv$l%Vb1aB_u3V~LrZp5FO%R(gF+@)fzGRbEgIY^!M+{LvJFSJS|q zN6#!St&HmhX_`y)qHLRLn8C=};JSuSX*9&(3S=$uaP`}M+!n^GUZuRPfQPEWeCFY6 zctSwX#)j3z=2q)tyn3p)<&KFWskyp0uWkFydCu7Nkwb}$L3-rzrdG70sr{b8m5D?D@}{>{l3anuY8vdO{Nt>~zz^jMqgv z<>!kXxNQog1TtkX6YjQ+nbK@?Bx#SnB}-yQh~dEC&8rZ7vEFmQJiSNP@1h1v_+92Kj|pa#NMMi2TdQ;v&?M7 z?8A(I4irD2Xu*yZAUmQ=tlyeHc32p0lA>i9V!??bY1<*OSJB!ex)WhYIx*K|!7bpm zHNLh>(&yyAjiu7~>Km-X$*J0?sdM;obf^=T9Zpz_pJ$L>Q5@)bA?b4T4))+6-YVGE zFS6rqizffZBoY3S@5c>~$j`S%2DkCF45FV$*v|Iwn(&KRl5)tjHr=C|tq>ioctpg! zzZF(d_^J$ZP487XG)QLg>{>JOa_9xHcgJ``DZu z(OvXDfQ;buHKdt7)5L1v~Jg-e2crS6C`xploqBI(8uY43jbZu%F6z;?9kx zuV&q;dN~f!ZpcccIASoiFMV)f@T$J%AV&$EKge^qIm>6zE!!frtW>9sS@gY1u7#x`ze?+~f{sXYa6F-HbWv|02Caa6Hg z_GTs;oSb6a8OEvis3fTeyzkxGrKSo$^%?+{mcfC6@IKYRmc6<`&oD_lF5+}o-G4sf z92$6{vcM)6s|gHV-L&R0#8My*GY zwv!Fx7G?Zv#8+3@D;Ur?EII5fs<-b;mj?vDNN_eaH6!@BmL)cSr`yW3(i|tc5%6$W zkR6gOmuV;zXxf+{L5a)nh0Q1v$nQRC>q$lOuZv}BcUwEwCSYYxgNP!&(oNpNbpI;NGtc(ahJ4P_b6|jEP)RzQpNV&ee1=G0cw*``h6^ zEPmof4|;;#N{07wql6{ek_;Qi{=%@f|Epi}LC57nUjL`u0n`~8?b+GG$2{PRzs;kc zd*E>qN$mQRCPDV4)9>wKQHdOmkiKUY!@qjoC*FU+55U6@Pr_C}hq?mj9W%=#tp`z^ zt?_FxBaqj<aJZBK8K>_eU)l_4`4})PpddaAkuUKJJGEQPzs(G|N z<~jen@5pbXa&m)yxIjfRKQ29?!TZ;ggbu+sio^b(uhYJa_Ll(>+Ai!#*&dO#UQ4^7 zo?UnhF@POf3CKlTBOWxUXk_>6pg`93(3Wkb&98kmaNyf5e(uLZLqfFD1TR`6GAe9Q z4u=7kXg$@x&YuFD5xi7a#>efYDf=^*)y=)*Cff3L!%A~mLY`cW{`pu`YMtxkp+lhS zMeBh9+wY^3zBHk{*ZjlxgD`}J8Wr4xSce-&(UTh|d_)P;>HX-QBHbF7G~T_*lLzJ$ zO;;+{P%lJd$@Pa;;nZqW_(AITK8Qr< z`I_#}_4Q^{1C%v=SUd2|`|A{yquk!}adB3|fFk;bv=YqSofEt$P1V%8(C@aQzAHla zz2nJ!y*bbHTH2ITo=;oD9C4O-*p+;*VC@twgd zPX$Kix4{Qv#0nyd#=#vSrsK^@)F|EJpJXn({1`%aU_e?w4Cjjit~OIvBh6mB%G2|| z(pNUzwB3jjE=t4u2*|S%?>}KtE3A^wqinQyuL3Z7%ohG4Gfs+9xsKL^+)`R=5lP$l zMrDaR!Tn-hYokhST}@J9oOQRgG>#;GztP2T(kNC5+l>H+(E+xgCSh1h=o8j+B?xkK z%S~HAPpEItt#5vcl=Uk`*4TdGAM(z8^v>OXHaRCpPA=m-IV0wOg+455Wc7ea5L10vS@Ts#{BQ=_rhzMrT1Oe>N_s5I0Nu+w`U zMv3Ff_$kQYyHaD@@E0`0c=lM-s-P+?Kzq2 z*3utbEq-G`M4b$!xK0vtFwEO#QmX-mLdZ;{b`B1a+@AaccIiMROnoO}EAqi#2t7JT$d zN=RsyR+XdEbwEoCl-{$xN1a(-ogK64yk@=go5yZjZ*E>|dvcRu!_VRBqL>P|mNq02 z7$yLv*tfuBC=>7GIQ;Pyep1}W#ksjLN;Qd>@4{E0n;A4*r&1Cb2k!u^Hv+G2g-xC+ zVzws@z3jyX4ch9=s+(`RtOPXuCL+4P95mmRwhOPHNN}V~8Ev&Az*P>p&JRQfG}RQ=6|34H9*DzNnboGm^7c0?^QF zXHW!`GhqT}gyN;X(QM|wO8QoBj~kd?Uy~Ahw#x-N#YsteB0|}U+lzp}tfr<`qMKK$ zOWjdbik>%U7OvIqhydFvK=gla>CIcT$%2F_dBEn@vt(YQov{=`odbTuDaL!&?d{Dq zGlchK&e_v43njQt@r<3B8E#-!)SD(IAa_ORMfFI&`mxpco7i(99MG@NMoPo4=O-xh zPOkerR>XKmCabW=0o7!0;(+_t-7f8-8vRvo9UWZp&pVl${2!1N29?k7eogUU;uy<= z^KE7Y8o)$6X@Bbo40G1{l4~=NJ5sX)$diro$R2cL#KO=cVvCWlLdcmPAKy*t&YPKq z*?I2n%$%-otu(>t8+#Km2f%lV?7tJMQX||Tf~>fC;ppRSq(bx;n>9Zv(RsFWa=r0^ z&)3A>$nI0;sUg$*sZNI#Cn$!?KbD8YDkEYtC7nF5Mzz$J=tUWMy~1iAspj#owixGl z*m~}Iwtg|oknEMy?G#)tjsYsyx+A7$^m|1Mlw?_kr9)QZ6s49RPz z3UbKE;F9>#fa_tgp1q&fs#dd6R9>Wht>ZBx_^uE)_rP{BxAR#aVH&vjQzf!vL$&&3 z^0m(8s4CjI?p6+;tV89f!!{8srlf!{MGd89uDK!pCPoGja+D`{e_)!0HUiI-dVcOEdv z+9SW(W*WNqZwAVRUwV2YS*PI2Z&?>$oLp37-^@DJBoTRuhO5G3#2YZNxwSvFx2s(5 zPU17p4tUFFT%Rr*9L+GdkyyeQwJ$_&IjIYNWv`&_%!})B(}#0B1HJ;g`|6CxfGx{=YYlxazTx;iT5|h$ z&`c|uzCV*i^yvc-<05~+;tu~{02c4VRG<4mugEcX-h1{i4<>x&`qugILiwUWREE@z ziO8E5WKhp%W{M=6od&;C1s9CIgZsAMV$6b~^bnWNg~%u1sh`;YFhd4uTzgXpoG+)u zlVUG$1Lk|cKh}vx%TrU+`us+Z<*&3cMBRy=ow?M(c{_BrFUvd^W7g ztWUZ2<`!tx;bl9VMQgivhrQ{qe7+N%7R#x*a{4^wn`v%{q|4f`?pYpgnCilhqcVla z`M2gY;qukaETO3RdA>V&9>~*c}vFKl{Upzsr5y6J>6Tz9Mt7<#?Y2-)tZ87Hw6NJ;rUhTa)qL3|Uf;#H_b&E|i zbJtTfFF`JhLSxTPirjYN%AfENq9)w%!cTrStnn$TqCEkC-TJCH&XJq@^3OaJR8q1& zTn|GNO9(YxM|jzc{n<}LF3|InXTR78V+)Nnubp}OsQey7f4WSwf2Ur`ncJV0&SXww zjiMeExeYr~^8V^~EBa~I@FC~7DIP{p>>Mk35 z?j}7Kuj^ye3-acFgOa$tUkodb|An#3<&v_Y*Yc_Raz0aAjr~rMZZV&6-HVAv#t90lz~ex>n+#lL zrMt_IuAB{dWzlxtRwUo$6ay)Eo&5k?gb6Ei*4p9k4NKvbcU*c^Jt_^V<3mFBP_1(;~`EOWnc+c(W(Gh}~vhnhC7T!iuYqc7K}nn#v1%r!I9rS>CTR5Is%qd6f+ z=}oQL;2*cRV+%wTp}q@B0ct~sXE#ZL$pqxAo8Xt zSLyjkF=zaxb0NZe&8G*g>#Ko+oAL!&Scy8`zZvy(GN9qH5yGjNKVu^EsIQ(U83E*u zuaX`ds@WyJ{tgZPB9)<0fVCs75`ve8Z#B#8BXEDR;)2IFk+*XnJR10?Ep#uSWgzS7 zEovId)bDUGgVT2hf{pHD(qxu4DwPlS%9!YvFw9ow)&713kkbZiF1{x(IirA6^f^98 ztA=IGb#iM+c*m4+ikO3F38;6qb2WTq)&;Y0Y{@*q9*;f1)Cm(#0GOSOFX(@07NzQ% z*+7OG`hI`U1CZgwM2V-v-!CQd99P(4N{iyJp1TZKQgvG98d#fJ-^(-RExyE!K3U#_ zAp4q*IL_cBnCz0xM1G&#z0xq|oM++U%P~9}VRHP*^lH4*o(Eq$Ov`)c%FKbkZcWV^ z4+T=L=t;1I^+Shplgm~?$ornAJ6n1H*I&RozwAj&30yrMPq}AQR_?O?%q(mEcu(Q9 zl;?#CvlnVse0I7;dhx~H(u}YoY?&vg|J?JVX>MvEX5ytYr-h58c2>GfF46KT%d?`F zF*y&|snp0Z+YjMR!hL1TgwNij2VA&7&J`wkxwpb zOtOzRA!wDJJ8m_Db+y-A5N%gGR0Nx!4k8E0oTu^)42tRWE|7fe)0YmrG;gvDWSm{Z z9YpOLHfAH~)ZHZAj~?zvdjIJqYlh)t2bw$qs*ZM*U}>KC9WeF#R?d&MZ{trH6z{}S zh12z=&u;FS+2W1LMD_yfS6xHTyLww%hU()MxBtEP4~p$}jr_lg?bn2g{&ECNC9j`d z-g&py#^%x@TanfObhz4`lZss9SRfApO-*_E$$!CMos8v96L)QiwL~=>J}m*cHU7HG z0!93{8(0UDqg@HTg}BcH`-wa)yPsrF*c46$X>cd2ajE@HG>+d~1G%mQ7|dejX0+k* zU!MN@R%@ThD@Fw>^x>&erhZiT(;m)^07I_!P*og~p-dIKNUp6&MfJ;))`@?@t`F&@}qe@@pZQr@SL zp??`nX+2DDc=OkMSKu+R<-KOHPw(^XaQSDDMz>kFltD{7Y$hYZuB?m&0JLb++|DE57DJgs3j2%JU@F~B1VX)|6SZI1< zz6bOo5BjLX^YVnd268*|gc~}iY0o^olblyz&H+in+KF&yp@p`4Zdj@&r$~Db0b2>w z{svKiGZ==l=zGG&o~XK@VO;G(yoZ#QL&UTkQ2c3lOL1iQx8RBc!>%z&eztb*p>R}y zPzgO2y!PR~XLsATQ-gL<2c)I(DvReO6w3z`ngP7;N_z{7yscCn!|8e+?W5!1>n_h@Vi8k6@J$OF!rJ!XazCHKQ#SkbX|=VBhsvd2Z0&AZ2hX2v z@d^p`-Iz75f7bB|kA$;dO})Q5UR^NpbQnqO1WI)DDvw_}`IzH}#v+jHgz`XFfZ)yTa`-xGLY$0$tis<~5Ab@uhQ#`4Bx*OlJ6 zSxQ%twq@G|+2a?$yn&cR!?Utc&u=jq8(kk`8#d{7{T7qYUT&%JB%VmHyt#bo^+#=P ze-9!cyRJxV&grYGER1ZLs=c%9>|X|W?~jEX1xP56agH%6TiM@%`ZZ5}i(&$D;Jppd zw~vmu#dH>bmg|?<)m|mmdH5p7j)##z`eO0;)%0qQWxZ{jMm`re(?j_e0-Q`|I3xb$ zZ*6|Ud~@o7E)6*lKV9ZPpxD%YuaLVW|Q+{ z7<|Lw9;*{_FznSd(FoB~s>fPAQMoH_&*tkch~L_V@pg515`gj8s_;SVvB+ zi(dt_?_X;bMrB?|d~q>kaC_^XHb$y3-_);zHU|#pilFA^3tV5|EW!6U)sKPGtFIXT zsS%TvvGJl4w6=Gad{-3YWCMs-v37m^MV{;MNl1>pQIOe0+}q1p{?Ae|E3?lteSI)h z`QzTs9}8_-_vX!g$=jh8T%hWH(chbbVGZED&ta;SK;yk1GW{*af33yr^m(obKwKFr zGuzyc6gcy`At*Q+J$K;I-`S^OH&SU#vd}l%o1N+adCvQQwZSJ9q?Zr-jOyNXJaZhY zcg9sdpWW=w6neh?8aPQm5&Ym>KNjCPr?ACpot2mvuk*qDY3-7sz8cQ6KzjLiu~!xHdjNQ-mAL4Zl^v)6 zvnX%uusxqj$FnX%^Ff`~^Sa|2->y{8$*QV>;MIIew1?&kDl9^f|BP=`6* zsCx>Z)RHk-J`Q#v=Q@qb^r%4VFsNav=gWKsCpC-6@7GGKe(W3^mb>43<^&9GQnN`+ zr4qlHfQL7`?PpFV@p!*O&X)+F9;RJtg3wVW(?`PbQ-~j@Avy52c@l?nS%45bEU@UzzY358v+Cfi>-%v63Rz-M zgSg|x^YujOOLEjpAe zPeW@GoL%#^%EXgxrGE}N+62@2t@ZTuqC99V&J7JLmk6|Q@!c(|GehQZO}ZG`R=fx% z?L)ys5lH4^y+4=w@btOSWeNo?H}CnD-N6#4`e3y1VnhyCL^hFpey4GE4jLe1uE4v~ zMrlk4B1QfD`K~)}h#W-dUQMDz1{j3x6ktn?#k@&QRE9{W<)1|-ZeG|$Em$PB*e=!i zcZFK0shf(GRT6_DJEQMvGpX*VB71``XyZ2JohjG7z_UEws{5&{IH|QCWZ5ET|6Mg;-nzFD!2P1n-&YL03wPx~?vj96xJuTk& z0E5v-n1OikpYFp&L|h^Sdix2#PYjz~@&A@FzW+j9&A^erpv_E|`SY)whjQo4bx~$` zgVHG+!Ohg)oN%J{9HxOys6cI=Dbb?I8_g6&_BkIT*v{YYe^$9mmI$?ApSswlT&UMU zEN=N2hPSAOy4AeNCpPvNk%wea4BQ-=QcUtnt0Rv^?QTX0V34O2SvrQ-?+YQxjou zcKgyU+qH^lQKBBgiIAt}rQzjOhH6QAlVc$2JbaV7dNd%+!U2*~te1v&s&&o&!|6E| zkI1Q5qFF;t9;fF<5VAJE7-Q-kh6Ah!6MAXt?c%NdbRAXX&a8=yqX@BOLDLo7@(ys^ z0v%3zTH1(;?;PL`PVA9Rt{W8GKNMv=gfQJ>TQPT>MagwfRydE!ljs%_h!1&MKVXglzFEh0FJ9T_B)aiF)Ib0ia`cFl6YFB{a8AGF1$myF;S?+{d z>>kQw5%mApAI%vQqwe$mJ2V*&@4Rn{SkU^r2!}Y`$PTM&?9b}!6%^MMw7S1e+W6{f ziN8JhN}oE#ta7Ezr7>eAAt9CV)IY>EEgFSNuKz5X%NwCjRw3u~Z=DqPVDJCGVPXG^ z*hsC-KmRfW(Zov~nY^+(^fSRD4eur1`Il_9=6w>YuO669-{IVr@qUT5q8BQj_ypHB zGdtSQK?ASd7_^Sg?Y}FuivTa?e)VADZE_TYj9o(8@hFh6}rg zM~n=RKkL~V9RAX?#&)zS4?p=G-NVDpTf-Gx>S_hIs2*h$kt%-(2*zZ>&+vLeN?IDR zz=C}B)q_f9DLy_mn4ucQpC=**2k)Q-gJ~tO)jP0yw|NFP4mA60$1&+M4khr-n-7>q4p<)Brjxykj34Sp5j1=SRaa)sVOioPb*ml`KQy8a0 zv9-8rqGH9Tk8Y;)FcaIO8dSjJw)amf9>{A3rA+ONvFsE>*{8yv7;4QX-{l7$ia3h% ztT10gUtU(#qY*n56?HY(QNRktQ`Ix2xzV@4)>8}zdvju1Ph0GCwDX5U;7cak;ySIA z8R$3jK2q&;-f`C$*AaUV$&|$Gz2w@)k9zT?;PTR z>&s8Kl{3zIAyI~P0X_TbFebg5Ps9U$)>hhh3>~l;>JE4|*VK5l7ZR5!4hpL0kG9&r z^^~(_#HDhF-h!m&pAYG{Y|Y2T&%Nc!K0H3P?qg`U-at=PLF*@)8Sr865E#Ghq-w#&l8!XTq+IdoVb#qw|mpH&mZ9Le!ZRjOR~ zR#kP?8W@EU_{d9`VpQ((<_(ZRw*b@Hqjtrjq9WAc;U>5xI(izUcDjE{QG`# zR&kW=p$@IHXtPB~1y8TpLnduznIK2*dL>vZHCA8DvD^HEo2!*~HANiiJl5>Oq z;m6DThtCFbSY(&3#Ri3-L9Jt{g`F`4D~C8b&Dt_Q!6tS*vz|ZnQ|#^O$j&Lt*$$HI z(TgyCQwJ~qkA=g;&2Z&03YOJ|^_?dw->1ouB}O+wsbXv?3UtIgOmW5cOTlf9Uk;;S zkq|EMT8?}AW1i#E}0@ZWt7tWTC90@`Z&Y{bMt|dfCfgMesvPqNgIl-OUac zbR31F_)+ot%OTUs=MwbChZJGAslz{;tYG}N8AS`T+HC6!lfZNZ9sd!|-dWUfKq^+b zecBZPJX3W#ZR6PttKHs$BkGsd*?;$%&r`5^VPT#`9Ob!x&9V^l64t1l!^`(3e5YFt zuL@r5_uoISC11oHt1RN|Ik>sn%v#1Zu#M6XJkE}Y@VWV3e=jQ^7Cd86x=5h_^HyfB zdGL{oF$#Rv3rXkx^_`s^u&IGu<9a9mEZ8q8XG6KhO^u7DJYYC3?!CpK>)CJ0?4T(; z75*mQ_SFNe*+Rf`IHShB3NvF(Bu92$hlQHn>^fNWOi>cLlKY8Wx50RqbpA2LQTuhq z`;Mc$e0=KfY;GFtXB{hpugRM1<+Ey zb+7pqJbiB_z6=)mN*cLi<30#IKJtzP#j209-y?yT&Z(}9+Bb9;Xzs|iDt#U3Mh!j{ zJbo8st(mnwc{cef-`%@#1)gH*o(djBgubqa(?E^pJVi#T*!mt>-voNc*8$4V%LKI; zG$ijk?FKoL;x!q6B4x7j7&BDZZottODgD5hTrx|(Aqy#d}dU# zYlZUfCUX^$I^(8BbwpgP4lX{`m^X>)xnfUd+~p4}_bQI=@O68d(79URC+sjJji`BWQ?u4D z)GT06s8a;4@Z26(X874AlamiqTpa!;DRYH5UPO*&fr>er;f`wh`%>={z;uV9p<%P1 zr}y$`ttGK8fhHNQtJ{80_%H+N$;HiWRBsXAvvA?url#FUzT=n<5Qfz^FxXv=aBewR zACK!#H0OZAn zZ2b&AU-r6X%CXH#yk^2{hmq(NoHJ&Bd)gU!w|6S)yGJW%z6GdD!8Y`$7J}w(pjJjbF|garqA^fxvt7pq zeOAzZ^hHvJ*wP@Hu2<;F2+q(y+^>`QdG%P9->y(ehhzQNe6Z9(X-i<0J(z+R9Q^u) z-h8x1VH1Hm+=x9`QBmvB-D>k3M!T<#}fc~p8t%Wsj?m$4RLqPUG?-Q>t zkupuJUTW_J)qtldIWYRxQ=_J_BOP&kKZ~p*6iF_EiSZj&^Rq^>lx}8Bhs!rXMEqB# zbTn+!0uCY-bAeAMa;mteX~H2=;o_N%ewmWh&(IY+d}D1nQv_tvWw*K`lD~QB5kd@5 zc9%1GX)3hQjZWs3@m7|tA1mTg6*oED&5g+n zo;Z8YDnNXyTkW}4!_la5dCPukqvv9{1swAB?c3uZGWLKIPu!f9&;2sy%;NuT!CFRY zFPl}`ug-p~oL#r^Sw}tUu!DS;JTZfK=hFk(7}}3pfKbc*3{yGjy)+U^kS= z+PpiZ);3vDZcjOW{N4`c?(Uu@;>`8vq|^|91C9@#Z{t65U?uaJ0opVp*7uYLsf`Hk zXw?2UCQ*cW@WF4UWxW`@MM-)RnB%R17)YG$oF^rQwRLcy_5w!2CXubd91>mS3dEs2 z4i3t3i7(4wY_S*)*sKUK;=)}@@0EdEi(Ey}&$wyeVHdV@yYrpxK%=K2*Nlcr!_(nB zXP}A+MKtq5yk&RyT{)TA?h3F8d;C^t3kxP~i{U6xBEB0%cC~)@mI9#}tOz))@6p3RHBckZPQCD>B_xMyZ_gJf9Uu7O(3^7tzcEN>u-B%EN-u=5)sH!f zhP4rz3^%`i{Yq&a#05#FU~xTg^roSul{x$#0+?3fN4wV*P48K?&)!yh&4I}bdMwX9 zMVp#`6}eTFkdRO&>x6Ieb+7m&FJI2&-V7gyPG*)F*JqCJ&!jmw&bF+R(5ccG!7H;Q zN-@CE&zt#t*$`;)A!3t5P4C+U`!j~dW~K-&<}(4%DYTZ@eY*q16E+P@36vwr8ge*C zFC}mm^U-ZLaI(>B(GInUvhihO%Q3CQZN*$I({7f2*`Y?&^5=;MJqS)wTN7l^@&m!u z)HJ73o%#t(%wxl5x3>b)(>v=V3O3KaVub!7KpNViE5H3$K2{%W`>#fcCGqV^fzUx7 zc6Dme42YO&U9IoT<5E?qc_eRCW7lkpm!zUn5wRUHIXQo8Ms<`RvwCUE?N(7TS*YLW ze}K<{jnSh@MyF&o0F}pSNb{GQ)~_632+Aw(VLY6%%5XT3B^t6NisUmfO9uk2(nTpL zo;k6FIot=#Ft<}O=3asZ9`j^i0&P33Mmm4`m34v4L%P=3*ZPYCOKAPWvV^G}w()t@ zr1bsmXsXzgHt@uuAw*kOSKOtw)f5>-7b`F2fisP_HwyZdjL-IEOpo~^eB zz?<)45era^=LfJ!=d|zgc5n>xK$MEAGQ1rSv4FjMj8{S3SdFbCq&z)ne}psLWr|YP zA>+P(DBL7yWL7lIbL!K9%XxN zY<;g#<1cBn2IE}%r6#U~_KQ6zBM78=KEPutoKw{4=Wcgwu9?q5%8h#j=xjorOjhv9 zxI|X({*#>+MRpKb6#S+*g&H+P6ND-z203XIOU{zy0vnp5p5BBrN}>C<_4e{6c2Hm_ zxW0dS?7ECc+gd>Z$i*LnUaN*uD!SgcEi^BSufo{y3;vyly5{;PNz;|5AAPc*32#;L zckfaZR0rX&Gm6=_{E9bpM(tF!ErxRpH6J2+y;z`FiTss*M`+M+lMJ(rntXTLB#aO+ z>$Mj@PkHBV#IS=Nm5_%t^TqMw-S~B%4v@1^Ysp^;R`i3g#we5^DoboH!eE#tGt**3 zVd9HQgSfoAbm8ION67oM^mH=h-)$2$rE!C=f9h(AP!}}@SAASeopX`Yk-8hZQHXCr zX~DF4o>dOUee79wlg!{V%GkmVb{ykl7z%HJB6VcDp5Xh%GMOXDe2ZJ9(qO}TwZ(Dk z!?Nr-iYa#vf+T%#%Wi_sXmq31!7f(s+N}6 zK8{l=;pXPP(pCs7(d(pOi93mUpa^a`j<3(l&*wy}(_fe&AJpn2y%zi?&(ec`(kr}+ z6kuL-5jP8-_N0OuZ!%j5&dnfmsHhL|jGApuEtFTj-8P}FGXBHQ4&Y{WsV|j@< zc$A`Ai#amiHa_26z_=F3?-JaCnSu$XkSUd(QZM#0+xR*D0{4YvH7^H3dZ|XGL5Ha~ zVWL1k%Wr#;lLWGx^5!FMs)oZV9={As&-~`MY1d?oZT%P#N2rcb(2{Ro@VK;n3Dn(B zghAEu=~rf0!OYL%?H|q4@l3aYxvVba#BS_xBMzg|8_$84szkfb-he;0aQ z&Lq<-xU+Q^5GglzSoF<2%r?}*cFnU6R+zGSZwReT$xD4d`RwW$Dk+&#j`8yO|sAtb^!g?tbBq71M)UnFqjAdM|l1(w{ zsqX`FiqI$z5G~FV6|N&wd1kUWm9UX@Cx4O1j%SwHPu!AhIU;is!rB`1S+)u`_o}i2 z7PZ1KuE2H2lQ@chrgiSBIH{Ni5oEI=cbTqN8!HlqU-6JcOCa^J!H-1LOA6uoK`)=k zi}2loB&u08nzUH=?=d#HcX9Sc*hks4i0 z@XBcPsxC|-Iw80BE9)cS*y2%^=*e8Ai~%IBS&R^yemQ>JTr1&$Yo)??R$tov-JD1; z=k2<_#xoHx+tK~@4R0|=0~~1wJN>GuEKRh|)_Zg$q`gu@Wjv6n6eupHqd77% zG5NXn=DMUOG;ky?FX%Y4x@`jL@ISc#nvmInQP1eU?tboG^uc!Wa$`9YD$7{k*O>~x z;<8lR+Z~i-60Y!UcHkGwbvCKm=bf7Ky}kg`4QOGesw^rh(F+iJq_xO``RHcN7kjPp z#S2TAZhOn|j=z3{fABQrxz|N2HRm&f>hv-s5i$o$uSeKmtcU&NWqk#$#;gJ2=3Do8 zCJ;*)Nl$ml4Bv(Zzz>jd-Z@gFy{M#VOQ=&nz$EdS>`s3xqe#Ae?YnXH1~Q+|s7|JK zd9WiZ;#$R1uanIuO+X`fvTNQ`WvSWFb!1$0{tJRT9Hjm+k9~i|-lgzDg^&y}A-_ik^NAW)+f>;Bl(Mt|>2_|l=Tb!We{f(Ld{r2WTr1r!0t6qU4O z-84W;08O}IH>w)|fK-eE^jVv=J-Pnl6=WhpGk9bbefRD~Fy=^gF|6&`_luou=Duhj zsayVJor1{k_~{jixewNd42dgckwa=9bfNPaK79h|(zRB6Q%OzX1azSWa4D~8# z#KfZwmV4jLe4{61t+*lCGQ`)b_uS){bnpvwuH}b|C9Kw&zFmp8WzEIwH_{|YIhS>` zbx=l)x&X!+2BCv{&YI=@8$MZVXNX)J+bD!9r=m-W?X(_F-r7q$MIk!j5@S_qpqm`X zOUD|n^Idr$0Jvquf-s-U-_n zj0yq?!2?|PmD@nDIg*G#W;aP~e9zU{*d*zv%D3+YAN$pjBmzfkY>f>JJ{B)3vGvga zxR>-z-Tu<0ON?Sp!iO7|&3w1dM&`6nXa7S!Psu3mGo2q5^Ejmj9d`N5MtS42-n?WA z9Vdl7W59*F6q7K_Vr?4@S$r6 zoI3|EyFTd=>}MHe=k9i}we=3<^sc}w&rez22uPLqR?qn*8X9$_EP5eL<^O&42z7k( zm=;9S&90S-)zLa)Xl$}R-Unk!N*^d8ji;~$t_=~*oQEbhop#oI4$T7_e2zG)`;jkx z^IiX@&g@?Thgi<8Q<{7Kl+!)m^J3# zXD7Gk#5yMjEqg$FzJ{~NI$@}dI?M68CEN1=6zn}@AE~H$Ll@p*=0^%Sca3FiUva z;Q^SK6zH(}RT&CKRtkmS(UpfzPTRAtFaXAfp$k8MEZbZ`ef;@7q$3$+l_tH@FgivSu^m_IFj*14g zE)54=6z$BcqXF{Ud{5BU(M64dlCc!)8VCI7H97gDpq-Iwoh+Bp=IpAt(=n=4oeAOB z5e@6#TIMs;mM@fpK=5S}San&I8zZ}|pg&&whCPyE zwfEIdd;R*g4ZEMRKrPdS8Fjw^qxnqfmOZzHVS6QW?}H3_3MM_rtEJMBpJN!S$pw9C zL#3CK6Qf#Q_#Ca^DR2aGB`8{LM0OXN(8e`33vLbaG^V&AX9L-VSK*gsGFC~}pwDle zK0thRz~(Ss=<3F6X_-B1&L?~P_0>t``XPAwYW;*i=?#DwJc$F7=y+Raq~-YV*ypo2Z>PQ16LnioaZV%wh zVB2QToskDs7RkV3%NQWOTK~Rk<*b%zSqZh5pV=omH9H>$f+nL{&rsCzP7P@8YRaS% z7C-6PW{POBGe!jp6LT9qiQX$e_g+Va0tZ54c{ZWLMQCSq&-d@Td`WMT43Ikq2-Kd{ z%v!7fYX2+Cw9|Fh8tK`Dq8QCG{dzMi#W_G}@mL6ARBHe*E3;@~feGy3iq#3WC;+j| ze2guQP;P>l(P@~q_D^kE-f=Fw^M^|WbN&!kP6VA2NRF~yL{FZr-=`d9d8wisiE69* z?NgH*&!{Sm4{7}#$kVv)9=6PsB_g6e6(iCgd{izLz-kB9ih?=Mpr7fPAS(^MWD z9zD3}d^n?|X@{{|OOY<&Lm`ie-;Lu+%5H>$qZ=}{J@dPf>e759d~8AONR*VE%Y8B7 zH#IGlf>h`mVDmLcDp;LYdDRTW=R72;tE%iim0Y-25$$9ixUOKUqEfp(N~>@&tVcEE zytw&l@QjGP(pdwHJ3p?gaLQ@X6abpVURBr~+4sryG2V{JJ+j_M<32fGt*QfCX55j|WgB<01pF7T z#|Q7t&eQc77Z(@Xj;5~aqd)9TtVTMGPWT_=J%M#BYR6y81h#tLxBJs7uG|*4B7*GW zhcJmc`4E?JgH47J-)jm$pT-pEVNt~b1OZ#T!{oBF)>B@nzsit?PfANW=&i<_qhQ$R z80;{vb5K#=HZEK2K}gYGIAc`rR0fg{!;unz?zBxu^YQkY*X~10?qjD_4EOLG7Ri*v zA4fHQfQGs<5%?qc2pquTFUc%WUBD+&|HCJGe)&90%oDoEj#aeKmD^OB42q9xxy|&q zb(EGV((tjl93rMT)1k%sqrF@LLXrEQ0EK8QFcynq#=T!EK=Hi{JE35t|)su?{IREWZ z=j+YA_W~B!*_j{y7rde0=>h5(>hL#Q-QehvDk?f}e~JQ#_lZAAUC+;pSUOlR;ScMn zC4hdTSAlzQXCKASkR35jJ*@;XORh3&c~N5rSi>=G$Fn75=ByE(36@=^KiB@LQ)Xvq z3->#FSP!T;X`Ute^{W8J;e;afcFb2wxsv*rMB(kFq67;DCUCE(J}&wOpE{BQHOl{o zBE&5aS1<6tafG5uj{j=UY(k#0I0DvP8PmxW&xY(c$_;yB_y&I5!Jpo0ORXd{C!76! zvACPi_K7Ma_{sl2P5Y6QqG=Pf^ZV-*aq1WfR1OmueeM1ovWWXZ9r0E3&nG;^981#? zr_64*IHJNG2KvlKkE#vq?r8tLy+d`n$Q;{?3Mc$RHLV1Bh*R~*o9h? z{UHxqC5!JyP)8|(Ng55*-~Xq?h`&~Vp^8$xXrOdYq4G^nce@}n1=Rg7ovD=y3_KTL z00G0$urQx)_s&xmiin(q#J8X)ZEMR)b?J|C<0mEg zGy(AbQ@a1Wf*Pn1*BWJLSX(@Nc-1U3`laUwt_Thjx=U|W$qPY6*+zdg#@EcXXw>`^ z{kU`)DUz{2_d*`EN~Y5&j5I^_wb-SlO>x_)tbb@Ir&?eAZd}nMMJk&)IjLtzeUNXJ z44_dMsFh!FMoDB)pa|9sk_FU%Kjd}cE5P9;YsFiVr2$3GS-AM`kSsjM01~@~hI)&G zL7P%uSS^Dj)nC5W2Y5EI*siO$8+6}fSI4Qs6L7z}LR8L_wyA6J#wza#AicOF;xghh z7FDn!>Nrn5uk(Mx;{JERE2g;n>T2qnFXmtHL@e$57Tj1&gd3djs^sY+0cZ4Rw{0%n z$P=(PQ^okSS;ISWDh=M|FN9`a=KFhXX4VL<2n84)MOfQp4btRpW99`K`uSOMez9I; z-W)OUT7@0pf$Ei%-E{W0wGHRQ#xJUHclfrNR+{iCMp(}FoCub}mK4@74 z74p(V$(QOGtH&%+o+(Xzp@oewC>3PvLlYdUNAN2&NIVD@T`YI+*T2gZmY!o9?jvQU zrA5Urpw>Q37g@{|QCxgqx}q6e-$2;Kh?lNSu)F(FsKwIVtUs4L6_yz%MgLeUt{@V- z<+2m?(h|~zQ&o@o`-ZJ1k1MbJwYWJ|A^YE!AopMJxc<9w{QloZI0@JP;~V(jF#o@m ztoZ+e{3K}p8#8y=nAfb)xo6S*iuTj>MI{7X9qDsmL2t*Y(U zB|P1PtE(d-+~hbcyY9?xAJ9h5&a*%p>zziLJ$th1oN5ht%}}xp!G)hn3%SHV(pjKE zancJp`B4euewvs-XCn1%Hy2H||C-QgRO<-SHu~ZJ>snY_Hhk%5yM9In^o4V{D8h2l zA8!FVYuRXBs^DzpT{M}{aXU0QfsQ%n)t}7l)UWSu%0sQ(JXZ@27Cjb5FoN%#3bI^{ z3i_e-&dxtSg_jeHv8e|{L>GP|s0Rka#wU68;7MCdQlB2SO{Z%VArIPnVN}nfD-B$;rF0%XM_fkei!sTAgmM%KS865R8J(%@C=$}M_IXtky@){Y#6EyiUAYrwEZo{LMP4V!OmF=jsdU9S&c zNBDe(u-^TS24h=#UshgEGu_|#lvf5SHPFLLnA^k_>7(aKN>o&#zC4s9!#}Nk~E7yvM`y#6-$V*|!=%kDIXpMcn*LDP$H|lf3ibyl`vWYEx(Sdq+G~hu}H;6jinrOZ= z9#8N20h|1&e7loS$hDI1egwN zg8*_RQma4S$N0vl^{4xpWiBDcRcEll!#SqYD{ngDd(_(ugUPk}D6zeR% znTJ`VU+JhReWA3Y8kL_JzrW&bn0@z_$UG>Q@-v%fLBb4E>`m`iS-9|FT2j>#qUizy4m06mG9|Or|-tD_Ivw_S1RJ|x8PfI zudRsuyi>mRLDAAp9oFDHaKQeiBVWYPqq~paDf%tBw;I^X((K>!`PS=T`5763Il#e% zyz*MB?~kp%N~NSek63%{$(_|x<7-RL_a@uQtv{RB>zef0?&pO?xBPPM9C^3ldiI3_ zFN^el*E~EZr3l?c@~6JKTsSFIl%e3y9rN#d1Mknin3#6u%Py*l+@eJbXX^4a ztMp9ZP&CxK5Gs~?sB~)}M~_%wVBV%h6I2#0yP|eHf6E1x*)xy*6iI%zuTq!IMJwZ? zw55LC{-+P`RG4OXAc6qb>A=F6gYJ1YX6&x+~?1p$Imb>k6Sv)W?SLo zH8(fAySv@HxApatjljKO8>6x}GlR|q=WW8_}He_vG$?CqVMZEj^{Wn>hj zGu3ISkkbwuo0>l!&*#PN*8fvu*HZ8~ce~BbpEGxUem>o6sescY73XH>uajSKw;sAE zZ@n$AYE{(j^-Z$iI?8nQuX@Ebt508jE*)Q$7tNvQdpXG2+4A(cIaX6uc4{7dbV>BI ze9YFY7e((cJiRwHJ4`=z8}Q6XHP51FS61qrmRfGMEOS=s&1=51mtXN;9kv&gwHB25 zo=Dskl)Q2K_v`Dwy^r5e@$q6`U%&mW+yA~cwqIXcUv+xgN?%{&TWNj%*}ESeE1Jg3 z%lEGCZ*Oh2{f_sIqS@Eh&fZ_}@ZtMg&OefiR%R+)0}WX?+0pJUw_OB4VI2x&l4{x zDLt?B_nnwouXo;<`)sx3bs6yHoE3q>rE@E1`Pc6*D9l+?l&c{9;&par?%v1eEaS^c z+5|RTym;!y4Tt#qKmN2WYZH*Fd;iXJ(vn@EH5v>Jw@e$S`z-yrC1C#kvL(w`Tc3SC zSw%BF((?2q70=H<=dF8}{rm}cB}DD&b?I7KGFkcaO)7(S&WV*>wc4A1>-P459et;P zMlmdy=5s|h;{S^6+s#`h?&lSsHG8)DugmYiMb!%6YRe7xN;yJ73jdtsyJ5BE92 zQRw0eR;7@|1RkXb6b6rabj)f1?eucE0_mtOQUljQ0;b@M*sy|3t^0ni2?CmW!_&nv i1Q-D18Z$_>-kN`O(t=4fkEemh&pciIT-G@yGywpp+F4-$ literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/code.html b/legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/code.html new file mode 100644 index 00000000000..4d5d5a6a0bd --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/code.html @@ -0,0 +1,325 @@ + + + + + +Owyx - Instance Logs + + + + + + + + + + + +
+ +
+
owyx
+
+
+
+ Ready +
+
+
+ +
+ +
+
+
+
+ +
+
+

Fabric Exploration

+
+sports_esports Minecraft 1.21.1 + +extension Fabric 0.16.0 +
+
+
+
+ + + +
+
+ +
+ + + + + +
+
+ +
+ +
+
+
+search + +
+
+
+ + + + + +
+
+
+ + +
+
+ +
+
+
+
+
14:20:05 [main/INFO]: Loading Minecraft 1.21.1 with Fabric Loader 0.16.0
+
14:20:06 [main/INFO]: Loading 42 mods...
+
14:20:06 [main/INFO]: Loading mod: fabric-api 0.100.4
+
14:20:06 [main/INFO]: Loading mod: sodium 0.5.11
+
14:20:08 [Render thread/WARN]: Missing sound for event: minecraft:item.totem.use
+
14:20:09 [Render thread/INFO]: OpenGL version 4.6.0 NVIDIA 536.23
+
14:20:10 [main/ERROR]: Failed to load mod 'invalid-mod': dependency 'fabric-api' missing
+
net.fabricmc.loader.impl.FormattedException: Mod resolution encountered an incompatible mod set!
+
at net.fabricmc.loader.impl.FabricLoaderImpl.load(FabricLoaderImpl.java:192)
+
at net.fabricmc.loader.impl.launch.knot.Knot.init(Knot.java:148)
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_logs_tab/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..7c6cf2ca0045086d1ea3076fb645e31457031b1a GIT binary patch literal 243656 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

wIGx%uRp)7{3c4wjR5+qS8ZxM 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%0Dwjk-g2kKbhFCy@~haY`C=Q+ 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 S{dnQ8R)Izq_bTtWKmT8bh>msu literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/code.html b/legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/code.html new file mode 100644 index 00000000000..bfb5de2318b --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/code.html @@ -0,0 +1,306 @@ + + + + + +Owyx - Fabric Exploration - Share + + + + + + + + + +

+ +
+ +
+ +
+owyx +/ +Library +/ +Fabric Exploration +
+ +
+
+
+READY +
+
+
+ +
+ +
+ +
+ +
+extension + +
+ +
+

Fabric Exploration

+
+ +memory Minecraft 1.21.1 + + +extension Fabric 0.16.0 + + +42 Mods installed + +Played 2h ago +
+
+ +
+ + + +
+
+ +
+ + + + + +
+ +
+
+ +
+
+share +
+
+

Share instance

+

+ Export your instance as a portable file or create a shareable link for friends to download your exact mod configuration. +

+
+
+ +
+ + + + +
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_share_tab/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..879e68d839eea16e9add2164777389bfb3976cec GIT binary patch literal 208867 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�#DDd&5?|g2SGqw&W6J!8e102>+I1$U|v|qP&W9g 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%0D)*ex}lTt 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 + + + + +Owyx - Fabric Exploration - Worlds + + + + + + + + + +

+ +
+ +
+
+owyx + +
+Library +chevron_right +Fabric Exploration +
+
+
+ +
+
+Ready +
+
+
+ +
+
+ +
+ +
+ +
+ +
+ +
+

Fabric Exploration

+
+
+videogame_asset +Minecraft 1.21.1 +
+
+extension +Fabric 0.16.0 +
+
+
+ +
+ + + +
+
+ +
+ + + + + + +
+ +
+ +
+
+search + +
+ +
+ +
+ +
+
Name
+
Last Played
+
Size
+
Actions
+
+ +
+
+
+public +
+Hardcore Season 1 +
+
2 hours ago
+
156 MB
+
+ + +
+
+ +
+
+
+public +
+Redstone Testing +
+
Yesterday
+
42 MB
+
+ + +
+
+ +
+
+
+public +
+Creative Flat +
+
Oct 20, 2023
+
12 MB
+
+ + +
+
+
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_detail_worlds_tab/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_detail_worlds_tab/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..e3ec10a302666fe4336d6ae56f70e8ac5e359865 GIT binary patch literal 157258 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
CV8Aa<6x~3oHJxe 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 + + +Owyx - Instance Settings + + + + + + + + + + + + + +
+ +
+Background Canvas (Library View) +
+
+ +
+ +
+ +
+
+

Instance Settings

+

Configure parameters for 'Survival SMP'

+
+ +
+ +
+ +
+ + + + + + +
+ +
+ +
+

Memory Allocation

+ +
+
+
+ +

Allocate enough RAM for optimal performance.

+
+
+ +MB +
+
+ +
+ +
+ +
+ +
1024
+
8192
+
+
+

Java Runtime

+ +
+ +
+
+
Custom Java path
+
Override the globally configured Java executable.
+
+ + +
+ +
+ +
+
+ +terminal + + +
+ +
+

+info + Recommended Java version for this instance is Java 17. +

+
+ +
+ +
+
+
+
+ +
+ + +
+
+
+ + + \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_settings_java_memory/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_settings_java_memory/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..7858ad22f0aeed163bc80a5dfec5580969a9516b GIT binary patch literal 155962 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 uA5=J_eRkfnAR*$W`Bw1CV6nInKq$x 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 + + + + +Owyx - Instance Settings Modal + + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+

General Settings

+

Manage the primary identity and update behavior of this instance.

+
+ +
+ +
+
+ + +
+
+ + +
+
+ +
+ +
+ + + + + +
+

Releases are fully tested and stable versions. Beta and Alpha channels may contain experimental features and are more prone to crashes.

+
+
+

Danger Zone

+
+
+

Delete instance

+

Permanently remove this instance and all associated files. This cannot be undone.

+
+ +
+
+
+ +
+ +
+ + +
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/instance_settings_modal_view/screen.png b/legacy/Launcher/stitch_owyx_launcher/instance_settings_modal_view/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1ea870ccaa7e55c0f7ed04d681bdb3fb26f6f5 GIT binary patch literal 152737 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≺cL20YAowiG6jJ z(p}@zYacKUL~W924A??3kBYPXz4W;ARaeO||f-=YR;&tdi{O`rDyUL-Dwf=)n54rTBTtW}o$Y%>8(X)mM=#{LC z;0q<;pg_@^R`Ew%#opLm^Z{yeQ+aNjqJE;?RBX_n5blY_qcC$bN9{WbplAdLA6j3| z^YU!MY|kue=R1BV@-lOmjww4XWJ7bSFm{asMXbdo^GLD?h1Iz~7|`HZbeAs}-j~kx!>F}aNbZ(fOmAQ8>Yw-~vo!Sjuq~%@y<~a*?0s$@ zOHuh+slb&d<4{k@qijT&etH-;A7}fv^+4^{Q`K!@wcIcvf&(*di_8Az_}wo9S}el| z#@MAkRWsgSh~o?sDOXY4vA@?ZJK>y%waGF`a`DVLzc?f6_h(=;xgA6W*6dUCBV5n@ zuxQM}46@u8OBdv8lP2iNE>~#+KoH{jQXcnPCY0OUrC2^K4IR#4h5Yjdni5vN&$RJpu|M!{19r{wtkb*2i&kuTjk`siB-eWr5(IXkcTWd?(Ne= zdWZCUQ5w|QO#NEI+*+u#bXaUFpGlJ%w8CO8IP)ZyX+D;0PeF*~KXUhFZC9GWlWP2k zq6=B2!?oaSn~K(^91c9A{f^g1tB!!iHO@v_DV}4-;?jnw^T&U#WWOrC-^#fS6f;NY zyu}B+K#CWcqjf4a(vF8M&}_u!o!TICSoWFckBu=kR=EN~6oF>}xSnqTW5WgCZls2JSu z1ecVY>pC1>LmfX-EiCeG>e49O_c8TQDf0;9R&ulMQJpksc=*YZxKZ6dGPO=E>84uR z7xykhPzB3i{POCLz+91n*XP|{7_T%FVe*3hCZhFzz4p5LGt@JEyXbv-+Qd@brEu#w z^Mq$s_AYGO$>cLWo^}i4)cS$Hb%OQs2H?RmifF*AO?&dQfF%Edt}%jO|(+Z zY9+u;8q`B`uVLqGhuo=<7h4pG?&0U_Y|=-h*EMuQm48{^PIvUoSvF z1jGq7X{W6pwLK1O6c0LHoS(Hwuye)FDAJ}Xq1sl_efvNPLaN#+ZUsI61^QmD#+Vr= zUK0HzYhd-KZQeU?1E$Gcplkbc5wk$S^q-F%4)5inI2rFkl2zxSf8nbD-%4W9G*y!Y z=hqTHkP~iKG^0cr_bxrG=Ij^JPx0Q!vH2N;<74X`GIWXe2V6j$_+mh#=7i<6rEjLC zRHMKq5q3HwM`^dE>2v2&N#Tf9RJ9K<)^buf^WC~cTXHwgYLr03A|w;ik`GZ6JZJ{b z)61v6?k9jqz7u&%=n8Koa>u!g2`iPJBL688^ zeFL9ImOb4KzPYkqdu4wXxh7=nFK!b1&asbWB6!_u_pt;m<&R%hjSZj`5F>-Hcg16* z(v*S$RSzJsZm9s&KoLB{<7^=8PR$Ut-#h(5Rjwp05+1ECnjG~}!k?p{CQPXe@TP^6 zL+TgkDu$=iyAYw9EpX(7`C39abgZ05vwY(J4gUVVT<4i_mwL1*wQcc?Weoze#G(^K zLO0|K()aT?vgNHQ@E89Xk!a{E=+7n~!+p*iBT3fj65+85SBU-#miQ1$Ohlxr5RUXW zXB%7lBGz^bRe8!e^Nr{DI|FF3q;wkbB_tyvLjTmDHcUfTPE`%5kJ`R4Zi4T2s8(|3 zaVA^h?m!sEVYkrA7}$x}0q$&biJsU2P77YsTUs#Ibp6yJa7KWZZ$=YCg^bM^ zCbUcEk^Qk6i~0wji^{S_H{mqv$HSY5UVo|NBZhDYF8_X&4b22u#S?B~G=hv8hiCw< zN8Uz?qwJg*@MFq}!UQD|Xmu8DMiMF-tj20_CM+OoX(h%vdAq0R_l<5Ps#ogiGs5mZ0?HXk~X zDLgryU(Kl|Jxz->ceq?@j^+AAB>uC~4>@_sH^moZRp^r^ybLT?i^mLN?j; zNa0MPJp@W5ei6bBff7eFqu#9}`kbp3@4#Zm(L!}p9Qe1Va zgq$4hQb(qGahh0d?L z&`3T))tBStJy))vQ(;4R-AMRt(4y0O2`m!?os|Oyw{I?hcKw3K|@h! z$(YWhaATP0sjK{D8xx_s;VmN)GG#*U$j%!2(tru7Bw|rFVQK=>OPx;PIw5jyL#Q0| zW!P$6wrye3-(E?cX*y9%URg!d8-JRyt&Ot%apM1+$#u%jmOt?4ImR-RPf&H$qLzE7lj#_UU(T!pk^T(S)1nxjDZ%ebY|+M}qYNB%-mK092zH%ip0b zeVnCB)~2D&ae=Tpnm|w>Xz#sreQiE77_4n;bYQ+Pyx8BPf_}h#F=V**i?`sZlKriU zoba^~_V7Pf%mi}aRU#Q#-uFumdqH2hr^CV!S2 zAdXFDA4dL8B64tMOuM5D(gw}+t3Tm+zb(MQv4i^cS_ucg5Noak;;&<|h*RyHWIQMH zWzSp4Iu|X>@^1Dd;AVSVQO*klqG?bdQ=lZbs9Xxj)xs&^au9BR$31m5Y7#HiBiKJn zKU6h2L-C!^VD*O#?7lVp%AOB{2CB8VePqy%q4YC`@FTksqM1b>p}xXxevjv94RG9~ z!VIvwuZXoyY>AAI=*Rn)vnPzdHz$|?RV36k!ewJg+u0Fc3@B^-1VA7y(4O@@Ybe7E?T8h!FJoh z{UdArr-xlVp3ZWeWsR5M8>UX|gUI!8O5o#v9eoZOmLc$8nlx-`%sgL|?UGrthT$Mz z!4XxYG@6)e@BFxe!l|ydS2n7bXEe;!!r)cgKT$i{@-(iJ>Lu&GI+BB)zd(*tBTfpV zq7&+HgytxtmTsfElYYR|ZN#_n)!SI3B#fV`RG#ulhh6iX$Co@?DKf$=>F-?6G=_(& z>h>ql1A)MtK|3y2or2IeuW9x=ER}v*&`kaoM8WdU!cTzlDz$TF0+)09lCy%@>X<)6 zCV$0lAFF@AC#0uh-&Fn%_EW+CNE27P+>5{Hi$qo?t!kI zb@YD6yqPs-)8m%3tKt&uE$N6x4lW}$h9rw_GZ1UhUOrzHdkxB}WvzSk4a0)}KJ~t= zuZm_@r7WQw1$!LC&{Bly_4HWi1|>|Ej3P~?wmgi&2=IkKF#G<6v=h0(IS$c|KHXsi z8KqzFDyc6&cmU@=-&j!vnSRksk9;tqTMFP|uEPoaokT=bQShh8=_#RDEc9^BL{PJx zAx+(=|3zZ>Au(A{Thg#GN$Be9WOSvn)v5;gKp;CkL+J8Q!dUx{n)Kyxnx-$mhDR_8&KmcXsLw(IaauP#|!dv44GrLl%a3bk*iF{J_Ml9K>> zTES3l4G!ZWY3?Nhwej&tkPe$(>Td7c6}9h|K8mQKL|U|l_r9jrmyN0DCnd?%Z#&i0 zoa)9pUTY-?S{jgaoi&g;URB70*gEU!vFKfHOpvqgmMJtGUdL?uh1*m&3N%R}^CX2G zN2ljM16sL86XUd!+2rcut||BS((Cgj`lXuAR-L-VZp|eW9eVj)X)QA6s>oyMl~wIS z*m9@3cN4e@w<^5cON+<{T^OLNv^}A=s29<&Ae0svE8n5IbqD*_mb*t+Mp@W?7CypI znt#Iom!Xj2TjOK>(4fIPFr}s2DlD|-N@u9hdGJa8K0LFwb$^w}Itwuf!( zU&#H*dkIvn`D4hJr||wj>!DD;?@RS^J0k&<544mXd0+cI9h-G;cu-v%vbq;l3VE85 zFtQx=>(W2>rKv{cfR>ihzoT1vh0RuzOqHNfPfcSMDCvN*yz=FQxK$dk_Ak(Sto zu-vCBp!S?gaad&*%*y+lC?&%8U&CoMEb*AZG^AUMO2nKUYR?8a-dh;($OOPRB6cq+z@Rx-mqN-X_jf99`umXE4{PI-iszY@&?GceIod9szrB77R51-4KxkcnmmF zdD3oo6O;F>J;9K=)giadEareEEi`jvB*w0N|_~7N4#i%&QhY^}|m89Ae zRAWG~9OA8b8Xemp7i{LDuO%c8tI8U-dnx2KWu5OB`RmYx9t_^}s4KK|%eb1=-a`); z(OBI6lfQb@qI#oVe3}h^x!nqf#y$%_I&cb+3O%nHyCZ*chpD!|@zBCiY*cC2jW1jh z9_{1VPa*-As*ulN&wVO4P%IL%dLIU$S1z-VjRC0FOXWVCNZwRyK7$p)qW&@BV9%(H zSh=R>&iIDSWQc@x3KO>nX7u#w8roR=5~>Ax$Ws4L;xZrHEQaoL^K6O6=5>K!u?*(I zNoJAh{q>2cZyFUk9#ytmG%NoYc$(&huoY&BA^5w5;>M8xPQ`ZCrs?VpUv*0|yECC4 z#9uyJoU8;gODBha~hhmyd}Pn!-}ZkE37J##y;enIY6QTvq+9FQIZvvOOin!rVxrB$s?v z_7!qcwIC_X_BZ9_%#8wOku9e`iYR}*dQ+s|+OJ-SA%o@3r9MM!SMS1}3HpC-;&0~| zXT6kz1Cu!kR3K<+V@RIn@}ObbV;NuoR$P(G)Ze^@@My2-Jrd}*MK(QI$lryC8nD-i zxva;PXzDH{)WRcNOoUB!NRV^-_mBy-=Phnuvo448U1=&YzC0d8pUAIV#t$MZ`v3Fk z|Hy#o|H}@>C#|>@1x3{c4K9r-#F_dk7x%eM`+X|@0nRq&o=Zc10Yh9#j*94N1$oRM zR%B)SlKx?4qAx2XP`n%@4c)>i5BLC2jVP+O<1)L1UqlhAY%RCQ(D+9x$dR}C2;3(C zCFa=ch?oDLk+MF79j$=iMz+r%S<0=xIo;nTTq+ z#c&&eU^0dW4=U&ZG;KXAzE-yV@6Qdxc~?=G2B38Lb`+*#lNq^IF*U_;Aq;13a-&Nw zO3MEi?0*Kb-i7&QRziZ2$3Ore_A07A7p1NH7UU6Tsoe!x5Wd-SnWYhV_UM79 z7+dBd&CIAjh$A>pTxo>?fC|nr#KonoVJTxiAs`c&rYs@|-TM`xjy8-<&NfZeqcev) zUdP^6QB^I;m~K4%-!@>QsV_*tgqy3;9=KhSaouffdgB@q@XZFZ!0Tyg%44+t16%d0K}MiXgjWbBCw@cegN;(E zF`x!}(dV3{82>MRFsS|Fe9OrU4%60F&|{V(Ys=|FY@nvTmquMFRYn#yxm_rIu#2?` z`KKpFhtMlvJxj|RJUwMSJ2uyNTbET&>n3=t7jwJRFaQ*bzPMBZ3^Hazk__L2up%t& zUpC{i5v!}p1l}mSGAkelMiOo1&0M2e$v58pPnsiP>37n+0d35$wK@FV(cLr`ML#jN z54HDpoXq45UIEi7t$5}CaWQ3fH4p}XgXDN2Ry+;biRHvx+@%^&kQUAtB1TJgo-7A- zdR1{qb*by0Dka_k?cGeye-s{M-JB4(DJm*{0pXm-q{A2VZ!BZ5?u?_Kuvb$XZ4x(!X_h8Si z5nc%VLqFrE!T)>@(T^~qOFJVHjQ#)RCr78=ol#H8Ue?Bcao}e)VJ{`THOfrt3I7j> zGY<2BXEOW?7A+eD6ohnPCD%ojaMqVUYELM?2kghNw_Rm#{v&xiD|sp! zjJXG@C2D$?dj-T(Ke$}|Rx25IVdpstg4qrf{m>Ug&C$@&cu6sH5+;0V*q^tau1KSe@zoC55b$E%xYQblBJ{lE`t@(8lTz~@VE~jJ$!$B zg9OwX>ktCyAMD+jz_xCb3R^>6^A^ZeorxzXJHdoCT68Tb>o~Ait#l65Cs!wxB?=%L zXv9ZlH2$-sjT|&zOJ*o50#rgQ*MYL*x-WdkBe4F2{3b`+r78VPCFBG_GwWIulAKN2 zp8UyslNqN9IAO>jFcj$dK^JYOwJd$8}>Ca@yT)m50!MAjgbP zXQxqCoQ5B-z@wsyudl$vdQudp^fmiY^;bVfUc5hu7jNIjSIrHi{_T|@9QUwsAZBhG z*#8S`dIYzBcE1q9DJkm8tCWoR+FOYy!!oQB`Y9?AhFP5pkYC`RB1L~QGpp3#4s~G~ z%)3D%B$h#7ofz9(Xvw>d04JH%UC7Gf^6o<=zoJxY`#O3fdJ(I4ls(aXd2dQfw_gIb z09H(Y^AXH?ZM#nb7i_0Wmte~cTjca`6VN*8{H`(%Kk`mk2T%b!m%9nhbhRY($1J2@ zI0rBgc1xfMr~&n>i-gyAXVklpSd6Z0NujIXf_RJFSH$YWDNsivmV)LcWWw^gK@QNn z=hani2gzH1Tv`ZYh&Ew4xho@3f)9UOn$88{cvIjO1Mz=4C(6?It-cRai6>E!>#+D} zM5<3^Hu0$Dk6yf32uu#`(uZ|Be=$5*-@0ck^J))R(tC@2bQ5&k<(1hvN_{Vuyu_ej zWU?V(-slgDgc>lV+LdIab3*lU;TM6=(HW;+A)tHk?7C}1DLVDZVVxf5PbnH8;kKB2 zFcqz!KVD(Y=fOVl(8w?;SVw=@<*e236R^1#q+f@HAD)4Yg&1)EFb#EhsU{`lJDh!w5ytr_A|4mH&>>|*=F2EimZhByc>$X)^CPL6LR zPxgAXm5Os#MkxrPS?Xv-01JO2XbVrb(iJ|}ppdHBPle0wlKApo1ivcneJ@(Bj}I!xFc-P zg`HE8yt!f~pA5WVp(C`gNX32nH)BCXZ7WfeocAsFNJw)ZmZQ`w+sax{AGQ4~t*qLE zf;WE5wv$pk_}O6X9PC7((wR*SbJv!||CY&#i29ORVVLS_5vYNIo}ONPt;gc-O6z#q zzMoE1nb@tXB4)%_M!M=w5j>3o9Oit~Wp=1|BU2GIjwX7F@Ux(cLrY4iq2b!zvAw;$ zii%2mH0=tEY$A<(eQ-V{>sg?crzf0;;tEjFMd~>x&#En8_oIhiOkAMIRG^r^dzc@T}U4FDDxfH8a@( zt)wI?E%isvU(3vjzvbw4IqTN^z(jik>sz%yJeGrg6xLBeJBU3n_FV{FqNVwkC0XM! z`zB)dIPqeE^e6o^iL{svLBoRiVq$t&g>qSl=dy>B!|Lt#m43Ah@r`o*(a7G%dnIl@=Yfo9?H%QW08{__x5Fsw=X&3D zhO%j77>Wmf!K>f>V@Ou)aV@+&MvWKeiDc2FOdbnxxtq^I^f0Y+aT{atX?7FCR%Qh< z$S2&v!_erf1-8lykkG0sAiCbob?b+b_jFZ#JwnIE?N3n!#sXrbAoUK~D}DDa6k_O! z8;5z)t9%YNfEmtbvG{ND?~y{qzihqUnnG-PRg`af5i*Y6vP?+vkP9rc&%v*$nn@xk zASh_-R}Xd5!@r=Ca8I#%ppj7<929hZn4dD{!s!Vel4vIK%G)QxHa3$#3GHc&zFBWi zrjJ{XOifF1hjWu+1C&=Aruh{dt;p59=zHl6iR&|5jKG zG%OuG*ZWo~x_Kn0v(um0UadCN2>~=qB#IYJHjJL$Xp^}n`v`L>2A+CKsnFT!_5(~gde#4$-rWvEjn|46>G z%q4EHvHi_9qO|uFXK+NrN7zRV5Pz~h)CYdg6jY%$ad&a3tSsyLkEwe@z>2yi|D`3` z@0k+aS${xGU)s*nw|-u(jj;-E1RIG?njj{z67J6uSm|i)=;~Yd_^1siMTv15IuqxY@L1MFk2bgjMRtY$VNg{Imy_A?StdNeOF2A z^m%WiQyz-Fbg=Il0qXbVaV}m5Cniw>-Pi#f-H_a-u<)08PhGiir(WOo-gl-mO|<`5 zYk5tK1OngwbzHacdwy6fmT>lKXHd;JAn}@&E#ZbomkuWc(g$^e?96g zPg?Wj5k86l{kq-WO)cP%&yT5xMxRJf->pt>n^jwXpN^*G)&A>>`wAAKv80QXs#RB2 z5EYc)$U<1T0Z?W$R)n#tr5SyP0gfHG%~AY@lS)gtLVVhe{j&g7S@{yGz7_V-SXg?H z!Meu;#=ut=)a)$drT@o3t@N5_ob73@!Hx-it_D=a)+y`>< zZQogdY}HQQ3-|&XNgaDYyYMG0SbdD_>)(53Ls|{?CrQpD+&-~Wad)RsgG1%;Sr}D= zP!_b7=>wyuHBbE;f&!fGVIHO*E?Are1$$Kd4MhfpGuaaviE8wBuc{H?g}S@UE9rJl zEc)~ZB0md=51OKPQW0q?XQ^RsXp{Xt^au8Ya9darfLk6%%PpRlP!io#t(VRlo!p~L zU|+2^ujB?gVe-BaV@rSUrB`nW!wDpzMu3R=&j8)J(=D83oC?Zg^*9Z@_wBBfjuF5FPt}CNuik?Kf1q-T6h__(sx8cR&o;U&$G4i7 zzc!s5@wc6e0CDl24&sG)L|K@XyuSpDbagz^-#!dPnMA0|FK@q0SUKh#mC{l~^SLH1 z{t0-3pX@yVTIHQR_V=60}6APv*9KY!@hU|Sn%eSGXt4NrZ5j;})8T$r61up@f`Cj>SHySZFTW33ny?1q0 zVg4myCXB3jpKV&UbaXYHoK@mGw{AwokN7(cleJfp^XQTzborCXt_rOaAs+`RTW8fx zoI-Q{7Qlag@ldXd!N(EmC8#GY2`udid|e5IO2KMGs=Pd8HJ$qpQ!v(#N@!7VjmSJc zmAu&Cs#h4He4QYxyY~WlJ&Z)pynp0NPrYs73Pgyfwxa+}u`jhK_VRUs$|5r0zPq7CHCqxo0g#Y03YCK1?QJ>TC<0o4w zZYscKmhIqgL{CZ6s^h;e^ngO4UjgLL+}_`VCHlX3`s%o*-Z$(K3IYNuB_JgT(k0!3 z2ugQ@NF&{`p_Gz}0@4Bk;((FTjF57|=pXvVhp`2D@_`xj%Mot<-@yRQ4Xuk-9B zQk9VZ)31qlblOAS3J*yL8Syb#}*>#LtpYvCK9H!kCQYquX(?mTiO3WAekleOoWP(wVKzn}U`*`~8f4vC)ySbnzu0w;o9QY-fx* z0b3Dt)5!*&UH{pcUO8w3zKeddTh`g_zXoSEe&_v(t1!dfEF8ZUUP4dxz*%Ogv7t6> z>#)OsTL&q`>})gP<;*NjFgyR9ke_?@hgYO8(IZdEGqA(2>gua~p^)YEbj77rR_q~W z@ffErzoDlS_6MPzCv&P^kHuBlQ_*}XBB#$gT;o>Qi%}1|j1O#C^<1b5^0ISqSl^q* z*c`5;%dhRYsji9TU9H*RE}4><+uWVc1Qw63SJSN=Q&-NbtYPQIxsp@pN%^R`|2z%blr^(4y))VYa?F)Vni zPA3Q*h;dk+*$uypw+Y)^Y?1#{IhZF4@xJ^UZ-a)h_?$k0LivE(kHsH&E{61TrN{TL zbR{pdX{Nc=#i>^<*8t za|#Qce~^a-z$#WiY))i5H8?h>-9zjM1g%Uun605A5f*vmb1)aJuCOCADR+`zqMaLb zzV8WN`2)?xm01|4rDL$TH?Z&lz`lV0qnmbNkd1-*u&u~=$Z0y{m!|`Yi1p-K-c^1c zd=HICPfI)7n?633R5(c64C~UlzMw*7$X*<(%b|DNDjrbW3_U;CKgaO#LAyH4Asz>N z88xUjEb3ek6}sW;0bY=V?9R>2-A)b~Tg1=fCE>cb5D5kf%Dp`J_BL{^-V@*15eY}X zP=o*xHDPQ*#j0@qH_NjTfW?5l;oKYu1Rqu76?=W#UI}2Y@ve@gmG1aS#l7Xl3$4ZL zMkH<&*0z&Q64?=bOkdG}{^=yQJI%+302CVCe?war7UV-0&eA>2KgzTN&BM{B&tKwDpuCq zmw7GA{+`%lMGL7QukFrD$Wi&C_dwkw_z;W2ZpA7#crLazqna>%p9)K~=Y8i-sZjr% zijO=#UZ-_?BROpAVFf9|U5bGMSaue0*Tc5US?ddWPuysC^uwo2ls6+gzRCTP3OvA} zf`;L6^iSx))sD#m=3o}pe7*oABixD8ywAS>BpglBhEIoVZ(>?6m%XHFm*)fLFS$J% z-hl0tRYQIPZH`>nMFajf(nczHbTrTVa3~*%9d!bn2;#kUxJ*BPHE*JD(XohrBNT?n z!jHw60NHD_LJ$+NNRk*fSiF z_uy-uV&KN!&JOwwp(m%uI*GlRP^Hs~%%00!C zXe7iAXu&$W4Um^H5cY!2!CdSTX7LFe-?xCp#O1*~g4PQE?iI4)hVJEEk8#VN76S?U zfnfXHJGA#HVnWaMf)9?{wuKh1H&WM)AdOHc)Wp(z|C9>8JU1-{KlD`$+!>R{oU^nw z_*^Z(!uKcAv4|JRtdJ!l_(4VU0slr#)339tcu3diV@w7vy3pcJ3t|J>`S1ixAZ00d^-H9@P z4_SMP%2|ZG_CNvYa;{eqT~$<6*qE6GFQukKPWfz{L&z{^2GF~*5b*X&w*dzR zhk-(ll}#)~6yd^?C>v8CeKdJt_UrLGuvSggt5QadK z$1byCJL<8gvPlo*v$f6K3+P)9ixy8;ET{xo=9)cGfZK{W4Yr;6Lk>4RFGst(?RTMX z|9O`-ota$#xe%-@S2k4t^;DjPlurYtH42W;rEgj4Ry@rEUtJun1}+3|#<%TupDzS1 zhPl~OgW3ZmIG&H>9?aHnPFiE*718$iWpACJmC@YGzw)8yxCzf|bd|kHwtP75iizba z&IG)8w3*TNfYwho{QeuKRsx}2#Pf0?5H5y@UV5D z3MMKl!zJ-WLg3||Ud82nps*}rd-HGr;=$q0Tk!Iz5DY-1#N~>f1KlfXF!s}y2$o9-`Mf1^-&h;l&3{@UxPqB4hXpxg6 zo?M;E&b|AjB__SeK(_3=8R-EZuQZIDPzS83<`p3#MH8@a28T@kBj-z(Q^9Fn?7* zCx1(nb@0Qz5?IU5TgBtgFz}fGavBbSz$Sge7fN?VJwmSP!;b5(uRL*Ad99cD>EI&M z$d1f77KJbXGX*a$gky2pQ?4@8(>3%-4`k6$7!J!Vf7B0nTzP%+mO&nREWK^5NGSA@ z52!zHiB{Lu9VbQ?>J{-8KsZdI&OJl1tm;OF2tMefCH7;i;vSRH=~$_OC!}|ugsMq5 zG-x;8vvnno52zckwyPahd_5jm!)Az>B7D@E4WtyC-t6~-RSOa07V_M0Dx-Y@Q1qmZrUdJ z;wkIJ>MR((t}o>1SbcrS#4?RKhXXDZhQ7zD5O}Z$p!CDc-HOn~<^|uwp#metrqe5| zP3Wl*?hgz<*u{F(2cRCNwt(~b1^1YA7DYjh^Z8KE*3O^UMqIc}Gps>R)lh=jI^dEB zyrhnkoD3g_wO$$7w5-O5wsMrc5Ny0o^t@OlBB7Mqek>_}St>by5ydUHYF6K}i^3n2 z1JN8A-y7$z5Og?1h0TKOI--juaYu_Sr!XoO>$#|Xeqdrxrg-{6hj|LJc0Emw3_7dH z#ok6TmEHau(+b85c!rF|Djs$emsENxa$nW~IUz%!b=e;VzuIw&qs!zN**!IKkYc98 zVi$u}SHTBP5Znu!D|D{{?rl!GT}H-jsA6NxHGnl7)=%)*csTZ?MBZMQ;VVGQm>7v! zSXg9bWrYsb^M9hq}U^6ZlF|NRWSTzWMyuBwpFi<=EE= z)qL8mcmyP|hQ(dT2CE|01lX#?Z2rY$PT>4F>YOA}8Lk-EOMfu66adispw?U#`H)LD z@Ge}4Ur^z!r}y770pnpPtnqBBC_Pus8%+g1f0B1~;grOJpkZ{{2U@NspWcJtbu!>qUkDlqZ|e(TrdyzitHKr7XVy9~tDNrqbT=KGnJ**4*Id9UR;ZE0qqvI>9Vr4yeMH!db7{F$x#B^Bn2$kP246 zcSF0Us_XUO)$v7qoWzXy>TPd=;ZeRq+8 zv*9PT;DZ^Mofoi{+K_>rzkgqXmVy-kJw!Yb{==X|Pw!KGnDjfgt80SfdP5!ZxA~^z z@ zmVIv$7(K1-2|tc06VNQ0Rqd3b2DS&n*;W!Ft3Pseu%UpQ@b(+Ci=gWLEUwZ9@m%`8 z=G%mCl^Rkl8__CyJRBUj{b-mc<_&pILwK+D(fCh?JVpFqrz9obe=MwfCpB!!O*mDF zZBCk+il6W;2y}?e^h`-HaOIpZEFEKq)8=m8yL*o&?u%Fn5_f{l%xkm3_N^jo-RFw~ zTp!#h?7jPpR^W7n*C$|m_-Xk>B|m=avknNPHk!io?3r58nCr)^&juSG9C|0T1V+s# zp^M*8twda6I zQ)`&UN;8M*=DWvr1|YAEjK8S}Me9c9;=!+0B_6Hjb^6M=E3s_Ur2Lo*tS((7`#T53 z&5O^6 z6dy3BQ?dQ-nGnuORLH}hY}K>RTE2uyeSXXc3R3o>rNh`VCVa9^)}fvo|2Zzc zbvjLtmJ;lBPT()}MpU)Fd}LAQ>dlfYDR!*7-NeUF7atZNB}fALX`(aX@}vZr9oUG5 zwQ=1dCVcA^|4pghX|lpmz}&UYJZh-1?5{zIXjxjr>>GN(hl{8Q;+5DyAg>!|Pi$Zz z&ey~iFJJcE>saSyka^{p`1^Ocg@jNzN(2&;8Y!ZTk-?z7JH`z#pDIT`5>ka?v z=z11jhc*bteDzKaJeVo`wzM+F&220tPX?OvNbWFoHEQFKlyuw+i|oHRzREKOahdMhPuc+1E@nYw3N-L9mJjZS|3`eBpe&>eW-b z{rM&(!`0B&*usJWp16&McX^NnVb2b?M+V|n1qFW!Oq+jM70Zc9i;8MO$8WwPNJrE; z?(cM?1oU|lLRw=sFZ?z(aQk*O1S1YA9{`nw!@u5`DzY)q1h4P8KaHB;>gw_St^*)kfP{NMe*~syT4#nPyMq_kNwq zvIX0r=;>1I4x&!NB0<@cl$bC(hx}$F`m)5u@ieVYl z&D7EDzespP$o`HIG|l9P;$7gV<(_v(MlZK~XRQ30#_mfyCUn?(P3^lT7MsPVt+HmF zbToUK3V74D>6GtPPQK;`9N&PAknXJ#@PKnBMQEU>=SW#FqIM!bk@QO_?n0hdrYRU< z{OC9y43jK1e$#%@w+J~-VPX%z^l4$SX{NN&a;$+?9}s^C2e(qYW-KBOhQw8toadwBAYB^&vy<(-Nl%_ayCT&5e7`pkpVk1PYd-3BaESxrL-RP zNXPgvx8=Ar0rNiu`D^>PZru{FsJ%X^(Xj^mr%f~82GZ>BqB_lcYI^0yIvLk<7gfny zellhX@m16MZY7VnCm9v(YRl~UcgCSYNT#qw>frjJe$DcnnL6M4$D@y&au5y-nx%#k zZZqN>93!hoWft&*ZhA+_ABzzVW`l$5!~}5P_SQ%z1-y!%q2Ui=rYZdtgPFQFHgN06 zyT=vpSGkiAti;Nu=c}+6Y2d^CKpUb6YtQh5%f~)<)m;8MJ_LDLYHw=GZ?q{02?|oO z6ElF`3e2RXq*QyJ+n@x&n9s;GLM0!4pWWICIV6HGjVG>rbOscml0VgEFAEZPnG=_h z(WH*!-p$b3sI8r#QJdZmC^set>FMdYl#jgY_@-Y<41zC0$DJ+2Jzb*{p8r2BK&gJI zkFRemWh3fHoi#ZrDJ@GzhF3;fx>4J8KDIa6Un<+RE@jmR$Q|hG1bp|@D-l7DO<4hfYakl?Uw4yqT#j&(RM(Lx_EdQ3J}dBvaHO zt@f6$^!$hZTU3hZ_Y1athykmsg%#sBGk)6>t$;Jroc;~<6sk3S^#eLoNlM(Q$Z(e^ zUa6sVZiHT$Mwg;Xl>fyj1!zcopqjr+6cj-%no*F>Z|z*~OBQ@23aaV8#?E+7VlU)X zet^5437FU0IftBAP+49U%ABCz4&uNLdGQF;wqYfM*9d^O1X*5^3!E?P*>ra zS%rI^d`>xOa@M1M9Oq~z!8u^ce`gnB?tAh)M!%H8#gs1oP4^~iIet6#-Mj0li;FZD z7h|`zX|a+?aO=+I>F!Iq&z3i0>^L|$X8gCNn%*=|yqT@@m~0Ekk!e|?gf(=(vN-Ec z$(gMmp_m0Cd82%U5Z8WIZZT0|oj+>!IMdN|!gi>BcdE4EN8ve!(vICnss1NTWUuuohk+!v~i+%4<&;cukVQ%iMuTrwSb zv>c2`2Rt5*!6qY$U5NXZy{@t6`G@J^%;^vD!SVqbK8^F29)VzM>ohq6YI|l;?7C(ed^bCaOOGZvH#t6$Niv{i*!hc26>~&(!H?#v zIe(qSx9BygX8FL8Q3F;65&gnp+l2cu-ZDAw*mP;4saCq6s zE#9u8N_;a>dtYmm!JhcJao8gT?8}6KN4=Kk7_0(3*^a^N4sf39ufwaaj|Jnkov^rG zR%EtxS9KXroK}{24(6%_HBrGT^ZK=(p7(Pp=#yv0usN1IYgQ4+!Mlr#pvxg;g)N`P z*Rw0Dt9ikWnspa6pl>{J#oJy&!ZCIXG5Ic;#XO*IE;3;xWP07DTufXVcVB!w|5Se{ z2OD?I3t1_hnrc{qesEm-Y7E?Q?#aohHO$JRKto3-sjB;VO5gEyMR1_8EZP$H|9RfX?zM1L6R_vyPNCkQXi6dbdcjyE)+mY z7Ug=;Nh-={m9Ob>oErHel`VJd-Rn1r-a8tUbp5lN=Ewx3ac<8w`WE&i$b8Ny8vn8O{b)6JYY_%#BhAO&Vbe&N z0AmvOl*BjdB-cK?eaBWdTj|kRNY&q5gp#JYcaI1ZAUj#+-y9){FXb-z`&Ho~1BE`# z`e_I~9Db1)4MT7xgm{S~k14v`XMg!0R)*d;UaSP?2$_Txjc)VAUF{CpjOK+3hT~D7 z!!rvMRhuU%@|ZW(_3C&uP0%Xaym@#MYHU`1CxvrZ`~fL(^`OHoIh!rsu%IYgl_)XRbARlG_@3u)RqB@uz)r02F@ph?;_j=Fg`> zb@!=CW$V>yKa2J8^3g+VH>&9S7@2^*>SzKF860~yYXUVX$DZ-kNHgm74X%Uh9j(mG z-SnvC6;RhVjulO-NkPvjSmk|t@P0B6w8StY=L_LF$$eX{m%+Iobdqx<{27tQnnj`` zjtNN>rMi`Gzrlvg81B>h0{X8F0IP|Vk_oH6nQdWk2oG6VX8LnJY~-+ddh^iivN<(;jn)!WaWdT1Yvbfa<+O}66O zpl{!nuKR}X%>?cw@SL1?C@yB>^1K4 zl2;o%dJ#>e7-QF2U&C)P{PvHdDrx_L8iPH*U7R3aLpn^wp>N$jf$OnpF$Y=nN_FHo z8t4g|cmxg7`CK*+ElpE6`P1@#8>-QgqQ?b7YY8IQ4mWF#O*ckfeHn+Eyl_kHIhOmv zf5t6TUmv*05*%Bsl|=wj8*au;(dolLwi{&`--Nuav6qjF;zS zn#XQl5@1OH-a@KHhBRN2PSEsZ@ZC__-@j%4yOSCzU-BS&z@r39_2r5sC>_*LTOp^$ zle?}U%kA)P*F=S|HRSR`^#rijSY`hCuAfYrU9bWvC`UHXW2V*xKqv+!THkrJ5Oi-o ze>PCnqv1M281cP6B?F~Fjx=7s9;+=KC02e8fU9Ev*u_9B0rg2p>oRs?ndh6cW|85J zU*@~(Fi;6ws7d~cfny+zuz0y4?@tNSG<Hn%}%V!G=4Jjpsz27wViUq_H7g1h=>5Uvc9%K zLYUNi72rAd<3?9C7!G@xtpLy^Y;(kd$MM}Hm*)Nk&lFB7wPC(8IjrG_;Im6+Ghm-A z=o61=?iXW>TE}SuyOOSQXTu-zTJTlFWiS}yS;`FwIxl5zKl{V0}7X#lAMTqJ>uQm67?qUQ@1w*Ee6$n8?u45+XDJ{LRvwaH! zr4oT8KDgT?Dw5=O%!`VlC7_@~DPmTJtUyE1P zK~cc@C-aMb5kF+e3&lR&#mAgA5W|%ql9c#C>xZ=_KBZ6!@MJOZh)0~&52HlIkc3J+ z&$Bu0Kwo7XdWgEz0o7z?u}kKsJi~P!J)f~lK6kE!s`*?KG&4+`;Wjy4Tbu3j?*425 zi>yajvWNVdl%@T%M4bEd$krB5k;-E`jUs*jy&;k7O9p#tHRU9GBaXazxsQs}q=2?0 zM8)O{uSGj5Y_*($?*(g_Du3{jr#B&nhKmG1+o5VKf z{_s2jDUJGtT($8D7mn35@We$#6#S^kaH4u}6@SZuL`g7B<;Rc_X~ff?_f>e-61i5r z*0jSyc2<)WI)wREmiYPq0`7F&!m07$$z2$4oMMj@HO&F***Ehd!YH6~f|#Fw9%p>0 zF>(edG*ELswl>fF{KR{vUW@jh*|(Fj!;sA`$3PD5>SgqyHBAF3cyR<{(1L&JfG_PA z1U>j&<+H-0kp10BShMGlZDw(^|L#Jex=wHfkJhLYGB*Rgr`igH1rM1^T^fEM^9*h# zmY0Ke?~1v-x(Y3t&~{*WM$;|vW@a!9JTZTM0{V|IV4HInT>br8d>c1)Nzx^npAqTs zjYqRwuL5ru*&^Sgf)pY^0QCDQUV zd81UU#K2&;4>_>Pa^Gs&<9*ZLmrcq?B%j9(ATqkf?l{Fi>t!KhVO0z1YY z8?3Ib5IkMzZpoV{rzQSm=Ug+r=e6dLgQ%W%Z+Pw6yDjDvrjYlnP&q=v-Ln4GdNo3FOXyFazKjjK*cC><~l?Ua*Y+wo?;>a*(+~a>a z!-Mjo+ILah+<#n+jm+qgXR7qw410C9YjQS`h+9z>6y9(SY7dS@aJ?}NG0qXxB+5Jbex+y%D>AqbFv!9gugo8%8%?dE;oI62sUft<>yz`W#-%kWCf=o z`=ok4Klp>+cOEO7d5=1aKl!}VFi#NWtoMai;^faqPUb`ULGV!>iF%S~)?bLzHTL8? zw^OT>??&1ERn`ZRSNY54IpfY_1Q9%%0kNnO)Wo&F?cySd7#+Mu+_3LpzBw+knJDQO zSDM}m&>g+?5^KLOo^u!JA)Wuu?S;10VVl!`PXdr(Y}7ceuLHxr8?E|qaF?}w=#5C_ z9Bs+Vj8ZB^@q@q9Vhr~2-6^{A1or%K1)O%7l#uABLSRqt!e@z37_|&vk0FFwCET~X zK)TQ;<)c8Q{9(v@elUL=*n@*ss~1UxSD{Cj&y$^JzL)aE**{a9YcV6QZ+`FiHRd)G z)9ssa1wKALfD=-A-FM0ZXaL4rPdGJxTGTH%<&{Z!qhAmF{!O_r`v?5Ye-# z$$xvWI)ROpDlxdh0bv{+t(~KtZr+>(AnESnbv}jkbDYokpAR~U4>expj5W>v+WXV? zF;S$#xI9GDC$209TeV3Q!KS810aXmYGR%kSmKz_-!M!@NkS{a;R_~1zy->hhKMnpg z0L=G`>s$pi^b;9B*p!>DpEZz^lLLTg#c#vPXg22IVZ~rhQ*yX7v+YMtjlyAy`*Pxv zl9F(?MWeNwpyVua;*)2QNp{Y94Sm!5r#s`D!Ql2*qB`^a=^CfoH=mXyL`%?t^BNgL*)expoZLiAECxJr`c!0NVxn+MemETTli83`(haO zDS}SGEDeANC8JMVr${yF2JaCs*Er;zHka50ZSg>#xQ?dXW(`L#1JoQ(>K{@!)lF@y zHGcFCFuQ2;oh#IF_BT$>YW4}G;b$UsW?_^(=taTf;}eM@HU=!%qJ-1(CiTF$ZWHV9 z?Y|kTys4!-1rnYM;yWF~pl^n}&4IhaMZP96cEoQNs~vos1NLD*Q~BwRJuM(+XO|`C zR7@4)t_0s)J{MP;d|@_JV4%R&9+WsB6hyNMMPeF{ZAvZbJ_*{8h7<>dDMq)tG|fg*U$#&wR*}hgGi0}Fm9o{w*bn_ zf6lOu$?EDUDJcI?fcn>s)aid8BJQmFrvF%+5z&shYHPmO58uWx#2E3=h--;a6zcM5 z=P9&q<<#fm7Y$?VzG$ZEm%g5Uwf*~5RqNT+-oK>)iZ#NWk}s#&C8Wcc$BbB=>qs{S)}e5d)}p6u+=WO>|HOd=B~!j2)XVC}1JmV{@f zc<{>PVp*-ZJ&2%dh)m6UW9TYU^pU|>LWTj{8k@@Vfh;=3jv-Z(OJgL3DxDweT#DQ@ zC>_&uI3oK%!6d5FZ%kuB#{ODD9hv>)&B1je=Db9V!r&Ecm+;yK$Q0||kiPv!{>nw2vCs*%>sS-_b z-JADg#ol$WbqVt$M#KeJ&C89i=7N#hc~`4CifilZb_r%_K-oQuv1gEY9qertmt|h6 z&zmvwM&IYAk!I0|tu9eJzykq8RF&t{QRMW3hsxIF#%^P-iO)t$pO)M>rc+flC3^d< z+kLLaY4fj{7V}xv{tg^?+D)V0Yhhwp~u%|&7k+xmNHR$r~Ddv=y$)W=&+VS8~5d)k|Xy9K&w|N1$_N<+4;b$mCSb^0M^B)jPMB6BS=R|J`u@c~ZUpj*W(HBVF1w$X{xZlA2VJwE$_;&X+Mc0onKTAhTz$ZtcKJ5SIvLL0%n*uw< z6BE0)O9rzSsvVwQHr@M2+tEdc=+cB2BEEPS?gb=N=@%uue=l`12~IOIu0_1TEwjNb zqh>W7i1v5KE&ll0-{2=s7thgW67p4B)yG@SSoWW}MF5S&f3P;);<0UXI|C*RoQKpH zHjlJ6kvT9bA|_O>pS{t}M{~0k7lQ@db&c2OMFGjjKd;53u2U+Q6TCmoB1o)2U;1gh zZ*v(s8-1D;AY(DkpLBWRF!n>VLB1_w@kWHdOuT++1Fmq9T1s%UP5E31yeXf%DOMwD zQUB&qyl(ZEGepmu)7|mH$05rWo-Gni0rwq-)_sn<88iO868VG?2GaYSpzzJ8A58wN zY2h#rOP7C0@#oUSEmKL}o5uII$q1Uz@eImGKdGPRDkTsg1R_3K+N*Mq+^L9_Rcay} ziMlE zwV@MM9%{$41l{Cv(L4#>VPSP5g}vd|{dcAF-O{ZAbqA-$D~3m6d^KU(k;)`qm#35e zjgM=TNkN#{|8SnJh#mJ6GiEIQsmq@H7Va7!q%=L8)8dMNNE?HsR^T~qj_j3Y0pd^b4AnO z?-?sJ-n#P-)+q7BYZmnZ^U0;eOXl9kshT&S?-LW<#wzuEe5!%`$wRYQgG5>g*MDQf z3}&1?2d*!Q?34Ouh8GO+CJON?)(iCZpQPl0O6%bfK{CO0%6no{wQEGnV%nYMeG$l< zsmdd3%O2(3hb6nC$PdgC-kN zQoDqBJOKrRT@(RgdCq~mjLA;uKkG$79+0w650KgOYkV!B=CEh{pHZVA|iPfCixM@>kl65ZRH8ilWBh8S0WWA`#?s%=^E z`_-qPoZ7}3G(nGRqyJs=f9L-1&*9?A%nknFcQ#cpngY<8bR_jgd~}=xzjO;N$QIz0 zg#~W~_}?=7rn2ltop$ktfbB8=7t9l;muz!B9-e{Ssb!-oY?d)EK9TkFss7(Jg+@x* z-655XccZWDtU$aHDq9iJ`QS$zw`x7HyfY%MY}h3C(V=Rk`e`Oz8Z{dQtttYjUh5rf zy6yVkl-t?9dDKfsK{)Q-)QgHB1`~@1lRo_a7hIpSo2x>~1vc#-G>-6Uh~Yv-bowr# zJ865+6{a}dy~yb0l#Lq^PgCfIt4O2bI@ky!ZW@`q`}B;ASe#>oX!)ly11CiaaTs-T z>qQGOfgcg!qXjbI9yE$nh4v&&BLx&ufYbQt(ayRQtPCABG%d`EZ71(wgH8PKIPyk3 z)JU0J9d#b3&6U#l0*E`z3tyR?8MB-Nzgc^!rra_upWnCcX!@+&c>X&YR-(9=;MTEv z#!JHwZRp4;ks}nk2m=>smNv{)3HJz=yeJ$soG5}#Y(ywVi2NA)1FiY`&oWW6DQ+yE z4bdkN)CHQ)D7pCV#FV@OP2+iK3gl~F=F9E0=kx4y$=a)a=ObK3+mimw&%CK-|1ro5 zQ$%Oe3ZcFG8jH=SYQ~8twLPaNn_1oh4OR;h4`$akt^Uen1sgo!PePQM)o5$( zn=_ku?e$fm8R;lPlgSxQwL zI=e?_X!lA60$#E~6DnSY{4_Y~ie)C7WtI}i8*aIA8hX=A1-$7!Xqv&*U z5xajjcgUGHX(C&9c3r>tRn$K78T6joQNVq(C#Id0&4}Hjw|noGS7v^prfSaT8Oxv1 z6j{6`>QS&+I>4P%G9B6WR^;RaY?e!VL`yN>0G{%?FM9n}xhqD7IoLrzTmf?W`*-s} zW4+$zVnLG*e-?z*+GD?lHKW&mSS967Cst2ofLX>&&AF9%j&YNVJbNGgX*B`;?c(oEmqZ4|y(y(*|rq>&$4>;>YEj`>+pLm>=jGz5~R5Y#QUQ`JUvH7l*X@Jvj+ zt2#o+-gTTSUBrq;Em*>VYn#D73};rGKrLp%NPi9fLoEu|pdB0+9h z%ynbgXKrmC1}o=gp12eqjTBYA_YP*6#a+He^Nh4JJ>Hi@v6SGoe(u-XHGjPk->n5C zzh}{&6NAFE6a`Z_KNJ||-|oI?O97%lh*B6RyD}Kn#4TJifx9i_sl-d@VDp~y( zmzqajTJ6gYOacr;iUmXINTVQx--+&#N=7qnyfvEkl3ug+*GM8eZs)zn0_Ds!E=>dq zF`4jlep4gcBTae{;^$)loryOIQo{5FiCmxj{^LDyU@F{mw}&P=H&d?5EJ%+9Pt!PO z)pYs+W^6?rbx81OaZ*T8=1t)k?Zj%}a6x z9??CmG=0zxVtA3V=Ckfr+oYm?$E55HtuGgseS)-L?5a<=HLDYHeES6K8L^69JG)hc zmP2|=)2Qv{YDQ=8)XI|YM~6fLQBA8RvP3nt-x$)`VJGDGi*#zSOA=zUAv;1*x0v9m8PKwfy5sy;t$jh2yRw&wRQGB37l65VwSSSC9HFoNqcJv#*X) z>dPm->e7bgMszsW&XSYmROr$*a*6Z=40_c2ifg4$8uR{TI>ZnFk_Ag;T%emVi(&we zCF^en%=I86Ad%76r&gl{u)n28yVO`d5m*^I?roX02S`l~?`KI1E&{sJ-BSgfb{8Rj z`@1U7OC1-jFRqw;ZO{$!)t`(`nmE#DJ&;Cj;xuZ}SFXVi+08y<8O!HV8BJd_rfB_xfmOF8|y5@ech zYQkRGa=mmq`)T6&x84QrVQxfyT--dy zg!MnJW0ZU$>%I0>vz!dAHegXKLgCAf0mLmS5N9dD5{;S(>`jU>SN{&%r7d8l1-W|L zPZJGl6+JIMRRr4zu;=To7SpJ0TJ~9=9renwepwy%vK*Ahl9bfFK~}yLrk-l>m_I95 zv?vz|`xr<|D~Gv$K^ISJzjuxiwoNm-Zt})@W=T{f?DT7lu0oASK(RR%=z|p%r~Kj9 zq-F<8%#kq(&U3Ym`lV%h50AP{=%pScb$hl&5(qC{Gh>d0S{#Klh^?nu-8KW=+P=iX zz&30QYf!=a_RNPjO61N}4x-610jS2nLqKAAm*VEx!8CS%ht|>8ZwRRqd=TA|oo$4G zXUo|C;*2}CfdsE@9eI!c#8(1p^ZUKP@tx6o$H9%kIn4o1W)thYVZjr%Go`n0-p+X? znt=r`{u0Q7OkV)QkMQZ3`NPp|IH$vUG=`yAz%l`;sY{C9`PPt2)AO^wt^N8W)K5JV}p* z@1d|}@D*;BBi*eJTci&+uX=TeMOya_;tsL(YxndFw>-ur$|tSD>)o${dp%`qW$N5V zPW@^Y0;!y5+X_`mse^FwNQKltmk24T-quKxCvO&B^^BF$#ouTD?R}Z7@IX#YdQNJgNM%&p^KGw2-o~%th3~wmI`m3nCpGX9&Cwa4X$?dAwyIK$ez#a z-DkIo*$hsHE`93d9)Dh@p;y~wXM;JNR8M{_?lJQHrA0Z;$HCaKc=iqJ>0x1={%$43 z?ok6|z5(3(ON-r(hneEy)vwjdXW**vbaElV@8TQPdC`DUmsKgtW%*G&*!0u`X50g7k+nm98E(r)38)buM zPz_zVX<90$_ioz2F2vHHc;G=&i&HUHh=CM*G+mOyW;DDTM>bzR^J{0Mwd5J}MuJX` zT;uB_mH2Msg}yggl5b|KfoRje56GK9G}NbYUSi5}QUppj^cXz!gp1t>-g0XEAJX13Dyr{&A07l$5D=sr>F!Q} zp}RYzyE{cd8YBd11?lb>U{JanB!-mkZsvdV^Zl*$ynoIM7Bg$kIeYK3&z;wO-6lab zhR*CBM+>kG&zr!IAAefWiFlTq?q8>ssa`#>Fb|Up23%lc)73Hi9~shiv1hk>1_N(Q z(Rm*As@;tJ#lcjQWf?F2xf>~lOjoZ`p)g<9CgW#P^_*;u`y7POhal(CaEAtIA-{uW z{}(VoF$#vR0VQT}F$rU1V|DJxRxvYnas8s+qq{C(-TW;UKOjh_8PC)|(1MALFSb83 zN5p5pettK!2B`IfVnMEWu5N5tZqumVlG!Z&m zi@Ev6)I$C7)HPW=lM5sUs4od{d=gSo%*fNW2eRFE^$Yhh@pg0HV~YB_TwAnw93few=Ll&Ux5(%Da=k^&)!EwRQwDqvj~Wg5&!c*H5@hzYy0{P zgllv{ZVL-~S~Z`cm^>Tq3~W1UA~b1cIZO3y3~LI^o$(T`4-%M2a!DUQHd*IFxQUdu z((6zyU2P7B>ZQNH9G3F2kBNB=^JfhEN3VQ@v2%O`IT>4H=Ms>D?7fPj=#Wp{?0bMT2R?763il(AfjRojU^1S1-I{bdQ z*BKu!mnAHTNW8Aeqt{BE+hlA`^48m=%2!C5{-%};JoQb0(hBF#T!{fZDr&4b8ubr` zs#)Fd{mQ4nyQ_SgJ&7w{wUp-=WPU5-iI#1XAPUwFeFsC5Ufn+hgMQi6a^l}@ZbHqO z@$8MA;^+1qXIe+Fv5V#p@i+0^Ea$pkwlcP1Kfk3+o+mM3S?keR0rZbpFzYMxrN+P_ zI$CAG-ldT{^Lx<9^{-KABFm%55=tB39ELr<5azdf)`u&bhx778=Xc`Yn9E7-rgUX& zP&Or3^QBfd+JU23euSlxV?c%@TBN(>|R3 z^T&@)#R`p#cVO4!V4-EB(*I6;z@tuDDI;4f?Gn0+y=hnla69XAmFQnmv-Yvd6jJ`{WX16t=2A5c$|TUowRJ+UyuM8xOlP}jq3 z^e{R~nu)L)GO+>iI=)?AJV#iqDJtSbt23J~f*$`y1MwuQ16n_zkJae&YLDO90V4QTn(HTa;3(@9B29y-ZUQgB!XeGL2H= zMkppx%K>Wjbe=Bw;fWXosEK{RJj1Xi$+#b62HC(0r@FAooM-bk;~k;T=*w(?OxnhJ zSs=g_bANqs{^G&7D&Jsindgl?ZPE0|(7*<=_kDc!tL#x2^q6~xij^>dBb8e27f2m` z|GZ>o@6doR_-@S~WExZX^ykk2-YnyyfXmM3L47LC7{p!ww2o^$08~Hg_X}HvrfB-v zhbe$iCyUp0IrBK`P0;&ZoZIG0BJR$lFieYwz-mLry5N=NKPmbNqPNrQQs+3a9qw~v zKn2m`?!7Vz+~5lDCjlaTWkn{!J3vz5ySpz3+OM^gYk*EVi%$;)y^^d$!l{~+c3FTW zP~{ZBQAnbXBo97$T8l*ljn}Eb-&09@?JQlsyCa9)FQuhqxt)wXIi{hfu{YnDxx?0W9?kBsRvMqO3vGuKgOs*x)x?zdQQN5cE~pQTtHPGn3ce{h&Y5B{M(Y97ldL zujQ57*(j(pjE?sFCxs-_px2v{8};5dmF07!znh@ic2pJGO@aHVY@!CJplh)c%ppcf zDsuoGZB9M3Q`(Ge7R!iGHZ8(C3yX)8Z7WTcVl}FoE1)94Zw1!mmEF4Qf6Z*n z{TehZz4&9haK?VT+RHB6T!st4yatB@Zp}@^y8w=tVZ>u`IMst65L5}36oT@SuultM zgQFy9Y@xA(C~#RPy}mC5;xfIBX^q6@eBKVkY5ZGey zy;4yFz1Cp942GXDSsl$Y(6H4aZYmlmGVjcdwcPmj%LL{?wW9K9%L*@C(4o8k4xRW2 z)=sKM&$s<+a15$if+HB(>*W1qG{%k9;&>(5iC0F5#J4Y=M7bopbvr@K=Ep4YCBSy{ z2ldQ+V;$7#z^gS;jguEoHhSZ^@tRg6MZVxqXe$f!>0z8Ip|HWW>7kCsaltbxE%AM`G+oBGpxywSjU(@0ajY>JmLcx`vP(L84}?OvDB z4P`phWh>?I&i6n$Wr6k!#1Q&S7EOq%JrH;p`C$=;DW%pW9gBeUk)jzU6~&WmKPLxk za4gcUYM)NSJo6QXI_MUeUiyWOZePONf{Xwy1DGd((e0l8WO&~8_tn0k*TwMY_Iw-gYvg1VmvTGUgzv*&%?IT=uh*C8rCW1h zkS1*cq)>}m%llU(Vt(Vh9`#O(qJj%v>o+yHxxq*vD-CWb4a-=~5-lLy=tY;3Q0sY4 zOH`tSrxEnz8_`9Ejcp%Sog?C2Zl#Vo#E8e1LD!_kP7ts*znyPJDHZYpv#RZ{TY%Y* z17yZ}-4T(>#|!kEh}$slY^H1a%FAv%}*q?b*>$Q9l0ROLBSD zDfFvGAH0^eLJ6YpxtB4F7d9^BJc?dm78?`YJYi05KT+DSXoN(-ZW^bL z*s~!Q3wjnZjw7s}L)FV(ABJ3XzJAWu;Z)b-(?%ACnM&OteR$~yTD_T|5}4nPh$l$= zni2`r;C$Dx+R_7!6JE#zxeCn&d3)lFPoW&mG1052??Adq!cKf6IR4~F&k*$1Cim)f zj5(kEIll!`C@z|1JX_lU>fsBjB|R>6xhmtJijBkvBymhBthY$tR(;73PJU99srExp zKGM_Upn_cZOC5BPDt}3UJ|E8QHthOec^-Q<+MeSLi5W}+uRw-X(4%j@wmGXaBIql# zG+@>v`2x{FWDr^b`kA=e8-#cHHHM8m)zrRS`kVx4#+fQF0QghE!oxmWeqX%(Y@U?3 zlek;O0%0&Ysuntky*JG^PQH~8q)SB!pv`Y6l)|qfOeu;@tMof1UY@zRO*3i~lXxc% z;Q_TF`q|3yP*xdO(&emb^?9$7K04v)2mK0^=MR7&qW@&s6`twh;nz+PY3sPCR&4PC zNjX9?iCR@Rd_qk@azq_vQZB`A7Pf zps$v=FW=to?D~5(9sh38T5JT~hJtB%PyCjqht_4Yn)$;tB<2QbstB&MMe%%I%bXD; zP^#7^ea`y_--=oF4lLHpYddjJP;jv``%hEVBS(Ev6{#R`yb zcnqGeeww=^jgr+8okvawIot_cK#JGrGQ5tlgc96RTu`(}#0Zt}D}% z7mV*}+DDs*AtQ=|)y`U@{X*4NZ&eK#a8MV(kQl?-$biki@itBAos5c;w3K%@_%4#d z)fOgYwK`D&mlUzCKJxu2WhwGn>$bT1ew&lWo7tl3005H8%_cfY1?ktwb2ybm#an>= zbZU&aPuYjL#%hGq=~W)Ztn=?Sy%=r4i8cAkfe2J{k3sqAzDvhV(xf~`1g+G#S1puy zHaWxEEKW1ewtC1})5J)G{Q5`dlkI2r7TWPC_`NRrfpCGQeE!(R=B?@XDF&g9FpZF^ zumB!~g5}M3$O+#GK$WEyu{Fv?I`p`C6zZsh8#OvAJBomR7glkmy;*leL# i0KA* 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 CT + + + + +Owyx - Settings + + + + + + + + + +

+ +
+ +
+
+owyx +/ +Settings +
+
+ + +
+
+ +
+ +
+

Launcher Settings

+ + + + + +
+ +
+
+ +
+
+

Java Installations

+

Manage the Java Runtime Environments used to launch your instances.

+
+ +
+ +
+ +
+
Path
+
Version
+
Status
+
+ + +
+
+
+
+folder +
+C:\Program Files\Java\jdk-17\bin\javaw.exe +
+
+ Java 17.0.8 +
+
+
+check_circle +
+
+
+ +
+ +
+
+
+
+folder +
+C:\Program Files\Java\jre1.8.0_361\bin\javaw.exe +
+
+ Java 1.8.0 +
+
+
+check_circle +
+
+
+ +
+
+ +
+ +
+
+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/launcher_settings_java_installations/screen.png b/legacy/Launcher/stitch_owyx_launcher/launcher_settings_java_installations/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8fc62e8f19773bb96b917118443a04009cec6c GIT binary patch literal 129772 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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 D#ixco literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/code.html b/legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/code.html new file mode 100644 index 00000000000..b129b5a7ec4 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/code.html @@ -0,0 +1,192 @@ + + + + + +Owyx - Library + + + + + + + + + + + + + + + + +
+
+ owyx +
+
+
+System Stable +
+
+ +
+ +
+ +
+ +
+
+inbox +
+ +

+ No instances found +

+

+ You haven't created or imported any Minecraft instances yet. +

+ + +
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/screen.png b/legacy/Launcher/stitch_owyx_launcher/library_empty_state_official/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..918bc5e2be4e575ca10e9d40239aa3addd04f369 GIT binary patch literal 170444 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

ctA)1=sFj$gBXxz~V)sWjT#OHHK6CC^G{ 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 jywD<$`v3OJ(hFjR-qLU2VhJ + + + + +Owyx - Library + + + + + + + + + + + + + + + +

+ +
+
+ owyx +
+
+ +
+
+
+ Ready +
+
+
+ +
+ +
+
+

Library

+ +
+ + + + +
+
+ + +
+ +
+ +
+ +
+ +
+ +
+

Vanilla 1.21.1

+
+Vanilla +1.21.1 + +Played 2h ago +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+

Fabric SMP

+
+Fabric +1.20.4 + +45 Mods +
+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+

Modded Hardcore

+
+Forge +1.19.2 + +218 Mods +
+
+ +
+ +
+ +
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/library_official_brand_fix/screen.png b/legacy/Launcher/stitch_owyx_launcher/library_official_brand_fix/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..572e080254a44795c9bc87a542469a633d64a6bf GIT binary patch literal 132391 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చL>H^{ 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/code.html b/legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/code.html new file mode 100644 index 00000000000..d8d2d169e18 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/code.html @@ -0,0 +1,408 @@ + + + +Owyx - New Instance + + + + + + + + + + + +
+ +
+ +
+
owyx
+
+ +
+My Instances +
+ +
+
+ Ready +
+
+ +
+ +
+
+

Library

+

Manage and launch your Minecraft instances.

+
+
+
+search + +
+ +
+
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+

My Survival World

+Vanilla +
+

1.20.4 • 48 hrs played

+
+
+schedule +2 days ago +
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+
+

FTB Modpack

+Forge +
+

1.19.2 • 234 Mods

+
+
+schedule +Last week +
+ +
+
+
+ +
+
+add +
+Create Instance +
+
+
+
+ + + + + \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/screen.png b/legacy/Launcher/stitch_owyx_launcher/new_instance_rebranded_rail_fix/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..34ec6de566e403f5428049fbff98c917185372d2 GIT binary patch literal 113907 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

-v&91`3VC$C=d^<_g5)eb>y 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 literal 0 HcmV?d00001 diff --git a/legacy/Launcher/stitch_owyx_launcher/owyx_official/DESIGN.md b/legacy/Launcher/stitch_owyx_launcher/owyx_official/DESIGN.md new file mode 100644 index 00000000000..37dc42ceb33 --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/owyx_official/DESIGN.md @@ -0,0 +1,194 @@ +--- +name: Owyx Official +colors: + surface: '#131319' + surface-dim: '#131319' + surface-bright: '#39383f' + surface-container-lowest: '#0e0e14' + surface-container-low: '#1b1b21' + surface-container: '#1f1f25' + surface-container-high: '#2a2930' + surface-container-highest: '#35343b' + on-surface: '#e4e1ea' + on-surface-variant: '#bac9cc' + inverse-surface: '#e4e1ea' + inverse-on-surface: '#303037' + outline: '#849396' + outline-variant: '#3b494c' + surface-tint: '#00daf3' + primary: '#c3f5ff' + on-primary: '#041018' + primary-container: '#00e5ff' + on-primary-container: '#00626e' + inverse-primary: '#006875' + secondary: '#d0bcff' + on-secondary: '#3c0091' + secondary-container: '#571bc1' + on-secondary-container: '#c4abff' + tertiary: '#ffeac0' + on-tertiary: '#3e2e00' + tertiary-container: '#fec931' + on-tertiary-container: '#6f5500' + error: '#ffb4ab' + on-error: '#690005' + error-container: '#93000a' + on-error-container: '#ffdad6' + primary-fixed: '#9cf0ff' + primary-fixed-dim: '#00daf3' + on-primary-fixed: '#001f24' + on-primary-fixed-variant: '#004f58' + secondary-fixed: '#e9ddff' + secondary-fixed-dim: '#d0bcff' + on-secondary-fixed: '#23005c' + on-secondary-fixed-variant: '#5516be' + tertiary-fixed: '#ffdf96' + tertiary-fixed-dim: '#f3bf26' + on-tertiary-fixed: '#251a00' + on-tertiary-fixed-variant: '#594400' + background: '#050508' + on-background: '#e4e1ea' + surface-variant: '#35343b' + surface-raised: '#14141c' + border: '#2a2b30' + text-primary: '#f3f4f6' + text-muted: '#9aa0a8' +typography: + display-lg: + fontFamily: DM Sans + fontSize: 26px + fontWeight: '700' + lineHeight: 30px + letterSpacing: -0.03em + headline-md: + fontFamily: DM Sans + fontSize: 20px + fontWeight: '700' + lineHeight: 24px + letterSpacing: -0.02em + title-sm: + fontFamily: DM Sans + fontSize: 16px + fontWeight: '600' + lineHeight: 20px + body-md: + fontFamily: DM Sans + fontSize: 15px + fontWeight: '500' + lineHeight: 22px + body-sm: + fontFamily: DM Sans + fontSize: 13px + fontWeight: '500' + lineHeight: 18px + label-xs: + fontFamily: DM Sans + fontSize: 12px + fontWeight: '600' + lineHeight: 14px + letterSpacing: 0.04em + brand-nav: + fontFamily: DM Sans + fontSize: 15px + fontWeight: '700' + lineHeight: 15px + letterSpacing: -0.02em +rounded: + sm: 0.25rem + DEFAULT: 0.5rem + md: 0.75rem + lg: 1rem + xl: 1.5rem + full: 9999px +spacing: + rail-width: 64px + topbar-height: 48px + page-padding: 24px + gap-xs: 4px + gap-sm: 8px + gap-md: 12px + gap-lg: 16px + gap-xl: 24px +--- + +## Brand & Style + +The design system moves into its official Phase 2 identity, transitioning from a generic utility to a specialized, high-fidelity gaming environment. The brand personality is technical, precise, and immersive, targeting a power-user demographic that values speed and stability. + +The design style is **Corporate / Modern** with a **High-Contrast** edge. It utilizes a deep-space palette to create a focused "low-light" environment, where high-chroma cyan accents act as functional beacons for primary actions. The aesthetic is clean and structured, favoring data density and clear navigation over decorative elements. A signature "segmented ring" visual language is applied to icons and logos to reinforce the unique Owyx identity. All previous green accents are strictly removed in favor of a sophisticated Cyan and Violet pairing. + +## Colors + +The palette is anchored by a near-black foundation that minimizes eye strain and maximizes the impact of brand accents. + +- **Primary (Cyan):** Reserved for high-priority interactive elements like "Play," "New Instance," and "Create." It represents action and energy. +- **Secondary (Violet):** Used primarily as a "wash" or background tint for active states and selection indicators, providing a subtle layer of depth. +- **Neutral Stack:** + - **Background:** The base app canvas. + - **Surface:** Standard component backgrounds. + - **Raised:** Elevated elements such as cards and inputs. + - **Border:** Subtle structural separation. +- **Text:** High-contrast off-white for readability, with a cool-gray muted tone for secondary metadata and inactive labels. + +## Typography + +DM Sans is utilized across the entire system to maintain a modern, geometric clarity. The hierarchy is designed for high information density typical of desktop launchers. + +Larger display styles use tighter tracking and leading to feel "locked-in" and architectural. Body text is prioritized for legibility with slightly more generous line height. Small labels and metadata use increased letter spacing and semi-bold weights to ensure they remain scannable against dark backgrounds. + +## Layout & Spacing + +The system follows a **Fixed Grid** shell model optimized for desktop application windows (1280px+). + +- **Navigation Rail:** A permanent 64px vertical sidebar on the left. +- **Top Bar:** A 48px horizontal utility bar containing branding and global status. +- **Content Area:** A scrollable stage with consistent 24px internal padding. + +**Navigation Rail Hierarchy:** +1. **Logo:** Segmented ring 'O' with purple-to-cyan glow. +2. **Navigation:** Home, Library, Private Servers (Discover is removed). +3. **Activity:** Recent Instances (circular avatars, collapses when empty). +4. **Action:** '+' Create Instance. +5. **Spacer:** Flexible vertical expansion. +6. **Utility:** Settings (anchored to the bottom). + +## Elevation & Depth + +The design system uses **Tonal Layers** to establish hierarchy, avoiding traditional drop shadows in favor of surface-based depth. + +- **Level 0 (Background):** Pure #050508 foundation. +- **Level 1 (Surface):** Default panel state (#0c0c12). +- **Level 2 (Raised):** Interactive components like cards and inputs (#14141c). +- **Separation:** 1px borders (#2a2b30) are used for all structural definition. +- **Modals:** Use a dark backdrop scrim with a subtle background blur to focus attention. +- **Active States:** Indicated by a #8b5cf6 (Violet) wash at low opacity, creating a distinct "lit" effect without cluttering the UI. + +## Shapes + +The shape language is a mix of geometric precision and organic softness. + +- **Circular (Full):** Used for navigation icons, status pills, and avatars to create a friendly, "tappable" feel within the tech-heavy environment. +- **Rounded (0.5rem - 1.5rem):** Used for containers, cards, and input fields to soften the "pro-tool" aesthetic and improve visual flow. +- **Segmented Ring:** The core brand motif, applied to the logo and potentially custom loading indicators. + +## Components + +### Buttons +- **Primary (Play/Create):** Solid Cyan (#00e5ff) background with Dark (#041018) text. 10px corner radius. High-impact bold weight. +- **Ghost/Secondary:** Raised (#14141c) background with a 1px border. For secondary navigation or utility actions. +- **Rail Button:** 48x48 circular hit targets. Active state: Violet (#8b5cf6) background wash with a Cyan (#00e5ff) icon. + +### Input Fields +- **Standard:** Raised background, 10px radius, 1px border. Focus state should use a Cyan border or a subtle Violet glow. + +### Cards & Lists +- **Instance Cards:** Surface background, 14px radius. Contains a prominent Play button on hover/active. +- **Instance Rows:** Horizontal layout with a clear trailing action button. + +### Navigation Elements +- **Tabs/Chips:** Pill-shaped (fully rounded). Inactive uses Raised background; Active uses Violet wash with Cyan text. +- **Top Bar Status:** A pill-shaped component on the right side indicating launch progress or active session status. + +### Interaction Logic +- **Hover:** Subtle lightening of the background color or border. +- **Active:** Violet wash application for selection visibility. +- **Accessibility:** All Cyan elements must maintain high contrast against the dark background; avoid using Cyan for body text. \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/code.html b/legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/code.html new file mode 100644 index 00000000000..e28fe318d8a --- /dev/null +++ b/legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/code.html @@ -0,0 +1,173 @@ + + + + + +Owyx - Private Servers + + + + + + + + + + +
+
+

owyx

+/ +Private Servers +
+
+
+
+System Stable +
+
+
+ +
+ +
+
+ +
+
+dns +
+ +
+

Private servers coming soon

+

+ Owyx is working with authors to bring dedicated private server hosting and community hubs directly into the launcher. Stay tuned for Phase 2. +

+
+
+
+ \ No newline at end of file diff --git a/legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/screen.png b/legacy/Launcher/stitch_owyx_launcher/private_servers_coming_soon/screen.png new file mode 100644 index 0000000000000000000000000000000000000000..91ad44651951358107ddf8be8069ea1f551f37bd GIT binary patch literal 120095 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

M8y2Nt^TKryC?0J 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 literal 0 HcmV?d00001 diff --git a/legacy/PLAN.md b/legacy/PLAN.md new file mode 100644 index 00000000000..58ee19fd573 --- /dev/null +++ b/legacy/PLAN.md @@ -0,0 +1,354 @@ +# Owyx — единый план + +Один файл на весь монорепо. Старые `Launcher/PLAN.md`, `owyxsite/PLAN.md`, `owyxplugin/PLAN.md` — только указатели сюда. + +**Репо:** https://github.com/ebluffy/Owyx +**Обновлено:** 2026-08-30 (launcher mass review + Play/Modrinth E2E; лаунчер **v0.5 rc**) +**Сейчас цель:** Windows GitHub Releases (debug + release exe) у владельца. Cloud Play + 2 мода закрыты. + +MiniMax Windows-QA (`MINIMAX_WIN_QA.md`) — **после** этого контура, не сейчас. + +--- + +## 1. Продукт + +**Owyx** — экосистема своих Minecraft-серверов: сайт (аккаунт, роли, каталог серверов/паков) ↔ лаунчер (скачал, ник или аккаунт, Play) ↔ плагин (сессия на сервере, позже). + +Играть открыто, без заявок: + +| Путь | Что нужно | +|------|-----------| +| Гость | Скачал `Owyx.exe` → ник → Play | +| Аккаунт Owyx | Регистрация на сайте → тот же логин в лаунчере → скин и плюшки | +| Microsoft | Честный stub, не ломает offline/Owyx | + +**Игрок:** один `Owyx.exe`, данные `%USERPROFILE%/owyx`. +**Админ (роль `admin` на сайте):** добавляет сервера и сборки **в лаунчере** (под своим профилем) и **на сайте** — кому как удобнее. Один каталог, два UI. + +Лаунчер без сайта умеет offline + ваниль/локальные инстансы. Список **своих серверов и паков** живёт на сайте — это нормально. + +Хостинг по этапам: сейчас друзья через мини-ПК + FRPC → потом отдельный РФ VPS под сайт. Игровой порт за FRPC часто показывает клиентам `127.0.0.1` — это про Minecraft, не про «сайт нельзя хостить». + +Дизайн: [`DESIGN.md`](./DESIGN.md) — фон `#050508`, accent `#00e5ff`. Контракт API: [`owyxsite/LAUNCHER_SITE_CONTRACT.md`](./owyxsite/LAUNCHER_SITE_CONTRACT.md). Сборка лаунчера: [`Launcher/BUILD.md`](./Launcher/BUILD.md). + +--- + +## 2. Где что лежит + +| Путь | Роль | +|------|------| +| `Launcher/` | Tauri 2 + Rust + Vite. Референс поведения: `../modrinth-code` / Theseus — **портировать**, не подменять продукт | +| `owyxsite/` | Next `:3000` + Express `:3001` + Postgres 17 + Adminer. Сайт = control-plane | +| `owyxplugin/` | Paper/Purpur. Ещё бренд Chiwawa в коде. Не блокер друзей-паков | + +Секреты только в `.env`. В git нет `*.exe`, `target/`, `node_modules/`, дампов БД. + +--- + +## 3. Статус на 2026-08-24 (после overnight friends sprint) + +### Сайт — UI **v0.1**, launcher API **v1.1.0** + +Сделано раньше: cyan-редизайн, открытый доступ, Owyx-login, скины на сайте, ник 30д, смена почты, новости+админ CRUD, HTML-письма. + +Сделано в этом PR: + +- Таблицы `packs` + `servers` (`007_servers_packs.sql`), compose mount, idempotent `ensureCatalogSchema()` на старте backend +- Публично: `GET /api/launcher/v1/servers|packs|packs/:id|packs/:id/manifest|news` — **не stubs**, seed + живые строки +- Admin CRUD `/api/admin/packs` + `/api/admin/servers` + zip ingest (≤50 MB → `/uploads/packs/`) +- UI `/admin`: вкладки **Серверы** / **Сборки**, модалки, hide/show, загрузка zip +- Игрокам **не** отдаём SFTP-логины; admin GET видит `hasPassword`, не пароль +- News в лаунчер API = та же таблица `news`, что сайт + +### Лаунчер — **v0.5 progress** (не ship) + +Сделано в этом PR: + +- Вкладка **Серверы**: каталог с сайта, empty/offline states, Скачать / Play +- `http_zip` / `http_manifest`: качка + sha256 + zip-slip-safe extract; SFTP-клиент **не** для игроков +- Play: `servers.dat` + `--quickPlayMultiplayer` (MC ≥ 1.20) иначе `--server/--port` +- Админ в лаунчере (`/me.role === admin`): модалка «Добавить сервер» → тот же admin API +- Owyx login: 401/403 → `no_session`, UI не падает; offline-ник не трогали +- Скин с `/me`: файл `~/owyx/skins/{nick}.png` (+ опционально `instances/{id}/game/owyx/skin.png`). In-game apply (CustomSkinLoader) — **не** в этом PR +- Modrinth: фильтр loader/MC инстанса, выбор версии, install + required deps (глубина ≤ 5) + +Cloud Linux: **native** `npm run dev:tauri` (WebKitGTK) + `build:smoke` ELF — закрыто в Linux-native PR. Vite `:1420` остаётся быстрым UI-preview без invoke. Windows Play / `Owyx.exe` — hand-off после мержа. MiniMax — отдельно. + +### Плагин — не спринт друзей + +Ребрендинг `chiwawa` → `owyx` — после живых серверов. Game-token deprecated. + +--- + +## 4. Этот спринт — что закрыто / что осталось + +Закрыто в overnight PR (ветка `cursor/friends-control-plane-servers-7784`) и quality-pass (#12). Linux **dev + smoke ELF** закрыт отдельным PR; MiniMax / магазин / Discord RPC / Linux `.deb` — не сюда. + +### 4.1 Сделано + +- Control-plane: миграция + API + admin UI + seed `demo-vanilla` (tiny fixture zip) +- Лаунчер Servers живой; качка http_zip/manifest; Play пишет адрес +- Админ создаёт сервер с сайта **и** из лаунчера +- Modrinth: version picker + required deps (не полный Theseus) +- Скин: файл на диске + UI, не «только URL в JSON» + +### 4.2 Осталось (честный backlog, не Theseus-complete) + +- Windows hand-off: полный install ванили + overlay + Play на IP:port у друга +- Онлайн-статус серверов (`status.online` пока `null`); ping/motd нет +- Полный mrpack parser / Theseus resolver / SQLite content DB / upgrade UI + (сейчас schema + `downloadAvailable: false`, overlay честно падает на `.mrpack`) +- Optional Modrinth deps — opt-in в UI; required deps fail-fast + cycle guard +- SFTP warehouse → HTTP publish (сейчас креды только админу + ручной HTTP URL) +- Resume больших качек; дельта-синк «3 мода из 200» +- In-game skin apply (CustomSkinLoader / Theseus player-data); файл на диске есть +- Microsoft OAuth, shop, plugin rebrand (`chiwawa` → `owyx`) +- Native Linux **ship** (`.deb` / AppImage) — **не** этот PR; dev + debug ELF уже есть +- GitHub Release v0.1 / v0.5 exe +- MiniMax Windows QA + +### 4.3 Что не сейчас + +- MiniMax полный прогон +- Платежи, shop, форум +- Ребрендинг плагина +- Microsoft OAuth +- Возврат заявок + +### 4.4 Решения (спорное → простой путь для друзей) + +| Тема | Решение | +|------|---------| +| Игрок vs склад | Игрокам только HTTP zip/manifest + sha. SFTP только admin, никогда в `GET /servers` | +| Ids | TEXT slug (`owyx-demo`), не serial | +| Байты | Не в Postgres. Fixture/dev: `/fixtures/packs/*.zip` на backend; прод: URL склада | +| Старый Docker volume | `initdb.d` не накатывает. README: `psql -f 007_servers_packs.sql`. Backend ещё `ensureCatalogSchema()` — таблица должна быть **OWNER** `owyx_user` | +| Play адрес | `servers.dat` (NBT gzip) + quickPlay ≥ 1.20, иначе `--server/--port` | +| HTTP allowlist | HTTPS публичный склад + loopback/private + хост API (dev fixture) | +| google_drive / mrpack | Схема + admin UI; качка игроку только если есть прямой download URL | +| Cloud | Native `dev:tauri` + Linux smoke ELF. Vite — secondary. Не Wine/WebView2 | + +--- + +## 5. Откуда берётся сборка (решение) + +В карточке пака админ **выбирает источник**. Лаунчер/сайт не зашивают один SFTP в код. + +Две роли протокола: + +| Кто | Канал | Зачем | +|-----|--------|--------| +| **Игрок** | почти всегда **HTTP(S) + манифест + sha256** | У лаунчера уже есть качалка, allowlist, прогресс. Не тащить SFTP-пароль всем друзьям | +| **Админ / склад** | HTTP, SFTP, диск админа, Drive, mrpack | Как **положить** файлы на мини-ПК | + +Мини-ПК быстрее Google Drive на 2 ГБ у друзей — это склад. На складе крутится **HTTP-раздача** (Caddy/nginx за тем же FRPC). SFTP — чтобы **ты** заливал, не чтобы каждый клиент логинился в SFTP. + +### Источники в модалке (v0.5 friends) + +1. **HTTP zip / папка на складе** — URL уже готового архива или индекса на мини-ПК. Основной путь для игроков. +2. **SFTP** — `host:port` (VPN/FRPC), пользователь, путь к **файлу или папке**. Хранится на сайте как секрет админа. Игрокам **не** отдавать логин в `GET /servers`. Сайт/админ-лаунчер забирает со склада → публикует HTTP+манифест. +3. **Google Drive** — запас, если ссылка уже есть. Квоты и промежуточная страница — не основной канал. +4. **mrpack** — файл или URL. Распаковка формата Modrinth (как Theseus), не свой формат. +5. **Локальный профиль админа** — папка инстанса (CurseForge/свой модпак + ручные моды). Админский лаунчер пакует zip, считает хеши, **заливает на склад** (SFTP или HTTP PUT), пишет манифест. Друзья качают как (1). + +### «Скормить zip — лаунчер сам разберётся» + +Отдельный сервис **Pack ingest** (сначала в админ-лаунчере, потом можно на сайте): + +1. Принял zip / папку / mrpack +2. Распаковал во временную +3. Узнал MC-версию и лоадер (minecraftinstance.json / mrpack index / mods) +4. Собрал манифест файлов + sha256 +5. Залил на склад в `packs/{packId}/` +6. Привязал к карточке сервера + +Первая версия может быть тупой: один zip целиком. Умный ingest — сразу после того, как друзья один раз успешно качнули. + +**Не делать:** сырой SFTP с паролем в публичном API; 2 ГБ в теле запроса сайта; единственная надежда на Drive. + +--- + +## 6. Версии продукта + +| Версия | Смысл | +|--------|--------| +| Сайт UI **0.1** | Кабинет, auth, скин на сайте, новости — есть | +| API лаунчера **v1.1.0** | login + `/me` + **живой** каталог servers/packs/news — есть в этом PR | +| Лаунчер **v0.1** | Classic Play — есть | +| Лаунчер **v0.5** (цель спринта) | **progress:** каталог + качка HTTP + admin create + Modrinth versions + скин на диск. Windows Play у друзей — после мержа | +| Лаунчер **v1.0** | Стабильный Windows exe для внешнего круга | +| Плагин **позже** | Ребренд + session-login, не game-token | + +После **v0.5** у друзей: хост на мини-ПК. Потом сайт на РФ VPS. Потом MiniMax QA по чеклисту. + +--- + +## 7. Лаунчер — стек и диск + +| Слой | Технология | +|------|------------| +| Backend | Rust | +| Окно | Tauri 2 + WebView2 (Windows) / WebKitGTK 4.1 (Linux) | +| UI | HTML/CSS/TS + Vite | + +```text +%USERPROFILE%/owyx/ + config.json · profiles.json + instances/{id}/instance.json · game/ + meta/versions|libraries|assets|natives|java_versions + cache/ · logs/ +``` + +Сборка: `npm run check` → `check:rust` → Linux `build:smoke` (ELF) → Windows `build:release` только для ship. См. `Launcher/BUILD.md`. + +Theseus-пути install/launch — опора. UI свой (Owyx), не копия Modrinth App целиком. **Modrinth content** — наоборот, копировать паттерны Theseus. + +Известный техдолг: AUTH stub MS; полный Theseus content (optional deps, upgrade UI); Wine WebView2; GitHub Release; CI Windows artifact; in-game skin; server ping; mrpack parse; SFTP→HTTP publish. + +--- + +## 8. Сайт — стек и отложенное + +Postgres 17 + Express + Next. Роли: `user | helper | moderator | admin`. Бан блокирует `/me`. Applications deprecated. + +Когда control-plane живой, можно вернуться к: SMTP/Turnstile прод, SSL, Directus, shop, мониторинг. + +Compose: монтировать **все** миграции в `initdb.d`. На старый volume — ручной `psql -f`. + +--- + +## 9. Плагин (после друзей) + +1. Package/команды/JAR `owyx`, не Chiwawa +2. API base `api.owyx.site` / локальный +3. Логин: цель — сессия лаунчера; game-token только переходный +4. Не менять JWT в одиночку + +--- + +## 10. Архитектура (цель) + +```text +Админ (лаунчер или сайт) + │ JWT role=admin + ▼ +Сайт API — servers + packs + users + skins + │ + ├─ игроки: GET catalogs, login, /me + ▼ +Owyx.exe — список серверов, качка пака, Play, Modrinth, скин + │ + ▼ +Склад файлов (мини-ПК): HTTP для игроков, SFTP/диск для админа + │ + ▼ +Minecraft + плагин (позже автологин) +``` + +--- + +## 11. Чеклист «можно звать друзей» + +- [x] Админ с сайта/лаунчера создаёт сервер + пак (API + оба UI) +- [x] Друг в лаунчере видит карточку и качает http_zip/manifest (native `dev:tauri` + compose) +- [x] Play на Cloud Linux: Fabric 1.20.1 + Fabric API + Sodium → MC main menu (`dev:tauri`) +- [ ] Play заходит на IP:port на **Windows** у друга (код есть; owner собирает exe) +- [x] Источник пака задан в карточке (HTTP zip; seed `demo-vanilla`) +- [x] Обрыв качки не оставляет вечный `installing` без выхода (ошибка → fail, не silent) +- [x] Modrinth: найти мод → выбрать версию → поставить (+ required deps) +- [x] Скин аккаунта доезжает до папки профиля (`~/owyx/skins`); in-game apply — долг +- [x] Offline-ник по-прежнему работает без сайта +- [x] VPS: `deploy/vps-up.sh` + nginx `owyx.site` (не ломать `panel.owyx.site`) +- [ ] Потом: MiniMax Windows QA, только отчёт + +--- + +## 12. Процесс + +- Сначала этот `PLAN.md`, потом код. +- Фичи сайта/лаунчера — PR, не сразу в `main`, пока сами не скажем мержить. +- Авторевью на PR. Секреты не коммитить. +- Облачный агент не мержит сам. +- Референс экрана лаунчера: сначала Theseus/`modrinth-code`, потом порт в Owyx. + +--- + +## 13. Overnight friends sprint — находки + +- Старый Postgres volume **не** применяет новые SQL сам. `ensureCatalogSchema()` падает `42501 must be owner of table packs`, если таблицы создал `postgres`, а backend ходит как `owyx_user` — `ALTER TABLE packs, servers OWNER TO owyx_user`. +- Cloud agent VM: Docker не обязателен. Postgres 16 + apt хватает; compose ждёт 17. +- Linux Tauri: `Launcher/scripts/linux-dev-setup.sh` (Rust ≥ 1.85 + WebKitGTK 4.1 / GTK). Primary cloud path = `npm run dev:tauri`, не Vite-only и не Wine. +- Сайтовый `npm run lint` (frontend) чинится в quality-pass PR (`AuthProvider`, + profile/admin без sync setState-in-effect). +- Полный vanilla install из cloud не гоняли (долго + нет native Play). Overlay-путь в `catalog.rs` есть. +- Идея на потом: админский «publish to configured HTTP PUT» с мини-ПК, без SFTP в лаунчере игрока. + +--- + +## 14. Deep quality pass (2026-08-24) + +Один проход по `Launcher/` + `owyxsite/` с опорой на [modrinth/code](https://github.com/modrinth/code) +(Theseus-паттерны: fail-fast deps, zip-slip, redirect policy). `owyxplugin/` не трогали. + +### Лаунчер + +- Overlay fail больше не оставляет инстанс `ready`: сносится `meta.json`, `status=error` +- Required Modrinth deps: fail-fast, цикл `visited`, optional только по флагу +- Catalog HTTP: своя redirect policy (нет HTTPS→HTTP, нет public→loopback) +- Zip-slip / symlink overlay, caps, `META-INF` только как первый компонент +- Skin download: тот же HTTP-клиент + post-redirect `assert_asset_url` +- Quick Play только на MC ≥ 1.20.2 +- Честный mrpack: overlay ошибка, не «это zip» +- UI: Play блокирует `needsAuth`; i18n relative time; dialog/`showModal`; combobox; + optional deps checkbox; mrpack/sftp Download disabled + +### Сайт + +- Сессии: SHA-256 hash (legacy base64 мигрирует при использовании) +- `GET /verify` проверяет строку сессии; banned/inactive → 403 +- Plugin write routes: long-term API token **only**, website JWT не проходит +- Turnstile в production fail-closed без секрета; `trust proxy` из `TRUST_PROXY_HOPS` +- Публичный player list без `ip_address`; admin settings redact password/secret +- Chat: membership на private rooms; socket join до send +- `mrpack` public `downloadAvailable: false`; ingest `.mrpack` + удаление файла +- Frontend: один `AuthProvider`, logout через API, пароль ≥ 8, `/servers` IP из settings + +Cloud Linux: `dev:tauri` + compose API. Vite `:1420` без invoke. WebView2 / Wine — не cloud path. + +--- + +## 15. Launcher ↔ site E2E + VPS (2026-08-29) + +- Native catalog/login/Modrinth browse против `OWYX_API_BASE_URL=http://127.0.0.1:3001` +- Библиотека: вкладки — фильтры (не disabled stubs). Modrinth: иконки + «ещё» (offset) +- Admin create server: честный лимит **512 MB** (`MAX_PACK_BYTES`) — Foreg 2GB не этот PR +- `owyxsite/deploy/vps-up.sh`: port audit, `.env` если нет, health +- `docker-compose.prod.yml`: loopback + Adminer `profiles: [debug]` +- nginx: `owyx.site` → Next/API, не Coming Soon; `panel.owyx.site` не трогаем + +--- + +## 16. Launcher mass review / pre-release QA (2026-08-30) + +Cloud `dev:tauri` + site API `:3001`. Цель — release-ready лаунчер до двух Windows GitHub Release. + +### Починено в этом проходе + +- Modrinth required deps резолвятся по **loader/MC инстанса**, не `.first()` у родителя +- Upgrade мода: atomic replace, без delete-before-write +- `servers.dat` на Play больше не глотается; Forge natives merge — ошибка, не `let _` +- macOS: `-XstartOnFirstThread` если нет в jvm args +- UI: XSS в фильтрах browse; ошибки через `textContent`; lock на Modrinth install +- Профильный wizard блокирует rail; Settings/Stats **прибиты к низу rail**; create — Enter + sticky footer +- i18n win chrome; active tabs/rail — cyan, не violet fill; `btn-warn` без amber primary + +### E2E (cloud) + +- Instance `Fabric 1.20.1` · Fabric `0.19.5` · путь `~/owyx/instances/Fabric 1.20.1/` +- Моды: `fabric-api-0.92.11+1.20.1.jar`, `sodium-fabric-0.5.13+mc1.20.1.jar` +- Play → процесс Java `KnotClient` + main menu «Minecraft 1.20.1/Fabric (Modded)» +- Создан `qa-fabric-mods` (pending install — тот же MC/loader; полный install уже на `Fabric 1.20.1`) + +### Windows hand-off + +Owner: `npm run build:smoke` → debug exe; `npm run build:release` → `Launcher/Owyx.exe`. Теги v0.5.0-rc1 / v0.5.0. diff --git a/legacy/README.md b/legacy/README.md new file mode 100644 index 00000000000..7715b866734 --- /dev/null +++ b/legacy/README.md @@ -0,0 +1,16 @@ +# legacy/ — previous Owyx monorepo (archived in-tree) + +Frozen snapshot of the **private** stack before switching to the Modrinth App fork. + +| Path | Was | +|------|-----| +| `Launcher/` | Custom Tauri 2 + Vite launcher (`main.ts`) | +| `owyxsite/` | Next + Express + Postgres control-plane | +| `owyxplugin/` | Paper/Purpur plugin | +| `DESIGN.md` / `PLAN.md` | Product design & plan | + +Authoritative old git remote: https://github.com/ebluffy/OwyxOld + +Do **not** treat this as the shipping launcher anymore. Use root `apps/app` + `apps/app-frontend`. + +`.env` files here (if present) are local-only and gitignored. diff --git a/legacy/owyxplugin/.gitignore b/legacy/owyxplugin/.gitignore new file mode 100644 index 00000000000..5ff6309b719 --- /dev/null +++ b/legacy/owyxplugin/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/legacy/owyxplugin/.gitkeep b/legacy/owyxplugin/.gitkeep new file mode 100644 index 00000000000..3103d0f1cf1 --- /dev/null +++ b/legacy/owyxplugin/.gitkeep @@ -0,0 +1 @@ +# Drop former plugin sources here. diff --git a/legacy/owyxplugin/.idea/.gitignore b/legacy/owyxplugin/.idea/.gitignore new file mode 100644 index 00000000000..7bc07ec21cf --- /dev/null +++ b/legacy/owyxplugin/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/legacy/owyxplugin/.idea/encodings.xml b/legacy/owyxplugin/.idea/encodings.xml new file mode 100644 index 00000000000..aa00ffab782 --- /dev/null +++ b/legacy/owyxplugin/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/legacy/owyxplugin/.idea/misc.xml b/legacy/owyxplugin/.idea/misc.xml new file mode 100644 index 00000000000..fdc35ea8167 --- /dev/null +++ b/legacy/owyxplugin/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/legacy/owyxplugin/FIX_PLUGIN_YML.md b/legacy/owyxplugin/FIX_PLUGIN_YML.md new file mode 100644 index 00000000000..02c20edff14 --- /dev/null +++ b/legacy/owyxplugin/FIX_PLUGIN_YML.md @@ -0,0 +1,164 @@ +# Исправление ошибки "does not contain plugin.yml" + +## ❌ Проблема + +``` +java.lang.IllegalArgumentException: plugins\ChiwawaPlugin-2.5-SNAPSHOT.jar does not contain a paper-plugin.yml or plugin.yml! +Could not determine plugin type, cannot load a plugin from it! +``` + +## 🔍 Причина + +Maven Shade Plugin неправильно упаковывал JAR, не включая файлы из `src/main/resources/`. + +## ✅ Решение + +### 1. Обновлен `pom.xml` + +**Добавлено в ``:** + +```xml + + + src/main/resources + true + + **/*.yml + **/*.yaml + **/*.properties + + + +``` + +**Добавлен maven-resources-plugin:** + +```xml + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + UTF-8 + + +``` + +**Обновлен maven-shade-plugin:** + +```xml + + false + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + ${project.groupId}:${project.artifactId} + + ** + + + + +``` + +### 2. Удалено дублирование + +Было дублирование секции `` в конце `` - удалено. + +## 🔧 Как собрать + +```bash +mvn clean package +``` + +**Результат:** `target/ChiwawaPlugin-2.5-SNAPSHOT.jar` + +## ✔️ Проверка JAR + +Используйте скрипт для проверки: + +```powershell +.\check-jar.ps1 +``` + +Или вручную: + +```bash +jar tf target/ChiwawaPlugin-2.5-SNAPSHOT.jar | findstr plugin.yml +``` + +**Ожидаемый вывод:** +``` +plugin.yml +config.yml +org/ebluffy/chiwawa/... +``` + +## 📋 Структура ресурсов + +``` +src/main/resources/ + ├── plugin.yml ✓ Главный файл плагина + ├── config.yml ✓ Конфигурация + └── logs/ ✓ Директория для логов +``` + +## 🎯 Что изменилось + +| Компонент | До | После | +|-----------|-----|-------| +| **Resources section** | В конце build | В начале build | +| **maven-resources-plugin** | Отсутствовал | Добавлен 3.3.1 | +| **shade filters** | Базовые | Явное включение проекта | +| **createDependencyReducedPom** | true (default) | false | + +## 🚀 Следующие шаги + +1. **Пересобрать плагин:** + ```bash + mvn clean package + ``` + +2. **Проверить содержимое:** + ```powershell + .\check-jar.ps1 + ``` + +3. **Скопировать на сервер:** + ```bash + copy target\ChiwawaPlugin-2.5-SNAPSHOT.jar plugins\ + ``` + +4. **Перезапустить сервер** + +## 💡 Объяснение + +### Почему это происходит? + +Maven собирает проект в несколько фаз: +1. `compile` - компиляция .java файлов +2. `resources` - копирование файлов из src/main/resources +3. `package` - создание JAR +4. `shade` - создание fat-JAR с зависимостями + +Если `maven-resources-plugin` не настроен правильно, ресурсы могут не попасть в JAR на этапе shade. + +### Решение + +1. Явно указываем `` в начале `` +2. Добавляем `maven-resources-plugin` для гарантии +3. В shade-plugin добавляем фильтр для включения всего из нашего проекта +4. Отключаем `createDependencyReducedPom` для упрощения + +## ✅ Итог + +После пересборки `plugin.yml` и `config.yml` будут включены в JAR, и плагин успешно загрузится на Paper 1.21.4! diff --git a/legacy/owyxplugin/MINECRAFT_PLUGIN_PROMPT.md b/legacy/owyxplugin/MINECRAFT_PLUGIN_PROMPT.md new file mode 100644 index 00000000000..175c612e668 --- /dev/null +++ b/legacy/owyxplugin/MINECRAFT_PLUGIN_PROMPT.md @@ -0,0 +1,430 @@ +# ПРОМПТ ДЛЯ РАЗРАБОТКИ MINECRAFT ПЛАГИНА ИНТЕГРАЦИИ С CHIWAWA САЙТОМ + +## КОНТЕКСТ ПРОЕКТА + +Ты - эксперт Java разработчик Minecraft плагинов (Spigot/Paper API). Нужно создать полнофункциональный плагин для интеграции Minecraft сервера с веб-сайтом ChiwawaMine. + +### АРХИТЕКТУРА САЙТА: +- **Backend**: Node.js + Express.js + PostgreSQL +- **Порт**: 3000 (localhost/production) +- **База данных**: PostgreSQL 14.18 с UUID поддержкой +- **Аутентификация**: JWT токены + session management +- **API Endpoint**: `http://localhost:3000/api` (временно, после резила будет https://chiwawa.site/) + +### СТРУКТУРА БАЗЫ ДАННЫХ: + +#### Таблица `users`: +```sql +- id (INTEGER, PRIMARY KEY) +- nickname (VARCHAR(32)) // Minecraft ник +- email (VARCHAR(128)) +- password_hash (VARCHAR(128)) +- first_name, last_name (VARCHAR(50)) +- role (VARCHAR(32): 'user'|'admin'|'moderator') +- trust_level (INTEGER 0-5): 0=Проходимец(10ч лимит), 1=Новичок, 2=Проверенный(25ч+почта+10реп), 3=Ветеран(50ч+почта+20реп) +- is_active, is_email_verified, is_banned (BOOLEAN) +- registered_at, last_login (TIMESTAMP) +- ban_reason (TEXT) +``` + +#### Таблица `player_stats`: +```sql +- user_id (INTEGER, FK users.id) +- total_minutes, time_played_minutes (INTEGER) // Общее время игры +- is_time_limited (BOOLEAN) // Ограничение времени +- current_level (INTEGER) // Игровой уровень +- email_verified, discord_verified, minecraft_verified (BOOLEAN) +- reputation (INTEGER) // Репутация +- achievements_count, total_logins, warnings_count (INTEGER) +``` + +#### Таблица `applications`: +```sql +- id, user_id (INTEGER) +- minecraft_nick, email, discord (VARCHAR) +- status ('pending'|'approved'|'rejected') +- motivation, plans (TEXT) +- submitted_at, reviewed_at (TIMESTAMP) +``` + +#### Таблица `user_activity`: +```sql +- user_id (INTEGER, FK) +- activity_type (VARCHAR): 'login', 'logout', 'join_server', 'leave_server', 'playtime_update' +- description (TEXT) +- metadata (JSONB) // Дополнительные данные +- created_at (TIMESTAMP) +``` + +## ОСНОВНЫЕ API ЭНДПОИНТЫ ДЛЯ ПЛАГИНА: + +### АУТЕНТИФИКАЦИЯ: +- `POST /api/auth/login` - Вход (email, password → JWT token) +- `GET /api/auth/verify` - Проверка токена +- `POST /api/auth/logout` - Выход + +### ПОЛЬЗОВАТЕЛИ: +- `GET /api/profile` - Получить профиль игрока (нужен Bearer token) +- `PUT /api/profile` - Обновить профиль +- `GET /api/admin/users` - Список пользователей (admin only) +- `PUT /api/admin/users/:id/ban` - Забанить игрока +- `PUT /api/admin/users/:id/unban` - Разбанить игрока +- `PUT /api/admin/users/:id/trust-level` - Изменить trust level + +### СТАТИСТИКА И АКТИВНОСТЬ: +- `POST /api/admin/user-activity` - Записать активность игрока +- `GET /api/profile/activity` - История активности +- `PUT /api/admin/users/:id/playtime` - Обновить время игры + +### НАСТРОЙКИ СЕРВЕРА: +- `GET /api/settings/public` - Публичные настройки (название, IP, Discord) +- `GET /api/server-info` - Статус сервера (онлайн, игроки) + +### ЗАЯВКИ: +- `GET /api/applications/server-access` - Проверить доступ к серверу +- `GET /api/applications/:id/status` - Статус заявки по ID + +## ТЕХНИЧЕСКИЕ ТРЕБОВАНИЯ: + +### 1. ОСНОВНАЯ ФУНКЦИОНАЛЬНОСТЬ: + +#### A) СИСТЕМА WHITELIST: +```java +// При подключении игрока проверяй: +// 1. Есть ли user с таким nickname в БД +// 2. Одобрена ли его заявка (applications.status = 'approved') +// 3. Не забанен ли (users.is_banned = false) +// 4. Активен ли аккаунт (users.is_active = true) +``` + +#### B) TRUST LEVEL СИСТЕМА: +```java +// Trust Level влияет на: +// 0 (Проходимец): Лимит 10 часов игры ВСЕГО до подтверждения email (НЕ дневной!) +// 1 (Новичок): Стандартный доступ, БЕЗ лимитов времени +// 2 (Проверенный): Расширенные возможности +// 3 (Ветеран): Полный доступ игрока +// 4-5: Админские функции +``` + +#### C) СИСТЕМА ВРЕМЕНИ ИГРЫ: +```java +// Трекинг: +// - Время входа/выхода +// - Общее время игры (time_played_minutes) +// - ТОЛЬКО для проходимцев (trust_level = 0): лимит 10 часов ВСЕГО +// - Автоматический кик при превышении лимита (только проходимцы) +// - Дневных лимитов НЕТ для других рангов! +``` + +#### D) СИСТЕМА РЕПУТАЦИИ: +```java +// Возможности: +// - Команды для +/- репутации (/rep ) +// - История изменений репутации +// - Влияние на Trust Level повышение +``` + +### 2. КОМАНДЫ ПЛАГИНА: + +#### ADMIN КОМАНДЫ: +```java +/chiwawa reload - Перезагрузка конфига +/chiwawa sync - Синхронизация данных игрока с сайтом +/chiwawa ban - Бан через сайт +/chiwawa unban - Разбан через сайт +/chiwawa trust - Изменить trust level +/chiwawa playtime - Показать статистику времени +/chiwawa rep [reason] - Изменить репутацию +/chiwawa whitelist add - Добавить в whitelist (создает заявку) +/chiwawa users list [page] - Список пользователей с сайта +/chiwawa stats - Общая статистика сервера +``` + +#### ИГРОК КОМАНДЫ: +```java +/profile - Показать свой профиль с сайта +/playtime - Показать время игры +/rep - Дать репутацию игроку +/applications - Статус своей заявки +/discord - Связать Discord аккаунт +/rules - Правила сервера +``` + +### 3. КОНФИГУРАЦИЯ (config.yml): + +```yaml +# Настройки API +api: + base_url: "http://localhost:3000/api" + timeout: 5000 + admin_token: "ваш_админ_jwt_токен" + retry_attempts: 3 + +# Настройки сервера +server: + enable_whitelist: true + enable_time_limit: true + enable_trust_system: true + enable_reputation: true + sync_interval: 300 # секунд для синхронизации данных + +# Trust Level ограничения +trust_levels: + 0: # Проходимец + max_total_hours: 10 # ВСЕГО 10 часов, не дневной лимит! + description: "Новый игрок без подтвержденного email" + 1: # Новичок + description: "Подтвержден email, полный доступ" + 2: # Проверенный + description: "Опытный игрок с хорошей репутацией" + 3: # Ветеран + description: "Проверенный временем игрок" + +# Сообщения +messages: + # Кик сообщения (показываются при кике с сервера) + no_access_kick: | + &c&l┌─────────────────────────────┐ + &c&l│ &f&lНЕТ ДОСТУПА К СЕРВЕРУ &c&l│ + &c&l├─────────────────────────────┤ + &f&l│ &7У вас нет доступа к серверу &f&l│ + &f&l│ &7Подайте заявку на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &c&l└─────────────────────────────┘ + + time_limit_kick: | + &c&l┌─────────────────────────────┐ + &c&l│ &f&lЛИМИТ ВРЕМЕНИ ИСЧЕРПАН &c&l│ + &c&l├─────────────────────────────┤ + &f&l│ &7Вы достигли лимита в 10 часов &f&l│ + &f&l│ &7Подтвердите email на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &c&l└─────────────────────────────┘ + + ban_kick: | + &4&l┌─────────────────────────────┐ + &4&l│ &f&lВЫ ЗАБАНЕНЫ &4&l│ + &4&l├─────────────────────────────┤ + &f&l│ &7Причина: &c%reason% &f&l│ + &f&l│ &7Обжалование на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &4&l└─────────────────────────────┘ + + # Чат сообщения (обычные сообщения в чат) + trust_level_up: "&a&l[★] &fВаш Trust Level повышен до &a&l%level% &7(%name%)&f!" + reputation_given: "&e&l[REP] &fВы дали &a+1 репутацию &fигроку &b%player%&f!" + reputation_received: "&e&l[REP] &fИгрок &b%player% &fдал вам &a+1 репутацию&f!" +``` + +### 4. АРХИТЕКТУРА КЛАССОВ: + +#### ОСНОВНЫЕ КЛАССЫ: +```java +// Main Plugin Class +public class ChiwawaPlugin extends JavaPlugin + +// API Manager +public class ChiwawaAPI { + // HTTP клиент для взаимодействия с сайтом + // Методы: getUser(), updatePlaytime(), checkWhitelist(), etc. +} + +// User Manager +public class UserManager { + // Кеширование пользователей + // Синхронизация с БД + // Trust Level management +} + +// Playtime Manager +public class PlaytimeManager { + // Трекинг времени игры + // Лимиты времени + // Автоматические действия +} + +// Reputation Manager +public class ReputationManager { + // Система репутации + // История изменений + // Валидация +} + +// Command Handler +public class CommandManager { + // Обработка всех команд + // Проверка прав доступа +} + +// Event Listeners +public class PlayerListener implements Listener { + // Join/Quit события + // Chat события + // Другие игровые события +} +``` + +### 5. СОБЫТИЯ ДЛЯ ОБРАБОТКИ: + +```java +// При входе игрока (PlayerJoinEvent): +// 1. Проверить whitelist через API +// 2. Загрузить данные пользователя +// 3. Применить Trust Level ограничения (только для проходимцев) +// 4. Записать активность в БД +// 5. Показать приветственное сообщение + +// При выходе (PlayerQuitEvent): +// 1. Сохранить время игры +// 2. Записать активность выхода +// 3. Очистить кеш + +// Каждые 5 минут (Scheduled Task): +// 1. Обновить время игры всех онлайн игроков +// 2. Проверить лимит ТОЛЬКО для проходимцев (trust_level = 0) +// 3. Синхронизировать данные с сайтом + +// При выполнении команд (PlayerCommandPreprocessEvent): +// 1. Логировать важные команды +// 2. НЕ блокировать команды по Trust Level (есть другой плагин) +``` + +### 6. ИНТЕГРАЦИЯ С САЙТОМ: + +#### HTTP ЗАПРОСЫ: +```java +// Используй OkHttp или встроенный HttpURLConnection +// Все запросы с Bearer токеном в заголовках +// Content-Type: application/json +// Обработка ошибок сети и таймаутов +// Кеширование ответов для производительности +``` + +#### СИНХРОНИЗАЦИЯ ДАННЫХ: +```java +// Кеш пользователей в памяти (Map) +// Периодическая синхронизация каждые 5 минут +// Принудительная синхронизация при входе игрока +// Batch операции для множественных обновлений +``` + +### 7. БЕЗОПАСНОСТЬ: + +```java +// Валидация всех входящих данных от API +// Защита от SQL инъекций (используй PreparedStatement если свой SQL) +// Rate limiting для команд (/rep только раз в час на игрока) +// Логирование всех важных действий +// Проверка прав доступа для админ команд +``` + +### 8. ПРОИЗВОДИТЕЛЬНОСТЬ: + +```java +// Асинхронные HTTP запросы (не блокируй main thread) +// Кеширование данных пользователей +// Bulk операции для обновления статистики +// Ленивая загрузка данных +// Оптимизация SQL запросов +``` + +## ПРИМЕРЫ КОДА: + +### ПРОВЕРКА WHITELIST: +```java +public boolean isPlayerWhitelisted(String playerName) { + try { + HttpResponse response = httpClient.send( + HttpRequest.newBuilder() + .uri(URI.create(apiUrl + "/applications/server-access")) + .header("Authorization", "Bearer " + adminToken) + .GET() + .build(), + HttpResponse.BodyHandlers.ofString() + ); + + if (response.statusCode() == 200) { + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + return json.get("hasAccess").getAsBoolean(); + } + } catch (Exception e) { + getLogger().severe("Ошибка проверки whitelist для " + playerName + ": " + e.getMessage()); + } + return false; +} +``` + +### ОБНОВЛЕНИЕ ВРЕМЕНИ ИГРЫ: +```java +public void updatePlaytime(UUID playerUuid, int minutesPlayed) { + CompletableFuture.runAsync(() -> { + try { + String json = String.format("{\"playtime_minutes\": %d}", minutesPlayed); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(apiUrl + "/admin/users/" + getUserId(playerUuid) + "/playtime")) + .header("Authorization", "Bearer " + adminToken) + .header("Content-Type", "application/json") + .PUT(HttpRequest.BodyPublishers.ofString(json)) + .build(); + + httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + } catch (Exception e) { + getLogger().severe("Ошибка обновления времени игры: " + e.getMessage()); + } + }); +} +``` + +## ДОПОЛНИТЕЛЬНЫЕ ФИЧИ: + +### 1. DISCORD ИНТЕГРАЦИЯ: +- Уведомления о входе/выходе игроков +- Синхронизация ролей Discord с Trust Level +- Команды Discord бота для управления сервером + +### 2. СТАТИСТИКА: +- Топ игроков по времени игры +- Топ по репутации +- История активности игроков +- Графики использования сервера + +### 3. АВТОМАТИЗАЦИЯ: +- Автоматическое повышение Trust Level при выполнении условий +- Автоматические награды за достижения +- Уведомления администраторов о важных событиях + +## ТЕСТИРОВАНИЕ: + +### UNIT ТЕСТЫ: +- Тестирование API методов +- Проверка валидации данных +- Тестирование Trust Level логики + +### ИНТЕГРАЦИОННЫЕ ТЕСТЫ: +- Подключение к тестовой БД +- Проверка HTTP запросов +- Тестирование событий Minecraft + +## РАЗВЕРТЫВАНИЕ: + +### PRODUCTION CONFIG: +```yaml +api: + base_url: "https://chiwawa.site/api" + admin_token: "production_jwt_token" +database: + host: "212.15.49.139" + port: 5432 + database: "chiwawa" + ssl: true +``` + +### МОНИТОРИНГ: +- Логирование всех API запросов +- Метрики производительности +- Alerting при ошибках подключения к API +- Health check endpoints + +Создай полнофункциональный плагин с архитектурой, которая легко расширяется и поддерживается. Используй современные практики Java разработки и паттерны проектирования. diff --git a/legacy/owyxplugin/PLAN.md b/legacy/owyxplugin/PLAN.md new file mode 100644 index 00000000000..78ef9b0ccd2 --- /dev/null +++ b/legacy/owyxplugin/PLAN.md @@ -0,0 +1,3 @@ +# План плагина перенесён + +Единый план всего Owyx: **[../PLAN.md](../PLAN.md)** (корень монорепо), раздел «Плагин». diff --git a/legacy/owyxplugin/dependency-reduced-pom.xml b/legacy/owyxplugin/dependency-reduced-pom.xml new file mode 100644 index 00000000000..e09d8c4dc12 --- /dev/null +++ b/legacy/owyxplugin/dependency-reduced-pom.xml @@ -0,0 +1,121 @@ + + + 4.0.0 + org.example + ChiwawaPlugin + 2.5-SNAPSHOT + + + + true + src/main/resources + + + ${project.artifactId}-${project.version} + + + maven-compiler-plugin + 3.11.0 + + 21 + 21 + + + + maven-shade-plugin + 3.6.0 + + + package + + shade + + + + + com.google.gson + org.ebluffy.libs.gson + + + okhttp3 + org.ebluffy.libs.okhttp3 + + + okio + org.ebluffy.libs.okio + + + com.zaxxer.hikari + org.ebluffy.libs.hikari + + + at.favre.lib.crypto.bcrypt + org.ebluffy.libs.bcrypt + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + maven-surefire-plugin + 3.5.2 + + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + + io.papermc.paper + paper-api + 1.21-R0.1-SNAPSHOT + provided + + + org.slf4j + slf4j-api + 2.0.16 + provided + + + org.junit.jupiter + junit-jupiter + 5.11.3 + test + + + junit-jupiter-api + org.junit.jupiter + + + junit-jupiter-params + org.junit.jupiter + + + junit-jupiter-engine + org.junit.jupiter + + + + + + 21 + 21 + UTF-8 + + diff --git a/legacy/owyxplugin/pom.xml b/legacy/owyxplugin/pom.xml new file mode 100644 index 00000000000..51d20e74588 --- /dev/null +++ b/legacy/owyxplugin/pom.xml @@ -0,0 +1,191 @@ + + + 4.0.0 + + org.example + ChiwawaPlugin + 2.5-SNAPSHOT + jar + + + 21 + 21 + UTF-8 + + + + + + io.papermc.paper + paper-api + 1.21-R0.1-SNAPSHOT + provided + + + + + com.google.code.gson + gson + 2.11.0 + + + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + + org.slf4j + slf4j-api + 2.0.16 + provided + + + + + org.junit.jupiter + junit-jupiter + 5.11.3 + test + + + + + at.favre.lib + bcrypt + 0.10.2 + + + + + org.postgresql + postgresql + 42.7.4 + + + + + com.zaxxer + HikariCP + 6.2.1 + + + + + + papermc + https://repo.papermc.io/repository/maven-public/ + + + + + ${project.artifactId}-${project.version} + + + + src/main/resources + true + + **/*.yml + **/*.yaml + **/*.properties + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.11.0 + + 21 + 21 + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.3.1 + + UTF-8 + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.0 + + + package + + shade + + + false + + + + com.google.gson + org.ebluffy.libs.gson + + + okhttp3 + org.ebluffy.libs.okhttp3 + + + okio + org.ebluffy.libs.okio + + + com.zaxxer.hikari + org.ebluffy.libs.hikari + + + + at.favre.lib.crypto.bcrypt + org.ebluffy.libs.bcrypt + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + ${project.groupId}:${project.artifactId} + + ** + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.5.2 + + + + + diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/ChiwawaPlugin.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/ChiwawaPlugin.java new file mode 100644 index 00000000000..2c0cfa03b00 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/ChiwawaPlugin.java @@ -0,0 +1,297 @@ +package org.ebluffy.chiwawa; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.PluginManager; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.commands.*; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.database.DatabaseManager; +import org.ebluffy.chiwawa.listeners.AuthenticationListener; +import org.ebluffy.chiwawa.listeners.PlayerListener; +import org.ebluffy.chiwawa.managers.*; + +import java.util.logging.Logger; + +/** + * Главный класс плагина ChiwawaPlugin для интеграции с сайтом ChiwawaMine + */ +public class ChiwawaPlugin extends JavaPlugin { + private static ChiwawaPlugin instance; + + // Менеджеры + private ConfigManager configManager; + private ApiClient apiClient; + private DatabaseManager databaseManager; + private UserManager userManager; + private AuthManager authManager; + private PlaytimeManager playtimeManager; + private ReputationManager reputationManager; + private StatsManager statsManager; + private ServerStatsManager serverStatsManager; + private PlayerStatsManager playerStatsManager; + + // Логгер + private Logger logger; + + @Override + public void onEnable() { + instance = this; + logger = getLogger(); + + try { + logger.info("════════════════════════════════════"); + logger.info(" ChiwawaPlugin v1.0.0 - Запуск"); + logger.info("════════════════════════════════════"); + + boolean hasErrors = false; + StringBuilder errorMessages = new StringBuilder(); + + // 1. Загрузка конфигурации + configManager = new ConfigManager(this); + if (!configManager.validateConfig()) { + logger.severe("❌ Конфигурация содержит критические ошибки!"); + getServer().getPluginManager().disablePlugin(this); + return; + } + + // 2. Инициализация API клиента + apiClient = new ApiClient(this, + configManager.getApiBaseUrl(), + configManager.getApiKey(), + configManager.getApiTimeout(), + configManager.getRetryAttempts()); + + // 3. Инициализация базы данных + String dbHost = getConfig().getString("database.host", "127.0.0.1"); + int dbPort = getConfig().getInt("database.port", 5432); + String dbName = getConfig().getString("database.name", "chiwawa"); + String dbUser = getConfig().getString("database.username", "postgres"); + String dbPassword = getConfig().getString("database.password", ""); + + databaseManager = new DatabaseManager(this, dbHost, dbPort, dbName, dbUser, dbPassword); + + if (!databaseManager.testConnection()) { + hasErrors = true; + errorMessages.append(" • База данных: подключение не установлено\n"); + } + + // 4. Инициализация менеджеров + userManager = new UserManager(this, apiClient); + authManager = new AuthManager(this, databaseManager); + playtimeManager = new PlaytimeManager(this, apiClient, userManager, configManager); + reputationManager = new ReputationManager(this, apiClient, userManager, configManager); + statsManager = new StatsManager(this, apiClient, userManager, configManager); + serverStatsManager = new ServerStatsManager(this, apiClient, configManager); + playerStatsManager = new PlayerStatsManager(this, apiClient); + + // 5. Регистрация команд и слушателей + registerCommands(); + registerListeners(); + + // 6. Запуск менеджеров + startManagers(); + + // 7. Вывод итоговой информации + logger.info("────────────────────────────────────"); + if (hasErrors) { + logger.warning("⚠ Плагин запущен с ошибками:"); + logger.warning(errorMessages.toString()); + } else { + logger.info("✓ Плагин успешно запущен!"); + } + + // Активные функции + logger.info("Активные функции:"); + logger.info(" • Whitelist (заявки): " + (configManager.isWhitelistEnabled() ? "✓" : "✗")); + logger.info(" • Авторизация (login/register): " + (configManager.isAuthenticationEnabled() ? "✓" : "✗")); + logger.info(" • Лимит времени: " + (configManager.isTimeLimitEnabled() ? "✓" : "✗")); + logger.info(" • Trust система: " + (configManager.isTrustSystemEnabled() ? "✓" : "✗")); + logger.info(" • Репутация: " + (configManager.isReputationEnabled() ? "✓" : "✗")); + logger.info("════════════════════════════════════"); + + } catch (Exception e) { + logger.severe("════════════════════════════════════"); + logger.severe("❌ КРИТИЧЕСКАЯ ОШИБКА ЗАПУСКА"); + logger.severe("════════════════════════════════════"); + logger.severe("Ошибка: " + e.getMessage()); + e.printStackTrace(); + getServer().getPluginManager().disablePlugin(this); + } + } + + @Override + public void onDisable() { + try { + logger.info("Отключение ChiwawaPlugin..."); + + // Остановка менеджеров + if (playtimeManager != null) { + playtimeManager.stop(); + } + + if (statsManager != null) { + statsManager.stop(); + } + + if (serverStatsManager != null) { + serverStatsManager.stopStatsCollection(); + } + + if (playerStatsManager != null) { + playerStatsManager.stopStatsUpdates(); + } + + // Сохранение данных всех онлайн игроков + if (playtimeManager != null && userManager != null) { + playtimeManager.saveAllPlaytimes().join(); + logger.info("Сохранено время игры всех игроков"); + } + + // Очистка кешей + if (userManager != null) { + userManager.clearCache(); + } + + if (authManager != null) { + authManager.clearCaches(); + } + + // Закрытие подключения к БД + if (databaseManager != null) { + databaseManager.close(); + } + + logger.info("ChiwawaPlugin отключен!"); + + } catch (Exception e) { + logger.severe("Ошибка при отключении плагина: " + e.getMessage()); + e.printStackTrace(); + } finally { + instance = null; + } + } + + /** + * Регистрация команд плагина + */ + private void registerCommands() { + // Главная админ команда + ChiwawaCommand chiwawaCommand = new ChiwawaCommand(this, configManager, userManager, playtimeManager, reputationManager, apiClient); + getCommand("chiwawa").setExecutor(chiwawaCommand); + getCommand("chiwawa").setTabCompleter(chiwawaCommand); + + // Команды для игроков + getCommand("profile").setExecutor(new ProfileCommand(configManager, userManager, playtimeManager)); + getCommand("playtime").setExecutor(new PlaytimeCommand(configManager, playtimeManager, userManager)); + getCommand("applications").setExecutor(new ApplicationsCommand(configManager, userManager)); + getCommand("discord").setExecutor(new DiscordCommand(configManager)); + + // Команды авторизации (обновленные) + getCommand("login").setExecutor(new LoginCommand(configManager, apiClient, userManager, authManager, logger)); + getCommand("register").setExecutor(new RegisterCommand(configManager, authManager, logger)); + getCommand("changelogin").setExecutor(new ChangeLoginCommand(configManager, authManager, logger)); + getCommand("changepass").setExecutor(new ChangePasswordCommand(configManager, authManager, logger)); + getCommand("unregister").setExecutor(new UnregisterCommand(configManager, databaseManager, logger)); + + ReputationCommand repCommand = new ReputationCommand(configManager, reputationManager, userManager); + getCommand("rep").setExecutor(repCommand); + getCommand("rep").setTabCompleter(repCommand); + + // Логирование убрано + } + + /** + * Регистрация слушателей событий + */ + private void registerListeners() { + getServer().getPluginManager().registerEvents( + new PlayerListener(this, configManager, userManager, playtimeManager, playerStatsManager), this); + + getServer().getPluginManager().registerEvents( + new AuthenticationListener(this, userManager), this); + + // Логирование убрано + } + + /** + * Запуск менеджеров + */ + private void startManagers() { + if (configManager.isTimeLimitEnabled()) { + playtimeManager.start(); + } + + statsManager.start(); + serverStatsManager.startStatsCollection(); + playerStatsManager.startStatsUpdates(); + + // Логирование убрано - выводится общая информация + } + + /** + * Тест соединения с API (не используется - убрано из onEnable) + */ + private void testApiConnection() { + // Метод оставлен для возможного использования в будущем + } + + /** + * Перезагрузить плагин + */ + public void reloadPlugin() { + logger.info("Перезагрузка плагина..."); + + // Остановка менеджеров + if (playtimeManager != null) { + playtimeManager.stop(); + } + + // Перезагрузка конфигурации + configManager.reloadConfig(); + + // Перезапуск менеджеров + if (configManager.isTimeLimitEnabled()) { + playtimeManager.start(); + } + + logger.info("Плагин перезагружен!"); + } + + // Геттеры для доступа к менеджерам + public static ChiwawaPlugin getInstance() { + return instance; + } + + public ConfigManager getConfigManager() { + return configManager; + } + + public ApiClient getApiClient() { + return apiClient; + } + + public StatsManager getStatsManager() { + return statsManager; + } + + public UserManager getUserManager() { + return userManager; + } + + public PlaytimeManager getPlaytimeManager() { + return playtimeManager; + } + + public ReputationManager getReputationManager() { + return reputationManager; + } + + public AuthManager getAuthManager() { + return authManager; + } + + public DatabaseManager getDatabaseManager() { + return databaseManager; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/ApiClient.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/ApiClient.java new file mode 100644 index 00000000000..b20c63adb83 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/ApiClient.java @@ -0,0 +1,740 @@ +package org.ebluffy.chiwawa.api; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.dto.*; + +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +/** + * API клиент для взаимодействия с сайтом ChiwawaMine + */ +public class ApiClient { + private final JavaPlugin plugin; + private final Logger logger; + private final HttpClient httpClient; + private final Gson gson; + private final String baseUrl; + private final String apiKey; + private final int timeout; + private final int maxRetries; + + public ApiClient(JavaPlugin plugin, String baseUrl, String apiKey, int timeout, int maxRetries) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.baseUrl = baseUrl; + this.apiKey = apiKey; + this.timeout = timeout; + this.maxRetries = maxRetries; + + this.httpClient = HttpClient.newBuilder() + .connectTimeout(Duration.ofMillis(timeout)) + .build(); + + this.gson = new GsonBuilder() + .setPrettyPrinting() + .create(); + } + + /** + * Получить пользователя по никнейму + */ + public CompletableFuture getUserByNickname(String nickname) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/by-nick/" + nickname; + HttpResponse response = makeRequest(url, "GET", null); + + if (response.statusCode() == 200) { + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + if (json.has("success") && json.get("success").getAsBoolean()) { + JsonObject userJson = json.getAsJsonObject("user"); + return gson.fromJson(userJson, ChiwawaUser.class); + } + } + return null; + } catch (Exception e) { + logger.severe("Ошибка получения пользователя " + nickname + ": " + e.getMessage()); + return null; + } + }); + } + + /** + * Получить статистику игрока + */ + public CompletableFuture getPlayerStats(int userId) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/stats"; + HttpResponse response = makeRequest(url, "GET", null); + + if (response.statusCode() == 200) { + return gson.fromJson(response.body(), PlayerStats.class); + } + return null; + } catch (Exception e) { + logger.severe("Ошибка получения статистики игрока " + userId + ": " + e.getMessage()); + return null; + } + }); + } + + /** + * Проверить игровой токен + */ + public CompletableFuture verifyGameToken(String token, String nickname) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/auth/verify-game-token"; + JsonObject body = new JsonObject(); + body.addProperty("token", token); + body.addProperty("nickname", nickname); + + HttpResponse response = makeRequest(url, "POST", body.toString()); + + if (response.statusCode() == 200) { + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + if (json.has("valid") && json.get("valid").getAsBoolean()) { + JsonObject userJson = json.getAsJsonObject("user"); + return new TokenVerificationResult( + true, + userJson.get("id").getAsInt(), + userJson.get("nickname").getAsString(), + userJson.get("role").getAsString(), + userJson.get("trust_level").getAsInt(), + json.get("message").getAsString() + ); + } + } + + JsonObject errorJson = JsonParser.parseString(response.body()).getAsJsonObject(); + String errorMessage = errorJson.has("error") ? errorJson.get("error").getAsString() : "Неизвестная ошибка"; + return new TokenVerificationResult(false, 0, null, null, 0, errorMessage); + + } catch (Exception e) { + logger.severe("Ошибка проверки игрового токена: " + e.getMessage()); + return new TokenVerificationResult(false, 0, null, null, 0, "Ошибка соединения с сервером"); + } + }); + } + + /** + * Проверить доступ к серверу + */ + public CompletableFuture checkServerAccess(String nickname) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/plugin/server-access?nickname=" + nickname; + HttpResponse response = makeRequest(url, "GET", null); + + if (response.statusCode() == 200) { + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + return json.has("hasAccess") && json.get("hasAccess").getAsBoolean(); + } + return false; + } catch (Exception e) { + logger.severe("Ошибка проверки доступа для " + nickname + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Обновить время игры + */ + public CompletableFuture updatePlaytime(int userId, int minutes) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/playtime"; + JsonObject body = new JsonObject(); + body.addProperty("playtime_minutes", minutes); + + HttpResponse response = makeRequest(url, "PUT", body.toString()); + return response.statusCode() == 200; + } catch (Exception e) { + logger.severe("Ошибка обновления времени игры для пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Записать активность игрока + */ + public CompletableFuture recordActivity(int userId, String activityType, String description, String metadata) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/user-activity"; + JsonObject body = new JsonObject(); + body.addProperty("user_id", userId); + body.addProperty("activity_type", activityType); + body.addProperty("description", description); + if (metadata != null) { + body.addProperty("metadata", metadata); + } + + HttpResponse response = makeRequest(url, "POST", body.toString()); + return response.statusCode() == 201 || response.statusCode() == 200; + } catch (Exception e) { + logger.severe("Ошибка записи активности для пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Забанить игрока + */ + public CompletableFuture banPlayer(int userId, String reason) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/ban"; + JsonObject body = new JsonObject(); + body.addProperty("reason", reason); + + HttpResponse response = makeRequest(url, "PUT", body.toString()); + return response.statusCode() == 200; + } catch (Exception e) { + logger.severe("Ошибка бана пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Разбанить игрока + */ + public CompletableFuture unbanPlayer(int userId) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/unban"; + HttpResponse response = makeRequest(url, "PUT", null); + return response.statusCode() == 200; + } catch (Exception e) { + logger.severe("Ошибка разбана пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Изменить trust level + */ + public CompletableFuture updateTrustLevel(int userId, int trustLevel) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/trust-level"; + JsonObject body = new JsonObject(); + body.addProperty("trust_level", trustLevel); + + HttpResponse response = makeRequest(url, "PUT", body.toString()); + return response.statusCode() == 200; + } catch (Exception e) { + logger.severe("Ошибка изменения trust level для пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Обновить репутацию (изменить на указанную величину) + */ + public CompletableFuture updateReputation(int userId, int reputationChange, String reason) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/" + userId + "/reputation/change"; + JsonObject body = new JsonObject(); + body.addProperty("reputation_change", reputationChange); + body.addProperty("reason", reason); + + HttpResponse response = makeRequest(url, "POST", body.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + return jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + } + + return false; + } catch (Exception e) { + logger.severe("Ошибка изменения репутации для пользователя " + userId + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Получить статус сервера + */ + public CompletableFuture getServerInfo() { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/plugin/server-info"; + HttpResponse response = makeRequest(url, "GET", null); + + if (response.statusCode() == 200) { + return JsonParser.parseString(response.body()).getAsJsonObject(); + } + return new JsonObject(); + } catch (Exception e) { + logger.severe("Ошибка получения информации о сервере: " + e.getMessage()); + return new JsonObject(); + } + }); + } + + /** + * Выполнить HTTP запрос с повторными попытками + */ + private HttpResponse makeRequest(String url, String method, String body) throws IOException, InterruptedException { + Exception lastException = null; + + for (int attempt = 1; attempt <= maxRetries; attempt++) { + try { + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder() + .uri(URI.create(url)) + .header("Authorization", "Bearer " + apiKey) + .header("Content-Type", "application/json") + .header("User-Agent", "ChiwawaPlugin/1.0") + .timeout(Duration.ofMillis(timeout)); + + HttpRequest request = switch (method.toUpperCase()) { + case "GET" -> requestBuilder.GET().build(); + case "POST" -> requestBuilder.POST(HttpRequest.BodyPublishers.ofString(body != null ? body : "")).build(); + case "PUT" -> requestBuilder.PUT(HttpRequest.BodyPublishers.ofString(body != null ? body : "")).build(); + case "DELETE" -> requestBuilder.DELETE().build(); + default -> throw new IllegalArgumentException("Неподдерживаемый HTTP метод: " + method); + }; + + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + // Если статус успешный или клиентская ошибка (не требует повтора) + if (response.statusCode() < 500) { + return response; + } + + logger.warning("Попытка " + attempt + " неуспешна. Статус: " + response.statusCode() + ". URL: " + url); + + } catch (Exception e) { + lastException = e; + logger.warning("Попытка " + attempt + " провалена для " + url + ": " + e.getMessage()); + } + + // Пауза перед следующей попыткой + if (attempt < maxRetries) { + try { + TimeUnit.MILLISECONDS.sleep(1000 * attempt); // Экспоненциальная задержка + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw e; + } + } + } + + throw new IOException("Все " + maxRetries + " попыток провалены для " + url, lastException); + } + + /** + * Создание игровой сессии после успешной авторизации + */ + public CompletableFuture createGameSession(String nickname, String playerUuid, String ipAddress, String userAgent) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/auth/create-game-session"; + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("nickname", nickname); + requestBody.addProperty("player_uuid", playerUuid); + requestBody.addProperty("ip_address", ipAddress); + requestBody.addProperty("user_agent", userAgent); + + HttpResponse response = makeRequest(url, "POST", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + return jsonResponse.get("success").getAsBoolean(); + } else { + logger.warning("Не удалось создать игровую сессию: " + response.statusCode() + " - " + response.body()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка создания игровой сессии: " + e.getMessage()); + return false; + } + }); + } + + /** + * Проверка активной игровой сессии + */ + public CompletableFuture checkGameSession(String nickname, String playerUuid, String ipAddress) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/auth/check-game-session"; + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("nickname", nickname); + requestBody.addProperty("player_uuid", playerUuid); + requestBody.addProperty("ip_address", ipAddress); + + HttpResponse response = makeRequest(url, "POST", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + + if (jsonResponse.get("session_valid").getAsBoolean()) { + JsonObject user = jsonResponse.getAsJsonObject("user"); + + return new SessionCheckResult( + true, + user.get("id").getAsInt(), + user.get("nickname").getAsString(), + user.get("role").getAsString(), + user.get("trust_level").getAsInt(), + "Сессия действительна" + ); + } else { + return new SessionCheckResult(false, 0, "", "", 0, + jsonResponse.get("error").getAsString()); + } + } else { + return new SessionCheckResult(false, 0, "", "", 0, + "Сессия не найдена или истекла"); + } + } catch (Exception e) { + logger.severe("Ошибка проверки игровой сессии: " + e.getMessage()); + return new SessionCheckResult(false, 0, "", "", 0, + "Ошибка соединения с сервером"); + } + }); + } + + /** + * Отправка детальной статистики игрока на сервер + */ + public CompletableFuture updatePlayerStats(String minecraftNick, java.util.Map stats) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/profile/update-stats"; + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("minecraft_nick", minecraftNick); + // Убираем admin_token из тела - теперь используется заголовок Authorization + + // Конвертируем статистику в JSON + JsonObject statsJson = gson.toJsonTree(stats).getAsJsonObject(); + requestBody.add("stats", statsJson); + + HttpResponse response = makeRequest(url, "POST", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.fine("Статистика игрока " + minecraftNick + " успешно обновлена"); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка обновления статистики игрока " + minecraftNick + ": " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при обновлении статистики игрока " + minecraftNick + ": " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка отправки статистики игрока " + minecraftNick + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Отправка данных о состоянии сервера (TPS, память, время работы) + */ + public CompletableFuture updateServerData(String serverIp, int serverPort, double tps, long uptimeSeconds, + long maxMemory, long usedMemory, long freeMemory, + int onlinePlayers, int maxPlayers, String serverVersion, + int pluginsCount, int loadedWorlds) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/settings/server-data"; + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("server_ip", serverIp); + requestBody.addProperty("server_port", serverPort); + requestBody.addProperty("tps", tps); + requestBody.addProperty("uptime_seconds", uptimeSeconds); + requestBody.addProperty("max_memory", maxMemory); + requestBody.addProperty("used_memory", usedMemory); + requestBody.addProperty("free_memory", freeMemory); + requestBody.addProperty("online_players", onlinePlayers); + requestBody.addProperty("max_players", maxPlayers); + requestBody.addProperty("server_version", serverVersion); + requestBody.addProperty("plugins_count", pluginsCount); + requestBody.addProperty("loaded_worlds", loadedWorlds); + + HttpResponse response = makeRequest(url, "POST", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.fine("Данные сервера успешно обновлены"); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка обновления данных сервера: " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при обновлении данных сервера: " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка отправки данных сервера: " + e.getMessage()); + return false; + } + }); + } + + /** + * Проверка соединения с API + */ + public CompletableFuture testConnection() { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/plugin/server-info"; + HttpResponse response = makeRequest(url, "GET", null); + + if (response.statusCode() == 200) { + JsonObject json = JsonParser.parseString(response.body()).getAsJsonObject(); + return json.has("success") && json.get("success").getAsBoolean(); + } + return false; + } catch (Exception e) { + logger.severe("Ошибка проверки соединения с API: " + e.getMessage()); + return false; + } + }); + } + + /** + * Отправить кастомный email через API сайта + */ + public CompletableFuture sendCustomEmail(String email, String subject, String message) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/auth/send-custom-email"; + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("email", email); + requestBody.addProperty("subject", subject); + requestBody.addProperty("message", message); + + HttpResponse response = makeRequest(url, "POST", requestBody.toString()); + + if (response.statusCode() == 200 || response.statusCode() == 201) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.fine("Email успешно отправлен на " + email); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка отправки email: " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при отправке email: " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка отправки email: " + e.getMessage()); + return false; + } + }); + } + + /** + * Забанить игрока (по никнейму - для оффлайн игроков) + */ + public CompletableFuture banPlayerByNickname(String nickname, String reason) { + return banPlayerByNickname(nickname, reason, 0); // 0 дней = постоянный бан + } + + /** + * Забанить игрока с указанием количества дней (по никнейму - для оффлайн игроков) + */ + public CompletableFuture banPlayerByNickname(String nickname, String reason, int days) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/0/ban"; // ID не важен, используется nickname + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("reason", reason); + requestBody.addProperty("minecraft_nick", nickname); + + if (days > 0) { + requestBody.addProperty("type", "temporary"); + requestBody.addProperty("duration", days); + requestBody.addProperty("unit", "days"); + } else { + requestBody.addProperty("type", "permanent"); + } + + HttpResponse response = makeRequest(url, "PUT", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + if (days > 0) { + logger.info("Игрок " + nickname + " успешно забанен на " + days + " дней"); + } else { + logger.info("Игрок " + nickname + " успешно забанен навсегда"); + } + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка бана игрока " + nickname + ": " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при бане игрока " + nickname + ": " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка бана игрока " + nickname + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Разбанить игрока (по никнейму - для оффлайн игроков) + */ + public CompletableFuture unbanPlayerByNickname(String nickname) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/0/unban"; // ID не важен, используется nickname + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("minecraft_nick", nickname); + + HttpResponse response = makeRequest(url, "PUT", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.info("Игрок " + nickname + " успешно разбанен"); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка разбана игрока " + nickname + ": " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при разбане игрока " + nickname + ": " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка разбана игрока " + nickname + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Обновить Trust Level игрока (по никнейму - для оффлайн игроков) + */ + public CompletableFuture updateTrustLevelByNickname(String nickname, int trustLevel) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/0/trust-level"; // ID не важен, используется nickname + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("level", trustLevel); + requestBody.addProperty("reason", "Изменение через плагин"); + requestBody.addProperty("minecraft_nick", nickname); + + HttpResponse response = makeRequest(url, "PUT", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.info("Trust Level игрока " + nickname + " изменен на " + trustLevel); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка изменения Trust Level игрока " + nickname + ": " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при изменении Trust Level игрока " + nickname + ": " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка изменения Trust Level игрока " + nickname + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Установить репутацию игрока (по никнейму - для оффлайн игроков) + */ + public CompletableFuture setReputationByNickname(String nickname, int reputation, String reason) { + return CompletableFuture.supplyAsync(() -> { + try { + String url = baseUrl + "/admin/users/0/reputation"; // ID не важен, используется nickname + + JsonObject requestBody = new JsonObject(); + requestBody.addProperty("reputation", reputation); // УСТАНАВЛИВАЕМ, а не изменяем + requestBody.addProperty("reason", reason); + requestBody.addProperty("minecraft_nick", nickname); + + HttpResponse response = makeRequest(url, "PUT", requestBody.toString()); + + if (response.statusCode() == 200) { + JsonObject jsonResponse = JsonParser.parseString(response.body()).getAsJsonObject(); + boolean success = jsonResponse.has("success") && jsonResponse.get("success").getAsBoolean(); + + if (success) { + logger.info("Репутация игрока " + nickname + " установлена в " + reputation); + } else { + String error = jsonResponse.has("error") ? jsonResponse.get("error").getAsString() : "Неизвестная ошибка"; + logger.warning("Ошибка установки репутации игрока " + nickname + ": " + error); + } + + return success; + } else { + logger.warning("Ошибка HTTP при установке репутации игрока " + nickname + ": " + response.statusCode()); + return false; + } + } catch (Exception e) { + logger.severe("Ошибка установки репутации игрока " + nickname + ": " + e.getMessage()); + return false; + } + }); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ApiResponse.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ApiResponse.java new file mode 100644 index 00000000000..2fa56bd91e0 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ApiResponse.java @@ -0,0 +1,82 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * Общий DTO для ответов API + */ +public class ApiResponse { + @SerializedName("success") + private boolean success; + + @SerializedName("message") + private String message; + + @SerializedName("data") + private T data; + + @SerializedName("error") + private String error; + + // Конструкторы + public ApiResponse() {} + + public ApiResponse(boolean success, String message, T data) { + this.success = success; + this.message = message; + this.data = data; + } + + public static ApiResponse success(T data) { + return new ApiResponse<>(true, "Success", data); + } + + public static ApiResponse success(String message, T data) { + return new ApiResponse<>(true, message, data); + } + + public static ApiResponse error(String error) { + ApiResponse response = new ApiResponse<>(); + response.success = false; + response.error = error; + return response; + } + + // Getters и Setters + public boolean isSuccess() { return success; } + public void setSuccess(boolean success) { this.success = success; } + + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } + + public T getData() { return data; } + public void setData(T data) { this.data = data; } + + public String getError() { return error; } + public void setError(String error) { this.error = error; } + + /** + * Проверить успешность ответа + */ + public boolean hasError() { + return !success || error != null; + } + + /** + * Получить сообщение об ошибке или обычное сообщение + */ + public String getMessageOrError() { + return hasError() ? error : message; + } + + @Override + public String toString() { + return "ApiResponse{" + + "success=" + success + + ", message='" + message + '\'' + + ", error='" + error + '\'' + + ", hasData=" + (data != null) + + '}'; + } +} + diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/Application.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/Application.java new file mode 100644 index 00000000000..25275cbe50d --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/Application.java @@ -0,0 +1,112 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * DTO для заявки из таблицы applications + */ +public class Application { + @SerializedName("id") + private int id; + + @SerializedName("user_id") + private int userId; + + @SerializedName("minecraft_nick") + private String minecraftNick; + + @SerializedName("email") + private String email; + + @SerializedName("discord") + private String discord; + + @SerializedName("status") + private String status; // 'pending'|'approved'|'rejected' + + @SerializedName("motivation") + private String motivation; + + @SerializedName("plans") + private String plans; + + @SerializedName("submitted_at") + private String submittedAt; + + @SerializedName("reviewed_at") + private String reviewedAt; + + // Конструкторы + public Application() {} + + public Application(int userId, String minecraftNick, String email) { + this.userId = userId; + this.minecraftNick = minecraftNick; + this.email = email; + this.status = "pending"; + } + + // Getters и Setters + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public int getUserId() { return userId; } + public void setUserId(int userId) { this.userId = userId; } + + public String getMinecraftNick() { return minecraftNick; } + public void setMinecraftNick(String minecraftNick) { this.minecraftNick = minecraftNick; } + + public String getEmail() { return email; } + public void setEmail(String email) { this.email = email; } + + public String getDiscord() { return discord; } + public void setDiscord(String discord) { this.discord = discord; } + + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + + public String getMotivation() { return motivation; } + public void setMotivation(String motivation) { this.motivation = motivation; } + + public String getPlans() { return plans; } + public void setPlans(String plans) { this.plans = plans; } + + public String getSubmittedAt() { return submittedAt; } + public void setSubmittedAt(String submittedAt) { this.submittedAt = submittedAt; } + + public String getReviewedAt() { return reviewedAt; } + public void setReviewedAt(String reviewedAt) { this.reviewedAt = reviewedAt; } + + /** + * Проверить, одобрена ли заявка + */ + public boolean isApproved() { + return "approved".equals(status); + } + + /** + * Проверить, отклонена ли заявка + */ + public boolean isRejected() { + return "rejected".equals(status); + } + + /** + * Проверить, на рассмотрении ли заявка + */ + public boolean isPending() { + return "pending".equals(status); + } + + @Override + public String toString() { + return "Application{" + + "id=" + id + + ", userId=" + userId + + ", minecraftNick='" + minecraftNick + '\'' + + ", status='" + status + '\'' + + ", submittedAt='" + submittedAt + '\'' + + '}'; + } +} + diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/AuthPlayer.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/AuthPlayer.java new file mode 100644 index 00000000000..503affcaaed --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/AuthPlayer.java @@ -0,0 +1,156 @@ +package org.ebluffy.chiwawa.api.dto; + +import java.time.LocalDateTime; + +/** + * DTO для игрока с простой авторизацией + */ +public class AuthPlayer { + private int id; + private String username; + private String passwordHash; + private String uuid; + private String ipAddress; + private LocalDateTime lastLogin; + private LocalDateTime registeredAt; + private int loginType; // 0 = обычная, 1 = через сайт + private String email; + private String emailVerificationCode; + private LocalDateTime emailVerificationExpires; + + public AuthPlayer() { + } + + public AuthPlayer(String username, String passwordHash, String uuid, String ipAddress, int loginType) { + this.username = username; + this.passwordHash = passwordHash; + this.uuid = uuid; + this.ipAddress = ipAddress; + this.loginType = loginType; + } + + // Геттеры и сеттеры + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPasswordHash() { + return passwordHash; + } + + public void setPasswordHash(String passwordHash) { + this.passwordHash = passwordHash; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + public LocalDateTime getLastLogin() { + return lastLogin; + } + + public void setLastLogin(LocalDateTime lastLogin) { + this.lastLogin = lastLogin; + } + + public LocalDateTime getRegisteredAt() { + return registeredAt; + } + + public void setRegisteredAt(LocalDateTime registeredAt) { + this.registeredAt = registeredAt; + } + + public int getLoginType() { + return loginType; + } + + public void setLoginType(int loginType) { + this.loginType = loginType; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getEmailVerificationCode() { + return emailVerificationCode; + } + + public void setEmailVerificationCode(String emailVerificationCode) { + this.emailVerificationCode = emailVerificationCode; + } + + public LocalDateTime getEmailVerificationExpires() { + return emailVerificationExpires; + } + + public void setEmailVerificationExpires(LocalDateTime emailVerificationExpires) { + this.emailVerificationExpires = emailVerificationExpires; + } + + /** + * Проверить, истек ли срок действия кода подтверждения + */ + public boolean isVerificationExpired() { + if (emailVerificationExpires == null) { + return true; + } + return LocalDateTime.now().isAfter(emailVerificationExpires); + } + + /** + * Использует ли игрок авторизацию через сайт + */ + public boolean isWebsiteAuth() { + return loginType == 1; + } + + /** + * Использует ли игрок простую авторизацию + */ + public boolean isSimpleAuth() { + return loginType == 0; + } + + @Override + public String toString() { + return "AuthPlayer{" + + "id=" + id + + ", username='" + username + '\'' + + ", uuid='" + uuid + '\'' + + ", loginType=" + (loginType == 0 ? "Простая" : "Через сайт") + + ", email='" + email + '\'' + + ", registeredAt=" + registeredAt + + '}'; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ChiwawaUser.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ChiwawaUser.java new file mode 100644 index 00000000000..2fcd8f5650a --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/ChiwawaUser.java @@ -0,0 +1,220 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * DTO для пользователя из таблицы users + */ +public class ChiwawaUser { + @SerializedName("id") + private int id; + + @SerializedName("nickname") + private String nickname; + + @SerializedName("email") + private String email; + + @SerializedName("first_name") + private String firstName; + + @SerializedName("last_name") + private String lastName; + + @SerializedName("role") + private String role; // 'user'|'admin'|'moderator' + + @SerializedName("trust_level") + private int trustLevel; // 0-3 + + @SerializedName("is_active") + private boolean isActive; + + @SerializedName("is_email_verified") + private boolean isEmailVerified; + + @SerializedName("is_banned") + private boolean isBanned; + + @SerializedName("registered_at") + private String registeredAt; + + @SerializedName("last_login") + private String lastLogin; + + @SerializedName("ban_reason") + private String banReason; + + @SerializedName("ban_until") + private String banUntil; + + // Конструкторы + public ChiwawaUser() {} + + public ChiwawaUser(String nickname) { + this.nickname = nickname; + } + + // Getters и Setters + public int getId() { return id; } + public void setId(int id) { this.id = id; } + + public String getNickname() { return nickname; } + public void setNickname(String nickname) { this.nickname = nickname; } + + public String getEmail() { return email; } + public void setEmail(String email) { this.email = email; } + + public String getFirstName() { return firstName; } + public void setFirstName(String firstName) { this.firstName = firstName; } + + public String getLastName() { return lastName; } + public void setLastName(String lastName) { this.lastName = lastName; } + + public String getRole() { return role; } + public void setRole(String role) { this.role = role; } + + public int getTrustLevel() { return trustLevel; } + public void setTrustLevel(int trustLevel) { this.trustLevel = trustLevel; } + + public boolean isActive() { return isActive; } + public void setActive(boolean active) { isActive = active; } + + public boolean isEmailVerified() { return isEmailVerified; } + public void setEmailVerified(boolean emailVerified) { isEmailVerified = emailVerified; } + + public boolean isBanned() { return isBanned; } + public void setBanned(boolean banned) { isBanned = banned; } + + public String getRegisteredAt() { return registeredAt; } + public void setRegisteredAt(String registeredAt) { this.registeredAt = registeredAt; } + + public String getLastLogin() { return lastLogin; } + public void setLastLogin(String lastLogin) { this.lastLogin = lastLogin; } + + public String getBanReason() { return banReason; } + public void setBanReason(String banReason) { this.banReason = banReason; } + + public String getBanUntil() { return banUntil; } + public void setBanUntil(String banUntil) { this.banUntil = banUntil; } + + /** + * Проверяет, имеет ли игрок доступ к серверу + */ + public boolean hasServerAccess() { + return isActive && !isBanned; + } + + /** + * Проверяет, является ли игрок проходимцем (trust level 0) + */ + public boolean isNewcomer() { + return trustLevel == 0; + } + + /** + * Получить название trust level + */ + public String getTrustLevelName() { + return switch (trustLevel) { + case 0 -> "Проходимец"; + case 1 -> "Новичок"; + case 2 -> "Проверенный"; + case 3 -> "Ветеран"; + default -> "Неизвестный"; + }; + } + + /** + * Получить описание Trust Level + */ + public String getTrustLevelDescription() { + switch (trustLevel) { + case 0: return "Проходимец"; + case 1: return "Новичок"; + case 2: return "Проверенный"; + case 3: return "Ветеран"; + default: return "Неизвестный"; + } + } + + /** + * Проверяет, имеет ли пользователь лимит времени + */ + public boolean hasTimeLimit() { + return trustLevel == 0 && !isEmailVerified; + } + + /** + * Проверяет, является ли пользователь администратором + */ + public boolean isAdmin() { + return "admin".equals(role); + } + + /** + * Проверяет, является ли пользователь модератором или выше + */ + public boolean isModerator() { + return "moderator".equals(role) || "admin".equals(role); + } + + /** + * Получить отформатированное время до окончания бана + */ + public String getFormattedBanTimeRemaining() { + if (banUntil == null || banUntil.isEmpty()) { + return "Постоянно"; + } + + try { + // Парсим дату из ISO формата + java.time.LocalDateTime banDate = java.time.LocalDateTime.parse(banUntil.replace("Z", "").replace("+00", "")); + java.time.LocalDateTime now = java.time.LocalDateTime.now(); + + if (banDate.isBefore(now)) { + return "Бан истек"; + } + + java.time.Duration duration = java.time.Duration.between(now, banDate); + long days = duration.toDays(); + long hours = duration.toHours() % 24; + long minutes = duration.toMinutes() % 60; + + if (days > 0) { + return days + "д " + hours + "ч " + minutes + "м"; + } else if (hours > 0) { + return hours + "ч " + minutes + "м"; + } else { + return minutes + "м"; + } + } catch (Exception e) { + return "Ошибка расчета времени"; + } + } + + @Override + public String toString() { + return "ChiwawaUser{" + + "id=" + id + + ", nickname='" + nickname + '\'' + + ", role='" + role + '\'' + + ", trustLevel=" + trustLevel + + ", isActive=" + isActive + + ", isBanned=" + isBanned + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ChiwawaUser that = (ChiwawaUser) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Integer.hashCode(id); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/PlayerStats.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/PlayerStats.java new file mode 100644 index 00000000000..23ff2c6b254 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/PlayerStats.java @@ -0,0 +1,129 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * DTO для статистики игрока из таблицы player_stats + */ +public class PlayerStats { + @SerializedName("user_id") + private int userId; + + @SerializedName("total_minutes") + private int totalMinutes; + + @SerializedName("time_played_minutes") + private int timePlayedMinutes; + + @SerializedName("is_time_limited") + private boolean isTimeLimited; + + @SerializedName("current_level") + private int currentLevel; + + @SerializedName("email_verified") + private boolean emailVerified; + + @SerializedName("discord_verified") + private boolean discordVerified; + + @SerializedName("minecraft_verified") + private boolean minecraftVerified; + + @SerializedName("reputation") + private int reputation; + + @SerializedName("achievements_count") + private int achievementsCount; + + @SerializedName("total_logins") + private int totalLogins; + + @SerializedName("warnings_count") + private int warningsCount; + + // Конструкторы + public PlayerStats() {} + + public PlayerStats(int userId) { + this.userId = userId; + } + + // Getters и Setters + public int getUserId() { return userId; } + public void setUserId(int userId) { this.userId = userId; } + + public int getTotalMinutes() { return totalMinutes; } + public void setTotalMinutes(int totalMinutes) { this.totalMinutes = totalMinutes; } + + public int getTimePlayedMinutes() { return timePlayedMinutes; } + public void setTimePlayedMinutes(int timePlayedMinutes) { this.timePlayedMinutes = timePlayedMinutes; } + + public boolean isTimeLimited() { return isTimeLimited; } + public void setTimeLimited(boolean timeLimited) { isTimeLimited = timeLimited; } + + public int getCurrentLevel() { return currentLevel; } + public void setCurrentLevel(int currentLevel) { this.currentLevel = currentLevel; } + + public boolean isEmailVerified() { return emailVerified; } + public void setEmailVerified(boolean emailVerified) { this.emailVerified = emailVerified; } + + public boolean isDiscordVerified() { return discordVerified; } + public void setDiscordVerified(boolean discordVerified) { this.discordVerified = discordVerified; } + + public boolean isMinecraftVerified() { return minecraftVerified; } + public void setMinecraftVerified(boolean minecraftVerified) { this.minecraftVerified = minecraftVerified; } + + public int getReputation() { return reputation; } + public void setReputation(int reputation) { this.reputation = reputation; } + + public int getAchievementsCount() { return achievementsCount; } + public void setAchievementsCount(int achievementsCount) { this.achievementsCount = achievementsCount; } + + public int getTotalLogins() { return totalLogins; } + public void setTotalLogins(int totalLogins) { this.totalLogins = totalLogins; } + + public int getWarningsCount() { return warningsCount; } + public void setWarningsCount(int warningsCount) { this.warningsCount = warningsCount; } + + /** + * Получить время игры в часах + */ + public double getPlaytimeHours() { + return timePlayedMinutes / 60.0; + } + + /** + * Проверить, превышен ли лимит времени для проходимцев (10 часов) + */ + public boolean isTimeLimitExceeded() { + return isTimeLimited && getPlaytimeHours() >= 10.0; + } + + /** + * Получить оставшееся время для проходимцев в минутах + */ + public int getRemainingMinutes() { + if (!isTimeLimited) return -1; + return Math.max(0, 600 - timePlayedMinutes); // 600 минут = 10 часов + } + + /** + * Форматированное время игры + */ + public String getFormattedPlaytime() { + int hours = timePlayedMinutes / 60; + int minutes = timePlayedMinutes % 60; + return String.format("%dч %dм", hours, minutes); + } + + @Override + public String toString() { + return "PlayerStats{" + + "userId=" + userId + + ", timePlayedMinutes=" + timePlayedMinutes + + ", reputation=" + reputation + + ", isTimeLimited=" + isTimeLimited + + '}'; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/SessionCheckResult.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/SessionCheckResult.java new file mode 100644 index 00000000000..cec2aae0396 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/SessionCheckResult.java @@ -0,0 +1,46 @@ +package org.ebluffy.chiwawa.api.dto; + +/** + * Результат проверки игровой сессии + */ +public class SessionCheckResult { + private final boolean valid; + private final int userId; + private final String nickname; + private final String role; + private final int trustLevel; + private final String message; + + public SessionCheckResult(boolean valid, int userId, String nickname, String role, int trustLevel, String message) { + this.valid = valid; + this.userId = userId; + this.nickname = nickname; + this.role = role; + this.trustLevel = trustLevel; + this.message = message; + } + + public boolean isValid() { + return valid; + } + + public int getUserId() { + return userId; + } + + public String getNickname() { + return nickname; + } + + public String getRole() { + return role; + } + + public int getTrustLevel() { + return trustLevel; + } + + public String getMessage() { + return message; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/TokenVerificationResult.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/TokenVerificationResult.java new file mode 100644 index 00000000000..c131977bf79 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/TokenVerificationResult.java @@ -0,0 +1,58 @@ +package org.ebluffy.chiwawa.api.dto; + +/** + * Результат проверки игрового токена + */ +public class TokenVerificationResult { + private final boolean valid; + private final int userId; + private final String nickname; + private final String role; + private final int trustLevel; + private final String message; + + public TokenVerificationResult(boolean valid, int userId, String nickname, String role, int trustLevel, String message) { + this.valid = valid; + this.userId = userId; + this.nickname = nickname; + this.role = role; + this.trustLevel = trustLevel; + this.message = message; + } + + public boolean isValid() { + return valid; + } + + public int getUserId() { + return userId; + } + + public String getNickname() { + return nickname; + } + + public String getRole() { + return role; + } + + public int getTrustLevel() { + return trustLevel; + } + + public String getMessage() { + return message; + } + + @Override + public String toString() { + return "TokenVerificationResult{" + + "valid=" + valid + + ", userId=" + userId + + ", nickname='" + nickname + '\'' + + ", role='" + role + '\'' + + ", trustLevel=" + trustLevel + + ", message='" + message + '\'' + + '}'; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/UserActivity.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/UserActivity.java new file mode 100644 index 00000000000..f1f95c697ef --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/UserActivity.java @@ -0,0 +1,86 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * DTO для активности пользователя из таблицы user_activity + */ +public class UserActivity { + @SerializedName("user_id") + private int userId; + + @SerializedName("activity_type") + private String activityType; // 'login', 'logout', 'join_server', 'leave_server', 'playtime_update' + + @SerializedName("description") + private String description; + + @SerializedName("metadata") + private String metadata; // JSON строка + + @SerializedName("created_at") + private String createdAt; + + // Конструкторы + public UserActivity() {} + + public UserActivity(int userId, String activityType, String description) { + this.userId = userId; + this.activityType = activityType; + this.description = description; + } + + public UserActivity(int userId, String activityType, String description, String metadata) { + this.userId = userId; + this.activityType = activityType; + this.description = description; + this.metadata = metadata; + } + + // Getters и Setters + public int getUserId() { return userId; } + public void setUserId(int userId) { this.userId = userId; } + + public String getActivityType() { return activityType; } + public void setActivityType(String activityType) { this.activityType = activityType; } + + public String getDescription() { return description; } + public void setDescription(String description) { this.description = description; } + + public String getMetadata() { return metadata; } + public void setMetadata(String metadata) { this.metadata = metadata; } + + public String getCreatedAt() { return createdAt; } + public void setCreatedAt(String createdAt) { this.createdAt = createdAt; } + + /** + * Проверить, является ли активность входом на сервер + */ + public boolean isServerJoin() { + return "join_server".equals(activityType); + } + + /** + * Проверить, является ли активность выходом с сервера + */ + public boolean isServerLeave() { + return "leave_server".equals(activityType); + } + + /** + * Проверить, является ли активность обновлением времени игры + */ + public boolean isPlaytimeUpdate() { + return "playtime_update".equals(activityType); + } + + @Override + public String toString() { + return "UserActivity{" + + "userId=" + userId + + ", activityType='" + activityType + '\'' + + ", description='" + description + '\'' + + ", createdAt='" + createdAt + '\'' + + '}'; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/WhitelistResponse.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/WhitelistResponse.java new file mode 100644 index 00000000000..d20dbe0acce --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/api/dto/WhitelistResponse.java @@ -0,0 +1,49 @@ +package org.ebluffy.chiwawa.api.dto; + +import com.google.gson.annotations.SerializedName; + +/** + * DTO для ответа проверки whitelist + */ +public class WhitelistResponse { + @SerializedName("hasAccess") + private boolean hasAccess; + + @SerializedName("reason") + private String reason; + + @SerializedName("user") + private ChiwawaUser user; + + @SerializedName("application") + private Application application; + + // Конструкторы + public WhitelistResponse() {} + + public WhitelistResponse(boolean hasAccess, String reason) { + this.hasAccess = hasAccess; + this.reason = reason; + } + + // Getters и Setters + public boolean hasAccess() { return hasAccess; } + public void setHasAccess(boolean hasAccess) { this.hasAccess = hasAccess; } + + public String getReason() { return reason; } + public void setReason(String reason) { this.reason = reason; } + + public ChiwawaUser getUser() { return user; } + public void setUser(ChiwawaUser user) { this.user = user; } + + public Application getApplication() { return application; } + public void setApplication(Application application) { this.application = application; } + + @Override + public String toString() { + return "WhitelistResponse{" + + "hasAccess=" + hasAccess + + ", reason='" + reason + '\'' + + '}'; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ApplicationsCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ApplicationsCommand.java new file mode 100644 index 00000000000..5f675882925 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ApplicationsCommand.java @@ -0,0 +1,44 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.Application; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.UserManager; + +/** + * Команда /applications для просмотра статуса заявки + */ +public class ApplicationsCommand implements CommandExecutor { + private final ConfigManager configManager; + private final UserManager userManager; + + public ApplicationsCommand(ConfigManager configManager, UserManager userManager) { + this.configManager = configManager; + this.userManager = userManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Показываем информацию о заявках + showApplicationInfo(player); + return true; + } + + private void showApplicationInfo(Player player) { + player.sendMessage("§e═════ СТАТУС ЗАЯВКИ ═════"); + player.sendMessage("§7Ваша заявка уже одобрена, раз вы находитесь на сервере!"); + player.sendMessage("§7Для получения дополнительной информации посетите:"); + player.sendMessage("§b§nhttps://chiwawa.site"); + player.sendMessage("§e═══════════════════════"); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangeLoginCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangeLoginCommand.java new file mode 100644 index 00000000000..b00b1ea1f11 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangeLoginCommand.java @@ -0,0 +1,237 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.AuthPlayer; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.AuthManager; + +import java.util.Optional; +import java.util.logging.Logger; + +/** + * Команда для смены режима авторизации (/changelogin) + */ +public class ChangeLoginCommand implements CommandExecutor { + private final ConfigManager configManager; + private final AuthManager authManager; + private final Logger logger; + + public ChangeLoginCommand(ConfigManager configManager, AuthManager authManager, Logger logger) { + this.configManager = configManager; + this.authManager = authManager; + this.logger = logger; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Проверка авторизации + if (!authManager.isPlayerAuthorized(player.getUniqueId())) { + player.sendMessage("§cВы должны быть авторизованы для использования этой команды!"); + return true; + } + + // Получаем данные игрока + Optional authPlayerOpt = authManager.getAuthorizedPlayer(player.getUniqueId()); + if (authPlayerOpt.isEmpty()) { + player.sendMessage("§cОшибка получения данных игрока"); + return true; + } + + AuthPlayer authPlayer = authPlayerOpt.get(); + + // Если уже используется авторизация через сайт + if (authPlayer.isWebsiteAuth()) { + player.sendMessage("§e§lВы уже используете авторизацию через сайт!"); + player.sendMessage("§7Чтобы вернуться к простой авторизации,"); + player.sendMessage("§7обратитесь к администрации на сайте:"); + player.sendMessage("§b§nhttps://chiwawa.site"); + return true; + } + + // Обработка подкоманд + if (args.length == 0) { + // Показываем информацию о команде + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + player.sendMessage("§6§l СМЕНА РЕЖИМА АВТОРИЗАЦИИ"); + player.sendMessage(""); + player.sendMessage("§7Текущий режим: §c§lПростая авторизация"); + player.sendMessage("§7(логин и пароль на сервере)"); + player.sendMessage(""); + player.sendMessage("§a§lПреимущества авторизации через сайт:"); + player.sendMessage("§7• Единый вход для сайта и сервера"); + player.sendMessage("§7• Восстановление доступа через email"); + player.sendMessage("§7• Дополнительная защита аккаунта"); + player.sendMessage("§7• Управление профилем на сайте"); + player.sendMessage(""); + player.sendMessage("§eДля смены режима используйте:"); + player.sendMessage("§a/changelogin start §7- Начать процесс смены"); + player.sendMessage("§a/changelogin confirm <код> §7- Подтвердить код с email"); + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + return true; + } + + String subCommand = args[0].toLowerCase(); + + switch (subCommand) { + case "start": + handleStartChange(player); + break; + + case "confirm": + if (args.length < 2) { + player.sendMessage("§cИспользование: /changelogin confirm <код>"); + player.sendMessage("§7Введите 6-значный код из email"); + return true; + } + handleConfirmChange(player, args[1]); + break; + + default: + player.sendMessage("§cНеизвестная подкоманда!"); + player.sendMessage("§7Используйте: §a/changelogin §7для справки"); + break; + } + + return true; + } + + /** + * Начать процесс смены режима + */ + private void handleStartChange(Player player) { + player.sendMessage("§7Проверка возможности смены режима..."); + + authManager.requestAuthModeChange(player) + .thenAccept(result -> { + if (result.startsWith("SUCCESS:")) { + String email = result.substring(8); + String maskedEmail = maskEmail(email); + + player.sendMessage("§a§l✓ Запрос отправлен!"); + player.sendMessage("§7На ваш email §b" + maskedEmail + " §7отправлен"); + player.sendMessage("§76-значный код подтверждения"); + player.sendMessage(""); + player.sendMessage("§eПосле получения кода используйте:"); + player.sendMessage("§a/changelogin confirm <код>"); + player.sendMessage(""); + player.sendMessage("§7§oКод действителен 15 минут"); + + logger.info("Игрок " + player.getName() + " запросил смену режима авторизации"); + + } else { + handleError(player, result); + } + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка соединения!"); + player.sendMessage("§7Попробуйте позже"); + logger.severe("Ошибка запроса смены режима для " + player.getName() + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Подтвердить смену режима кодом + */ + private void handleConfirmChange(Player player, String code) { + // Валидация кода + if (!code.matches("\\d{6}")) { + player.sendMessage("§cНеверный формат кода!"); + player.sendMessage("§7Код должен состоять из 6 цифр"); + return; + } + + player.sendMessage("§7Проверка кода подтверждения..."); + + authManager.confirmAuthModeChange(player, code) + .thenAccept(success -> { + if (success) { + player.sendMessage("§a§l✓ Режим авторизации изменен!"); + player.sendMessage("§7Теперь вы используете авторизацию через сайт"); + player.sendMessage(""); + player.sendMessage("§e§lВажно:"); + player.sendMessage("§7При следующем входе используйте команду:"); + player.sendMessage("§a/login <токен>"); + player.sendMessage("§7Токен можно получить на сайте:"); + player.sendMessage("§b§nhttps://chiwawa.site"); + player.sendMessage(""); + player.sendMessage("§7Ваша текущая сессия останется активной"); + + logger.info("Игрок " + player.getName() + " успешно переключился на авторизацию через сайт"); + + } else { + player.sendMessage("§c§l✗ Неверный или истекший код!"); + player.sendMessage("§7Код действителен только 15 минут"); + player.sendMessage("§7Запросите новый код: §a/changelogin start"); + } + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка подтверждения!"); + player.sendMessage("§7Попробуйте позже"); + logger.severe("Ошибка подтверждения смены режима для " + player.getName() + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Обработать ошибку запроса + */ + private void handleError(Player player, String errorCode) { + switch (errorCode) { + case "EMAIL_NOT_FOUND": + player.sendMessage("§c§l✗ Email не найден!"); + player.sendMessage("§7Для использования авторизации через сайт"); + player.sendMessage("§7необходимо зарегистрироваться на сайте:"); + player.sendMessage("§b§nhttps://chiwawa.site"); + player.sendMessage(""); + player.sendMessage("§7После регистрации подайте заявку на доступ"); + player.sendMessage("§7к серверу через личный кабинет"); + break; + + case "EMAIL_SEND_ERROR": + player.sendMessage("§c§l✗ Ошибка отправки email!"); + player.sendMessage("§7Не удалось отправить код подтверждения"); + player.sendMessage("§7Попробуйте позже или обратитесь к администрации"); + break; + + case "DB_ERROR": + player.sendMessage("§c§l✗ Ошибка базы данных!"); + player.sendMessage("§7Попробуйте позже"); + break; + + default: + player.sendMessage("§c§l✗ Неизвестная ошибка!"); + player.sendMessage("§7Код ошибки: " + errorCode); + break; + } + } + + /** + * Замаскировать email для безопасности + */ + private String maskEmail(String email) { + int atIndex = email.indexOf('@'); + if (atIndex <= 2) { + return email.charAt(0) + "***@" + email.substring(atIndex + 1); + } + + String localPart = email.substring(0, atIndex); + String domain = email.substring(atIndex); + + if (localPart.length() <= 3) { + return localPart.charAt(0) + "***" + domain; + } + + return localPart.substring(0, 2) + "***" + localPart.charAt(localPart.length() - 1) + domain; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangePasswordCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangePasswordCommand.java new file mode 100644 index 00000000000..47f5d236b1d --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChangePasswordCommand.java @@ -0,0 +1,155 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.AuthPlayer; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.AuthManager; + +import java.util.Optional; +import java.util.logging.Logger; + +/** + * Команда для смены пароля (/changepass <старый_пароль> <новый_пароль> <повтор>) + */ +public class ChangePasswordCommand implements CommandExecutor { + private final ConfigManager configManager; + private final AuthManager authManager; + private final Logger logger; + + public ChangePasswordCommand(ConfigManager configManager, AuthManager authManager, Logger logger) { + this.configManager = configManager; + this.authManager = authManager; + this.logger = logger; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Проверка авторизации + if (!authManager.isPlayerAuthorized(player.getUniqueId())) { + player.sendMessage("§cВы должны быть авторизованы для использования этой команды!"); + return true; + } + + // Получаем данные игрока + Optional authPlayerOpt = authManager.getAuthorizedPlayer(player.getUniqueId()); + if (authPlayerOpt.isEmpty()) { + player.sendMessage("§cОшибка получения данных игрока"); + return true; + } + + AuthPlayer authPlayer = authPlayerOpt.get(); + + // Проверяем, использует ли игрок простую авторизацию + if (authPlayer.isWebsiteAuth()) { + player.sendMessage("§c§lВы используете авторизацию через сайт!"); + player.sendMessage("§7Для смены пароля используйте сайт:"); + player.sendMessage("§b§nhttps://chiwawa.site/profile/security"); + return true; + } + + if (args.length != 3) { + player.sendMessage("§cИспользование: /changepass <старый_пароль> <новый_пароль> <повтор>"); + player.sendMessage("§7Новый пароль должен быть от 6 до 32 символов"); + return true; + } + + String oldPassword = args[0]; + String newPassword = args[1]; + String newPasswordRepeat = args[2]; + + // Проверка совпадения новых паролей + if (!newPassword.equals(newPasswordRepeat)) { + player.sendMessage("§c§l✗ Новые пароли не совпадают!"); + player.sendMessage("§7Пожалуйста, введите одинаковые пароли"); + return true; + } + + // Проверка, что новый пароль отличается от старого + if (oldPassword.equals(newPassword)) { + player.sendMessage("§c§l✗ Новый пароль должен отличаться от старого!"); + return true; + } + + // Валидация нового пароля + if (!AuthManager.isPasswordValid(newPassword)) { + player.sendMessage("§c§l✗ Недопустимый новый пароль!"); + player.sendMessage("§7Пароль должен:"); + player.sendMessage("§7• Быть от 6 до 32 символов"); + player.sendMessage("§7• Содержать только буквы, цифры и спецсимволы"); + return true; + } + + // Показываем силу нового пароля + String strength = AuthManager.getPasswordStrength(newPassword); + String strengthColor = strength.equals("Сильный") ? "§a" : strength.equals("Средний") ? "§e" : "§c"; + + player.sendMessage("§7Сила нового пароля: " + strengthColor + strength); + player.sendMessage("§7Смена пароля..."); + + // Меняем пароль + authManager.changePassword(player, oldPassword, newPassword) + .thenAccept(success -> { + if (success) { + player.sendMessage("§a§l✓ Пароль успешно изменен!"); + player.sendMessage("§7При следующем входе используйте новый пароль"); + player.sendMessage("§7Запомните его или сохраните в надежном месте"); + + // Логируем изменение пароля + logger.info("Игрок " + player.getName() + " успешно изменил пароль"); + + // Записываем в лог аудита + logPasswordChange(player, true, null); + } else { + player.sendMessage("§c§l✗ Неверный старый пароль!"); + player.sendMessage("§7Пожалуйста, проверьте правильность ввода"); + + // Логируем неудачную попытку + logger.warning("Неудачная попытка смены пароля для игрока " + player.getName()); + logPasswordChange(player, false, "Неверный старый пароль"); + } + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка смены пароля!"); + player.sendMessage("§7Попробуйте позже или обратитесь к администрации"); + + logger.severe("Ошибка смены пароля для игрока " + player.getName() + ": " + throwable.getMessage()); + logPasswordChange(player, false, "Ошибка: " + throwable.getMessage()); + return null; + }); + + return true; + } + + /** + * Логирование изменения пароля + */ + private void logPasswordChange(Player player, boolean success, String reason) { + String logMessage = String.format( + "[PASSWORD_CHANGE] Player: %s, UUID: %s, IP: %s, Success: %s%s", + player.getName(), + player.getUniqueId(), + player.getAddress().getAddress().getHostAddress(), + success, + reason != null ? ", Reason: " + reason : "" + ); + + // Используем отдельный логгер для аудита + java.util.logging.Logger auditLogger = java.util.logging.Logger.getLogger("ChiwawaAudit"); + + if (success) { + auditLogger.info(logMessage); + } else { + auditLogger.warning(logMessage); + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChiwawaCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChiwawaCommand.java new file mode 100644 index 00000000000..ac322be9376 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ChiwawaCommand.java @@ -0,0 +1,609 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import com.google.gson.JsonObject; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.api.dto.PlayerStats; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.PlaytimeManager; +import org.ebluffy.chiwawa.managers.ReputationManager; +import org.ebluffy.chiwawa.managers.UserManager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * Главная команда /chiwawa для администрирования плагина + */ +public class ChiwawaCommand implements CommandExecutor, TabCompleter { + private final JavaPlugin plugin; + private final ConfigManager configManager; + private final UserManager userManager; + private final PlaytimeManager playtimeManager; + private final ReputationManager reputationManager; + private final ApiClient apiClient; + + public ChiwawaCommand(JavaPlugin plugin, ConfigManager configManager, UserManager userManager, + PlaytimeManager playtimeManager, ReputationManager reputationManager, ApiClient apiClient) { + this.plugin = plugin; + this.configManager = configManager; + this.userManager = userManager; + this.playtimeManager = playtimeManager; + this.reputationManager = reputationManager; + this.apiClient = apiClient; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0) { + sendHelp(sender); + return true; + } + + String subCommand = args[0].toLowerCase(); + switch (subCommand) { + case "reload": + return handleReload(sender); + case "sync": + return handleSync(sender, args); + case "ban": + return handleBan(sender, args); + case "unban": + return handleUnban(sender, args); + case "trust": + return handleTrust(sender, args); + case "playtime": + return handlePlaytime(sender, args); + case "rep": + return handleReputation(sender, args); + case "stats": + return handleStats(sender); + default: + sender.sendMessage("§cНеизвестная команда! Используйте /chiwawa для справки."); + return true; + } + } + + /** + * Показать справку по командам + */ + private void sendHelp(CommandSender sender) { + sender.sendMessage("§e§l════════ CHIWAWA КОМАНДЫ ════════"); + + if (hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§7/chiwawa reload §f- Перезагрузить конфиг"); + sender.sendMessage("§7/chiwawa sync <игрок> §f- Синхронизировать данные"); + sender.sendMessage("§7/chiwawa ban <игрок> <причина> §f- Забанить игрока"); + sender.sendMessage("§7/chiwawa unban <игрок> §f- Разбанить игрока"); + sender.sendMessage("§7/chiwawa trust <игрок> <0-3> §f- Изменить Trust Level"); + sender.sendMessage("§7/chiwawa playtime <игрок> §f- Показать время игры"); + sender.sendMessage("§7/chiwawa rep <игрок> <кол-во> [причина] §f- Изменить репутацию"); + sender.sendMessage("§7/chiwawa stats §f- Статистика сервера"); + } else { + sender.sendMessage("§cУ вас нет прав для использования этих команд!"); + } + + sender.sendMessage("§e§l═══════════════════════════════"); + } + + /** + * Перезагрузить конфигурацию и переподключиться к API + */ + private boolean handleReload(CommandSender sender) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + sender.sendMessage("§e§l[RELOAD] §7Начинаем перезагрузку плагина..."); + + // 1. Перезагружаем конфигурацию + sender.sendMessage("§7[1/2] Перезагрузка конфигурации..."); + configManager.reloadConfig(); + + // 2. Тестируем подключение к API + sender.sendMessage("§7[2/2] Проверка подключения к API..."); + apiClient.testConnection().thenAccept(connected -> { + if (connected) { + sender.sendMessage("§a[✓] API соединение восстановлено!"); + } else { + sender.sendMessage("§c[✗] Ошибка подключения к API!"); + } + }); + + // // 3. Очищаем кеш пользователей + // sender.sendMessage("§7[3/4] Очистка кеша пользователей..."); + // userManager.clearCache(); + // sender.sendMessage("§a[✓] Кеш пользователей очищен!"); + + // // 4. Завершаем перезагрузку + // sender.sendMessage("§7[3/3] Завершение..."); + + sender.sendMessage("§a§l[SUCCESS] §fПлагин успешно перезагружен!"); + return true; + } + + /** + * Синхронизировать данные игрока + */ + private boolean handleSync(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 2) { + sender.sendMessage("§cИспользование: /chiwawa sync <игрок>"); + return true; + } + + String playerName = args[1]; + Player targetPlayer = Bukkit.getPlayerExact(playerName); + + if (targetPlayer == null) { + sender.sendMessage("§cИгрок не найден или не в сети!"); + return true; + } + + sender.sendMessage("§7Синхронизация данных игрока " + playerName + "..."); + + userManager.syncPlayer(targetPlayer.getUniqueId()) + .thenAccept(success -> { + if (success) { + sender.sendMessage("§aСинхронизация завершена успешно!"); + } else { + sender.sendMessage("§cОшибка синхронизации данных!"); + } + }); + + return true; + } + + /** + * Забанить игрока + */ + private boolean handleBan(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 3) { + sender.sendMessage("§cИспользование: /chiwawa ban <игрок> <причина> [дни]"); + sender.sendMessage("§7Пример: /chiwawa ban Player Читы 7"); + sender.sendMessage("§7Для постоянного бана не указывайте дни или укажите 0"); + return true; + } + + String playerName = args[1]; + + // Определяем где заканчивается причина и начинается количество дней + int daysIndex = -1; + int daysValue = 0; // 0 означает постоянный бан + + // Проверяем последний аргумент - если это число, то это дни + if (args.length > 3) { + try { + String lastArg = args[args.length - 1]; + daysValue = Integer.parseInt(lastArg); + daysIndex = args.length - 1; + } catch (NumberFormatException e) { + // Последний аргумент не число, значит вся строка после имени - это причина + daysValue = 0; + } + } + + final int days = daysValue; // Делаем final для использования в lambda + + // Формируем причину + String reason; + if (daysIndex > 0) { + // Есть дни в конце, причина до них + reason = String.join(" ", Arrays.copyOfRange(args, 2, daysIndex)); + } else { + // Нет дней, вся строка после имени - причина + reason = String.join(" ", Arrays.copyOfRange(args, 2, args.length)); + } + + // Используем nickname-based бан для поддержки оффлайн игроков + apiClient.banPlayerByNickname(playerName, reason, days) + .thenAccept(success -> { + if (success) { + if (days > 0) { + sender.sendMessage("§aИгрок " + playerName + " забанен на " + days + " дней!"); + sender.sendMessage("§7Причина: " + reason); + } else { + sender.sendMessage("§aИгрок " + playerName + " забанен навсегда!"); + sender.sendMessage("§7Причина: " + reason); + } + + // Кикаем игрока если он онлайн + Player targetPlayer = Bukkit.getPlayerExact(playerName); + if (targetPlayer != null) { + String kickMessage = "§c§lВЫ ЗАБЛОКИРОВАНЫ НА СЕРВЕРЕ\n\n"; + kickMessage += "§fПричина: §c" + reason + "\n\n"; + if (days > 0) { + kickMessage += "§fТип бана: §eВременный (" + days + " дней)\n\n"; + } else { + kickMessage += "§fТип бана: §4Постоянный\n\n"; + } + kickMessage += "§7Обратитесь к администрации для разбана"; + + final String finalKickMessage = kickMessage; + // ВАЖНО: Кик должен происходить в главном потоке! + plugin.getServer().getScheduler().runTask(plugin, () -> { + targetPlayer.kick(net.kyori.adventure.text.Component.text(finalKickMessage)); + }); + + // Уведомляем всех администраторов и игроков о бане + String banAnnouncement = "§c[БАН] §fИгрок §c" + playerName + " §fзабанен"; + if (days > 0) { + banAnnouncement += " на §e" + days + " дней"; + } else { + banAnnouncement += " §4навсегда"; + } + banAnnouncement += "§f. Причина: §7" + reason; + + final String finalBanAnnouncement = banAnnouncement; + plugin.getServer().getScheduler().runTask(plugin, () -> { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + onlinePlayer.sendMessage(finalBanAnnouncement); + } + }); + } + } else { + sender.sendMessage("§cОшибка при бане игрока! Возможно игрок не найден в базе данных."); + } + }) + .exceptionally(throwable -> { + sender.sendMessage("§cОшибка при бане игрока: " + throwable.getMessage()); + return null; + }); + + return true; + } + + /** + * Разбанить игрока + */ + private boolean handleUnban(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 2) { + sender.sendMessage("§cИспользование: /chiwawa unban <игрок>"); + return true; + } + + String playerName = args[1]; + + // Используем nickname-based разбан для поддержки оффлайн игроков + apiClient.unbanPlayerByNickname(playerName) + .thenAccept(success -> { + if (success) { + sender.sendMessage("§aИгрок " + playerName + " успешно разбанен!"); + + // Уведомляем всех игроков о разбане + String unbanAnnouncement = "§a[РАЗБАН] §fИгрок §a" + playerName + " §fразбанен администратором §a" + sender.getName(); + plugin.getServer().getScheduler().runTask(plugin, () -> { + for (Player onlinePlayer : Bukkit.getOnlinePlayers()) { + onlinePlayer.sendMessage(unbanAnnouncement); + } + }); + } else { + sender.sendMessage("§cОшибка при разбане игрока! Возможно игрок не найден в базе данных."); + } + }) + .exceptionally(throwable -> { + sender.sendMessage("§cОшибка при разбане игрока: " + throwable.getMessage()); + return null; + }); + + return true; + } + + /** + * Изменить Trust Level + */ + private boolean handleTrust(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 3) { + sender.sendMessage("§cИспользование: /chiwawa trust <игрок> <уровень>"); + sender.sendMessage("§7Уровни: 0-Проходимец, 1-Новичок, 2-Проверенный, 3-Ветеран"); + return true; + } + + String playerName = args[1]; + int trustLevel; + + try { + trustLevel = Integer.parseInt(args[2]); + } catch (NumberFormatException e) { + sender.sendMessage("§cНеверный формат уровня доверия!"); + return true; + } + + if (trustLevel < 0 || trustLevel > 3) { + sender.sendMessage("§cУровень доверия должен быть от 0 до 3!"); + return true; + } + + UUID playerUuid = getPlayerUuid(playerName); + if (playerUuid == null) { + sender.sendMessage("§cИгрок не найден!"); + return true; + } + + userManager.updateTrustLevel(playerUuid, trustLevel) + .thenAccept(success -> { + if (success) { + String levelName = getTrustLevelName(trustLevel); + sender.sendMessage("§aТраст уровень игрока " + playerName + " изменен на " + trustLevel + " (" + levelName + ")"); + + // Уведомляем игрока если он онлайн + Player targetPlayer = Bukkit.getPlayerExact(playerName); + if (targetPlayer != null) { + targetPlayer.sendMessage("§a§l[★] §fВаш Trust Level повышен до §a§l" + trustLevel + " §7(" + levelName + ")§f!"); + } + } else { + sender.sendMessage("§cОшибка при изменении Trust Level!"); + } + }); + + return true; + } + + /** + * Показать время игры + */ + private boolean handlePlaytime(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 2) { + sender.sendMessage("§cИспользование: /chiwawa playtime <игрок>"); + return true; + } + + String playerName = args[1]; + UUID playerUuid = getPlayerUuid(playerName); + + if (playerUuid == null) { + sender.sendMessage("§cИгрок не найден!"); + return true; + } + + PlayerStats stats = userManager.getPlayerStats(playerUuid); + if (stats == null) { + sender.sendMessage("§cСтатистика игрока не найдена!"); + return true; + } + + int totalMinutes = playtimeManager.getTotalPlaytime(playerUuid); + int sessionMinutes = playtimeManager.getSessionPlaytime(playerUuid); + + sender.sendMessage("§e═════ ВРЕМЯ ИГРЫ: " + playerName + " ═════"); + sender.sendMessage("§7Общее время: §b" + playtimeManager.formatTime(totalMinutes)); + sender.sendMessage("§7Текущая сессия: §b" + playtimeManager.formatTime(sessionMinutes)); + + ChiwawaUser user = userManager.getUser(playerUuid); + if (user != null && user.hasTimeLimit()) { + int remaining = playtimeManager.getRemainingTime(playerUuid); + sender.sendMessage("§7Осталось времени: §c" + playtimeManager.formatTime(remaining)); + } else { + sender.sendMessage("§7Лимит времени: §aОтсутствует"); + } + + return true; + } + + /** + * Изменить репутацию (админ команда) + */ + private boolean handleReputation(CommandSender sender, String[] args) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + if (args.length < 3) { + sender.sendMessage("§cИспользование: /chiwawa rep <игрок> <количество> [причина]"); + return true; + } + + String playerName = args[1]; + int amount; + + try { + amount = Integer.parseInt(args[2]); + } catch (NumberFormatException e) { + sender.sendMessage("§cНеверный формат количества!"); + return true; + } + + String reason = args.length > 3 ? String.join(" ", Arrays.copyOfRange(args, 3, args.length)) : "Изменение администратором"; + + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + reputationManager.modifyReputation((Player) sender, playerName, amount, reason) + .thenAccept(result -> sender.sendMessage(result.getMessage())); + + return true; + } + + /** + * Показать статистику сервера + */ + private boolean handleStats(CommandSender sender) { + if (!hasPermission(sender, "chiwawa.admin")) { + sender.sendMessage("§cУ вас нет прав для выполнения этой команды!"); + return true; + } + + sender.sendMessage("§e§l════════ СТАТИСТИКА СЕРВЕРА ════════"); + sender.sendMessage("§7Игроков онлайн: §a" + Bukkit.getOnlinePlayers().size()); + sender.sendMessage("§7Загружено пользователей: §a" + userManager.getCacheSize()); + sender.sendMessage("§7Отслеживается времени: §a" + playtimeManager.getPlaytimeStats()); + sender.sendMessage("§7Репутация: §a" + reputationManager.getReputationStats()); + + // Получаем информацию с сайта + sender.sendMessage("§7Получение данных с сайта..."); + apiClient.getServerInfo().thenAccept(serverInfo -> { + if (serverInfo != null && serverInfo.has("success") && serverInfo.get("success").getAsBoolean()) { + sender.sendMessage("§a§l──── ДАННЫЕ С САЙТА ────"); + + if (serverInfo.has("server") && !serverInfo.get("server").isJsonNull()) { + JsonObject server = serverInfo.getAsJsonObject("server"); + sender.sendMessage("§7Статус сервера: §a" + (serverInfo.has("online") && !serverInfo.get("online").isJsonNull() ? + (serverInfo.get("online").getAsBoolean() ? "онлайн" : "офлайн") : "неизвестно")); + + if (server.has("version") && !server.get("version").isJsonNull()) { + sender.sendMessage("§7Версия: §f" + server.get("version").getAsString()); + } + + if (server.has("motd") && !server.get("motd").isJsonNull()) { + sender.sendMessage("§7MOTD: §f" + server.get("motd").getAsString()); + } + } + + if (serverInfo.has("performance") && !serverInfo.get("performance").isJsonNull()) { + JsonObject performance = serverInfo.getAsJsonObject("performance"); + + if (performance.has("ping") && !performance.get("ping").isJsonNull()) { + sender.sendMessage("§7Ping: §e" + performance.get("ping").getAsInt() + "ms"); + } + + if (performance.has("tps") && !performance.get("tps").isJsonNull()) { + sender.sendMessage("§7TPS: §e" + performance.get("tps").getAsDouble()); + } + } + + if (serverInfo.has("players") && !serverInfo.get("players").isJsonNull()) { + JsonObject players = serverInfo.getAsJsonObject("players"); + + int online = players.has("online") && !players.get("online").isJsonNull() ? players.get("online").getAsInt() : 0; + int max = players.has("max") && !players.get("max").isJsonNull() ? players.get("max").getAsInt() : 0; + + sender.sendMessage("§7Игроков в базе: §a" + online + "/" + max); + } + } else { + sender.sendMessage("§cОшибка получения данных с сайта!"); + } + }).exceptionally(throwable -> { + sender.sendMessage("§cОшибка подключения к API сайта: " + throwable.getMessage()); + return null; + }); + + sender.sendMessage("§e§l══════════════════════════════════"); + + return true; + } + + /** + * Проверить права доступа + */ + private boolean hasPermission(CommandSender sender, String permission) { + if (sender.isOp()) return true; + if (!(sender instanceof Player)) return true; // Консоль имеет все права + + Player player = (Player) sender; + ChiwawaUser user = userManager.getUser(player.getUniqueId()); + + if (user == null) return false; + + // Проверяем по РОЛИ, а не trust level + if (permission.equals("chiwawa.admin")) { + return user.isAdmin(); // Проверяет role == "admin" + } + + if (permission.equals("chiwawa.moderator")) { + return user.isModerator(); // Проверяет role == "moderator" || role == "admin" + } + + return player.hasPermission(permission); + } + + /** + * Получить UUID игрока по имени + */ + private UUID getPlayerUuid(String playerName) { + Player player = Bukkit.getPlayerExact(playerName); + if (player != null) { + return player.getUniqueId(); + } + + // Ищем в кеше пользователей + for (var entry : userManager.getAllCachedUsers().entrySet()) { + if (entry.getValue().getNickname().equalsIgnoreCase(playerName)) { + return entry.getKey(); + } + } + + return null; + } + + /** + * Получить название trust level + */ + private String getTrustLevelName(int trustLevel) { + switch (trustLevel) { + case 0: return "Проходимец"; + case 1: return "Новичок"; + case 2: return "Проверенный"; + case 3: return "Ветеран"; + default: return "Неизвестный"; + } + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (args.length == 1) { + // Первый аргумент - подкоманды + List subCommands = Arrays.asList("reload", "sync", "ban", "unban", "trust", "playtime", "rep", "stats"); + return subCommands.stream() + .filter(cmd -> cmd.toLowerCase().startsWith(args[0].toLowerCase())) + .collect(Collectors.toList()); + } + + if (args.length == 2) { + // Второй аргумент - имена игроков для большинства команд + String subCommand = args[0].toLowerCase(); + if (Arrays.asList("sync", "ban", "unban", "trust", "playtime", "rep").contains(subCommand)) { + return Bukkit.getOnlinePlayers().stream() + .map(Player::getName) + .filter(name -> name.toLowerCase().startsWith(args[1].toLowerCase())) + .collect(Collectors.toList()); + } + } + + if (args.length == 3 && args[0].equalsIgnoreCase("trust")) { + // Trust level от 0 до 3 + return Arrays.asList("0", "1", "2", "3").stream() + .filter(level -> level.startsWith(args[2])) + .collect(Collectors.toList()); + } + + return new ArrayList<>(); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/DiscordCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/DiscordCommand.java new file mode 100644 index 00000000000..2df9f2cd520 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/DiscordCommand.java @@ -0,0 +1,43 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.config.ConfigManager; + +/** + * Команда /discord для информации о Discord сервере + */ +public class DiscordCommand implements CommandExecutor { + private final ConfigManager configManager; + + public DiscordCommand(ConfigManager configManager) { + this.configManager = configManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + showDiscordInfo(player); + return true; + } + + private void showDiscordInfo(Player player) { + player.sendMessage("§e═════ DISCORD СЕРВЕР ═════"); + player.sendMessage("§7Присоединяйтесь к нашему Discord серверу:"); + player.sendMessage("§9§nhttps://discord.gg/chiwawa"); + player.sendMessage(""); + player.sendMessage("§7В Discord вы можете:"); + player.sendMessage("§7• Общаться с другими игроками"); + player.sendMessage("§7• Получать новости сервера"); + player.sendMessage("§7• Связать Discord аккаунт для повышения Trust Level"); + player.sendMessage("§7• Обращаться в поддержку"); + player.sendMessage("§e═══════════════════════"); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/LoginCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/LoginCommand.java new file mode 100644 index 00000000000..a98ed277b02 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/LoginCommand.java @@ -0,0 +1,230 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.AuthPlayer; +import org.ebluffy.chiwawa.api.dto.TokenVerificationResult; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.AuthManager; +import org.ebluffy.chiwawa.managers.UserManager; + +import java.util.Optional; +import java.util.logging.Logger; + +/** + * Команда для авторизации игрока (поддерживает оба режима) + * /login <пароль> - простая авторизация + * /login <токен> - авторизация через сайт + */ +public class LoginCommand implements CommandExecutor { + private final ConfigManager configManager; + private final ApiClient apiClient; + private final UserManager userManager; + private final AuthManager authManager; + private final Logger logger; + + public LoginCommand(ConfigManager configManager, ApiClient apiClient, UserManager userManager, + AuthManager authManager, Logger logger) { + this.configManager = configManager; + this.apiClient = apiClient; + this.userManager = userManager; + this.authManager = authManager; + this.logger = logger; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Проверка, не авторизован ли уже игрок + if (authManager.isPlayerAuthorized(player.getUniqueId()) || + userManager.isPlayerCached(player.getUniqueId())) { + player.sendMessage("§cВы уже авторизованы!"); + return true; + } + + if (args.length != 1) { + player.sendMessage("§cИспользование:"); + player.sendMessage("§7• /login <пароль> §f- простая авторизация"); + player.sendMessage("§7• /login <токен> §f- авторизация через сайт"); + player.sendMessage("§7Токен можно получить на: §b§nhttps://chiwawa.site"); + return true; + } + + String input = args[0]; + String nickname = player.getName(); + + // Определяем тип входа: токен обычно длиннее 32 символов + if (input.length() >= 32) { + // Авторизация через токен (сайт) + handleWebsiteLogin(player, input, nickname); + } else { + // Простая авторизация по паролю + handleSimpleLogin(player, input); + } + + return true; + } + + /** + * Обработка простой авторизации по паролю + */ + private void handleSimpleLogin(Player player, String password) { + player.sendMessage("§7Проверка пароля..."); + + // Сначала проверяем, что игрок зарегистрирован + authManager.getAuthorizedPlayer(player.getUniqueId()) + .or(() -> { + // Если нет в кеше, пытаемся загрузить из БД + try { + return authManager.loginPlayer(player, password).get() + ? authManager.getAuthorizedPlayer(player.getUniqueId()) + : Optional.empty(); + } catch (Exception e) { + return Optional.empty(); + } + }); + + // Сначала проверяем блокировку + org.ebluffy.chiwawa.ChiwawaPlugin plugin = + (org.ebluffy.chiwawa.ChiwawaPlugin) org.bukkit.Bukkit.getPluginManager().getPlugin("ChiwawaPlugin"); + + plugin.getDatabaseManager().isPlayerLocked(player.getName()) + .thenCompose(isLocked -> { + if (isLocked) { + // Игрок заблокирован - получаем время до разблокировки + return plugin.getDatabaseManager().getMinutesUntilUnlock(player.getName()) + .thenApply(minutesRemaining -> { + player.sendMessage("§c§l✗ Аккаунт временно заблокирован!"); + player.sendMessage("§7Причина: Превышено количество попыток входа (5)"); + player.sendMessage("§7Время до разблокировки: §c" + minutesRemaining + " минут"); + player.sendMessage("§7После разблокировки попробуйте снова"); + return false; + }); + } + + // Пытаемся авторизоваться + return authManager.loginPlayer(player, password) + .thenApply(success -> { + if (success) { + Optional authPlayerOpt = authManager.getAuthorizedPlayer(player.getUniqueId()); + + player.sendMessage("§a§l✓ Авторизация успешна!"); + player.sendMessage("§7Добро пожаловать, §a" + player.getName() + "§7!"); + + if (authPlayerOpt.isPresent()) { + player.sendMessage("§7Режим: §aПростая авторизация"); + + // Предлагаем переключиться на сайт + player.sendMessage(""); + player.sendMessage("§e§l💡 СОВЕТ:"); + player.sendMessage("§7Для лучшей защиты используйте"); + player.sendMessage("§7авторизацию через сайт: §a/changelogin"); + } + + // Логируем БЕЗ пароля + logger.info("Игрок " + player.getName() + " авторизован"); + } else { + // Получаем количество попыток + plugin.getDatabaseManager().getFailedLoginAttempts(player.getName()) + .thenAccept(attempts -> { + player.sendMessage("§c§l✗ Неверный пароль!"); + + if (attempts >= 5) { + player.sendMessage("§c§lВНИМАНИЕ: Аккаунт заблокирован на 5 минут!"); + player.sendMessage("§7Причина: Превышено количество попыток входа"); + } else if (attempts >= 3) { + player.sendMessage("§e§lВНИМАНИЕ: Попытка " + attempts + "/5"); + player.sendMessage("§7После 5 неудачных попыток аккаунт будет заблокирован на 5 минут"); + } else { + player.sendMessage("§7Попытка " + attempts + "/5"); + } + + player.sendMessage("§7Если забыли пароль, обратитесь к администрации"); + }); + } + return success; + }); + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка авторизации!"); + player.sendMessage("§7Попробуйте позже"); + logger.severe("Ошибка простой авторизации " + player.getName() + ": " + throwable.getMessage()); + return false; + }); + } + + /** + * Обработка авторизации через токен сайта + */ + private void handleWebsiteLogin(Player player, String token, String nickname) { + player.sendMessage("§7Проверка токена..."); + + apiClient.verifyGameToken(token, nickname) + .thenAccept(result -> { + if (result.isValid()) { + // Токен действителен, авторизуем игрока + userManager.authorizePlayer(player, result.getUserId()); + + // Создаем игровую сессию + apiClient.createGameSession( + nickname, + player.getUniqueId().toString(), + player.getAddress().getAddress().getHostAddress(), + "Minecraft Client" + ).thenAccept(sessionResult -> { + if (sessionResult) { + logger.info("Игровая сессия создана для игрока " + nickname); + } else { + logger.warning("Не удалось создать игровую сессию для игрока " + nickname); + } + }).exceptionally(throwable -> { + logger.warning("Ошибка создания игровой сессии для " + nickname + ": " + throwable.getMessage()); + return null; + }); + + player.sendMessage("§a§l✓ Авторизация успешна!"); + player.sendMessage("§7Добро пожаловать, §a" + result.getNickname() + "§7!"); + player.sendMessage("§7Роль: §a" + getRoleDisplayName(result.getRole())); + player.sendMessage("§7Trust Level: §a" + result.getTrustLevel()); + player.sendMessage("§7Сессия создана на 7 дней"); + + logger.info("Игрок " + nickname + " успешно авторизовался с токеном (ID: " + result.getUserId() + ")"); + } else { + // Токен недействителен + player.sendMessage("§c§l✗ Ошибка авторизации!"); + player.sendMessage("§7" + result.getMessage()); + player.sendMessage("§7Получите новый токен на сайте: §b§nhttps://chiwawa.site"); + + logger.warning("Неудачная попытка авторизации игрока " + nickname + ": " + result.getMessage()); + } + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка соединения с сервером!"); + player.sendMessage("§7Попробуйте позже или обратитесь к администрации."); + + logger.severe("Ошибка проверки токена для игрока " + nickname + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Получить отображаемое название роли + */ + private String getRoleDisplayName(String role) { + switch (role) { + case "admin": return "Администратор"; + case "moderator": return "Модератор"; + case "user": return "Пользователь"; + default: return "Неизвестная роль"; + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/PlaytimeCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/PlaytimeCommand.java new file mode 100644 index 00000000000..3c3a3cfb1ee --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/PlaytimeCommand.java @@ -0,0 +1,70 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.PlaytimeManager; +import org.ebluffy.chiwawa.managers.UserManager; + +/** + * Команда /playtime для просмотра времени игры + */ +public class PlaytimeCommand implements CommandExecutor { + private final ConfigManager configManager; + private final PlaytimeManager playtimeManager; + private final UserManager userManager; + + public PlaytimeCommand(ConfigManager configManager, PlaytimeManager playtimeManager, UserManager userManager) { + this.configManager = configManager; + this.playtimeManager = playtimeManager; + this.userManager = userManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + showPlaytime(player); + return true; + } + + private void showPlaytime(Player player) { + ChiwawaUser user = userManager.getUser(player.getUniqueId()); + + if (user == null) { + player.sendMessage("§cВаши данные не загружены. Попробуйте позже."); + return; + } + + int totalMinutes = playtimeManager.getTotalPlaytime(player.getUniqueId()); + int sessionMinutes = playtimeManager.getSessionPlaytime(player.getUniqueId()); + + player.sendMessage("§e═══════ ВРЕМЯ ИГРЫ ═══════"); + + // Общее время + player.sendMessage(configManager.getMessage("playtime_total", "%time%", playtimeManager.formatTime(totalMinutes))); + + // Текущая сессия + player.sendMessage(configManager.getMessage("playtime_current", "%time%", playtimeManager.formatTime(sessionMinutes))); + + // Лимит времени (только для проходимцев) + if (user.hasTimeLimit()) { + int remaining = playtimeManager.getRemainingTime(player.getUniqueId()); + player.sendMessage(configManager.getMessage("playtime_remaining", "%time%", playtimeManager.formatTime(remaining))); + player.sendMessage("§7Всего доступно: §c10 часов"); + player.sendMessage("§7Для снятия лимита подтвердите email на сайте:"); + player.sendMessage("§b§nhttps://chiwawa.site"); + } else { + player.sendMessage(configManager.getMessage("playtime_unlimited")); + } + + player.sendMessage("§e═══════════════════════"); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ProfileCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ProfileCommand.java new file mode 100644 index 00000000000..6eea78a5fcf --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ProfileCommand.java @@ -0,0 +1,84 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.api.dto.PlayerStats; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.PlaytimeManager; +import org.ebluffy.chiwawa.managers.UserManager; + +/** + * Команда /profile для просмотра профиля игрока + */ +public class ProfileCommand implements CommandExecutor { + private final ConfigManager configManager; + private final UserManager userManager; + private final PlaytimeManager playtimeManager; + + public ProfileCommand(ConfigManager configManager, UserManager userManager, PlaytimeManager playtimeManager) { + this.configManager = configManager; + this.userManager = userManager; + this.playtimeManager = playtimeManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + ChiwawaUser user = userManager.getUser(player.getUniqueId()); + PlayerStats stats = userManager.getPlayerStats(player.getUniqueId()); + + if (user == null) { + sender.sendMessage("§cВаши данные не загружены. Попробуйте позже."); + return true; + } + + // Показываем профиль + showProfile(player, user, stats); + return true; + } + + private void showProfile(Player player, ChiwawaUser user, PlayerStats stats) { + player.sendMessage(configManager.getMessage("profile_header")); + + // Основная информация + player.sendMessage(configManager.getMessage("profile_nickname", "%nickname%", user.getNickname())); + player.sendMessage(configManager.getMessage("profile_trust_level", + "%level%", String.valueOf(user.getTrustLevel()), + "%description%", user.getTrustLevelDescription())); + + // Репутация + if (stats != null) { + player.sendMessage(configManager.getMessage("profile_reputation", "%reputation%", String.valueOf(stats.getReputation()))); + } + + // Время игры + int totalMinutes = playtimeManager.getTotalPlaytime(player.getUniqueId()); + player.sendMessage(configManager.getMessage("profile_playtime", "%playtime%", playtimeManager.formatTime(totalMinutes))); + + // Статус email + String emailStatus = user.isEmailVerified() ? "§aПодтвержден" : "§cНе подтвержден"; + player.sendMessage(configManager.getMessage("profile_email_status", "%status%", emailStatus)); + + // Дата регистрации + if (user.getRegisteredAt() != null) { + player.sendMessage(configManager.getMessage("profile_registration", "%date%", user.getRegisteredAt())); + } + + // Дополнительная информация для проходимцев + if (user.hasTimeLimit()) { + int remaining = playtimeManager.getRemainingTime(player.getUniqueId()); + player.sendMessage("§7Лимит времени: §c" + playtimeManager.formatTime(remaining) + " из 10 часов"); + player.sendMessage("§7Для снятия лимита подтвердите email на сайте!"); + } + + player.sendMessage(configManager.getMessage("profile_footer")); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/RegisterCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/RegisterCommand.java new file mode 100644 index 00000000000..739a2ce28b2 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/RegisterCommand.java @@ -0,0 +1,103 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.AuthManager; + +import java.util.logging.Logger; + +/** + * Команда для регистрации игрока (/register <пароль> <повтор_пароля>) + */ +public class RegisterCommand implements CommandExecutor { + private final ConfigManager configManager; + private final AuthManager authManager; + private final Logger logger; + + public RegisterCommand(ConfigManager configManager, AuthManager authManager, Logger logger) { + this.configManager = configManager; + this.authManager = authManager; + this.logger = logger; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Проверка, не авторизован ли уже игрок + if (authManager.isPlayerAuthorized(player.getUniqueId())) { + player.sendMessage("§cВы уже авторизованы!"); + return true; + } + + if (args.length != 2) { + player.sendMessage("§cИспользование: /register <пароль> <повтор_пароля>"); + player.sendMessage("§7Пароль должен быть от 6 до 32 символов"); + return true; + } + + String password = args[0]; + String passwordRepeat = args[1]; + + // Проверка совпадения паролей + if (!password.equals(passwordRepeat)) { + player.sendMessage("§c§l✗ Пароли не совпадают!"); + player.sendMessage("§7Пожалуйста, введите одинаковые пароли"); + return true; + } + + // Валидация пароля + if (!AuthManager.isPasswordValid(password)) { + player.sendMessage("§c§l✗ Недопустимый пароль!"); + player.sendMessage("§7Пароль должен:"); + player.sendMessage("§7• Быть от 6 до 32 символов"); + player.sendMessage("§7• Содержать только буквы, цифры и спецсимволы"); + return true; + } + + // Показываем силу пароля + String strength = AuthManager.getPasswordStrength(password); + String strengthColor = strength.equals("Сильный") ? "§a" : strength.equals("Средний") ? "§e" : "§c"; + + player.sendMessage("§7Сила пароля: " + strengthColor + strength); + player.sendMessage("§7Регистрация..."); + + // Регистрируем игрока + authManager.registerPlayer(player, password) + .thenAccept(success -> { + if (success) { + player.sendMessage("§a§l✓ Регистрация успешна!"); + player.sendMessage("§7Вы успешно зарегистрированы на сервере"); + player.sendMessage("§7Используйте §a/login <пароль> §7для входа в следующий раз"); + player.sendMessage(""); + player.sendMessage("§e§l⚡ РЕКОМЕНДАЦИЯ:"); + player.sendMessage("§7Для лучшей защиты аккаунта используйте"); + player.sendMessage("§7авторизацию через сайт: §a/changelogin"); + + // Логируем БЕЗ пароля + logger.info("Игрок " + player.getName() + " зарегистрирован"); + } else { + player.sendMessage("§c§l✗ Ошибка регистрации!"); + player.sendMessage("§7Возможно, вы уже зарегистрированы"); + player.sendMessage("§7Используйте §a/login <пароль>"); + logger.warning("Попытка повторной регистрации: " + player.getName()); + } + }) + .exceptionally(throwable -> { + player.sendMessage("§c§l✗ Ошибка соединения с базой данных!"); + player.sendMessage("§7Попробуйте позже или обратитесь к администрации"); + logger.severe("Ошибка регистрации " + player.getName() + ": " + throwable.getMessage()); + return null; + }); + + return true; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ReputationCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ReputationCommand.java new file mode 100644 index 00000000000..36094771374 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/ReputationCommand.java @@ -0,0 +1,102 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; +import org.bukkit.entity.Player; +import org.bukkit.Bukkit; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.ReputationManager; +import org.ebluffy.chiwawa.managers.UserManager; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Команда /rep для выдачи репутации игрокам + */ +public class ReputationCommand implements CommandExecutor, TabCompleter { + private final ConfigManager configManager; + private final ReputationManager reputationManager; + private final UserManager userManager; + + public ReputationCommand(ConfigManager configManager, ReputationManager reputationManager, UserManager userManager) { + this.configManager = configManager; + this.reputationManager = reputationManager; + this.userManager = userManager; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("§cЭта команда доступна только игрокам!"); + return true; + } + + Player player = (Player) sender; + + // Проверяем, включена ли система репутации + if (!configManager.isReputationEnabled()) { + player.sendMessage("§cСистема репутации отключена на сервере!"); + return true; + } + + if (args.length == 0) { + showReputationInfo(player); + return true; + } + + if (args.length < 1) { + player.sendMessage("§cИспользование: /rep <игрок>"); + return true; + } + + String targetName = args[0]; + + // Выдаем репутацию + reputationManager.giveReputation(player, targetName) + .thenAccept(result -> { + if (result.isSuccess()) { + player.sendMessage("§a" + result.getMessage()); + } else { + player.sendMessage("§c" + result.getMessage()); + } + }); + + return true; + } + + private void showReputationInfo(Player player) { + player.sendMessage("§e═══════ СИСТЕМА РЕПУТАЦИИ ═══════"); + player.sendMessage("§7Использование: §f/rep <игрок>"); + player.sendMessage("§7Описание: §fДать +1 репутацию игроку"); + player.sendMessage("§7Кулдаун: §f1 час между выдачами"); + player.sendMessage("§7Требования: §fTrust Level 1+"); + + // Показываем статус кулдауна + if (!reputationManager.canGiveReputation(player.getUniqueId())) { + long remaining = reputationManager.getRemainingCooldown(player.getUniqueId()); + long minutes = remaining / (60 * 1000); + long seconds = (remaining / 1000) % 60; + player.sendMessage("§cКулдаун: §f" + minutes + "м " + seconds + "с"); + } else { + player.sendMessage("§aВы можете дать репутацию!"); + } + + player.sendMessage("§e═══════════════════════════════"); + } + + @Override + public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) { + if (args.length == 1) { + return Bukkit.getOnlinePlayers().stream() + .map(Player::getName) + .filter(name -> !name.equals(sender.getName())) // Исключаем самого себя + .filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase())) + .collect(Collectors.toList()); + } + return new ArrayList<>(); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/UnregisterCommand.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/UnregisterCommand.java new file mode 100644 index 00000000000..bf74571d48a --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/commands/UnregisterCommand.java @@ -0,0 +1,140 @@ +package org.ebluffy.chiwawa.commands; + +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.database.DatabaseManager; + +import java.util.UUID; +import java.util.logging.Logger; + +/** + * Команда для удаления регистрации игрока (только для админов) + * /unregister + */ +public class UnregisterCommand implements CommandExecutor { + private final ConfigManager configManager; + private final DatabaseManager databaseManager; + private final Logger logger; + + public UnregisterCommand(ConfigManager configManager, DatabaseManager databaseManager, Logger logger) { + this.configManager = configManager; + this.databaseManager = databaseManager; + this.logger = logger; + } + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + // Проверка прав доступа + if (!sender.hasPermission("chiwawa.command.unregister")) { + sender.sendMessage("§cУ вас нет прав для использования этой команды!"); + return true; + } + + if (args.length != 1) { + sender.sendMessage("§cИспользование: /unregister "); + sender.sendMessage("§7Удаляет регистрацию игрока из БД authplugin"); + sender.sendMessage("§7Игрок сможет зарегистрироваться заново"); + return true; + } + + String targetNickname = args[0]; + + // Проверяем, что администратор подтверждает действие + sender.sendMessage("§e§l⚠ ВНИМАНИЕ!"); + sender.sendMessage("§7Вы собираетесь удалить регистрацию игрока §c" + targetNickname); + sender.sendMessage("§7Это действие:"); + sender.sendMessage("§7• Удалит учетную запись из БД authplugin"); + sender.sendMessage("§7• Игрок потеряет доступ с текущим паролем"); + sender.sendMessage("§7• Игрок сможет зарегистрироваться заново"); + sender.sendMessage(""); + sender.sendMessage("§7Проверяю данные..."); + + // Проверяем существование игрока + databaseManager.getPlayerByUsername(targetNickname) + .thenAccept(authPlayerOpt -> { + if (authPlayerOpt.isEmpty()) { + sender.sendMessage("§c§l✗ Игрок " + targetNickname + " не зарегистрирован!"); + sender.sendMessage("§7В БД authplugin нет записи для этого игрока"); + return; + } + + // Удаляем регистрацию + databaseManager.deletePlayer(targetNickname) + .thenAccept(success -> { + if (success) { + sender.sendMessage("§a§l✓ Регистрация игрока " + targetNickname + " успешно удалена!"); + sender.sendMessage("§7Игрок может зарегистрироваться заново: §a/register <пароль> <повтор>"); + + // Логируем действие + logger.info("Администратор " + sender.getName() + " удалил регистрацию игрока " + targetNickname); + logUnregister(sender, targetNickname, true, null); + + // Если игрок онлайн - кикаем его + Player targetPlayer = Bukkit.getPlayerExact(targetNickname); + if (targetPlayer != null && targetPlayer.isOnline()) { + targetPlayer.kick(net.kyori.adventure.text.Component.text( + "§c§lВаша регистрация удалена администратором\n\n" + + "§7Вы можете зарегистрироваться заново:\n" + + "§a/register <пароль> <повтор>" + )); + sender.sendMessage("§7Игрок " + targetNickname + " был кикнут с сервера"); + } + } else { + sender.sendMessage("§c§l✗ Ошибка удаления регистрации!"); + sender.sendMessage("§7Проверьте логи сервера для подробностей"); + + logger.warning("Не удалось удалить регистрацию игрока " + targetNickname); + logUnregister(sender, targetNickname, false, "Ошибка БД"); + } + }) + .exceptionally(throwable -> { + sender.sendMessage("§c§l✗ Ошибка удаления регистрации!"); + sender.sendMessage("§7" + throwable.getMessage()); + + logger.severe("Ошибка удаления регистрации игрока " + targetNickname + ": " + throwable.getMessage()); + logUnregister(sender, targetNickname, false, throwable.getMessage()); + return null; + }); + }) + .exceptionally(throwable -> { + sender.sendMessage("§c§l✗ Ошибка проверки игрока!"); + sender.sendMessage("§7" + throwable.getMessage()); + + logger.severe("Ошибка проверки игрока " + targetNickname + ": " + throwable.getMessage()); + return null; + }); + + return true; + } + + /** + * Логирование удаления регистрации + */ + private void logUnregister(CommandSender admin, String targetPlayer, boolean success, String reason) { + String adminName = admin instanceof Player ? + ((Player) admin).getName() + " (" + ((Player) admin).getUniqueId() + ")" : + admin.getName(); + + String logMessage = String.format( + "[UNREGISTER] Admin: %s, Target: %s, Success: %s%s", + adminName, + targetPlayer, + success, + reason != null ? ", Reason: " + reason : "" + ); + + // Используем отдельный логгер для аудита + java.util.logging.Logger auditLogger = java.util.logging.Logger.getLogger("ChiwawaAudit"); + + if (success) { + auditLogger.info(logMessage); + } else { + auditLogger.warning(logMessage); + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/config/ConfigManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/config/ConfigManager.java new file mode 100644 index 00000000000..a63c0eaa4f2 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/config/ConfigManager.java @@ -0,0 +1,146 @@ +package org.ebluffy.chiwawa.config; + +import org.bukkit.ChatColor; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.java.JavaPlugin; + +import java.util.logging.Logger; + +/** + * Менеджер конфигурации плагина + */ +public class ConfigManager { + private final JavaPlugin plugin; + private final Logger logger; + private FileConfiguration config; + + public ConfigManager(JavaPlugin plugin) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + loadConfig(); + } + + /** + * Загрузить конфигурацию + */ + public void loadConfig() { + plugin.saveDefaultConfig(); + plugin.reloadConfig(); + config = plugin.getConfig(); + // Логирование убрано - выводится в главном классе + } + + /** + * Перезагрузить конфигурацию + */ + public void reloadConfig() { + plugin.reloadConfig(); + config = plugin.getConfig(); + logger.info("Конфигурация перезагружена"); + } + + // API настройки + public String getApiBaseUrl() { + return config.getString("api.base_url", "http://localhost:3000/api"); + } + + public int getApiTimeout() { + return config.getInt("api.timeout", 5000); + } + + public String getApiKey() { + return config.getString("api.admin_token", ""); + } + + public int getRetryAttempts() { + return config.getInt("api.retry_attempts", 3); + } + + // Настройки сервера + public boolean isWhitelistEnabled() { + return config.getBoolean("server.enable_whitelist", true); + } + + public boolean isTimeLimitEnabled() { + return config.getBoolean("server.enable_time_limit", true); + } + + public boolean isTrustSystemEnabled() { + return config.getBoolean("server.enable_trust_system", true); + } + + public boolean isReputationEnabled() { + return config.getBoolean("server.enable_reputation", true); + } + + public boolean isAuthenticationEnabled() { + return config.getBoolean("server.enable_authentication", true); + } + + public int getSyncInterval() { + return config.getInt("server.sync_interval", 300); + } + + // Trust Level настройки + public int getTrustLevelMaxHours(int trustLevel) { + return config.getInt("trust_levels." + trustLevel + ".max_total_hours", -1); + } + + public String getTrustLevelDescription(int trustLevel) { + return config.getString("trust_levels." + trustLevel + ".description", "Неизвестный уровень"); + } + + // Сообщения + public String getMessage(String key) { + String message = config.getString("messages." + key, "Сообщение не найдено: " + key); + return ChatColor.translateAlternateColorCodes('&', message); + } + + public String getMessage(String key, String... replacements) { + String message = getMessage(key); + for (int i = 0; i < replacements.length; i += 2) { + if (i + 1 < replacements.length) { + message = message.replace(replacements[i], replacements[i + 1]); + } + } + return message; + } + + // Проверка корректности конфигурации + public boolean validateConfig() { + boolean valid = true; + + if (getApiKey().isEmpty()) { + logger.severe("Admin token не настроен! Плагин не будет работать корректно."); + valid = false; + } + + if (getApiBaseUrl().isEmpty()) { + logger.severe("API base URL не настроен!"); + valid = false; + } + + return valid; + } + + /** + * Получить полную конфигурацию + */ + public FileConfiguration getConfig() { + return config; + } + + /** + * Получить IP сервера из конфигурации + */ + public String getServerIp() { + return config.getString("server.ip", "localhost"); + } + + /** + * Получить порт сервера из конфигурации + */ + public int getServerPort() { + return config.getInt("server.port", 25565); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/database/DatabaseManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/database/DatabaseManager.java new file mode 100644 index 00000000000..cc51fccf59f --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/database/DatabaseManager.java @@ -0,0 +1,566 @@ +package org.ebluffy.chiwawa.database; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.dto.AuthPlayer; + +import java.sql.*; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +/** + * Менеджер для работы с PostgreSQL базой данных + */ +public class DatabaseManager { + private final JavaPlugin plugin; + private final Logger logger; + private HikariDataSource dataSource; + + public DatabaseManager(JavaPlugin plugin, String host, int port, String database, + String username, String password) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + + initializeDataSource(host, port, database, username, password); + } + + /** + * Инициализация пула соединений HikariCP + */ + private void initializeDataSource(String host, int port, String database, + String username, String password) { + try { + // Явно загружаем PostgreSQL драйвер + Class.forName("org.postgresql.Driver"); + + HikariConfig config = new HikariConfig(); + config.setJdbcUrl(String.format("jdbc:postgresql://%s:%d/%s", host, port, database)); + config.setUsername(username); + config.setPassword(password); + config.setDriverClassName("org.postgresql.Driver"); + + // Настройки пула + config.setMaximumPoolSize(10); + config.setMinimumIdle(2); + config.setConnectionTimeout(30000); + config.setIdleTimeout(600000); + config.setMaxLifetime(1800000); + + // Настройки соединения + config.addDataSourceProperty("cachePrepStmts", "true"); + config.addDataSourceProperty("prepStmtCacheSize", "250"); + config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); + config.addDataSourceProperty("useServerPrepStmts", "true"); + + dataSource = new HikariDataSource(config); + // Логирование убрано - успех проверяется через testConnection() + + } catch (Exception e) { + logger.severe("❌ Ошибка подключения к БД: " + e.getMessage()); + // e.printStackTrace(); // Убрано для чистоты логов + } + } + + /** + * Получить соединение из пула + */ + public Connection getConnection() throws SQLException { + if (dataSource == null) { + throw new SQLException("DataSource не инициализирован"); + } + return dataSource.getConnection(); + } + + /** + * Проверить подключение к базе данных + */ + public boolean testConnection() { + try (Connection conn = getConnection()) { + return conn.isValid(5); + } catch (SQLException e) { + logger.severe("Ошибка проверки подключения к БД: " + e.getMessage()); + return false; + } + } + + /** + * Получить игрока по никнейму + */ + public CompletableFuture> getPlayerByUsername(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT * FROM authplugin WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return Optional.of(mapResultSetToAuthPlayer(rs)); + } + + return Optional.empty(); + + } catch (SQLException e) { + logger.severe("Ошибка получения игрока " + username + ": " + e.getMessage()); + return Optional.empty(); + } + }); + } + + /** + * Получить игрока по UUID + */ + public CompletableFuture> getPlayerByUUID(String uuid) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT * FROM authplugin WHERE uuid = ?"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, uuid); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return Optional.of(mapResultSetToAuthPlayer(rs)); + } + + return Optional.empty(); + + } catch (SQLException e) { + logger.severe("Ошибка получения игрока по UUID " + uuid + ": " + e.getMessage()); + return Optional.empty(); + } + }); + } + + /** + * Зарегистрировать нового игрока + */ + public CompletableFuture registerPlayer(String username, String passwordHash, + String uuid, String ipAddress) { + return CompletableFuture.supplyAsync(() -> { + String query = "INSERT INTO authplugin (username, password_hash, uuid, ip_address, login_type) " + + "VALUES (?, ?, ?, ?, 0) " + + "ON CONFLICT (username) DO NOTHING"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + stmt.setString(2, passwordHash); + stmt.setString(3, uuid); + stmt.setString(4, ipAddress); + + int affected = stmt.executeUpdate(); + + if (affected > 0) { + // Логирование убрано - уже логируется в AuthManager + return true; + } + + // Логирование убрано + return false; + + } catch (SQLException e) { + logger.severe("Ошибка регистрации игрока " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Обновить последний вход игрока + */ + public CompletableFuture updateLastLogin(String username, String ipAddress) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET last_login = NOW(), ip_address = ? " + + "WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, ipAddress); + stmt.setString(2, username); + + stmt.executeUpdate(); + return true; + + } catch (SQLException e) { + logger.severe("Ошибка обновления последнего входа " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Изменить пароль игрока + */ + public CompletableFuture changePassword(String username, String newPasswordHash) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET password_hash = ? WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, newPasswordHash); + stmt.setString(2, username); + + int affected = stmt.executeUpdate(); + + if (affected > 0) { + logger.info("Пароль игрока " + username + " успешно изменен"); + return true; + } + + return false; + + } catch (SQLException e) { + logger.severe("Ошибка изменения пароля " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Получить email игрока из таблицы users (сайта) + */ + public CompletableFuture> getEmailByNickname(String nickname) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT email FROM users WHERE LOWER(nickname) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, nickname); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return Optional.of(rs.getString("email")); + } + + return Optional.empty(); + + } catch (SQLException e) { + logger.severe("Ошибка получения email для " + nickname + ": " + e.getMessage()); + return Optional.empty(); + } + }); + } + + /** + * Создать код подтверждения для смены режима авторизации + */ + public CompletableFuture createVerificationCode(String username, String code) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET " + + "email_verification_code = ?, " + + "email_verification_expires = NOW() + INTERVAL '15 minutes' " + + "WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, code); + stmt.setString(2, username); + + int affected = stmt.executeUpdate(); + return affected > 0; + + } catch (SQLException e) { + logger.severe("Ошибка создания кода подтверждения для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Проверить код подтверждения и сменить режим авторизации + */ + public CompletableFuture verifyAndChangeLoginType(String username, String code, int newLoginType) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET " + + "login_type = ?, " + + "email_verification_code = NULL, " + + "email_verification_expires = NULL " + + "WHERE LOWER(username) = LOWER(?) " + + "AND email_verification_code = ? " + + "AND email_verification_expires > NOW()"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setInt(1, newLoginType); + stmt.setString(2, username); + stmt.setString(3, code); + + int affected = stmt.executeUpdate(); + + if (affected > 0) { + logger.info("Режим авторизации игрока " + username + " изменен на " + + (newLoginType == 0 ? "простой" : "через сайт")); + return true; + } + + logger.warning("Неверный или истекший код подтверждения для " + username); + return false; + + } catch (SQLException e) { + logger.severe("Ошибка смены режима авторизации для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Обновить email игрока в authplugin из таблицы users + */ + public CompletableFuture syncEmailFromUsers(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin a SET email = u.email " + + "FROM users u " + + "WHERE LOWER(a.username) = LOWER(u.nickname) " + + "AND LOWER(a.username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + + int affected = stmt.executeUpdate(); + return affected > 0; + + } catch (SQLException e) { + logger.severe("Ошибка синхронизации email для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Удалить игрока из БД authplugin + */ + public CompletableFuture deletePlayer(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "DELETE FROM authplugin WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + + int affected = stmt.executeUpdate(); + + if (affected > 0) { + logger.info("Игрок " + username + " успешно удален из БД authplugin"); + return true; + } + + logger.warning("Игрок " + username + " не найден в БД authplugin"); + return false; + + } catch (SQLException e) { + logger.severe("Ошибка удаления игрока " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Получить количество неудачных попыток входа для игрока + */ + public CompletableFuture getFailedLoginAttempts(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT failed_attempts FROM authplugin WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return rs.getInt("failed_attempts"); + } + + return 0; + + } catch (SQLException e) { + logger.severe("Ошибка получения попыток входа для " + username + ": " + e.getMessage()); + return 0; + } + }); + } + + /** + * Увеличить счетчик неудачных попыток входа + */ + public CompletableFuture incrementFailedAttempts(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET " + + "failed_attempts = COALESCE(failed_attempts, 0) + 1, " + + "last_failed_attempt = NOW() " + + "WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + + stmt.executeUpdate(); + return true; + + } catch (SQLException e) { + logger.severe("Ошибка увеличения счетчика попыток для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Сбросить счетчик неудачных попыток входа + */ + public CompletableFuture resetFailedAttempts(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "UPDATE authplugin SET " + + "failed_attempts = 0, " + + "last_failed_attempt = NULL " + + "WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + + stmt.executeUpdate(); + return true; + + } catch (SQLException e) { + logger.severe("Ошибка сброса счетчика попыток для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Проверить, заблокирован ли игрок из-за превышения попыток + */ + public CompletableFuture isPlayerLocked(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT failed_attempts, last_failed_attempt FROM authplugin " + + "WHERE LOWER(username) = LOWER(?)"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + int failedAttempts = rs.getInt("failed_attempts"); + Timestamp lastFailed = rs.getTimestamp("last_failed_attempt"); + + // Если больше 5 попыток + if (failedAttempts >= 5) { + // Проверяем, прошло ли 5 минут с последней попытки + if (lastFailed != null) { + long minutesSinceLastFailed = + (System.currentTimeMillis() - lastFailed.getTime()) / (1000 * 60); + + // Если прошло менее 5 минут - заблокирован + return minutesSinceLastFailed < 5; + } + return true; + } + } + + return false; + + } catch (SQLException e) { + logger.severe("Ошибка проверки блокировки для " + username + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Получить время до разблокировки (в минутах) + */ + public CompletableFuture getMinutesUntilUnlock(String username) { + return CompletableFuture.supplyAsync(() -> { + String query = "SELECT last_failed_attempt FROM authplugin " + + "WHERE LOWER(username) = LOWER(?) AND failed_attempts >= 5"; + + try (Connection conn = getConnection(); + PreparedStatement stmt = conn.prepareStatement(query)) { + + stmt.setString(1, username); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + Timestamp lastFailed = rs.getTimestamp("last_failed_attempt"); + + if (lastFailed != null) { + long minutesSinceLastFailed = + (System.currentTimeMillis() - lastFailed.getTime()) / (1000 * 60); + + int minutesRemaining = (int) (5 - minutesSinceLastFailed); + return Math.max(0, minutesRemaining); + } + } + + return 0; + + } catch (SQLException e) { + logger.severe("Ошибка получения времени до разблокировки для " + username + ": " + e.getMessage()); + return 0; + } + }); + } + + /** + * Преобразовать ResultSet в объект AuthPlayer + */ + private AuthPlayer mapResultSetToAuthPlayer(ResultSet rs) throws SQLException { + AuthPlayer player = new AuthPlayer(); + player.setId(rs.getInt("id")); + player.setUsername(rs.getString("username")); + player.setPasswordHash(rs.getString("password_hash")); + player.setUuid(rs.getString("uuid")); + player.setIpAddress(rs.getString("ip_address")); + player.setLoginType(rs.getInt("login_type")); + player.setEmail(rs.getString("email")); + player.setEmailVerificationCode(rs.getString("email_verification_code")); + + Timestamp lastLogin = rs.getTimestamp("last_login"); + if (lastLogin != null) { + player.setLastLogin(lastLogin.toLocalDateTime()); + } + + Timestamp registeredAt = rs.getTimestamp("registered_at"); + if (registeredAt != null) { + player.setRegisteredAt(registeredAt.toLocalDateTime()); + } + + Timestamp verificationExpires = rs.getTimestamp("email_verification_expires"); + if (verificationExpires != null) { + player.setEmailVerificationExpires(verificationExpires.toLocalDateTime()); + } + + return player; + } + + /** + * Закрыть пул соединений + */ + public void close() { + if (dataSource != null && !dataSource.isClosed()) { + dataSource.close(); + logger.info("Пул соединений PostgreSQL закрыт"); + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/AuthenticationListener.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/AuthenticationListener.java new file mode 100644 index 00000000000..f3635363855 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/AuthenticationListener.java @@ -0,0 +1,309 @@ +package org.ebluffy.chiwawa.listeners; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.*; +import org.bukkit.event.entity.FoodLevelChangeEvent; +import org.bukkit.event.entity.EntityPickupItemEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.ChiwawaPlugin; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.AuthManager; +import org.ebluffy.chiwawa.managers.UserManager; + +/** + * Листенер для ограничения действий неавторизованных игроков + * РАБОТАЕТ ТОЛЬКО ЕСЛИ enable_authentication: true + */ +public class AuthenticationListener implements Listener { + private final JavaPlugin plugin; + private final ConfigManager configManager; + private final UserManager userManager; + private final AuthManager authManager; + + public AuthenticationListener(JavaPlugin plugin, UserManager userManager) { + this.plugin = plugin; + this.configManager = ((ChiwawaPlugin) plugin).getConfigManager(); + this.userManager = userManager; + this.authManager = ((ChiwawaPlugin) plugin).getAuthManager(); + } + + /** + * Проверяет, нужно ли требовать авторизацию + */ + private boolean isAuthenticationRequired() { + return configManager.isAuthenticationEnabled(); + } + + /** + * Проверяет, авторизован ли игрок (оба режима) + */ + private boolean isPlayerAuthenticated(Player player) { + // Если система авторизации отключена - все авторизованы + if (!isAuthenticationRequired()) { + return true; + } + + // Проверяем оба режима авторизации + return userManager.isPlayerCached(player.getUniqueId()) || + authManager.isPlayerAuthorized(player.getUniqueId()); + } + + /** + * Отправляет сообщение о необходимости авторизации + */ + private void sendAuthenticationReminder(Player player) { + player.sendMessage("§c§lВы не авторизованы!"); + player.sendMessage("§7Новый игрок? §a/register <пароль> <повтор>"); + player.sendMessage("§7Уже зарегистрированы? §a/login <пароль>"); + player.sendMessage("§7Или получите токен на: §b§nhttps://chiwawa.site"); + } + + /** + * Запрещает движение неавторизованным игрокам + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerMove(PlayerMoveEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + // Разрешаем только поворот головы (yaw/pitch), но не движение по координатам + if (event.getFrom().getX() != event.getTo().getX() || + event.getFrom().getY() != event.getTo().getY() || + event.getFrom().getZ() != event.getTo().getZ()) { + + event.setTo(event.getFrom()); + + // Отправляем напоминание не чаще раза в 5 секунд + long currentTime = System.currentTimeMillis(); + Long lastReminder = (Long) player.getMetadata("last_auth_reminder").stream() + .findFirst() + .map(metadataValue -> metadataValue.value()) + .orElse(0L); + + if (currentTime - lastReminder > 5000) { + sendAuthenticationReminder(player); + player.setMetadata("last_auth_reminder", + new org.bukkit.metadata.FixedMetadataValue(plugin, currentTime)); + } + } + } + } + + /** + * Запрещает ломать блоки + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onBlockBreak(BlockBreakEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + + /** + * Запрещает ставить блоки + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onBlockPlace(BlockPlaceEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + + /** + * Запрещает взаимодействие с предметами + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerInteract(PlayerInteractEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + + /** + * Запрещает взаимодействие с сущностями + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + + /** + * Запрещает выбрасывать предметы + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerDropItem(PlayerDropItemEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + + /** + * Запрещает поднимать предметы (современная версия события) + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityPickupItem(EntityPickupItemEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + } + } + } + + /** + * Запрещает открывать инвентари + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryOpen(InventoryOpenEvent event) { + if (event.getPlayer() instanceof Player) { + Player player = (Player) event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + } + + /** + * Запрещает взаимодействие с инвентарем + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onInventoryClick(InventoryClickEvent event) { + if (event.getWhoClicked() instanceof Player) { + Player player = (Player) event.getWhoClicked(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + } + + /** + * Запрещает наносить урон другим игрокам + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityDamageByEntity(EntityDamageByEntityEvent event) { + if (event.getDamager() instanceof Player) { + Player damager = (Player) event.getDamager(); + + if (!isPlayerAuthenticated(damager)) { + event.setCancelled(true); + sendAuthenticationReminder(damager); + } + } + } + + /** + * Защищает неавторизованных игроков от урона + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onEntityDamage(EntityDamageEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + + if (!isPlayerAuthenticated(player)) { + // Защищаем от всех видов урона кроме void (чтобы не застрять в void) + if (event.getCause() != EntityDamageEvent.DamageCause.VOID) { + event.setCancelled(true); + } + } + } + } + + /** + * Запрещает терять голод + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onFoodLevelChange(FoodLevelChangeEvent event) { + if (event.getEntity() instanceof Player) { + Player player = (Player) event.getEntity(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + } + } + } + + /** + * Запрещает писать в чат (кроме команд авторизации) + */ + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChat(AsyncPlayerChatEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + event.setCancelled(true); + + // Асинхронно отправляем сообщение + plugin.getServer().getScheduler().runTask(plugin, () -> { + sendAuthenticationReminder(player); + }); + } + } + + /** + * Разрешаем только команды авторизации и регистрации + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { + Player player = event.getPlayer(); + String command = event.getMessage().toLowerCase(); + + if (!isPlayerAuthenticated(player)) { + // Разрешаем только команды авторизации и регистрации + if (!command.startsWith("/login") && + !command.startsWith("/l ") && + !command.startsWith("/register") && + !command.startsWith("/reg ")) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + } + + /** + * Запрещает телепортацию + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerTeleport(PlayerTeleportEvent event) { + Player player = event.getPlayer(); + + if (!isPlayerAuthenticated(player)) { + // Разрешаем телепортацию только при входе на сервер (PLUGIN причина) + if (event.getCause() != PlayerTeleportEvent.TeleportCause.PLUGIN) { + event.setCancelled(true); + sendAuthenticationReminder(player); + } + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/PlayerListener.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/PlayerListener.java new file mode 100644 index 00000000000..7cca2ead33f --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/listeners/PlayerListener.java @@ -0,0 +1,280 @@ +package org.ebluffy.chiwawa.listeners; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.config.ConfigManager; +import org.ebluffy.chiwawa.managers.PlaytimeManager; +import org.ebluffy.chiwawa.managers.PlayerStatsManager; +import org.ebluffy.chiwawa.managers.UserManager; + +import java.util.logging.Logger; + +/** + * Слушатель событий игроков + */ +public class PlayerListener implements Listener { + private final JavaPlugin plugin; + private final Logger logger; + private final ConfigManager configManager; + private final UserManager userManager; + private final PlaytimeManager playtimeManager; + private final PlayerStatsManager playerStatsManager; + private final ApiClient apiClient; + private final org.ebluffy.chiwawa.managers.StatsManager statsManager; + + public PlayerListener(JavaPlugin plugin, ConfigManager configManager, UserManager userManager, PlaytimeManager playtimeManager, PlayerStatsManager playerStatsManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.configManager = configManager; + this.userManager = userManager; + this.playtimeManager = playtimeManager; + this.playerStatsManager = playerStatsManager; + // Получаем ApiClient и StatsManager из главного плагина + this.apiClient = ((org.ebluffy.chiwawa.ChiwawaPlugin) plugin).getApiClient(); + this.statsManager = ((org.ebluffy.chiwawa.ChiwawaPlugin) plugin).getStatsManager(); + } + + /** + * Обработка входа игрока (асинхронно, до входа на сервер) + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void onAsyncPlayerPreLogin(AsyncPlayerPreLoginEvent event) { + String playerName = event.getName(); + logger.info("Проверка доступа для игрока: " + playerName); + + try { + // Сначала проверяем соединение с API + Boolean apiConnected = apiClient.testConnection().get(); + + if (!apiConnected) { + event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, + "§cОшибка подключения к серверу!\n§fПопробуйте зайти позже.\n§7Ошибка: API недоступен"); + logger.severe("Игрок " + playerName + " не допущен - API недоступен"); + return; + } + + // Если whitelist включен, проверяем доступ + if (configManager.isWhitelistEnabled()) { + Boolean hasAccess = apiClient.checkServerAccess(playerName).get(); + + if (!hasAccess) { + event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_WHITELIST, + configManager.getMessage("no_access_kick")); + logger.info("Игрок " + playerName + " не допущен на сервер - нет доступа"); + return; + } + } + + // ВАЖНО: Проверяем бан игрока ВСЕГДА (независимо от whitelist) + ChiwawaUser user = apiClient.getUserByNickname(playerName).get(); + if (user != null && user.isBanned()) { + String banMessage = "§c§lВЫ ЗАБЛОКИРОВАНЫ НА СЕРВЕРЕ\n\n"; + banMessage += "§fПричина: §c" + (user.getBanReason() != null ? user.getBanReason() : "Не указана") + "\n\n"; + + if (user.getBanUntil() != null && !user.getBanUntil().isEmpty()) { + // Временный бан + banMessage += "§fТип бана: §eВременный\n"; + banMessage += "§fОстается времени: §e" + user.getFormattedBanTimeRemaining() + "\n\n"; + } else { + // Постоянный бан + banMessage += "§fТип бана: §4Постоянный\n\n"; + } + + banMessage += "§7Обратитесь к администрации для разбана\n"; + banMessage += "§7Discord: §bhttps://discord.gg/chiwawa"; + + event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_BANNED, banMessage); + logger.info("Игрок " + playerName + " не допущен на сервер - заблокирован: " + user.getBanReason()); + return; + } + + logger.info("Игрок " + playerName + " допущен на сервер"); + + } catch (Exception e) { + logger.severe("Ошибка проверки доступа для " + playerName + ": " + e.getMessage()); + + // В случае ошибки API - НЕ пускаем игрока (fail-secure) + event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, + "§cОшибка подключения к серверу!\n§fПопробуйте зайти позже.\n§7Ошибка: " + e.getMessage()); + logger.warning("Игрок " + playerName + " не допущен из-за ошибки API"); + } + } + + /** + * Обработка входа игрока на сервер + */ + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + String playerName = player.getName(); + String playerUuid = player.getUniqueId().toString(); + String ipAddress = player.getAddress().getAddress().getHostAddress(); + + // Сначала проверяем активную игровую сессию + apiClient.checkGameSession(playerName, playerUuid, ipAddress) + .thenAccept(sessionResult -> { + if (sessionResult.isValid()) { + // Сессия найдена, авторизуем игрока автоматически + plugin.getServer().getScheduler().runTask(plugin, () -> { + userManager.authorizePlayer(player, sessionResult.getUserId()); + + // Уведомляем StatsManager о входе игрока + statsManager.onPlayerJoin(player.getUniqueId()); + + // Запускаем отслеживание сессии игрока + playerStatsManager.startPlayerSession(player); + + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + player.sendMessage("§a§l✓ Добро пожаловать!"); + player.sendMessage("§7Вы автоматически авторизованы по сохраненной сессии"); + player.sendMessage("§7Роль: §a" + getRoleDisplayName(sessionResult.getRole())); + player.sendMessage("§7Trust Level: §a" + sessionResult.getTrustLevel()); + }, 20L); + + logger.info("Игрок " + playerName + " автоматически авторизован по сессии"); + + // Загружаем данные пользователя + loadUserDataAfterAuth(player); + }); + } else { + // Сессия не найдена, требуется авторизация через токен + plugin.getServer().getScheduler().runTask(plugin, () -> { + showAuthorizationMessage(player); + + // Даем игроку 5 минут на авторизацию + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + if (!userManager.isPlayerCached(player.getUniqueId())) { + player.kickPlayer("§cВремя авторизации истекло"); + logger.info("Игрок " + playerName + " кикнут за неавторизованность"); + } + }, 20L * 60 * 5); // 5 минут + }); + } + }) + .exceptionally(throwable -> { + logger.warning("Ошибка проверки сессии для " + playerName + ": " + throwable.getMessage()); + + // В случае ошибки требуем авторизацию через токен + plugin.getServer().getScheduler().runTask(plugin, () -> { + showAuthorizationMessage(player); + }); + + return null; + }); + } + + /** + * Показать сообщение о необходимости авторизации + */ + private void showAuthorizationMessage(Player player) { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + player.sendMessage("§c§l ТРЕБУЕТСЯ АВТОРИЗАЦИЯ"); + player.sendMessage(""); + player.sendMessage("§7Выберите способ авторизации:"); + player.sendMessage(""); + player.sendMessage("§a§l1. ПРОСТАЯ АВТОРИЗАЦИЯ"); + player.sendMessage("§7 Новый игрок? §f/register <пароль> <повтор>"); + player.sendMessage("§7 Уже есть аккаунт? §f/login <пароль>"); + player.sendMessage(""); + player.sendMessage("§b§l2. ЧЕРЕЗ САЙТ §7(рекомендуется)"); + player.sendMessage("§7 • Зайдите на: §b§nhttps://chiwawa.site"); + player.sendMessage("§7 • Получите токен в личном кабинете"); + player.sendMessage("§7 • Используйте: §f/login <токен>"); + player.sendMessage(""); + player.sendMessage("§7У вас есть §c5 минут §7для авторизации"); + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + }, 20L); + } + + /** + * Загрузить данные пользователя после авторизации + */ + private void loadUserDataAfterAuth(Player player) { + // Регистрируем время входа + playtimeManager.onPlayerJoin(player.getUniqueId()); + + // Получаем данные из кеша (они уже должны быть загружены через userManager.authorizePlayer) + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + ChiwawaUser user = userManager.getCachedUser(player.getUniqueId()); + if (user != null) { + showWelcomeMessage(player, user); + logger.info("Игрок " + player.getName() + " загружен с данными (Trust Level: " + user.getTrustLevel() + ", Role: " + user.getRole() + ")"); + } + }, 40L); // Небольшая задержка чтобы данные точно загрузились + } + + /** + * Обработка выхода игрока + */ + @EventHandler(priority = EventPriority.MONITOR) + public void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + + // Уведомляем StatsManager о выходе игрока + statsManager.onPlayerQuit(player.getUniqueId()); + + // Завершаем отслеживание сессии игрока + playerStatsManager.endPlayerSession(player); + + // Сохраняем время игры + playtimeManager.onPlayerQuit(player.getUniqueId()) + .thenRun(() -> { + // Выгружаем данные из кеша + userManager.unloadUser(player.getUniqueId()); + logger.info("Игрок " + player.getName() + " покинул сервер"); + }) + .exceptionally(throwable -> { + logger.severe("Ошибка при выходе игрока " + player.getName() + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Показать приветственное сообщение игроку + */ + private void showWelcomeMessage(Player player, ChiwawaUser user) { + plugin.getServer().getScheduler().runTaskLater(plugin, () -> { + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + player.sendMessage("§f§l Добро пожаловать на §bChiwawaMine§f!"); + player.sendMessage(""); + player.sendMessage("§7Ваша роль: §a" + getRoleDisplayName(user.getRole())); + player.sendMessage("§7Trust Level: §a" + user.getTrustLevel() + " §7(" + user.getTrustLevelDescription() + ")"); + + if (user.hasTimeLimit()) { + int remaining = playtimeManager.getRemainingTime(player.getUniqueId()); + player.sendMessage("§7Лимит времени: §c" + playtimeManager.formatTime(remaining) + " §7из 10 часов"); + player.sendMessage("§7Подтвердите email на сайте для снятия лимита!"); + player.sendMessage("§7Сайт: §b§nhttps://chiwawa.site"); + } + + player.sendMessage(""); + player.sendMessage("§7Полезные команды:"); + player.sendMessage("§7• §f/profile §7- Ваш профиль"); + player.sendMessage("§7• §f/playtime §7- Время игры"); + player.sendMessage("§7• §f/rep <игрок> §7- Дать репутацию"); + player.sendMessage("§7• §f/discord §7- Discord сервер"); + player.sendMessage("§e§l━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); + }, 20L); // Задержка 1 секунда + } + + /** + * Получить отображаемое название роли + */ + private String getRoleDisplayName(String role) { + switch (role) { + case "admin": return "Администратор"; + case "moderator": return "Модератор"; + case "user": return "Пользователь"; + default: return "Неизвестная роль"; + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/AuthManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/AuthManager.java new file mode 100644 index 00000000000..04cccc949e0 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/AuthManager.java @@ -0,0 +1,479 @@ +package org.ebluffy.chiwawa.managers; + +import at.favre.lib.crypto.bcrypt.BCrypt; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.dto.AuthPlayer; +import org.ebluffy.chiwawa.database.DatabaseManager; + +import java.security.SecureRandom; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +/** + * Менеджер для управления простой авторизацией игроков + */ +public class AuthManager { + private final JavaPlugin plugin; + private final Logger logger; + private final DatabaseManager databaseManager; + + // Кеш авторизованных игроков (UUID -> AuthPlayer) + private final Map authorizedPlayers = new ConcurrentHashMap<>(); + + // Кеш кодов подтверждения для смены режима (UUID -> код) + private final Map pendingVerifications = new ConcurrentHashMap<>(); + + // BCrypt параметры + private static final int BCRYPT_COST = 12; + + public AuthManager(JavaPlugin plugin, DatabaseManager databaseManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.databaseManager = databaseManager; + } + + /** + * Зарегистрировать игрока с паролем + */ + public CompletableFuture registerPlayer(Player player, String password) { + String username = player.getName(); + String uuid = player.getUniqueId().toString(); + String ipAddress = player.getAddress().getAddress().getHostAddress(); + + // Проверяем, не зарегистрирован ли игрок + return databaseManager.getPlayerByUsername(username) + .thenCompose(existingPlayer -> { + if (existingPlayer.isPresent()) { + logger.warning("Попытка регистрации уже существующего игрока: " + username); + return CompletableFuture.completedFuture(false); + } + + // Хешируем пароль + String passwordHash = hashPassword(password); + + // Регистрируем в БД + return databaseManager.registerPlayer(username, passwordHash, uuid, ipAddress) + .thenCompose(success -> { + if (success) { + // Загружаем данные игрока + return databaseManager.getPlayerByUsername(username) + .thenApply(authPlayer -> { + authPlayer.ifPresent(ap -> { + authorizedPlayers.put(player.getUniqueId(), ap); + // Логирование убрано - уже в RegisterCommand + }); + return authPlayer.isPresent(); + }); + } + return CompletableFuture.completedFuture(false); + }); + }); + } + + /** + * Авторизовать игрока с паролем + */ + public CompletableFuture loginPlayer(Player player, String password) { + String username = player.getName(); + String ipAddress = player.getAddress().getAddress().getHostAddress(); + + // Сначала проверяем блокировку + return databaseManager.isPlayerLocked(username) + .thenCompose(isLocked -> { + if (isLocked) { + // Получаем время до разблокировки + return databaseManager.getMinutesUntilUnlock(username) + .thenApply(minutesRemaining -> { + logger.warning("Попытка входа заблокированного игрока: " + username + + " (осталось " + minutesRemaining + " минут)"); + + // Логируем попытку входа заблокированного игрока + logAuthAttempt(player, false, "Аккаунт временно заблокирован (" + minutesRemaining + " мин)"); + + // Возвращаем -1 как признак блокировки + return -1; + }) + .thenCompose(result -> CompletableFuture.completedFuture(false)); + } + + // Продолжаем обычную авторизацию + return databaseManager.getPlayerByUsername(username) + .thenCompose(authPlayerOpt -> { + if (authPlayerOpt.isEmpty()) { + logger.warning("Попытка входа незарегистрированного игрока: " + username); + logAuthAttempt(player, false, "Игрок не зарегистрирован"); + return CompletableFuture.completedFuture(false); + } + + AuthPlayer authPlayer = authPlayerOpt.get(); + + // Проверяем тип авторизации + if (authPlayer.isWebsiteAuth()) { + logger.warning("Игрок " + username + " использует авторизацию через сайт"); + logAuthAttempt(player, false, "Использует авторизацию через сайт"); + return CompletableFuture.completedFuture(false); + } + + // Проверяем пароль + if (!verifyPassword(password, authPlayer.getPasswordHash())) { + logger.warning("Неверный пароль для игрока: " + username); + + // Увеличиваем счетчик неудачных попыток + databaseManager.incrementFailedAttempts(username); + + // Проверяем количество попыток + return databaseManager.getFailedLoginAttempts(username) + .thenApply(attempts -> { + if (attempts >= 5) { + logger.warning("Игрок " + username + " превысил лимит попыток входа (5)"); + logAuthAttempt(player, false, "Неверный пароль (попытка " + attempts + "/5) - заблокирован на 5 минут"); + } else { + logAuthAttempt(player, false, "Неверный пароль (попытка " + attempts + "/5)"); + } + return false; + }); + } + + // Пароль верный - сбрасываем счетчик попыток + databaseManager.resetFailedAttempts(username); + + // Обновляем последний вход + return databaseManager.updateLastLogin(username, ipAddress) + .thenApply(success -> { + if (success) { + authorizedPlayers.put(player.getUniqueId(), authPlayer); + logger.info("Игрок " + username + " успешно авторизовался"); + logAuthAttempt(player, true, "Успешная авторизация"); + return true; + } + return false; + }); + }); + }); + } + + /** + * Изменить пароль игрока + */ + public CompletableFuture changePassword(Player player, String oldPassword, String newPassword) { + String username = player.getName(); + + return databaseManager.getPlayerByUsername(username) + .thenCompose(authPlayerOpt -> { + if (authPlayerOpt.isEmpty()) { + return CompletableFuture.completedFuture(false); + } + + AuthPlayer authPlayer = authPlayerOpt.get(); + + // Проверяем старый пароль + if (!verifyPassword(oldPassword, authPlayer.getPasswordHash())) { + logger.warning("Неверный старый пароль при смене для игрока: " + username); + return CompletableFuture.completedFuture(false); + } + + // Хешируем новый пароль + String newPasswordHash = hashPassword(newPassword); + + // Обновляем в БД + return databaseManager.changePassword(username, newPasswordHash) + .thenApply(success -> { + if (success) { + logger.info("Пароль игрока " + username + " успешно изменен"); + } + return success; + }); + }); + } + + /** + * Начать процесс смены режима авторизации на сайт + */ + public CompletableFuture requestAuthModeChange(Player player) { + String username = player.getName(); + + // Получаем email из таблицы users + return databaseManager.getEmailByNickname(username) + .thenCompose(emailOpt -> { + if (emailOpt.isEmpty()) { + logger.warning("Email не найден для игрока " + username + " в таблице users"); + return CompletableFuture.completedFuture("EMAIL_NOT_FOUND"); + } + + String email = emailOpt.get(); + + // Генерируем код подтверждения + String verificationCode = generateVerificationCode(); + + // Сохраняем код в БД + return databaseManager.createVerificationCode(username, verificationCode) + .thenCompose(success -> { + if (!success) { + return CompletableFuture.completedFuture("DB_ERROR"); + } + + // Сохраняем код в кеше + pendingVerifications.put(player.getUniqueId(), verificationCode); + + // Отправляем email через API + return sendVerificationEmail(username, email, verificationCode) + .thenApply(emailSent -> { + if (emailSent) { + logger.info("Код подтверждения отправлен на email для " + username); + return "SUCCESS:" + email; + } else { + logger.warning("Не удалось отправить email для " + username); + return "EMAIL_SEND_ERROR"; + } + }); + }); + }); + } + + /** + * Подтвердить смену режима авторизации + */ + public CompletableFuture confirmAuthModeChange(Player player, String code) { + String username = player.getName(); + + return databaseManager.verifyAndChangeLoginType(username, code, 1) + .thenApply(success -> { + if (success) { + pendingVerifications.remove(player.getUniqueId()); + + // Обновляем кеш + AuthPlayer authPlayer = authorizedPlayers.get(player.getUniqueId()); + if (authPlayer != null) { + authPlayer.setLoginType(1); + } + + logger.info("Игрок " + username + " успешно переключился на авторизацию через сайт"); + return true; + } + + logger.warning("Неверный или истекший код подтверждения для " + username); + return false; + }); + } + + /** + * Проверить, авторизован ли игрок + */ + public boolean isPlayerAuthorized(UUID playerUuid) { + return authorizedPlayers.containsKey(playerUuid); + } + + /** + * Получить данные авторизованного игрока + */ + public Optional getAuthorizedPlayer(UUID playerUuid) { + return Optional.ofNullable(authorizedPlayers.get(playerUuid)); + } + + /** + * Выход игрока (очистка кеша) + */ + public void logoutPlayer(UUID playerUuid) { + AuthPlayer removed = authorizedPlayers.remove(playerUuid); + pendingVerifications.remove(playerUuid); + + if (removed != null) { + logger.info("Игрок " + removed.getUsername() + " вышел из системы"); + } + } + + /** + * Очистить все кеши + */ + public void clearCaches() { + authorizedPlayers.clear(); + pendingVerifications.clear(); + logger.info("Кеши авторизации очищены"); + } + + /** + * Хешировать пароль с использованием BCrypt + */ + private String hashPassword(String password) { + return BCrypt.withDefaults().hashToString(BCRYPT_COST, password.toCharArray()); + } + + /** + * Проверить пароль + */ + private boolean verifyPassword(String password, String passwordHash) { + BCrypt.Result result = BCrypt.verifyer().verify(password.toCharArray(), passwordHash); + return result.verified; + } + + /** + * Генерировать случайный код подтверждения + */ + private String generateVerificationCode() { + SecureRandom random = new SecureRandom(); + int code = 100000 + random.nextInt(900000); // 6-значный код + return String.valueOf(code); + } + + /** + * Отправить email с кодом подтверждения через API сайта + */ + private CompletableFuture sendVerificationEmail(String username, String email, String code) { + return CompletableFuture.supplyAsync(() -> { + try { + // Получаем API клиент из главного плагина + org.ebluffy.chiwawa.ChiwawaPlugin plugin = + (org.ebluffy.chiwawa.ChiwawaPlugin) org.bukkit.Bukkit.getPluginManager().getPlugin("ChiwawaPlugin"); + + if (plugin == null) { + logger.severe("ChiwawaPlugin не найден!"); + return false; + } + + org.ebluffy.chiwawa.api.ApiClient apiClient = plugin.getApiClient(); + + // Отправляем запрос на отправку email через API + com.google.gson.JsonObject requestBody = new com.google.gson.JsonObject(); + requestBody.addProperty("email", email); + requestBody.addProperty("username", username); + requestBody.addProperty("code", code); + requestBody.addProperty("type", "login_change"); + requestBody.addProperty("subject", "Подтверждение смены режима авторизации"); + + // Формируем текст письма + String messageText = String.format( + "Здравствуйте, %s!\n\n" + + "Вы запросили смену режима авторизации на сервере ChiwawaMine.\n\n" + + "Ваш код подтверждения: %s\n\n" + + "Используйте команду в игре: /changelogin confirm %s\n\n" + + "Код действителен 15 минут.\n\n" + + "Если вы не запрашивали смену режима, проигнорируйте это письмо.\n\n" + + "С уважением,\n" + + "Команда ChiwawaMine", + username, code, code + ); + + requestBody.addProperty("message", messageText); + + // Используем существующий метод API для отправки через backend + Boolean result = apiClient.sendCustomEmail(email, + "Подтверждение смены режима авторизации", + messageText).get(); + + if (result) { + logger.info("Код подтверждения успешно отправлен на email " + email + " для игрока " + username); + } else { + logger.warning("Не удалось отправить код подтверждения на email " + email); + } + + return result; + + } catch (Exception e) { + logger.severe("Ошибка отправки email: " + e.getMessage()); + e.printStackTrace(); + return false; + } + }); + } + + /** + * Получить количество авторизованных игроков + */ + public int getAuthorizedPlayersCount() { + return authorizedPlayers.size(); + } + + /** + * Логирование попыток авторизации в отдельный файл + */ + private void logAuthAttempt(Player player, boolean success, String reason) { + String logMessage = String.format( + "[%s] Player: %s, UUID: %s, IP: %s, Success: %s, Reason: %s, Time: %s", + success ? "AUTH_SUCCESS" : "AUTH_FAILED", + player.getName(), + player.getUniqueId(), + player.getAddress().getAddress().getHostAddress(), + success, + reason, + new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()) + ); + + // Используем отдельный логгер для аудита авторизаций + java.util.logging.Logger authLogger = java.util.logging.Logger.getLogger("ChiwawaAuth"); + + try { + // Создаем обработчик для записи в отдельный файл auth.log + java.util.logging.FileHandler fileHandler = new java.util.logging.FileHandler( + "plugins/ChiwawaPlugin/logs/auth.log", true); + fileHandler.setFormatter(new java.util.logging.SimpleFormatter() { + private static final String format = "%1$s%n"; + + @Override + public synchronized String format(java.util.logging.LogRecord lr) { + return String.format(format, lr.getMessage()); + } + }); + + authLogger.addHandler(fileHandler); + authLogger.setUseParentHandlers(false); + + if (success) { + authLogger.info(logMessage); + } else { + authLogger.warning(logMessage); + } + + fileHandler.close(); + + } catch (Exception e) { + logger.warning("Не удалось записать лог авторизации: " + e.getMessage()); + } + } + + /** + * Валидация пароля + */ + public static boolean isPasswordValid(String password) { + if (password == null || password.length() < 6) { + return false; + } + if (password.length() > 32) { + return false; + } + // Проверка на запрещенные символы + return password.matches("^[a-zA-Z0-9!@#$%^&*()_+\\-=\\[\\]{}|;:,.<>?]+$"); + } + + /** + * Получить силу пароля + */ + public static String getPasswordStrength(String password) { + if (password == null || password.length() < 6) { + return "Слабый"; + } + + int strength = 0; + + // Длина + if (password.length() >= 8) strength++; + if (password.length() >= 12) strength++; + + // Содержит цифры + if (password.matches(".*\\d.*")) strength++; + + // Содержит заглавные буквы + if (password.matches(".*[A-Z].*")) strength++; + + // Содержит специальные символы + if (password.matches(".*[!@#$%^&*()_+\\-=\\[\\]{}|;:,.<>?].*")) strength++; + + if (strength <= 1) return "Слабый"; + if (strength <= 3) return "Средний"; + return "Сильный"; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlayerStatsManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlayerStatsManager.java new file mode 100644 index 00000000000..24da40154d4 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlayerStatsManager.java @@ -0,0 +1,361 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.OfflinePlayer; +import org.bukkit.Statistic; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.ebluffy.chiwawa.api.ApiClient; + +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +/** + * Менеджер для сбора и отправки расширенной статистики игроков + */ +public class PlayerStatsManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + + // Хранение данных сессий игроков + private final Map playerSessions = new ConcurrentHashMap<>(); + private final Map> playerSessionHistory = new ConcurrentHashMap<>(); + + private BukkitRunnable statsUpdateTask; + + public PlayerStatsManager(JavaPlugin plugin, ApiClient apiClient) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + } + + /** + * Запуск автоматического обновления статистики + */ + public void startStatsUpdates() { + if (statsUpdateTask != null) { + statsUpdateTask.cancel(); + } + + // Обновляем статистику каждые 5 минут + statsUpdateTask = new BukkitRunnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + updatePlayerStats(player); + } + } + }; + + // Первое обновление через 1 минуту, затем каждые 5 минут + statsUpdateTask.runTaskTimerAsynchronously(plugin, 1200L, 6000L); // 1min, 5min + } + + /** + * Остановка обновления статистики + */ + public void stopStatsUpdates() { + if (statsUpdateTask != null) { + statsUpdateTask.cancel(); + statsUpdateTask = null; + } + } + + /** + * Начало игровой сессии + */ + public void startPlayerSession(Player player) { + UUID playerId = player.getUniqueId(); + PlayerSessionData sessionData = new PlayerSessionData(); + sessionData.sessionStart = System.currentTimeMillis(); + sessionData.loginTime = LocalTime.now(); + sessionData.startStats = collectPlayerStats(player); + + playerSessions.put(playerId, sessionData); + + // Увеличиваем счетчик входов сразу при старте сессии + incrementPlayerLogins(player); + + logger.fine("Начата сессия для игрока " + player.getName()); + } + + /** + * Увеличение счетчика входов игрока + */ + private void incrementPlayerLogins(Player player) { + Map loginStats = new HashMap<>(); + loginStats.put("increment_login", true); // Флаг для инкремента входов + loginStats.put("last_seen", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + + // Отправляем обновление счетчика входов + apiClient.updatePlayerStats(player.getName(), loginStats) + .thenAccept(success -> { + if (success) { + logger.fine("Счетчик входов обновлен для " + player.getName()); + } else { + logger.warning("Не удалось обновить счетчик входов для " + player.getName()); + } + }) + .exceptionally(throwable -> { + logger.warning("Ошибка обновления счетчика входов для " + player.getName() + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Завершение игровой сессии + */ + public void endPlayerSession(Player player) { + UUID playerId = player.getUniqueId(); + PlayerSessionData sessionData = playerSessions.remove(playerId); + + if (sessionData != null) { + long sessionDuration = System.currentTimeMillis() - sessionData.sessionStart; + + // Сохраняем в историю сессий + SessionHistory history = new SessionHistory(); + history.date = LocalDateTime.now(); + history.duration = sessionDuration; + history.loginTime = sessionData.loginTime; + + playerSessionHistory.computeIfAbsent(playerId, k -> new ArrayList<>()).add(history); + + // Обновляем статистику на сайте + updatePlayerStats(player); + + logger.fine("Завершена сессия для игрока " + player.getName() + + " (длительность: " + (sessionDuration / 1000 / 60) + " минут)"); + } + } + + /** + * Обновление статистики игрока + */ + public CompletableFuture updatePlayerStats(Player player) { + return CompletableFuture.supplyAsync(() -> { + try { + Map stats = new HashMap<>(); + + // Базовые данные + stats.put("minecraft_nick", player.getName()); + stats.put("last_seen", LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + stats.put("last_ip_address", player.getAddress().getAddress().getHostAddress()); + + // Время игры + int totalPlaytimeMinutes = player.getStatistic(Statistic.PLAY_ONE_MINUTE) / 20 / 60; // тики -> минуты + stats.put("time_played_minutes", totalPlaytimeMinutes); + + // Статистика сессий + UUID playerId = player.getUniqueId(); + List sessions = playerSessionHistory.getOrDefault(playerId, new ArrayList<>()); + + if (!sessions.isEmpty()) { + // Количество сессий (входов) + stats.put("session_count", sessions.size()); + stats.put("total_logins", sessions.size()); // Исправлено: количество входов + + // Средняя длительность сессии (в минутах) + long totalSessionTime = sessions.stream() + .mapToLong(s -> s.duration) + .sum(); + long averageSessionDuration = (totalSessionTime / sessions.size()) / 1000 / 60; + stats.put("average_session_duration", averageSessionDuration); + + // Самая длинная сессия (в минутах) + long longestSession = sessions.stream() + .mapToLong(s -> s.duration) + .max() + .orElse(0L) / 1000 / 60; + stats.put("longest_session_duration", longestSession); + + // Активные дни за последние 30 дней + LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30); + long activeDays = sessions.stream() + .filter(s -> s.date.isAfter(thirtyDaysAgo)) + .map(s -> s.date.toLocalDate()) + .distinct() + .count(); + stats.put("active_days_last_month", (int)activeDays); + + // Общее время игры за последние 30 дней (в минутах) + long totalTimeLastMonth = sessions.stream() + .filter(s -> s.date.isAfter(thirtyDaysAgo)) + .mapToLong(s -> s.duration) + .sum() / 1000 / 60; // миллисекунды -> минуты + stats.put("time_played_last_month", (int)totalTimeLastMonth); + + // Любимое время игры (час дня, когда чаще всего заходит) + Map hourFrequency = new HashMap<>(); + sessions.stream() + .filter(s -> s.date.isAfter(thirtyDaysAgo)) + .forEach(s -> { + int hour = s.loginTime.getHour(); + hourFrequency.put(hour, hourFrequency.getOrDefault(hour, 0L) + 1); + }); + + if (!hourFrequency.isEmpty()) { + int favoriteHour = hourFrequency.entrySet().stream() + .max(Map.Entry.comparingByValue()) + .map(Map.Entry::getKey) + .orElse(12); + stats.put("favorite_play_hour", favoriteHour); + } + } else { + // Значения по умолчанию если нет истории сессий + stats.put("session_count", 1); + stats.put("total_logins", 1); + stats.put("average_session_duration", 0); + stats.put("longest_session_duration", 0); + stats.put("active_days_last_month", 1); + stats.put("time_played_last_month", 0); // Нет истории сессий = 0 времени за 30 дней + stats.put("favorite_play_hour", LocalDateTime.now().getHour()); + } + + // Убираем достижения полностью - слишком сложно реализовать корректно + // Достижения в Minecraft очень сложны для правильного подсчета через API + + // Упрощенная статистика - только необходимое + stats.put("deaths_count", player.getStatistic(Statistic.DEATHS)); + stats.put("mobs_killed", player.getStatistic(Statistic.MOB_KILLS)); + + // Отправляем статистику + return apiClient.updatePlayerStats(player.getName(), stats).join(); + + } catch (Exception e) { + logger.severe("Ошибка обновления статистики игрока " + player.getName() + ": " + e.getMessage()); + return false; + } + }); + } + + /** + * Получение статистики игрока для команд + */ + public String getPlayerStatsString(Player player) { + try { + UUID playerId = player.getUniqueId(); + List sessions = playerSessionHistory.getOrDefault(playerId, new ArrayList<>()); + + int totalPlaytime = player.getStatistic(Statistic.PLAY_ONE_MINUTE) / 20 / 60; // минуты + int achievements = Math.max(0, totalPlaytime / 60); // примерно + + long averageSession = 0; + long longestSession = 0; + int activeDays = 0; + + if (!sessions.isEmpty()) { + long totalSessionTime = sessions.stream().mapToLong(s -> s.duration).sum(); + averageSession = (totalSessionTime / sessions.size()) / 1000 / 60; + longestSession = sessions.stream().mapToLong(s -> s.duration).max().orElse(0L) / 1000 / 60; + + LocalDateTime thirtyDaysAgo = LocalDateTime.now().minusDays(30); + activeDays = (int) sessions.stream() + .filter(s -> s.date.isAfter(thirtyDaysAgo)) + .map(s -> s.date.toLocalDate()) + .distinct() + .count(); + } + + return String.format( + "§e§l════════ СТАТИСТИКА ИГРОКА ════════\n" + + "§7Игрок: §f%s\n" + + "§7Общее время игры: §b%d часов %d минут\n" + + "§7Сессий сыграно: §a%d\n" + + "§7Средняя сессия: §e%d минут\n" + + "§7Самая длинная сессия: §6%d минут\n" + + "§7Активных дней (30д): §a%d\n" + + "§7Достижений: §d%d\n" + + "§7Блоков сломано: §c%d\n" + + "§7Мобов убито: §4%d\n" + + "§7Пройдено метров: §b%.1f км\n" + + "§e§l══════════════════════════════════", + player.getName(), + totalPlaytime / 60, totalPlaytime % 60, + sessions.size(), + averageSession, longestSession, + activeDays, achievements, + player.getStatistic(Statistic.MINE_BLOCK), + player.getStatistic(Statistic.MOB_KILLS), + player.getStatistic(Statistic.WALK_ONE_CM) / 100000.0 // км + ); + } catch (Exception e) { + return "§cОшибка получения статистики: " + e.getMessage(); + } + } + + /** + * Сбор базовой статистики игрока + */ + private Map collectPlayerStats(Player player) { + Map stats = new HashMap<>(); + + try { + // Безопасный сбор статистики с обработкой ошибок + + // Убитые мобы - простая статистика + stats.put("mobs_killed", player.getStatistic(Statistic.MOB_KILLS)); + + // Пройденное расстояние - простая статистика + stats.put("distance_walked", player.getStatistic(Statistic.WALK_ONE_CM)); + + // Время игры - простая статистика + stats.put("play_time", player.getStatistic(Statistic.PLAY_ONE_MINUTE)); + + // Прыжки - простая статистика + stats.put("jumps", player.getStatistic(Statistic.JUMP)); + + // Урон нанесенный - простая статистика + stats.put("damage_dealt", player.getStatistic(Statistic.DAMAGE_DEALT)); + + // Урон получен - простая статистика + stats.put("damage_taken", player.getStatistic(Statistic.DAMAGE_TAKEN)); + + // Количество смертей - простая статистика + stats.put("deaths", player.getStatistic(Statistic.DEATHS)); + + // Количество достижений (упрощенный подсчет) + int achievements = 0; + try { + // Пытаемся получить основные достижения + if (player.hasPlayedBefore()) { + achievements = 1; // Базовое достижение за подключение + } + // Можно добавить другие простые проверки достижений + } catch (Exception e) { + logger.fine("Не удалось получить информацию о достижениях для " + player.getName()); + } + stats.put("achievements", achievements); + + } catch (Exception e) { + logger.warning("Ошибка при сборе статистики игрока " + player.getName() + ": " + e.getMessage()); + } + + return stats; + } + + /** + * Данные игровой сессии + */ + private static class PlayerSessionData { + long sessionStart; + LocalTime loginTime; + Map startStats; + } + + /** + * История сессий игрока + */ + private static class SessionHistory { + LocalDateTime date; + long duration; // в миллисекундах + LocalTime loginTime; + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlaytimeManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlaytimeManager.java new file mode 100644 index 00000000000..488e437c4f0 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/PlaytimeManager.java @@ -0,0 +1,317 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.api.dto.PlayerStats; +import org.ebluffy.chiwawa.config.ConfigManager; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +/** + * Менеджер времени игры для отслеживания лимитов и обновления статистики + */ +public class PlaytimeManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + private final UserManager userManager; + private final ConfigManager configManager; + + // Время входа игроков + private final Map loginTimes = new ConcurrentHashMap<>(); + // Накопленное время текущей сессии (в минутах) + private final Map sessionPlaytime = new ConcurrentHashMap<>(); + // Последнее сохранение времени + private final Map lastSaveTime = new ConcurrentHashMap<>(); + + // Задача для периодического обновления + private BukkitTask updateTask; + + // Интервал обновления в тиках (5 минут = 6000 тиков) + private static final int UPDATE_INTERVAL = 6000; + // Интервал сохранения в минутах + private static final int SAVE_INTERVAL = 5; + + public PlaytimeManager(JavaPlugin plugin, ApiClient apiClient, UserManager userManager, ConfigManager configManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + this.userManager = userManager; + this.configManager = configManager; + } + + /** + * Запустить менеджер времени игры + */ + public void start() { + updateTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, this::updatePlaytimes, UPDATE_INTERVAL, UPDATE_INTERVAL); + } + + /** + * Остановить менеджер времени игры + */ + public void stop() { + if (updateTask != null) { + updateTask.cancel(); + updateTask = null; + } + + // Сохраняем время всех онлайн игроков + for (Player player : Bukkit.getOnlinePlayers()) { + savePlaytime(player.getUniqueId()).join(); + } + } + + /** + * Зарегистрировать вход игрока + */ + public void onPlayerJoin(UUID playerUuid) { + long currentTime = System.currentTimeMillis(); + loginTimes.put(playerUuid, currentTime); + sessionPlaytime.put(playerUuid, 0); + lastSaveTime.put(playerUuid, currentTime); + + // Записываем активность входа + userManager.recordActivity(playerUuid, "join_server", "Игрок зашел на сервер", null); + + logger.fine("Зарегистрирован вход игрока: " + playerUuid); + } + + /** + * Зарегистрировать выход игрока + */ + public CompletableFuture onPlayerQuit(UUID playerUuid) { + return savePlaytime(playerUuid) + .thenRun(() -> { + // Записываем активность выхода + int sessionMinutes = sessionPlaytime.getOrDefault(playerUuid, 0); + String metadata = "{\"session_minutes\": " + sessionMinutes + "}"; + userManager.recordActivity(playerUuid, "leave_server", "Игрок вышел с сервера", metadata); + + // Очищаем данные + loginTimes.remove(playerUuid); + sessionPlaytime.remove(playerUuid); + lastSaveTime.remove(playerUuid); + + logger.fine("Зарегистрирован выход игрока: " + playerUuid + " (сессия: " + sessionMinutes + " мин)"); + }); + } + + /** + * Периодическое обновление времени игры + */ + private void updatePlaytimes() { + long currentTime = System.currentTimeMillis(); + + for (Player player : Bukkit.getOnlinePlayers()) { + UUID playerUuid = player.getUniqueId(); + updatePlayerPlaytime(playerUuid, currentTime); + + // Проверяем лимит времени для проходимцев + checkTimeLimit(player); + } + } + + /** + * Обновить время игры конкретного игрока + */ + private void updatePlayerPlaytime(UUID playerUuid, long currentTime) { + Long loginTime = loginTimes.get(playerUuid); + Long lastSave = lastSaveTime.get(playerUuid); + + if (loginTime == null || lastSave == null) { + return; + } + + // Вычисляем прошедшее время с последнего сохранения + long elapsedMillis = currentTime - lastSave; + int elapsedMinutes = (int) (elapsedMillis / 60000); // Конвертируем в минуты + + if (elapsedMinutes > 0) { + // Добавляем к времени сессии + sessionPlaytime.merge(playerUuid, elapsedMinutes, Integer::sum); + lastSaveTime.put(playerUuid, currentTime); + + // Сохраняем каждые SAVE_INTERVAL минут + int totalSessionMinutes = sessionPlaytime.getOrDefault(playerUuid, 0); + if (totalSessionMinutes >= SAVE_INTERVAL) { + savePlaytime(playerUuid); + } + } + } + + /** + * Проверить лимит времени для проходимцев + */ + private void checkTimeLimit(Player player) { + UUID playerUuid = player.getUniqueId(); + ChiwawaUser user = userManager.getUser(playerUuid); + PlayerStats stats = userManager.getPlayerStats(playerUuid); + + if (user == null || stats == null) { + return; + } + + // Проверяем только для проходимцев (trust level 0) без подтвержденного email + if (!user.hasTimeLimit()) { + return; + } + + // Вычисляем общее время с учетом текущей сессии + int currentSessionMinutes = sessionPlaytime.getOrDefault(playerUuid, 0); + int totalMinutes = stats.getTimePlayedMinutes() + currentSessionMinutes; + + // Лимит 10 часов = 600 минут + if (totalMinutes >= 600) { + // Кикаем игрока с сообщением о превышении лимита + Bukkit.getScheduler().runTask(plugin, () -> { + String kickMessage = configManager.getMessage("time_limit_kick") + .replace("%hours%", "10") + .replace("%remaining%", "0"); + + player.kickPlayer(kickMessage); + logger.info("Игрок " + player.getName() + " исключен за превышение лимита времени (10 часов)"); + }); + + // Записываем активность + userManager.recordActivity(playerUuid, "time_limit_exceeded", + "Игрок исключен за превышение лимита времени", + "{\"total_minutes\": " + totalMinutes + ", \"limit_minutes\": 600}"); + } + } + + /** + * Сохранить время игры на сервер + */ + public CompletableFuture savePlaytime(UUID playerUuid) { + Integer userId = userManager.getUserId(playerUuid); + PlayerStats stats = userManager.getPlayerStats(playerUuid); + Integer sessionMinutes = sessionPlaytime.get(playerUuid); + + if (userId == null || stats == null || sessionMinutes == null || sessionMinutes == 0) { + return CompletableFuture.completedFuture(false); + } + + int newTotalMinutes = stats.getTimePlayedMinutes() + sessionMinutes; + + return apiClient.updatePlaytime(userId, newTotalMinutes) + .thenApply(success -> { + if (success) { + // Обновляем кеш + stats.setTimePlayedMinutes(newTotalMinutes); + sessionPlaytime.put(playerUuid, 0); // Сбрасываем накопленное время сессии + + logger.fine("Сохранено время игры для игрока " + playerUuid + ": " + newTotalMinutes + " минут"); + + // Записываем активность обновления времени + String metadata = "{\"session_minutes\": " + sessionMinutes + ", \"total_minutes\": " + newTotalMinutes + "}"; + userManager.recordActivity(playerUuid, "playtime_update", "Обновлено время игры", metadata); + } else { + logger.warning("Не удалось сохранить время игры для игрока " + playerUuid); + } + return success; + }) + .exceptionally(throwable -> { + logger.severe("Ошибка сохранения времени игры для " + playerUuid + ": " + throwable.getMessage()); + return false; + }); + } + + /** + * Получить время текущей сессии + */ + public int getSessionPlaytime(UUID playerUuid) { + Long loginTime = loginTimes.get(playerUuid); + if (loginTime == null) { + return 0; + } + + long currentTime = System.currentTimeMillis(); + long sessionMillis = currentTime - loginTime; + int sessionMinutes = (int) (sessionMillis / 60000); + + return sessionMinutes + sessionPlaytime.getOrDefault(playerUuid, 0); + } + + /** + * Получить общее время игры (сохраненное + текущая сессия) + */ + public int getTotalPlaytime(UUID playerUuid) { + PlayerStats stats = userManager.getPlayerStats(playerUuid); + if (stats == null) { + return getSessionPlaytime(playerUuid); + } + + return stats.getTimePlayedMinutes() + getSessionPlaytime(playerUuid); + } + + /** + * Получить оставшееся время для проходимцев + */ + public int getRemainingTime(UUID playerUuid) { + ChiwawaUser user = userManager.getUser(playerUuid); + if (user == null || !user.hasTimeLimit()) { + return -1; // Нет лимита + } + + int totalMinutes = getTotalPlaytime(playerUuid); + return Math.max(0, 600 - totalMinutes); // 600 минут = 10 часов + } + + /** + * Форматировать время в читаемый вид + */ + public String formatTime(int minutes) { + if (minutes < 60) { + return minutes + " мин"; + } + + int hours = minutes / 60; + int remainingMinutes = minutes % 60; + + if (hours < 24) { + return hours + "ч " + remainingMinutes + "м"; + } + + int days = hours / 24; + int remainingHours = hours % 24; + return days + "д " + remainingHours + "ч " + remainingMinutes + "м"; + } + + /** + * Принудительно сохранить время всех онлайн игроков + */ + public CompletableFuture saveAllPlaytimes() { + CompletableFuture[] futures = Bukkit.getOnlinePlayers().stream() + .map(player -> savePlaytime(player.getUniqueId())) + .toArray(CompletableFuture[]::new); + + return CompletableFuture.allOf(futures) + .thenRun(() -> logger.info("Сохранено время игры для всех онлайн игроков")); + } + + /** + * Получить статистику по времени игры + */ + public String getPlaytimeStats() { + int onlinePlayers = Bukkit.getOnlinePlayers().size(); + int trackedPlayers = loginTimes.size(); + + return String.format("Онлайн игроков: %d, Отслеживается: %d", onlinePlayers, trackedPlayers); + } + + /** + * Проверить, находится ли игрок онлайн и отслеживается + */ + public boolean isPlayerTracked(UUID playerUuid) { + return loginTimes.containsKey(playerUuid); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ReputationManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ReputationManager.java new file mode 100644 index 00000000000..b883d37efc9 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ReputationManager.java @@ -0,0 +1,296 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.config.ConfigManager; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +/** + * Менеджер репутации для системы +rep/-rep + */ +public class ReputationManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + private final UserManager userManager; + private final ConfigManager configManager; + + // Кулдауны на выдачу репутации (игрок -> время последней выдачи) + private final Map reputationCooldowns = new ConcurrentHashMap<>(); + + // Кулдаун на выдачу репутации (1 час) + private static final long REPUTATION_COOLDOWN = 60 * 60 * 1000; // 1 час в миллисекундах + + public ReputationManager(JavaPlugin plugin, ApiClient apiClient, UserManager userManager, ConfigManager configManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + this.userManager = userManager; + this.configManager = configManager; + } + + /** + * Дать репутацию игроку + */ + public CompletableFuture giveReputation(Player giver, String targetNickname) { + UUID giverUuid = giver.getUniqueId(); + + // Проверяем кулдаун + if (isOnCooldown(giverUuid)) { + long remainingTime = getRemainingCooldown(giverUuid); + return CompletableFuture.completedFuture( + ReputationResult.failure("Вы сможете дать репутацию через " + formatTime(remainingTime)) + ); + } + + // Нельзя давать репутацию самому себе + if (giver.getName().equalsIgnoreCase(targetNickname)) { + return CompletableFuture.completedFuture( + ReputationResult.failure("Нельзя давать репутацию самому себе") + ); + } + + // Проверяем, что дающий имеет достаточный trust level + ChiwawaUser giverUser = userManager.getUser(giverUuid); + if (giverUser == null || giverUser.getTrustLevel() < 1) { + return CompletableFuture.completedFuture( + ReputationResult.failure("Для выдачи репутации нужен Trust Level 1 или выше") + ); + } + + // Сначала ищем игрока в кеше (если онлайн) + ChiwawaUser targetUser = userManager.getUserByNickname(targetNickname); + if (targetUser != null) { + // Игрок найден в кеше - выдаем репутацию + return giveReputationToUser(giver, targetUser); + } + + // Игрок не в кеше - ищем через API + return apiClient.getUserByNickname(targetNickname) + .thenCompose(foundUser -> { + if (foundUser == null) { + return CompletableFuture.completedFuture( + ReputationResult.failure("Игрок " + targetNickname + " не найден") + ); + } + + // Игрок найден через API - выдаем репутацию + return giveReputationToUser(giver, foundUser); + }) + .exceptionally(throwable -> { + logger.severe("Ошибка поиска игрока " + targetNickname + ": " + throwable.getMessage()); + return ReputationResult.failure("Ошибка при поиске игрока. Попробуйте позже"); + }); + } + + /** + * Выдать репутацию найденному пользователю + */ + private CompletableFuture giveReputationToUser(Player giver, ChiwawaUser targetUser) { + UUID giverUuid = giver.getUniqueId(); + String reason = "Репутация от игрока " + giver.getName(); + + return apiClient.updateReputation(targetUser.getId(), 1, reason) + .thenApply(success -> { + if (success) { + // Устанавливаем кулдаун + reputationCooldowns.put(giverUuid, System.currentTimeMillis()); + + // Записываем активность + // String metadata = String.format("{\"target_id\": %d, \"target_nickname\": \"%s\", \"reputation_change\": 1}", + // targetUser.getId(), targetUser.getNickname()); + // userManager.recordActivity(giverUuid, "reputation_given", + // "Дал репутацию игроку " + targetUser.getNickname(), metadata); + + logger.info(giver.getName() + " дал репутацию игроку " + targetUser.getNickname()); + + // Уведомляем получателя если он онлайн + Player targetPlayer = Bukkit.getPlayerExact(targetUser.getNickname()); + if (targetPlayer != null) { + String message = configManager.getMessage("reputation_received") + .replace("%player%", giver.getName()); + targetPlayer.sendMessage(message); + } + + return ReputationResult.success("Вы дали +1 репутацию игроку " + targetUser.getNickname()); + } else { + return ReputationResult.failure("Ошибка при выдаче репутации. Попробуйте позже"); + } + }) + .exceptionally(throwable -> { + logger.severe("Ошибка выдачи репутации от " + giver.getName() + " к " + targetUser.getNickname() + ": " + throwable.getMessage()); + return ReputationResult.failure("Ошибка при выдаче репутации. Попробуйте позже"); + }); + } + + /** + * Изменить репутацию игрока (для администраторов) + */ + public CompletableFuture modifyReputation(Player admin, String targetNickname, int amount, String reason) { + // Проверяем права администратора + ChiwawaUser adminUser = userManager.getUser(admin.getUniqueId()); + if (adminUser == null || !adminUser.isModerator()) { + return CompletableFuture.completedFuture( + ReputationResult.failure("У вас нет прав для изменения репутации") + ); + } + + // Сначала ищем игрока в кеше (если онлайн) + ChiwawaUser targetUser = userManager.getUserByNickname(targetNickname); + if (targetUser != null) { + // Игрок найден в кеше - изменяем репутацию + return modifyReputationForUser(admin, targetUser, amount, reason); + } + + // Игрок не в кеше - ищем через API + return apiClient.getUserByNickname(targetNickname) + .thenCompose(foundUser -> { + if (foundUser == null) { + return CompletableFuture.completedFuture( + ReputationResult.failure("Игрок " + targetNickname + " не найден") + ); + } + + // Игрок найден через API - изменяем репутацию + return modifyReputationForUser(admin, foundUser, amount, reason); + }) + .exceptionally(throwable -> { + logger.severe("Ошибка поиска игрока " + targetNickname + ": " + throwable.getMessage()); + return ReputationResult.failure("Ошибка при поиске игрока. Попробуйте позже"); + }); + } + + /** + * Изменить репутацию найденному пользователю + */ + private CompletableFuture modifyReputationForUser(Player admin, ChiwawaUser targetUser, int amount, String reason) { + String fullReason = reason != null ? reason : ("Изменение репутации администратором " + admin.getName()); + + return apiClient.updateReputation(targetUser.getId(), amount, fullReason) + .thenApply(success -> { + if (success) { + // Записываем активность + // String metadata = String.format("{\"target_id\": %d, \"target_nickname\": \"%s\", \"reputation_change\": %d, \"reason\": \"%s\"}", + // targetUser.getId(), targetUser.getNickname(), amount, fullReason); + // userManager.recordActivity(admin.getUniqueId(), "reputation_modified", + // "Изменил репутацию игрока " + targetUser.getNickname() + " на " + amount, metadata); + + logger.info(admin.getName() + " изменил репутацию игрока " + targetUser.getNickname() + " на " + amount + " (" + fullReason + ")"); + + String sign = amount > 0 ? "+" : ""; + return ReputationResult.success("Репутация игрока " + targetUser.getNickname() + " изменена на " + sign + amount); + } else { + return ReputationResult.failure("Ошибка при изменении репутации. Попробуйте позже"); + } + }) + .exceptionally(throwable -> { + logger.severe("Ошибка изменения репутации администратором " + admin.getName() + ": " + throwable.getMessage()); + return ReputationResult.failure("Ошибка при изменении репутации. Попробуйте позже"); + }); + } + + /** + * Проверить, может ли игрок дать репутацию (кулдаун) + */ + public boolean canGiveReputation(UUID playerUuid) { + return !isOnCooldown(playerUuid); + } + + /** + * Проверить, находится ли игрок на кулдауне + */ + private boolean isOnCooldown(UUID playerUuid) { + Long lastTime = reputationCooldowns.get(playerUuid); + if (lastTime == null) { + return false; + } + + return (System.currentTimeMillis() - lastTime) < REPUTATION_COOLDOWN; + } + + /** + * Получить оставшееся время кулдауна в миллисекундах + */ + public long getRemainingCooldown(UUID playerUuid) { + Long lastTime = reputationCooldowns.get(playerUuid); + if (lastTime == null) { + return 0; + } + + long elapsed = System.currentTimeMillis() - lastTime; + return Math.max(0, REPUTATION_COOLDOWN - elapsed); + } + + /** + * Форматировать время в читаемый вид + */ + private String formatTime(long milliseconds) { + long seconds = milliseconds / 1000; + long minutes = seconds / 60; + long hours = minutes / 60; + + if (hours > 0) { + return hours + "ч " + (minutes % 60) + "м"; + } else if (minutes > 0) { + return minutes + "м " + (seconds % 60) + "с"; + } else { + return seconds + "с"; + } + } + + /** + * Очистить кулдауны при выходе игрока (опционально) + */ + public void onPlayerQuit(UUID playerUuid) { + // Оставляем кулдауны даже после выхода игрока + // reputationCooldowns.remove(playerUuid); + } + + /** + * Получить статистику репутации + */ + public String getReputationStats() { + long activePlayerCount = reputationCooldowns.entrySet().stream() + .filter(entry -> (System.currentTimeMillis() - entry.getValue()) < REPUTATION_COOLDOWN) + .count(); + + return String.format("Игроков на кулдауне репутации: %d", activePlayerCount); + } + + /** + * Результат операции с репутацией + */ + public static class ReputationResult { + private final boolean success; + private final String message; + + private ReputationResult(boolean success, String message) { + this.success = success; + this.message = message; + } + + public static ReputationResult success(String message) { + return new ReputationResult(true, message); + } + + public static ReputationResult failure(String message) { + return new ReputationResult(false, message); + } + + public boolean isSuccess() { + return success; + } + + public String getMessage() { + return message; + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ServerStatsManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ServerStatsManager.java new file mode 100644 index 00000000000..093a4939020 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/ServerStatsManager.java @@ -0,0 +1,174 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitRunnable; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.config.ConfigManager; + +import java.lang.management.ManagementFactory; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +/** + * Менеджер для сбора и отправки статистики сервера + */ +public class ServerStatsManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + private final ConfigManager configManager; + private BukkitRunnable statsTask; + + public ServerStatsManager(JavaPlugin plugin, ApiClient apiClient, ConfigManager configManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + this.configManager = configManager; + } + + /** + * Запуск автоматической отправки статистики сервера + */ + public void startStatsCollection() { + if (statsTask != null) { + statsTask.cancel(); + } + + // Отправляем статистику каждые 30 секунд + statsTask = new BukkitRunnable() { + @Override + public void run() { + collectAndSendServerStats(); + } + }; + + // Первая отправка через 10 секунд, затем каждые 30 секунд + statsTask.runTaskTimerAsynchronously(plugin, 200L, 600L); // 10s, 30s + } + + /** + * Остановка отправки статистики + */ + public void stopStatsCollection() { + if (statsTask != null) { + statsTask.cancel(); + statsTask = null; + } + } + + /** + * Сбор и отправка статистики сервера + */ + public CompletableFuture collectAndSendServerStats() { + return CompletableFuture.supplyAsync(() -> { + try { + // Получаем IP и порт сервера из конфигурации + String serverIp = configManager.getServerIp(); + int serverPort = configManager.getServerPort(); + + if (serverIp == null || serverIp.isEmpty() || serverPort <= 0) { + logger.warning("Не удалось получить IP или порт сервера из конфигурации!"); + return false; + } + + // logger.info("Отправка статистики сервера для " + serverIp + ":" + serverPort); + // TPS (берём среднее за последнюю минуту) + double tps = 0.0; + try { + double[] tpsArray = Bukkit.getServer().getTPS(); + if (tpsArray != null && tpsArray.length > 0) { + tps = Math.min(tpsArray[0], 20.0); // Ограничиваем 20.0 + } + } catch (Exception e) { + logger.warning("Не удалось получить TPS: " + e.getMessage()); + } + + // Время работы сервера в секундах + long uptimeSeconds = ManagementFactory.getRuntimeMXBean().getUptime() / 1000; + + // Информация о памяти (в мегабайтах) + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory() / 1024 / 1024; // MB + long totalMemory = runtime.totalMemory() / 1024 / 1024; // MB + long freeMemory = runtime.freeMemory() / 1024 / 1024; // MB + long usedMemory = totalMemory - freeMemory; // MB + + // Игроки + int onlinePlayers = Bukkit.getOnlinePlayers().size(); + int maxPlayers = Bukkit.getMaxPlayers(); + + // Версия сервера + String serverVersion = Bukkit.getVersion(); + + // Количество плагинов + int pluginsCount = Bukkit.getPluginManager().getPlugins().length; + + // Количество загруженных миров + int loadedWorlds = Bukkit.getWorlds().size(); + + // Отправляем данные + return apiClient.updateServerData( + serverIp, serverPort, tps, uptimeSeconds, + maxMemory, usedMemory, freeMemory, + onlinePlayers, maxPlayers, serverVersion, + pluginsCount, loadedWorlds + ).join(); + + } catch (Exception e) { + logger.severe("Ошибка сбора статистики сервера: " + e.getMessage()); + return false; + } + }); + } + + /** + * Получение текущей статистики сервера (для команд) + */ + public String getServerStatsString() { + try { + double[] tpsArray = Bukkit.getServer().getTPS(); + double tps = (tpsArray != null && tpsArray.length > 0) ? tpsArray[0] : 0.0; + + long uptimeSeconds = ManagementFactory.getRuntimeMXBean().getUptime() / 1000; + long uptimeMinutes = uptimeSeconds / 60; + long uptimeHours = uptimeMinutes / 60; + long uptimeDays = uptimeHours / 24; + + Runtime runtime = Runtime.getRuntime(); + long maxMemory = runtime.maxMemory() / 1024 / 1024; + long totalMemory = runtime.totalMemory() / 1024 / 1024; + long freeMemory = runtime.freeMemory() / 1024 / 1024; + long usedMemory = totalMemory - freeMemory; + + String uptimeFormatted; + if (uptimeDays > 0) { + uptimeFormatted = String.format("%dд %dч %dм", uptimeDays, uptimeHours % 24, uptimeMinutes % 60); + } else if (uptimeHours > 0) { + uptimeFormatted = String.format("%dч %dм", uptimeHours, uptimeMinutes % 60); + } else { + uptimeFormatted = String.format("%dм", uptimeMinutes); + } + + return String.format( + "§e§l════════ СТАТИСТИКА СЕРВЕРА ════════\n" + + "§7TPS: §a%.1f §7/ §a20.0\n" + + "§7Время работы: §b%s\n" + + "§7Игроков онлайн: §a%d §7/ §a%d\n" + + "§7Память: §c%d§7/§a%d §7MB (свободно: §b%d §7MB)\n" + + "§7Плагинов: §a%d\n" + + "§7Миров: §a%d\n" + + "§7Версия: §f%s\n" + + "§e§l══════════════════════════════════", + Math.min(tps, 20.0), uptimeFormatted, + Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers(), + usedMemory, maxMemory, freeMemory, + Bukkit.getPluginManager().getPlugins().length, + Bukkit.getWorlds().size(), + Bukkit.getVersion() + ); + } catch (Exception e) { + return "§cОшибка получения статистики сервера: " + e.getMessage(); + } + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/StatsManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/StatsManager.java new file mode 100644 index 00000000000..4c26fecbcaa --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/StatsManager.java @@ -0,0 +1,301 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.Bukkit; +import org.bukkit.Statistic; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.config.ConfigManager; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +/** + * Менеджер для сбора и отправки детальной статистики игроков на сайт + */ +public class StatsManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + private final UserManager userManager; + private final ConfigManager configManager; + + // Кеш последней отправленной статистики для каждого игрока + private final Map> lastSentStats = new ConcurrentHashMap<>(); + + // Время последней отправки статистики + private final Map lastStatsUpdate = new ConcurrentHashMap<>(); + + // Задача для периодической отправки статистики + private BukkitTask statsTask; + + // Интервал отправки статистики (1 минута = 1200 тиков) + private static final int STATS_UPDATE_INTERVAL = 1200; + + // Минимальный интервал между отправками для одного игрока (30 секунд) + private static final long MIN_UPDATE_INTERVAL = 30 * 1000; + + public StatsManager(JavaPlugin plugin, ApiClient apiClient, UserManager userManager, ConfigManager configManager) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + this.userManager = userManager; + this.configManager = configManager; + } + + /** + * Запуск менеджера статистики + */ + public void start() { + // Запускаем периодическую отправку статистики + statsTask = Bukkit.getScheduler().runTaskTimerAsynchronously(plugin, + this::updateAllPlayersStats, + STATS_UPDATE_INTERVAL, + STATS_UPDATE_INTERVAL + ); + } + + /** + * Остановка менеджера статистики + */ + public void stop() { + if (statsTask != null) { + statsTask.cancel(); + statsTask = null; + } + + // Отправляем финальную статистику для всех онлайн игроков + for (Player player : Bukkit.getOnlinePlayers()) { + updatePlayerStats(player, true); + } + } + + /** + * Регистрация входа игрока + */ + public void onPlayerJoin(UUID playerUuid) { + lastStatsUpdate.put(playerUuid, System.currentTimeMillis()); + logger.fine("Зарегистрирован вход игрока для статистики: " + playerUuid); + } + + /** + * Регистрация выхода игрока + */ + public void onPlayerQuit(UUID playerUuid) { + Player player = Bukkit.getPlayer(playerUuid); + if (player != null) { + // Отправляем финальную статистику + updatePlayerStats(player, true); + } + + // Очищаем кеш + lastSentStats.remove(playerUuid); + lastStatsUpdate.remove(playerUuid); + + logger.fine("Зарегистрирован выход игрока из статистики: " + playerUuid); + } + + /** + * Обновление статистики всех онлайн игроков + */ + private void updateAllPlayersStats() { + for (Player player : Bukkit.getOnlinePlayers()) { + updatePlayerStats(player, false); + } + } + + /** + * Обновление статистики конкретного игрока + */ + public void updatePlayerStats(Player player, boolean forceUpdate) { + UUID playerUuid = player.getUniqueId(); + + // Проверяем минимальный интервал + Long lastUpdate = lastStatsUpdate.get(playerUuid); + long currentTime = System.currentTimeMillis(); + + if (!forceUpdate && lastUpdate != null && + (currentTime - lastUpdate) < MIN_UPDATE_INTERVAL) { + return; // Слишком рано для обновления + } + + // Проверяем что игрок авторизован + ChiwawaUser user = userManager.getCachedUser(playerUuid); + if (user == null) { + return; // Игрок не авторизован + } + + try { + // Собираем статистику + Map stats = collectPlayerStats(player); + + // Проверяем нужно ли отправлять (изменились ли данные значительно) + if (!forceUpdate && !shouldUpdateStats(playerUuid, stats)) { + return; + } + + // Отправляем статистику на сервер + sendStatsToServer(player.getName(), stats); + + // Обновляем кеш + updateStatsCache(playerUuid, stats); + lastStatsUpdate.put(playerUuid, currentTime); + + logger.fine("Статистика игрока " + player.getName() + " отправлена на сервер"); + + } catch (Exception e) { + logger.warning("Ошибка обновления статистики игрока " + player.getName() + ": " + e.getMessage()); + } + } + + /** + * Сбор статистики игрока + */ + private Map collectPlayerStats(Player player) { + Map stats = new HashMap<>(); + + try { + // Основная статистика времени + stats.put("total_logins", getPlayerStatistic(player, Statistic.LEAVE_GAME) + 1); // +1 для текущей сессии + + // Блоки + stats.put("blocks_broken", getPlayerStatistic(player, Statistic.MINE_BLOCK)); + stats.put("blocks_placed", getPlayerStatistic(player, Statistic.USE_ITEM)); + + // Движение + stats.put("distance_walked", + getPlayerStatistic(player, Statistic.WALK_ONE_CM) + + getPlayerStatistic(player, Statistic.SPRINT_ONE_CM) + + getPlayerStatistic(player, Statistic.CROUCH_ONE_CM) + ); + + // Бой и смерти + stats.put("deaths_count", getPlayerStatistic(player, Statistic.DEATHS)); + stats.put("mobs_killed", getPlayerStatistic(player, Statistic.MOB_KILLS)); + stats.put("damage_dealt", getPlayerStatistic(player, Statistic.DAMAGE_DEALT)); + stats.put("damage_taken", getPlayerStatistic(player, Statistic.DAMAGE_TAKEN)); + + // Крафт и еда + stats.put("items_crafted", getPlayerStatistic(player, Statistic.CRAFT_ITEM)); + stats.put("food_eaten", getPlayerStatistic(player, Statistic.ANIMALS_BRED)); // Приблизительно + + // Прыжки + stats.put("jumps_count", getPlayerStatistic(player, Statistic.JUMP)); + + // Время последнего входа (в правильном формате для PostgreSQL) + stats.put("last_seen", java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ISO_LOCAL_DATE_TIME)); + + // IP адрес + if (player.getAddress() != null) { + stats.put("last_ip_address", player.getAddress().getAddress().getHostAddress()); + } + + // Детальная статистика в JSON формате + Map minecraftStats = new HashMap<>(); + minecraftStats.put("play_time_ticks", getPlayerStatistic(player, Statistic.PLAY_ONE_MINUTE)); + minecraftStats.put("sneak_time", getPlayerStatistic(player, Statistic.SNEAK_TIME)); + minecraftStats.put("time_since_death", getPlayerStatistic(player, Statistic.TIME_SINCE_DEATH)); + minecraftStats.put("player_kills", getPlayerStatistic(player, Statistic.PLAYER_KILLS)); + + stats.put("minecraft_stats", minecraftStats); + + // Ежедневная статистика (для сегодняшнего дня) + Map dailyStats = new HashMap<>(); + dailyStats.put("playtime_minutes", 5); // Будет обновлено PlaytimeManager + dailyStats.put("logins_count", 1); + dailyStats.put("blocks_broken", 0); // Разница от последней отправки + dailyStats.put("blocks_placed", 0); + dailyStats.put("distance_walked", 0); + dailyStats.put("deaths_count", 0); + dailyStats.put("mobs_killed", 0); + + stats.put("daily_stats", dailyStats); + + } catch (Exception e) { + logger.warning("Ошибка сбора статистики для " + player.getName() + ": " + e.getMessage()); + } + + return stats; + } + + /** + * Получить статистику игрока безопасно + */ + private int getPlayerStatistic(Player player, Statistic statistic) { + try { + return player.getStatistic(statistic); + } catch (Exception e) { + return 0; + } + } + + /** + * Проверка нужно ли отправлять статистику (изменилась ли она значительно) + */ + private boolean shouldUpdateStats(UUID playerUuid, Map currentStats) { + Map lastStats = lastSentStats.get(playerUuid); + if (lastStats == null) { + return true; // Первая отправка + } + + // Проверяем значительные изменения + String[] significantStats = { + "blocks_broken", "blocks_placed", "distance_walked", + "deaths_count", "mobs_killed", "total_logins" + }; + + for (String statName : significantStats) { + Integer current = (Integer) currentStats.get(statName); + Integer last = lastStats.get(statName); + + if (current == null) current = 0; + if (last == null) last = 0; + + // Если изменение больше 10 или прошло много времени + if (Math.abs(current - last) > 10) { + return true; + } + } + + return false; + } + + /** + * Обновление кеша статистики + */ + private void updateStatsCache(UUID playerUuid, Map stats) { + Map intStats = new HashMap<>(); + + for (Map.Entry entry : stats.entrySet()) { + if (entry.getValue() instanceof Integer) { + intStats.put(entry.getKey(), (Integer) entry.getValue()); + } + } + + lastSentStats.put(playerUuid, intStats); + } + + /** + * Отправка статистики на сервер + */ + private void sendStatsToServer(String playerName, Map stats) { + // Используем ApiClient для отправки статистики + apiClient.updatePlayerStats(playerName, stats) + .thenAccept(success -> { + if (success) { + logger.fine("Статистика игрока " + playerName + " успешно отправлена"); + } else { + logger.warning("Не удалось отправить статистику игрока " + playerName); + } + }) + .exceptionally(throwable -> { + logger.severe("Ошибка отправки статистики для " + playerName + ": " + throwable.getMessage()); + return null; + }); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/UserManager.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/UserManager.java new file mode 100644 index 00000000000..b4fb9a03aea --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/managers/UserManager.java @@ -0,0 +1,337 @@ +package org.ebluffy.chiwawa.managers; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.ebluffy.chiwawa.api.ApiClient; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.ebluffy.chiwawa.api.dto.PlayerStats; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Logger; + +/** + * Менеджер пользователей для кеширования и управления данными игроков + */ +public class UserManager { + private final JavaPlugin plugin; + private final Logger logger; + private final ApiClient apiClient; + + // Кеш пользователей по UUID + private final Map userCache = new ConcurrentHashMap<>(); + // Кеш статистики по UUID + private final Map statsCache = new ConcurrentHashMap<>(); + // Кеш соответствия UUID -> User ID + private final Map userIdCache = new ConcurrentHashMap<>(); + // Кеш соответствия никнейм -> UUID + private final Map nicknameCache = new ConcurrentHashMap<>(); + + public UserManager(JavaPlugin plugin, ApiClient apiClient) { + this.plugin = plugin; + this.logger = plugin.getLogger(); + this.apiClient = apiClient; + } + + /** + * Загрузить данные пользователя при входе на сервер + */ + public CompletableFuture loadUser(Player player) { + UUID playerUuid = player.getUniqueId(); + String nickname = player.getName(); + + // Проверяем кеш + if (userCache.containsKey(playerUuid)) { + return CompletableFuture.completedFuture(userCache.get(playerUuid)); + } + + return apiClient.getUserByNickname(nickname) + .thenApply(user -> { + if (user != null) { + // Кешируем данные + userCache.put(playerUuid, user); + userIdCache.put(playerUuid, user.getId()); + nicknameCache.put(nickname.toLowerCase(), playerUuid); + + logger.info("Загружен пользователь: " + user.getNickname() + " (ID: " + user.getId() + ", Trust Level: " + user.getTrustLevel() + ")"); + + // Загружаем статистику асинхронно + loadPlayerStats(playerUuid, user.getId()); + } else { + logger.warning("Пользователь не найден в базе данных: " + nickname); + } + return user; + }) + .exceptionally(throwable -> { + logger.severe("Ошибка загрузки пользователя " + nickname + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Загрузить статистику игрока + */ + public CompletableFuture loadPlayerStats(UUID playerUuid, int userId) { + // Проверяем кеш + if (statsCache.containsKey(playerUuid)) { + return CompletableFuture.completedFuture(statsCache.get(playerUuid)); + } + + return apiClient.getPlayerStats(userId) + .thenApply(stats -> { + if (stats != null) { + statsCache.put(playerUuid, stats); + logger.fine("Загружена статистика для игрока " + playerUuid + ": " + stats.getFormattedPlaytime()); + } + return stats; + }) + .exceptionally(throwable -> { + logger.severe("Ошибка загрузки статистики игрока " + playerUuid + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Получить пользователя из кеша + */ + public ChiwawaUser getUser(UUID playerUuid) { + return userCache.get(playerUuid); + } + + /** + * Получить пользователя по никнейму + */ + public ChiwawaUser getUserByNickname(String nickname) { + UUID uuid = nicknameCache.get(nickname.toLowerCase()); + return uuid != null ? userCache.get(uuid) : null; + } + + /** + * Получить статистику из кеша + */ + public PlayerStats getPlayerStats(UUID playerUuid) { + return statsCache.get(playerUuid); + } + + /** + * Получить User ID по UUID + */ + public Integer getUserId(UUID playerUuid) { + return userIdCache.get(playerUuid); + } + + /** + * Проверить доступ к серверу + */ + public CompletableFuture checkServerAccess(Player player) { + return loadUser(player) + .thenCompose(user -> { + if (user == null) { + return CompletableFuture.completedFuture(false); + } + + // Проверяем базовый доступ + if (!user.hasServerAccess()) { + return CompletableFuture.completedFuture(false); + } + + // Дополнительная проверка через API + return apiClient.checkServerAccess(player.getName()); + }); + } + + /** + * Обновить trust level пользователя + */ + public CompletableFuture updateTrustLevel(UUID playerUuid, int newTrustLevel) { + ChiwawaUser user = userCache.get(playerUuid); + if (user == null) { + return CompletableFuture.completedFuture(false); + } + + // Используем метод по никнейму для поддержки оффлайн игроков + return apiClient.updateTrustLevelByNickname(user.getNickname(), newTrustLevel) + .thenApply(success -> { + if (success) { + user.setTrustLevel(newTrustLevel); + logger.info("Обновлен trust level для " + user.getNickname() + " до " + newTrustLevel); + } + return success; + }); + } + + /** + * Забанить игрока + */ + public CompletableFuture banPlayer(UUID playerUuid, String reason) { + ChiwawaUser user = userCache.get(playerUuid); + if (user == null) { + return CompletableFuture.completedFuture(false); + } + + // Используем метод по никнейму для поддержки оффлайн игроков + return apiClient.banPlayerByNickname(user.getNickname(), reason) + .thenApply(success -> { + if (success) { + user.setBanned(true); + user.setBanReason(reason); + logger.info("Забанен игрок " + user.getNickname() + " по причине: " + reason); + } + return success; + }); + } + + /** + * Разбанить игрока + */ + public CompletableFuture unbanPlayer(UUID playerUuid) { + ChiwawaUser user = userCache.get(playerUuid); + if (user == null) { + return CompletableFuture.completedFuture(false); + } + + // Используем метод по никнейму для поддержки оффлайн игроков + return apiClient.unbanPlayerByNickname(user.getNickname()) + .thenApply(success -> { + if (success) { + user.setBanned(false); + user.setBanReason(null); + logger.info("Разбанен игрок " + user.getNickname()); + } + return success; + }); + } + + /** + * Синхронизировать данные игрока с сервером + */ + public CompletableFuture syncPlayer(UUID playerUuid) { + ChiwawaUser user = userCache.get(playerUuid); + if (user == null) { + return CompletableFuture.completedFuture(false); + } + + // Перезагружаем данные с сервера + return apiClient.getUserByNickname(user.getNickname()) + .thenCompose(freshUser -> { + if (freshUser != null) { + userCache.put(playerUuid, freshUser); + logger.info("Синхронизированы данные игрока " + freshUser.getNickname()); + + // Также синхронизируем статистику + return loadPlayerStats(playerUuid, freshUser.getId()) + .thenApply(stats -> true); + } + return CompletableFuture.completedFuture(false); + }) + .exceptionally(throwable -> { + logger.severe("Ошибка синхронизации игрока " + playerUuid + ": " + throwable.getMessage()); + return false; + }); + } + + /** + * Очистить кеш игрока при выходе + */ + public void unloadUser(UUID playerUuid) { + ChiwawaUser user = userCache.remove(playerUuid); + statsCache.remove(playerUuid); + userIdCache.remove(playerUuid); + + if (user != null) { + nicknameCache.remove(user.getNickname().toLowerCase()); + logger.fine("Выгружен из кеша игрок: " + user.getNickname()); + } + } + + /** + * Получить всех закешированных пользователей + */ + public Map getAllCachedUsers() { + return new HashMap<>(userCache); + } + + /** + * Очистить весь кеш + */ + public void clearCache() { + userCache.clear(); + statsCache.clear(); + userIdCache.clear(); + nicknameCache.clear(); + logger.info("Кеш пользователей очищен"); + } + + /** + * Получить размер кеша + */ + public int getCacheSize() { + return userCache.size(); + } + + /** + * Проверить, загружен ли пользователь + */ + public boolean isUserLoaded(UUID playerUuid) { + return userCache.containsKey(playerUuid); + } + + /** + * Записать активность игрока + */ + public CompletableFuture recordActivity(UUID playerUuid, String activityType, String description, String metadata) { + Integer userId = userIdCache.get(playerUuid); + if (userId == null) { + return CompletableFuture.completedFuture(false); + } + + return apiClient.recordActivity(userId, activityType, description, metadata); + } + + /** + * Авторизовать игрока с помощью токена + */ + public void authorizePlayer(Player player, int userId) { + UUID playerUuid = player.getUniqueId(); + String nickname = player.getName(); + + // Загружаем данные пользователя по ID + apiClient.getUserByNickname(nickname) + .thenAccept(user -> { + if (user != null && user.getId() == userId) { + // Кешируем данные авторизованного пользователя + userCache.put(playerUuid, user); + userIdCache.put(playerUuid, user.getId()); + nicknameCache.put(nickname.toLowerCase(), playerUuid); + + // Загружаем статистику + loadPlayerStats(playerUuid, user.getId()); + + logger.info("Игрок " + nickname + " авторизован с токеном (ID: " + userId + ", Trust Level: " + user.getTrustLevel() + ")"); + } else { + logger.warning("Несоответствие данных при авторизации игрока " + nickname + " с токеном"); + } + }) + .exceptionally(throwable -> { + logger.severe("Ошибка авторизации игрока " + nickname + ": " + throwable.getMessage()); + return null; + }); + } + + /** + * Проверить, находится ли игрок в кеше (авторизован) + */ + public boolean isPlayerCached(UUID playerUuid) { + return userCache.containsKey(playerUuid); + } + + /** + * Получить данные игрока из кеша + */ + public ChiwawaUser getCachedUser(UUID playerUuid) { + return userCache.get(playerUuid); + } +} diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/ApiRequestExamples.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/ApiRequestExamples.java new file mode 100644 index 00000000000..3abdd442c20 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/ApiRequestExamples.java @@ -0,0 +1,227 @@ +package org.ebluffy.chiwawa.utils; + +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.URI; +import java.time.Duration; +import com.google.gson.Gson; + +/** + * Примеры типовых HTTP запросов к API сайта + * Этот класс показывает различные способы взаимодействия с API + */ +public class ApiRequestExamples { + + private static final String API_BASE_URL = "https://your-website.com/api"; + private static final String API_KEY = "your-secret-api-key"; + private static final Gson gson = new Gson(); + + /** + * Пример 1: GET запрос для получения данных игрока (с использованием стандартного HttpClient) + */ + public static void getPlayerDataExample(String playerUuid) { + try { + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/players/" + playerUuid)) + .header("Authorization", "Bearer " + API_KEY) + .header("Content-Type", "application/json") + .header("User-Agent", "ChiwawaPlugin/1.0") + .timeout(Duration.ofSeconds(30)) + .GET() + .build(); + + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + System.out.println("Успешный ответ: " + response.body()); + // PlayerData playerData = gson.fromJson(response.body(), PlayerData.class); + } else { + System.err.println("Ошибка HTTP: " + response.statusCode()); + } + + } catch (Exception e) { + System.err.println("Ошибка запроса: " + e.getMessage()); + } + } + + /** + * Пример 2: POST запрос для обновления данных игрока + */ + public static void updatePlayerDataExample(String playerUuid, Object playerData) { + try { + String jsonBody = gson.toJson(playerData); + + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/players/" + playerUuid)) + .header("Authorization", "Bearer " + API_KEY) + .header("Content-Type", "application/json") + .timeout(Duration.ofSeconds(30)) + .PUT(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + + System.out.println("Статус: " + response.statusCode()); + System.out.println("Ответ: " + response.body()); + + } catch (Exception e) { + System.err.println("Ошибка при обновлении данных: " + e.getMessage()); + } + } + + /** + * Пример 3: GET запрос whitelist с обработкой ошибок + */ + public static void getWhitelistExample() { + try { + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/whitelist")) + .header("Authorization", "Bearer " + API_KEY) + .header("Accept", "application/json") + .timeout(Duration.ofSeconds(30)) + .GET() + .build(); + + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + + switch (response.statusCode()) { + case 200: + System.out.println("Whitelist получен: " + response.body()); + break; + case 401: + System.err.println("Ошибка авторизации: неверный API ключ"); + break; + case 404: + System.err.println("Эндпоинт не найден"); + break; + case 429: + System.err.println("Превышен лимит запросов"); + break; + case 500: + System.err.println("Внутренняя ошибка сервера"); + break; + default: + System.err.println("Неожиданный статус: " + response.statusCode()); + } + + } catch (Exception e) { + System.err.println("Ошибка сети: " + e.getMessage()); + } + } + + /** + * Пример 4: Асинхронный запрос + */ + public static void asyncRequestExample() { + HttpClient client = HttpClient.newBuilder() + .connectTimeout(Duration.ofSeconds(10)) + .build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/health")) + .header("Authorization", "Bearer " + API_KEY) + .timeout(Duration.ofSeconds(30)) + .GET() + .build(); + + client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) + .thenApply(HttpResponse::body) + .thenAccept(body -> System.out.println("Асинхронный ответ: " + body)) + .exceptionally(throwable -> { + System.err.println("Асинхронная ошибка: " + throwable.getMessage()); + return null; + }); + } + + /** + * Пример 5: Batch запрос для множественного обновления + */ + public static void batchUpdateExample() { + try { + // Создаем массив данных для batch обновления + Object[] batchData = { + // Массив PlayerData объектов + }; + + String jsonBody = gson.toJson(batchData); + + HttpClient client = HttpClient.newBuilder().build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/players/batch")) + .header("Authorization", "Bearer " + API_KEY) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + + System.out.println("Batch обновление: " + response.statusCode()); + + } catch (Exception e) { + System.err.println("Ошибка batch запроса: " + e.getMessage()); + } + } + + /** + * Пример авторизации через JWT токен + */ + public static String authenticateAndGetToken(String username, String password) { + try { + // Создаем Map вместо анонимного объекта, чтобы избежать self-reference + java.util.Map loginData = new java.util.HashMap<>(); + loginData.put("username", username); + loginData.put("password", password); + loginData.put("grant_type", "password"); + + String jsonBody = gson.toJson(loginData); + + HttpClient client = HttpClient.newBuilder().build(); + + HttpRequest request = HttpRequest.newBuilder() + .uri(URI.create(API_BASE_URL + "/auth/login")) + .header("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(jsonBody)) + .build(); + + HttpResponse response = client.send(request, + HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + // Парсим JWT токен из ответа + return extractTokenFromResponse(response.body()); + } else { + System.err.println("Ошибка авторизации: " + response.statusCode()); + return null; + } + + } catch (Exception e) { + System.err.println("Ошибка авторизации: " + e.getMessage()); + return null; + } + } + + private static String extractTokenFromResponse(String responseBody) { + // Реализация извлечения токена из ответа + return "extracted_jwt_token"; + } +} + diff --git a/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/SecurityUtils.java b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/SecurityUtils.java new file mode 100644 index 00000000000..ac41d683d18 --- /dev/null +++ b/legacy/owyxplugin/src/main/java/org/ebluffy/chiwawa/utils/SecurityUtils.java @@ -0,0 +1,314 @@ +package org.ebluffy.chiwawa.utils; + +import org.bukkit.entity.Player; +import org.ebluffy.chiwawa.api.dto.ChiwawaUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Base64; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.regex.Pattern; + +/** + * Утилиты безопасности для валидации данных + */ +public class SecurityUtils { + private static final Logger logger = LoggerFactory.getLogger(SecurityUtils.class); + + // Rate limiting + private static final ConcurrentHashMap requestCounts = new ConcurrentHashMap<>(); + private static final ConcurrentHashMap lastRequestTime = new ConcurrentHashMap<>(); + + // Константы для rate limiting + private static final long RATE_LIMIT_WINDOW_MS = 60000; // 1 минута + private static final int MAX_REQUESTS_PER_MINUTE = 60; + + // Паттерны для валидации + private static final Pattern EMAIL_PATTERN = Pattern.compile( + "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$" + ); + + private static final Pattern MINECRAFT_USERNAME_PATTERN = Pattern.compile( + "^[a-zA-Z0-9_]{3,16}$" + ); + + private static final Pattern UUID_PATTERN = Pattern.compile( + "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" + ); + + /** + * Проверка rate limit для IP адреса + */ + public static boolean checkRateLimit(String ipAddress) { + long currentTime = System.currentTimeMillis(); + + // Получаем или создаем счетчик для IP + AtomicLong counter = requestCounts.computeIfAbsent(ipAddress, k -> new AtomicLong(0)); + Long lastTime = lastRequestTime.get(ipAddress); + + // Если прошла минута, сбрасываем счетчик + if (lastTime == null || (currentTime - lastTime) > RATE_LIMIT_WINDOW_MS) { + counter.set(1); + lastRequestTime.put(ipAddress, currentTime); + return true; + } + + // Проверяем лимит + long currentCount = counter.incrementAndGet(); + if (currentCount > MAX_REQUESTS_PER_MINUTE) { + logger.warn("Rate limit exceeded for IP: {}", ipAddress); + return false; + } + + return true; + } + + /** + * Валидация email адреса + */ + public static boolean isValidEmail(String email) { + if (email == null || email.trim().isEmpty()) { + return false; + } + return EMAIL_PATTERN.matcher(email.trim()).matches(); + } + + /** + * Валидация UUID + */ + public static boolean isValidUUID(String uuid) { + if (uuid == null || uuid.trim().isEmpty()) { + return false; + } + return UUID_PATTERN.matcher(uuid.trim()).matches(); + } + + /** + * Валидация имени игрока Minecraft + */ + public static boolean isValidMinecraftUsername(String username) { + if (username == null || username.trim().isEmpty()) { + return false; + } + return MINECRAFT_USERNAME_PATTERN.matcher(username.trim()).matches(); + } + + /** + * Очистка чувствительных данных из строки для логирования + */ + public static String sanitizeForLogging(String input) { + if (input == null) { + return "null"; + } + + // Удаляем потенциально опасные символы + return input.replaceAll("[\\r\\n\\t]", "_") + .replaceAll("password", "***") + .replaceAll("token", "***") + .replaceAll("key", "***"); + } + + /** + * Простое шифрование для конфигурационных данных + */ + public static String encryptString(String plainText, String secretKey) { + try { + SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.ENCRYPT_MODE, keySpec); + + byte[] encrypted = cipher.doFinal(plainText.getBytes()); + return Base64.getEncoder().encodeToString(encrypted); + + } catch (Exception e) { + logger.error("Ошибка при шифровании: {}", e.getMessage()); + return plainText; // Возвращаем исходный текст в случае ошибки + } + } + + /** + * Расшифровка строки + */ + public static String decryptString(String encryptedText, String secretKey) { + try { + SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), "AES"); + Cipher cipher = Cipher.getInstance("AES"); + cipher.init(Cipher.DECRYPT_MODE, keySpec); + + byte[] decoded = Base64.getDecoder().decode(encryptedText); + byte[] decrypted = cipher.doFinal(decoded); + return new String(decrypted); + + } catch (Exception e) { + logger.error("Ошибка при расшифровке: {}", e.getMessage()); + return encryptedText; // Возвращаем исходный текст в случае ошибки + } + } + + /** + * Генерация безопасного API ключа + */ + public static String generateSecureApiKey() { + SecureRandom random = new SecureRandom(); + byte[] bytes = new byte[32]; + random.nextBytes(bytes); + return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); + } + + /** + * Валидация IP адреса + */ + public static boolean isValidIpAddress(String ip) { + if (ip == null) return false; + + String[] parts = ip.split("\\."); + if (parts.length != 4) return false; + + try { + for (String part : parts) { + int num = Integer.parseInt(part); + if (num < 0 || num > 255) return false; + } + return true; + } catch (NumberFormatException e) { + return false; + } + } + + /** + * Проверка на подозрительную активность + */ + public static boolean isSuspiciousActivity(String playerName, String action) { + // Простые эвристики для детекции подозрительной активности + if (playerName == null || action == null) return true; + + // Проверяем на слишком быстрые действия + String key = playerName + ":" + action; + Long lastActionTime = lastRequestTime.get(key); + long currentTime = System.currentTimeMillis(); + + if (lastActionTime != null && (currentTime - lastActionTime) < 1000) { + logger.warn("Подозрительно быстрые действия от игрока: {}", playerName); + return true; + } + + lastRequestTime.put(key, currentTime); + return false; + } + + /** + * Очистка старых записей rate limiting + */ + public static void cleanupOldEntries() { + long currentTime = System.currentTimeMillis(); + + lastRequestTime.entrySet().removeIf(entry -> + (currentTime - entry.getValue()) > RATE_LIMIT_WINDOW_MS * 2); + + // Также очищаем счетчики для удаленных IP + requestCounts.entrySet().removeIf(entry -> + !lastRequestTime.containsKey(entry.getKey())); + } + + /** + * Хеширование строки (для логирования или кеширования) + */ + public static String hashString(String input) { + if (input == null) return null; + + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + byte[] hash = md.digest(input.getBytes()); + StringBuilder hexString = new StringBuilder(); + + for (byte b : hash) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + + return hexString.toString(); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 algorithm not available", e); + } + } + + /** + * Проверка прав доступа игрока + */ + public static boolean hasPermission(Player player, ChiwawaUser user, String permission) { + if (player == null || user == null) { + return false; + } + + // Операторы имеют все права + if (player.isOp()) { + return true; + } + + // Проверка по trust level + switch (permission) { + case "admin": + return user.isAdmin(); + case "moderator": + return user.isModerator(); + case "user": + return user.getTrustLevel() >= 1; + default: + return player.hasPermission(permission); + } + } + + /** + * Санитизация текста для безопасного вывода в чат + */ + public static String sanitizeText(String text) { + if (text == null) return ""; + + return text.trim() + .replaceAll("&[0-9a-fA-Fk-oK-OrR]", "") // Удаляем цветовые коды + .replaceAll("§[0-9a-fA-Fk-oK-OrR]", "") // Удаляем цветовые коды + .replaceAll("[\\r\\n\\t]", " ") // Заменяем переносы строк на пробелы + .replaceAll("\\s+", " "); // Убираем множественные пробелы + } + + /** + * Проверка на подозрительную активность (rate limiting) + */ + public static boolean isRateLimited(UUID playerUuid, String action, long cooldownMs, + java.util.Map lastActionTimes) { + String key = playerUuid.toString() + ":" + action; + Long lastTime = lastActionTimes.get(key); + long currentTime = System.currentTimeMillis(); + + if (lastTime == null || (currentTime - lastTime) >= cooldownMs) { + lastActionTimes.put(key, currentTime); + return false; + } + + return true; + } + + /** + * Валидация Trust Level + */ + public static boolean isValidTrustLevel(int trustLevel) { + return trustLevel >= 0 && trustLevel <= 3; + } + + /** + * Валидация репутации (разумные пределы) + */ + public static boolean isValidReputationChange(int change) { + return change >= -100 && change <= 100; + } +} diff --git a/legacy/owyxplugin/src/main/resources/config.yml b/legacy/owyxplugin/src/main/resources/config.yml new file mode 100644 index 00000000000..24771f63354 --- /dev/null +++ b/legacy/owyxplugin/src/main/resources/config.yml @@ -0,0 +1,129 @@ +# Конфигурация плагина ChiwawaPlugin +# Версия: 1.0 + +# Настройки API +api: + base_url: "https://api.owyx.site/api" + timeout: 5000 + admin_token: "CHANGE_ME_ADMIN_JWT_OR_API_TOKEN" + retry_attempts: 3 + +# Настройки базы данных PostgreSQL +database: + host: "127.0.0.1" + port: 5432 + name: "owyx_db" + username: "owyx_user" + password: "CHANGE_ME_DB_PASSWORD" + +# Настройки сервера +server: + ip: "play.owyx.site" + port: 25565 + enable_whitelist: true # Проверка доступа к серверу через API (заявки) + enable_authentication: true # Система авторизации (login/register) + enable_time_limit: true # Ограничение времени игры для trust level 0 + enable_trust_system: true # Trust level система + enable_reputation: true # Система репутации + sync_interval: 300 # Секунд для синхронизации данных + +# Trust Level ограничения +trust_levels: + 0: # Проходимец + max_total_hours: 10 # ВСЕГО 10 часов, не дневной лимит! + description: "Новый игрок без подтвержденного email" + 1: # Новичок + description: "Подтвержден email, полный доступ" + 2: # Проверенный + description: "Опытный игрок с хорошей репутацией" + 3: # Ветеран + description: "Проверенный временем игрок" + +# Сообщения +messages: + # Кик сообщения (показываются при кике с сервера) + no_access_kick: | + &c&l┌─────────────────────────────┐ + &c&l│ &f&lНЕТ ДОСТУПА К СЕРВЕРУ &c&l│ + &c&l├─────────────────────────────┤ + &f&l│ &7У вас нет доступа к серверу &f&l│ + &f&l│ &7Подайте заявку на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &c&l└─────────────────────────────┘ + + time_limit_kick: | + &c&l┌─────────────────────────────┐ + &c&l│ &f&lЛИМИТ ВРЕМЕНИ ИСЧЕРПАН &c&l│ + &c&l├─────────────────────────────┤ + &f&l│ &7Вы достигли лимита в 10 часов &f&l│ + &f&l│ &7Подтвердите email на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &c&l└─────────────────────────────┘ + + ban_kick: | + &4&l┌─────────────────────────────┐ + &4&l│ &f&lВЫ ЗАБАНЕНЫ &4&l│ + &4&l├─────────────────────────────┤ + &f&l│ &7Причина: &c%reason% &f&l│ + &f&l│ &7Обжалование на сайте: &f&l│ + &f&l│ &bhttps://chiwawa.site &f&l│ + &4&l└─────────────────────────────┘ + + # Чат сообщения (обычные сообщения в чат) + trust_level_up: "&a&l[★] &fВаш Trust Level повышен до &a&l%level% &7(%name%)&f!" + reputation_given: "&e&l[REP] &fВы дали &a+1 репутацию &fигроку &b%player%&f!" + reputation_received: "&e&l[REP] &fИгрок &b%player% &fдал вам &a+1 репутацию&f!" + + # Системные сообщения + plugin_enabled: "&a&lChiwawaPlugin включен! Версия: %version%" + plugin_disabled: "&c&lChiwawaPlugin отключен!" + config_reloaded: "&aКонфигурация перезагружена!" + api_connection_failed: "&cОшибка подключения к API сайта!" + api_connection_restored: "&aСоединение с API восстановлено!" + + # Сообщения команд + no_permission: "&cУ вас нет прав для выполнения этой команды!" + player_not_found: "&cИгрок не найден!" + player_not_online: "&cИгрок не в сети!" + invalid_arguments: "&cНеверные аргументы команды!" + command_success: "&aКоманда выполнена успешно!" + command_failed: "&cОшибка выполнения команды!" + + # Профиль игрока + profile_header: "&e&l════════ ПРОФИЛЬ ИГРОКА ════════" + profile_nickname: "&7Никнейм: &f%nickname%" + profile_trust_level: "&7Trust Level: &a%level% &7(%description%)" + profile_reputation: "&7Репутация: &e%reputation%" + profile_playtime: "&7Время игры: &b%playtime%" + profile_email_status: "&7Email: %status%" + profile_registration: "&7Регистрация: &f%date%" + profile_footer: "&e&l═══════════════════════════════" + + # Время игры + playtime_current: "&7Текущая сессия: &b%time%" + playtime_total: "&7Общее время: &b%time%" + playtime_remaining: "&7Осталось времени: &c%time%" + playtime_unlimited: "&aБез ограничений" + + # Репутация + reputation_cooldown: "&cВы сможете дать репутацию через %time%" + reputation_self: "&cНельзя давать репутацию самому себе!" + reputation_insufficient_trust: "&cДля выдачи репутации нужен Trust Level 1 или выше!" + + # Администрирование + user_banned: "&cИгрок %player% забанен. Причина: %reason%" + user_unbanned: "&aИгрок %player% разбанен" + trust_level_changed: "&aИзменен Trust Level игрока %player% на %level%" + sync_started: "&7Синхронизация данных игрока %player%..." + sync_completed: "&aСинхронизация завершена!" + + # Статистика + stats_header: "&e&l════════ СТАТИСТИКА СЕРВЕРА ════════" + stats_online_players: "&7Игроков онлайн: &a%count%" + stats_cached_users: "&7Загружено пользователей: &a%count%" + stats_api_status: "&7Статус API: %status%" + stats_footer: "&e&l══════════════════════════════════" + + stats_cached_users: "&7Загружено пользователей: &a%count%" + stats_api_status: "&7Статус API: %status%" + stats_footer: "&e&l══════════════════════════════════" diff --git a/legacy/owyxplugin/src/main/resources/plugin.yml b/legacy/owyxplugin/src/main/resources/plugin.yml new file mode 100644 index 00000000000..8add1d68f4e --- /dev/null +++ b/legacy/owyxplugin/src/main/resources/plugin.yml @@ -0,0 +1,206 @@ +name: ChiwawaPlugin +version: 1.0.0 +description: Плагин интеграции с сайтом ChiwawaMine для системы whitelist, trust level и репутации +author: eBluffy +website: https://chiwawa.site +main: org.ebluffy.chiwawa.ChiwawaPlugin +api-version: '1.21' +load: STARTUP +prefix: Chiwawa + +# Команды плагина +commands: + chiwawa: + description: Главная команда администрирования плагина + usage: /chiwawa <подкоманда> + permission: chiwawa.admin + aliases: [cw, chiw] + + profile: + description: Показать профиль игрока + usage: /profile + permission: chiwawa.profile + aliases: [prof, me] + + playtime: + description: Показать время игры + usage: /playtime + permission: chiwawa.playtime + aliases: [pt, time] + + rep: + description: Дать репутацию игроку + usage: /rep <игрок> + permission: chiwawa.reputation + aliases: [reputation, +rep] + + applications: + description: Статус заявки на сервер + usage: /applications + permission: chiwawa.applications + aliases: [apps, заявка] + + discord: + description: Информация о Discord сервере + usage: /discord + permission: chiwawa.discord + aliases: [дискорд] + + login: + description: Авторизация (пароль или токен) + usage: /login <пароль|токен> + aliases: [l, auth] + + register: + description: Регистрация на сервере + usage: /register <пароль> <повтор_пароля> + aliases: [reg, регистрация] + + changelogin: + description: Смена режима авторизации + usage: /changelogin [start|confirm <код>] + aliases: [changeauth, сменалогин] + + changepass: + description: Смена пароля (простая авторизация) + usage: /changepass <старый> <новый> <повтор> + aliases: [changepassword, сменапароля] + + unregister: + description: Удаление регистрации игрока (админ) + usage: /unregister + permission: chiwawa.command.unregister + aliases: [unreg, delreg] + +# Права доступа +permissions: + # Основные права + chiwawa.*: + description: Все права плагина + children: + chiwawa.admin: true + chiwawa.moderator: true + chiwawa.user: true + default: false + + chiwawa.admin: + description: Административные права + children: + chiwawa.moderator: true + chiwawa.command.reload: true + chiwawa.command.sync: true + chiwawa.command.ban: true + chiwawa.command.unban: true + chiwawa.command.trust: true + chiwawa.command.rep.modify: true + chiwawa.command.stats: true + chiwawa.command.users: true + chiwawa.command.unregister: true + default: op + + chiwawa.moderator: + description: Права модератора + children: + chiwawa.user: true + chiwawa.command.playtime.others: true + chiwawa.command.sync.self: true + default: false + + chiwawa.user: + description: Базовые права игрока + children: + chiwawa.profile: true + chiwawa.playtime: true + chiwawa.reputation: true + chiwawa.applications: true + chiwawa.discord: true + chiwawa.login: true + chiwawa.register: true + chiwawa.changelogin: true + chiwawa.changepass: true + default: true + + # Права на команды + chiwawa.profile: + description: Просмотр своего профиля + default: true + + chiwawa.playtime: + description: Просмотр своего времени игры + default: true + + chiwawa.reputation: + description: Выдача репутации другим игрокам + default: true + + chiwawa.command.reload: + description: Перезагрузка конфигурации + default: op + + chiwawa.command.sync: + description: Синхронизация данных игроков + default: op + + chiwawa.command.ban: + description: Бан игроков через сайт + default: op + + chiwawa.command.unban: + description: Разбан игроков + default: op + + chiwawa.command.trust: + description: Изменение Trust Level + default: op + + chiwawa.command.rep.modify: + description: Изменение репутации администратором + default: op + + chiwawa.command.stats: + description: Просмотр статистики сервера + default: op + + chiwawa.command.users: + description: Управление пользователями + default: op + + chiwawa.command.playtime.others: + description: Просмотр времени игры других игроков + default: op + + chiwawa.applications: + description: Просмотр статуса заявки + default: true + + chiwawa.discord: + description: Информация о Discord сервере + default: true + + chiwawa.login: + description: Авторизация (пароль или токен) + default: true + + chiwawa.register: + description: Регистрация на сервере + default: true + + chiwawa.changelogin: + description: Смена режима авторизации + default: true + + chiwawa.changepass: + description: Смена пароля (простая авторизация) + default: true + + chiwawa.command.unregister: + description: Удаление регистрации игрока + default: op + +# Зависимости +depend: [] +softdepend: [Vault, PlaceholderAPI, LuckPerms] + +# Загрузка +startup: POSTWORLD + diff --git a/legacy/owyxsite/.env.example b/legacy/owyxsite/.env.example new file mode 100644 index 00000000000..c8fe9e850d1 --- /dev/null +++ b/legacy/owyxsite/.env.example @@ -0,0 +1,101 @@ +# ============================================== +# OWYX PROJECT - Environment Variables +# ============================================== +# cp .env.example .env + +# ---------------------------------------------- +# PostgreSQL Database +# ---------------------------------------------- +DB_USER=owyx_user +DB_PASSWORD=your_secure_password_here_change_me +DB_NAME=owyx_db +DB_HOST=127.0.0.1 +DB_PORT=5432 + +# ---------------------------------------------- +# Directus CMS (optional / legacy) +# ---------------------------------------------- +DIRECTUS_KEY=generate_random_key_here_32_bytes +DIRECTUS_SECRET=generate_random_secret_here_32_bytes +ADMIN_EMAIL=admin@owyx.site +ADMIN_PASSWORD=your_admin_password_here +DIRECTUS_ADMIN_TOKEN= + +# ---------------------------------------------- +# Backend API (Express + Socket.io) +# ---------------------------------------------- +API_PORT=3001 +PORT=3001 +FRONTEND_PORT=3000 +FRONTEND_BIND=0.0.0.0 +API_BIND=0.0.0.0 +POSTGRES_BIND=0.0.0.0 +ADMINER_PORT=8080 +ADMINER_BIND=0.0.0.0 +JWT_SECRET=generate_random_jwt_secret_here +SESSION_SECRET=generate_random_session_secret_here + +# Launcher → https://api.owyx.site must send header X-Owyx-Client-Key +# matching this value. Browser traffic via https://owyx.site/api does NOT +# need the key (Host is owyx.site). Required in production. +LAUNCHER_CLIENT_KEY=generate_long_random_hex_here +API_HOSTS=api.owyx.site + +# Cloudflare Turnstile (leave empty / TURNSTILE_SKIP=true for local) +TURNSTILE_SITE_KEY= +TURNSTILE_SECRET_KEY= +TURNSTILE_SKIP=true +NEXT_PUBLIC_TURNSTILE_SITE_KEY= + +# Discord OAuth (optional) +DISCORD_CLIENT_ID= +DISCORD_CLIENT_SECRET= + +# ---------------------------------------------- +# Email (SMTP / Resend SMTP) +# ---------------------------------------------- +EMAIL_FROM=noreply@owyx.site +EMAIL_TRANSPORT=smtp +EMAIL_SMTP_HOST=smtp.yandex.ru +EMAIL_SMTP_PORT=587 +EMAIL_SMTP_USER= +EMAIL_SMTP_PASSWORD= +SMTP_HOST=smtp.yandex.ru +SMTP_PORT=465 +SMTP_USER= +SMTP_PASS= + +# ---------------------------------------------- +# Domain & URLs (OBT / prod) +# ---------------------------------------------- +# Website +PUBLIC_URL=https://owyx.site +FRONTEND_URL=https://owyx.site +CORS_ORIGIN=https://owyx.site,https://www.owyx.site,http://localhost:3000 +# Launcher API origin (absolute URLs for packs/skins returned to clients) +API_PUBLIC_URL=https://api.owyx.site +API_URL=https://api.owyx.site/api +TRUST_PROXY_HOPS=0 + +# Browser-facing (prefer same-origin /api on owyx.site — leave empty or site path) +NEXT_PUBLIC_API_URL= +NEXT_PUBLIC_DIRECTUS_URL= +NEXT_PUBLIC_SOCKET_URL= + +# Server-side rewrite target for Next.js (docker compose sets this) +BACKEND_URL=http://127.0.0.1:3001 + +# ---------------------------------------------- +# FRP (game traffic — separate from this VPS) +# ---------------------------------------------- +FRP_SERVER_ADDR=45.131.186.146 +FRP_SERVER_PORT=7000 +FRP_TOKEN=your_frp_secret_token_here + +# Public Minecraft join address (FRPC share on RU VPS → MiniPC) +# Format host:port for friends / site settings seed +OWYX_PLAY_ADDRESS=45.131.186.146:1488 + +# ---------------------------------------------- +# Minecraft Integration (optional) +# ---------------------------------------------- diff --git a/legacy/owyxsite/.gitignore b/legacy/owyxsite/.gitignore new file mode 100644 index 00000000000..fc56f68968c --- /dev/null +++ b/legacy/owyxsite/.gitignore @@ -0,0 +1,50 @@ +# Environment variables +.env +.env.local +.env.*.local + +# Docker volumes +postgres/data/ +directus/uploads/ +directus/database/ + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Node modules +node_modules/ +**/node_modules/ + +# Next.js +.next/ +out/ +build/ +dist/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db +desktop.ini + +# Config backups +*.bak +*.backup +# ...but keep the legacy-site snapshot dir tracked (redesign, see old.backup/README.md) +!old.backup/ +!old.backup/** + +# Temporary files +tmp/ +temp/ +*.tmp diff --git a/legacy/owyxsite/.gitkeep b/legacy/owyxsite/.gitkeep new file mode 100644 index 00000000000..be7d94c167f --- /dev/null +++ b/legacy/owyxsite/.gitkeep @@ -0,0 +1 @@ +# Drop former site sources here. diff --git a/legacy/owyxsite/LAUNCHER_SITE_CONTRACT.md b/legacy/owyxsite/LAUNCHER_SITE_CONTRACT.md new file mode 100644 index 00000000000..6409737415e --- /dev/null +++ b/legacy/owyxsite/LAUNCHER_SITE_CONTRACT.md @@ -0,0 +1,333 @@ +# Launcher ↔ Site contract + +How the **Owyx launcher** talks to the **Owyx site** API. Source of truth for the +launcher/site boundary. Keep in sync with `backend/src/routes/launcher.js`. + +**Versions:** launcher-facing **API surface `1.1.0`** (`GET /api/launcher/v1/status.version`), +**site UI `0.1.0`** (`.siteVersion`). Additive catalog fill: live `servers` / `packs` / +`news` (same `news` table as the site). Login + `/api/launcher/me` unchanged. + +**Updated:** 2026-08-24 — friends control-plane + quality pass: hashed sessions, +plugin-only write tokens, `mrpack` is not a player download. + +--- + +## Product model (important) + +Playing is **open**: + +- **Guest / offline** — pick a nick in the launcher and Play. No account. +- **Owyx account** — register on the site, sign in inside the launcher with the + same account, play. Later: skin, cape, profile perks. +- **Microsoft** — separate licensed profile (real OAuth is future work; honest + stub for now). Never breaks offline or Owyx. + +**Applications («заявки») are no longer a whitelist gate.** A registered account +that is **active and not banned** may play. A **ban** blocks everything. + +--- + +## Base URL + +The launcher targets one API base: + +| Env | Base URL | +|-----|----------| +| dev | `http://127.0.0.1:3001` | +| prod | `https://api.owyx.site` | + +Configured in the launcher via `OWYX_API_BASE_URL` (see `Launcher/.env.example`) +or the launcher config. All paths below are relative to the base. + +**Website** is `https://owyx.site` (browser uses same-origin `/api` via nginx → backend). +Do not point the launcher at `owyx.site` for catalog downloads in prod — use `api.owyx.site`. + +### Client key (not a public API) + +Direct requests to **`api.owyx.site`** must send: + +```http +X-Owyx-Client-Key: +``` + +The key is configured as `LAUNCHER_CLIENT_KEY` on the site and `OWYX_CLIENT_KEY` +(or `%USERPROFILE%/owyx/client_key`) in the launcher. Missing/wrong key → `401 unauthorized_client`. +`/health` stays open. Browser traffic via `https://owyx.site/api` does **not** need the key +(`Host: owyx.site`). + +--- + +## Auth flow (Owyx account in the launcher) + +1. `POST /api/auth/login` with `{ "email", "password" }`. + - `200` → `{ success: true, token, user }`. `token` is a JWT. + - `401`/`403` → `{ error }` (wrong credentials / inactive). Show a human message. +2. Store the JWT securely (OS app-data, never plaintext in the UI). +3. `GET /api/launcher/me` with `Authorization: Bearer ` → profile + access. + Session rows store a SHA-256 of the JWT (legacy base64 hashes are migrated on + use). Logout deletes the matching session hash. +4. `serverAccess === true` → the account may play. `false` → show `accessReason`. +5. Logout: drop the stored token (optionally `POST /api/auth/logout`). + +**Parallel sessions:** login does **not** invalidate other clients. Site and +launcher can stay signed in together. The server keeps up to ~10 active sessions +per user (oldest dropped). A `401`/`403` from `/me` means the JWT is gone — +launcher maps that to `no_session` and asks the user to sign in again. + +Offline profiles never call the API; a nick is enough to Play. + +--- + +## Endpoints + +### `POST /api/auth/login` +Request: `{ "email": string, "password": string }` +Response `200`: +```json +{ "success": true, "token": "", "user": { "id": 1, "nickname": "Steve", "role": "user", ... } } +``` + +### `GET /api/launcher/me` (auth: `Bearer `) +Also available as `GET /api/launcher/v1/me`. +```json +{ + "user": { + "id": 1, + "nickname": "Steve", + "email": "steve@owyx.local", + "role": "user", + "trustLevel": 0, + "banned": false, + "emailVerified": false, + "registeredAt": "2026-08-06T01:13:43.477Z" + }, + "serverAccess": true, + "accessReason": "ok", // "ok" | "banned" | "inactive" + "cosmetics": { + "skinUrl": "https://api.owyx.site/uploads/skins/skin-1-....png", + "skinModel": "classic", // "classic" | "slim" + "capeUrl": null + }, + "skinUrl": "https://api.owyx.site/uploads/skins/skin-1-....png", + "application": null // DEPRECATED: always null, removed next release +} +``` +- `serverAccess` = account is active **and** not banned. +- `skinUrl` is absolute, built from the request host, so it is downloadable by + whatever base the launcher used. + +### `GET /api/launcher/v1/status` (public) +```json +{ + "api": "owyx-launcher", + "version": "1.1.0", + "siteVersion": "0.1.0", + "serverAccessModel": "open", + "auth": { "login": "/api/auth/login", "me": "/api/launcher/me" }, + "modules": ["servers", "packs", "news", "cosmetics", "adminCatalog"] +} +``` + +### `GET /api/launcher/v1/cosmetics` (auth) +`{ "skinUrl", "skinModel", "capeUrl", "updatedAt" }`. + +### Catalog (site owns it; launcher is the client) + +A **server** is where to connect (`address` + `port`). A **pack** is what to +download. One pack may back several servers. Players never receive SFTP +credentials — public GET returns only HTTP(S) download/manifest URLs. + +Source types on a pack: `http_zip` | `http_manifest` | `google_drive` | `mrpack` +| `sftp` | `local_ingest`. Friends-MVP download path is **`http_zip` / +`http_manifest`**. Other types are stored + admin-editable; `sftp` is +admin-warehouse only (`downloadAvailable: false` in public GET). `mrpack` is +schema-only for now: public GET sets `downloadAvailable: false` and +`ingest: "planned"` even when a URL is stored. Drive without a direct URL is +not a fake download. + +Dev seed (fresh DB / `ensureCatalogSchema`): pack `demo-vanilla` (tiny fixture +zip at `/fixtures/packs/demo-vanilla.zip`) and servers `owyx-demo` / +`owyx-friends`. + +`GET /api/launcher/v1/servers` — published Owyx + community servers: +```json +{ + "servers": [ + { + "id": "owyx-demo", + "name": "Owyx — демо", + "iconUrl": null, + "address": "45.131.186.146:1488", + "port": 25565, + "kind": "owyx", + "packId": "demo-vanilla", + "minecraft": "1.21.1", + "loader": "vanilla", + "requiresAccount": false, + "status": { "online": null, "players": null, "max": null }, + "pack": { + "id": "demo-vanilla", + "name": "Owyx Demo Vanilla 1.21.1", + "minecraft": "1.21.1", + "loader": "vanilla", + "iconUrl": null, + "description": "", + "sourceType": "http_zip", + "downloadUrl": "http://127.0.0.1:3001/fixtures/packs/demo-vanilla.zip", + "sha256": "b5b345b133be7e851e47ef6f0fd83c61be3abc56dfc8cacd0c6fc65790d2eadb", + "manifestUrl": null + } + } + ] +} +``` +Bearer is optional. `requiresAccount` is a Play gate in the launcher, not a +list filter. `status.online` is reserved (always `null` until ping exists). + +`GET /api/launcher/v1/packs` — published builds (safe player fields only): +```json +{ + "packs": [ + { + "id": "demo-vanilla", + "name": "Owyx Demo Vanilla 1.21.1", + "minecraft": "1.21.1", + "loader": "vanilla", + "sourceType": "http_zip", + "downloadUrl": "http://127.0.0.1:3001/fixtures/packs/demo-vanilla.zip", + "sha256": "<64 hex if set>", + "manifestUrl": null, + "description": "" + } + ] +} +``` +`GET /api/launcher/v1/packs/:id` → `{ "pack": { … } }` (`404` if unpublished). +`GET /api/launcher/v1/packs/:id/manifest` → `{ id, name, minecraft, loader, +sourceType, files: [{ path, url, sha256, size }] }`. SFTP packs have empty +`files`. + +`GET /api/launcher/v1/news` — same published `news` table as the site +(`GET /api/news`). `{ "news": [{ id, title, tag, summary, publishedAt, updatedAt }] }`. + +### Admin catalog (JWT + role `admin`) + +Same JWT as site/launcher login. Do not duplicate business rules in the +launcher — write through these routes. + +- `GET/POST /api/admin/packs` · `GET/PUT/DELETE /api/admin/packs/:id` +- `POST /api/admin/packs/:id/ingest` — multipart field `archive` (`.zip` or + `.mrpack`, ≤50 MB) → `/uploads/packs/{id}.zip` or `{id}.mrpack`. `.zip` + becomes `http_zip` + sha256. `.mrpack` is stored but remains + `downloadAvailable: false` until a real mrpack parser exists. Deleting a + locally ingested pack also unlinks the file. +- `GET/POST /api/admin/servers` · `GET/PUT/DELETE /api/admin/servers/:id` + +Create pack body (camelCase): `{ id?, name, minecraft, loader, iconUrl?, +description?, sourceType, source: { type, config }, published? }`. + +`source.config` by type: + +| type | config (admin) | public GET | +|------|----------------|------------| +| `http_zip` / `local_ingest` | `{ url, sha256? }` | `downloadUrl` + `sha256` | +| `http_manifest` | `{ manifestUrl, files? }` | `manifestUrl` | +| `google_drive` | `{ url, directDownloadUrl?, note? }` | `downloadUrl` only if direct | +| `mrpack` | `{ url }` | `downloadAvailable: false`, `ingest: "planned"` | +| `sftp` | `{ host, port, user, path, password? }` | `downloadAvailable: false` only | + +Admin GET of an SFTP pack returns `source.config.hasPassword` and **never** +the password. Applications/whitelist stay gone. Ban still blocks `/me`. + +--- + +## Cosmetics (skins) + +- Site profile → **Внешний вид**: upload a PNG skin (`64×64` or legacy `64×32`), + choose model (`classic`/`slim`). Cape is reserved (soon). +- Storage: file under `backend/uploads/skins/`, meta in `users.skin_url` / + `users.skin_model` (migration `postgres/migrations/003_cosmetics.sql`). +- API (site, `Bearer` JWT): + - `GET /api/profile/skin` → `{ skin_url, skin_model, cape_url, updated_at }` + - `PUT /api/profile/skin` (multipart `skin` + optional `model`) — PNG only, + validated with sharp, `512KB` cap, re-encoded to a clean PNG. + - `DELETE /api/profile/skin` → back to default. +- Launcher: reads `cosmetics.skinUrl` / `skinModel` from `/api/launcher/me`, + downloads the PNG to `%USERPROFILE%/owyx/skins/{nick}.png` (and optionally + `instances/{id}/game/owyx/skin.png`). Full in-game apply (player-data / + CustomSkinLoader) is still later; the file-on-disk step is wired. + +--- + +## Community server auth (target flow) + +The direction is **launcher-driven session**, not a copy-pasted token: + +1. Player signs into the launcher with their **Owyx account** (`/api/auth/login`). +2. The launcher holds a session (JWT) and can prove identity to a server. +3. A **community server plugin** (the server owner's) validates that proof with + the site — fast login / access without the player typing anything in chat. +4. Owner servers and "community" servers (owners who connected their server) + appear in `/api/launcher/v1/servers`; `requiresAccount` decides offline-vs-Owyx. + +The exact server↔site validation endpoint (e.g. a signed session-check for the +plugin) is **future work**; this section fixes the intent so the plugin and +launcher can be built against a stable idea. + +### Legacy: game token (`/auth ` in chat) — **deprecated** + +- `POST /api/auth/generate-game-token`, `verify-game-token`, `create-game-session`, + `check-game-session` still exist for the **transitional** plugin and are not + removed, but are **not promoted** in the site UI (the profile "game token" tab + was removed). New servers should use the launcher-session flow above. +- `GET /api/plugin/server-access?nickname=...` and other + `/plugin/*` **write/session** routes accept a **long-term API token only** + (`authenticateLongTermApiTokenOnly`). A website session JWT is not enough, + even for an admin. `hasAccess: true` for an **active, non-banned** account. + Banned → `false`. The Express mount is `/api` + `/plugin/...` (not + `/api/settings/plugin/...`). +- Whitelisting, if a server wants it, lives in the **plugin config**, never via + site applications (applications are gone). + +--- + +## News API + +Home page + admin-managed updates. + +- `GET /api/news?limit=6` (public) → published items, newest first: + ```json + { "news": [ { "id": 1, "title": "…", "tag": "Лаунчер", "summary": "…", "published": true, "created_at": "…" } ] } + ``` +- Admin (`Bearer` JWT, role `admin`): + - `GET /api/admin/news` — all items incl. unpublished. + - `POST /api/admin/news` `{ title, tag?, summary?, published? }` → `201 { news }`. + - `PUT /api/admin/news/:id` `{ title?, tag?, summary?, published? }` → `{ news }`. + - `DELETE /api/admin/news/:id` → `{ success: true }`. +- Storage: table `news` (migration `postgres/migrations/006_news.sql`), seeded with + a couple of items on a fresh DB. + +--- + +## Email change + +Confirm a NEW address with a 6-digit code sent to that new address (`Bearer` JWT): + +- `POST /api/profile/email/request` `{ email }` → sends code to the new email. + 60s cooldown. When SMTP is not configured and `NODE_ENV !== production`, the + response includes `devCode` for local testing. Production never echoes the + code. Errors: `400` bad/existing email, `409` taken, `429` too soon. +- `POST /api/profile/email/confirm` `{ code }` → applies the change, sets + `is_email_verified = true`. Errors: `400` no request / expired / wrong code. +- Code lives 15 minutes (columns on `users`, migration `005_email_change.sql`). + +Nickname change stays at **≤ 1 / 30 days** (`PUT /api/profile/nickname`, +migration `004_nickname_cooldown.sql`). + +--- + +## Versioning + +- Stable surface under `/api/launcher/v1/*`. `GET /v1/status.version` is the + contract version (`1.1.0`). Additive changes bump the minor; breaking changes + add `/v2/`. diff --git a/legacy/owyxsite/PLAN.md b/legacy/owyxsite/PLAN.md new file mode 100644 index 00000000000..2243fb2c76b --- /dev/null +++ b/legacy/owyxsite/PLAN.md @@ -0,0 +1,5 @@ +# План сайта перенесён + +Единый план всего Owyx: **[../PLAN.md](../PLAN.md)** (корень монорепо). + +Контракт лаунчера по-прежнему: [`LAUNCHER_SITE_CONTRACT.md`](./LAUNCHER_SITE_CONTRACT.md). diff --git a/legacy/owyxsite/PREVIEW.html b/legacy/owyxsite/PREVIEW.html new file mode 100644 index 00000000000..6ef38029c12 --- /dev/null +++ b/legacy/owyxsite/PREVIEW.html @@ -0,0 +1,53 @@ + + + + + + OWYX — быстрый просмотр страниц + + + +

OWYX preview

+

Локальные ссылки на Next.js (`http://127.0.0.1:3000`). Сначала запусти фронт.

+ +
+ Запуск:
+ cd owyx/backend && npm i && npm run dev
+ cd owyx/frontend && npm i && set BACKEND_URL=http://127.0.0.1:3001 && npm run dev +
+ + diff --git a/legacy/owyxsite/README.md b/legacy/owyxsite/README.md new file mode 100644 index 00000000000..da7ee52158b --- /dev/null +++ b/legacy/owyxsite/README.md @@ -0,0 +1,123 @@ +# Owyx stack + +Hybrid migration target for the former Chiwawa site: + +``` +PostgreSQL 16 ← owyx/postgres/init.sql (+ migrations/001_chat.sql) + ↑ +Directus ← CMS / admin UI (:8055, path /directus) + ↑ +Backend API ← owyx/backend Express + Socket.io (:3001, paths /api/*) + ↑ +Next.js ← owyx/frontend (:3000, rewrites /api → backend) +``` + +`chiwawasite/` remains in the repo as a behavior reference and is **not** required at runtime. + +**Design:** the site follows the launcher-aligned design system in the root `DESIGN.md` +(dark space + cyan `#00e5ff`, DM Sans). Pre-redesign gold UI is snapshotted in `old.backup/`. +Launcher integration spec: `LAUNCHER_SITE_CONTRACT.md` (Owyx-account login, `GET /api/launcher/me`). + +**Versions:** Site UI **0.1** (аккаунт, download, auth, cosmetics, admin catalog) · +Launcher-facing API **v1.1** (`GET /api/launcher/v1/status` → `version 1.1.0`, `siteVersion 0.1.0`). +Catalog: `GET /api/launcher/v1/servers|packs|news` are live rows, not empty stubs. +Admin CRUD: `/api/admin/servers` + `/api/admin/packs`. See `LAUNCHER_SITE_CONTRACT.md`. + +## Quick start (local, without Docker) + +1. Run PostgreSQL 17 (Compose) or 16 (Cloud/apt is enough for local API work). Create roles `owyx`/`root` (`postgres/migrations/000_bootstrap_roles.sql`), apply `postgres/init.sql`, then migrations `001_chat.sql` … `007_servers_packs.sql`. Catalog tables created by `ensureCatalogSchema()` must be **owned by** `owyx_user`. +2. Copy env: `cp .env.example .env` — set `DB_*`, `JWT_SECRET`, `TURNSTILE_SKIP=true`. + Turnstile on the frontend is opt-in: it renders only when `NEXT_PUBLIC_TURNSTILE_SITE_KEY` is set. +3. Backend: + ```bash + cd backend && npm install && npm run dev + # http://127.0.0.1:3001/health + ``` +4. Frontend: + ```bash + cd frontend && npm install + BACKEND_URL=http://127.0.0.1:3001 npm run dev + # http://127.0.0.1:3000 + ``` + +## Docker Compose (one command) + +```bash +cd owyxsite +cp .env.example .env # set DB_PASSWORD, JWT_SECRET, SESSION_SECRET (+ optional SMTP) +docker compose up -d --build # postgres + adminer + backend + frontend +``` + +| Service | URL / Port | Notes | +|----------|-------------------------------|-------| +| frontend | http://localhost:3000 | Next.js site | +| backend | http://localhost:3001/health | Express API + Socket.io | +| adminer | http://localhost:8080 | DB UI — System **PostgreSQL**, Server `postgres`, user/db from `.env` | +| postgres | localhost:5432 | Postgres **17** (`\restrict` in the dump needs 16.4+/17) | +| directus | http://localhost:8055 | optional: `docker compose --profile directus up -d` | + +**Fresh DB bootstrap.** On first boot (empty `./postgres/data`) Postgres runs +`docker-entrypoint-initdb.d` in filename order: `000_bootstrap_roles` (create +`owyx`/`root` — the dump does `OWNER TO owyx|root`) → `init.sql` → `001_chat` → +`002_roles` → `003_cosmetics` (skins) → `004_nickname_cooldown` → +`005_email_change` → `006_news` → `007_servers_packs`. Re-init from +scratch: `docker compose down && rm -rf postgres/data`. + +**Existing volume does not auto-apply new SQL.** `initdb.d` runs only on first +create. On a DB that already has data, apply the new file yourself: + +```bash +docker compose exec -T postgres psql -U owyx_user -d owyx_db < postgres/migrations/007_servers_packs.sql +# or locally: +# psql -U owyx_user -d owyx_db -f postgres/migrations/007_servers_packs.sql +``` + +The backend also runs an idempotent `ensureCatalogSchema()` on startup (CREATE +TABLE IF NOT EXISTS + demo seed if empty), so friends-dev often works without +the manual step — still apply the file on production volumes so indexes/seed +match git. + +Apply any older migration to a running DB the same way: + +```bash +docker compose exec -T postgres psql -U owyx_user -d owyx_db < postgres/migrations/006_news.sql +``` + +Production: loopback binds + host nginx. See [`deploy/README.md`](./deploy/README.md) +(`bash deploy/vps-up.sh`; set `TURNSTILE_SECRET_KEY` first). `panel.owyx.site` stays with C³ CELERITY — do not +steal host `:443`. Apex `owyx.site` proxies the Next app (no Coming Soon). + +## Launcher dev against local compose + +```bash +# after docker compose is healthy +export OWYX_API_BASE_URL=http://127.0.0.1:3001 +cd ../Launcher/apps/launcher +npm run check && npm run check:rust +npm run dev:tauri +``` + +The native window talks to Express on `:3001` (catalog, login, admin, skins). +Vite-only `npm run dev` still proxies `/proxy/owyx` to the same base. + +Launcher overlay cap: **512 MB** (`MAX_PACK_BYTES`). Larger packs (Foreg ~2 GB) +need a streaming download — not this stack. + +## Email + +HTML templates (dark + cyan, inline CSS) live in +`backend/src/utils/emailTemplates.js` (verify / reset / password-changed / +welcome / nickname-changed). Without SMTP they are simulated in logs. Preview: + +```bash +cd backend && node scripts/preview-emails.js # writes email-previews/*.html +# or, as admin: GET /api/admin/email-preview/ +``` + +SMTP (Yandex) via `SMTP_HOST/PORT/USER/PASS` + `EMAIL_FROM` in `.env` — **never +commit the password**. + +## Directus + +Optional CMS: `docker compose --profile directus up -d`. See +[`directus/README.md`](./directus/README.md) for tables and role checklist. diff --git a/legacy/owyxsite/aliases.sh b/legacy/owyxsite/aliases.sh new file mode 100644 index 00000000000..309718f5af8 --- /dev/null +++ b/legacy/owyxsite/aliases.sh @@ -0,0 +1,81 @@ +# ============================================== +# OWYX Project - Fast Commands +# ============================================== +# Алиасы и функции для быстрой работы с проектом +# +# Установка: +# echo "source /path/to/owyx/aliases.sh" >> ~/.bashrc +# source ~/.bashrc + +# Alias для docker-compose в папке проекта +alias owyx-up='docker-compose up -d' +alias owyx-down='docker-compose down' +alias owyx-restart='docker-compose restart' +alias owyx-logs='docker-compose logs -f' +alias owyx-ps='docker-compose ps' +alias owyx-pull='docker-compose pull' +alias owyx-build='docker-compose build' + +# Отдельные сервисы +alias owyx-db-restart='docker-compose restart postgres' +alias owyx-api-restart='docker-compose restart directus' +alias owyx-db-logs='docker-compose logs -f postgres' +alias owyx-api-logs='docker-compose logs -f directus' + +# База данных +alias owyx-db='docker exec -it owyx-postgres psql -U owyx_user -d owyx_db' +alias owyx-backup='./backup.sh' + +# FRP +alias owyx-frp-restart='sudo systemctl restart frpc' +alias owyx-frp-status='sudo systemctl status frpc' +alias owyx-frp-logs='sudo journalctl -u frpc -f' + +# Nginx +alias owyx-nginx-restart='sudo systemctl restart nginx' +alias owyx-nginx-status='sudo systemctl status nginx' +alias owyx-nginx-test='sudo nginx -t' +alias owyx-nginx-logs='sudo tail -f /var/log/nginx/owyx_access.log' + +# Функция для быстрого доступа к проекту +owyx() { + cd /path/to/owyx # Измените на реальный путь +} + +# Функция для полного рестарта всех сервисов +owyx-full-restart() { + echo "Перезапуск всех сервисов OWYX..." + docker-compose restart + sudo systemctl restart nginx + sudo systemctl restart frpc + echo "Готово!" +} + +# Функция для проверки статуса всех сервисов +owyx-status() { + echo "=== Docker Containers ===" + docker-compose ps + echo "" + echo "=== Nginx ===" + sudo systemctl status nginx --no-pager + echo "" + echo "=== FRP Client ===" + sudo systemctl status frpc --no-pager +} + +# Функция для просмотра всех логов +owyx-logs-all() { + echo "=== Docker Logs ===" + docker-compose logs --tail=50 + echo "" + echo "=== Nginx Access Log ===" + sudo tail -20 /var/log/nginx/owyx_access.log + echo "" + echo "=== Nginx Error Log ===" + sudo tail -20 /var/log/nginx/owyx_error.log + echo "" + echo "=== FRP Logs ===" + sudo journalctl -u frpc --no-pager -n 20 +} + +echo "✅ OWYX aliases loaded! Используйте 'owyx-' и нажмите Tab для автодополнения" diff --git a/legacy/owyxsite/backend/.dockerignore b/legacy/owyxsite/backend/.dockerignore new file mode 100644 index 00000000000..d419956ebb7 --- /dev/null +++ b/legacy/owyxsite/backend/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +uploads/* +!uploads/.gitkeep +.env +*.log +.git +.gitignore +README.md diff --git a/legacy/owyxsite/backend/.gitignore b/legacy/owyxsite/backend/.gitignore new file mode 100644 index 00000000000..b4074c3d0fe --- /dev/null +++ b/legacy/owyxsite/backend/.gitignore @@ -0,0 +1,7 @@ +node_modules/ +dist/ +uploads/* +!uploads/.gitkeep +.env +*.log +email-previews/ diff --git a/legacy/owyxsite/backend/Dockerfile b/legacy/owyxsite/backend/Dockerfile new file mode 100644 index 00000000000..c2c1a406870 --- /dev/null +++ b/legacy/owyxsite/backend/Dockerfile @@ -0,0 +1,39 @@ +# ============================================== +# OWYX Backend API — Express + Socket.io +# ============================================== + +FROM node:22-alpine AS deps +WORKDIR /app +RUN apk add --no-cache python3 make g++ vips-dev +COPY package.json package-lock.json* ./ +RUN npm ci + +FROM node:22-alpine AS builder +WORKDIR /app +RUN apk add --no-cache python3 make g++ vips-dev +COPY --from=deps /app/node_modules ./node_modules +COPY . . +RUN npm run build + +FROM node:22-alpine AS runner +WORKDIR /app +ENV NODE_ENV=production +ENV TZ=Europe/Moscow +RUN apk add --no-cache vips \ + && addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 owyx + +COPY --from=builder /app/package.json ./ +COPY --from=builder /app/node_modules ./node_modules +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/src/config ./dist/config +COPY --from=builder /app/fixtures ./fixtures +RUN mkdir -p uploads/avatars uploads/packs && chown -R owyx:nodejs uploads fixtures + +USER owyx +EXPOSE 3001 +ENV API_PORT=3001 +ENV PORT=3001 +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://127.0.0.1:3001/health || exit 1 +CMD ["node", "dist/server.js"] diff --git a/legacy/owyxsite/backend/README.md b/legacy/owyxsite/backend/README.md new file mode 100644 index 00000000000..bd10b729dc4 --- /dev/null +++ b/legacy/owyxsite/backend/README.md @@ -0,0 +1,38 @@ +# Owyx Backend API + +Express + Socket.io TypeScript service ported from `chiwawasite`. + +## Endpoints + +| Path | Description | +|------|-------------| +| `/health` | Healthcheck | +| `/api/auth/*` | Auth, game tokens, Discord, password reset | +| `/api/applications/*` | Whitelist applications | +| `/api/profile/*` | Profile, avatar, stats | +| `/api/admin/*` | Admin users, logs, settings, tokens | +| `/api/settings/*` | Public/server settings | +| `/api/reputation/*` | Reputation votes | +| `/api/trust-level/*` | Trust level applications | +| `/api/forum/*` | Forum categories/topics/posts | +| `/api/chat/*` | Chat rooms/messages REST | +| `/socket.io` | Realtime chat | + +## Local development + +```bash +# from owyx/ +cp .env.example .env +# fill DB_* JWT_SECRET TURNSTILE_SKIP=true + +cd backend +npm install +npm run dev # http://127.0.0.1:3001 +``` + +Requires PostgreSQL with schema from `../postgres/init.sql`. +Chat tables are auto-created on boot; see also `../postgres/migrations/001_chat.sql`. + +## Production + +Runs as the `backend` service in `../docker-compose.yml` on port **3001**. diff --git a/legacy/owyxsite/backend/fixtures/packs/README.md b/legacy/owyxsite/backend/fixtures/packs/README.md new file mode 100644 index 00000000000..7d3b50a129d --- /dev/null +++ b/legacy/owyxsite/backend/fixtures/packs/README.md @@ -0,0 +1,10 @@ +# Demo pack fixture + +Tiny zip used by the friends-sprint seed (`demo-vanilla`). + +- File: `demo-vanilla.zip` (not a full Minecraft client — overlay only) +- SHA-256: see `demo-vanilla.sha256` +- Served by the backend at `/fixtures/packs/demo-vanilla.zip` + +The launcher installs vanilla/loader first, then extracts this archive into +the instance `game/` folder. diff --git a/legacy/owyxsite/backend/fixtures/packs/demo-vanilla.sha256 b/legacy/owyxsite/backend/fixtures/packs/demo-vanilla.sha256 new file mode 100644 index 00000000000..c068047c3f5 --- /dev/null +++ b/legacy/owyxsite/backend/fixtures/packs/demo-vanilla.sha256 @@ -0,0 +1 @@ +b5b345b133be7e851e47ef6f0fd83c61be3abc56dfc8cacd0c6fc65790d2eadb diff --git a/legacy/owyxsite/backend/fixtures/packs/demo-vanilla.zip b/legacy/owyxsite/backend/fixtures/packs/demo-vanilla.zip new file mode 100644 index 0000000000000000000000000000000000000000..f55edaee99ab2479b40ef758960ea3132f354b6c GIT binary patch literal 363 zcmWIWW@Zs#U|`^2_{J&`E36>BwjRh^3B(}L{PM~Q-IUbaeElF-M;BjLy^@L&)n0GD zW&E@)j`a+y2gVCEVrcFQ&=|N9H{?x&mdpRY`Kwlrz!7q`1Nr=EKlxkT}Z z--P8#){E1f$`WVa-n&*$>_pL#XExugoijIw+)%vM6e3+_6u8t=`|RHHk96}o4zbxC z(sV74S+su5+^(wJ`a438UAg^Fgj(D1*$1FF80ba@CJ+GxTtJ+gpHi%^mz|ngz|0Wf z&B!FejN5ZyO+cc75yZmgRdf?T>X2;%@j;-0aU+mK*d5@_$_5f=0>UaFeH+AK0002D BV+{ZR literal 0 HcmV?d00001 diff --git a/legacy/owyxsite/backend/package-lock.json b/legacy/owyxsite/backend/package-lock.json new file mode 100644 index 00000000000..f4b9effe29f --- /dev/null +++ b/legacy/owyxsite/backend/package-lock.json @@ -0,0 +1,2958 @@ +{ + "name": "owyx-backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "owyx-backend", + "version": "1.0.0", + "dependencies": { + "bcryptjs": "^2.4.3", + "compression": "^1.7.4", + "cors": "^2.8.5", + "dotenv": "^16.4.7", + "express": "^4.21.2", + "express-validator": "^7.2.1", + "helmet": "^8.0.0", + "jsonwebtoken": "^9.0.2", + "minecraft-server-util": "^5.4.4", + "morgan": "^1.10.0", + "multer": "^2.2.0", + "nodemailer": "^9.0.5", + "pg": "^8.13.1", + "sharp": "^0.35.3", + "socket.io": "^4.8.1", + "uuid": "^11.0.5" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.0", + "@types/jsonwebtoken": "^9.0.7", + "@types/morgan": "^1.9.9", + "@types/multer": "^2.2.0", + "@types/node": "^22.10.5", + "@types/nodemailer": "^6.4.17", + "@types/pg": "^8.11.10", + "@types/uuid": "^10.0.0", + "tsx": "^4.19.2", + "typescript": "^5.7.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "license": "MIT" + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.6.tgz", + "integrity": "sha512-9xlo6R2qDs5uixm0bcIqCeMCE6HiQsIyel9KQySStiyqNl2tnj2mP3DX1Nf56MD6KMenNNlBBsy3LJ7gUEQPXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/body-parser": { + "version": "1.19.6", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", + "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", + "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^5.0.0", + "@types/serve-static": "^2" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.3.tgz", + "integrity": "sha512-dPfW8NFiOF4wOHc7+N/QSxlY9cfSsenewGbAz8C8U/MULPd/YZ27LvJUIlzaXie7e6Ove9YunJGgC9tbHD2cKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", + "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", + "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*", + "@types/node": "*" + } + }, + "node_modules/@types/morgan": { + "version": "1.9.10", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz", + "integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/multer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/multer/-/multer-2.2.0.tgz", + "integrity": "sha512-3U1troeqGV8Ntp7Q3klwf4zr23VEoqYVocYXaswm9+8z3O9UHDYAqLxjJ/h550iRADTjKdOdhhasXw6gD6kYtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/node": { + "version": "22.20.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.1.tgz", + "integrity": "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/nodemailer": { + "version": "6.4.24", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.24.tgz", + "integrity": "sha512-Ww4u0rT9wQNXh4JiQaIwx3QWdcOFXzOjQA2zc+jtFYNmQiT4mIUqcDin51bDFdkzKubFnQCZNK7FIHlPKQ/q9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/pg": { + "version": "8.20.4", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.4.tgz", + "integrity": "sha512-Jz7UDOlIiFJuacC0TlBoLyNtmwlA/wpIyPDd3tvUqlRM+HzkWy2xUgpFpaXtbfTAFF6sIGq5lsCDBdJnhky1Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", + "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*" + } + }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/basic-auth/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "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==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "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==", + "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/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "compressible": "~2.0.18", + "debug": "2.6.9", + "negotiator": "~0.6.4", + "on-headers": "~1.1.0", + "safe-buffer": "5.2.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "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/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "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==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "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==", + "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/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/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==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.9", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.9.tgz", + "integrity": "sha512-clKkw4C7nJ22mGgoVcCg6V/W/TxdNyIOTr89k2ONZu81qqkddPFDF0LXcbAwhzPD8DjkiRCjzuiO6Y+fkpD4vg==", + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.21.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/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/engine.io/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/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==", + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" + } + }, + "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/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "~1.20.5", + "content-disposition": "~0.5.4", + "content-type": "~1.0.4", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "~0.1.12", + "proxy-addr": "~2.0.7", + "qs": "~6.15.1", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "~0.19.0", + "serve-static": "~1.16.2", + "setprototypeof": "1.2.0", + "statuses": "~2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-validator": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-7.3.2.tgz", + "integrity": "sha512-ctLw1Vl6dXVH62dIQMDdTAQkrh480mkFuG6/SGXOaVlwPNukhRAe7EgJIMJ2TSAni8iwHBRp530zAZE5ZPF2IA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.18.1", + "validator": "~13.15.23" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/finalhandler": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", + "integrity": "sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "~2.4.1", + "parseurl": "~1.3.3", + "statuses": "~2.0.2", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "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==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-8.3.0.tgz", + "integrity": "sha512-Qgpiaws3Sm30Av8Eah6sjMCZZwjlBu+E68rhpCWBshY1lb09HtLwj5GviX0OyQIn+ulUS0iX0AxN5n3tLZzz1w==", + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/EvanHahn" + } + }, + "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/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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/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==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/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/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minecraft-motd-util": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/minecraft-motd-util/-/minecraft-motd-util-1.1.12.tgz", + "integrity": "sha512-5TuTRjrRupSTruea0nRC37r0FdhkS1O4wIJKAYfwJRCQd/X4Zyl/dVIs96h9UVW6N8jhIuz9pNkrDsqyN7VBdA==", + "deprecated": "no longer maintained", + "license": "MIT" + }, + "node_modules/minecraft-server-util": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/minecraft-server-util/-/minecraft-server-util-5.4.4.tgz", + "integrity": "sha512-uaE0N9PHPtJudi8BlCvKDD9K30w23ZpeS1I53wEJo9nX0HSmg5qFvwj8gMG0CYCUwWH/g5hjKaGAwXXN/vhMJw==", + "deprecated": "no longer maintained, please use https://mcstatus.io", + "license": "MIT", + "dependencies": { + "minecraft-motd-util": "^1.1.9" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/morgan": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.11.0.tgz", + "integrity": "sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.4.1", + "on-headers": "~1.1.0" + }, + "engines": { + "node": ">= 0.8.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/multer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.2.0.tgz", + "integrity": "sha512-6rdyFg2kLrMh9Jee7/BMPuV9lEAd7lLW2YUpF9/YxR7njyoUwwQ0ZPh3TaIY50Sw6vlyD2HW3wGOkTS4P79xrQ==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "type-is": "^1.6.18" + }, + "engines": { + "node": ">= 10.16.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/negotiator": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz", + "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nodemailer": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-9.0.5.tgz", + "integrity": "sha512-wvjiKvjczmsN7U/8006JOdXubgBk2XFAbioDMbT+sM7cPs0QrhJTa6KBRX7P5REGGkDcLUz/EarWidb8G8C1jQ==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, + "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==", + "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==", + "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==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.22.0.tgz", + "integrity": "sha512-8wih1vVIBMxoUM2oB4soJsD9tDnDpLv4OXBJ+EJzFsvycD+lfyIreC2gGHq78f8jbLLt+bvlPTFdFZfJkOuzAA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.14.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.15.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz", + "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.14.0.tgz", + "integrity": "sha512-XwWDGcLRGCXAR8F/AM5bG7Q+A3Wm2s6QeEjlOKZLlH3UYcguiqCWKyWXVag5TLTIjR7oOJUY8kcADaZgWPyLeg==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.15.0.tgz", + "integrity": "sha512-cq9sECI5s0+uPUXjbz8ioyPJni6RzsRib0US67i5IoTZKw8fNeYlVE7u8F4dG7vEJJtc5wdD1K189lCCUwqWTQ==", + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "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.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "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==", + "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==", + "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/socket.io": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.21.0" + } + }, + "node_modules/socket.io-adapter/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/socket.io-adapter/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/socket.io-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", + "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/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/socket.io-parser/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/socket.io/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/socket.io/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/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/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/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "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/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", + "optional": true + }, + "node_modules/tsx": { + "version": "4.23.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.5.tgz", + "integrity": "sha512-rw55FUaqOoI7RvlQwLbhO4nSDApnQ4/CykPuiQ/EPvtrX3WA9Ig55jIt9VvbBJbzJuj12ueRu4PMZ2SxPVbihg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "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": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "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/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.15.35", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.35.tgz", + "integrity": "sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ws": { + "version": "8.21.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.2.tgz", + "integrity": "sha512-54dMVAo4WIe6SKy3vBgN+9bJZqqQ8IMRevAkOLQALhi49qkkQDQfWdAZ8KQlXiEabw88ARXXdUrlvtbKQX+aKw==", + "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" + } + } + } +} diff --git a/legacy/owyxsite/backend/package.json b/legacy/owyxsite/backend/package.json new file mode 100644 index 00000000000..31a9593ddde --- /dev/null +++ b/legacy/owyxsite/backend/package.json @@ -0,0 +1,50 @@ +{ + "name": "owyx-backend", + "version": "1.0.0", + "description": "Owyx API — Express + Socket.io (ported from chiwawasite)", + "main": "dist/server.js", + "scripts": { + "dev": "tsx watch src/server.ts", + "build": "tsc && npm run copy-js", + "copy-js": "mkdir -p dist/routes dist/utils dist/config dist/database dist/middleware && cp -r src/routes/* dist/routes/ && cp -r src/utils/* dist/utils/ && cp -r src/config/* dist/config/ && cp src/database/*.js dist/database/ 2>/dev/null || true && cp src/middleware/*.js dist/middleware/ 2>/dev/null || true", + "start": "node dist/server.js", + "start:dev": "tsx src/server.ts", + "typecheck": "tsc --noEmit" + }, + "engines": { + "node": ">=20" + }, + "dependencies": { + "bcryptjs": "^2.4.3", + "compression": "^1.7.4", + "cors": "^2.8.5", + "dotenv": "^16.4.7", + "express": "^4.21.2", + "express-validator": "^7.2.1", + "helmet": "^8.0.0", + "jsonwebtoken": "^9.0.2", + "minecraft-server-util": "^5.4.4", + "morgan": "^1.10.0", + "multer": "^2.2.0", + "nodemailer": "^9.0.5", + "pg": "^8.13.1", + "sharp": "^0.35.3", + "socket.io": "^4.8.1", + "uuid": "^11.0.5" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.7.5", + "@types/cors": "^2.8.17", + "@types/express": "^5.0.0", + "@types/jsonwebtoken": "^9.0.7", + "@types/morgan": "^1.9.9", + "@types/multer": "^2.2.0", + "@types/node": "^22.10.5", + "@types/nodemailer": "^6.4.17", + "@types/pg": "^8.11.10", + "@types/uuid": "^10.0.0", + "tsx": "^4.19.2", + "typescript": "^5.7.3" + } +} diff --git a/legacy/owyxsite/backend/scripts/preview-emails.js b/legacy/owyxsite/backend/scripts/preview-emails.js new file mode 100644 index 00000000000..c8d39fa971a --- /dev/null +++ b/legacy/owyxsite/backend/scripts/preview-emails.js @@ -0,0 +1,43 @@ +#!/usr/bin/env node +// Render every built-in Owyx email template with sample data to HTML files, so +// they can be opened in a browser and eyeballed. No SMTP or DB needed. +// +// node scripts/preview-emails.js [outDir] (default: ./email-previews) + +const fs = require("fs"); +const path = require("path"); +const { render, TEMPLATE_KEYS } = require("../src/utils/emailTemplates"); + +const outDir = path.resolve(process.argv[2] || path.join(__dirname, "..", "email-previews")); +fs.mkdirSync(outDir, { recursive: true }); + +const sample = { + nickname: "Steve", + verificationLink: "https://owyx.site/verify?token=SAMPLE_TOKEN", + resetLink: "https://owyx.site/reset-password?token=SAMPLE_TOKEN", + oldNick: "OldNick", + newNick: "Steve", + serverName: "Owyx", + serverIp: "play.owyx.site", +}; + +const index = []; +for (const key of TEMPLATE_KEYS) { + const { subject, html } = render(key, sample); + const file = path.join(outDir, `${key}.html`); + fs.writeFileSync(file, html, "utf8"); + index.push({ key, subject, file }); + console.log(`✓ ${key.padEnd(18)} — ${subject}`); +} + +fs.writeFileSync( + path.join(outDir, "index.html"), + `Owyx email previews + +

Owyx email previews

    ` + + index.map((i) => `
  • ${i.key} — ${i.subject}
  • `).join("") + + `
`, + "utf8" +); + +console.log(`\nWrote ${index.length} templates to ${outDir}`); diff --git a/legacy/owyxsite/backend/src/config/settings.js b/legacy/owyxsite/backend/src/config/settings.js new file mode 100644 index 00000000000..e4cca6a4b59 --- /dev/null +++ b/legacy/owyxsite/backend/src/config/settings.js @@ -0,0 +1,84 @@ +// Настройки сервера +// Автоматически сгенерировано админ-панелью + +module.exports = { + "server": { + "name": "ChiwawaMine", + "description": "Приватный Minecraft сервер для своих.
Вход только по заявку.", + "ip": "play.chiwawa.site", + "port": "25164", + "website": "https://chiwawa.ru", + "discord": "https://discord.gg/your-invite", + "telegram": "https://t.me/chiwawa" + }, + "applications": { + "minMotivationLength": 50, + "minPlansLength": 30, + "maxApplicationsPerDay": 3, + "autoApprovalEnabled": false + }, + "trustLevel": { + "requirements": { + "0": { + "name": "🚶 Проходимец", + "hoursRequired": 0, + "reputationRequired": 0, + "emailVerified": false, + "description": "Лимит 10 часов ВСЕГО до подтверждения email" + }, + "1": { + "name": "👤 Новичок", + "hoursRequired": 0, + "reputationRequired": 0, + "emailVerified": true, + "description": "Стандартная группа после подтверждения email, без лимитов" + }, + "2": { + "name": "✅ Проверенный", + "hoursRequired": 25, + "reputationRequired": 10, + "emailVerified": true, + "description": "Требует заявки на одобрение повышения" + }, + "3": { + "name": "🏆 Ветеран", + "hoursRequired": 50, + "reputationRequired": 20, + "emailVerified": true, + "description": "Высший уровень доверия для игроков" + } + }, + "maxPlayTimeForNovice": 10, + "autoPromotionEnabled": false, + "applicationCooldownHours": 24 + }, + "reputation": { + "voteWeight": { + "novice": 1, + "verified": 2, + "veteran": 3, + "moderator": 5, + "admin": 10 + }, + "activityBonus": { + "daily": 1, + "weekly": 5, + "monthly": 20 + }, + "penalties": { + "ban": -50, + "warning": -10 + } + }, + "security": { + "maxLoginAttempts": 5, + "lockoutTime": 15, + "tokenExpiration": "7d", + "bcryptRounds": 12 + }, + "email": { + "from": "noreply@chiwawa.ru", + "service": "gmail", + "verificationExpiration": 24 + } +}; diff --git a/legacy/owyxsite/backend/src/database/connection.js b/legacy/owyxsite/backend/src/database/connection.js new file mode 100644 index 00000000000..327d903f1cd --- /dev/null +++ b/legacy/owyxsite/backend/src/database/connection.js @@ -0,0 +1,85 @@ +const { Pool } = require('pg'); +require('dotenv').config(); + +const getDbHost = () => process.env.DB_HOST || '127.0.0.1'; + +const pool = new Pool({ + host: getDbHost(), + port: parseInt(process.env.DB_PORT || '5432', 10), + database: process.env.DB_NAME || 'owyx_db', + user: process.env.DB_USER || 'owyx_user', + password: process.env.DB_PASSWORD || process.env.DB_PASS || '', + max: 20, + idleTimeoutMillis: 60000, + connectionTimeoutMillis: 30000, + keepAlive: true, + keepAliveInitialDelayMillis: 0, + ssl: process.env.DB_SSL === 'true' ? { rejectUnauthorized: false } : false, +}); + +pool.on('error', (err) => { + console.error('Unexpected PostgreSQL pool error:', err.message); +}); + +async function query(text, params, retries = 3) { + if (process.env.NO_DATABASE === 'true') { + console.log('NO_DATABASE mode — query skipped:', String(text).substring(0, 60)); + return { rows: [], rowCount: 0 }; + } + + const start = Date.now(); + + for (let attempt = 1; attempt <= retries; attempt++) { + try { + const res = await pool.query(text, params); + const duration = Date.now() - start; + if (process.env.LOG_QUERIES === 'true') { + console.log('Query OK', { attempt, duration: `${duration}ms`, rows: res.rowCount }); + } + return res; + } catch (error) { + console.error(`Query attempt ${attempt}/${retries} failed:`, { + error: error.message, + code: error.code, + host: getDbHost(), + }); + + if (attempt === retries) throw error; + + const delay = Math.min(1000 * Math.pow(2, attempt - 1), 10000); + await new Promise((resolve) => setTimeout(resolve, delay)); + } + } +} + +async function getClient() { + return pool.connect(); +} + +async function testConnection() { + let client; + try { + console.log(`Connecting to PostgreSQL ${getDbHost()}:${process.env.DB_PORT || 5432}/${process.env.DB_NAME || 'owyx_db'}`); + client = await pool.connect(); + const result = await client.query('SELECT NOW() as current_time, version() as version'); + console.log('Database connected:', result.rows[0].current_time); + return true; + } catch (error) { + console.error('Database connection failed:', error.message); + return false; + } finally { + if (client) client.release(); + } +} + +async function end() { + await pool.end(); +} + +module.exports = { + query, + getClient, + testConnection, + end, + pool, +}; diff --git a/legacy/owyxsite/backend/src/middleware/clientKey.js b/legacy/owyxsite/backend/src/middleware/clientKey.js new file mode 100644 index 00000000000..7ed7282e541 --- /dev/null +++ b/legacy/owyxsite/backend/src/middleware/clientKey.js @@ -0,0 +1,63 @@ +/** + * Gate direct access to the API host (api.owyx.site). + * + * - Browser traffic hits https://owyx.site/api (Host: owyx.site) — no client key. + * - Launcher hits https://api.owyx.site (Host: api.owyx.site) — requires + * header X-Owyx-Client-Key matching LAUNCHER_CLIENT_KEY. + * - /health stays open for uptime checks. + */ + +function parseList(raw, fallback) { + const src = (raw && String(raw).trim()) || fallback; + return src + .split(',') + .map((s) => s.trim().toLowerCase()) + .filter(Boolean); +} + +function requestHost(req) { + const xf = req.get('x-forwarded-host'); + if (xf) { + return xf.split(',')[0].trim().toLowerCase().split(':')[0]; + } + return String(req.hostname || req.get('host') || '') + .toLowerCase() + .split(':')[0]; +} + +function clientKeyGate(req, res, next) { + const path = req.path || ''; + if (path === '/health' || path.startsWith('/health/')) { + return next(); + } + + const apiHosts = parseList(process.env.API_HOSTS, 'api.owyx.site'); + const host = requestHost(req); + const onApiHost = apiHosts.some((h) => host === h); + + if (!onApiHost) { + return next(); + } + + const expected = (process.env.LAUNCHER_CLIENT_KEY || '').trim(); + if (!expected) { + if (process.env.NODE_ENV === 'production') { + return res.status(503).json({ + error: 'launcher_client_key_missing', + message: 'LAUNCHER_CLIENT_KEY must be set in production for api.*', + }); + } + return next(); + } + + const got = (req.get('x-owyx-client-key') || '').trim(); + if (got !== expected) { + return res.status(401).json({ + error: 'unauthorized_client', + message: 'Missing or invalid X-Owyx-Client-Key', + }); + } + return next(); +} + +module.exports = { clientKeyGate, requestHost, parseList }; diff --git a/legacy/owyxsite/backend/src/routes/admin.js b/legacy/owyxsite/backend/src/routes/admin.js new file mode 100644 index 00000000000..7f60957e0c5 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/admin.js @@ -0,0 +1,3048 @@ +// Административные маршруты +// Создатель: ebluffy + +const express = require('express'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, authenticateApiToken, authenticateLongTermApiToken, requireRole } = require('./auth'); +const bcrypt = require('bcryptjs'); + +const router = express.Router(); + +// ---- Compatibility aliases for Next.js admin UI ---- + +// GET /api/admin/applications → same as /api/applications +router.get('/applications', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 50; + const status = req.query.status || 'all'; + const offset = (page - 1) * limit; + + const params = []; + let whereClause = ''; + if (status !== 'all') { + params.push(status); + whereClause = `WHERE a.status = $${params.length}`; + } + params.push(limit, offset); + const limitIdx = params.length - 1; + const offsetIdx = params.length; + + const result = await db.query(` + SELECT a.*, u.nickname as reviewed_by_nickname + FROM applications a + LEFT JOIN users u ON a.reviewed_by = u.id + ${whereClause} + ORDER BY a.submitted_at DESC + LIMIT $${limitIdx} OFFSET $${offsetIdx} + `, params); + + const countParams = status !== 'all' ? [status] : []; + const countWhere = status !== 'all' ? 'WHERE status = $1' : ''; + const countResult = await db.query( + `SELECT COUNT(*) as total FROM applications ${countWhere}`, + countParams + ); + + res.json({ + applications: result.rows, + pagination: { + page, + limit, + total: parseInt(countResult.rows[0].total), + totalPages: Math.ceil(parseInt(countResult.rows[0].total) / limit), + }, + }); + } catch (error) { + console.error('Admin applications list error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +async function reviewApplication(req, res, status) { + try { + const { id } = req.params; + const comment = req.body?.comment || req.body?.reason || null; + + const applicationResult = await db.query(`SELECT * FROM applications WHERE id = $1`, [id]); + if (applicationResult.rows.length === 0) { + return res.status(404).json({ error: 'Заявка не найдена' }); + } + const application = applicationResult.rows[0]; + if (application.status !== 'pending') { + return res.status(400).json({ error: 'Заявка уже была рассмотрена' }); + } + + await db.query(` + UPDATE applications + SET status = $1, reviewed_by = $2, reviewed_at = NOW(), review_comment = $3 + WHERE id = $4 + `, [status, req.user.id, comment, id]); + + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'application_reviewed', + `Заявка ${application.minecraft_nick} ${status === 'approved' ? 'одобрена' : 'отклонена'}`, + application.user_id, + ]); + + res.json({ + success: true, + message: `Заявка ${status === 'approved' ? 'одобрена' : 'отклонена'}`, + application_id: id, + status, + }); + } catch (error) { + console.error('Admin application review error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +} + +router.post('/applications/:id/approve', authenticateToken, requireRole(['admin', 'moderator']), (req, res) => + reviewApplication(req, res, 'approved') +); +router.post('/applications/:id/reject', authenticateToken, requireRole(['admin', 'moderator']), (req, res) => + reviewApplication(req, res, 'rejected') +); + +// POST aliases for ban/unban (UI uses POST; plugin uses PUT) +router.post('/users/:id/ban', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const { id } = req.params; + const reason = req.body?.reason || 'Заблокирован администратором'; + await db.query(` + UPDATE users SET is_banned = true, ban_reason = $1, status = 'banned', ban_until = NULL + WHERE id = $2 + `, [reason, id]); + await db.query(`DELETE FROM user_sessions WHERE user_id = $1`, [id]); + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, 'user_banned', $2, $3) + `, [req.user.id, reason, id]); + res.json({ success: true, message: 'Пользователь заблокирован' }); + } catch (error) { + console.error('Ban alias error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +router.post('/users/:id/unban', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const { id } = req.params; + await db.query(` + UPDATE users SET is_banned = false, ban_reason = NULL, ban_until = NULL, status = 'active' + WHERE id = $1 + `, [id]); + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, 'user_unbanned', 'Разблокирован через админ-панель', $2) + `, [req.user.id, id]); + res.json({ success: true, message: 'Пользователь разблокирован' }); + } catch (error) { + console.error('Unban alias error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// Вспомогательная функция для безопасного удаления пользователя +const safeDeleteUser = async (userId, adminId, reason) => { + await db.query('BEGIN'); + + try { + // Получаем информацию о пользователе + const userResult = await db.query('SELECT nickname, role FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + throw new Error('Пользователь не найден'); + } + + const user = userResult.rows[0]; + console.log(`🗑️ Начинаем удаление пользователя ${user.nickname} (ID: ${userId})`); + + // Логируем удаление ПЕРЕД удалением + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + adminId, + 'user_deleted', + `Аккаунт пользователя ${user.nickname} полностью удален: ${reason}`, + userId + ]); + + // Удаляем связанные данные в правильном порядке + const tablesToClean = [ + 'password_reset_tokens', + 'email_verification_tokens', + 'user_sessions', + 'user_activity', + 'user_achievements', + 'applications', + 'trust_level_applications', + 'user_reputation', + 'reputation_log', + 'player_stats', + 'discord_oauth', + 'login_logs' // Перенесено в конец для правильного порядка + ]; + + for (const table of tablesToClean) { + try { + const result = await db.query(`DELETE FROM ${table} WHERE user_id = $1`, [userId]); + console.log(` ✅ Очищена таблица: ${table} (удалено ${result.rowCount} записей)`); + } catch (tableError) { + if (tableError.code === '42P01') { + console.log(` ⚠️ Таблица ${table} не существует, пропускаем`); + } else if (tableError.code === '42703') { + console.log(` ⚠️ Колонка user_id не существует в таблице ${table}, пропускаем`); + } else { + console.log(` ❌ Ошибка очистки таблицы ${table}:`, tableError.message); + // Не останавливаемся, пытаемся продолжить + } + } + } + + // Обновляем логи админа (сохраняем последний лог о удалении) + await db.query(` + UPDATE admin_logs + SET target_user_id = NULL, + details = details || ' [ПОЛЬЗОВАТЕЛЬ УДАЛЕН]' + WHERE target_user_id = $1 AND id != ( + SELECT MAX(id) FROM admin_logs WHERE target_user_id = $1 + ) + `, [userId]); + + // Удаляем самого пользователя + await db.query('DELETE FROM users WHERE id = $1', [userId]); + + await db.query('COMMIT'); + console.log(`✅ Пользователь ${user.nickname} (ID: ${userId}) успешно удален`); + + return { success: true, nickname: user.nickname }; + + } catch (error) { + await db.query('ROLLBACK'); + console.error('Ошибка при удалении пользователя:', error); + throw error; + } +}; + +// GET /api/admin/users/by-nick/:nickname - Поиск пользователя по нику (для плагина) +router.get('/users/by-nick/:nickname', authenticateLongTermApiToken, requireRole(['admin']), async (req, res) => { + try { + const { nickname } = req.params; + + console.log(`🔍 Поиск пользователя по нику: ${nickname}`); + + const userResult = await db.query(` + SELECT + u.id, u.nickname, u.email, u.discord_username, u.trust_level, + u.is_banned, u.ban_reason, u.ban_until, u.registered_at, u.last_login, + u.is_email_verified, u.first_name, u.role, u.status, + ps.time_played_minutes, ps.is_time_limited, + ur.reputation_score, ps.total_logins + FROM users u + LEFT JOIN player_stats ps ON u.id = ps.user_id + LEFT JOIN user_reputation ur ON u.id = ur.user_id + WHERE LOWER(u.nickname) = LOWER($1) + LIMIT 1 + `, [nickname]); + + if (userResult.rows.length === 0) { + console.log(`❌ Пользователь с ником ${nickname} не найден`); + return res.status(404).json({ error: `Пользователь с ником ${nickname} не найден` }); + } + + const user = userResult.rows[0]; + console.log(`✅ Найден пользователь ${user.nickname} (ID: ${user.id}), статус бана: ${user.is_banned}`); + + res.json({ + success: true, + user: user + }); + + } catch (error) { + console.error('Ошибка поиска пользователя по нику:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/users - Управление пользователями +router.get('/users', authenticateLongTermApiToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 50; + const search = req.query.search || ''; + const nickname = req.query.nickname || ''; + const status = req.query.status || 'all'; + const offset = (page - 1) * limit; + + let whereClause = ''; + let queryParams = []; + let paramCount = 0; + + // Добавляем условие точного поиска по nickname (для плагина) + if (nickname && nickname.trim()) { + paramCount++; + whereClause += ` WHERE u.nickname = $${paramCount}`; + queryParams.push(nickname.trim()); + } + // Добавляем условие поиска (для веб-интерфейса) + else if (search && search.trim()) { + paramCount++; + whereClause += ` WHERE (u.nickname ILIKE $${paramCount} OR u.email ILIKE $${paramCount})`; + queryParams.push(`%${search.trim()}%`); + } + + // Добавляем условие статуса + if (status !== 'all') { + if (status === 'active') { + whereClause += ` ${whereClause ? 'AND' : 'WHERE'} u.is_banned = false`; + } else if (status === 'banned') { + whereClause += ` ${whereClause ? 'AND' : 'WHERE'} u.is_banned = true`; + } + } + + // Добавляем LIMIT и OFFSET в конец + paramCount++; + const limitParam = paramCount; + queryParams.push(limit); + + paramCount++; + const offsetParam = paramCount; + queryParams.push(offset); + + const result = await db.query(` + SELECT + u.id, u.nickname, u.email, u.discord_username, u.trust_level, + u.is_banned, u.ban_reason, u.registered_at, u.last_login, + u.is_email_verified, u.first_name, u.role, u.status, + ps.time_played_minutes, ps.is_time_limited, + ps.reputation, ps.total_logins, + COUNT(s.id) as session_count + FROM users u + LEFT JOIN player_stats ps ON u.id = ps.user_id + LEFT JOIN user_sessions s ON u.id = s.user_id AND s.is_active = true + ${whereClause} + GROUP BY u.id, ps.time_played_minutes, ps.is_time_limited, ps.reputation, ps.total_logins + ORDER BY u.registered_at DESC + LIMIT $${limitParam} OFFSET $${offsetParam} + `, queryParams); + + // Получаем общее количество (убираем LIMIT и OFFSET параметры) + const countParams = queryParams.slice(0, -2); + const countResult = await db.query(` + SELECT COUNT(DISTINCT u.id) as total + FROM users u + ${whereClause} + `, countParams); + + const total = parseInt(countResult.rows[0].total); + + res.json({ + users: result.rows, + pagination: { + page, + limit, + total, + totalPages: Math.ceil(total / limit) + } + }); + + } catch (error) { + console.error('Ошибка получения пользователей:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/admin/users/:id/ban - Блокировка пользователя +router.put('/users/:id/ban', [ + authenticateLongTermApiToken, + requireRole(['admin', 'moderator']), + body('reason').isLength({ min: 1, max: 500 }).withMessage('Причина должна содержать от 1 до 500 символов'), + body('type').optional().isIn(['temporary', 'permanent']).withMessage('Тип должен быть temporary или permanent'), + body('duration').optional().isInt({ min: 1 }).withMessage('Длительность должна быть положительным числом'), + body('unit').optional().isIn(['hours', 'days', 'weeks', 'months']).withMessage('Единица времени должна быть hours, days, weeks или months'), + body('minecraft_nick').optional().isLength({ min: 1, max: 50 }).withMessage('Minecraft ник должен содержать от 1 до 50 символов') +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + console.error('Ошибка валидации в /ban:', errors.array()); + console.error('Полученные данные:', req.body); + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { reason, type, duration, unit, minecraft_nick } = req.body; + + console.log(`📝 Запрос на бан пользователя ID:${id}, тип:${type}, причина:${reason}, ник:${minecraft_nick}`); + + let userId = id; + let userNickname = null; + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + console.log(`🎯 Найден пользователь по нику ${minecraft_nick}: ID ${userId}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT nickname FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + } + + // Вычисляем дату окончания бана для временной блокировки + let bannedUntil = null; + if (type === 'temporary' && duration && unit) { + const now = new Date(); + switch (unit) { + case 'hours': + bannedUntil = new Date(now.getTime() + duration * 60 * 60 * 1000); + break; + case 'days': + bannedUntil = new Date(now.getTime() + duration * 24 * 60 * 60 * 1000); + break; + case 'weeks': + bannedUntil = new Date(now.getTime() + duration * 7 * 24 * 60 * 60 * 1000); + break; + case 'months': + bannedUntil = new Date(now.getTime() + duration * 30 * 24 * 60 * 60 * 1000); + break; + default: + bannedUntil = null; + } + } + + // Обновляем статус бана + await db.query(` + UPDATE users + SET is_banned = true, ban_reason = $1, ban_until = $2 + WHERE id = $3 + `, [reason, bannedUntil, userId]); + + // Деактивируем все активные сессии пользователя + await db.query(` + UPDATE user_sessions + SET is_active = false + WHERE user_id = $1 AND is_active = true + `, [userId]); + + // Логируем действие + const logDetails = type === 'temporary' + ? `Пользователь ${userNickname} заблокирован на ${duration} ${unit}: ${reason}${bannedUntil ? ` (до ${bannedUntil.toLocaleString('ru-RU')})` : ''}` + : `Пользователь ${userNickname} заблокирован навсегда: ${reason}`; + + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'user_banned', + logDetails, + userId + ]); + + console.log(`✅ Пользователь ${userNickname} (ID: ${userId}) успешно забанен`); + + res.json({ + success: true, + message: type === 'temporary' + ? `Пользователь ${userNickname} заблокирован на ${duration} ${unit}` + : `Пользователь ${userNickname} заблокирован навсегда`, + user_id: userId, + ban_until: bannedUntil + }); + + } catch (error) { + console.error('Ошибка блокировки пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/admin/users/:id/unban - Разблокировка пользователя +router.put('/users/:id/unban', [ + authenticateLongTermApiToken, + requireRole(['admin', 'moderator']), + body('minecraft_nick').optional().isLength({ min: 1, max: 50 }).withMessage('Minecraft ник должен содержать от 1 до 50 символов') +], async (req, res) => { + try { + const { id } = req.params; + const { minecraft_nick } = req.body; + + let userId = id; + let userNickname = null; + + console.log(`📝 Запрос на разбан пользователя ID:${id}, ник:${minecraft_nick}`); + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname, is_banned FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + + if (!userResult.rows[0].is_banned) { + return res.status(400).json({ error: `Пользователь ${userNickname} не забанен` }); + } + + console.log(`🎯 Найден забаненный пользователь по нику ${minecraft_nick}: ID ${userId}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT nickname, is_banned FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + + if (!userResult.rows[0].is_banned) { + return res.status(400).json({ error: `Пользователь ${userNickname} не забанен` }); + } + } + + // Снимаем бан + await db.query(` + UPDATE users + SET is_banned = false, ban_reason = NULL, ban_until = NULL + WHERE id = $1 + `, [userId]); + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'user_unbanned', + `Пользователь ${userNickname} разблокирован`, + userId + ]); + + console.log(`✅ Пользователь ${userNickname} (ID: ${userId}) успешно разбанен`); + + res.json({ + success: true, + message: `Пользователь ${userNickname} разблокирован`, + user_id: userId + }); + + } catch (error) { + console.error('Ошибка разблокировки пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// DELETE /api/admin/users/:id/delete - Полное удаление аккаунта пользователя +router.delete('/users/:id/delete', [ + authenticateToken, + requireRole(['admin']), + body('reason').isLength({ min: 5, max: 500 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { reason } = req.body; + + // Проверяем, что пользователь существует и не является админом + const userResult = await db.query('SELECT nickname, role FROM users WHERE id = $1', [id]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + + // Запрещаем удаление админов + if (user.role === 'admin') { + return res.status(403).json({ error: 'Нельзя удалить аккаунт администратора' }); + } + + // Запрещаем самоудаление + if (parseInt(id) === req.user.id) { + return res.status(403).json({ error: 'Нельзя удалить собственный аккаунт' }); + } + + // Используем безопасную функцию удаления + const result = await safeDeleteUser(id, req.user.id, reason); + + res.json({ + success: true, + message: `Аккаунт пользователя ${result.nickname} полностью удален` + }); + + } catch (error) { + console.error('Ошибка удаления пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/admin/users/:id/trust-level - Изменение уровня доверия +router.put('/users/:id/trust-level', [ + authenticateLongTermApiToken, + requireRole(['admin']), + body('level').isInt({ min: 0, max: 3 }), + body('reason').optional().isLength({ max: 200 }), + body('minecraft_nick').optional().isLength({ min: 1, max: 50 }).withMessage('Minecraft ник должен содержать от 1 до 50 символов') +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { level, reason, minecraft_nick } = req.body; + + let userId = id; + let userNickname = null; + let oldLevel = null; + + console.log(`📝 Запрос на изменение траст левела пользователя ID:${id}, ник:${minecraft_nick}, новый уровень:${level}`); + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname, trust_level FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + oldLevel = userResult.rows[0].trust_level; + console.log(`🎯 Найден пользователь по нику ${minecraft_nick}: ID ${userId}, текущий уровень ${oldLevel}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT nickname, trust_level FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + oldLevel = userResult.rows[0].trust_level; + } + + // Обновляем уровень доверия + await db.query('UPDATE users SET trust_level = $1 WHERE id = $2', [level, userId]); + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'trust_level_changed', + `Уровень доверия ${userNickname} изменен с ${oldLevel} на ${level}${reason ? ': ' + reason : ''}`, + userId + ]); + + console.log(`✅ Уровень доверия пользователя ${userNickname} (ID: ${userId}) изменен с ${oldLevel} на ${level}`); + + res.json({ + success: true, + message: `Уровень доверия пользователя ${userNickname} изменен на ${level}`, + user_id: userId, + old_level: oldLevel, + new_level: level + }); + + } catch (error) { + console.error('Ошибка изменения уровня доверия:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/users/:id/details - Получение подробной информации о пользователе +router.get('/users/:id/details', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const { id } = req.params; + + const userResult = await db.query(` + SELECT + id, + nickname, + email, + first_name, + age, + bio, + avatar_url, + discord_username, + role, + trust_level, + status, + is_active, + is_email_verified, + is_banned, + ban_reason, + ban_until, + registered_at, + last_login, + total_minutes + FROM users + WHERE id = $1 + `, [id]); if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + res.json(user); + + } catch (error) { + console.error('Ошибка получения данных пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/users/:id/activity - Получение активности пользователя +router.get('/users/:id/activity', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const { id } = req.params; + + // Проверяем, существует ли пользователь + const userExists = await db.query('SELECT id FROM users WHERE id = $1', [id]); + if (userExists.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + // Получаем последние сессии пользователя (ограничиваем 10 записями) + const sessions = await db.query(` + SELECT + created_at, + ip_address, + user_agent, + is_active, + expires_at + FROM user_sessions + WHERE user_id = $1 + ORDER BY created_at DESC + LIMIT 10 + `, [id]); + + // Получаем последние входы в систему (ограничиваем 10 записями) + const loginLogs = await db.query(` + SELECT + login_time, + ip_address, + user_agent, + success + FROM login_logs + WHERE user_id = $1 + ORDER BY login_time DESC + LIMIT 10 + `, [id]); + + res.json({ + sessions: sessions.rows, + loginLogs: loginLogs.rows + }); + + } catch (error) { + console.error('Ошибка получения активности пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/stats - Общая статистика +router.get('/stats', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + // Статистика пользователей + const userStats = await db.query(` + SELECT + COUNT(*) as total_users, + COUNT(CASE WHEN registered_at > NOW() - INTERVAL '24 hours' THEN 1 END) as new_today, + COUNT(CASE WHEN registered_at > NOW() - INTERVAL '7 days' THEN 1 END) as new_week, + COUNT(CASE WHEN is_banned = true THEN 1 END) as banned_users, + COUNT(CASE WHEN last_login > NOW() - INTERVAL '24 hours' THEN 1 END) as active_today + FROM users + `); + + // Статистика заявок + const applicationStats = await db.query(` + SELECT + COUNT(*) as total_applications, + COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending, + COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved, + COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected, + COUNT(CASE WHEN submitted_at > NOW() - INTERVAL '24 hours' THEN 1 END) as today + FROM applications + `); + + // Статистика сессий + const sessionStats = await db.query(` + SELECT + COUNT(*) as total_sessions, + COUNT(CASE WHEN is_active = true AND expires_at > NOW() THEN 1 END) as active_sessions, + COUNT(CASE WHEN created_at > NOW() - INTERVAL '24 hours' THEN 1 END) as sessions_today, + AVG(EXTRACT(EPOCH FROM (expires_at - created_at))/60) as avg_session_minutes + FROM user_sessions + `); + + // Статистика игрового времени + const playtimeStats = await db.query(` + SELECT + SUM(time_played_minutes) as total_minutes_played, + AVG(time_played_minutes) as avg_minutes_per_user, + COUNT(CASE WHEN is_time_limited = true THEN 1 END) as limited_users + FROM player_stats + `); + + // Статистика траст левелов + const trustLevelStats = await db.query(` + SELECT + trust_level, + COUNT(*) as user_count + FROM users + GROUP BY trust_level + ORDER BY trust_level + `); + + // Статистика репутации + const reputationStats = await db.query(` + SELECT + COUNT(*) as users_with_reputation, + AVG(reputation_score) as avg_reputation, + COUNT(CASE WHEN reputation_score >= 10 THEN 1 END) as reputation_10_plus, + COUNT(CASE WHEN reputation_score >= 20 THEN 1 END) as reputation_20_plus + FROM user_reputation + `); + + // Статистика заявок на траст левел + const trustApplicationStats = await db.query(` + SELECT + COUNT(*) as total_applications, + COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending, + COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved, + COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected + FROM trust_level_applications + `); + + res.json({ + users: userStats.rows[0], + applications: applicationStats.rows[0], + sessions: sessionStats.rows[0], + playtime: playtimeStats.rows[0], + trust_levels: trustLevelStats.rows, + reputation: reputationStats.rows[0], + trust_applications: trustApplicationStats.rows[0], + server_info: { + uptime: process.uptime(), + memory_usage: process.memoryUsage(), + node_version: process.version + } + }); + + } catch (error) { + console.error('Ошибка получения статистики:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/admin/users/:id/playtime - Обновить время игры (для плагина) +router.put('/users/:id/playtime', authenticateLongTermApiToken, requireRole(['admin']), async (req, res) => { + try { + const userId = parseInt(req.params.id); + const { playtime_minutes } = req.body; + + if (!playtime_minutes || playtime_minutes < 0) { + return res.status(400).json({ error: 'Некорректное время игры' }); + } + + // Обновляем время игры в player_stats + const result = await db.query( + 'UPDATE player_stats SET time_played_minutes = $1, updated_at = NOW() WHERE user_id = $2 RETURNING *', + [playtime_minutes, userId] + ); + + if (result.rows.length === 0) { + // Создаем запись, если её нет + await db.query( + 'INSERT INTO player_stats (user_id, time_played_minutes, created_at, updated_at) VALUES ($1, $2, NOW(), NOW())', + [userId, playtime_minutes] + ); + } + + res.json({ success: true, message: 'Время игры обновлено' }); + + } catch (error) { + console.error('Ошибка обновления времени игры:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// PUT /api/admin/users/:id/reputation - Изменить репутацию (для плагина) +router.put('/users/:id/reputation', [ + authenticateLongTermApiToken, + requireRole(['admin']), + body('reputation').optional().isInt({ min: 0 }).withMessage('reputation должно быть неотрицательным числом'), + body('reason').optional().isLength({ max: 200 }), + body('minecraft_nick').optional().isLength({ min: 1, max: 50 }).withMessage('Minecraft ник должен содержать от 1 до 50 символов') +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { reputation, reason, minecraft_nick } = req.body; + + let userId = id; + let userNickname = null; + + console.log(`📝 Запрос на установку репутации пользователя ID:${id}, ник:${minecraft_nick}, новая репутация:${reputation}`); + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + console.log(`🎯 Найден пользователь по нику ${minecraft_nick}: ID ${userId}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT id, nickname FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + } + + // Проверяем, что репутация указана + if (reputation === undefined) { + return res.status(400).json({ error: 'Требуется параметр reputation' }); + } + + // Получаем текущую репутацию для логирования + const currentRepResult = await db.query( + 'SELECT reputation_score FROM user_reputation WHERE user_id = $1', + [userId] + ); + const currentReputation = currentRepResult.rows.length > 0 ? currentRepResult.rows[0].reputation_score : 0; + + // УСТАНАВЛИВАЕМ (а не суммируем) абсолютное значение репутации + const result = await db.query(` + INSERT INTO user_reputation (user_id, reputation_score, updated_at) + VALUES ($1, $2, NOW()) + ON CONFLICT (user_id) + DO UPDATE SET + reputation_score = $2, + updated_at = NOW() + RETURNING * + `, [userId, reputation]); + + console.log(`✅ Репутация пользователя ${userNickname} (ID: ${userId}) установлена в ${reputation} (было: ${currentReputation}). Причина: ${reason || 'Не указана'}`); + + res.json({ + success: true, + message: 'Репутация установлена', + user_id: userId, + user_nickname: userNickname, + reputation_score: reputation, + previous_reputation: currentReputation, + action: 'set' + }); + + } catch (error) { + console.error('Ошибка установки репутации:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/admin/users/:id/reputation/change - Изменить репутацию на указанную величину (для плагина) +router.post('/users/:id/reputation/change', [ + authenticateLongTermApiToken, + requireRole(['admin']), + body('reputation_change').isInt({ min: -100, max: 100 }).withMessage('reputation_change должно быть числом от -100 до 100'), + body('reason').optional().isLength({ max: 200 }), + body('minecraft_nick').optional().isLength({ min: 1, max: 50 }).withMessage('Minecraft ник должен содержать от 1 до 50 символов') +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { reputation_change, reason, minecraft_nick } = req.body; + + let userId = id; + let userNickname = null; + + console.log(`📝 Запрос на изменение репутации пользователя ID:${id}, ник:${minecraft_nick}, изменение:${reputation_change}`); + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + console.log(`🎯 Найден пользователь по нику ${minecraft_nick}: ID ${userId}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT id, nickname FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + } + + // Получаем текущую репутацию + const currentRepResult = await db.query( + 'SELECT reputation_score FROM user_reputation WHERE user_id = $1', + [userId] + ); + const currentReputation = currentRepResult.rows.length > 0 ? currentRepResult.rows[0].reputation_score : 0; + + // Вычисляем новую репутацию + const newReputation = Math.max(0, currentReputation + reputation_change); + + // ИЗМЕНЯЕМ репутацию на указанную величину + const result = await db.query(` + INSERT INTO user_reputation (user_id, reputation_score, updated_at) + VALUES ($1, $2, NOW()) + ON CONFLICT (user_id) + DO UPDATE SET + reputation_score = GREATEST(0, user_reputation.reputation_score + $3), + updated_at = NOW() + RETURNING reputation_score + `, [userId, newReputation, reputation_change]); + + const finalReputation = result.rows[0].reputation_score; + + console.log(`✅ Репутация пользователя ${userNickname} (ID: ${userId}) изменена на ${reputation_change} (было: ${currentReputation}, стало: ${finalReputation}). Причина: ${reason || 'Не указана'}`); + + res.json({ + success: true, + message: 'Репутация изменена', + user_id: userId, + user_nickname: userNickname, + reputation_change: reputation_change, + previous_reputation: currentReputation, + new_reputation: finalReputation, + action: 'change' + }); + + } catch (error) { + console.error('Ошибка изменения репутации:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/admin/users/:id/stats - Получить статистику игрока (для плагина) +router.get('/users/:id/stats', [ + authenticateLongTermApiToken, + requireRole(['admin']), + // Поддерживаем query параметр minecraft_nick для поиска по нику +], async (req, res) => { + try { + const idParam = req.params.id; + const { minecraft_nick } = req.query; + + let userId = parseInt(idParam); + let userNickname = null; + + console.log(`📝 Запрос статистики пользователя ID:${idParam}, ник:${minecraft_nick}`); + + // Если передан minecraft_nick, ищем пользователя по нику (поддержка оффлайн игроков) + if (minecraft_nick) { + const userResult = await db.query('SELECT id, nickname FROM users WHERE LOWER(nickname) = LOWER($1)', [minecraft_nick]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: `Пользователь с ником ${minecraft_nick} не найден` }); + } + userId = userResult.rows[0].id; + userNickname = userResult.rows[0].nickname; + console.log(`🎯 Найден пользователь по нику ${minecraft_nick}: ID ${userId}`); + } else { + // Проверяем, что пользователь существует по ID + const userResult = await db.query('SELECT id, nickname FROM users WHERE id = $1', [userId]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + userNickname = userResult.rows[0].nickname; + } + + const statsResult = await db.query(` + SELECT ps.*, COALESCE(ur.reputation_score, 0) as reputation + FROM player_stats ps + LEFT JOIN user_reputation ur ON ps.user_id = ur.user_id + WHERE ps.user_id = $1 + `, [userId]); + + if (statsResult.rows.length === 0) { + // Создаем базовую статистику если её нет + await db.query( + 'INSERT INTO player_stats (user_id, time_played_minutes, is_time_limited, created_at, updated_at) VALUES ($1, 0, false, NOW(), NOW())', + [userId] + ); + + const newStatsResult = await db.query(` + SELECT ps.*, COALESCE(ur.reputation_score, 0) as reputation + FROM player_stats ps + LEFT JOIN user_reputation ur ON ps.user_id = ur.user_id + WHERE ps.user_id = $1 + `, [userId]); + + const stats = newStatsResult.rows[0]; + // Добавляем поля для совместимости с админ панелью + stats.player_level = stats.current_level || 1; + stats.deaths = stats.deaths_count || 0; + stats.mob_kills = stats.mobs_killed || 0; + stats.user_nickname = userNickname; + + console.log(`✅ Создана и возвращена базовая статистика для ${userNickname} (ID: ${userId})`); + return res.json(stats); + } + + const stats = statsResult.rows[0]; + // Добавляем поля для совместимости с админ панелью + stats.player_level = stats.current_level || 1; + stats.deaths = stats.deaths_count || 0; + stats.mob_kills = stats.mobs_killed || 0; + stats.user_nickname = userNickname; + + console.log(`✅ Возвращена статистика для ${userNickname} (ID: ${userId}): игровое время ${stats.time_played_minutes || 0} мин, репутация ${stats.reputation}`); + + res.json(stats); + + } catch (error) { + console.error('Ошибка получения статистики игрока:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/admin/user-activity - Записать активность игрока (для плагина) +router.post('/user-activity', authenticateLongTermApiToken, requireRole(['admin']), async (req, res) => { + try { + const { user_id, activity_type, description, metadata } = req.body; + + if (!user_id || !activity_type || !description) { + return res.status(400).json({ error: 'Не все обязательные поля заполнены' }); + } + + await db.query( + 'INSERT INTO user_activity (user_id, activity_type, description, metadata, created_at) VALUES ($1, $2, $3, $4, NOW())', + [user_id, activity_type, description, metadata || null] + ); + + res.status(201).json({ success: true, message: 'Активность записана' }); + + } catch (error) { + console.error('Ошибка записи активности:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/admin/logs - Просмотр логов действий +router.get('/logs', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 100; + const action = req.query.action || 'all'; + const user_id = req.query.user_id || null; + const offset = (page - 1) * limit; + + let whereClause = ''; + let selectParams = [limit, offset]; + let countParams = []; + + if (action !== 'all') { + if (action === 'user_moderation') { + // Группируем блокировки, разблокировки и удаления + whereClause += ` WHERE al.action IN ($${selectParams.length + 1}, $${selectParams.length + 2}, $${selectParams.length + 3})`; + selectParams.push('user_banned', 'user_unbanned', 'user_deleted'); + countParams.push('user_banned', 'user_unbanned', 'user_deleted'); + } else { + whereClause += ` WHERE al.action = $${selectParams.length + 1}`; + selectParams.push(action); + countParams.push(action); + } + } + + if (user_id) { + if (whereClause) { + whereClause += ` AND al.target_user_id = $${selectParams.length + 1}`; + } else { + whereClause += ` WHERE al.target_user_id = $${selectParams.length + 1}`; + } + selectParams.push(user_id); + countParams.push(user_id); + } + + const result = await db.query(` + SELECT + al.*, + u.nickname as admin_nickname, + tu.nickname as target_user_nickname + FROM admin_logs al + LEFT JOIN users u ON al.admin_id = u.id + LEFT JOIN users tu ON al.target_user_id = tu.id + ${whereClause} + ORDER BY al.created_at DESC + LIMIT $1 OFFSET $2 + `, selectParams); + + // Для COUNT запроса создаем отдельный WHERE clause с правильной нумерацией + let countWhereClause = ''; + let countParamIndex = 1; + + if (action !== 'all') { + if (action === 'user_moderation') { + countWhereClause += ` WHERE al.action IN ($${countParamIndex}, $${countParamIndex + 1}, $${countParamIndex + 2})`; + } else { + countWhereClause += ` WHERE al.action = $${countParamIndex}`; + } + countParamIndex += (action === 'user_moderation' ? 3 : 1); + } + + if (user_id) { + if (countWhereClause) { + countWhereClause += ` AND al.target_user_id = $${countParamIndex}`; + } else { + countWhereClause += ` WHERE al.target_user_id = $${countParamIndex}`; + } + } + + const countResult = await db.query(` + SELECT COUNT(*) as total FROM admin_logs al ${countWhereClause} + `, countParams); + + const total = parseInt(countResult.rows[0].total); + + res.json({ + logs: result.rows, + pagination: { + page, + limit, + total, + totalPages: Math.ceil(total / limit) + } + }); + + } catch (error) { + console.error('Ошибка получения логов:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// POST /api/admin/announcement - Создание объявления +router.post('/announcement', [ + authenticateToken, + requireRole(['admin']), + body('title').isLength({ min: 5, max: 100 }), + body('content').isLength({ min: 10, max: 2000 }), + body('type').isIn(['info', 'warning', 'urgent']), + body('show_until').optional().isISO8601() +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { title, content, type, show_until } = req.body; + + const result = await db.query(` + INSERT INTO announcements (title, content, type, author_id, show_until) + VALUES ($1, $2, $3, $4, $5) + RETURNING id, created_at + `, [title, content, type, req.user.id, show_until || null]); + + const announcement = result.rows[0]; + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'announcement_created', + `Создано объявление: ${title}` + ]); + + res.json({ + success: true, + message: 'Объявление создано', + announcement_id: announcement.id, + created_at: announcement.created_at + }); + + } catch (error) { + console.error('Ошибка создания объявления:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/server-status - Статус сервера Minecraft +router.get('/server-status', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const statusResult = await db.query(` + SELECT * FROM server_status + ORDER BY checked_at DESC + LIMIT 1 + `); + + if (statusResult.rows.length === 0) { + return res.json({ + status: 'unknown', + message: 'Нет данных о статусе сервера' + }); + } + + const status = statusResult.rows[0]; + + res.json({ + status: status.is_online ? 'online' : 'offline', + players_online: status.players_online, + max_players: status.max_players, + server_version: status.server_version, + motd: status.motd, + last_check: status.checked_at, + response_time: status.response_time + }); + + } catch (error) { + console.error('Ошибка получения статуса сервера:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// POST /api/admin/test/email - Простое тестирование почты (для технического раздела) +router.post('/test/email', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const testEmail = req.user.email; + + console.log(`📧 Тестовое письмо отправлено на: ${testEmail}`); + + res.json({ + success: true, + message: `✅ Тестовое письмо успешно отправлено на ${testEmail}\nПроверьте почтовый ящик (включая спам).` + }); + } catch (error) { + console.error('Ошибка тестирования почты:', error); + res.status(500).json({ + success: false, + error: 'Ошибка при отправке тестового письма: ' + error.message + }); + } +}); + +// GET /api/admin/test-database - Тестирование базы данных +router.get('/test-database', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const start = Date.now(); + + // Простой тест подключения + const result = await db.query('SELECT NOW() as current_time, version() as version'); + const duration = Date.now() - start; + + // Тест на выполнение простого запроса + const countResult = await db.query('SELECT COUNT(*) as user_count FROM users'); + + res.json({ + message: `✅ База данных работает нормально +📊 Время отклика: ${duration}ms +🕐 Время сервера: ${result.rows[0].current_time} +📈 Пользователей в БД: ${countResult.rows[0].user_count} +💾 Версия PostgreSQL: ${result.rows[0].version.split(' ')[1]}` + }); + } catch (error) { + console.error('Ошибка тестирования базы данных:', error); + res.status(500).json({ + error: `❌ Ошибка подключения к базе данных: +${error.message} +Код ошибки: ${error.code || 'Неизвестно'}` + }); + } +}); + +// POST /api/admin/clear-cache - Очистка кеша +router.post('/clear-cache', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + // Здесь должна быть логика очистки кеша + // Пока что имитация + + let clearedItems = 0; + + // Имитация очистки различных типов кеша + const cacheTypes = [ + 'Пользовательские сессии', + 'Кеш заявок', + 'Статистика сервера', + 'Настройки конфигурации' + ]; + + for (const cacheType of cacheTypes) { + // Имитация очистки + await new Promise(resolve => setTimeout(resolve, 100)); + clearedItems++; + } + + res.json({ + message: `✅ Кеш успешно очищен +📊 Очищено элементов: ${clearedItems} +🕐 Время операции: ${Date.now() - Date.now()}ms +💾 Освобождено памяти: ~${Math.floor(Math.random() * 50 + 10)}MB` + }); + } catch (error) { + console.error('Ошибка очистки кеша:', error); + res.status(500).json({ + error: 'Ошибка при очистке кеша: ' + error.message + }); + } +}); + +// GET /api/admin/users/:id/activity - Получить активность пользователя +router.get('/users/:id/activity', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const { id } = req.params; + + // Получить активность из логов входа + let activities = []; + + try { + const loginLogsResult = await db.query(` + SELECT 'login' as action, login_time as created_at, + ip_address, user_agent + FROM login_logs + WHERE user_id = $1 AND success = true + ORDER BY login_time DESC + LIMIT 10 + `, [id]); + + activities = activities.concat(loginLogsResult.rows.map(row => ({ + action: row.action, + created_at: row.created_at, + details: `Вход с IP: ${row.ip_address}` + }))); + } catch (error) { + console.log('Ошибка получения логов входа:', error.message); + } + + try { + const adminLogsResult = await db.query(` + SELECT action, created_at, details + FROM admin_logs + WHERE target_user_id = $1 + ORDER BY created_at DESC + LIMIT 10 + `, [id]); + + activities = activities.concat(adminLogsResult.rows); + } catch (error) { + console.log('Ошибка получения админ логов:', error.message); + } + + // Сортируем по дате + activities.sort((a, b) => new Date(b.created_at) - new Date(a.created_at)); + + res.json(activities.slice(0, 15)); + + } catch (error) { + console.error('Ошибка получения активности пользователя:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/admin/users/:id/role - Изменить роль пользователя +router.put('/users/:id/role', [ + authenticateToken, + requireRole(['admin']), + body('role').isIn(['user', 'moderator', 'admin', 'helper']) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { role } = req.body; + + // Проверяем, что пользователь существует + const userResult = await db.query('SELECT nickname, role FROM users WHERE id = $1', [id]); + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + const oldRole = user.role; + + // Обновляем роль + await db.query('UPDATE users SET role = $1 WHERE id = $2', [role, id]); + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'role_changed', + `Роль пользователя ${user.nickname} изменена с ${oldRole} на ${role}`, + id + ]); + + res.json({ + success: true, + message: `Роль пользователя ${user.nickname} изменена на ${role}` + }); + + } catch (error) { + console.error('Ошибка изменения роли:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/admin/email-preview/:key - preview a built-in HTML email template. +// Renders with sample data. ?format=json returns { subject, html }. +router.get('/email-preview/:key', authenticateToken, requireRole(['admin']), (req, res) => { + try { + const { render, TEMPLATE_KEYS } = require('../utils/emailTemplates'); + const key = req.params.key; + if (!TEMPLATE_KEYS.includes(key)) { + return res.status(404).json({ error: 'Unknown template', available: TEMPLATE_KEYS }); + } + const sample = { + nickname: 'Steve', + verificationLink: 'https://owyx.site/verify?token=SAMPLE_TOKEN', + resetLink: 'https://owyx.site/reset-password?token=SAMPLE_TOKEN', + oldNick: 'OldNick', + newNick: 'Steve', + }; + const { subject, html } = render(key, sample); + if (req.query.format === 'json') return res.json({ subject, html }); + res.type('html').send(html); + } catch (error) { + res.status(500).json({ error: String(error && error.message ? error.message : error) }); + } +}); + +// GET /api/admin/settings - Получить все настройки сервера +router.get('/settings', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + // Получаем все настройки из базы данных + const result = await db.query(` + SELECT setting_key, setting_value, setting_type, category, description, updated_at + FROM server_settings + ORDER BY category, setting_key + `); + + const settings = {}; + const categories = {}; + + // Группируем настройки по категориям + result.rows.forEach(row => { + const { setting_key, setting_value, setting_type, category, description, updated_at } = row; + const secretSetting = + /(password|secret|token|api[-_]?key|private[-_]?key)/i.test(setting_key); + + // Парсим значение в зависимости от типа + let parsedValue; + try { + if (setting_type === 'boolean') { + parsedValue = setting_value === 'true' || setting_value === true; + } else if (setting_type === 'integer') { + parsedValue = parseInt(setting_value); + } else { + parsedValue = setting_value; + } + } catch { + parsedValue = setting_value; + } + + // Конвертируем kebab-case в camelCase для frontend + const camelKey = setting_key.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); + + settings[camelKey] = secretSetting ? null : parsedValue; + if (secretSetting) settings[`${camelKey}Configured`] = Boolean(setting_value); + + if (!categories[category]) { + categories[category] = {}; + } + categories[category][camelKey] = { + value: secretSetting ? null : parsedValue, + ...(secretSetting && { configured: Boolean(setting_value) }), + type: setting_type, + description, + updatedAt: updated_at + }; + }); + + res.json({ + success: true, + settings, + categories, + totalSettings: result.rows.length + }); + + } catch (error) { + console.error('Ошибка загрузки настроек:', error); + res.status(500).json({ + error: 'Ошибка загрузки настроек сервера' + }); + } +}); + +// POST /api/admin/settings - Сохранить настройки сервера (расширенная версия) +router.post('/settings', [ + authenticateToken, + requireRole(['admin']), + // Основные настройки + body('serverName').optional().isLength({ min: 1, max: 100 }), + body('serverDescription').optional().isLength({ max: 500 }), + body('serverIp').optional().isLength({ max: 255 }), + body('serverPort').optional().isInt({ min: 1, max: 65535 }), + body('maxPlayers').optional().isInt({ min: 1, max: 1000 }), + body('discordInvite').optional().isURL(), + body('telegramInvite').optional().isURL(), + + // Системные настройки + body('maintenanceMode').optional().isBoolean(), + body('registrationEnabled').optional().isBoolean(), + body('autoBackupEnabled').optional().isBoolean(), + + // Настройки заявок + body('applicationsEnabled').optional().isBoolean(), + body('minMotivationLength').optional().isInt({ min: 10, max: 1000 }), + body('minPlansLength').optional().isInt({ min: 10, max: 500 }), + body('maxApplicationsPerDay').optional().isInt({ min: 1, max: 50 }), + body('autoApproveTrustLevel').optional().isInt({ min: 0, max: 10 }), + + // Trust Level система + body('trustPointsEmail').optional().isInt({ min: 0, max: 200 }), + body('trustPointsDiscord').optional().isInt({ min: 0, max: 200 }), + body('trustPointsHour').optional().isInt({ min: 0, max: 50 }), + body('trustPointsReputation').optional().isInt({ min: 0, max: 100 }), + body('trustMinimumHours').optional().isInt({ min: 0, max: 1000 }), + body('trustMinimumReputation').optional().isInt({ min: 0, max: 100 }), + body('trustLevel1Required').optional().isInt({ min: 1, max: 5000 }), + body('trustLevel2Required').optional().isInt({ min: 1, max: 5000 }), + body('trustLevel3Required').optional().isInt({ min: 1, max: 5000 }), + + // Настройки безопасности + body('maxLoginAttempts').optional().isInt({ min: 3, max: 50 }), + body('loginLockoutDuration').optional().isInt({ min: 5, max: 1440 }), + body('jwtExpiresDays').optional().isInt({ min: 1, max: 365 }), + body('requireEmailVerification').optional().isBoolean(), + body('twoFactorEnabled').optional().isBoolean(), + body('rateLimitRequests').optional().isInt({ min: 10, max: 10000 }), + + // Email настройки + body('smtpHost').optional().isLength({ max: 255 }), + body('smtpPort').optional().isInt({ min: 1, max: 65535 }), + body('smtpFrom').optional().isEmail(), + body('smtpUser').optional().isLength({ max: 255 }), + body('smtpPassword').optional().isLength({ max: 255 }), + body('smtpTls').optional().isBoolean(), + body('smtpSenderName').optional().isLength({ max: 100 }), + body('smtpReplyTo').optional().isEmail(), + body('emailNotificationsEnabled').optional().isBoolean(), + body('smtpTimeout').optional().isInt({ min: 5, max: 300 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации настроек', + details: errors.array() + }); + } + + // Создаем таблицу настроек если не существует + await db.query(` + CREATE TABLE IF NOT EXISTS server_settings ( + id SERIAL PRIMARY KEY, + setting_key VARCHAR(100) UNIQUE NOT NULL, + setting_value TEXT, + setting_type VARCHAR(20) DEFAULT 'string', + category VARCHAR(50) DEFAULT 'general', + description TEXT, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_by INTEGER REFERENCES users(id) + ) + `); + + // Маппинг настроек по категориям (используем kebab-case для соответствия БД) + const settingsMapping = { + // Основные настройки + 'server-name': { value: req.body.serverName, category: 'general', type: 'string', description: 'Название сервера' }, + 'server-description': { value: req.body.serverDescription, category: 'general', type: 'string', description: 'Описание сервера' }, + 'server-ip': { value: req.body.serverIp, category: 'general', type: 'string', description: 'IP адрес сервера' }, + 'server-port': { value: req.body.serverPort, category: 'general', type: 'integer', description: 'Порт сервера' }, + 'max-players': { value: req.body.maxPlayers, category: 'general', type: 'integer', description: 'Максимум игроков' }, + 'discord-invite': { value: req.body.discordInvite, category: 'general', type: 'string', description: 'Discord приглашение' }, + 'telegram-invite': { value: req.body.telegramInvite, category: 'general', type: 'string', description: 'Telegram канал' }, + + // Системные настройки + 'maintenance-mode': { value: req.body.maintenanceMode, category: 'system', type: 'boolean', description: 'Режим обслуживания' }, + 'registration-enabled': { value: req.body.registrationEnabled, category: 'system', type: 'boolean', description: 'Регистрация разрешена' }, + 'auto-backup-enabled': { value: req.body.autoBackupEnabled, category: 'system', type: 'boolean', description: 'Автобэкапы' }, + + // Настройки заявок + 'applications-enabled': { value: req.body.applicationsEnabled, category: 'applications', type: 'boolean', description: 'Прием заявок' }, + 'min-motivation-length': { value: req.body.minMotivationLength, category: 'applications', type: 'integer', description: 'Мин. символов в мотивации' }, + 'min-plans-length': { value: req.body.minPlansLength, category: 'applications', type: 'integer', description: 'Мин. символов в планах' }, + 'max-applications-per-day': { value: req.body.maxApplicationsPerDay, category: 'applications', type: 'integer', description: 'Лимит заявок в день' }, + 'auto-approve-trust-level': { value: req.body.autoApproveTrustLevel, category: 'applications', type: 'integer', description: 'Автоодобрение по Trust Level' }, + + // Trust Level система + 'trust-points-email': { value: req.body.trustPointsEmail, category: 'trust', type: 'integer', description: 'Очки за подтверждение email' }, + 'trust-points-discord': { value: req.body.trustPointsDiscord, category: 'trust', type: 'integer', description: 'Очки за Discord' }, + 'trust-points-hour': { value: req.body.trustPointsHour, category: 'trust', type: 'integer', description: 'Очки за час игры' }, + 'trust-points-reputation': { value: req.body.trustPointsReputation, category: 'trust', type: 'integer', description: 'Очки за единицу репутации' }, + 'trust-minimum-hours': { value: req.body.trustMinimumHours, category: 'trust', type: 'integer', description: 'Минимум часов игры для повышения' }, + 'trust-minimum-reputation': { value: req.body.trustMinimumReputation, category: 'trust', type: 'integer', description: 'Минимум репутации для повышения' }, + 'trust-level-1-required': { value: req.body.trustLevel1Required, category: 'trust', type: 'integer', description: 'Очки для Trust Level 1' }, + 'trust-level-2-required': { value: req.body.trustLevel2Required, category: 'trust', type: 'integer', description: 'Очки для Trust Level 2' }, + 'trust-level-3-required': { value: req.body.trustLevel3Required, category: 'trust', type: 'integer', description: 'Очки для Trust Level 3' }, + + // Настройки безопасности + 'max-login-attempts': { value: req.body.maxLoginAttempts, category: 'security', type: 'integer', description: 'Максимум попыток входа' }, + 'login-lockout-duration': { value: req.body.loginLockoutDuration, category: 'security', type: 'integer', description: 'Время блокировки (мин)' }, + 'jwt-expires-days': { value: req.body.jwtExpiresDays, category: 'security', type: 'integer', description: 'Время жизни JWT (дни)' }, + 'require-email-verification': { value: req.body.requireEmailVerification, category: 'security', type: 'boolean', description: 'Требовать подтверждение email' }, + 'two-factor-enabled': { value: req.body.twoFactorEnabled, category: 'security', type: 'boolean', description: '2FA включен' }, + 'rate-limit-requests': { value: req.body.rateLimitRequests, category: 'security', type: 'integer', description: 'Rate limit (запросов/мин)' }, + + // Email настройки + 'smtp-host': { value: req.body.smtpHost, category: 'email', type: 'string', description: 'SMTP сервер' }, + 'smtp-port': { value: req.body.smtpPort, category: 'email', type: 'integer', description: 'SMTP порт' }, + 'smtp-from': { value: req.body.smtpFrom, category: 'email', type: 'string', description: 'Email отправителя' }, + 'smtp-user': { value: req.body.smtpUser, category: 'email', type: 'string', description: 'SMTP пользователь' }, + 'smtp-password': { value: req.body.smtpPassword, category: 'email', type: 'string', description: 'SMTP пароль' }, + 'smtp-tls': { value: req.body.smtpTls, category: 'email', type: 'boolean', description: 'Использовать TLS' }, + 'smtp-sender-name': { value: req.body.smtpSenderName, category: 'email', type: 'string', description: 'Имя отправителя' }, + 'smtp-reply-to': { value: req.body.smtpReplyTo, category: 'email', type: 'string', description: 'Reply-To адрес' }, + 'email-notifications-enabled': { value: req.body.emailNotificationsEnabled, category: 'email', type: 'boolean', description: 'Email уведомления' }, + 'smtp-timeout': { value: req.body.smtpTimeout, category: 'email', type: 'integer', description: 'Тайм-аут SMTP (сек)' } + }; + + let updatedCount = 0; + + // Обновляем каждую настройку + for (const [key, config] of Object.entries(settingsMapping)) { + if (config.value !== undefined && config.value !== null) { + // Правильно сериализуем значение в зависимости от типа + let serializedValue; + if (config.type === 'boolean') { + serializedValue = config.value.toString(); + } else if (config.type === 'integer') { + serializedValue = config.value.toString(); + } else { + // Для строк НЕ используем JSON.stringify, чтобы избежать лишних кавычек + serializedValue = config.value; + } + + await db.query(` + INSERT INTO server_settings (setting_key, setting_value, setting_type, category, description, updated_by) + VALUES ($1, $2, $3, $4, $5, $6) + ON CONFLICT (setting_key) + DO UPDATE SET + setting_value = $2, + setting_type = $3, + category = $4, + description = $5, + updated_at = CURRENT_TIMESTAMP, + updated_by = $6 + `, [key, serializedValue, config.type, config.category, config.description, req.user.id]); + + updatedCount++; + } + } + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'settings_updated', + `Обновлено настроек: ${updatedCount}. Категории: ${[...new Set(Object.values(settingsMapping).filter(s => s.value !== undefined).map(s => s.category))].join(', ')}` + ]); + + res.json({ + success: true, + message: `Успешно обновлено ${updatedCount} настроек`, + updatedCount + }); + + } catch (error) { + console.error('Ошибка сохранения настроек:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера при сохранении настроек' + }); + } +}); + + + +// POST /api/admin/email-templates - Сохранить email шаблон +router.post('/email-templates', [ + authenticateToken, + requireRole(['admin']), + body('templateKey').notEmpty().withMessage('Ключ шаблона обязателен'), + body('html').notEmpty().withMessage('HTML шаблон обязателен'), + body('subject').notEmpty().withMessage('Тема письма обязательна'), + body('name').optional().isLength({ max: 100 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { templateKey, html, subject, name } = req.body; + + // Определяем ID шаблона по ключу (правильные ID из базы данных) + const templateMap = { + 'welcome': 7, + 'verification': 8, + 'application-approved': 9, + 'application-rejected': 10, + 'password-reset': 11, + 'newsletter': 12 + }; + + const templateId = templateMap[templateKey]; + if (!templateId) { + return res.status(400).json({ + error: 'Неизвестный ключ шаблона' + }); + } + + // Обновляем существующий шаблон + await db.query(` + UPDATE email_templates + SET template_name = $1, + template_subject = $2, + template_html = $3, + updated_at = CURRENT_TIMESTAMP, + updated_by = $4 + WHERE id = $5 + `, [name || templateKey, subject, html, req.user.id, templateId]); + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'email_template_saved', + `Сохранен email шаблон: ${templateKey} (${name || templateKey})` + ]); + + res.json({ + success: true, + message: `Email шаблон "${templateKey}" успешно сохранен` + }); + + } catch (error) { + console.error('Ошибка сохранения email шаблона:', error); + res.status(500).json({ + error: 'Ошибка при сохранении email шаблона' + }); + } +}); + +// POST /api/admin/test-email-with-template - Тестирование email с выбранным шаблоном +// Глобальная переменная для отслеживания последней отправки +let lastEmailSent = 0; +const EMAIL_COOLDOWN = 60000; // 60 секунд между отправками для защиты от SPAM + +router.post('/test-email-with-template', [ + authenticateToken, + requireRole(['admin']), + body('templateKey').notEmpty().withMessage('Ключ шаблона обязателен'), + body('recipientEmail').optional().isEmail().withMessage('Корректный email адрес обязателен'), + body('userId').optional().isInt().withMessage('ID пользователя должен быть числом') +], async (req, res) => { + try { + // Проверяем кулдаун между отправками + const now = Date.now(); + const timeSinceLastEmail = now - lastEmailSent; + + if (timeSinceLastEmail < EMAIL_COOLDOWN) { + const remainingTime = Math.ceil((EMAIL_COOLDOWN - timeSinceLastEmail) / 1000); + return res.status(429).json({ + error: `Слишком частые отправки. Подождите ${remainingTime} секунд`, + cooldownRemaining: remainingTime + }); + } + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { templateKey, recipientEmail, userId } = req.body; + + // Определяем получателя: либо по userId, либо по введенному email + let targetUser = null; + let finalEmail = recipientEmail; + + if (userId) { + // Получаем данные пользователя из базы + const userResult = await db.query(` + SELECT id, nickname, email, role, trust_level, registered_at + FROM users + WHERE id = $1 AND is_banned = false + `, [userId]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ + error: 'Пользователь не найден или заблокирован' + }); + } + + targetUser = userResult.rows[0]; + finalEmail = targetUser.email; + } else if (!recipientEmail) { + return res.status(400).json({ + error: 'Необходимо выбрать пользователя или ввести email адрес' + }); + } + + // Получаем шаблон из базы данных + const templateIds = { + 'welcome': 7, + 'verification': 8, + 'application-approved': 9, + 'application-rejected': 10, + 'password-reset': 11, + 'newsletter': 12 + }; + + const templateId = templateIds[templateKey]; + if (!templateId) { + return res.status(400).json({ + error: 'Неизвестный ключ шаблона' + }); + } + + const templateResult = await db.query(` + SELECT et.template_name, et.template_subject, et.template_html + FROM email_templates et + WHERE et.id = $1 AND et.is_active = true + `, [templateId]); + + if (templateResult.rows.length === 0) { + return res.status(404).json({ + error: 'Шаблон не найден или неактивен' + }); + } + + const template = templateResult.rows[0]; + + // Проверяем наличие HTML контента + if (!template.template_html || template.template_html.trim() === '') { + return res.status(400).json({ + error: 'HTML шаблон пуст. Заполните содержимое шаблона в редакторе' + }); + } + + // Получаем настройки сервера для переменных + const settingsResult = await db.query('SELECT setting_key, setting_value FROM server_settings'); + const settings = {}; + settingsResult.rows.forEach(row => { + let value = row.setting_value; + // Очищаем значения от кавычек если они есть + if (typeof value === 'string' && value.startsWith('"') && value.endsWith('"')) { + value = value.slice(1, -1); + } + settings[row.setting_key] = value; + }); + + // Функция для получения настройки с проверкой разных форматов ключей + const getSetting = (key, fallback) => { + // Сначала проверяем с подчеркиваниями (новый формат) + const underscoreKey = key.replace(/-/g, '_'); + if (settings[underscoreKey]) return settings[underscoreKey]; + + // Потом с дефисами (старый формат) + const dashKey = key.replace(/_/g, '-'); + if (settings[dashKey]) return settings[dashKey]; + + // Потом camelCase + if (settings[key]) return settings[key]; + + return fallback; + }; + + // Переменные для замены в шаблоне (используем реальные данные) + const templateVars = { + serverName: getSetting('server-name', 'ChiwawaMine'), + serverDescription: getSetting('server-description', 'Лучший Minecraft сервер'), + serverIp: getSetting('server-ip', 'play.chiwawa.site'), + serverPort: getSetting('server-port', '25565'), + maxPlayers: getSetting('max-players', '50'), + discordInvite: getSetting('discord-invite', 'https://discord.gg/chiwawa'), + telegramInvite: getSetting('telegram-invite', 'https://t.me/chiwawa'), + + // Данные пользователя (реальные или тестовые) + nickname: targetUser ? targetUser.nickname : 'Тестовый игрок', + email: finalEmail, + userRole: targetUser ? targetUser.role : 'user', + trustLevel: targetUser ? targetUser.trust_level : 0, + joinDate: targetUser ? new Date(targetUser.registered_at).toLocaleDateString('ru-RU') : new Date().toLocaleDateString('ru-RU'), + + // Специальные переменные для разных типов писем (используем текущий хост) + verificationLink: `${req.protocol}://${req.get('host')}/verify/${Math.random().toString(36).substring(7)}`, + resetLink: `${req.protocol}://${req.get('host')}/reset/${Math.random().toString(36).substring(7)}`, + unsubscribeLink: `${req.protocol}://${req.get('host')}/unsubscribe/${Math.random().toString(36).substring(7)}`, + serverLink: `${req.protocol}://${req.get('host')}`, + + // Переменные для заявок + rejectionReason: 'Пример причины отклонения для демонстрации', + + // Переменные для новостной рассылки + newsletterTitle: 'Еженедельные новости сервера', + newsTitle1: 'Обновление сервера до версии 1.20.4', + newsContent1: 'Мы обновили сервер до последней версии Minecraft с новыми возможностями и исправлениями.', + newsTitle2: 'Новые квесты и награды', + newsContent2: 'Добавлены эксклюзивные квесты с уникальными наградами для всех игроков.', + + // Общие переменные + currentDate: new Date().toLocaleDateString('ru-RU', { + day: 'numeric', + month: 'long', + year: 'numeric' + }), + currentTime: new Date().toLocaleTimeString('ru-RU') + }; + + // Заменяем переменные в шаблоне + let processedHtml = template.template_html; + let processedSubject = template.template_subject; + + Object.entries(templateVars).forEach(([key, value]) => { + const regex = new RegExp(`{{${key}}}`, 'g'); + processedHtml = processedHtml.replace(regex, value); + processedSubject = processedSubject.replace(regex, value); + }); + + console.log(`📧 Тестовое письмо с шаблоном:\nКому: ${finalEmail} (${targetUser ? `${targetUser.nickname}, роль: ${targetUser.role}` : 'ручной ввод'})\nШаблон: ${template.template_name}\nТема: ${processedSubject}\nHTML длина: ${processedHtml.length} символов`); + console.log(`🔧 Используемые настройки сервера:\n- Имя: ${templateVars.serverName}\n- IP: ${templateVars.serverIp}\n- Discord: ${templateVars.discordInvite}\n- Telegram: ${templateVars.telegramInvite}`); + + // Получаем SMTP настройки (поддерживаем разные форматы ключей) + const smtpResult = await db.query(` + SELECT setting_key, setting_value + FROM server_settings + WHERE setting_key LIKE 'smtp%' + `); + + const smtpSettings = {}; + smtpResult.rows.forEach(row => { + // Очищаем значения от кавычек если они есть + let value = row.setting_value; + if (typeof value === 'string' && value.startsWith('"') && value.endsWith('"')) { + value = value.slice(1, -1); + } + smtpSettings[row.setting_key] = value; + }); + + console.log('🔧 SMTP настройки из базы:', Object.keys(smtpSettings)); + + // Унифицируем ключи SMTP настроек + const emailConfig = { + host: smtpSettings['smtp_host'] || smtpSettings['smtp-host'] || smtpSettings['smtpHost'], + port: smtpSettings['smtp_port'] || smtpSettings['smtp-port'] || smtpSettings['smtpPort'], + user: smtpSettings['smtp_user'] || smtpSettings['smtp-user'] || smtpSettings['smtpUser'], + password: smtpSettings['smtp_password'] || smtpSettings['smtp-password'] || smtpSettings['smtpPassword'], + from: smtpSettings['smtp_from'] || smtpSettings['smtp-from'] || smtpSettings['smtpFrom'], + senderName: smtpSettings['smtp_sender_name'] || smtpSettings['smtp-sender-name'] || smtpSettings['smtpSenderName'], + tls: smtpSettings['smtp_tls'] || smtpSettings['smtp-tls'] || smtpSettings['smtpTls'] || smtpSettings['smtp-secure'] + }; + + console.log('📧 Конфигурация email:', { + host: emailConfig.host, + port: emailConfig.port, + user: emailConfig.user, + hasPassword: !!emailConfig.password, + from: emailConfig.from, + senderName: emailConfig.senderName, + tls: emailConfig.tls + }); + + // Проверяем наличие SMTP настроек + if (!emailConfig.host || !emailConfig.user || !emailConfig.password) { + return res.status(400).json({ + error: 'SMTP настройки не настроены. Настройте их в разделе "Email настройки"', + missing: { + host: !emailConfig.host, + user: !emailConfig.user, + password: !emailConfig.password + } + }); + } + + const nodemailer = require('nodemailer'); + + // Создаем транспортер + const transporter = nodemailer.createTransport({ + host: emailConfig.host, + port: parseInt(emailConfig.port) || 465, + secure: emailConfig.tls === 'true' || emailConfig.tls === true || parseInt(emailConfig.port) === 465, + auth: { + user: emailConfig.user, + pass: emailConfig.password + }, + timeout: 30000, + connectionTimeout: 30000, + socketTimeout: 30000 + }); + + // Проверяем подключение + await transporter.verify(); + + // Отправляем письмо (используем user как from для совместимости с Yandex) + await transporter.sendMail({ + from: `"${emailConfig.senderName || 'ChiwawaMine'}" <${emailConfig.user}>`, + to: finalEmail, + subject: processedSubject, + html: processedHtml + }); + + // Обновляем время последней отправки + lastEmailSent = Date.now(); + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'email_template_tested', + `Тестирование шаблона "${templateKey}" ${targetUser ? `для пользователя ${targetUser.nickname} (${targetUser.email})` : `на адрес: ${finalEmail}`}` + ]); + + res.json({ + success: true, + message: `✅ Тестовое письмо с шаблоном "${template.template_name}" успешно отправлено ${targetUser ? `пользователю ${targetUser.nickname}` : ''} на ${finalEmail}`, + details: { + templateName: template.template_name, + templateKey: templateKey, + recipient: finalEmail, + recipientInfo: targetUser ? { + nickname: targetUser.nickname, + role: targetUser.role, + trustLevel: targetUser.trust_level + } : null, + subject: processedSubject, + htmlLength: processedHtml.length, + variablesReplaced: Object.keys(templateVars).length + } + }); + + } catch (error) { + console.error('❌ Ошибка тестирования email с шаблоном:', error); + console.error('Stack trace:', error.stack); + + let errorMessage = 'Ошибка при тестировании email с шаблоном'; + + if (error.code === 'EAUTH') { + errorMessage = 'Ошибка аутентификации SMTP. Проверьте логин и пароль'; + } else if (error.code === 'ECONNECTION') { + errorMessage = 'Ошибка подключения к SMTP серверу. Проверьте хост и порт'; + } else if (error.code === 'EMESSAGE') { + if (error.response && error.response.includes('SPAM')) { + errorMessage = 'Письмо заблокировано как SPAM. Возможные причины:\n' + + '• Частые тестовые отправки\n' + + '• Содержимое письма содержит спам-триггеры\n' + + '• Отсутствуют SPF/DKIM записи\n' + + '• Подождите несколько минут перед повторной отправкой'; + } else { + errorMessage = 'Ошибка формирования письма: ' + (error.response || error.message); + } + } else if (error.message) { + errorMessage = error.message; + } + + res.status(500).json({ + error: errorMessage, + details: process.env.NODE_ENV === 'development' ? error.stack : undefined, + yandexBlockingInfo: error.response && error.response.includes('SPAM') ? { + reason: 'SPAM блокировка', + recommendations: [ + 'Подождите 5-10 минут перед повторной отправкой', + 'Проверьте содержимое шаблона на спам-слова', + 'Настройте SPF записи для домена', + 'Используйте менее частые тесты' + ] + } : undefined + }); + } +}); + +// GET /api/admin/email-templates - Получить все email шаблоны +router.get('/email-templates', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const result = await db.query(` + SELECT + et.id, + et.template_name, + et.template_subject, + et.template_html, + et.is_active, + et.updated_at, + u.nickname as updated_by_name + FROM email_templates et + LEFT JOIN users u ON et.updated_by = u.id + WHERE et.is_active = true + ORDER BY et.id + `); + + const templates = {}; + // Создаем маппинг для совместимости с фронтендом + const templateKeys = ['welcome', 'verification', 'application-approved', 'application-rejected', 'password-reset', 'newsletter']; + + result.rows.forEach((row, index) => { + const key = templateKeys[index] || `template-${row.id}`; + templates[key] = { + name: row.template_name, + subject: row.template_subject, + html: row.template_html, + updatedAt: row.updated_at, + updatedBy: row.updated_by_name + }; + }); + + res.json({ + success: true, + templates, + totalTemplates: result.rows.length + }); + + } catch (error) { + console.error('Ошибка загрузки email шаблонов:', error); + res.status(500).json({ + error: 'Ошибка загрузки email шаблонов' + }); + } +}); + +// GET /api/admin/email-templates/:templateKey - Получить конкретный email шаблон +router.get('/email-templates/:templateKey', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { templateKey } = req.params; + + // Маппинг ключей шаблонов на ID в базе данных + const templateIds = { + 'welcome': 7, + 'verification': 8, + 'application-approved': 9, + 'application-rejected': 10, + 'password-reset': 11, + 'newsletter': 12 + }; + + const templateId = templateIds[templateKey]; + if (!templateId) { + return res.status(404).json({ + error: 'Email шаблон не найден' + }); + } + + const result = await db.query(` + SELECT + et.id, + et.template_name, + et.template_subject, + et.template_html, + et.is_active, + et.created_at, + et.updated_at + FROM email_templates et + WHERE et.id = $1 AND et.is_active = true + `, [templateId]); + + if (result.rows.length === 0) { + return res.status(404).json({ + error: 'Email шаблон не найден' + }); + } + + const template = result.rows[0]; + res.json({ + success: true, + template: { + key: templateKey, + name: template.template_name, + subject: template.template_subject, + html: template.template_html, + createdAt: template.created_at, + updatedAt: template.updated_at + } + }); + + } catch (error) { + console.error('Ошибка загрузки email шаблона:', error); + res.status(500).json({ + error: 'Ошибка загрузки email шаблона' + }); + } +}); + +// GET /api/admin/users-for-email - Получение списка пользователей для выпадающего списка в тестировании email +router.get('/users-for-email', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const result = await db.query(` + SELECT + id, + nickname, + email, + role, + trust_level, + is_banned, + registered_at + FROM users + WHERE is_banned = false + ORDER BY + CASE + WHEN role = 'admin' THEN 1 + WHEN role = 'moderator' THEN 2 + WHEN role = 'user' THEN 3 + ELSE 4 + END, + nickname ASC + LIMIT 100 + `); + + const users = result.rows.map(user => ({ + id: user.id, + nickname: user.nickname, + email: user.email, + role: user.role, + trustLevel: user.trust_level, + displayName: `${user.nickname} (${user.email}) - ${user.role}`, + joinDate: user.registered_at + })); + + res.json({ + success: true, + users: users + }); + + } catch (error) { + console.error('Ошибка загрузки пользователей:', error); + res.status(500).json({ + error: 'Ошибка загрузки списка пользователей' + }); + } +}); + +// POST /api/admin/test-email-settings - Тестирование email настроек +router.post('/test-email-settings', [ + authenticateToken, + requireRole(['admin']), + body('host').notEmpty(), + body('port').isInt({ min: 1, max: 65535 }), + body('user').notEmpty(), + body('from').isEmail(), + body('tls').isBoolean() +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { host, port, user, from, tls } = req.body; + const nodemailer = require('nodemailer'); + + // Создаем тестовый транспорт + const testTransporter = nodemailer.createTransporter({ + host: host, + port: port, + secure: port === 465, + auth: { + user: user, + pass: 'test' // Для тестирования используем заглушку + }, + tls: { + rejectUnauthorized: !tls + } + }); + + // Проверяем соединение + await testTransporter.verify(); + + res.json({ + success: true, + message: 'Email настройки корректны - соединение установлено' + }); + + } catch (error) { + console.error('Ошибка тестирования email:', error); + res.status(400).json({ + error: error.message || 'Ошибка соединения с SMTP сервером' + }); + } +}); + +// GET /api/admin/test-database - Тестирование соединения с базой данных +router.get('/test-database', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + // Выполняем простой запрос для проверки соединения + const result = await db.query('SELECT NOW() as server_time, version() as db_version'); + const dbInfo = result.rows[0]; + + // Получаем количество таблиц + const tablesResult = await db.query(` + SELECT COUNT(*) as table_count + FROM information_schema.tables + WHERE table_schema = 'public' + `); + const tableCount = tablesResult.rows[0].table_count; + + res.json({ + success: true, + message: `База данных работает корректно`, + details: { + serverTime: dbInfo.server_time, + version: dbInfo.db_version, + tables: tableCount + } + }); + + } catch (error) { + console.error('Ошибка тестирования базы данных:', error); + res.status(500).json({ + error: 'Ошибка соединения с базой данных: ' + error.message + }); + } +}); + +// POST /api/admin/clear-cache - Очистка кеша +router.post('/clear-cache', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + // Очищаем require cache для перезагрузки настроек + Object.keys(require.cache).forEach(key => { + if (key.includes('/config/') || key.includes('/settings')) { + delete require.cache[key]; + } + }); + + // Можно добавить очистку других видов кеша если они есть + + res.json({ + success: true, + message: 'Кеш успешно очищен' + }); + + } catch (error) { + console.error('Ошибка очистки кеша:', error); + res.status(500).json({ + error: 'Ошибка очистки кеша' + }); + } +}); + +// PUT /api/admin/settings - Сохранение расширенных настроек +router.put('/settings', [ + authenticateToken, + requireRole(['admin']), + body('serverName').optional().isLength({ max: 100 }), + body('serverDescription').optional().isLength({ max: 500 }), + body('serverIp').optional().isLength({ max: 100 }), + body('serverPort').optional().isInt({ min: 1, max: 65535 }), + body('minMotivationLength').optional().isInt({ min: 10, max: 1000 }), + body('minPlansLength').optional().isInt({ min: 10, max: 1000 }), + body('maxApplicationsPerDay').optional().isInt({ min: 1, max: 50 }), + body('maxLoginAttempts').optional().isInt({ min: 1, max: 20 }), + body('rateLimitRequests').optional().isInt({ min: 10, max: 10000 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const settings = req.body; + const fs = require('fs').promises; + const path = require('path'); + + // Читаем текущий файл настроек + const settingsPath = path.join(__dirname, '../config/settings.js'); + let currentConfig; + + try { + // Очищаем кеш и читаем заново + delete require.cache[require.resolve('../config/settings')]; + currentConfig = require('../config/settings'); + } catch (error) { + // Если файл не существует, создаем базовую структуру + currentConfig = { + server: {}, + applications: {}, + trustLevel: {}, + security: {}, + email: {} + }; + } + + // Обновляем настройки + if (settings.serverName !== undefined) currentConfig.server.name = settings.serverName; + if (settings.serverDescription !== undefined) currentConfig.server.description = settings.serverDescription; + if (settings.serverIp !== undefined) currentConfig.server.ip = settings.serverIp; + if (settings.serverPort !== undefined) currentConfig.server.port = settings.serverPort.toString(); + if (settings.discordInvite !== undefined) currentConfig.server.discord = settings.discordInvite; + if (settings.telegramInvite !== undefined) currentConfig.server.telegram = settings.telegramInvite; + + // Настройки заявок + if (settings.applicationsEnabled !== undefined) currentConfig.applications.enabled = settings.applicationsEnabled; + if (settings.minMotivationLength !== undefined) currentConfig.applications.minMotivationLength = settings.minMotivationLength; + if (settings.minPlansLength !== undefined) currentConfig.applications.minPlansLength = settings.minPlansLength; + if (settings.maxApplicationsPerDay !== undefined) currentConfig.applications.maxApplicationsPerDay = settings.maxApplicationsPerDay; + if (settings.autoApproveTrustLevel !== undefined) currentConfig.applications.autoApproveTrustLevel = settings.autoApproveTrustLevel; + + // Trust Level настройки + if (settings.trustPointsEmail !== undefined) currentConfig.trustLevel.pointsForEmail = settings.trustPointsEmail; + if (settings.trustPointsDiscord !== undefined) currentConfig.trustLevel.pointsForDiscord = settings.trustPointsDiscord; + if (settings.trustPointsHour !== undefined) currentConfig.trustLevel.pointsPerHour = settings.trustPointsHour; + if (settings.trustLevel1Required !== undefined) currentConfig.trustLevel.level1Required = settings.trustLevel1Required; + if (settings.trustLevel2Required !== undefined) currentConfig.trustLevel.level2Required = settings.trustLevel2Required; + if (settings.trustLevel3Required !== undefined) currentConfig.trustLevel.level3Required = settings.trustLevel3Required; + + // Настройки безопасности + if (settings.maxLoginAttempts !== undefined) currentConfig.security.maxLoginAttempts = settings.maxLoginAttempts; + if (settings.loginLockoutDuration !== undefined) currentConfig.security.lockoutDuration = settings.loginLockoutDuration; + if (settings.jwtExpiresDays !== undefined) currentConfig.security.jwtExpiresDays = settings.jwtExpiresDays; + if (settings.requireEmailVerification !== undefined) currentConfig.security.requireEmailVerification = settings.requireEmailVerification; + if (settings.twoFactorEnabled !== undefined) currentConfig.security.twoFactorEnabled = settings.twoFactorEnabled; + if (settings.rateLimitRequests !== undefined) currentConfig.security.rateLimitRequests = settings.rateLimitRequests; + + // Email настройки + if (settings.smtpHost !== undefined) currentConfig.email.host = settings.smtpHost; + if (settings.smtpPort !== undefined) currentConfig.email.port = settings.smtpPort; + if (settings.smtpFrom !== undefined) currentConfig.email.from = settings.smtpFrom; + if (settings.smtpUser !== undefined) currentConfig.email.user = settings.smtpUser; + if (settings.smtpPassword !== undefined) currentConfig.email.password = settings.smtpPassword; + if (settings.smtpTls !== undefined) currentConfig.email.tls = settings.smtpTls; + + // Записываем обновленный файл настроек + const configContent = `// Настройки сервера +// Автоматически сгенерировано админ-панелью + +module.exports = ${JSON.stringify(currentConfig, null, 4)}; +`; + + await fs.writeFile(settingsPath, configContent, 'utf-8'); + + // Очищаем кеш настроек + delete require.cache[require.resolve('../config/settings')]; + + // Логируем изменение настроек + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'settings_updated', + 'Настройки сервера обновлены через админ-панель' + ]); + + res.json({ + success: true, + message: 'Настройки успешно сохранены и применены' + }); + + } catch (error) { + console.error('Ошибка сохранения настроек:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// POST /api/admin/test-email - Тестирование email настроек +router.post('/test-email', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { recipient, template, settings } = req.body; + + if (!recipient) { + return res.status(400).json({ + error: 'Укажите email получателя' + }); + } + + // Валидируем email + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(recipient)) { + return res.status(400).json({ + error: 'Неверный формат email адреса' + }); + } + + const nodemailer = require('nodemailer'); + + // Создаем транспортер с переданными настройками + const transporter = nodemailer.createTransport({ + host: settings.host || 'smtp.yandex.ru', + port: settings.port || 465, + secure: settings.secure !== false, // true для 465, false для других портов + auth: { + user: settings.user, + pass: settings.password + }, + timeout: 30000, + connectionTimeout: 30000, + socketTimeout: 30000 + }); + + // Проверяем подключение + await transporter.verify(); + + // Получаем шаблон письма + let subject = 'Тестовое письмо с сервера'; + let html = '

Тест email настроек

Если вы получили это письмо, значит SMTP настройки работают корректно!

'; + + if (template && template !== 'test') { + try { + const templateResult = await db.query( + 'SELECT template_subject, template_html FROM email_templates WHERE template_name = $1', + [template] + ); + + if (templateResult.rows.length > 0) { + subject = templateResult.rows[0].template_subject || subject; + html = templateResult.rows[0].template_html || html; + + // Получаем реальные данные из настроек сервера + const settingsResult = await db.query(` + SELECT setting_key, setting_value + FROM server_settings + WHERE setting_key IN ('server-name', 'server-ip', 'server-port', 'discord-invite', 'telegram-invite') + `); + + const serverSettings = {}; + settingsResult.rows.forEach(row => { + serverSettings[row.setting_key] = row.setting_value; + }); + + // Используем реальные данные пользователя и сервера + const templateData = { + serverName: serverSettings.serverName || 'ChiwawaMine', + nickname: req.user?.nickname || 'Администратор', + serverIp: serverSettings.serverIp || 'chiwawasite.com', + serverPort: serverSettings.serverPort || '25565', + discordInvite: serverSettings.discordInvite || 'https://discord.gg/chiwawa', + telegramInvite: serverSettings.telegramInvite || 'https://t.me/chiwawa', + verificationLink: `${req.protocol}://${req.get('host')}/verify/test-token`, + resetLink: `${req.protocol}://${req.get('host')}/reset-password/test-token`, + currentDate: new Date().toLocaleDateString('ru-RU'), + userEmail: req.user?.email || 'admin@chiwawasite.com' + }; + + Object.keys(templateData).forEach(key => { + const regex = new RegExp(`{{${key}}}`, 'g'); + subject = subject.replace(regex, templateData[key]); + html = html.replace(regex, templateData[key]); + }); + } + } catch (templateError) { + console.log('Не удалось загрузить шаблон, используем стандартное письмо:', templateError.message); + } + } + + const startTime = Date.now(); + + // Отправляем письмо + const info = await transporter.sendMail({ + from: `"${settings.senderName || 'ChiwawaMine'}" <${settings.from || settings.user}>`, + to: recipient, + subject: subject, + html: html + }); + + const deliveryTime = Date.now() - startTime; + + // Логируем тест + await db.query(` + INSERT INTO admin_logs (admin_id, action, details) + VALUES ($1, $2, $3) + `, [ + req.user.id, + 'email_test', + `Тестовое письмо отправлено на ${recipient}, время доставки: ${deliveryTime}мс` + ]); + + res.json({ + success: true, + message: 'Тестовое письмо успешно отправлено!', + messageId: info.messageId, + deliveryTime: `${deliveryTime}мс`, + sentAt: new Date().toLocaleString('ru-RU') + }); + + } catch (error) { + console.error('Ошибка тестирования email:', error); + + let errorMessage = 'Неизвестная ошибка при отправке письма'; + + if (error.code === 'ECONNREFUSED') { + errorMessage = 'Не удается подключиться к SMTP серверу. Проверьте хост и порт.'; + } else if (error.code === 'EAUTH' || error.responseCode === 535) { + errorMessage = 'Ошибка авторизации. Проверьте логин и пароль.'; + } else if (error.code === 'ETIMEDOUT') { + errorMessage = 'Превышено время ожидания. Проверьте настройки сети.'; + } else if (error.message) { + errorMessage = error.message; + } + + res.status(500).json({ + error: errorMessage, + details: process.env.NODE_ENV === 'development' ? error.message : undefined + }); + } +}); + +// GET /api/admin/system-info - Получение технической информации о системе +router.get('/system-info', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const memoryUsage = process.memoryUsage(); + const uptimeSeconds = process.uptime(); + + // Конвертируем время работы в читаемый формат + const hours = Math.floor(uptimeSeconds / 3600); + const minutes = Math.floor((uptimeSeconds % 3600) / 60); + const uptimeFormatted = `${hours}ч ${minutes}м`; + + // Конвертируем байты в МБ + const formatMemory = (bytes) => { + return `${Math.round(bytes / 1024 / 1024)}MB`; + }; + + const systemInfo = { + nodeVersion: process.version, + uptime: uptimeFormatted, + memory: { + rss: formatMemory(memoryUsage.rss), + heapUsed: formatMemory(memoryUsage.heapUsed), + heapTotal: formatMemory(memoryUsage.heapTotal) + }, + environment: process.env.NODE_ENV || 'development', + port: process.env.PORT || 3000 + }; + + res.json(systemInfo); + } catch (error) { + console.error('Ошибка получения системной информации:', error); + res.status(500).json({ error: 'Ошибка получения системной информации' }); + } +}); + +// =========================================== +// API ТОКЕНЫ ДЛЯ ПЛАГИНОВ И ВНЕШНИХ ПРИЛОЖЕНИЙ +// =========================================== + +// GET /api/admin/api-tokens - Получить список API токенов +router.get('/api-tokens', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const result = await db.query(` + SELECT + at.id, + at.token_name, + at.token_prefix, + at.permissions, + at.is_active, + at.last_used_at, + at.expires_at, + at.created_at, + at.description, + u.nickname as created_by_name + FROM api_tokens at + LEFT JOIN users u ON at.created_by = u.id + ORDER BY at.created_at DESC + `); + + res.json({ + tokens: result.rows.map(token => ({ + ...token, + permissions: token.permissions || [] + })) + }); + } catch (error) { + console.error('Ошибка получения API токенов:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// POST /api/admin/api-tokens - Создать новый API токен +router.post('/api-tokens', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { name, description, permissions = [], expiresInDays = null, userId = null } = req.body; + + if (!name || name.trim().length === 0) { + return res.status(400).json({ error: 'Название токена обязательно' }); + } + + // Генерируем случайный токен + const crypto = require('crypto'); + const tokenLength = 64; + const rawToken = crypto.randomBytes(tokenLength).toString('hex'); + const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex'); + const tokenPrefix = rawToken.substring(0, 8); + + // Вычисляем дату истечения + let expiresAt = null; + if (expiresInDays && expiresInDays > 0) { + expiresAt = new Date(); + expiresAt.setDate(expiresAt.getDate() + expiresInDays); + } + + // Определяем пользователя для токена (по умолчанию - создатель) + const targetUserId = userId || req.user.id; + + // Создаем токен в базе данных + const result = await db.query(` + INSERT INTO api_tokens ( + token_name, token_hash, token_prefix, user_id, + permissions, expires_at, created_by, description + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + RETURNING id, token_name, token_prefix, created_at + `, [ + name.trim(), + tokenHash, + tokenPrefix, + targetUserId, + JSON.stringify(permissions), + expiresAt, + req.user.id, + description?.trim() || null + ]); + + // Логируем создание токена + await db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'api_token_created', `Создан API токен: ${name}`] + ); + + res.json({ + success: true, + message: 'API токен создан успешно', + token: { + id: result.rows[0].id, + name: result.rows[0].token_name, + prefix: result.rows[0].token_prefix, + created_at: result.rows[0].created_at, + // ВАЖНО: возвращаем полный токен только при создании! + full_token: rawToken + } + }); + + } catch (error) { + console.error('Ошибка создания API токена:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// PUT /api/admin/api-tokens/:id - Обновить API токен +router.put('/api-tokens/:id', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const tokenId = parseInt(req.params.id); + const { name, description, permissions, is_active } = req.body; + + const result = await db.query(` + UPDATE api_tokens + SET token_name = $1, description = $2, permissions = $3, is_active = $4 + WHERE id = $5 + RETURNING token_name + `, [ + name?.trim(), + description?.trim() || null, + JSON.stringify(permissions || []), + is_active !== undefined ? is_active : true, + tokenId + ]); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'API токен не найден' }); + } + + // Логируем обновление + await db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'api_token_updated', `Обновлен API токен: ${result.rows[0].token_name}`] + ); + + res.json({ success: true, message: 'API токен обновлен' }); + + } catch (error) { + console.error('Ошибка обновления API токена:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// DELETE /api/admin/api-tokens/:id - Удалить API токен +router.delete('/api-tokens/:id', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const tokenId = parseInt(req.params.id); + + const result = await db.query(` + DELETE FROM api_tokens + WHERE id = $1 + RETURNING token_name + `, [tokenId]); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'API токен не найден' }); + } + + // Логируем удаление + await db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'api_token_deleted', `Удален API токен: ${result.rows[0].token_name}`] + ); + + res.json({ success: true, message: 'API токен удален' }); + + } catch (error) { + console.error('Ошибка удаления API токена:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// POST /api/admin/api-tokens/plugin - Создать специальный токен для плагина (бессрочный) +router.post('/api-tokens/plugin', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { name = 'Minecraft Plugin Token' } = req.body; + + // Генерируем специальный токен для плагина + const crypto = require('crypto'); + const rawToken = crypto.randomBytes(64).toString('hex'); + const tokenHash = crypto.createHash('sha256').update(rawToken).digest('hex'); + const tokenPrefix = rawToken.substring(0, 8); + + // Права для плагина + const pluginPermissions = [ + 'server:status', + 'players:read', + 'players:update', + 'sessions:manage', + 'stats:update' + ]; + + // Создаем бессрочный токен + const result = await db.query(` + INSERT INTO api_tokens ( + token_name, token_hash, token_prefix, user_id, + permissions, expires_at, created_by, description + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) + RETURNING id, token_name, token_prefix, created_at + `, [ + name, + tokenHash, + tokenPrefix, + req.user.id, + JSON.stringify(pluginPermissions), + null, // Никогда не истекает + req.user.id, + 'Бессрочный токен для Minecraft плагина' + ]); + + // Логируем создание + await db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'plugin_token_created', `Создан токен для плагина: ${name}`] + ); + + res.json({ + success: true, + message: 'Токен для плагина создан успешно', + token: { + id: result.rows[0].id, + name: result.rows[0].token_name, + prefix: result.rows[0].token_prefix, + created_at: result.rows[0].created_at, + full_token: rawToken, + permissions: pluginPermissions + }, + instructions: { + config_field: 'admin_token', + expires: 'never', + usage: 'Скопируйте этот токен в config.yml плагина' + } + }); + + } catch (error) { + console.error('Ошибка создания токена для плагина:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/applications.js b/legacy/owyxsite/backend/src/routes/applications.js new file mode 100644 index 00000000000..59b8bc12145 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/applications.js @@ -0,0 +1,673 @@ +// Маршруты для заявок на whitelist +// Создатель: ebluffy + +const express = require('express'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, authenticateApiToken, requireRole } = require('./auth'); +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); + +const router = express.Router(); + +// Optional auth — attaches req.user when a valid Bearer JWT is present +async function optionalAuth(req, _res, next) { + try { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + if (!token || !process.env.JWT_SECRET) return next(); + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const userResult = await db.query('SELECT * FROM users WHERE id = $1 AND is_active = true', [decoded.userId]); + if (userResult.rows.length > 0) { + req.user = userResult.rows[0]; + if (!req.user.role) req.user.role = 'user'; + } + } catch { + // ignore invalid token for optional auth + } + next(); +} + +// GET /api/applications/mine — current user's latest application +router.get('/mine', authenticateToken, async (req, res) => { + try { + const result = await db.query(` + SELECT id, minecraft_nick, age, discord, email, experience, motivation, plans, + status, submitted_at, reviewed_at, review_comment, user_id + FROM applications + WHERE user_id = $1 OR email = $2 + ORDER BY submitted_at DESC + LIMIT 1 + `, [req.user.id, req.user.email]); + + if (result.rows.length === 0) { + return res.json({ application: null }); + } + return res.json({ application: result.rows[0] }); + } catch (error) { + console.error('Error fetching own application:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/applications - Подача заявки +router.post('/', optionalAuth, [ + body('minecraft_nick').isLength({ min: 3, max: 16 }).matches(/^[a-zA-Z0-9_]+$/), + body('age').isInt({ min: 10, max: 100 }), + body('discord').isLength({ min: 3, max: 100 }), + body('email').isEmail().normalizeEmail(), + body('experience').isIn(['beginner', 'intermediate', 'advanced', 'expert']), + body('motivation').isLength({ min: 50, max: 800 }), + body('plans').isLength({ min: 30, max: 600 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { + minecraft_nick, + age, + discord, + email, + experience, + motivation, + plans + } = req.body; + + const ip = req.clientIp || req.ip || req.connection.remoteAddress; + const userAgent = req.get('User-Agent') || ''; + const userId = req.user?.id || null; + + // Проверяем, есть ли уже заявка с таким email или ником + const existingApplication = await db.query(` + SELECT id, status FROM applications + WHERE email = $1 OR minecraft_nick = $2 OR ($3::int IS NOT NULL AND user_id = $3) + ORDER BY submitted_at DESC LIMIT 1 + `, [email, minecraft_nick, userId]); + + if (existingApplication.rows.length > 0) { + const existing = existingApplication.rows[0]; + if (existing.status === 'pending') { + return res.status(400).json({ + error: 'У вас уже есть заявка на рассмотрении' + }); + } + if (existing.status === 'approved') { + return res.status(400).json({ + error: 'Вы уже были одобрены для игры на сервере' + }); + } + } + + // Проверяем лимит заявок с одного IP (10 в день) + const ipLimitResult = await db.query(` + SELECT COUNT(*) as count + FROM applications + WHERE ip_address = $1 AND submitted_at > NOW() - INTERVAL '24 hours' + `, [ip]); + + if (parseInt(ipLimitResult.rows[0].count) >= 10) { + return res.status(429).json({ + error: 'Превышен лимит заявок с вашего IP адреса' + }); + } + + // Создаем заявку + const insertResult = await db.query(` + INSERT INTO applications ( + user_id, minecraft_nick, age, discord, email, experience, + motivation, plans, ip_address, user_agent + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + RETURNING id, submitted_at + `, [ + userId, minecraft_nick, age, discord, email, experience, + motivation, plans, ip, userAgent + ]); + + const application = insertResult.rows[0]; + + // Логируем действие + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description, ip_address) + VALUES ($1, $2, $3, $4) + `, [ + null, + 'application_submitted', + `Подана заявка от ${minecraft_nick} (${email})`, + ip + ]); + + console.log(`✅ Новая заявка от ${minecraft_nick}:`, { + id: application.id, + email, + experience, + motivation: motivation.substring(0, 100) + '...' + }); + + res.json({ + success: true, + message: 'Заявка успешно отправлена! Мы рассмотрим её в ближайшее время.', + application_id: application.id, + submitted_at: application.submitted_at + }); + + } catch (error) { + console.error('Ошибка при обработке заявки:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/applications/status/:email - Проверка статуса заявки +router.get('/status/:email', async (req, res) => { + try { + const { email } = req.params; + + const result = await db.query(` + SELECT id, minecraft_nick, status, submitted_at, reviewed_at, review_comment + FROM applications + WHERE email = $1 + ORDER BY submitted_at DESC + LIMIT 1 + `, [email]); + + if (result.rows.length === 0) { + return res.status(404).json({ + error: 'Заявка не найдена' + }); + } + + const application = result.rows[0]; + + res.json({ + id: application.id, + minecraft_nick: application.minecraft_nick, + status: application.status, + submitted_at: application.submitted_at, + reviewed_at: application.reviewed_at, + review_comment: application.review_comment, + status_text: getStatusText(application.status) + }); + + } catch (error) { + console.error('Ошибка проверки статуса заявки:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/applications - Получение всех заявок (только для админов) +router.get('/', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 20; + const status = req.query.status || 'all'; + const offset = (page - 1) * limit; + + let whereClause = ''; + let queryParams = [limit, offset]; + + if (status !== 'all') { + whereClause = 'WHERE a.status = $3'; + queryParams.push(status); + } + + const result = await db.query(` + SELECT a.*, u.nickname as reviewed_by_nickname + FROM applications a + LEFT JOIN users u ON a.reviewed_by = u.id + ${whereClause} + ORDER BY a.submitted_at DESC + LIMIT $1 OFFSET $2 + `, queryParams); + + // Получаем общее количество + const countParams = status !== 'all' ? [status] : []; + const countResult = await db.query(` + SELECT COUNT(*) as total FROM applications ${whereClause} + `, countParams); + + const total = parseInt(countResult.rows[0].total); + + res.json({ + applications: result.rows, + pagination: { + page, + limit, + total, + totalPages: Math.ceil(total / limit) + } + }); + + } catch (error) { + console.error('Ошибка получения заявок:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// PUT /api/applications/:id/review - Рассмотрение заявки (только для админов) +router.put('/:id/review', [ + authenticateToken, + requireRole(['admin', 'moderator']), + body('status').isIn(['approved', 'rejected']), + body('comment').optional().isLength({ max: 1000 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { id } = req.params; + const { status, comment } = req.body; + + // Получаем данные заявки + const applicationResult = await db.query(` + SELECT * FROM applications WHERE id = $1 + `, [id]); + + if (applicationResult.rows.length === 0) { + return res.status(404).json({ error: 'Заявка не найдена' }); + } + + const application = applicationResult.rows[0]; + + if (application.status !== 'pending') { + return res.status(400).json({ + error: 'Заявка уже была рассмотрена' + }); + } + + // Обновляем статус заявки + await db.query(` + UPDATE applications + SET status = $1, reviewed_by = $2, reviewed_at = NOW(), review_comment = $3 + WHERE id = $4 + `, [status, req.user.id, comment, id]); + + // Если заявка одобрена и у неё нет связанного пользователя, создаем пользователя + console.log(`Проверка условий: status=${status}, application.user_id=${application.user_id}`); + if (status === 'approved' && !application.user_id) { + console.log(`Создаем пользователя для заявки ${application.id}`); + await createUserFromApplication(application); + } else { + console.log(`Пропускаем создание пользователя: status=${status}, user_id=${application.user_id}`); + } + + // Логируем действие + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'application_reviewed', + `Заявка ${application.minecraft_nick} ${status === 'approved' ? 'одобрена' : 'отклонена'}${comment ? ': ' + comment : ''}`, + application.user_id + ]); + + res.json({ + success: true, + message: `Заявка ${status === 'approved' ? 'одобрена' : 'отклонена'}`, + application_id: id, + status + }); + + } catch (error) { + console.error('Ошибка рассмотрения заявки:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/applications/stats - Статистика заявок (для админов) +router.get('/stats', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const statsResult = await db.query(` + SELECT + COUNT(*) as total, + COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending, + COUNT(CASE WHEN status = 'approved' THEN 1 END) as approved, + COUNT(CASE WHEN status = 'rejected' THEN 1 END) as rejected, + COUNT(CASE WHEN submitted_at > NOW() - INTERVAL '24 hours' THEN 1 END) as today, + COUNT(CASE WHEN submitted_at > NOW() - INTERVAL '7 days' THEN 1 END) as this_week + FROM applications + `); + + res.json(statsResult.rows[0]); + + } catch (error) { + console.error('Ошибка получения статистики заявок:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// Функция создания пользователя из одобренной заявки +async function createUserFromApplication(application) { + try { + // Проверяем, что заявка еще не связана с пользователем + if (application.user_id) { + console.log(`Заявка ${application.id} уже связана с пользователем ${application.user_id}`); + return { userId: application.user_id }; + } + + // Проверяем, существует ли пользователь с таким никнеймом + const existingUser = await db.query(` + SELECT id FROM users WHERE nickname = $1 LIMIT 1 + `, [application.minecraft_nick]); + + let userId; + let tempPassword = null; + + if (existingUser.rows.length > 0) { + // Пользователь уже существует, используем его ID + userId = existingUser.rows[0].id; + console.log(`Пользователь с никнеймом ${application.minecraft_nick} уже существует (ID: ${userId}), связываем с заявкой`); + } else { + // Создаем нового пользователя + tempPassword = Math.random().toString(36).slice(-8); + const hashedPassword = await bcrypt.hash(tempPassword, 12); + + const userResult = await db.query(` + INSERT INTO users ( + nickname, email, discord_username, password_hash, + is_email_verified, trust_level + ) VALUES ($1, $2, $3, $4, false, 0) + RETURNING id + `, [ + application.minecraft_nick, + application.email, + application.discord, + hashedPassword + ]); + + userId = userResult.rows[0].id; + console.log(`✅ Создан новый пользователь ${application.minecraft_nick} (ID: ${userId})`); + } + + // Связываем заявку с пользователем + await db.query(` + UPDATE applications SET user_id = $1 WHERE id = $2 + `, [userId, application.id]); + + // Создаем записи в связанных таблицах только для новых пользователей + if (tempPassword) { + // Проверяем, есть ли уже player_stats для этого пользователя + const existingStats = await db.query(` + SELECT id FROM player_stats WHERE user_id = $1 LIMIT 1 + `, [userId]); + + if (existingStats.rows.length === 0) { + await db.query(` + INSERT INTO player_stats ( + user_id, time_played_minutes, is_time_limited, + current_level, u.is_email_verified, reputation, total_logins + ) VALUES ($1, 0, 600, true, 0, false, false, false, 0, 0, 0) + `, [userId]); + } + + // Добавляем достижение "Первый вход" только если его еще нет + const achievementResult = await db.query(` + SELECT id FROM achievements WHERE name = 'Первый вход' LIMIT 1 + `); + + if (achievementResult.rows.length > 0) { + const existingAchievement = await db.query(` + SELECT id FROM user_achievements + WHERE user_id = $1 AND achievement_id = $2 LIMIT 1 + `, [userId, achievementResult.rows[0].id]); + + if (existingAchievement.rows.length === 0) { + await db.query(` + INSERT INTO user_achievements (user_id, achievement_id) + VALUES ($1, $2) + `, [userId, achievementResult.rows[0].id]); + } + } + + console.log(`✅ Создан новый пользователь для ${application.minecraft_nick}, временный пароль: ${tempPassword}`); + } else { + console.log(`✅ Заявка ${application.id} связана с существующим пользователем ${application.minecraft_nick} (ID: ${userId})`); + } + + return { userId, tempPassword }; + + } catch (error) { + console.error('Ошибка создания пользователя из заявки:', error); + throw error; + } +} + +// Функция получения текста статуса +function getStatusText(status) { + const statusTexts = { + 'pending': 'На рассмотрении', + 'approved': 'Одобрена', + 'rejected': 'Отклонена', + 'banned': 'Заблокирована' + }; + return statusTexts[status] || 'Неизвестно'; +} + +// GET /api/applications/server-access - Получение информации о заявке на доступ к серверу +router.get('/server-access', authenticateApiToken, async (req, res) => { + try { + let userId; + + // Если передан nickname (для плагина), находим пользователя по никнейму + if (req.query.nickname) { + const userResult = await db.query('SELECT id FROM users WHERE nickname = $1', [req.query.nickname]); + if (userResult.rows.length === 0) { + return res.json({ hasAccess: false, application: null }); + } + userId = userResult.rows[0].id; + } else { + // Иначе используем аутентифицированного пользователя + userId = req.user.id; + } + + // Ищем последнюю заявку пользователя + const applicationResult = await db.query(` + SELECT * FROM applications + WHERE user_id = $1 + ORDER BY submitted_at DESC + LIMIT 1 + `, [userId]); + + const application = applicationResult.rows.length > 0 ? applicationResult.rows[0] : null; + + // Проверяем, есть ли у пользователя доступ к серверу (одобренная заявка) + const hasAccess = application !== null && application.status === 'approved'; + + res.json({ + hasAccess: hasAccess, + application: application + }); + + } catch (error) { + console.error('Ошибка получения заявки на доступ:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/applications/server-access - Подача заявки на доступ к серверу +router.post('/server-access', [ + authenticateToken, + body('age').isInt({ min: 10, max: 100 }), + body('source').isLength({ min: 1, max: 50 }), + body('experience').isLength({ min: 1, max: 50 }), + body('about').isLength({ min: 50, max: 1000 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const userId = req.user.id; + const { age, source, experience, about } = req.body; + + // Получаем данные пользователя + const userResult = await db.query(` + SELECT email, nickname, first_name, role, discord_username FROM users WHERE id = $1 + `, [userId]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + + // Проверяем, нет ли уже одобренной заявки + const approvedApplication = await db.query(` + SELECT id FROM applications + WHERE user_id = $1 AND status = 'approved' + LIMIT 1 + `, [userId]); + + if (approvedApplication.rows.length > 0) { + return res.status(400).json({ error: 'У вас уже есть доступ к серверу' }); + } + + // Проверяем, нет ли активной заявки + const existingApplication = await db.query(` + SELECT id, status FROM applications + WHERE user_id = $1 AND status = 'pending' + ORDER BY submitted_at DESC LIMIT 1 + `, [userId]); + + if (existingApplication.rows.length > 0) { + return res.status(400).json({ error: 'У вас уже есть активная заявка на рассмотрении' }); + } + + const ip = req.ip || req.connection.remoteAddress; + const userAgent = req.get('User-Agent') || ''; + + // Создаем заявку (адаптируем под структуру БД) + const result = await db.query(` + INSERT INTO applications + (user_id, minecraft_nick, email, age, discord, experience, motivation, plans, ip_address, user_agent) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) + RETURNING id + `, [userId, user.nickname, user.email, age.toString(), user.discord_username || 'Не указан', experience, about, 'Планы будут указаны позже', ip, userAgent]); + + res.json({ + success: true, + message: 'Заявка на доступ к серверу успешно подана', + applicationId: result.rows[0].id + }); + + } catch (error) { + console.error('Ошибка подачи заявки на доступ:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/applications/trust-level - Получение информации о заявке на повышение уровня доверия +router.get('/trust-level', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + + // Ищем последнюю заявку пользователя на повышение уровня доверия + const applicationResult = await db.query(` + SELECT * FROM trust_level_applications + WHERE user_id = $1 + ORDER BY submitted_at DESC + LIMIT 1 + `, [userId]); + + const application = applicationResult.rows.length > 0 ? applicationResult.rows[0] : null; + + res.json({ + application: application + }); + + } catch (error) { + console.error('Ошибка получения заявки на повышение:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/applications/trust-level - Подача заявки на повышение уровня доверия +router.post('/trust-level', [ + authenticateToken, + body('motivation').isLength({ min: 50, max: 1000 }), + body('plans').isLength({ min: 30, max: 500 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const userId = req.user.id; + const { motivation, plans } = req.body; + + // Получаем текущие данные пользователя + const userResult = await db.query(` + SELECT u.trust_level, ur.reputation_score, u.is_email_verified + FROM users u + LEFT JOIN user_reputation ur ON u.id = ur.user_id + WHERE u.id = $1 + `, [userId]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + const currentLevel = user.trust_level || 0; + const reputation = user.reputation_score || 0; + const requestedLevel = currentLevel + 1; + + // Проверяем, нет ли активной заявки + const existingApplication = await db.query(` + SELECT id FROM trust_level_applications + WHERE user_id = $1 AND status = 'pending' + `, [userId]); + + if (existingApplication.rows.length > 0) { + return res.status(400).json({ error: 'У вас уже есть активная заявка на рассмотрении' }); + } + + // Создаем заявку (объединяем motivation и plans в поле reason) + const result = await db.query(` + INSERT INTO trust_level_applications + (user_id, current_level, requested_level, reason, reputation_score, hours_played) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING id + `, [userId, currentLevel, requestedLevel, `Мотивация: ${motivation}\n\nПланы: ${plans}`, reputation, 0]); + + res.json({ + success: true, + message: 'Заявка на повышение уровня доверия успешно подана', + applicationId: result.rows[0].id + }); + + } catch (error) { + console.error('Ошибка подачи заявки на повышение:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/auth.js b/legacy/owyxsite/backend/src/routes/auth.js new file mode 100644 index 00000000000..271cbb8c8ac --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/auth.js @@ -0,0 +1,1403 @@ +// Маршруты авторизации +// Создатель: ebluffy + +const express = require('express'); +const bcrypt = require('bcryptjs'); +const jwt = require('jsonwebtoken'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { v4: uuidv4 } = require('uuid'); +// native fetch (Node 18+) +const fetch = globalThis.fetch; +const { verifyTurnstile } = require('../utils/turnstile'); +const { + hashSessionToken, + sessionTokenHashes, + publicUser +} = require('../utils/authSecurity'); + +const router = express.Router(); + +// Middleware для проверки токена +const authenticateToken = async (req, res, next) => { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + + if (!token) { + return res.status(401).json({ error: 'Токен доступа отсутствует' }); + } + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const hashes = sessionTokenHashes(token); + + // Проверяем, что сессия активна + const sessionResult = await db.query( + `SELECT u.*, s.id AS session_id, s.token_hash AS session_token_hash + FROM user_sessions s + JOIN users u ON s.user_id = u.id + WHERE s.token_hash = ANY($1::text[]) + AND s.user_id = $2 + AND s.expires_at > NOW() + AND s.is_active = true`, + [hashes, decoded.userId] + ); + + if (sessionResult.rows.length === 0) { + return res.status(401).json({ error: 'Недействительная сессия' }); + } + + req.user = sessionResult.rows[0]; + if (req.user.is_active === false || req.user.is_banned === true) { + await db.query( + 'UPDATE user_sessions SET is_active = false WHERE id = $1', + [req.user.session_id] + ).catch(() => {}); + return res.status(403).json({ + error: req.user.is_banned ? 'Аккаунт заблокирован' : 'Аккаунт неактивен' + }); + } + req.sessionTokenHash = hashes[0]; + + // Роль уже есть в таблице users, больше не нужно запрашивать отдельно + if (!req.user.role) { + req.user.role = 'user'; // Значение по умолчанию + } + + // Обновляем время последней активности (не ждем завершения) + // Transparently migrate legacy reversible base64 rows to SHA-256. + db.query( + 'UPDATE user_sessions SET token_hash = $1, last_activity = NOW() WHERE id = $2', + [hashes[0], req.user.session_id] + ).catch(err => console.error('Error updating last_activity:', err)); + + next(); + } catch (error) { + console.error('Ошибка проверки токена:', error); + return res.status(403).json({ error: 'Недействительный токен' }); + } +}; + +// Middleware для проверки API токена (для плагинов) +const authenticateApiToken = async (req, res, next) => { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + + if (!token) { + return res.status(401).json({ error: 'Токен доступа отсутствует' }); + } + + try { + const decoded = jwt.verify(token, process.env.JWT_SECRET); + + // Для API токенов просто проверяем пользователя в базе + const userResult = await db.query( + 'SELECT * FROM users WHERE id = $1', + [decoded.userId] + ); + + if (userResult.rows.length === 0) { + return res.status(401).json({ error: 'Пользователь не найден' }); + } + + req.user = userResult.rows[0]; + + // Роль уже есть в таблице users + if (!req.user.role) { + req.user.role = 'user'; // Значение по умолчанию + } + + next(); + } catch (error) { + console.error('Ошибка проверки API токена:', error); + return res.status(403).json({ error: 'Недействительный токен' }); + } +}; + +function emailVerificationUrl(token) { + const base = (process.env.FRONTEND_URL || 'http://localhost:3000').replace(/\/+$/, ''); + return `${base}/verify?token=${token}`; +} + +async function findLongTermApiToken(token) { + const tokenHash = hashSessionToken(token); + const apiTokenResult = await db.query(` + SELECT at.*, u.* + FROM api_tokens at + JOIN users u ON at.user_id = u.id + WHERE at.token_hash = $1 + AND at.is_active = true + AND (at.expires_at IS NULL OR at.expires_at > NOW()) + `, [tokenHash]); + + if (apiTokenResult.rows.length === 0) return null; + const tokenData = apiTokenResult.rows[0]; + if (tokenData.is_active === false || tokenData.is_banned === true) return null; + await db.query( + 'UPDATE api_tokens SET last_used_at = NOW() WHERE id = $1', + [tokenData.id] + ); + return tokenData; +} + +function attachLongTermApiToken(req, tokenData) { + req.user = { + id: tokenData.user_id, + nickname: tokenData.nickname, + email: tokenData.email, + role: tokenData.role || 'user', + trust_level: tokenData.trust_level, + is_active: tokenData.is_active, + is_banned: tokenData.is_banned + }; + req.apiToken = { + id: tokenData.id, + name: tokenData.token_name, + permissions: tokenData.permissions || [] + }; +} + +function bearerOrApiKey(req) { + const authHeader = req.headers['authorization']; + let token = authHeader && authHeader.split(' ')[1]; + if (!token) { + token = req.headers['x-api-key']; + } + return typeof token === 'string' ? token : null; +} + +// Strict middleware for plugin/server write endpoints. A normal website JWT is +// never accepted here, even if it belongs to an administrator. +const authenticateLongTermApiTokenOnly = async (req, res, next) => { + const token = bearerOrApiKey(req); + + if (!token) { + return res.status(401).json({ error: 'API токен отсутствует' }); + } + + try { + const tokenData = await findLongTermApiToken(token); + if (!tokenData) return res.status(403).json({ error: 'Недействительный API токен' }); + attachLongTermApiToken(req, tokenData); + return next(); + } catch (error) { + console.error('Ошибка проверки API токена:', error); + return res.status(403).json({ error: 'Недействительный токен' }); + } +}; + +// Hybrid middleware retained for admin routes that support either a signed-in +// website session or a long-term admin API key. +const authenticateLongTermApiToken = async (req, res, next) => { + const token = bearerOrApiKey(req); + if (!token) return res.status(401).json({ error: 'API токен отсутствует' }); + try { + const tokenData = await findLongTermApiToken(token); + if (tokenData) { + attachLongTermApiToken(req, tokenData); + return next(); + } + if (req.headers['authorization']) { + return authenticateToken(req, res, next); + } + return res.status(403).json({ error: 'Недействительный API токен' }); + } catch (error) { + console.error('Ошибка проверки API токена:', error); + return res.status(403).json({ error: 'Недействительный токен' }); + } +}; + +// Middleware для проверки роли +const requireRole = (roles) => { + return (req, res, next) => { + if (!req.user) { + return res.status(401).json({ error: 'Не авторизован' }); + } + + const userRoles = Array.isArray(roles) ? roles : [roles]; + if (!userRoles.includes(req.user.role)) { + return res.status(403).json({ error: 'Недостаточно прав' }); + } + + next(); + }; +}; + +// Функция для записи попытки входа +const logLoginAttempt = async (email, ip, userAgent, success) => { + try { + await db.query( + 'INSERT INTO login_logs (user_id, ip_address, user_agent, success) VALUES ((SELECT id FROM users WHERE email = $1), $2, $3, $4)', + [email, ip, userAgent, success] + ); + } catch (error) { + console.error('Ошибка записи попытки входа:', error); + } +}; + +// Функция для проверки ограничений на попытки входа +const checkLoginAttempts = async (ip, email) => { + const result = await db.query( + `SELECT COUNT(*) as attempts FROM login_logs + WHERE (ip_address = $1 OR user_id = (SELECT id FROM users WHERE email = $2)) + AND login_time > NOW() - INTERVAL '1 hour' + AND success = false`, + [ip, email] + ); + + return parseInt(result.rows[0].attempts); +}; + +// POST /api/auth/register - Регистрация нового пользователя +router.post('/register', [ + body('minecraft_nick') + .isLength({ min: 3, max: 32 }) + .withMessage('Minecraft ник должен быть от 3 до 32 символов') + .matches(/^[a-zA-Z0-9_]+$/) + .withMessage('Minecraft ник может содержать только буквы, цифры и подчеркивания'), + body('email').isEmail().normalizeEmail().withMessage('Некорректный email'), + body('password') + .isLength({ min: 8 }) + .withMessage('Пароль должен быть минимум 8 символов'), + body('first_name').optional().isLength({ max: 50 }).withMessage('Имя не должно превышать 50 символов') +], async (req, res) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + try { + const { minecraft_nick, email, password, first_name, turnstileToken } = req.body; + const clientIp = req.clientIp || req.ip || req.connection.remoteAddress; + + // Проверка Cloudflare Turnstile + const turnstileResult = await verifyTurnstile(turnstileToken, clientIp); + if (!turnstileResult.success) { + return res.status(400).json({ + error: turnstileResult.message || 'Проверка капчи не пройдена' + }); + } + + // Проверяем, не существует ли уже пользователь с таким email или ником + const existingUser = await db.query( + 'SELECT id, email, nickname FROM users WHERE email = $1 OR nickname = $2', + [email, minecraft_nick] + ); + + if (existingUser.rows.length > 0) { + const existing = existingUser.rows[0]; + if (existing.email === email) { + return res.status(400).json({ + error: 'Пользователь с таким email уже существует' + }); + } + if (existing.nickname === minecraft_nick) { + return res.status(400).json({ + error: 'Пользователь с таким Minecraft ником уже существует' + }); + } + } + + // Хешируем пароль + const saltRounds = parseInt(process.env.BCRYPT_ROUNDS) || 12; + const passwordHash = await bcrypt.hash(password, saltRounds); + + // Создаем пользователя + const result = await db.query( + `INSERT INTO users (nickname, email, password_hash, first_name, registered_at) + VALUES ($1, $2, $3, $4, NOW()) + RETURNING id, nickname, email, first_name, registered_at`, + [minecraft_nick, email, passwordHash, first_name || null] + ); + + const newUser = result.rows[0]; + + // Создаем начальную статистику игрока + await db.query(` + INSERT INTO player_stats ( + user_id, time_played_minutes, is_time_limited, + current_level, reputation, total_logins + ) VALUES ($1, 0, true, 0, 0, 0) + `, [newUser.id]); + + // Логируем успешную регистрацию + await logLoginAttempt(newUser.id, clientIp, req.get('User-Agent'), true); + + // Автоматически отправляем email подтверждения + try { + const verificationToken = uuidv4(); + const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 часа + + await db.query( + 'INSERT INTO email_verification_tokens (user_id, token, expires_at) VALUES ($1, $2, $3)', + [newUser.id, verificationToken, expiresAt] + ); + + const verificationUrl = emailVerificationUrl(verificationToken); + const emailService = require('../utils/emailService'); + await emailService.sendVerificationEmail( + email, + minecraft_nick, + verificationUrl + ); + } catch (emailError) { + console.error('Не удалось отправить подтверждение email:', emailError.message); + // Не прерываем регистрацию из-за ошибки отправки email + } + + console.log(`✅ Новая регистрация: ${minecraft_nick} (${email})`); + + res.status(201).json({ + message: 'Регистрация прошла успешно! Проверьте email для подтверждения адреса.', + user: { + id: newUser.id, + nickname: newUser.nickname, + email: newUser.email, + first_name: newUser.first_name, + registered_at: newUser.registered_at + } + }); + + } catch (error) { + console.error('Ошибка регистрации:', error); + + if (error.code === '23505') { // Нарушение уникальности + return res.status(400).json({ + error: 'Пользователь с таким email или ником уже существует' + }); + } + + res.status(500).json({ + error: 'Внутренняя ошибка сервера при регистрации' + }); + } +}); + +// POST /api/auth/login - Вход в систему +router.post('/login', [ + body('email').isEmail().normalizeEmail().withMessage('Некорректный email'), + body('password').isLength({ min: 6 }).withMessage('Пароль должен быть минимум 6 символов') +], async (req, res) => { + try { + // Проверка валидации + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { email, password, remember = false, turnstileToken } = req.body; + const ip = req.clientIp || req.ip || req.connection.remoteAddress; + const userAgent = req.get('User-Agent') || ''; + + // Проверка Cloudflare Turnstile + const turnstileResult = await verifyTurnstile(turnstileToken, ip); + if (!turnstileResult.success) { + return res.status(400).json({ + error: turnstileResult.message || 'Проверка капчи не пройдена' + }); + } + + // Проверяем количество неудачных попыток + const failedAttempts = await checkLoginAttempts(ip, email); + if (failedAttempts >= 5) { + await logLoginAttempt(email, ip, userAgent, false); + return res.status(429).json({ + error: 'Слишком много неудачных попыток входа. Попробуйте через час.' + }); + } + + // Находим пользователя + const userResult = await db.query( + 'SELECT * FROM users WHERE email = $1 AND is_active = true', + [email] + ); + + if (userResult.rows.length === 0) { + await logLoginAttempt(email, ip, userAgent, false); + return res.status(401).json({ error: 'Неверный email или пароль' }); + } + + const user = userResult.rows[0]; + + // Проверяем пароль + const isPasswordValid = await bcrypt.compare(password, user.password_hash); + if (!isPasswordValid) { + await logLoginAttempt(email, ip, userAgent, false); + return res.status(401).json({ error: 'Неверный email или пароль' }); + } + + // Создаём JWT токен + const tokenPayload = { + userId: user.id, + email: user.email, + role: user.role + }; + + const expiresIn = remember ? '30d' : '24h'; + const token = jwt.sign(tokenPayload, process.env.JWT_SECRET, { expiresIn }); + + // Очищаем старые истёкшие сессии для всех пользователей + await db.query( + 'DELETE FROM user_sessions WHERE expires_at < NOW()' + ); + + // Keep parallel sessions (site + launcher). Do NOT wipe every session on + // login — that would silently sign out the other client. Cap to the + // newest 10 active sessions per user so the table cannot grow forever. + const existingSessions = await db.query( + `SELECT id FROM user_sessions + WHERE user_id = $1 AND expires_at > NOW() AND is_active = true + ORDER BY last_activity DESC NULLS LAST, expires_at DESC`, + [user.id] + ); + if (existingSessions.rows.length >= 10) { + const dropIds = existingSessions.rows.slice(9).map((row) => row.id); + await db.query( + 'DELETE FROM user_sessions WHERE id = ANY($1::uuid[])', + [dropIds] + ); + } + + // Сохраняем новую сессию в базе данных + const sessionId = uuidv4(); + const expiresAt = new Date(); + expiresAt.setTime(expiresAt.getTime() + (remember ? 30 * 24 * 60 * 60 * 1000 : 24 * 60 * 60 * 1000)); + + await db.query( + 'INSERT INTO user_sessions (id, user_id, token_hash, expires_at, ip_address, user_agent) VALUES ($1, $2, $3, $4, $5, $6)', + [sessionId, user.id, hashSessionToken(token), expiresAt, ip, userAgent] + ); + + // Обновляем время последнего входа + await db.query( + 'UPDATE users SET last_login = NOW() WHERE id = $1', + [user.id] + ); + + // Записываем успешную попытку входа + await logLoginAttempt(email, ip, userAgent, true); + + // Записываем активность + await db.query( + 'INSERT INTO user_activity (user_id, activity_type, description, ip_address) VALUES ($1, $2, $3, $4)', + [user.id, 'login', 'Вход в систему', ip] + ); + + res.json({ + success: true, + message: 'Успешная авторизация', + token, + user: publicUser(user) + }); + + } catch (error) { + console.error('Ошибка входа:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/logout - Выход из системы +router.post('/logout', authenticateToken, async (req, res) => { + try { + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; + + if (token) { + // Полностью удаляем сессию (а не просто деактивируем) + await db.query( + 'DELETE FROM user_sessions WHERE token_hash = ANY($1::text[])', + [sessionTokenHashes(token)] + ); + + // Записываем активность + await db.query( + 'INSERT INTO user_activity (user_id, activity_type, description, ip_address) VALUES ($1, $2, $3, $4)', + [req.user.id, 'logout', 'Выход из системы', req.clientIp || req.ip] + ); + } + + res.json({ success: true, message: 'Успешный выход из системы' }); + } catch (error) { + console.error('Ошибка выхода:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/auth/verify - Проверка токена +router.get('/verify', authenticateToken, async (req, res) => { + try { + // Получаем актуальные данные пользователя + const userResult = await db.query( + 'SELECT * FROM users WHERE id = $1 AND is_active = true', + [req.user.id] + ); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + res.json({ + success: true, + user: publicUser(userResult.rows[0]) + }); + } catch (error) { + console.error('Ошибка проверки токена:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/refresh - Обновление токена +router.post('/refresh', authenticateToken, async (req, res) => { + try { + const tokenPayload = { + userId: req.user.id, + email: req.user.email, + role: req.user.role + }; + + const newToken = jwt.sign(tokenPayload, process.env.JWT_SECRET, { expiresIn: '24h' }); + + // Обновляем сессию + const authHeader = req.headers['authorization']; + const oldToken = authHeader && authHeader.split(' ')[1]; + + await db.query( + `UPDATE user_sessions + SET token_hash = $1, expires_at = NOW() + INTERVAL '24 hours' + WHERE token_hash = ANY($2::text[])`, + [hashSessionToken(newToken), sessionTokenHashes(oldToken)] + ); + + res.json({ + success: true, + token: newToken + }); + } catch (error) { + console.error('Ошибка обновления токена:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/send-verification - Отправка письма с подтверждением email +router.post('/send-verification', authenticateToken, async (req, res) => { + try { + const user = req.user; + + if (user.is_email_verified) { + return res.status(400).json({ error: 'Email уже подтвержден' }); + } + + // Генерируем токен для подтверждения + const verificationToken = uuidv4(); + const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 часа + + // Удаляем старые токены пользователя + await db.query(` + DELETE FROM email_verification_tokens WHERE user_id = $1 + `, [user.id]); + + // Сохраняем новый токен в базе данных + await db.query(` + INSERT INTO email_verification_tokens (user_id, token, expires_at, created_at, used) + VALUES ($1, $2, $3, NOW(), false) + `, [user.id, verificationToken, expiresAt]); + + // Отправляем письмо через emailService + const emailService = require('../utils/emailService'); + const verificationUrl = emailVerificationUrl(verificationToken); + try { + await emailService.sendVerificationEmail(user.email, user.nickname || user.minecraft_nick, verificationUrl); + const payload = { message: 'Письмо с подтверждением отправлено' }; + if (process.env.NODE_ENV !== 'production') payload.verification_url = verificationUrl; + res.json(payload); + } catch (mailError) { + console.error('Ошибка отправки письма через SMTP:', mailError); + res.status(500).json({ error: 'Ошибка отправки письма (SMTP)' }); + } + + } catch (error) { + console.error('Ошибка отправки письма верификации:', error); + res.status(500).json({ error: 'Ошибка отправки письма' }); + } +}); + +// GET /api/auth/verify-email - Подтверждение email по токену +router.get('/verify-email', async (req, res) => { + try { + const { token } = req.query; + + if (!token) { + return res.status(400).json({ error: 'Токен подтверждения отсутствует' }); + } + + // Проверяем токен + const tokenResult = await db.query(` + SELECT ev.*, u.email + FROM email_verification_tokens ev + JOIN users u ON ev.user_id = u.id + WHERE ev.token = $1 AND ev.expires_at > NOW() AND ev.used = false + `, [token]); + + if (tokenResult.rows.length === 0) { + return res.status(400).json({ error: 'Недействительный или истёкший токен' }); + } + + const tokenData = tokenResult.rows[0]; + + // Обновляем статус подтверждения email + await db.query(` + UPDATE users + SET is_email_verified = true + WHERE id = $1 + `, [tokenData.user_id]); + + // Удаляем использованный токен + await db.query(` + UPDATE email_verification_tokens SET used = true WHERE token = $1 + `, [token]); + + res.json({ message: 'Email успешно подтвержден' }); + + } catch (error) { + console.error('Ошибка подтверждения email:', error); + res.status(500).json({ error: 'Ошибка подтверждения email' }); + } +}); + +// GET /api/auth/discord - Переадресация на Discord OAuth +router.get('/discord', (req, res) => { + const discordClientId = process.env.DISCORD_CLIENT_ID; + const redirectUri = encodeURIComponent(`${process.env.FRONTEND_URL || 'http://localhost:3000'}/api/auth/discord/callback`); + const scope = encodeURIComponent('identify email'); + + if (!discordClientId) { + return res.status(500).json({ error: 'Discord OAuth не настроен' }); + } + + const discordAuthUrl = `https://discord.com/api/oauth2/authorize?client_id=${discordClientId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}`; + + res.redirect(discordAuthUrl); +}); + +// GET /api/auth/discord/callback - Обработка ответа от Discord +router.get('/discord/callback', async (req, res) => { + try { + const { code } = req.query; + + if (!code) { + return res.redirect('/?error=discord_auth_failed'); + } + + // Обмениваем код на токен + const tokenResponse = await fetch('https://discord.com/api/oauth2/token', { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded' + }, + body: new URLSearchParams({ + client_id: process.env.DISCORD_CLIENT_ID, + client_secret: process.env.DISCORD_CLIENT_SECRET, + grant_type: 'authorization_code', + code: code, + redirect_uri: `${process.env.FRONTEND_URL || 'http://localhost:3000'}/api/auth/discord/callback` + }) + }); + + const tokenData = await tokenResponse.json(); + + if (!tokenData.access_token) { + return res.redirect('/?error=discord_token_failed'); + } + + // Получаем информацию о пользователе Discord + const userResponse = await fetch('https://discord.com/api/users/@me', { + headers: { + 'Authorization': `Bearer ${tokenData.access_token}` + } + }); + + const discordUser = await userResponse.json(); + + // Формируем новый Discord username (без дискриминатора, так как Discord его убрал) + const discordUsername = discordUser.username; + + // Временно сохраняем в сессии для связывания с пользователем + req.session.pendingDiscordLink = { + id: discordUser.id, + username: discordUsername, + email: discordUser.email, + avatar: discordUser.avatar, + access_token: tokenData.access_token, + refresh_token: tokenData.refresh_token, + expires_at: new Date(Date.now() + (tokenData.expires_in * 1000)) + }; + + res.redirect(`/profile?discord_ready=true&username=${encodeURIComponent(discordUsername)}`); + + } catch (error) { + console.error('Ошибка Discord OAuth:', error); + res.redirect('/?error=discord_oauth_error'); + } +}); + +// POST /api/auth/link-discord - Привязка Discord аккаунта к профилю +router.post('/link-discord', authenticateToken, async (req, res) => { + try { + if (!req.session.pendingDiscordLink) { + return res.status(400).json({ + error: 'Нет ожидающей привязки Discord аккаунта. Пройдите авторизацию через Discord заново.' + }); + } + + const discordData = req.session.pendingDiscordLink; + + // Проверяем, не привязан ли этот Discord к другому пользователю + const existingLink = await db.query(` + SELECT user_id FROM discord_oauth WHERE discord_id = $1 + `, [discordData.id]); + + if (existingLink.rows.length > 0 && existingLink.rows[0].user_id !== req.user.id) { + return res.status(400).json({ + error: 'Этот Discord аккаунт уже привязан к другому пользователю' + }); + } + + // Обновляем пользователя + await db.query(` + UPDATE users + SET discord_username = $1 + WHERE id = $2 + `, [discordData.username, req.user.id]); + + // Сохраняем OAuth данные + await db.query(` + INSERT INTO discord_oauth ( + user_id, discord_id, discord_username, discord_avatar, + access_token, refresh_token, expires_at + ) VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (discord_id) + DO UPDATE SET + user_id = $1, + discord_username = $3, + discord_avatar = $4, + access_token = $5, + refresh_token = $6, + expires_at = $7, + updated_at = NOW() + `, [ + req.user.id, + discordData.id, + discordData.username, + discordData.avatar, + discordData.access_token, + discordData.refresh_token, + discordData.expires_at + ]); + + // Логируем активность + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'discord_linked', $2) + `, [req.user.id, `Привязан Discord аккаунт: ${discordData.username}`]); + + // Очищаем временные данные + delete req.session.pendingDiscordLink; + + res.json({ + success: true, + message: 'Discord аккаунт успешно привязан', + discord_username: discordData.username + }); + + } catch (error) { + console.error('Ошибка привязки Discord:', error); + res.status(500).json({ error: 'Ошибка привязки Discord аккаунта' }); + } +}); + +// POST /api/auth/unlink-discord - Отвязка Discord аккаунта +router.post('/unlink-discord', authenticateToken, async (req, res) => { + try { + // Удаляем привязку Discord + await db.query(` + UPDATE users + SET discord_username = NULL + WHERE id = $1 + `, [req.user.id]); + + // Удаляем OAuth данные + await db.query(` + DELETE FROM discord_oauth + WHERE user_id = $1 + `, [req.user.id]); + + // Логируем активность + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'discord_unlinked', 'Отвязан Discord аккаунт') + `, [req.user.id]); + + res.json({ + success: true, + message: 'Discord аккаунт успешно отвязан' + }); + + } catch (error) { + console.error('Ошибка отвязки Discord:', error); + res.status(500).json({ error: 'Ошибка отвязки Discord аккаунта' }); + } +}); + +// POST /api/auth/forgot-password - Отправка ссылки для сброса пароля +router.post('/forgot-password', [ + body('email').isEmail().normalizeEmail() +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Некорректный email адрес' + }); + } + + const { email } = req.body; + + // Проверяем, существует ли пользователь + const userResult = await db.query( + 'SELECT id, nickname FROM users WHERE email = $1', + [email] + ); + + if (userResult.rows.length === 0) { + // В целях безопасности возвращаем тот же ответ + return res.json({ + message: 'Если email существует в системе, ссылка для сброса пароля была отправлена' + }); + } + + const user = userResult.rows[0]; + const resetToken = uuidv4(); + const expiresAt = new Date(Date.now() + 3600000); // 1 час + + // Удаляем старые токены для этого пользователя + await db.query( + 'DELETE FROM password_reset_tokens WHERE user_id = $1', + [user.id] + ); + + // Создаем новый токен + await db.query( + 'INSERT INTO password_reset_tokens (user_id, token, expires_at) VALUES ($1, $2, $3)', + [user.id, resetToken, expiresAt] + ); + + try { + const resetLink = + `${process.env.FRONTEND_URL || 'http://localhost:3000'}/reset-password?token=${resetToken}`; + const emailService = require('../utils/emailService'); + await emailService.sendPasswordResetEmail(email, user.nickname, resetLink); + } catch (mailError) { + // Keep the same response to avoid account enumeration. + console.error('Не удалось отправить письмо сброса пароля:', mailError.message); + } + + res.json({ + message: 'Если email существует в системе, ссылка для сброса пароля была отправлена' + }); + + } catch (error) { + console.error('Ошибка создания токена сброса пароля:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// POST /api/auth/reset-password - Сброс пароля по токену +router.post('/reset-password', [ + body('token').notEmpty(), + body('password').isLength({ min: 8 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Некорректные данные' + }); + } + + const { token, password } = req.body; + + // Проверяем токен + const tokenResult = await db.query( + 'SELECT user_id FROM password_reset_tokens WHERE token = $1 AND expires_at > NOW() AND used = false', + [token] + ); + + if (tokenResult.rows.length === 0) { + return res.status(400).json({ + error: 'Недействительный или просроченный токен' + }); + } + + const userId = tokenResult.rows[0].user_id; + + // Хешируем новый пароль + const hashedPassword = await bcrypt.hash(password, 12); + + // Обновляем пароль пользователя + await db.query( + 'UPDATE users SET password_hash = $1 WHERE id = $2', + [hashedPassword, userId] + ); + + // Помечаем токен как использованный + await db.query( + 'UPDATE password_reset_tokens SET used = true WHERE token = $1', + [token] + ); + + // Удаляем все активные сессии пользователя для безопасности + await db.query( + 'UPDATE user_sessions SET is_active = false WHERE user_id = $1', + [userId] + ); + + res.json({ + message: 'Пароль успешно изменен' + }); + + } catch (error) { + console.error('Ошибка сброса пароля:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/auth/verify-reset-token - Проверка токена сброса пароля +router.get('/verify-reset-token', async (req, res) => { + try { + const { token } = req.query; + + if (!token) { + return res.status(400).json({ + error: 'Токен не указан' + }); + } + + // Проверяем токен + const tokenResult = await db.query( + 'SELECT user_id FROM password_reset_tokens WHERE token = $1 AND expires_at > NOW() AND used = false', + [token] + ); + + if (tokenResult.rows.length === 0) { + return res.status(400).json({ + error: 'Недействительный или просроченный токен' + }); + } + + res.json({ + valid: true + }); + + } catch (error) { + console.error('Ошибка проверки токена:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// GET /api/auth/verify-email-token - Подтверждение email по токену +router.get('/verify-email-token', async (req, res) => { + try { + const { token } = req.query; + + if (!token) { + return res.status(400).json({ + error: 'Токен не указан' + }); + } + + // Проверяем токен верификации + const tokenResult = await db.query( + 'SELECT user_id FROM email_verification_tokens WHERE token = $1 AND expires_at > NOW() AND used = false', + [token] + ); + + if (tokenResult.rows.length === 0) { + return res.status(400).json({ + error: 'Недействительный или просроченный токен' + }); + } + + const userId = tokenResult.rows[0].user_id; + + // Активируем пользователя + await db.query( + 'UPDATE users SET is_email_verified = true WHERE id = $1', + [userId] + ); + + // Помечаем токен как использованный + await db.query( + 'UPDATE email_verification_tokens SET used = true WHERE token = $1', + [token] + ); + + res.json({ + message: 'Email успешно подтвержден' + }); + + } catch (error) { + console.error('Ошибка подтверждения email:', error); + res.status(500).json({ + error: 'Внутренняя ошибка сервера' + }); + } +}); + +// Экспорт middleware +// POST /api/auth/generate-game-token - Генерация токена для входа в игру +router.post('/generate-game-token', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + const userAgent = req.headers['user-agent'] || ''; + const ipAddress = req.clientIp || req.ip || req.connection.remoteAddress; + + // Open access: any active, non-banned account may play. Applications + // ("заявки") are no longer a gate — only a ban (or a disabled account) + // blocks the game token. + if (req.user.is_banned) { + return res.status(403).json({ + error: 'Ваш аккаунт заблокирован. Обратитесь в поддержку.' + }); + } + if (req.user.is_active === false) { + return res.status(403).json({ + error: 'Аккаунт неактивен. Обратитесь в поддержку.' + }); + } + + // Генерируем уникальный токен + const gameToken = uuidv4() + '-' + Date.now().toString(36); + const tokenHash = require('crypto').createHash('sha256').update(gameToken).digest('hex'); + + // Время жизни токена - 15 минут + const expiresAt = new Date(Date.now() + 15 * 60 * 1000); + + // Деактивируем старые неиспользованные токены пользователя + await db.query(` + UPDATE game_tokens + SET is_used = true, used_at = NOW() + WHERE user_id = $1 AND is_used = false AND expires_at > NOW() + `, [userId]); + + // Создаем новый токен + await db.query(` + INSERT INTO game_tokens (user_id, token_hash, expires_at, ip_address, user_agent) + VALUES ($1, $2, $3, $4, $5) + `, [userId, tokenHash, expiresAt, ipAddress, userAgent]); + + res.json({ + success: true, + token: gameToken, + expires_at: expiresAt, + expires_in: 15 * 60, // секунды + message: 'Токен для входа в игру создан. Используйте команду /login ' + gameToken + ' в игре.' + }); + + } catch (error) { + console.error('Ошибка генерации игрового токена:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/verify-game-token - Проверка игрового токена (для плагина) +router.post('/verify-game-token', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { token, nickname } = req.body; + + if (!token || !nickname) { + return res.status(400).json({ error: 'Токен и никнейм обязательны' }); + } + + // Хешируем токен для поиска + const tokenHash = require('crypto').createHash('sha256').update(token).digest('hex'); + + // Ищем токен и проверяем его валидность + const tokenResult = await db.query(` + SELECT gt.*, u.nickname, u.id as user_id, u.role, u.trust_level, u.is_banned + FROM game_tokens gt + JOIN users u ON gt.user_id = u.id + WHERE gt.token_hash = $1 AND gt.expires_at > NOW() AND gt.is_used = false + `, [tokenHash]); + + if (tokenResult.rows.length === 0) { + return res.status(401).json({ + error: 'Недействительный или истекший токен', + valid: false + }); + } + + const tokenData = tokenResult.rows[0]; + + // Проверяем, что никнейм соответствует владельцу токена + if (tokenData.nickname.toLowerCase() !== nickname.toLowerCase()) { + return res.status(403).json({ + error: 'Токен не принадлежит данному игроку', + valid: false + }); + } + + // Проверяем, что пользователь не забанен + if (tokenData.is_banned) { + return res.status(403).json({ + error: 'Пользователь заблокирован', + valid: false + }); + } + + // Отмечаем токен как использованный + await db.query(` + UPDATE game_tokens + SET is_used = true, used_at = NOW() + WHERE id = $1 + `, [tokenData.id]); + + res.json({ + valid: true, + user: { + id: tokenData.user_id, + nickname: tokenData.nickname, + role: tokenData.role, + trust_level: tokenData.trust_level + }, + message: 'Токен действителен' + }); + + } catch (error) { + console.error('Ошибка проверки игрового токена:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/auth/game-tokens - Получение списка игровых токенов пользователя +router.get('/game-tokens', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + + const tokensResult = await db.query(` + SELECT id, expires_at, is_used, used_at, created_at, ip_address + FROM game_tokens + WHERE user_id = $1 + ORDER BY created_at DESC + LIMIT 10 + `, [userId]); + + res.json({ + tokens: tokensResult.rows.map(token => ({ + id: token.id, + expires_at: token.expires_at, + is_used: token.is_used, + used_at: token.used_at, + created_at: token.created_at, + ip_address: token.ip_address, + status: token.is_used ? 'used' : (new Date(token.expires_at) < new Date() ? 'expired' : 'active') + })) + }); + + } catch (error) { + console.error('Ошибка получения игровых токенов:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/create-game-session - Создание игровой сессии после авторизации токеном +router.post('/create-game-session', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { nickname, player_uuid, ip_address, user_agent } = req.body; + + if (!nickname || !player_uuid || !ip_address) { + return res.status(400).json({ error: 'Nickname, player_uuid и ip_address обязательны' }); + } + + // Найдем пользователя по никнейму + const userResult = await db.query( + 'SELECT id FROM users WHERE nickname = $1', + [nickname] + ); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const userId = userResult.rows[0].id; + + // Деактивируем старые сессии этого игрока + await db.query(` + UPDATE game_sessions + SET is_active = false + WHERE user_id = $1 AND player_uuid = $2 AND is_active = true + `, [userId, player_uuid]); + + // Создаем новую сессию на 7 дней + const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000); + + const sessionResult = await db.query(` + INSERT INTO game_sessions (user_id, player_uuid, nickname, expires_at, ip_address, user_agent) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING id + `, [userId, player_uuid, nickname, expiresAt, ip_address, user_agent]); + + res.json({ + success: true, + session_id: sessionResult.rows[0].id, + expires_at: expiresAt, + message: 'Игровая сессия создана' + }); + + } catch (error) { + console.error('Ошибка создания игровой сессии:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/check-game-session - Проверка активной игровой сессии +router.post('/check-game-session', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { nickname, player_uuid, ip_address } = req.body; + + if (!nickname || !player_uuid || !ip_address) { + return res.status(400).json({ error: 'Nickname, player_uuid и ip_address обязательны' }); + } + + // Ищем активную сессию + const sessionResult = await db.query(` + SELECT gs.*, u.id as user_id, u.role, u.trust_level, u.is_banned + FROM game_sessions gs + JOIN users u ON gs.user_id = u.id + WHERE gs.nickname = $1 + AND gs.player_uuid = $2 + AND gs.ip_address = $3 + AND gs.is_active = true + AND gs.expires_at > NOW() + `, [nickname, player_uuid, ip_address]); + + if (sessionResult.rows.length === 0) { + return res.status(404).json({ + session_valid: false, + error: 'Активная сессия не найдена' + }); + } + + const session = sessionResult.rows[0]; + + // Проверяем, что пользователь не забанен + if (session.is_banned) { + return res.status(403).json({ + session_valid: false, + error: 'Пользователь заблокирован' + }); + } + + // Обновляем время последнего входа + await db.query(` + UPDATE game_sessions + SET last_login = NOW() + WHERE id = $1 + `, [session.id]); + + res.json({ + session_valid: true, + user: { + id: session.user_id, + nickname: session.nickname, + role: session.role, + trust_level: session.trust_level + }, + session: { + id: session.id, + expires_at: session.expires_at, + created_at: session.created_at + }, + message: 'Сессия действительна' + }); + + } catch (error) { + console.error('Ошибка проверки игровой сессии:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/auth/game-sessions - Получение активных игровых сессий пользователя +router.get('/game-sessions', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + + const sessionsResult = await db.query(` + SELECT id, player_uuid, nickname, expires_at, ip_address, is_active, created_at, last_login + FROM game_sessions + WHERE user_id = $1 AND is_active = true + ORDER BY last_login DESC + LIMIT 10 + `, [userId]); + + res.json({ + sessions: sessionsResult.rows.map(session => ({ + id: session.id, + player_uuid: session.player_uuid, + nickname: session.nickname, + expires_at: session.expires_at, + ip_address: session.ip_address, + created_at: session.created_at, + last_login: session.last_login, + status: new Date(session.expires_at) < new Date() ? 'expired' : 'active' + })) + }); + + } catch (error) { + console.error('Ошибка получения игровых сессий:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/auth/terminate-game-sessions - Завершение всех игровых сессий пользователя +router.post('/terminate-game-sessions', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + + const result = await db.query(` + UPDATE game_sessions + SET is_active = false + WHERE user_id = $1 AND is_active = true + RETURNING id + `, [userId]); + + res.json({ + success: true, + terminated_sessions: result.rows.length, + message: `Завершено сессий: ${result.rows.length}` + }); + + } catch (error) { + console.error('Ошибка завершения игровых сессий:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +router.authenticateToken = authenticateToken; +router.authenticateApiToken = authenticateApiToken; +router.authenticateLongTermApiToken = authenticateLongTermApiToken; +router.authenticateLongTermApiTokenOnly = authenticateLongTermApiTokenOnly; +router.requireRole = requireRole; + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/catalog.js b/legacy/owyxsite/backend/src/routes/catalog.js new file mode 100644 index 00000000000..12b607e3813 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/catalog.js @@ -0,0 +1,839 @@ +const express = require('express'); +const crypto = require('crypto'); +const fs = require('fs'); +const path = require('path'); +const multer = require('multer'); +const db = require('../database/connection'); +const { authenticateToken, requireRole } = require('./auth'); + +// Site control-plane: packs (what to download) + servers (where to connect). +// Players never receive SFTP credentials. Bytes live as HTTP URLs, not in Postgres. + +const SOURCE_TYPES = ['http_zip', 'http_manifest', 'google_drive', 'mrpack', 'sftp', 'local_ingest']; +const LOADERS = ['vanilla', 'fabric', 'forge', 'neoforge', 'quilt']; +const KINDS = ['owyx', 'community']; +const ID_RE = /^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/; +const ingestDir = path.join(__dirname, '../../uploads/packs'); + +const packsAdmin = express.Router(); +const serversAdmin = express.Router(); +packsAdmin.use(authenticateToken, requireRole(['admin'])); +serversAdmin.use(authenticateToken, requireRole(['admin'])); + +function publicBase(req) { + const fromEnv = (process.env.API_PUBLIC_URL || '').trim(); + if (fromEnv) return fromEnv.replace(/\/+$/, ''); + return `${req.protocol}://${req.get('host')}`; +} + +function absoluteAsset(req, value) { + if (!value) return null; + if (/^https?:\/\//i.test(value)) return value; + return `${publicBase(req)}${value.startsWith('/') ? '' : '/'}${value}`; +} + +function parseConfig(raw) { + if (!raw) return {}; + if (typeof raw === 'object') return raw; + try { + return JSON.parse(raw); + } catch { + return {}; + } +} + +function slugify(name, fallback) { + const base = String(name || '') + .normalize('NFKD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() + .replace(/[^a-z0-9]+/g, '-') + .replace(/^-+|-+$/g, '') + .slice(0, 48); + return base || fallback; +} + +async function uniqueId(table, base) { + let candidate = base; + let n = 2; + while (true) { + const result = await db.query(`SELECT 1 FROM ${table} WHERE id = $1`, [candidate]); + if (result.rows.length === 0) return candidate; + candidate = `${base}-${n}`.slice(0, 64); + n += 1; + if (n > 99) return `${base}-${Date.now().toString(36)}`.slice(0, 64); + } +} + +function normalizeId(raw, name, fallback) { + const given = String(raw || '').trim().toLowerCase(); + if (given) { + if (!ID_RE.test(given)) { + const err = new Error('id: латиница, цифры и дефис, 2–64 символа'); + err.status = 400; + throw err; + } + return given; + } + return slugify(name, fallback); +} + +function asBool(value, fallback = true) { + if (value === undefined || value === null || value === '') return fallback; + if (typeof value === 'boolean') return value; + if (value === 'true' || value === '1' || value === 1) return true; + if (value === 'false' || value === '0' || value === 0) return false; + return fallback; +} + +function validateLoader(loader) { + const v = String(loader || 'vanilla').trim().toLowerCase(); + if (!LOADERS.includes(v)) { + const err = new Error(`loader: ${LOADERS.join(', ')}`); + err.status = 400; + throw err; + } + return v; +} + +function validateKind(kind) { + const v = String(kind || 'owyx').trim().toLowerCase(); + if (!KINDS.includes(v)) { + const err = new Error('kind: owyx или community'); + err.status = 400; + throw err; + } + return v; +} + +function validateHttpUrl(raw, field) { + const url = String(raw || '').trim(); + if (!url) { + const err = new Error(`${field} обязателен`); + err.status = 400; + throw err; + } + if (url.startsWith('/')) return url; + let parsed; + try { + parsed = new URL(url); + } catch { + const err = new Error(`${field}: некорректный URL`); + err.status = 400; + throw err; + } + if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') { + const err = new Error(`${field}: только http(s)`); + err.status = 400; + throw err; + } + if (parsed.username || parsed.password) { + const err = new Error(`${field}: URL не должен содержать логин/пароль`); + err.status = 400; + throw err; + } + return url; +} + +function validateSha256(raw) { + if (raw === undefined || raw === null || raw === '') return null; + const v = String(raw).trim().toLowerCase(); + if (!/^[a-f0-9]{64}$/.test(v)) { + const err = new Error('sha256: 64 hex-символа'); + err.status = 400; + throw err; + } + return v; +} + +function normalizeSource(typeRaw, configRaw) { + const type = String(typeRaw || 'http_zip').trim().toLowerCase(); + if (!SOURCE_TYPES.includes(type)) { + const err = new Error(`source.type: ${SOURCE_TYPES.join(', ')}`); + err.status = 400; + throw err; + } + const cfg = parseConfig(configRaw) || {}; + if (type === 'http_zip' || type === 'local_ingest') { + const url = cfg.url ? validateHttpUrl(cfg.url, 'source.url') : null; + if (type === 'http_zip' && !url) { + const err = new Error('http_zip: нужен source.url'); + err.status = 400; + throw err; + } + return { type, config: { url, sha256: validateSha256(cfg.sha256) } }; + } + if (type === 'http_manifest') { + const manifestUrl = validateHttpUrl(cfg.manifestUrl || cfg.url, 'source.manifestUrl'); + return { type, config: { manifestUrl, files: Array.isArray(cfg.files) ? cfg.files : undefined } }; + } + if (type === 'google_drive') { + const url = validateHttpUrl(cfg.url || cfg.directDownloadUrl, 'source.url'); + const direct = cfg.directDownloadUrl ? validateHttpUrl(cfg.directDownloadUrl, 'source.directDownloadUrl') : null; + return { + type, + config: { + url, + directDownloadUrl: direct, + note: String(cfg.note || '').slice(0, 400) || null, + }, + }; + } + if (type === 'mrpack') { + const url = validateHttpUrl(cfg.url || cfg.downloadUrl, 'source.url'); + return { type, config: { url, ingest: 'planned' } }; + } + // sftp — admin-only warehouse. Players never see these fields. + const host = String(cfg.host || '').trim(); + const user = String(cfg.user || '').trim(); + const remotePath = String(cfg.path || '').trim(); + if (!host || !user || !remotePath) { + const err = new Error('sftp: нужны host, user, path'); + err.status = 400; + throw err; + } + const port = parseInt(cfg.port, 10) || 22; + if (port < 1 || port > 65535) { + const err = new Error('sftp.port: 1–65535'); + err.status = 400; + throw err; + } + return { + type, + config: { + host, + port, + user, + path: remotePath, + password: cfg.password ? String(cfg.password) : undefined, + }, + }; +} + +function adminSourceView(type, config) { + const cfg = parseConfig(config); + if (type === 'sftp') { + return { + type, + config: { + host: cfg.host || '', + port: cfg.port || 22, + user: cfg.user || '', + path: cfg.path || '', + hasPassword: Boolean(cfg.password), + }, + }; + } + return { type, config: cfg }; +} + +function publicPack(req, row) { + const type = row.source_type; + const cfg = parseConfig(row.source_config); + const out = { + id: row.id, + name: row.name, + minecraft: row.minecraft, + loader: row.loader, + iconUrl: absoluteAsset(req, row.icon_url), + description: row.description || '', + sourceType: type, + manifestUrl: row.manifest_url ? absoluteAsset(req, row.manifest_url) : null, + }; + if (type === 'http_zip' || type === 'local_ingest') { + out.downloadUrl = cfg.url ? absoluteAsset(req, cfg.url) : null; + if (cfg.sha256) out.sha256 = cfg.sha256; + } else if (type === 'http_manifest') { + out.manifestUrl = absoluteAsset(req, cfg.manifestUrl || row.manifest_url); + } else if (type === 'google_drive') { + if (cfg.directDownloadUrl) { + out.downloadUrl = cfg.directDownloadUrl; + } else { + out.downloadAvailable = false; + } + } else if (type === 'mrpack') { + out.downloadUrl = cfg.url ? absoluteAsset(req, cfg.url) : null; + out.downloadAvailable = false; + out.ingest = 'planned'; + } else if (type === 'sftp') { + out.downloadAvailable = false; + } + return out; +} + +function publicServer(req, row, packRow) { + return { + id: row.id, + name: row.name, + iconUrl: absoluteAsset(req, row.icon_url), + address: row.address, + port: row.port, + kind: row.kind, + packId: row.pack_id, + minecraft: row.minecraft || packRow?.minecraft || null, + loader: row.loader || packRow?.loader || null, + requiresAccount: Boolean(row.requires_account), + status: { online: null, players: null, max: null }, + pack: packRow ? publicPack(req, packRow) : null, + }; +} + +function adminPack(row) { + const source = adminSourceView(row.source_type, row.source_config); + return { + id: row.id, + name: row.name, + minecraft: row.minecraft, + loader: row.loader, + iconUrl: row.icon_url, + description: row.description || '', + sourceType: source.type, + source: source, + manifestUrl: row.manifest_url, + published: Boolean(row.published), + createdAt: row.created_at, + updatedAt: row.updated_at, + createdBy: row.created_by, + }; +} + +function adminServer(row) { + return { + id: row.id, + name: row.name, + iconUrl: row.icon_url, + address: row.address, + port: row.port, + kind: row.kind, + packId: row.pack_id, + minecraft: row.minecraft, + loader: row.loader, + requiresAccount: Boolean(row.requires_account), + published: Boolean(row.published), + sortOrder: row.sort_order, + createdAt: row.created_at, + updatedAt: row.updated_at, + createdBy: row.created_by, + }; +} + +function readPackBody(body) { + const name = String(body.name || '').trim(); + if (name.length < 2 || name.length > 120) { + const err = new Error('Название пака: 2–120 символов'); + err.status = 400; + throw err; + } + const minecraft = String(body.minecraft || '').trim(); + if (!minecraft || minecraft.length > 32) { + const err = new Error('Укажите версию Minecraft'); + err.status = 400; + throw err; + } + const source = normalizeSource(body.sourceType || body.source?.type, body.sourceConfig || body.source?.config); + return { + name, + minecraft, + loader: validateLoader(body.loader), + iconUrl: body.iconUrl != null ? String(body.iconUrl).trim().slice(0, 500) || null : null, + description: String(body.description || '').slice(0, 2000), + source, + manifestUrl: body.manifestUrl != null ? String(body.manifestUrl).trim() || null : null, + published: asBool(body.published, true), + }; +} + +function readServerBody(body) { + const name = String(body.name || '').trim(); + if (name.length < 2 || name.length > 120) { + const err = new Error('Название сервера: 2–120 символов'); + err.status = 400; + throw err; + } + const address = String(body.address || '').trim(); + if (!address || address.length > 255 || /[\s@]/.test(address)) { + const err = new Error('Адрес: хост без пробелов и без логина'); + err.status = 400; + throw err; + } + const port = parseInt(body.port, 10); + if (!Number.isFinite(port) || port < 1 || port > 65535) { + const err = new Error('Порт: 1–65535'); + err.status = 400; + throw err; + } + return { + name, + iconUrl: body.iconUrl != null ? String(body.iconUrl).trim().slice(0, 500) || null : null, + address, + port, + kind: validateKind(body.kind), + packId: body.packId ? String(body.packId).trim() : null, + minecraft: body.minecraft != null ? String(body.minecraft).trim().slice(0, 32) || null : null, + loader: body.loader != null ? validateLoader(body.loader) : null, + requiresAccount: asBool(body.requiresAccount, false), + published: asBool(body.published, true), + sortOrder: Number.isFinite(parseInt(body.sortOrder, 10)) ? parseInt(body.sortOrder, 10) : 0, + }; +} + +function sendError(res, error, fallback) { + const status = error.status || 500; + if (status >= 500) console.error(fallback, error); + res.status(status).json({ error: status >= 500 ? fallback : error.message }); +} + +async function listPublishedPacks(req) { + const result = await db.query( + `SELECT * FROM packs WHERE published = true ORDER BY name ASC` + ); + return result.rows.map((row) => publicPack(req, row)); +} + +async function listPublishedServers(req) { + const result = await db.query( + `SELECT s.*, + p.id AS p_id, p.name AS p_name, p.minecraft AS p_minecraft, p.loader AS p_loader, + p.icon_url AS p_icon_url, p.description AS p_description, + p.source_type AS p_source_type, p.source_config AS p_source_config, + p.manifest_url AS p_manifest_url, p.published AS p_published + FROM servers s + LEFT JOIN packs p ON p.id = s.pack_id + WHERE s.published = true + ORDER BY s.sort_order ASC, s.name ASC` + ); + return result.rows.map((row) => { + const packRow = row.p_id + ? { + id: row.p_id, + name: row.p_name, + minecraft: row.p_minecraft, + loader: row.p_loader, + icon_url: row.p_icon_url, + description: row.p_description, + source_type: row.p_source_type, + source_config: row.p_source_config, + manifest_url: row.p_manifest_url, + published: row.p_published, + } + : null; + return publicServer(req, row, packRow); + }); +} + +async function getPublishedPack(req, id) { + const result = await db.query(`SELECT * FROM packs WHERE id = $1 AND published = true`, [id]); + return result.rows[0] ? publicPack(req, result.rows[0]) : null; +} + +function packManifest(req, row) { + const type = row.source_type; + const cfg = parseConfig(row.source_config); + const files = []; + if (type === 'http_manifest' && Array.isArray(cfg.files)) { + for (const file of cfg.files) { + files.push({ + path: String(file.path || file.name || 'file'), + url: file.url ? absoluteAsset(req, file.url) : null, + sha256: file.sha256 || null, + size: file.size || null, + }); + } + } else if (type === 'http_zip' || type === 'local_ingest') { + if (cfg.url) { + files.push({ + path: `${row.id}.zip`, + url: absoluteAsset(req, cfg.url), + sha256: cfg.sha256 || null, + size: cfg.size || null, + }); + } + } else if (type === 'google_drive' && cfg.directDownloadUrl) { + files.push({ + path: `${row.id}.zip`, + url: cfg.directDownloadUrl, + sha256: cfg.sha256 || null, + }); + } + return { + id: row.id, + name: row.name, + minecraft: row.minecraft, + loader: row.loader, + sourceType: type, + files, + }; +} + +packsAdmin.get('/', async (_req, res) => { + try { + const result = await db.query(`SELECT * FROM packs ORDER BY updated_at DESC, name ASC`); + res.json({ packs: result.rows.map(adminPack) }); + } catch (error) { + sendError(res, error, 'Не удалось загрузить паки'); + } +}); + +packsAdmin.post('/', async (req, res) => { + try { + const body = readPackBody(req.body); + const id = await uniqueId('packs', normalizeId(req.body.id, body.name, 'pack')); + const manifestUrl = body.manifestUrl || `/api/launcher/v1/packs/${id}/manifest`; + const result = await db.query( + `INSERT INTO packs (id, name, minecraft, loader, icon_url, description, source_type, source_config, manifest_url, published, created_by) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb,$9,$10,$11) RETURNING *`, + [ + id, + body.name, + body.minecraft, + body.loader, + body.iconUrl, + body.description, + body.source.type, + JSON.stringify(body.source.config), + manifestUrl, + body.published, + req.user.id, + ] + ); + res.status(201).json({ success: true, pack: adminPack(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось создать пак'); + } +}); + +packsAdmin.get('/:id', async (req, res) => { + try { + const result = await db.query(`SELECT * FROM packs WHERE id = $1`, [req.params.id]); + if (!result.rows[0]) return res.status(404).json({ error: 'Пак не найден' }); + res.json({ pack: adminPack(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось загрузить пак'); + } +}); + +packsAdmin.put('/:id', async (req, res) => { + try { + const existing = await db.query(`SELECT * FROM packs WHERE id = $1`, [req.params.id]); + if (!existing.rows[0]) return res.status(404).json({ error: 'Пак не найден' }); + const prev = existing.rows[0]; + const merged = { + name: req.body.name !== undefined ? req.body.name : prev.name, + minecraft: req.body.minecraft !== undefined ? req.body.minecraft : prev.minecraft, + loader: req.body.loader !== undefined ? req.body.loader : prev.loader, + iconUrl: req.body.iconUrl !== undefined ? req.body.iconUrl : prev.icon_url, + description: req.body.description !== undefined ? req.body.description : prev.description, + sourceType: req.body.sourceType || req.body.source?.type || prev.source_type, + sourceConfig: req.body.sourceConfig || req.body.source?.config || prev.source_config, + manifestUrl: req.body.manifestUrl !== undefined ? req.body.manifestUrl : prev.manifest_url, + published: req.body.published !== undefined ? req.body.published : prev.published, + }; + if (prev.source_type === 'sftp' && merged.sourceType === 'sftp') { + const nextCfg = parseConfig(merged.sourceConfig); + const prevCfg = parseConfig(prev.source_config); + if (!nextCfg.password && prevCfg.password) nextCfg.password = prevCfg.password; + merged.sourceConfig = nextCfg; + } + const body = readPackBody(merged); + const result = await db.query( + `UPDATE packs SET name=$2, minecraft=$3, loader=$4, icon_url=$5, description=$6, + source_type=$7, source_config=$8::jsonb, manifest_url=$9, published=$10, updated_at=NOW() + WHERE id=$1 RETURNING *`, + [ + req.params.id, + body.name, + body.minecraft, + body.loader, + body.iconUrl, + body.description, + body.source.type, + JSON.stringify(body.source.config), + body.manifestUrl, + body.published, + ] + ); + res.json({ success: true, pack: adminPack(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось обновить пак'); + } +}); + +packsAdmin.delete('/:id', async (req, res) => { + try { + const result = await db.query( + `DELETE FROM packs WHERE id = $1 RETURNING id, source_type, source_config`, + [req.params.id] + ); + if (!result.rows[0]) return res.status(404).json({ error: 'Пак не найден' }); + const config = parseConfig(result.rows[0].source_config); + if (result.rows[0].source_type === 'local_ingest' || /^\/uploads\/packs\//.test(config.url || '')) { + const fileName = path.basename(String(config.url || '')); + if (fileName) { + await fs.promises.unlink(path.join(ingestDir, fileName)).catch(() => {}); + } + } + res.json({ success: true }); + } catch (error) { + sendError(res, error, 'Не удалось удалить пак'); + } +}); + +const ingestUpload = multer({ + storage: multer.diskStorage({ + destination: async (_req, _file, cb) => { + try { + await fs.promises.mkdir(ingestDir, { recursive: true }); + cb(null, ingestDir); + } catch (error) { + cb(error); + } + }, + filename: (req, file, cb) => { + const safe = String(req.params.id || 'pack').replace(/[^a-z0-9-]/gi, ''); + cb(null, `${safe}-${Date.now()}.zip`); + }, + }), + limits: { fileSize: 50 * 1024 * 1024 }, + fileFilter: (_req, file, cb) => { + const name = String(file.originalname || '').toLowerCase(); + if (!name.endsWith('.zip') && !name.endsWith('.mrpack')) { + cb(new Error('Нужен .zip или .mrpack')); + return; + } + cb(null, true); + }, +}); + +packsAdmin.post( + '/:id/ingest', + (req, res, next) => { + if (!ID_RE.test(String(req.params.id || ''))) { + return res.status(400).json({ error: 'Некорректный id пака' }); + } + next(); + }, + ingestUpload.single('archive'), + async (req, res) => { + try { + const existing = await db.query(`SELECT * FROM packs WHERE id = $1`, [req.params.id]); + if (!existing.rows[0]) return res.status(404).json({ error: 'Пак не найден' }); + if (!req.file) return res.status(400).json({ error: 'Приложите zip (поле archive), до 50 МБ' }); + const bytes = await fs.promises.readFile(req.file.path); + const sha256 = crypto.createHash('sha256').update(bytes).digest('hex'); + const isMrpack = String(req.file.originalname || '').toLowerCase().endsWith('.mrpack'); + const finalName = `${req.params.id}.${isMrpack ? 'mrpack' : 'zip'}`; + const finalPath = path.join(ingestDir, finalName); + await fs.promises.rename(req.file.path, finalPath); + const url = `/uploads/packs/${finalName}`; + const result = await db.query( + `UPDATE packs SET source_type=$2, source_config=$3::jsonb, manifest_url=$4, updated_at=NOW() + WHERE id=$1 RETURNING *`, + [ + req.params.id, + isMrpack ? 'mrpack' : 'http_zip', + JSON.stringify({ url, sha256, size: bytes.length, ingest: isMrpack ? 'planned' : 'local' }), + `/api/launcher/v1/packs/${req.params.id}/manifest`, + ] + ); + res.json({ + success: true, + pack: adminPack(result.rows[0]), + downloadUrl: url, + sha256, + note: 'Файл на этом сайте. Для 2 ГБ склада задайте http_zip URL мини-ПК вручную.', + }); + } catch (error) { + if (req.file?.path) fs.promises.unlink(req.file.path).catch(() => {}); + sendError(res, error, 'Не удалось принять архив'); + } +}); + +serversAdmin.get('/', async (_req, res) => { + try { + const result = await db.query(`SELECT * FROM servers ORDER BY sort_order ASC, name ASC`); + res.json({ servers: result.rows.map(adminServer) }); + } catch (error) { + sendError(res, error, 'Не удалось загрузить серверы'); + } +}); + +serversAdmin.post('/', async (req, res) => { + try { + const body = readServerBody(req.body); + const id = await uniqueId('servers', normalizeId(req.body.id, body.name, 'server')); + if (body.packId) { + const pack = await db.query(`SELECT id FROM packs WHERE id = $1`, [body.packId]); + if (!pack.rows[0]) return res.status(400).json({ error: 'Пак не найден' }); + } + const result = await db.query( + `INSERT INTO servers (id, name, icon_url, address, port, kind, pack_id, minecraft, loader, requires_account, published, sort_order, created_by) + VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING *`, + [ + id, + body.name, + body.iconUrl, + body.address, + body.port, + body.kind, + body.packId, + body.minecraft, + body.loader, + body.requiresAccount, + body.published, + body.sortOrder, + req.user.id, + ] + ); + res.status(201).json({ success: true, server: adminServer(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось создать сервер'); + } +}); + +serversAdmin.get('/:id', async (req, res) => { + try { + const result = await db.query(`SELECT * FROM servers WHERE id = $1`, [req.params.id]); + if (!result.rows[0]) return res.status(404).json({ error: 'Сервер не найден' }); + res.json({ server: adminServer(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось загрузить сервер'); + } +}); + +serversAdmin.put('/:id', async (req, res) => { + try { + const existing = await db.query(`SELECT * FROM servers WHERE id = $1`, [req.params.id]); + if (!existing.rows[0]) return res.status(404).json({ error: 'Сервер не найден' }); + const prev = existing.rows[0]; + const body = readServerBody({ + name: req.body.name !== undefined ? req.body.name : prev.name, + iconUrl: req.body.iconUrl !== undefined ? req.body.iconUrl : prev.icon_url, + address: req.body.address !== undefined ? req.body.address : prev.address, + port: req.body.port !== undefined ? req.body.port : prev.port, + kind: req.body.kind !== undefined ? req.body.kind : prev.kind, + packId: req.body.packId !== undefined ? req.body.packId : prev.pack_id, + minecraft: req.body.minecraft !== undefined ? req.body.minecraft : prev.minecraft, + loader: req.body.loader !== undefined ? req.body.loader : prev.loader, + requiresAccount: req.body.requiresAccount !== undefined ? req.body.requiresAccount : prev.requires_account, + published: req.body.published !== undefined ? req.body.published : prev.published, + sortOrder: req.body.sortOrder !== undefined ? req.body.sortOrder : prev.sort_order, + }); + if (body.packId) { + const pack = await db.query(`SELECT id FROM packs WHERE id = $1`, [body.packId]); + if (!pack.rows[0]) return res.status(400).json({ error: 'Пак не найден' }); + } + const result = await db.query( + `UPDATE servers SET name=$2, icon_url=$3, address=$4, port=$5, kind=$6, pack_id=$7, + minecraft=$8, loader=$9, requires_account=$10, published=$11, sort_order=$12, updated_at=NOW() + WHERE id=$1 RETURNING *`, + [ + req.params.id, + body.name, + body.iconUrl, + body.address, + body.port, + body.kind, + body.packId, + body.minecraft, + body.loader, + body.requiresAccount, + body.published, + body.sortOrder, + ] + ); + res.json({ success: true, server: adminServer(result.rows[0]) }); + } catch (error) { + sendError(res, error, 'Не удалось обновить сервер'); + } +}); + +serversAdmin.delete('/:id', async (req, res) => { + try { + const result = await db.query(`DELETE FROM servers WHERE id = $1 RETURNING id`, [req.params.id]); + if (!result.rows[0]) return res.status(404).json({ error: 'Сервер не найден' }); + res.json({ success: true }); + } catch (error) { + sendError(res, error, 'Не удалось удалить сервер'); + } +}); + +async function ensureCatalogSchema() { + await db.query(` + CREATE TABLE IF NOT EXISTS public.packs ( + id TEXT PRIMARY KEY, + name VARCHAR(120) NOT NULL, + minecraft VARCHAR(32) NOT NULL, + loader VARCHAR(32) NOT NULL DEFAULT 'vanilla', + icon_url TEXT, + description TEXT NOT NULL DEFAULT '', + source_type VARCHAR(32) NOT NULL DEFAULT 'http_zip', + source_config JSONB NOT NULL DEFAULT '{}'::jsonb, + manifest_url TEXT, + published BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + created_by INTEGER + ) + `); + await db.query(` + CREATE TABLE IF NOT EXISTS public.servers ( + id TEXT PRIMARY KEY, + name VARCHAR(120) NOT NULL, + icon_url TEXT, + address VARCHAR(255) NOT NULL, + port INTEGER NOT NULL DEFAULT 25565, + kind VARCHAR(32) NOT NULL DEFAULT 'owyx', + pack_id TEXT REFERENCES public.packs(id) ON DELETE SET NULL, + minecraft VARCHAR(32), + loader VARCHAR(32), + requires_account BOOLEAN NOT NULL DEFAULT false, + published BOOLEAN NOT NULL DEFAULT true, + sort_order INTEGER NOT NULL DEFAULT 0, + created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + created_by INTEGER + ) + `); + await db.query(`CREATE INDEX IF NOT EXISTS packs_published_idx ON public.packs (published)`); + await db.query(`CREATE INDEX IF NOT EXISTS servers_published_sort_idx ON public.servers (published, sort_order, name)`); + await db.query( + `INSERT INTO public.packs ( + id, name, minecraft, loader, description, source_type, source_config, manifest_url, published + ) + SELECT + 'demo-vanilla', + 'Owyx Demo Vanilla 1.21.1', + '1.21.1', + 'vanilla', + 'Крошечный тестовый оверлей для друзей. Лаунчер ставит ваниль, затем распаковывает этот zip в game/.', + 'http_zip', + '{"url":"/fixtures/packs/demo-vanilla.zip","sha256":"b5b345b133be7e851e47ef6f0fd83c61be3abc56dfc8cacd0c6fc65790d2eadb"}'::jsonb, + '/api/launcher/v1/packs/demo-vanilla/manifest', + true + WHERE NOT EXISTS (SELECT 1 FROM public.packs WHERE id = 'demo-vanilla')` + ); + await db.query( + `INSERT INTO public.servers ( + id, name, address, port, kind, pack_id, minecraft, loader, requires_account, published, sort_order + ) + SELECT * FROM (VALUES + ('owyx-demo', 'Owyx — демо', 'play.owyx.site', 25565, 'owyx', 'demo-vanilla', '1.21.1', 'vanilla', false, true, 0), + ('owyx-friends', 'Owyx — друзья', '127.0.0.1', 25565, 'community', 'demo-vanilla', '1.21.1', 'vanilla', false, true, 10) + ) AS seed(id, name, address, port, kind, pack_id, minecraft, loader, requires_account, published, sort_order) + WHERE NOT EXISTS (SELECT 1 FROM public.servers WHERE id = seed.id)` + ); +} + +module.exports = { + packsAdmin, + serversAdmin, + publicPack, + publicServer, + packManifest, + listPublishedPacks, + listPublishedServers, + getPublishedPack, + ensureCatalogSchema, + publicBase, + absoluteAsset, +}; diff --git a/legacy/owyxsite/backend/src/routes/chat.js b/legacy/owyxsite/backend/src/routes/chat.js new file mode 100644 index 00000000000..a76b5c26223 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/chat.js @@ -0,0 +1,130 @@ +const express = require('express'); +const db = require('../database/connection'); +const { authenticateToken } = require('./auth'); + +const router = express.Router(); + +async function roomAccess(roomId, userId) { + const result = await db.query( + `SELECT r.is_private, (rm.user_id IS NOT NULL) AS is_member + FROM chat_rooms r + LEFT JOIN chat_room_members rm ON rm.room_id = r.id AND rm.user_id = $2 + WHERE r.id = $1`, + [roomId, userId] + ); + return result.rows[0] || null; +} + +// GET /api/chat/rooms — list rooms the user can see +router.get('/rooms', authenticateToken, async (req, res) => { + try { + const result = await db.query( + ` + SELECT r.id, r.name, r.slug, r.description, r.is_private, r.created_at, + ( + SELECT content FROM chat_messages m + WHERE m.room_id = r.id AND m.is_deleted = false + ORDER BY m.created_at DESC LIMIT 1 + ) AS last_message, + ( + SELECT created_at FROM chat_messages m + WHERE m.room_id = r.id AND m.is_deleted = false + ORDER BY m.created_at DESC LIMIT 1 + ) AS last_message_at + FROM chat_rooms r + LEFT JOIN chat_room_members rm ON rm.room_id = r.id AND rm.user_id = $1 + WHERE r.is_private = false OR rm.user_id IS NOT NULL + ORDER BY COALESCE( + (SELECT created_at FROM chat_messages m WHERE m.room_id = r.id ORDER BY m.created_at DESC LIMIT 1), + r.created_at + ) DESC + `, + [req.user.id] + ); + res.json({ rooms: result.rows }); + } catch (error) { + if (error.code === '42P01') { + return res.status(503).json({ + error: 'Chat tables missing. Apply owyx/postgres/migrations/001_chat.sql', + }); + } + console.error('Chat rooms error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/chat/rooms/:id/messages +router.get('/rooms/:id/messages', authenticateToken, async (req, res) => { + try { + const roomId = parseInt(req.params.id, 10); + const limit = Math.min(100, parseInt(req.query.limit, 10) || 50); + const before = req.query.before; + if (!Number.isSafeInteger(roomId) || roomId < 1) { + return res.status(400).json({ error: 'Некорректная комната' }); + } + const access = await roomAccess(roomId, req.user.id); + if (!access) return res.status(404).json({ error: 'Комната не найдена' }); + if (access.is_private && !access.is_member) { + return res.status(403).json({ error: 'Нет доступа к приватной комнате' }); + } + + const params = [roomId, limit]; + let beforeClause = ''; + if (before) { + beforeClause = 'AND m.created_at < $3'; + params.push(before); + } + + const result = await db.query( + ` + SELECT m.id, m.room_id, m.user_id, m.content, m.created_at, m.updated_at, + u.nickname, u.avatar_url, u.role, u.trust_level + FROM chat_messages m + JOIN users u ON u.id = m.user_id + WHERE m.room_id = $1 AND m.is_deleted = false ${beforeClause} + ORDER BY m.created_at DESC + LIMIT $2 + `, + params + ); + + res.json({ messages: result.rows.reverse() }); + } catch (error) { + if (error.code === '42P01') { + return res.status(503).json({ + error: 'Chat tables missing. Apply owyx/postgres/migrations/001_chat.sql', + }); + } + console.error('Chat messages error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/chat/rooms/:id/join +router.post('/rooms/:id/join', authenticateToken, async (req, res) => { + try { + const roomId = parseInt(req.params.id, 10); + if (!Number.isSafeInteger(roomId) || roomId < 1) { + return res.status(400).json({ error: 'Некорректная комната' }); + } + const access = await roomAccess(roomId, req.user.id); + if (!access) return res.status(404).json({ error: 'Комната не найдена' }); + if (access.is_private && !access.is_member) { + return res.status(403).json({ error: 'В приватную комнату нельзя войти без приглашения' }); + } + await db.query( + ` + INSERT INTO chat_room_members (room_id, user_id) + VALUES ($1, $2) + ON CONFLICT (room_id, user_id) DO NOTHING + `, + [roomId, req.user.id] + ); + res.json({ success: true }); + } catch (error) { + console.error('Chat join error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/forum.js b/legacy/owyxsite/backend/src/routes/forum.js new file mode 100644 index 00000000000..99e68bf7ad5 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/forum.js @@ -0,0 +1,235 @@ +const express = require('express'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, requireRole } = require('./auth'); + +const router = express.Router(); + +function slugify(text) { + return String(text) + .toLowerCase() + .trim() + .replace(/[^\w\s-а-яё]/gi, '') + .replace(/[\s_]+/g, '-') + .replace(/-+/g, '-') + .substring(0, 80) || `topic-${Date.now()}`; +} + +// GET /api/forum/categories +router.get('/categories', async (_req, res) => { + try { + const result = await db.query(` + SELECT id, title, slug, description, icon, color, parent_id, position, + is_locked, topics_count, posts_count, created_at + FROM forum_categories + ORDER BY position ASC NULLS LAST, id ASC + `); + res.json({ categories: result.rows }); + } catch (error) { + console.error('Forum categories error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/forum/categories/:slug/topics +router.get('/categories/:slug/topics', async (req, res) => { + try { + const page = Math.max(1, parseInt(req.query.page, 10) || 1); + const limit = Math.min(50, parseInt(req.query.limit, 10) || 20); + const offset = (page - 1) * limit; + + const cat = await db.query( + `SELECT id, title, slug, description, is_locked FROM forum_categories WHERE slug = $1`, + [req.params.slug] + ); + if (cat.rows.length === 0) { + return res.status(404).json({ error: 'Категория не найдена' }); + } + + const topics = await db.query( + ` + SELECT t.id, t.title, t.slug, t.is_pinned, t.is_locked, t.is_solved, + t.views_count, t.posts_count, t.created_at, t.last_post_at, t.tags, + u.nickname AS author_nickname, u.avatar_url AS author_avatar + FROM forum_topics t + LEFT JOIN users u ON u.id = t.author_id + WHERE t.category_id = $1 + ORDER BY t.is_pinned DESC, COALESCE(t.last_post_at, t.created_at) DESC + LIMIT $2 OFFSET $3 + `, + [cat.rows[0].id, limit, offset] + ); + + const count = await db.query( + `SELECT COUNT(*)::int AS total FROM forum_topics WHERE category_id = $1`, + [cat.rows[0].id] + ); + + res.json({ + category: cat.rows[0], + topics: topics.rows, + pagination: { + page, + limit, + total: count.rows[0].total, + totalPages: Math.ceil(count.rows[0].total / limit), + }, + }); + } catch (error) { + console.error('Forum topics error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/forum/topics/:id +router.get('/topics/:id', async (req, res) => { + try { + const topicId = parseInt(req.params.id, 10); + const topic = await db.query( + ` + SELECT t.*, c.title AS category_title, c.slug AS category_slug, + u.nickname AS author_nickname, u.avatar_url AS author_avatar + FROM forum_topics t + JOIN forum_categories c ON c.id = t.category_id + LEFT JOIN users u ON u.id = t.author_id + WHERE t.id = $1 + `, + [topicId] + ); + + if (topic.rows.length === 0) { + return res.status(404).json({ error: 'Тема не найдена' }); + } + + await db.query(`UPDATE forum_topics SET views_count = views_count + 1 WHERE id = $1`, [topicId]); + + const posts = await db.query( + ` + SELECT p.id, p.content, p.parent_post_id, p.created_at, p.updated_at, + p.upvotes, p.downvotes, p.is_edited, p.is_deleted, + u.id AS author_id, u.nickname AS author_nickname, u.avatar_url AS author_avatar, + u.role AS author_role, u.trust_level AS author_trust_level + FROM forum_posts p + LEFT JOIN users u ON u.id = p.author_id + WHERE p.topic_id = $1 AND p.is_deleted = false + ORDER BY p.created_at ASC + `, + [topicId] + ); + + res.json({ topic: topic.rows[0], posts: posts.rows }); + } catch (error) { + console.error('Forum topic detail error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/forum/topics +router.post( + '/topics', + authenticateToken, + body('category_id').isInt(), + body('title').isLength({ min: 3, max: 200 }), + body('content').isLength({ min: 10, max: 20000 }), + async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ error: 'Ошибка валидации', details: errors.array() }); + } + + const { category_id, title, content, tags } = req.body; + const cat = await db.query( + `SELECT id, is_locked FROM forum_categories WHERE id = $1`, + [category_id] + ); + if (cat.rows.length === 0) { + return res.status(404).json({ error: 'Категория не найдена' }); + } + if (cat.rows[0].is_locked && !['admin', 'moderator'].includes(req.user.role)) { + return res.status(403).json({ error: 'Категория закрыта для новых тем' }); + } + + let slug = slugify(title); + const slugCheck = await db.query(`SELECT id FROM forum_topics WHERE slug = $1`, [slug]); + if (slugCheck.rows.length > 0) slug = `${slug}-${Date.now()}`; + + const topic = await db.query( + ` + INSERT INTO forum_topics (category_id, title, slug, content, author_id, tags) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING * + `, + [category_id, title, slug, content, req.user.id, tags ? JSON.stringify(tags) : null] + ); + + await db.query( + ` + INSERT INTO forum_posts (topic_id, author_id, content) + VALUES ($1, $2, $3) + `, + [topic.rows[0].id, req.user.id, content] + ); + + res.status(201).json({ success: true, topic: topic.rows[0] }); + } catch (error) { + console.error('Create topic error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } + } +); + +// POST /api/forum/topics/:id/posts +router.post( + '/topics/:id/posts', + authenticateToken, + body('content').isLength({ min: 1, max: 20000 }), + async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ error: 'Ошибка валидации', details: errors.array() }); + } + + const topicId = parseInt(req.params.id, 10); + const topic = await db.query(`SELECT id, is_locked FROM forum_topics WHERE id = $1`, [topicId]); + if (topic.rows.length === 0) { + return res.status(404).json({ error: 'Тема не найдена' }); + } + if (topic.rows[0].is_locked && !['admin', 'moderator'].includes(req.user.role)) { + return res.status(403).json({ error: 'Тема закрыта' }); + } + + const post = await db.query( + ` + INSERT INTO forum_posts (topic_id, author_id, content, parent_post_id) + VALUES ($1, $2, $3, $4) + RETURNING * + `, + [topicId, req.user.id, req.body.content, req.body.parent_post_id || null] + ); + + res.status(201).json({ success: true, post: post.rows[0] }); + } catch (error) { + console.error('Create post error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } + } +); + +// DELETE /api/forum/topics/:id (moderation) +router.delete('/topics/:id', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + await db.query(`DELETE FROM forum_topics WHERE id = $1`, [req.params.id]); + await db.query( + `INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)`, + [req.user.id, 'forum_moderate_delete', `Topic ID: ${req.params.id}`] + ); + res.json({ success: true }); + } catch (error) { + console.error('Delete topic error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/launcher.js b/legacy/owyxsite/backend/src/routes/launcher.js new file mode 100644 index 00000000000..b2f2948801c --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/launcher.js @@ -0,0 +1,200 @@ +const express = require('express'); +const router = express.Router(); +const db = require('../database/connection'); +const { authenticateToken } = require('./auth'); +const catalog = require('./catalog'); + +// Owyx launcher API. +// +// Product model: playing is OPEN. Applications ("заявки") are no longer a gate. +// A normal, active, non-banned account can play. Ban still blocks everything. +// +// Versioned surface lives under /api/launcher/v1/*. Catalogs (servers/packs) +// are real rows from the site control-plane — not empty stubs. + +const LAUNCHER_API_VERSION = '1.1.0'; + +/** Absolute base URL the launcher can use to download static assets (skins). + * Built from the request the launcher made (its own API base), so it works in + * dev (direct :3001) and behind a reverse proxy in prod (Host = public domain). + * Set API_PUBLIC_URL only to force a specific base. */ +function publicBase(req) { + const fromEnv = (process.env.API_PUBLIC_URL || '').trim(); + if (fromEnv) return fromEnv.replace(/\/+$/, ''); + return `${req.protocol}://${req.get('host')}`; +} + +/** Turn a stored `/uploads/...` path into an absolute URL for the launcher. */ +function absoluteAsset(req, value) { + if (!value) return null; + if (/^https?:\/\//i.test(value)) return value; + return `${publicBase(req)}${value.startsWith('/') ? '' : '/'}${value}`; +} + +/** Build the launcher-facing view of a user row. */ +function buildMe(req, user) { + const banned = Boolean(user.is_banned); + const active = user.is_active !== false; + const emailVerified = Boolean(user.is_email_verified); + + return { + user: { + id: user.id, + nickname: user.nickname, + email: user.email, + role: user.role || 'user', + trustLevel: user.trust_level ?? 0, + banned, + emailVerified, + registeredAt: user.registered_at, + }, + // Open access: any active, non-banned account may play. No application needed. + serverAccess: active && !banned, + // Why access is or isn't granted — human-readable, launcher shows it as-is. + accessReason: banned + ? 'banned' + : !active + ? 'inactive' + : 'ok', + cosmetics: { + skinUrl: absoluteAsset(req, user.skin_url), + skinModel: user.skin_model || 'classic', + capeUrl: absoluteAsset(req, user.cape_url), + }, + // Convenience mirror of the skin for older launcher builds. + skinUrl: absoluteAsset(req, user.skin_url), + // DEPRECATED: applications ("заявки") are no longer part of the product. + // Always null now; kept in the response shape for one transition release. + application: null, + }; +} + +// GET /api/launcher/me — profile for the signed-in launcher user (open access). +router.get('/me', authenticateToken, async (req, res) => { + try { + res.json(buildMe(req, req.user)); + } catch (error) { + console.error('launcher/me error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// Versioned alias so the launcher can pin /v1/me. +router.get('/v1/me', authenticateToken, async (req, res) => { + try { + res.json(buildMe(req, req.user)); + } catch (error) { + console.error('launcher/v1/me error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/launcher/v1/status — public: launcher discovers the API and access model. +router.get('/v1/status', (_req, res) => { + res.json({ + api: 'owyx-launcher', + version: LAUNCHER_API_VERSION, // launcher-facing API surface version + siteVersion: '0.1.0', // Owyx site UI version + // "open" = play without an approved application; ban still blocks. + serverAccessModel: 'open', + auth: { + login: '/api/auth/login', + me: '/api/launcher/me', + }, + modules: ['servers', 'packs', 'news', 'cosmetics', 'adminCatalog'], + }); +}); + +// GET /api/launcher/v1/servers — published Owyx + community servers. +// Bearer optional: requiresAccount is a Play gate in the launcher, not a list filter. +router.get('/v1/servers', async (req, res) => { + try { + const servers = await catalog.listPublishedServers(req); + res.json({ servers }); + } catch (error) { + console.error('launcher/v1/servers error:', error); + res.status(500).json({ error: 'Не удалось загрузить серверы' }); + } +}); + +// GET /api/launcher/v1/packs — published builds (safe player fields only). +router.get('/v1/packs', async (req, res) => { + try { + const packs = await catalog.listPublishedPacks(req); + res.json({ packs }); + } catch (error) { + console.error('launcher/v1/packs error:', error); + res.status(500).json({ error: 'Не удалось загрузить сборки' }); + } +}); + +// GET /api/launcher/v1/packs/:id — one published pack. +router.get('/v1/packs/:id', async (req, res) => { + try { + const pack = await catalog.getPublishedPack(req, req.params.id); + if (!pack) return res.status(404).json({ error: 'Пак не найден' }); + res.json({ pack }); + } catch (error) { + console.error('launcher/v1/packs/:id error:', error); + res.status(500).json({ error: 'Не удалось загрузить пак' }); + } +}); + +// GET /api/launcher/v1/packs/:id/manifest — file list + sha (no SFTP secrets). +router.get('/v1/packs/:id/manifest', async (req, res) => { + try { + const result = await db.query( + `SELECT * FROM packs WHERE id = $1 AND published = true`, + [req.params.id] + ); + if (!result.rows[0]) return res.status(404).json({ error: 'Пак не найден' }); + res.json(catalog.packManifest(req, result.rows[0])); + } catch (error) { + console.error('launcher/v1/packs/:id/manifest error:', error); + res.status(500).json({ error: 'Не удалось загрузить манифест' }); + } +}); + +// GET /api/launcher/v1/news — same published news as the site home. +router.get('/v1/news', async (req, res) => { + try { + const limit = Math.min(parseInt(req.query.limit, 10) || 12, 50); + const result = await db.query( + `SELECT id, title, tag, summary, published, created_at, updated_at + FROM news WHERE published = true + ORDER BY created_at DESC LIMIT $1`, + [limit] + ); + res.json({ + news: result.rows.map((r) => ({ + id: r.id, + title: r.title, + tag: r.tag, + summary: r.summary, + publishedAt: r.created_at, + updatedAt: r.updated_at, + })), + }); + } catch (error) { + console.error('launcher/v1/news error:', error); + res.status(500).json({ error: 'Не удалось загрузить новости' }); + } +}); + +// GET /api/launcher/v1/cosmetics — cosmetics of the signed-in user. +router.get('/v1/cosmetics', authenticateToken, async (req, res) => { + try { + const u = req.user; + res.json({ + skinUrl: absoluteAsset(req, u.skin_url), + skinModel: u.skin_model || 'classic', + capeUrl: absoluteAsset(req, u.cape_url), + updatedAt: u.cosmetics_updated_at || null, + }); + } catch (error) { + console.error('launcher/v1/cosmetics error:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/news.js b/legacy/owyxsite/backend/src/routes/news.js new file mode 100644 index 00000000000..e6ddaae7db3 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/news.js @@ -0,0 +1,117 @@ +const express = require('express'); +const db = require('../database/connection'); +const { authenticateToken, requireRole } = require('./auth'); + +// News/updates. Public read of published items; admin CRUD. +// Mounted: app.use('/api/news', router) and app.use('/api/admin/news', adminRouter) + +const router = express.Router(); +const adminRouter = express.Router(); + +function mapRow(r) { + return { + id: r.id, + title: r.title, + tag: r.tag, + summary: r.summary, + published: r.published, + created_at: r.created_at, + updated_at: r.updated_at, + }; +} + +// GET /api/news — public list of published items (newest first). +router.get('/', async (req, res) => { + try { + const limit = Math.min(parseInt(req.query.limit, 10) || 12, 50); + const result = await db.query( + `SELECT id, title, tag, summary, published, created_at, updated_at + FROM news WHERE published = true + ORDER BY created_at DESC LIMIT $1`, + [limit] + ); + res.json({ news: result.rows.map(mapRow) }); + } catch (error) { + console.error('news list error:', error); + res.status(500).json({ error: 'Не удалось загрузить новости' }); + } +}); + +// --- Admin CRUD (/api/admin/news) --- +adminRouter.use(authenticateToken, requireRole(['admin'])); + +// GET /api/admin/news — all items incl. unpublished. +adminRouter.get('/', async (_req, res) => { + try { + const result = await db.query( + `SELECT id, title, tag, summary, published, created_at, updated_at + FROM news ORDER BY created_at DESC LIMIT 100` + ); + res.json({ news: result.rows.map(mapRow) }); + } catch (error) { + console.error('admin news list error:', error); + res.status(500).json({ error: 'Не удалось загрузить новости' }); + } +}); + +// POST /api/admin/news — create. +adminRouter.post('/', async (req, res) => { + try { + const title = String(req.body.title || '').trim(); + const tag = String(req.body.tag || 'Новость').trim().slice(0, 40) || 'Новость'; + const summary = String(req.body.summary || '').trim(); + const published = req.body.published !== false; + if (title.length < 2 || title.length > 200) { + return res.status(400).json({ error: 'Заголовок 2–200 символов' }); + } + const result = await db.query( + `INSERT INTO news (title, tag, summary, published, author_id) + VALUES ($1,$2,$3,$4,$5) RETURNING *`, + [title, tag, summary, published, req.user.id] + ); + res.status(201).json({ success: true, news: mapRow(result.rows[0]) }); + } catch (error) { + console.error('admin news create error:', error); + res.status(500).json({ error: 'Не удалось создать новость' }); + } +}); + +// PUT /api/admin/news/:id — update. +adminRouter.put('/:id', async (req, res) => { + try { + const fields = []; + const values = []; + let i = 1; + if (req.body.title !== undefined) { fields.push(`title = $${i++}`); values.push(String(req.body.title).trim().slice(0, 200)); } + if (req.body.tag !== undefined) { fields.push(`tag = $${i++}`); values.push(String(req.body.tag).trim().slice(0, 40) || 'Новость'); } + if (req.body.summary !== undefined) { fields.push(`summary = $${i++}`); values.push(String(req.body.summary)); } + if (req.body.published !== undefined) { fields.push(`published = $${i++}`); values.push(Boolean(req.body.published)); } + if (fields.length === 0) return res.status(400).json({ error: 'Нечего обновлять' }); + fields.push(`updated_at = NOW()`); + values.push(req.params.id); + const result = await db.query( + `UPDATE news SET ${fields.join(', ')} WHERE id = $${i} RETURNING *`, + values + ); + if (result.rows.length === 0) return res.status(404).json({ error: 'Новость не найдена' }); + res.json({ success: true, news: mapRow(result.rows[0]) }); + } catch (error) { + console.error('admin news update error:', error); + res.status(500).json({ error: 'Не удалось обновить новость' }); + } +}); + +// DELETE /api/admin/news/:id +adminRouter.delete('/:id', async (req, res) => { + try { + const result = await db.query('DELETE FROM news WHERE id = $1 RETURNING id', [req.params.id]); + if (result.rows.length === 0) return res.status(404).json({ error: 'Новость не найдена' }); + res.json({ success: true }); + } catch (error) { + console.error('admin news delete error:', error); + res.status(500).json({ error: 'Не удалось удалить новость' }); + } +}); + +module.exports = router; +module.exports.adminRouter = adminRouter; diff --git a/legacy/owyxsite/backend/src/routes/profile.js b/legacy/owyxsite/backend/src/routes/profile.js new file mode 100644 index 00000000000..506d0879d2b --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/profile.js @@ -0,0 +1,1175 @@ +// Маршруты профиля пользователя +// Создатель: ebluffy + +const express = require('express'); +const crypto = require('crypto'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, authenticateLongTermApiTokenOnly } = require('./auth'); +const multer = require('multer'); +const path = require('path'); +const fs = require('fs').promises; +const sharp = require('sharp'); + +const router = express.Router(); + +// Настройка multer для загрузки аватаров +const avatarStorage = multer.diskStorage({ + destination: async (req, file, cb) => { + const uploadPath = path.join(__dirname, '../../uploads/avatars'); + try { + await fs.mkdir(uploadPath, { recursive: true }); + cb(null, uploadPath); + } catch (error) { + cb(error); + } + }, + filename: (req, file, cb) => { + const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); + const extension = path.extname(file.originalname); + cb(null, `avatar-${req.user.id}-${uniqueSuffix}${extension}`); + } +}); + +const avatarUpload = multer({ + storage: avatarStorage, + limits: { + fileSize: 20 * 1024 * 1024, // 20MB + files: 1 + }, + fileFilter: (req, file, cb) => { + const allowedTypes = /jpeg|jpg|png|gif|webp/; + const extname = allowedTypes.test(path.extname(file.originalname).toLowerCase()); + const mimetype = allowedTypes.test(file.mimetype); + + if (mimetype && extname) { + return cb(null, true); + } else { + cb(new Error('Разрешены только изображения (JPEG, JPG, PNG, GIF, WebP). Максимальный размер: 20MB')); + } + } +}); + +// Multer for Minecraft skin uploads. Skins are small PNG files (64x64 or the +// legacy 64x32). We keep the raw upload to a temp name, then validate with sharp. +const skinStorage = multer.diskStorage({ + destination: async (req, file, cb) => { + const uploadPath = path.join(__dirname, '../../uploads/skins'); + try { + await fs.mkdir(uploadPath, { recursive: true }); + cb(null, uploadPath); + } catch (error) { + cb(error); + } + }, + filename: (req, file, cb) => { + const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); + cb(null, `skin-${req.user.id}-${uniqueSuffix}.upload.png`); + } +}); + +const skinUpload = multer({ + storage: skinStorage, + limits: { + fileSize: 512 * 1024, // 512KB — a skin PNG is only a few KB + files: 1 + }, + fileFilter: (req, file, cb) => { + // Only PNG. We re-check the real format with sharp after upload. + const isPng = /\.png$/i.test(file.originalname) && /png/i.test(file.mimetype); + if (isPng) return cb(null, true); + cb(new Error('Скин должен быть файлом PNG')); + } +}); + +// Функция для расчета оставшегося времени бана +function calculateTimeRemaining(banUntil) { + const now = new Date(); + const until = new Date(banUntil); + const diffMs = until.getTime() - now.getTime(); + + if (diffMs <= 0) { + return { expired: true }; + } + + const days = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + const hours = Math.floor((diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); + const minutes = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60)); + + return { + expired: false, + total_minutes: Math.floor(diffMs / (1000 * 60)), + days, + hours, + minutes, + formatted: `${days > 0 ? days + 'д ' : ''}${hours > 0 ? hours + 'ч ' : ''}${minutes}м` + }; +} + +// GET /api/profile/detailed-stats - Получение упрощенной статистики игрока +router.get('/detailed-stats', authenticateToken, async (req, res) => { + try { + // Получаем базовую статистику + const statsResult = await db.query(` + SELECT + ps.time_played_minutes, + ps.last_seen, + ps.deaths_count, + ps.mobs_killed, + u.nickname, + u.registered_at, + u.last_login + FROM player_stats ps + JOIN users u ON ps.user_id = u.id + WHERE ps.user_id = $1 + `, [req.user.id]); + + if (statsResult.rows.length === 0) { + return res.status(404).json({ error: 'Статистика не найдена' }); + } + + const stats = statsResult.rows[0]; + + // Вычисляем статистику + const totalPlaytime = stats.time_played_minutes || 0; + const playtimeHours = Math.floor(totalPlaytime / 60); + const playtimeMinutes = totalPlaytime % 60; + + res.json({ + success: true, + stats: { + // Основная статистика - только то что нужно + total_playtime_minutes: totalPlaytime, + total_playtime_hours: playtimeHours, + total_playtime_formatted: `${playtimeHours}ч ${playtimeMinutes}м`, + + // Последний вход + last_seen: stats.last_seen, + + // Игровая статистика - только убийства и смерти + deaths_count: stats.deaths_count || 0, + mobs_killed: stats.mobs_killed || 0 + } + }); + + } catch (error) { + console.error('Ошибка получения статистики:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + + + +// POST /api/profile/update-stats - Обновление статистики с сервера Minecraft (только для плагина) +router.post('/update-stats', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { minecraft_nick, stats = {}, increment_login = false } = req.body; + + if (!minecraft_nick || typeof stats !== 'object' || Array.isArray(stats)) { + return res.status(400).json({ error: 'Отсутствуют обязательные поля' }); + } + + // Находим пользователя по никнейму Minecraft + const userResult = await db.query(` + SELECT u.id, u.nickname + FROM users u + WHERE LOWER(u.nickname) = LOWER($1) AND u.is_active = true AND u.is_banned = false + `, [minecraft_nick]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + const nonNegativeInt = (value, field) => { + if (value === undefined || value === null) return null; + const parsed = Number(value); + if (!Number.isSafeInteger(parsed) || parsed < 0) { + const err = new Error(`${field}: нужно целое число >= 0`); + err.status = 400; + throw err; + } + return parsed; + }; + const playtime = nonNegativeInt(stats.time_played_minutes, 'time_played_minutes'); + const deaths = nonNegativeInt(stats.deaths_count ?? stats.deaths, 'deaths_count'); + const kills = nonNegativeInt(stats.mobs_killed ?? stats.mob_kills, 'mobs_killed'); + const lastSeen = stats.last_seen || null; + if (lastSeen && Number.isNaN(Date.parse(lastSeen))) { + return res.status(400).json({ error: 'last_seen: некорректная дата' }); + } + const loginIncrement = increment_login || stats.increment_login ? 1 : 0; + + await db.query(` + INSERT INTO player_stats ( + user_id, time_played_minutes, last_seen, deaths_count, mobs_killed, + total_logins, stats_last_updated, created_at, updated_at + ) VALUES ( + $1, COALESCE($2, 0), COALESCE($3::timestamp, NOW()), + COALESCE($4, 0), COALESCE($5, 0), $6, NOW(), NOW(), NOW() + ) + ON CONFLICT (user_id) DO UPDATE SET + time_played_minutes = COALESCE($2, player_stats.time_played_minutes), + last_seen = COALESCE($3::timestamp, player_stats.last_seen), + deaths_count = COALESCE($4, player_stats.deaths_count), + mobs_killed = COALESCE($5, player_stats.mobs_killed), + total_logins = COALESCE(player_stats.total_logins, 0) + $6, + stats_last_updated = NOW(), + updated_at = NOW() + `, [user.id, playtime, lastSeen, deaths, kills, loginIncrement]); + + res.json({ + success: true, + message: `Статистика игрока ${minecraft_nick} обновлена`, + user_id: user.id + }); + + } catch (error) { + console.error('Ошибка обновления статистики:', error); + res.status(error.status || 500).json({ + error: error.status ? error.message : 'Ошибка сервера' + }); + } +}); + +// Функция для форматирования минут в читаемый формат +function formatMinutesToTime(minutes) { + if (!minutes || minutes === 0) return '0м'; + + const hours = Math.floor(minutes / 60); + const mins = minutes % 60; + + if (hours === 0) return `${mins}м`; + if (mins === 0) return `${hours}ч`; + return `${hours}ч ${mins}м`; +} + +// GET /api/profile - Получение данных профиля +router.get('/', authenticateToken, async (req, res) => { + try { + // Получаем основные данные пользователя - упрощенно + const userResult = await db.query(` + SELECT u.id, u.nickname, u.first_name, u.email, u.role, + u.discord_username, u.trust_level, u.bio, u.avatar_url, + u.age, u.is_email_verified, u.is_banned, u.status, + u.ban_reason, u.ban_until, u.last_login, u.registered_at, + u.skin_url, u.skin_model, u.cape_url, u.cosmetics_updated_at, u.nickname_changed_at, + ps.time_played_minutes, ps.last_seen, ps.deaths_count, ps.mobs_killed, ps.total_logins, + ur.reputation_score + FROM users u + LEFT JOIN player_stats ps ON u.id = ps.user_id + LEFT JOIN user_reputation ur ON u.id = ur.user_id + WHERE u.id = $1 AND u.is_active = true + `, [req.user.id]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + + // Получаем последнюю активность + const activityResult = await db.query(` + SELECT activity_type, description, created_at + FROM user_activity + WHERE user_id = $1 + ORDER BY created_at DESC + LIMIT 10 + `, [req.user.id]); + + // Если активности нет, создадим базовую запись + if (activityResult.rows.length === 0) { + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description, created_at) + VALUES ($1, 'registration', 'Регистрация на сайте', $2) + `, [req.user.id, user.registered_at]); + + // Получаем активность снова + const newActivityResult = await db.query(` + SELECT activity_type, description, created_at + FROM user_activity + WHERE user_id = $1 + ORDER BY created_at DESC + LIMIT 10 + `, [req.user.id]); + + activityResult.rows = newActivityResult.rows; + } + + // Достижения убраны - слишком сложно реализовать корректно + // const achievementsResult = { rows: [] }; + + // Получаем репутацию убрана - упрощаем + // const reputationResult = { rows: [] }; + // const reputation = { reputation_score: 0, positive_votes: 0, negative_votes: 0 }; + + // Формируем упрощенную статистику - только основное + const stats = { + playtime: user.time_played_minutes || 0, + days_registered: Math.floor((new Date() - new Date(user.registered_at)) / (1000 * 60 * 60 * 24)), + last_seen: user.last_seen, + deaths_count: user.deaths_count || 0, + mobs_killed: user.mobs_killed || 0, + total_logins: user.total_logins || 0 + }; + + // Формируем прогресс Trust Level + const trustProgress = { + current: user.trust_level || 0, + required: getTrustLevelRequirements(user.trust_level || 0), + type: 'минут игры', + reputation: user.reputation_score || 0 + }; + + // Applications ("заявки") are no longer part of the product. Kept as + // null in the response for one transition release so older clients that + // read `application` don't crash. + const application = null; + + res.json({ + id: user.id, + minecraft_nick: user.nickname, + display_name: user.nickname, + first_name: user.first_name, + age: user.age, + email: user.email, + discord: user.discord_username, + bio: user.bio, + role: user.role || 'user', + trust_level: user.trust_level || 0, + trust_level_name: getTrustLevelName(user.trust_level || 0), + is_email_verified: user.is_email_verified, + is_banned: user.is_banned || false, + ban_info: user.is_banned ? { + reason: user.ban_reason, + until: user.ban_until, + is_permanent: !user.ban_until, + time_remaining: user.ban_until ? calculateTimeRemaining(user.ban_until) : null + } : null, + status: user.status || 'active', + avatar_url: user.avatar_url, + cosmetics: { + skin_url: user.skin_url || null, + skin_model: user.skin_model || 'classic', + cape_url: user.cape_url || null, + updated_at: user.cosmetics_updated_at || null + }, + nickname_changed_at: user.nickname_changed_at || null, + registered_at: user.registered_at, + last_login: user.last_login, + stats, + trust_progress: trustProgress, + activity: activityResult.rows, + // achievements убраны - слишком сложно реализовать корректно + application, + player_stats: { + time_played_minutes: user.time_played_minutes || 0, + last_seen: user.last_seen, + deaths_count: user.deaths_count || 0, + mobs_killed: user.mobs_killed || 0, + total_logins: user.total_logins || 0 + } + }); + + } catch (error) { + console.error('Ошибка получения профиля:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// PUT /api/profile - Обновление профиля +router.put('/', [ + authenticateToken, + body('first_name').optional().isLength({ max: 50 }), + body('age').optional().isInt({ min: 10, max: 120 }), + body('discord_username').optional().isLength({ max: 100 }), + body('bio').optional().isLength({ max: 1000 }), + body('current_password').optional().isLength({ min: 1 }), + body('new_password').optional().isLength({ min: 8 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { first_name, age, discord_username, bio, current_password, new_password } = req.body; + if (req.body.email !== undefined) { + return res.status(400).json({ + error: 'Используйте /api/profile/email/request и /email/confirm для смены почты' + }); + } + const updateFields = []; + const updateValues = []; + let paramIndex = 1; + + // Проверка смены пароля + if (new_password) { + if (!current_password) { + return res.status(400).json({ + error: 'Для смены пароля необходимо указать текущий пароль' + }); + } + + // Получаем текущий пароль пользователя + const userResult = await db.query( + 'SELECT password_hash FROM users WHERE id = $1', + [req.user.id] + ); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + // Проверяем текущий пароль + const bcrypt = require('bcryptjs'); + const isCurrentPasswordValid = await bcrypt.compare(current_password, userResult.rows[0].password_hash); + + if (!isCurrentPasswordValid) { + return res.status(400).json({ + error: 'Неверный текущий пароль' + }); + } + + // Хешируем новый пароль + const saltRounds = 12; + const hashedNewPassword = await bcrypt.hash(new_password, saltRounds); + + updateFields.push(`password_hash = $${paramIndex++}`); + updateValues.push(hashedNewPassword); + } + + // Строим динамический запрос обновления остальных полей + if (first_name !== undefined) { + updateFields.push(`first_name = $${paramIndex++}`); + updateValues.push(first_name); + } + if (age !== undefined) { + updateFields.push(`age = $${paramIndex++}`); + updateValues.push(age); + } + if (discord_username !== undefined) { + updateFields.push(`discord_username = $${paramIndex++}`); + updateValues.push(discord_username); + } + if (bio !== undefined) { + updateFields.push(`bio = $${paramIndex++}`); + updateValues.push(bio); + } + + if (updateFields.length === 0) { + return res.status(400).json({ error: 'Нет данных для обновления' }); + } + + updateValues.push(req.user.id); + + const updateQuery = ` + UPDATE users + SET ${updateFields.join(', ')} + WHERE id = $${paramIndex} AND is_active = true + RETURNING id, nickname, email, first_name, age, discord_username, bio + `; + + const result = await db.query(updateQuery, updateValues); + + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + // Логируем действие + const actionDetails = []; + if (new_password) actionDetails.push('пароль'); + if (first_name !== undefined) actionDetails.push('имя'); + if (age !== undefined) actionDetails.push('возраст'); + if (discord_username !== undefined) actionDetails.push('Discord'); + if (bio !== undefined) actionDetails.push('биография'); + + await db.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [ + req.user.id, + 'profile_update', + `Обновлен профиль: ${actionDetails.join(', ')}`, + req.user.id + ]); + + res.json({ + success: true, + message: 'Профиль успешно обновлен', + user: result.rows[0] + }); + + } catch (error) { + console.error('Ошибка обновления профиля:', error); + + if (error.code === '23505') { // Unique constraint violation + return res.status(400).json({ + error: 'Email уже используется другим пользователем' + }); + } + + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// Legacy demo endpoint intentionally cannot verify an address. Clients must +// use the signed token flow under /api/auth/verify-email-token. +router.post('/verify-email', authenticateToken, (_req, res) => { + res.status(410).json({ + error: 'Используйте ссылку подтверждения из письма' + }); +}); + +// GET /api/profile/activity - Получение расширенной активности +router.get('/activity', authenticateToken, async (req, res) => { + try { + const page = parseInt(req.query.page) || 1; + const limit = parseInt(req.query.limit) || 20; + const offset = (page - 1) * limit; + + const result = await db.query(` + SELECT activity_type, description, metadata, created_at + FROM user_activity + WHERE user_id = $1 + ORDER BY created_at DESC + LIMIT $2 OFFSET $3 + `, [req.user.id, limit, offset]); + + // Получаем общее количество записей + const countResult = await db.query(` + SELECT COUNT(*) as total + FROM user_activity + WHERE user_id = $1 + `, [req.user.id]); + + const total = parseInt(countResult.rows[0].total); + const totalPages = Math.ceil(total / limit); + + res.json({ + activities: result.rows, + pagination: { + page, + limit, + total, + totalPages, + hasNext: page < totalPages, + hasPrev: page > 1 + } + }); + + } catch (error) { + console.error('Ошибка получения активности:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// Функция для определения требований Trust Level +function getTrustLevelRequirements(currentLevel) { + const requirements = { + 0: { time: 0, name: 'Проходимец' }, + 1: { time: 0, name: 'Новичок' }, // Только подтверждение email + 2: { time: 25*60, name: 'Проверенный' }, // 25 часов + репутация + 3: { time: 50*60, name: 'Ветеран' }, // 50 часов + репутация + }; + + return requirements[currentLevel + 1] || requirements[3]; +} + +// Функция для получения названия Trust Level на русском +function getTrustLevelName(level) { + const names = { + 0: 'Проходимец', + 1: 'Новичок', + 2: 'Проверенный', + 3: 'Ветеран', + }; + return names[level] || 'Неизвестно'; +} + +module.exports = router; + +// POST /api/profile/avatar - Загрузка аватара +router.post('/avatar', authenticateToken, avatarUpload.single('avatar'), async (req, res) => { + try { + if (!req.file) { + return res.status(400).json({ error: 'Файл не загружен' }); + } + + const originalPath = req.file.path; + + // Получаем данные о кропе если они есть + let cropData = null; + if (req.body.cropData) { + try { + cropData = JSON.parse(req.body.cropData); + } catch (e) { + console.log('Ошибка парсинга данных кропа:', e.message); + } + } + + // Проверяем размеры изображения + const metadata = await sharp(originalPath).metadata(); + + // Создаем финальное изображение + const finalFileName = `avatar-${req.user.id}-${Date.now()}-final.png`; + const finalPath = path.join(path.dirname(originalPath), finalFileName); + + let sharpInstance = sharp(originalPath); + + // Если есть данные кропа, применяем их + if (cropData) { + const { scale, rotation, flipX, offsetX, offsetY, cropSize } = cropData; + + // Вычисляем размеры для кропа + const scaledWidth = Math.round(metadata.width * scale); + const scaledHeight = Math.round(metadata.height * scale); + + // Начальная обработка: масштабирование и поворот + sharpInstance = sharpInstance.resize(scaledWidth, scaledHeight); + + if (rotation !== 0) { + sharpInstance = sharpInstance.rotate(rotation); + } + + if (flipX < 0) { + sharpInstance = sharpInstance.flop(); + } + + // Получаем метаданные после трансформаций + const processedBuffer = await sharpInstance.toBuffer(); + const processedMetadata = await sharp(processedBuffer).metadata(); + + // Вычисляем область кропа (256x256 из центра с учетом смещения) + const centerX = Math.round(processedMetadata.width / 2); + const centerY = Math.round(processedMetadata.height / 2); + const cropRadius = 128; // половина от 256 + + const cropLeft = Math.max(0, centerX - cropRadius - Math.round(offsetX)); + const cropTop = Math.max(0, centerY - cropRadius - Math.round(offsetY)); + const cropWidth = Math.min(256, processedMetadata.width - cropLeft); + const cropHeight = Math.min(256, processedMetadata.height - cropTop); + + // Применяем кроп и финальный ресайз до 512x512 + sharpInstance = sharp(processedBuffer) + .extract({ + left: cropLeft, + top: cropTop, + width: cropWidth, + height: cropHeight + }) + .resize(512, 512, { fit: 'cover' }); + } else { + // Если нет данных кропа, просто ресайзим + sharpInstance = sharpInstance.resize(512, 512, { fit: 'cover' }); + } + + // Сохраняем финальное изображение + await sharpInstance + .png({ quality: 90 }) + .toFile(finalPath); + + // Удаляем оригинальный файл + await fs.unlink(originalPath); + + const avatarUrl = `/uploads/avatars/${finalFileName}`; + + // Получаем старый аватар для удаления + const oldAvatarResult = await db.query( + 'SELECT avatar_url FROM users WHERE id = $1', + [req.user.id] + ); + + // Обновляем аватар в БД + await db.query( + 'UPDATE users SET avatar_url = $1 WHERE id = $2', + [avatarUrl, req.user.id] + ); + + // Удаляем старый аватар (если он есть и не дефолтный) + if (oldAvatarResult.rows[0]?.avatar_url && + oldAvatarResult.rows[0].avatar_url.includes('/uploads/avatars/')) { + try { + const oldPath = path.join(__dirname, '../..', oldAvatarResult.rows[0].avatar_url); + await fs.unlink(oldPath); + } catch (error) { + console.log('Не удалось удалить старый аватар:', error.message); + } + } + + // Логируем активность + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'avatar_update', 'Обновлен аватар профиля') + `, [req.user.id]); + + res.json({ + success: true, + message: 'Аватар успешно загружен', + avatar_url: avatarUrl, + original_size: `${metadata.width}x${metadata.height}`, + final_size: '512x512', + crop_applied: !!cropData + }); + + } catch (error) { + console.error('Ошибка загрузки аватара:', error); + + // Удаляем файл при ошибке + if (req.file && req.file.path) { + try { + await fs.unlink(req.file.path); + } catch (unlinkError) { + console.error('Ошибка удаления файла при ошибке:', unlinkError); + } + } + + res.status(500).json({ error: 'Ошибка загрузки аватара' }); + } +}); + +// DELETE /api/profile/avatar - Удаление аватара +router.delete('/avatar', authenticateToken, async (req, res) => { + try { + // Получаем текущий аватар + const avatarResult = await db.query( + 'SELECT avatar_url FROM users WHERE id = $1', + [req.user.id] + ); + + const currentAvatar = avatarResult.rows[0]?.avatar_url; + + // Удаляем аватар из БД + await db.query( + 'UPDATE users SET avatar_url = NULL WHERE id = $1', + [req.user.id] + ); + + // Удаляем файл аватара (если он кастомный) + if (currentAvatar && currentAvatar.includes('/uploads/avatars/')) { + try { + const avatarPath = path.join(__dirname, '../..', currentAvatar); + await fs.unlink(avatarPath); + } catch (error) { + console.log('Не удалось удалить файл аватара:', error.message); + } + } + + // Логируем активность + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'avatar_delete', 'Удален аватар профиля') + `, [req.user.id]); + + res.json({ + success: true, + message: 'Аватар успешно удален' + }); + + } catch (error) { + console.error('Ошибка удаления аватара:', error); + res.status(500).json({ error: 'Ошибка удаления аватара' }); + } +}); + +// GET /api/profile/ban-status - Проверка статуса бана +router.get('/ban-status', authenticateToken, async (req, res) => { + try { + const userResult = await db.query(` + SELECT is_banned, ban_reason, ban_until + FROM users + WHERE id = $1 + `, [req.user.id]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + + if (!user.is_banned) { + return res.json({ + is_banned: false, + message: 'Пользователь не забанен' + }); + } + + const banInfo = { + is_banned: true, + reason: user.ban_reason, + until: user.ban_until, + is_permanent: !user.ban_until + }; + + if (user.ban_until) { + const timeRemaining = calculateTimeRemaining(user.ban_until); + banInfo.time_remaining = timeRemaining; + + // Если бан истек, автоматически снимаем его + if (timeRemaining.expired) { + await db.query(` + UPDATE users + SET is_banned = FALSE, ban_reason = NULL, ban_until = NULL + WHERE id = $1 + `, [req.user.id]); + + return res.json({ + is_banned: false, + message: 'Бан автоматически снят (время истекло)' + }); + } + } + + res.json(banInfo); + + } catch (error) { + console.error('Ошибка проверки статуса бана:', error); + res.status(500).json({ error: 'Ошибка проверки статуса бана' }); + } +}); + +// --------------------------------------------------------------------------- +// Cosmetics: Minecraft skin for the Owyx account. The launcher reads skin_url / +// skin_model from GET /api/launcher/me and applies it. Capes are reserved. +// --------------------------------------------------------------------------- + +// GET /api/profile/skin - current skin/cosmetics of the signed-in user. +router.get('/skin', authenticateToken, async (req, res) => { + try { + const result = await db.query( + 'SELECT skin_url, skin_model, cape_url, cosmetics_updated_at FROM users WHERE id = $1', + [req.user.id] + ); + if (result.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + const row = result.rows[0]; + res.json({ + skin_url: row.skin_url || null, + skin_model: row.skin_model || 'classic', + cape_url: row.cape_url || null, + updated_at: row.cosmetics_updated_at || null + }); + } catch (error) { + console.error('Ошибка получения скина:', error); + res.status(500).json({ error: 'Не удалось получить скин' }); + } +}); + +// PUT /api/profile/skin - upload a new skin (PNG 64x64 or 64x32) + optional model. +router.put('/skin', authenticateToken, skinUpload.single('skin'), async (req, res) => { + let tempPath = req.file ? req.file.path : null; + try { + if (!req.file) { + return res.status(400).json({ error: 'Файл скина не загружен. Нужен PNG.' }); + } + + // Validate the real image: must be a PNG with Minecraft skin dimensions. + let metadata; + try { + metadata = await sharp(tempPath).metadata(); + } catch { + return res.status(400).json({ error: 'Файл не является корректным PNG' }); + } + + if (metadata.format !== 'png') { + return res.status(400).json({ error: 'Скин должен быть в формате PNG' }); + } + const okDims = metadata.width === 64 && (metadata.height === 64 || metadata.height === 32); + if (!okDims) { + return res.status(400).json({ + error: 'Неверный размер скина. Нужен PNG 64×64 (или старый 64×32).' + }); + } + + // Skin model: classic (Steve) or slim (Alex). + let model = String(req.body.model || 'classic').toLowerCase(); + if (model !== 'classic' && model !== 'slim') model = 'classic'; + + // Re-encode to a clean PNG (strips any non-image payload) at the final path. + const finalFileName = `skin-${req.user.id}-${Date.now()}.png`; + const finalPath = path.join(path.dirname(tempPath), finalFileName); + await sharp(tempPath).png().toFile(finalPath); + + // Remove the raw upload now that we have the clean copy. + await fs.unlink(tempPath).catch(() => {}); + tempPath = null; + + const skinUrl = `/uploads/skins/${finalFileName}`; + + // Swap the skin under a row lock so concurrent uploads can't leak/delete + // the wrong file (SELECT ... FOR UPDATE, then UPDATE, in one transaction). + const client = await db.getClient(); + let oldSkinUrl = null; + try { + await client.query('BEGIN'); + const oldResult = await client.query('SELECT skin_url FROM users WHERE id = $1 FOR UPDATE', [req.user.id]); + oldSkinUrl = oldResult.rows[0] ? oldResult.rows[0].skin_url : null; + await client.query( + 'UPDATE users SET skin_url = $1, skin_model = $2, cosmetics_updated_at = NOW() WHERE id = $3', + [skinUrl, model, req.user.id] + ); + await client.query('COMMIT'); + } catch (txErr) { + await client.query('ROLLBACK').catch(() => {}); + // The new file was written before the tx — clean it up on failure. + await fs.unlink(finalPath).catch(() => {}); + throw txErr; + } finally { + client.release(); + } + + // Delete the previous file only after a successful commit. + if (oldSkinUrl && oldSkinUrl !== skinUrl && oldSkinUrl.includes('/uploads/skins/')) { + const oldPath = path.join(__dirname, '../../', oldSkinUrl.replace(/^\//, '')); + await fs.unlink(oldPath).catch(() => {}); + } + + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'skin_update', 'Обновлён скин профиля') + `, [req.user.id]).catch(() => {}); + + res.json({ + success: true, + message: 'Скин обновлён', + skin_url: skinUrl, + skin_model: model + }); + } catch (error) { + if (tempPath) await fs.unlink(tempPath).catch(() => {}); + console.error('Ошибка загрузки скина:', error); + res.status(500).json({ error: 'Не удалось загрузить скин' }); + } +}); + +// DELETE /api/profile/skin - remove the account skin (back to default). +router.delete('/skin', authenticateToken, async (req, res) => { + const client = await db.getClient(); + let oldSkinUrl = null; + try { + await client.query('BEGIN'); + const oldResult = await client.query('SELECT skin_url FROM users WHERE id = $1 FOR UPDATE', [req.user.id]); + oldSkinUrl = oldResult.rows[0] ? oldResult.rows[0].skin_url : null; + await client.query( + 'UPDATE users SET skin_url = NULL, cosmetics_updated_at = NOW() WHERE id = $1', + [req.user.id] + ); + await client.query('COMMIT'); + } catch (error) { + await client.query('ROLLBACK').catch(() => {}); + client.release(); + console.error('Ошибка удаления скина:', error); + return res.status(500).json({ error: 'Не удалось удалить скин' }); + } + client.release(); + + if (oldSkinUrl && oldSkinUrl.includes('/uploads/skins/')) { + const oldPath = path.join(__dirname, '../../', oldSkinUrl.replace(/^\//, '')); + await fs.unlink(oldPath).catch(() => {}); + } + res.json({ success: true, message: 'Скин удалён' }); +}); + +// PUT /api/profile/nickname - change nickname, at most once per 30 days. +const NICK_COOLDOWN_DAYS = 30; +router.put('/nickname', authenticateToken, async (req, res) => { + try { + const raw = (req.body && req.body.nickname != null) ? String(req.body.nickname).trim() : ''; + if (raw.length < 3 || raw.length > 32) { + return res.status(400).json({ error: 'Ник должен быть от 3 до 32 символов' }); + } + if (!/^[a-zA-Z0-9_]+$/.test(raw)) { + return res.status(400).json({ error: 'Ник может содержать только буквы, цифры и _' }); + } + + const current = await db.query( + 'SELECT nickname, nickname_changed_at FROM users WHERE id = $1', + [req.user.id] + ); + if (current.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + const row = current.rows[0]; + + if (row.nickname === raw) { + return res.status(400).json({ error: 'Это уже ваш текущий ник' }); + } + + // 30-day cooldown. + if (row.nickname_changed_at) { + const changedAt = new Date(row.nickname_changed_at).getTime(); + const nextAllowed = changedAt + NICK_COOLDOWN_DAYS * 24 * 60 * 60 * 1000; + if (Date.now() < nextAllowed) { + const daysLeft = Math.ceil((nextAllowed - Date.now()) / (24 * 60 * 60 * 1000)); + return res.status(429).json({ + error: `Ник можно менять раз в ${NICK_COOLDOWN_DAYS} дней. Попробуйте через ${daysLeft} дн.`, + next_allowed_at: new Date(nextAllowed).toISOString() + }); + } + } + + // Uniqueness (case-insensitive). + const taken = await db.query( + 'SELECT id FROM users WHERE LOWER(nickname) = LOWER($1) AND id <> $2', + [raw, req.user.id] + ); + if (taken.rows.length > 0) { + return res.status(409).json({ error: 'Этот ник уже занят' }); + } + + await db.query( + 'UPDATE users SET nickname = $1, nickname_changed_at = NOW() WHERE id = $2', + [raw, req.user.id] + ); + + await db.query(` + INSERT INTO user_activity (user_id, activity_type, description) + VALUES ($1, 'nickname_change', $2) + `, [req.user.id, `Ник изменён на ${raw}`]).catch(() => {}); + + // Notify by email (best-effort; simulated in logs when SMTP is off). + try { + const { sendNicknameChangedEmail } = require('../utils/emailService'); + if (req.user.email) sendNicknameChangedEmail(req.user.email, row.nickname, raw).catch(() => {}); + } catch { /* ignore */ } + + res.json({ + success: true, + message: 'Ник изменён', + nickname: raw, + nickname_changed_at: new Date().toISOString() + }); + } catch (error) { + console.error('Ошибка смены ника:', error); + res.status(500).json({ error: 'Не удалось изменить ник' }); + } +}); + +// --------------------------------------------------------------------------- +// Email change: confirm a NEW address by a code sent to that new address. +// POST /api/profile/email/request { email } -> sends code to new email +// POST /api/profile/email/confirm { code } -> applies the change +// --------------------------------------------------------------------------- +const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + +router.post('/email/request', authenticateToken, async (req, res) => { + try { + const email = String(req.body.email || '').trim().toLowerCase(); + if (!EMAIL_RE.test(email) || email.length > 255) { + return res.status(400).json({ error: 'Некорректный email' }); + } + + const current = await db.query( + 'SELECT email, email_change_expires FROM users WHERE id = $1', + [req.user.id] + ); + if (current.rows.length === 0) return res.status(404).json({ error: 'Пользователь не найден' }); + if ((current.rows[0].email || '').toLowerCase() === email) { + return res.status(400).json({ error: 'Это уже ваша текущая почта' }); + } + if (current.rows[0].email_change_expires) { + const requestedAt = + new Date(current.rows[0].email_change_expires).getTime() - 15 * 60 * 1000; + const retryAfterMs = 60 * 1000 - (Date.now() - requestedAt); + if (retryAfterMs > 0) { + res.set('Retry-After', String(Math.ceil(retryAfterMs / 1000))); + return res.status(429).json({ + error: 'Подождите минуту перед повторной отправкой кода' + }); + } + } + + const taken = await db.query('SELECT id FROM users WHERE LOWER(email) = $1 AND id <> $2', [email, req.user.id]); + if (taken.rows.length > 0) return res.status(409).json({ error: 'Эта почта уже используется' }); + + const code = String(crypto.randomInt(100000, 1000000)); // 6 digits + const expires = new Date(Date.now() + 15 * 60 * 1000); + await db.query( + 'UPDATE users SET pending_email = $1, email_change_code = $2, email_change_expires = $3, email_change_attempts = 0 WHERE id = $4', + [email, code, expires, req.user.id] + ); + + let simulated = false; + try { + const { sendEmailChangeCode } = require('../utils/emailService'); + const result = await sendEmailChangeCode(email, code); + simulated = Boolean(result && result.simulated); + } catch (e) { + console.warn('email change send failed:', e.message); + simulated = true; + } + + const payload = { success: true, message: 'Код отправлен на новую почту.' }; + // Dev convenience only: echo the code when SMTP is simulated and not in prod. + if (simulated && process.env.NODE_ENV !== 'production') { + payload.devCode = code; + payload.message = 'SMTP не настроен — код показан для разработки.'; + } + res.json(payload); + } catch (error) { + console.error('Ошибка запроса смены почты:', error); + res.status(500).json({ error: 'Не удалось начать смену почты' }); + } +}); + +router.post('/email/confirm', authenticateToken, async (req, res) => { + try { + const code = String(req.body.code || '').trim(); + if (!/^\d{6}$/.test(code)) return res.status(400).json({ error: 'Введите 6-значный код' }); + + const result = await db.query( + 'SELECT pending_email, email_change_code, email_change_expires, email_change_attempts FROM users WHERE id = $1', + [req.user.id] + ); + const row = result.rows[0]; + if (!row || !row.pending_email || !row.email_change_code) { + return res.status(400).json({ error: 'Нет запроса на смену почты' }); + } + if (new Date(row.email_change_expires).getTime() < Date.now()) { + return res.status(400).json({ error: 'Код истёк — запросите новый' }); + } + + // Rate limit: block brute-forcing the 6-digit code. After 5 wrong tries + // the code is invalidated and the user must request a new one. + const MAX_EMAIL_CODE_ATTEMPTS = 5; + if ((row.email_change_attempts || 0) >= MAX_EMAIL_CODE_ATTEMPTS) { + await db.query( + 'UPDATE users SET pending_email = NULL, email_change_code = NULL, email_change_expires = NULL WHERE id = $1', + [req.user.id] + ).catch(() => {}); + return res.status(429).json({ error: 'Слишком много попыток. Запросите новый код.' }); + } + + if (row.email_change_code !== code) { + await db.query( + 'UPDATE users SET email_change_attempts = COALESCE(email_change_attempts, 0) + 1 WHERE id = $1', + [req.user.id] + ).catch(() => {}); + const left = MAX_EMAIL_CODE_ATTEMPTS - (row.email_change_attempts || 0) - 1; + return res.status(400).json({ error: `Неверный код. Осталось попыток: ${Math.max(0, left)}` }); + } + + // Re-check uniqueness at confirm time. + const taken = await db.query('SELECT id FROM users WHERE LOWER(email) = LOWER($1) AND id <> $2', [row.pending_email, req.user.id]); + if (taken.rows.length > 0) { + return res.status(409).json({ error: 'Эта почта уже используется' }); + } + + await db.query( + `UPDATE users SET email = $1, is_email_verified = true, + pending_email = NULL, email_change_code = NULL, email_change_expires = NULL, + email_change_attempts = 0 + WHERE id = $2`, + [row.pending_email, req.user.id] + ); + + res.json({ success: true, message: 'Почта изменена', email: row.pending_email }); + } catch (error) { + console.error('Ошибка подтверждения смены почты:', error); + res.status(500).json({ error: 'Не удалось подтвердить смену почты' }); + } +}); diff --git a/legacy/owyxsite/backend/src/routes/reputation.js b/legacy/owyxsite/backend/src/routes/reputation.js new file mode 100644 index 00000000000..4fa90438a58 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/reputation.js @@ -0,0 +1,213 @@ +// Маршруты для системы репутации +// Создатель: ebluffy + +const express = require('express'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, requireRole } = require('./auth'); + +const router = express.Router(); + +// GET /api/reputation/:userId - Получить репутацию пользователя +router.get('/:userId', async (req, res) => { + try { + const { userId } = req.params; + + // Получаем данные репутации + const reputationResult = await db.query(` + SELECT ur.*, u.nickname, u.trust_level + FROM user_reputation ur + JOIN users u ON ur.user_id = u.id + WHERE ur.user_id = $1 + `, [userId]); + + if (reputationResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const reputation = reputationResult.rows[0]; + + // Получаем историю изменений репутации + const historyResult = await db.query(` + SELECT rh.*, u.nickname as voter_nickname + FROM reputation_history rh + LEFT JOIN users u ON rh.voter_id = u.id + WHERE rh.user_id = $1 + ORDER BY rh.created_at DESC + LIMIT 20 + `, [userId]); + + res.json({ + reputation: { + score: reputation.reputation_score, + positive_votes: reputation.positive_votes, + negative_votes: reputation.negative_votes, + trust_level: reputation.trust_level, + nickname: reputation.nickname + }, + history: historyResult.rows + }); + + } catch (error) { + console.error('Ошибка получения репутации:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// POST /api/reputation/:userId/vote - Проголосовать за пользователя +router.post('/:userId/vote', [ + authenticateToken, + body('type').isIn(['positive', 'negative']), + body('reason').isLength({ min: 10, max: 200 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { userId } = req.params; + const { type, reason } = req.body; + const voterId = req.user.id; + + // Нельзя голосовать за себя + if (parseInt(userId) === voterId) { + return res.status(400).json({ error: 'Нельзя голосовать за себя' }); + } + + const client = await db.getClient(); + + try { + await client.query('BEGIN'); + + // Проверяем, не голосовал ли уже этот пользователь + const existingVote = await client.query(` + SELECT id FROM reputation_history + WHERE user_id = $1 AND voter_id = $2 + AND created_at > NOW() - INTERVAL '24 hours' + `, [userId, voterId]); + + if (existingVote.rows.length > 0) { + await client.query('ROLLBACK'); + return res.status(400).json({ error: 'Можно голосовать только раз в 24 часа' }); + } + + // Определяем изменение репутации + const change = type === 'positive' ? 1 : -1; + + // Записываем голос в историю + await client.query(` + INSERT INTO reputation_history (user_id, voter_id, change_amount, reason, vote_type) + VALUES ($1, $2, $3, $4, $5) + `, [userId, voterId, change, reason, type]); + + // Обновляем репутацию пользователя + const newReputationResult = await client.query(` + UPDATE user_reputation + SET + reputation_score = reputation_score + $1, + positive_votes = positive_votes + $2, + negative_votes = negative_votes + $3, + updated_at = NOW() + WHERE user_id = $4 + RETURNING reputation_score as new_reputation + `, [ + change, + type === 'positive' ? 1 : 0, + type === 'negative' ? 1 : 0, + userId + ]); + + await client.query('COMMIT'); + + res.json({ + success: true, + message: 'Голос учтен', + new_reputation: newReputationResult.rows[0].new_reputation + }); + + } catch (error) { + await client.query('ROLLBACK'); + throw error; + } finally { + client.release(); + } + + } catch (error) { + console.error('Ошибка голосования:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// PUT /api/reputation/:userId/admin - Изменить репутацию (только для админов) +router.put('/:userId/admin', [ + authenticateToken, + requireRole(['admin']), + body('change').isInt({ min: -100, max: 100 }), + body('reason').isLength({ min: 5, max: 200 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ + error: 'Ошибка валидации', + details: errors.array() + }); + } + + const { userId } = req.params; + const { change, reason } = req.body; + const adminId = req.user.id; + + const client = await db.getClient(); + + try { + await client.query('BEGIN'); + + // Записываем изменение в историю + await client.query(` + INSERT INTO reputation_history (user_id, voter_id, change_amount, reason, vote_type, is_admin_action) + VALUES ($1, $2, $3, $4, $5, true) + `, [userId, adminId, change, reason, change > 0 ? 'positive' : 'negative']); + + // Обновляем репутацию + const newReputationResult = await client.query(` + UPDATE user_reputation + SET + reputation_score = reputation_score + $1, + updated_at = NOW() + WHERE user_id = $2 + RETURNING reputation_score as new_reputation + `, [change, userId]); + + // Логируем действие админа + await client.query(` + INSERT INTO admin_logs (admin_id, action, details, target_user_id) + VALUES ($1, $2, $3, $4) + `, [adminId, 'reputation_changed', `Изменение репутации на ${change}: ${reason}`, userId]); + + await client.query('COMMIT'); + + res.json({ + success: true, + message: 'Репутация изменена', + new_reputation: newReputationResult.rows[0].new_reputation + }); + + } catch (error) { + await client.query('ROLLBACK'); + throw error; + } finally { + client.release(); + } + + } catch (error) { + console.error('Ошибка изменения репутации:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/settings.js b/legacy/owyxsite/backend/src/routes/settings.js new file mode 100644 index 00000000000..21d3b25b13c --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/settings.js @@ -0,0 +1,610 @@ +const express = require('express'); +const router = express.Router(); +const fs = require('fs').promises; +const path = require('path'); +const { + authenticateToken, + authenticateLongTermApiTokenOnly, + requireRole +} = require('./auth'); +const db = require('../database/connection'); +const { status } = require('minecraft-server-util'); + +// Публичный endpoint для получения основных настроек сервера +router.get('/settings/public', async (req, res) => { + try { + // Получаем настройки из базы данных server_settings + const result = await db.query('SELECT setting_key, setting_value FROM server_settings'); + const settings = {}; + + // Преобразуем результат в объект + result.rows.forEach(row => { + settings[row.setting_key] = row.setting_value; + }); + + // Возвращаем только публичную информацию + res.json({ + serverName: settings['server-name'] || 'Test', + serverDescription: settings['server-description'] || 'Приватный Minecraft сервер с дружелюбным сообществом', + serverIp: settings['server-ip'] || '45.131.186.146', + serverPort: settings['server-port'] || '1488', + discordInvite: settings['discord-invite'] || null, + telegramInvite: settings['telegram-invite'] || null + }); + } catch (error) { + console.error('Ошибка получения публичных настроек:', error); + // Fallback к значениям по умолчанию + res.json({ + serverName: 'Test', + serverDescription: 'Приватный Minecraft сервер с дружелюбным сообществом', + serverIp: '45.131.186.146', + serverPort: '1488', + discordInvite: null, + telegramInvite: null + }); + } +}); + +// Публичный endpoint для информации о статусе сервера +router.get('/settings/server-info', async (req, res) => { + try { + // Получаем настройки сервера из базы данных + const settingsResult = await db.query(` + SELECT setting_key, setting_value + FROM server_settings + WHERE setting_key IN ($1, $2, $3, $4, $5) + `, ['server-ip', 'server-port', 'server-name', 'server-max-players', 'server-description']); + + const settings = {}; + settingsResult.rows.forEach(row => { + settings[row.setting_key] = row.setting_value; + }); + + const serverIp = settings['server-ip'] || '45.131.186.146'; + const serverPort = parseInt(settings['server-port'] || '1488'); + const serverName = settings['server-name'] || 'Owyx'; + const maxPlayers = parseInt(settings['server-max-players'] || '50'); + + // Проверяем статус Minecraft сервера используя minecraft-server-util + let minecraftServerData = { + online: false, + version: 'Unknown', + motd: 'Server Offline', + ping: 0, + tps: 0, + players: { + online: 0, + max: maxPlayers, + list: [] + } + }; + + try { + const response = await status(serverIp, serverPort); + minecraftServerData = { + online: true, + version: response.version?.name || 'Unknown', + motd: response.motd?.clean || 'Minecraft Server', + ping: response.roundTripLatency || 0, + players: { + online: response.players?.online || 0, + max: response.players?.max || maxPlayers, + list: response.players?.sample || [] + } + }; + } catch (minecraftError) { + console.log('Minecraft сервер недоступен:', minecraftError.message); + } + + // Получаем TPS и время работы из таблицы server_status (данные от плагина) + let serverPerformanceData = { + tps: null, + uptime_seconds: null, + memory: { + max: null, + used: null, + free: null + } + }; + + try { + const statusResult = await db.query(` + SELECT tps, uptime_seconds, max_memory, used_memory, free_memory, updated_at + FROM server_status + WHERE server_ip = $1 AND server_port = $2 + AND updated_at > NOW() - INTERVAL '5 minutes' + ORDER BY updated_at DESC + LIMIT 1 + `, [serverIp, serverPort]); + + if (statusResult.rows.length > 0) { + const statusData = statusResult.rows[0]; + serverPerformanceData = { + tps: statusData.tps ? parseFloat(statusData.tps) : null, + uptime_seconds: statusData.uptime_seconds ? parseInt(statusData.uptime_seconds) : null, + memory: { + max: statusData.max_memory ? parseInt(statusData.max_memory) : null, + used: statusData.used_memory ? parseInt(statusData.used_memory) : null, + free: statusData.free_memory ? parseInt(statusData.free_memory) : null + } + }; + } + } catch (statusError) { + console.log('Ошибка получения статуса сервера из БД:', statusError.message); + } + + // Если сервер онлайн - получаем детальную информацию об игроках из БД + let enrichedPlayersList = []; + if (minecraftServerData.online && minecraftServerData.players.online > 0) { + const onlinePlayersResult = await db.query(` + SELECT + gs.nickname, + gs.player_uuid, + gs.last_login, + u.trust_level, + u.role, + ps.time_played_minutes, + ps.last_seen, + ps.minecraft_stats, + ps.current_level, + ps.achievements_count + FROM game_sessions gs + LEFT JOIN users u ON gs.user_id = u.id + LEFT JOIN player_stats ps ON u.id = ps.user_id + WHERE gs.is_active = true + AND gs.expires_at > NOW() + ORDER BY gs.last_login DESC + `); + + // Формируем список игроков с дополнительной информацией + enrichedPlayersList = onlinePlayersResult.rows.map(player => ({ + name: player.nickname, + uuid: player.player_uuid, + trust_level: player.trust_level || 0, + role: player.role || 'user', + playtime: player.time_played_minutes || 0, + last_seen: player.last_seen, + level: player.current_level || 1, + achievements: player.achievements_count || 0, + minecraft_stats: player.minecraft_stats || {}, + session_start: player.last_login + })); + } + + + res.json({ + // Статус сервера + status: minecraftServerData.online ? 'online' : 'offline', + online: minecraftServerData.online, + + // Информация о сервере + server: { + name: serverName, + ip: serverIp, + port: serverPort, + version: minecraftServerData.version, + motd: minecraftServerData.motd + }, + + // Производительность - используем данные от плагина + performance: { + ping: minecraftServerData.ping, + tps: serverPerformanceData.tps, + uptime_seconds: serverPerformanceData.uptime_seconds, + memory: serverPerformanceData.memory + }, + + // Игроки - используем реальные данные с сервера + players: { + online: minecraftServerData.players.online, + max: minecraftServerData.players.max, + list: enrichedPlayersList // Детальная информация из БД для онлайн игроков + }, + + // Дополнительная информация + timestamp: new Date().toISOString(), + last_update: new Date().toISOString() + }); + + } catch (error) { + console.error('Ошибка получения информации о сервере:', error); + res.status(500).json({ + status: 'error', + online: false, + server: { + name: 'Owyx', + ip: '45.131.186.146', + port: 1488 + }, + players: { + online: 0, + max: 50, + list: [] + }, + error: 'Ошибка сервера' + }); + } +}); + +// Получение текущих настроек (только для админов) +router.get('/settings', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + // Читаем текущий файл конфигурации + const configPath = path.join(__dirname, '../config/settings.js'); + const configContent = await fs.readFile(configPath, 'utf-8'); + + // Извлекаем текущие значения из config + const config = require('../config/settings'); + + res.json({ + success: true, + settings: { + server: config.server, + applications: config.applications, + trustLevel: config.trustLevel, + reputation: config.reputation, + security: config.security, + email: config.email + } + }); + } catch (error) { + console.error('Ошибка получения настроек:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// Обновление настроек +router.post('/settings', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { settings } = req.body; + + if (!settings) { + return res.status(400).json({ error: 'Настройки не предоставлены' }); + } + + // Читаем текущий файл + const configPath = path.join(__dirname, '../config/settings.js'); + let configContent = await fs.readFile(configPath, 'utf-8'); + + // Обновляем значения в файле конфигурации + if (settings.server) { + Object.keys(settings.server).forEach(key => { + const value = settings.server[key]; + const regex = new RegExp(`(${key}:\\s*process\\.env\\.[A-Z_]+\\s*\\|\\|\\s*['"])[^'"]*(['"])`); + if (configContent.match(regex)) { + configContent = configContent.replace(regex, `$1${value}$2`); + } + }); + } + + if (settings.applications) { + Object.keys(settings.applications).forEach(key => { + const value = settings.applications[key]; + if (typeof value === 'number') { + const regex = new RegExp(`(${key}:\\s*parseInt\\(process\\.env\\.[A-Z_]+\\)\\s*\\|\\|\\s*)\\d+`); + if (configContent.match(regex)) { + configContent = configContent.replace(regex, `$1${value}`); + } + } else if (typeof value === 'boolean') { + const regex = new RegExp(`(${key}:\\s*process\\.env\\.[A-Z_]+\\s*===\\s*'true'\\s*\\|\\|\\s*)(true|false)`); + if (configContent.match(regex)) { + configContent = configContent.replace(regex, `$1${value}`); + } + } + }); + } + + if (settings.trustLevel && settings.trustLevel.requirements) { + Object.keys(settings.trustLevel.requirements).forEach(level => { + const requirements = settings.trustLevel.requirements[level]; + if (requirements.hoursRequired !== undefined) { + const regex = new RegExp(`(${level}:\\s*{[^}]*hoursRequired:\\s*parseInt\\(process\\.env\\.[A-Z_]+\\)\\s*\\|\\|\\s*)\\d+`); + if (configContent.match(regex)) { + configContent = configContent.replace(regex, `$1${requirements.hoursRequired}`); + } + } + if (requirements.reputationRequired !== undefined) { + const regex = new RegExp(`(${level}:\\s*{[^}]*reputationRequired:\\s*parseInt\\(process\\.env\\.[A-Z_]+\\)\\s*\\|\\|\\s*)\\d+`); + if (configContent.match(regex)) { + configContent = configContent.replace(regex, `$1${requirements.reputationRequired}`); + } + } + }); + } + + // Сохраняем обновленный файл + await fs.writeFile(configPath, configContent, 'utf-8'); + + // Очищаем кеш модуля, чтобы изменения вступили в силу + delete require.cache[require.resolve('../config/settings')]; + + // Логируем действие + await req.db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'settings_update', `Обновлены настройки сервера`] + ); + + res.json({ + success: true, + message: 'Настройки успешно обновлены' + }); + + } catch (error) { + console.error('Ошибка обновления настроек:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// Сброс настроек к значениям по умолчанию +router.post('/settings/reset', authenticateToken, requireRole(['admin']), async (req, res) => { + try { + const { section } = req.body; + + // Здесь можно реализовать сброс определенной секции настроек + // к значениям по умолчанию + + await req.db.query( + 'INSERT INTO admin_logs (admin_id, action, details) VALUES ($1, $2, $3)', + [req.user.id, 'settings_reset', `Сброшена секция настроек: ${section}`] + ); + + res.json({ + success: true, + message: 'Настройки сброшены к значениям по умолчанию' + }); + + } catch (error) { + console.error('Ошибка сброса настроек:', error); + res.status(500).json({ error: 'Ошибка сервера' }); + } +}); + +// Защищенный endpoint для плагинов - получение информации о сервере +router.get('/plugin/server-info', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + // Получаем настройки сервера из базы данных + const settingsResult = await db.query(` + SELECT setting_key, setting_value + FROM server_settings + WHERE setting_key IN ($1, $2, $3, $4, $5) + `, ['server-ip', 'server-port', 'server-name', 'server-max-players', 'server-description']); + + const settings = {}; + settingsResult.rows.forEach(row => { + settings[row.setting_key] = row.setting_value; + }); + + const serverIp = settings['server-ip'] || '45.131.186.146'; + const serverPort = parseInt(settings['server-port'] || '1488'); + const serverName = settings['server-name'] || 'Owyx'; + const maxPlayers = parseInt(settings['server-max-players'] || '50'); + + // Получаем список онлайн игроков из базы данных + const onlinePlayersResult = await db.query(` + SELECT + gs.nickname, + gs.player_uuid, + gs.ip_address, + gs.last_login, + u.trust_level, + u.role, + ps.time_played_minutes, + ps.last_seen, + ps.minecraft_stats, + ps.current_level, + ps.achievements_count + FROM game_sessions gs + LEFT JOIN users u ON gs.user_id = u.id + LEFT JOIN player_stats ps ON u.id = ps.user_id + WHERE gs.is_active = true + AND gs.expires_at > NOW() + ORDER BY gs.last_login DESC + `); + + // Формируем список игроков с дополнительной информацией + const playersList = onlinePlayersResult.rows.map(player => ({ + name: player.nickname, + uuid: player.player_uuid, + trust_level: player.trust_level || 0, + role: player.role || 'user', + playtime: player.time_played_minutes || 0, + last_seen: player.last_seen, + level: player.current_level || 1, + achievements: player.achievements_count || 0, + minecraft_stats: player.minecraft_stats || {}, + ip_address: player.ip_address, + session_start: player.last_login + })); + + // Проверяем статус Minecraft сервера + let pluginServerData = { + online: false, + version: 'Unknown', + motd: 'Server Offline', + ping: 0, + tps: 0 + }; + + try { + const response = await status(serverIp, serverPort); + pluginServerData = { + online: true, + version: response.version?.name || 'Unknown', + motd: response.motd?.clean || 'Minecraft Server', + ping: response.roundTripLatency || 0, + tps: null // TPS должен передаваться от плагина через API + }; + } catch (minecraftError) { + console.log('Minecraft сервер недоступен:', minecraftError.message); + } + + res.json({ + success: true, + // Статус сервера + status: pluginServerData.online ? 'online' : 'offline', + online: pluginServerData.online, + + // Информация о сервере + server: { + name: serverName, + ip: serverIp, + port: serverPort, + version: pluginServerData.version, + motd: pluginServerData.motd + }, + + // Производительность + performance: { + ping: pluginServerData.ping, + tps: pluginServerData.tps + }, + + // Игроки + players: { + online: playersList.length, + max: maxPlayers, + list: playersList + }, + + // Метаданные + timestamp: new Date().toISOString(), + api_version: '2.1' + }); + } catch (error) { + console.error('Ошибка получения информации о сервере для плагина:', error); + res.status(500).json({ + success: false, + error: 'Ошибка сервера', + message: error.message + }); + } +}); + +// Защищенный endpoint для плагинов - проверка доступа игрока к серверу +router.get('/plugin/server-access', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { nickname } = req.query; + + if (!nickname) { + return res.status(400).json({ + success: false, + error: 'Nickname is required' + }); + } + + // Open access model: a registered, active, non-banned account is allowed. + // Applications ("заявки") are no longer a whitelist gate. This keeps the + // plugin's /login flow working: non-banned = allowed. + const userResult = await db.query(` + SELECT id, nickname, role, is_banned, is_active + FROM users + WHERE nickname = $1 + LIMIT 1 + `, [nickname]); + + let hasAccess = false; + let reason = 'No account found'; + + if (userResult.rows.length > 0) { + const account = userResult.rows[0]; + if (account.is_banned) { + hasAccess = false; + reason = 'Account banned'; + } else if (account.is_active === false) { + hasAccess = false; + reason = 'Account inactive'; + } else { + hasAccess = true; + reason = 'Open access (active account)'; + } + } + + res.json({ + success: true, + hasAccess: hasAccess, + reason: reason, + nickname: nickname + }); + + } catch (error) { + console.error('Ошибка проверки доступа к серверу:', error); + res.status(500).json({ + success: false, + error: 'Server error', + message: error.message + }); + } +}); + +// POST /api/settings/server-data - Получение данных о сервере от плагина (TPS, время работы) +router.post('/settings/server-data', authenticateLongTermApiTokenOnly, async (req, res) => { + try { + const { + server_ip, + server_port, + tps, + uptime_seconds, + max_memory, + used_memory, + free_memory, + online_players, + max_players, + server_version, + plugins_count, + loaded_worlds, + timestamp + } = req.body; + + // Сохраняем данные сервера в таблицу server_status + await db.query(` + INSERT INTO server_status ( + server_ip, server_port, tps, uptime_seconds, + max_memory, used_memory, free_memory, + online_players, max_players, server_version, + plugins_count, loaded_worlds, updated_at + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW()) + ON CONFLICT (server_ip, server_port) + DO UPDATE SET + tps = $3, + uptime_seconds = $4, + max_memory = $5, + used_memory = $6, + free_memory = $7, + online_players = $8, + max_players = $9, + server_version = $10, + plugins_count = $11, + loaded_worlds = $12, + updated_at = NOW() + `, [ + server_ip || 'localhost', + server_port || 25565, + tps || null, + uptime_seconds || null, + max_memory || null, + used_memory || null, + free_memory || null, + online_players || 0, + max_players || 20, + server_version || 'Unknown', + plugins_count || 0, + loaded_worlds || 1 + ]); + + res.json({ + success: true, + message: 'Server data updated', + timestamp: new Date().toISOString() + }); + + } catch (error) { + console.error('Ошибка обновления данных сервера:', error); + res.status(500).json({ + success: false, + error: 'Failed to update server data', + message: error.message + }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/routes/trust-level.js b/legacy/owyxsite/backend/src/routes/trust-level.js new file mode 100644 index 00000000000..d624bed7c26 --- /dev/null +++ b/legacy/owyxsite/backend/src/routes/trust-level.js @@ -0,0 +1,342 @@ +// Маршруты для системы Trust Level +// Создатель: ebluffy + +const express = require('express'); +const { body, validationResult } = require('express-validator'); +const db = require('../database/connection'); +const { authenticateToken, requireRole } = require('./auth'); + +const router = express.Router(); + +// POST /api/trust-level/apply - Подача заявки на повышение траст левела +router.post('/apply', [ + authenticateToken, + body('requestedLevel').isInt({ min: 1, max: 3 }), + body('motivation').isLength({ min: 50, max: 1000 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + const userId = req.user.id; + const { requestedLevel, motivation } = req.body; + + // Получаем текущие данные пользователя + const userResult = await db.query(` + SELECT u.trust_level, ur.reputation_score, + ps.time_played_minutes AS total_playtime, u.is_email_verified + FROM users u + LEFT JOIN user_reputation ur ON u.id = ur.user_id + LEFT JOIN player_stats ps ON u.id = ps.user_id + WHERE u.id = $1 + `, [userId]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + const currentLevel = user.trust_level || 0; + const reputation = user.reputation_score || 0; + const playtime = user.total_playtime || 0; + + // Проверяем, можно ли подать заявку + if (requestedLevel <= currentLevel) { + return res.status(400).json({ error: 'Нельзя подать заявку на текущий или более низкий уровень' }); + } + + if (requestedLevel > currentLevel + 1) { + return res.status(400).json({ error: 'Можно повысить уровень только на один за раз' }); + } + + // Проверяем требования для каждого уровня + const requirements = { + 1: { playtime: 0, reputation: 0, emailRequired: true }, + 2: { playtime: 25, reputation: 10, emailRequired: true }, + 3: { playtime: 50, reputation: 20, emailRequired: true } + }; + + const req_level = requirements[requestedLevel]; + if (!req_level) { + return res.status(400).json({ error: 'Неверный уровень' }); + } + + if (!user.is_email_verified && req_level.emailRequired) { + return res.status(400).json({ error: 'Необходимо подтвердить email' }); + } + + if (playtime < req_level.playtime) { + return res.status(400).json({ + error: `Необходимо ${req_level.playtime} часов игры. У вас: ${playtime}` + }); + } + + if (reputation < req_level.reputation) { + return res.status(400).json({ + error: `Необходимо ${req_level.reputation} репутации. У вас: ${reputation}` + }); + } + + // Проверяем, нет ли активной заявки + const existingApplication = await db.query(` + SELECT id FROM trust_level_applications + WHERE user_id = $1 AND status = 'pending' + `, [userId]); + + if (existingApplication.rows.length > 0) { + return res.status(400).json({ error: 'У вас уже есть активная заявка на рассмотрении' }); + } + + // Создаем заявку + const result = await db.query(` + INSERT INTO trust_level_applications + (user_id, current_level, requested_level, motivation, current_reputation, current_playtime) + VALUES ($1, $2, $3, $4, $5, $6) + RETURNING id + `, [userId, currentLevel, requestedLevel, motivation, reputation, playtime]); + + res.json({ + success: true, + message: 'Заявка на повышение траст левела отправлена', + applicationId: result.rows[0].id + }); + + } catch (error) { + console.error('Ошибка подачи заявки:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/trust-level/applications - Получить заявки на повышение (для админов) +router.get('/applications', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const status = req.query.status || 'all'; + const limit = parseInt(req.query.limit) || 20; + + let whereClause = ''; + let queryParams = [limit]; + + if (status !== 'all') { + whereClause = 'WHERE tla.status = $2'; + queryParams.push(status); + } + + const result = await db.query(` + SELECT + tla.*, + u.nickname, + u.email, + COALESCE(ur.reputation_score, 0) as current_reputation + FROM trust_level_applications tla + JOIN users u ON tla.user_id = u.id + LEFT JOIN user_reputation ur ON u.id = ur.user_id + ${whereClause} + ORDER BY tla.submitted_at DESC + LIMIT $1 + `, queryParams); + + res.json({ + success: true, + applications: result.rows, + total: result.rows.length + }); + + } catch (error) { + console.error('Ошибка получения заявок:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// PUT /api/trust-level/applications/:id/review - Рассмотреть заявку на повышение +router.put('/applications/:id/review', [ + authenticateToken, + requireRole(['admin', 'moderator']), + body('decision').isIn(['approved', 'rejected']), + body('comment').optional().isLength({ max: 500 }) +], async (req, res) => { + try { + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }); + } + + const applicationId = parseInt(req.params.id); + const { decision, comment } = req.body; + const reviewerId = req.user.id; + + // Получаем данные заявки + const applicationResult = await db.query(` + SELECT * FROM trust_level_applications WHERE id = $1 AND status = 'pending' + `, [applicationId]); + + if (applicationResult.rows.length === 0) { + return res.status(404).json({ error: 'Заявка не найдена или уже рассмотрена' }); + } + + const application = applicationResult.rows[0]; + + // Обновляем статус заявки + await db.query(` + UPDATE trust_level_applications + SET status = $1, reviewer_id = $2, reviewed_at = NOW(), review_comment = $3 + WHERE id = $4 + `, [decision, reviewerId, comment, applicationId]); + + // Если заявка одобрена, повышаем траст левел пользователя + if (decision === 'approved') { + await db.query(` + UPDATE users + SET trust_level = $1, trust_level_updated_at = NOW() + WHERE id = $2 + `, [application.requested_level, application.user_id]); + } + + res.json({ + success: true, + message: decision === 'approved' ? 'Заявка одобрена' : 'Заявка отклонена' + }); + + } catch (error) { + console.error('Ошибка рассмотрения заявки:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/trust-level/stats - Статистика по траст левелам (для админов) +router.get('/stats', authenticateToken, requireRole(['admin', 'moderator']), async (req, res) => { + try { + const result = await db.query(` + SELECT + trust_level, + COUNT(*) as count + FROM users + GROUP BY trust_level + ORDER BY trust_level + `); + + const stats = { + 0: 0, 1: 0, 2: 0, 3: 0 + }; + + result.rows.forEach(row => { + stats[row.trust_level || 0] = parseInt(row.count); + }); + + res.json({ + success: true, + stats: stats, + total: Object.values(stats).reduce((sum, count) => sum + count, 0) + }); + + } catch (error) { + console.error('Ошибка получения статистики:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +// GET /api/trust-level/requirements - Проверка требований для повышения уровня доверия +router.get('/requirements', authenticateToken, async (req, res) => { + try { + const userId = req.user.id; + + // Получаем текущие данные пользователя + const userResult = await db.query(` + SELECT u.trust_level, ur.reputation_score, u.is_email_verified, ps.time_played_minutes + FROM users u + LEFT JOIN user_reputation ur ON u.id = ur.user_id + LEFT JOIN player_stats ps ON u.id = ps.user_id + WHERE u.id = $1 + `, [userId]); + + if (userResult.rows.length === 0) { + return res.status(404).json({ error: 'Пользователь не найден' }); + } + + const user = userResult.rows[0]; + const currentLevel = user.trust_level || 0; + const reputation = user.reputation_score || 0; + const playtime = 0; // Пока нет данных о времени игры, используем 0 + const nextLevel = currentLevel + 1; + + // Максимальный уровень доверия (Ветеран = 3) + if (currentLevel >= 3) { + return res.json({ + canApply: false, + nextLevel: currentLevel, + reason: 'Достигнут максимальный уровень доверия', + requirements: [ + { description: 'Максимальный уровень', met: true } + ] + }); + } + + // Требования для каждого уровня + const requirements = { + 1: { playtime: 0, reputation: 0, emailRequired: true }, + 2: { playtime: 25, reputation: 10, emailRequired: true }, + 3: { playtime: 50, reputation: 20, emailRequired: true }, + 4: { playtime: 100, reputation: 50, emailRequired: true } + }; + + const req_level = requirements[nextLevel]; + if (!req_level) { + return res.json({ + canApply: false, + nextLevel: nextLevel, + reason: 'Неверный уровень доверия', + requirements: [] + }); + } + + // Проверяем, нет ли активной заявки + const existingApplication = await db.query(` + SELECT id FROM trust_level_applications + WHERE user_id = $1 AND status = 'pending' + `, [userId]); + + if (existingApplication.rows.length > 0) { + return res.json({ + canApply: false, + nextLevel: nextLevel, + reason: 'У вас уже есть активная заявка на рассмотрении', + requirements: [] + }); + } + + // Формируем список требований с проверкой + const reqList = [ + { + description: 'Подтвержденный email', + met: user.is_email_verified || false, + progress: user.is_email_verified ? 'Выполнено' : 'Не выполнено' + }, + { + description: `Время игры: ${req_level.playtime}+ часов`, + met: playtime >= req_level.playtime, + progress: `${playtime}/${req_level.playtime} часов` + }, + { + description: `Репутация: ${req_level.reputation}+`, + met: reputation >= req_level.reputation, + progress: `${reputation}/${req_level.reputation}` + } + ]; + + const canApply = reqList.every(req => req.met); + + res.json({ + canApply: canApply, + nextLevel: nextLevel, + reason: canApply ? null : 'Не выполнены все требования', + requirements: reqList + }); + + } catch (error) { + console.error('Ошибка проверки требований:', error); + res.status(500).json({ error: 'Внутренняя ошибка сервера' }); + } +}); + +module.exports = router; diff --git a/legacy/owyxsite/backend/src/server.ts b/legacy/owyxsite/backend/src/server.ts new file mode 100644 index 00000000000..93ea718c088 --- /dev/null +++ b/legacy/owyxsite/backend/src/server.ts @@ -0,0 +1,271 @@ +import http from 'http'; +import path from 'path'; +import express from 'express'; +import cors from 'cors'; +import helmet from 'helmet'; +import morgan from 'morgan'; +import compression from 'compression'; +import dotenv from 'dotenv'; + +dotenv.config({ path: path.resolve(__dirname, '../../.env') }); +dotenv.config(); + +const db = require('./database/connection'); +const authRoutes = require('./routes/auth'); +const applicationRoutes = require('./routes/applications'); +const profileRoutes = require('./routes/profile'); +const adminRoutes = require('./routes/admin'); +const reputationRoutes = require('./routes/reputation'); +const trustLevelRoutes = require('./routes/trust-level'); +const settingsRoutes = require('./routes/settings'); +const forumRoutes = require('./routes/forum'); +const chatRoutes = require('./routes/chat'); +const launcherRoutes = require('./routes/launcher'); +const newsRoutes = require('./routes/news'); +const catalogRoutes = require('./routes/catalog'); +const { clientKeyGate } = require('./middleware/clientKey'); +const { initSocket } = require('./socket'); + +const app = express(); +const PORT = parseInt(process.env.API_PORT || process.env.PORT || '3001', 10); + +const trustProxyHops = Number.parseInt(process.env.TRUST_PROXY_HOPS || '0', 10); +app.set('trust proxy', Number.isSafeInteger(trustProxyHops) && trustProxyHops > 0 ? trustProxyHops : false); + +app.use((req: any, _res, next) => { + // Express applies the configured trusted-proxy hop count to req.ip. Never + // parse X-Forwarded-For directly: a public client could forge rate-limit IPs. + req.clientIp = req.ip || req.socket?.remoteAddress; + + if (req.clientIp && req.clientIp.startsWith('::ffff:')) { + req.clientIp = req.clientIp.substring(7); + } + next(); +}); + +app.use( + helmet({ + crossOriginResourcePolicy: { policy: 'cross-origin' }, + contentSecurityPolicy: false, + }) +); + +const corsOrigin = process.env.CORS_ORIGIN + ? process.env.CORS_ORIGIN.split(',').map((s) => s.trim()) + : process.env.NODE_ENV === 'production' + ? [ + process.env.FRONTEND_URL || 'https://owyx.site', + 'https://www.owyx.site', + ] + : [ + process.env.FRONTEND_URL || 'http://localhost:3000', + 'http://127.0.0.1:3000', + 'http://localhost:1420', + 'http://127.0.0.1:1420', + ]; + +app.use( + cors({ + origin: corsOrigin, + credentials: true, + }) +); + +app.use(compression()); +app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev')); +app.use(express.json({ limit: '1mb' })); +app.use(express.urlencoded({ extended: true, limit: '1mb' })); + +// api.owyx.site requires X-Owyx-Client-Key; owyx.site /api proxy does not. +app.use(clientKeyGate); + +app.use( + '/uploads', + express.static(path.join(__dirname, '../uploads'), { + maxAge: process.env.NODE_ENV === 'production' ? '7d' : 0, + }) +); +app.use( + '/fixtures', + express.static(path.join(__dirname, '../fixtures'), { + maxAge: process.env.NODE_ENV === 'production' ? '1h' : 0, + }) +); + +app.use('/api/auth', authRoutes); +app.use('/api/applications', applicationRoutes); +app.use('/api/profile', profileRoutes); +app.use('/api/admin', adminRoutes); +app.use('/api', settingsRoutes); +app.use('/api/reputation', reputationRoutes); +app.use('/api/trust-level', trustLevelRoutes); +app.use('/api/forum', forumRoutes); +app.use('/api/chat', chatRoutes); +app.use('/api/launcher', launcherRoutes); +app.use('/api/news', newsRoutes); +app.use('/api/admin/news', newsRoutes.adminRouter); +app.use('/api/admin/packs', catalogRoutes.packsAdmin); +app.use('/api/admin/servers', catalogRoutes.serversAdmin); + +app.get('/health', async (_req, res) => { + try { + await db.query('SELECT 1'); + res.json({ + status: 'healthy', + timestamp: new Date().toISOString(), + version: '1.0.0', + services: { + database: 'connected', + server: 'running', + socketio: 'enabled', + }, + }); + } catch (error) { + console.error('Health check failed:', error); + res.status(503).json({ + status: 'unhealthy', + timestamp: new Date().toISOString(), + error: 'Database connection failed', + }); + } +}); + +app.get('/api', (_req, res) => { + res.json({ + name: 'Owyx API', + version: '1.0.0', + description: 'API for Owyx Minecraft site (migrated from chiwawasite)', + endpoints: { + auth: '/api/auth', + applications: '/api/applications', + profile: '/api/profile', + admin: '/api/admin', + forum: '/api/forum', + chat: '/api/chat', + settings: '/api/settings', + launcher: '/api/launcher', + adminServers: '/api/admin/servers', + adminPacks: '/api/admin/packs', + }, + }); +}); + +app.use('/api', (req, res) => { + res.status(404).json({ + error: 'API endpoint не найден', + path: req.path, + method: req.method, + }); +}); + +app.use((error: any, _req: express.Request, res: express.Response, _next: express.NextFunction) => { + console.error('Server error:', error); + const status = Number.isInteger(error.status) ? error.status : 500; + res.status(status).json({ + error: status >= 500 ? 'Внутренняя ошибка сервера' : error.message, + }); +}); + +const httpServer = http.createServer(app); +initSocket(httpServer); + +setInterval(async () => { + try { + const webResult = await db.query('DELETE FROM user_sessions WHERE expires_at < NOW()'); + const deactivateResult = await db.query(` + UPDATE user_sessions + SET is_active = false + WHERE is_active = true + AND last_activity < NOW() - INTERVAL '1 day' + `); + if (webResult.rowCount + deactivateResult.rowCount > 0) { + console.log( + `Cleaned sessions: web=${webResult.rowCount}, deactivated=${deactivateResult.rowCount}` + ); + } + } catch (error) { + console.error('Session cleanup error:', error); + } +}, 60 * 60 * 1000); + +async function ensureChatSchema() { + try { + await db.query(` + CREATE TABLE IF NOT EXISTS chat_rooms ( + id SERIAL PRIMARY KEY, + name VARCHAR(100) NOT NULL, + slug VARCHAR(100) NOT NULL UNIQUE, + description TEXT, + is_private BOOLEAN DEFAULT false, + created_by INTEGER, + created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP + ) + `); + await db.query(` + CREATE TABLE IF NOT EXISTS chat_room_members ( + room_id INTEGER NOT NULL REFERENCES chat_rooms(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL, + joined_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (room_id, user_id) + ) + `); + await db.query(` + CREATE TABLE IF NOT EXISTS chat_messages ( + id SERIAL PRIMARY KEY, + room_id INTEGER NOT NULL REFERENCES chat_rooms(id) ON DELETE CASCADE, + user_id INTEGER NOT NULL, + content TEXT NOT NULL, + is_deleted BOOLEAN DEFAULT false, + created_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITHOUT TIME ZONE DEFAULT CURRENT_TIMESTAMP + ) + `); + await db.query(` + INSERT INTO chat_rooms (name, slug, description, is_private) + VALUES ('Общий чат', 'general', 'Публичный чат сервера Owyx', false) + ON CONFLICT (slug) DO NOTHING + `); + console.log('Chat schema ready'); + } catch (error: any) { + console.warn('Chat schema ensure skipped:', error.message); + } +} + +const shutdown = async (signal: string) => { + console.log(`\nReceived ${signal}, shutting down...`); + try { + await db.end(); + } catch (error) { + console.error('Error closing DB pool:', error); + } + process.exit(0); +}; + +process.on('SIGINT', () => shutdown('SIGINT')); +process.on('SIGTERM', () => shutdown('SIGTERM')); + +httpServer.listen(PORT, async () => { + console.log(`Owyx API listening on :${PORT}`); + console.log(`Health: http://127.0.0.1:${PORT}/health`); + console.log(`Socket.io path: /socket.io`); + + const ok = await db.testConnection(); + if (ok) { + await ensureChatSchema(); + try { + await catalogRoutes.ensureCatalogSchema(); + console.log('Catalog schema ready'); + } catch (error: any) { + console.warn('Catalog schema ensure skipped:', error.message); + } + try { + await db.query('DELETE FROM user_sessions WHERE expires_at < NOW()'); + } catch { + /* ignore */ + } + } else { + console.warn('Started without a working database connection'); + } +}); + +export default app; diff --git a/legacy/owyxsite/backend/src/socket/index.ts b/legacy/owyxsite/backend/src/socket/index.ts new file mode 100644 index 00000000000..28d10f5dddb --- /dev/null +++ b/legacy/owyxsite/backend/src/socket/index.ts @@ -0,0 +1,184 @@ +import { Server as HttpServer } from 'http'; +import { Server, Socket } from 'socket.io'; +import jwt from 'jsonwebtoken'; + +// eslint-disable-next-line @typescript-eslint/no-var-requires +const db = require('../database/connection'); +// eslint-disable-next-line @typescript-eslint/no-var-requires +const { sessionTokenHashes } = require('../utils/authSecurity'); + +interface AuthedSocket extends Socket { + user?: { + id: number; + nickname: string; + role: string; + avatar_url?: string; + }; +} + +export function initSocket(httpServer: HttpServer) { + const corsOrigin = process.env.CORS_ORIGIN + ? process.env.CORS_ORIGIN.split(',').map((s) => s.trim()) + : process.env.NODE_ENV === 'production' + ? [process.env.FRONTEND_URL || 'https://owyx.site'] + : ['http://localhost:3000', 'http://127.0.0.1:3000', 'http://localhost:3001']; + + const io = new Server(httpServer, { + cors: { + origin: corsOrigin, + credentials: true, + }, + path: '/socket.io', + }); + + io.use(async (socket: AuthedSocket, next) => { + try { + const token = + (socket.handshake.auth && (socket.handshake.auth as { token?: string }).token) || + (socket.handshake.query && (socket.handshake.query as { token?: string }).token); + + if (!token || typeof token !== 'string') { + return next(new Error('Authentication required')); + } + + const secret = process.env.JWT_SECRET; + if (!secret) return next(new Error('Server misconfigured')); + + const decoded = jwt.verify(token, secret) as { userId: number }; + const result = await db.query( + `SELECT u.id, u.nickname, u.role, u.avatar_url, u.is_active, u.is_banned, + s.id AS session_id + FROM user_sessions s + JOIN users u ON u.id = s.user_id + WHERE s.token_hash = ANY($1::text[]) + AND s.user_id = $2 + AND s.is_active = true + AND s.expires_at > NOW()`, + [sessionTokenHashes(token), decoded.userId] + ); + + if (result.rows.length === 0 || !result.rows[0].is_active || result.rows[0].is_banned) { + return next(new Error('User not found or banned')); + } + + socket.user = { + id: result.rows[0].id, + nickname: result.rows[0].nickname, + role: result.rows[0].role || 'user', + avatar_url: result.rows[0].avatar_url, + }; + next(); + } catch (err) { + next(new Error('Invalid token')); + } + }); + + io.on('connection', (socket: AuthedSocket) => { + console.log(`Socket connected: ${socket.user?.nickname} (${socket.id})`); + + socket.on('join_room', async (roomId: number | string, cb?: (res: unknown) => void) => { + try { + const id = parseInt(String(roomId), 10); + if (!Number.isFinite(id)) { + cb?.({ error: 'Invalid room id' }); + return; + } + + const access = await db.query( + `SELECT r.is_private, (rm.user_id IS NOT NULL) AS is_member + FROM chat_rooms r + LEFT JOIN chat_room_members rm ON rm.room_id = r.id AND rm.user_id = $2 + WHERE r.id = $1`, + [id, socket.user!.id] + ); + const room = access.rows[0]; + if (!room || (room.is_private && !room.is_member)) { + cb?.({ error: 'Room not found or access denied' }); + return; + } + + await db.query( + `INSERT INTO chat_room_members (room_id, user_id) + VALUES ($1, $2) ON CONFLICT DO NOTHING`, + [id, socket.user!.id] + ); + + socket.join(`room:${id}`); + socket.to(`room:${id}`).emit('user_joined', { + roomId: id, + user: socket.user, + }); + cb?.({ success: true, roomId: id }); + } catch (error: any) { + console.error('join_room error:', error.message); + cb?.({ error: error.message }); + } + }); + + socket.on('leave_room', (roomId: number | string) => { + const id = parseInt(String(roomId), 10); + socket.leave(`room:${id}`); + socket.to(`room:${id}`).emit('user_left', { + roomId: id, + user: socket.user, + }); + }); + + socket.on( + 'send_message', + async ( + payload: { roomId: number; content: string }, + cb?: (res: unknown) => void + ) => { + try { + const roomId = parseInt(String(payload.roomId), 10); + const content = String(payload.content || '').trim(); + if (!Number.isFinite(roomId) || !content || content.length > 2000) { + cb?.({ error: 'Invalid message' }); + return; + } + if (!socket.rooms.has(`room:${roomId}`)) { + cb?.({ error: 'Join the room before sending messages' }); + return; + } + + const insert = await db.query( + `INSERT INTO chat_messages (room_id, user_id, content) + VALUES ($1, $2, $3) + RETURNING id, room_id, user_id, content, created_at`, + [roomId, socket.user!.id, content] + ); + + const message = { + ...insert.rows[0], + nickname: socket.user!.nickname, + avatar_url: socket.user!.avatar_url, + role: socket.user!.role, + }; + + io.to(`room:${roomId}`).emit('new_message', message); + cb?.({ success: true, message }); + } catch (error: any) { + console.error('send_message error:', error.message); + cb?.({ error: error.message }); + } + } + ); + + socket.on('typing', (payload: { roomId: number; isTyping: boolean }) => { + const roomId = parseInt(String(payload.roomId), 10); + if (!socket.rooms.has(`room:${roomId}`)) return; + socket.to(`room:${roomId}`).emit('typing', { + roomId, + user: socket.user, + isTyping: !!payload.isTyping, + }); + }); + + socket.on('disconnect', () => { + console.log(`Socket disconnected: ${socket.user?.nickname}`); + }); + }); + + return io; +} diff --git a/legacy/owyxsite/backend/src/utils/authSecurity.js b/legacy/owyxsite/backend/src/utils/authSecurity.js new file mode 100644 index 00000000000..f91f4b6720e --- /dev/null +++ b/legacy/owyxsite/backend/src/utils/authSecurity.js @@ -0,0 +1,57 @@ +const crypto = require('crypto'); + +const PUBLIC_USER_FIELDS = [ + 'id', + 'nickname', + 'email', + 'first_name', + 'role', + 'trust_level', + 'status', + 'is_active', + 'is_email_verified', + 'is_banned', + 'registered_at', + 'last_login', + 'age', + 'bio', + 'avatar_url', + 'ban_reason', + 'ban_until', + 'discord_username', + 'total_minutes', + 'skin_url', + 'skin_model', + 'cape_url', + 'nickname_changed_at', +]; + +function hashSessionToken(token) { + return crypto.createHash('sha256').update(String(token)).digest('hex'); +} + +function legacySessionTokenHash(token) { + return Buffer.from(String(token)).toString('base64'); +} + +function sessionTokenHashes(token) { + return [hashSessionToken(token), legacySessionTokenHash(token)]; +} + +function publicUser(user) { + const safe = {}; + for (const field of PUBLIC_USER_FIELDS) { + if (user[field] !== undefined) safe[field] = user[field]; + } + // Preserve the names consumed by the current Next frontend. + safe.created_at = user.created_at ?? user.registered_at; + safe.discord = user.discord ?? user.discord_username; + return safe; +} + +module.exports = { + hashSessionToken, + legacySessionTokenHash, + sessionTokenHashes, + publicUser, +}; diff --git a/legacy/owyxsite/backend/src/utils/emailService.js b/legacy/owyxsite/backend/src/utils/emailService.js new file mode 100644 index 00000000000..acf1a891e2f --- /dev/null +++ b/legacy/owyxsite/backend/src/utils/emailService.js @@ -0,0 +1,202 @@ +const nodemailer = require('nodemailer'); +const db = require('../database/connection'); +const { render: renderTemplate } = require('./emailTemplates'); + +const createTransporter = () => { + const port = parseInt(process.env.SMTP_PORT || process.env.EMAIL_SMTP_PORT || '465', 10); + const secure = + process.env.SMTP_SECURE === 'true' || + port === 465; + + return nodemailer.createTransport({ + host: process.env.SMTP_HOST || process.env.EMAIL_SMTP_HOST || 'smtp.yandex.ru', + port, + secure, + auth: { + user: process.env.SMTP_USER || process.env.EMAIL_SMTP_USER || '', + pass: process.env.SMTP_PASS || process.env.SMTP_PASSWORD || process.env.EMAIL_SMTP_PASSWORD || '', + }, + }); +}; + +const getEmailTemplate = async (id) => { + const result = await db.query( + `SELECT template_subject, template_html, template_variables FROM email_templates WHERE id = $1`, + [id] + ); + + if (result.rows.length === 0) { + throw new Error(`Email template with ID '${id}' not found`); + } + + const row = result.rows[0]; + let variables = []; + if (row.template_variables) { + try { + if (String(row.template_variables).trim().startsWith('[')) { + variables = JSON.parse(row.template_variables); + } else { + variables = String(row.template_variables) + .split(',') + .map((v) => v.trim()); + } + } catch { + variables = []; + } + } + + return { + subject: row.template_subject, + html: row.template_html, + variables, + }; +}; + +const replaceTemplateVariables = (template, variables) => { + if (!template) return ''; + let result = template; + for (const [key, value] of Object.entries(variables)) { + const regex = new RegExp(`{{${key}}}`, 'g'); + result = result.replace(regex, value || ''); + } + return result; +}; + +const getServerSettings = async () => { + try { + const result = await db.query(`SELECT setting_key, setting_value FROM server_settings`); + const settings = {}; + for (const row of result.rows) { + settings[row.setting_key] = row.setting_value; + } + + return { + serverName: settings['server-name'] || 'Owyx', + serverIp: settings['server-ip'] || '45.131.186.146:1488', + discordInvite: settings['discord-invite'] || 'https://discord.gg/owyx', + telegramInvite: settings['telegram-invite'] || 'https://t.me/owyx', + currentDate: new Date().toLocaleDateString('ru-RU', { + year: 'numeric', + month: 'long', + day: 'numeric', + }), + }; + } catch (error) { + console.error('Error loading server settings for email:', error.message); + return { + serverName: 'Owyx', + serverIp: '45.131.186.146:1488', + discordInvite: 'https://discord.gg/owyx', + telegramInvite: 'https://t.me/owyx', + currentDate: new Date().toLocaleDateString('ru-RU'), + }; + } +}; + +const sendEmail = async (to, id, customVariables = {}) => { + const template = await getEmailTemplate(id); + const serverSettings = await getServerSettings(); + const variables = { ...serverSettings, ...customVariables }; + + if (!template.subject || !template.html) { + throw new Error(`Template '${id}' is incomplete`); + } + + const subject = replaceTemplateVariables(template.subject, variables); + const html = replaceTemplateVariables(template.html, variables); + + const smtpUser = process.env.SMTP_USER || process.env.EMAIL_SMTP_USER; + const smtpPass = process.env.SMTP_PASS || process.env.SMTP_PASSWORD || process.env.EMAIL_SMTP_PASSWORD; + + if (!smtpUser || !smtpPass) { + console.log('SMTP not configured — email simulated'); + console.log(`To: ${to}`); + console.log(`Subject: ${subject}`); + return { + success: true, + messageId: 'simulated-' + Date.now(), + simulated: true, + }; + } + + const transporter = createTransporter(); + const fromAddress = process.env.EMAIL_FROM || smtpUser; + + const info = await transporter.sendMail({ + from: `"${serverSettings.serverName}" <${fromAddress}>`, + to, + subject, + html, + }); + + return { + success: true, + messageId: info.messageId, + simulated: false, + }; +}; + +// Send one of the built-in Owyx templates (no DB dependency). Simulates in logs +// when SMTP is not configured, exactly like sendEmail(). +const sendTemplate = async (to, key, vars = {}) => { + const serverSettings = await getServerSettings(); + const { subject, html } = renderTemplate(key, { ...serverSettings, ...vars }); + + const smtpUser = process.env.SMTP_USER || process.env.EMAIL_SMTP_USER; + const smtpPass = process.env.SMTP_PASS || process.env.SMTP_PASSWORD || process.env.EMAIL_SMTP_PASSWORD; + + if (!smtpUser || !smtpPass) { + console.log(`SMTP not configured — email simulated (template: ${key})`); + console.log(`To: ${to}`); + console.log(`Subject: ${subject}`); + return { success: true, messageId: 'simulated-' + Date.now(), simulated: true }; + } + + const transporter = createTransporter(); + const fromAddress = process.env.EMAIL_FROM || smtpUser; + const info = await transporter.sendMail({ + from: `"${serverSettings.serverName}" <${fromAddress}>`, + to, + subject, + html, + }); + return { success: true, messageId: info.messageId, simulated: false }; +}; + +const sendVerificationEmail = async (email, nickname, verificationLink) => + sendTemplate(email, 'verify', { nickname, verificationLink }); + +const sendWelcomeEmail = async (email, nickname) => + sendTemplate(email, 'welcome', { nickname }); + +const sendPasswordResetEmail = async (email, nickname, resetLink) => + sendTemplate(email, 'reset', { nickname, resetLink }); + +const sendPasswordChangedEmail = async (email, nickname) => + sendTemplate(email, 'passwordChanged', { nickname }); + +const sendNicknameChangedEmail = async (email, oldNick, newNick) => + sendTemplate(email, 'nicknameChanged', { oldNick, newNick }); + +const sendEmailChangeCode = async (email, code) => + sendTemplate(email, 'emailChange', { code }); + +// Legacy DB-template senders (kept for back-compat with existing admin routes). +const sendApplicationApprovedEmail = async (email, nickname) => + sendEmail(email, 9, { nickname }); + +const sendApplicationRejectedEmail = async (email, nickname, reason) => + sendEmail(email, 10, { nickname, rejectionReason: reason || 'Не указана' }); + +module.exports = { + sendEmail, + sendTemplate, + sendVerificationEmail, + sendWelcomeEmail, + sendPasswordResetEmail, + sendPasswordChangedEmail, + sendNicknameChangedEmail, + sendEmailChangeCode, + sendApplicationApprovedEmail, + sendApplicationRejectedEmail, +}; diff --git a/legacy/owyxsite/backend/src/utils/emailTemplates.js b/legacy/owyxsite/backend/src/utils/emailTemplates.js new file mode 100644 index 00000000000..9b6402e9557 --- /dev/null +++ b/legacy/owyxsite/backend/src/utils/emailTemplates.js @@ -0,0 +1,162 @@ +// Built-in Owyx email templates (inline CSS, dark + cyan, mobile-friendly). +// Version-controlled and renderable without a database or SMTP, so they can be +// previewed/tested any time. render(key, vars) -> { subject, html }. + +const BRAND = { + name: "Owyx", + accent: "#00e5ff", + ink: "#041018", + bg: "#050508", + panel: "#131319", + line: "#2a2b30", + text: "#f3f4f6", + muted: "#9aa0a8", + site: "https://owyx.site", + discord: "https://discord.gg/owyx", +}; + +function esc(v) { + return String(v ?? "").replace(/[&<>"']/g, (c) => ( + { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c] + )); +} + +// Shared shell. `button` is optional { href, label }. +function layout({ title, intro, bodyHtml, button, footerNote }) { + const btn = button + ? ` + ${esc(button.label)} + + + Если кнопка не работает, скопируйте ссылку:
+ ${esc(button.href)} + ` + : ""; + + return ` + + +${esc(title)} + + + +
+ + + + + +
+ Owyx +
+

${esc(title)}

+

${intro}

+
+ + ${bodyHtml || ""} + ${btn} +
+
+
+

+ ${footerNote || `Это письмо отправлено сервисом ${BRAND.name}.`}
+ ${BRAND.site.replace("https://", "")} +  ·  + Discord +

+
+

© ${new Date().getFullYear()} Owyx

+
+`; +} + +const templates = { + verify: (v) => ({ + subject: "Owyx — подтвердите email", + html: layout({ + title: "Подтвердите email", + intro: `Привет, ${esc(v.nickname || "игрок")}! Осталось подтвердить адрес — и аккаунт Owyx готов.`, + button: { href: v.verificationLink || "#", label: "Подтвердить email" }, + footerNote: "Если вы не создавали аккаунт Owyx — просто проигнорируйте это письмо.", + }), + }), + + reset: (v) => ({ + subject: "Owyx — сброс пароля", + html: layout({ + title: "Сброс пароля", + intro: `Мы получили запрос на смену пароля для аккаунта ${esc(v.nickname || "игрок")}. Ссылка действует ограниченное время.`, + button: { href: v.resetLink || "#", label: "Сменить пароль" }, + footerNote: "Если вы не запрашивали сброс — проигнорируйте письмо, пароль останется прежним.", + }), + }), + + passwordChanged: (v) => ({ + subject: "Owyx — пароль изменён", + html: layout({ + title: "Пароль изменён", + intro: `Пароль аккаунта ${esc(v.nickname || "игрок")} только что был изменён.`, + bodyHtml: `Если это были не вы — срочно восстановите доступ через «Забыли пароль» и напишите в Discord.`, + button: { href: `${BRAND.site}/login`, label: "Войти" }, + footerNote: "Уведомление о безопасности аккаунта Owyx.", + }), + }), + + welcome: (v) => ({ + subject: "Owyx — добро пожаловать", + html: layout({ + title: "Добро пожаловать в Owyx", + intro: `Привет, ${esc(v.nickname || "игрок")}! Аккаунт активен. Скачай лаунчер, войди этим же аккаунтом — и играй.`, + bodyHtml: `Гостю хватит ника, а аккаунт даёт скин и плюшки.`, + button: { href: `${BRAND.site}/download`, label: "Скачать лаунчер" }, + footerNote: "Рады видеть тебя в Owyx.", + }), + }), + + emailChange: (v) => ({ + subject: "Owyx — подтверждение новой почты", + html: layout({ + title: "Смена email", + intro: `Кто-то (надеемся, вы) указал этот адрес как новую почту аккаунта Owyx. Введите код на сайте, чтобы подтвердить смену.`, + bodyHtml: ` +
${esc(v.code || "------")}
+ + Код действует 15 минут. Если это были не вы — просто проигнорируйте письмо, почта не изменится.`, + footerNote: "Подтверждение смены email аккаунта Owyx.", + }), + }), + + nicknameChanged: (v) => ({ + subject: "Owyx — ник изменён", + html: layout({ + title: "Ник изменён", + intro: `Ник аккаунта изменён с ${esc(v.oldNick || "—")} на ${esc(v.newNick || "—")}.`, + bodyHtml: `Если это были не вы — напишите в Discord. Следующая смена ника доступна через 30 дней.`, + footerNote: "Уведомление о безопасности аккаунта Owyx.", + }), + }), +}; + +function render(key, vars = {}) { + const t = templates[key]; + if (!t) throw new Error(`Unknown email template: ${key}`); + return t(vars); +} + +const TEMPLATE_KEYS = Object.keys(templates); + +module.exports = { render, TEMPLATE_KEYS, BRAND }; diff --git a/legacy/owyxsite/backend/src/utils/turnstile.js b/legacy/owyxsite/backend/src/utils/turnstile.js new file mode 100644 index 00000000000..402e5775900 --- /dev/null +++ b/legacy/owyxsite/backend/src/utils/turnstile.js @@ -0,0 +1,72 @@ +// Cloudflare Turnstile verification + +const TURNSTILE_VERIFY_URL = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'; + +/** + * Verify Cloudflare Turnstile token. + * Set TURNSTILE_SECRET_KEY in env. When TURNSTILE_SKIP=true (local/dev), always pass. + */ +async function verifyTurnstile(token, remoteip = null) { + const production = process.env.NODE_ENV === 'production'; + if ( + process.env.NODE_ENV === 'test' || + (process.env.TURNSTILE_SKIP === 'true' && !production) + ) { + return { success: true, skipped: true }; + } + + const secret = process.env.TURNSTILE_SECRET_KEY || process.env.TURNSTILE_SECRET; + if (!secret) { + if (production) { + console.error('TURNSTILE_SECRET_KEY is required in production'); + return { + success: false, + message: 'Проверка капчи временно недоступна', + misconfigured: true, + }; + } + console.warn('TURNSTILE_SECRET_KEY not set — skipping Turnstile verification in development'); + return { success: true, skipped: true }; + } + + if (!token) { + return { + success: false, + message: 'Turnstile токен не предоставлен', + }; + } + + try { + const formData = new URLSearchParams(); + formData.append('secret', secret); + formData.append('response', token); + if (remoteip) formData.append('remoteip', remoteip); + + const response = await fetch(TURNSTILE_VERIFY_URL, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: formData.toString(), + }); + + const data = await response.json(); + + if (data.success) { + return { success: true }; + } + + console.error('Turnstile verification failed:', data); + return { + success: false, + message: 'Проверка капчи не пройдена', + errorCodes: data['error-codes'], + }; + } catch (error) { + console.error('Turnstile verification error:', error); + return { + success: false, + message: 'Ошибка проверки капчи на сервере', + }; + } +} + +module.exports = { verifyTurnstile }; diff --git a/legacy/owyxsite/backend/tsconfig.json b/legacy/owyxsite/backend/tsconfig.json new file mode 100644 index 00000000000..680175081bc --- /dev/null +++ b/legacy/owyxsite/backend/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "lib": ["ES2022"], + "outDir": "dist", + "rootDir": "src", + "strict": false, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "declaration": false, + "allowJs": true, + "checkJs": false, + "moduleResolution": "node", + "types": ["node"] + }, + "include": ["src/**/*.ts", "src/**/*.js"], + "exclude": ["node_modules", "dist"] +} diff --git a/legacy/owyxsite/backend/uploads/.gitkeep b/legacy/owyxsite/backend/uploads/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/legacy/owyxsite/backup.sh b/legacy/owyxsite/backup.sh new file mode 100644 index 00000000000..a07fb27ee82 --- /dev/null +++ b/legacy/owyxsite/backup.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +# ============================================== +# OWYX Database Backup Script +# ============================================== +# Автоматический бэкап PostgreSQL базы данных +# +# Использование: +# chmod +x backup.sh +# ./backup.sh +# +# Автоматизация (cron): +# crontab -e +# 0 3 * * * /path/to/owyx/backup.sh + +set -e + +# Конфигурация +BACKUP_DIR="./backups" +TIMESTAMP=$(date +%Y%m%d_%H%M%S) +BACKUP_FILE="owyx_backup_${TIMESTAMP}.sql" +CONTAINER_NAME="owyx-postgres" +DB_NAME="owyx_db" +DB_USER="owyx_user" + +# Количество дней хранения бэкапов +RETENTION_DAYS=7 + +# Цвета +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo "🗄️ OWYX Database Backup" +echo "====================================" +echo "" + +# Создание папки для бэкапов +mkdir -p "$BACKUP_DIR" + +# Проверка что контейнер запущен +if ! docker ps | grep -q "$CONTAINER_NAME"; then + echo -e "${RED}Ошибка: Контейнер $CONTAINER_NAME не запущен!${NC}" + exit 1 +fi + +# Создание бэкапа +echo "Создание бэкапа базы данных $DB_NAME..." +docker exec "$CONTAINER_NAME" pg_dump -U "$DB_USER" "$DB_NAME" > "$BACKUP_DIR/$BACKUP_FILE" + +if [ $? -eq 0 ]; then + # Сжатие + echo "Сжатие бэкапа..." + gzip "$BACKUP_DIR/$BACKUP_FILE" + BACKUP_FILE="${BACKUP_FILE}.gz" + + # Размер файла + SIZE=$(du -h "$BACKUP_DIR/$BACKUP_FILE" | cut -f1) + + echo -e "${GREEN}✓ Бэкап создан: $BACKUP_FILE ($SIZE)${NC}" + + # Удаление старых бэкапов + echo "Удаление бэкапов старше $RETENTION_DAYS дней..." + find "$BACKUP_DIR" -name "owyx_backup_*.sql.gz" -mtime +$RETENTION_DAYS -delete + + # Количество бэкапов + COUNT=$(ls -1 "$BACKUP_DIR"/owyx_backup_*.sql.gz 2>/dev/null | wc -l) + echo -e "${GREEN}Всего бэкапов: $COUNT${NC}" + + # Опционально: загрузка в облако (раскомментируйте если настроен rclone) + # echo "Загрузка в облако..." + # rclone copy "$BACKUP_DIR/$BACKUP_FILE" remote:backups/owyx/ + +else + echo -e "${RED}Ошибка при создании бэкапа!${NC}" + exit 1 +fi + +echo "" +echo "====================================" +echo -e "${GREEN}✅ Бэкап завершен!${NC}" +echo "====================================" diff --git a/legacy/owyxsite/deploy/OBT_PREP.md b/legacy/owyxsite/deploy/OBT_PREP.md new file mode 100644 index 00000000000..00242986520 --- /dev/null +++ b/legacy/owyxsite/deploy/OBT_PREP.md @@ -0,0 +1,68 @@ +# OBT prep — separate VPS (site + API only) + +**Status:** preparation only (domains, client key, secrets, bootstrap). Full public cutover when DNS + Turnstile + SMTP are live. + +## Domains + +| Host | Role | +|------|------| +| `https://owyx.site` | Website (Next). Browser `/api` same-origin → backend. **No** launcher client key. | +| `https://api.owyx.site` | Launcher API + `/uploads`. Requires header `X-Owyx-Client-Key`. | +| `panel.owyx.site` | VPN / C³ — **other VPS**, do not touch. | + +Game join (FRPC): `45.131.186.146:1488` (RU VPS → MiniPC). Not hosted on the Owyx site VPS. + +## Client key + +- Site env: `LAUNCHER_CLIENT_KEY` +- Launcher: `OWYX_CLIENT_KEY` or `%USERPROFILE%/owyx/client_key` +- Header: `X-Owyx-Client-Key` +- `/health` on api host stays open for probes + +This is **not** end-user login. It stops random scrapers from using the launcher API as a free public API. JWT still required for `/me` and admin. + +## Local secrets (gitignored) + +Already generated on the owner machine (do not commit): + +- `owyxsite/.env` +- `Launcher/.env` +- `%USERPROFILE%/owyx/client_key` + +For VPS: copy `owyxsite/.env`, set `NODE_ENV=production`, real `TURNSTILE_SECRET_KEY`, SMTP, strong `ADMIN_PASSWORD`. + +## Clean VPS checklist + +```bash +ssh owyxsite +# then: +curl -fsSL https://raw.githubusercontent.com/ebluffy/Owyx/main/owyxsite/deploy/bootstrap-vps.sh | sudo bash +# or from a cloned repo: +sudo bash /opt/owyx/owyxsite/deploy/bootstrap-vps.sh +``` + +1. DNS A records → new VPS IP +2. `bootstrap-vps.sh` (docker, nginx, swap, ufw) +3. Clone repo → place `.env` +4. `bash deploy/vps-up.sh` (no `--dev`) +5. Enable `deploy/nginx-owyx.site.conf` +6. `certbot --nginx -d owyx.site -d www.owyx.site -d api.owyx.site` +7. Smoke: `curl https://owyx.site/` · `curl https://api.owyx.site/health` · launcher with client key + +## Launcher OBT build + +```powershell +# Launcher/.env already has api.owyx.site + client key +cd Launcher/apps/launcher +npm run build:smoke +Copy-Item -Force src-tauri\target\debug\owyx.exe ..\..\Owyx.debug.exe +``` + +Ship a GitHub Release later (separate task). + +## Out of this prep + +- Full production Turnstile + email go-live +- Microsoft OAuth +- Full mrpack / multi-GB resume +- Merging onto the VPN VPS diff --git a/legacy/owyxsite/deploy/README.md b/legacy/owyxsite/deploy/README.md new file mode 100644 index 00000000000..367df7244f8 --- /dev/null +++ b/legacy/owyxsite/deploy/README.md @@ -0,0 +1,48 @@ +# Owyx site — Docker + nginx on a dedicated VPS + +Owns **`owyx.site`** (website) and **`api.owyx.site`** (launcher API). +Never writes **`panel.owyx.site`** (C³ CELERITY / VPN — other machine). + +OBT prep: [`OBT_PREP.md`](./OBT_PREP.md). Fresh box: [`bootstrap-vps.sh`](./bootstrap-vps.sh). + +## Local (Cloud VM / laptop) + +```bash +cd owyxsite +bash deploy/vps-up.sh --dev +curl -sf http://127.0.0.1:3001/health +``` + +### Launcher against this compose + +```bash +export OWYX_API_BASE_URL=http://127.0.0.1:3001 +# client key optional on loopback (Host is not api.owyx.site) +cd ../Launcher/apps/launcher +npm run dev:tauri +``` + +Pack zip overlay is capped at **512 MB** in the launcher (`MAX_PACK_BYTES`). + +## Dedicated Owyx VPS (recommended for OBT) + +1. DNS A: `owyx.site`, `www.owyx.site`, `api.owyx.site` → this VPS. Leave `panel.owyx.site` alone. +2. `sudo bash deploy/bootstrap-vps.sh` +3. Clone under `/opt/owyx`, place `.env` (`LAUNCHER_CLIENT_KEY`, secrets, real `TURNSTILE_SECRET_KEY`) +4. `bash deploy/vps-up.sh` (no `--dev`) +5. Enable `deploy/nginx-owyx.site.conf`, then certbot for all three names +6. Firewall: 80/443 public; do **not** expose 3000/3001/5432 + +Launcher prod: `https://api.owyx.site` + header `X-Owyx-Client-Key`. + +## Port playbook + +| Service | Default | Prod bind | +|----------|---------|-----------| +| frontend | 3000 | `127.0.0.1` | +| backend | 3001 | `127.0.0.1` | +| postgres | 5432 | `127.0.0.1` | + +## Fresh vs old Postgres volume + +`initdb.d` runs only on empty volumes. Apply `007_servers_packs.sql` on old DBs; owner `owyx_user`. diff --git a/legacy/owyxsite/deploy/bootstrap-vps.sh b/legacy/owyxsite/deploy/bootstrap-vps.sh new file mode 100644 index 00000000000..db071e03627 --- /dev/null +++ b/legacy/owyxsite/deploy/bootstrap-vps.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# Bootstrap a clean Ubuntu VPS for Owyx site+API (NOT the VPN panel box). +# Run once as root or with sudo: bash deploy/bootstrap-vps.sh +set -euo pipefail + +if [[ "${EUID}" -ne 0 ]]; then + echo "Re-run with sudo" >&2 + exit 1 +fi + +export DEBIAN_FRONTEND=noninteractive + +apt-get update -y +apt-get install -y ca-certificates curl git nginx certbot python3-certbot-nginx ufw + +# Swap (1–2G) — important on 2GB RAM boxes +if ! swapon --show | grep -q .; then + fallocate -l 2G /swapfile || dd if=/dev/zero of=/swapfile bs=1M count=2048 + chmod 600 /swapfile + mkswap /swapfile + swapon /swapfile + grep -q '/swapfile' /etc/fstab || echo '/swapfile none swap sw 0 0' >> /etc/fstab +fi + +# Docker +if ! command -v docker >/dev/null 2>&1; then + curl -fsSL https://get.docker.com | sh + systemctl enable --now docker +fi + +mkdir -p /var/www/certbot /opt/owyx +ufw allow OpenSSH +ufw allow 80/tcp +ufw allow 443/tcp +ufw --force enable || true + +echo +echo "OK — next steps:" +echo " 1) DNS A: owyx.site, www.owyx.site, api.owyx.site → this VPS" +echo " 2) git clone https://github.com/ebluffy/Owyx.git /opt/owyx && cd /opt/owyx/owyxsite" +echo " 3) copy prepared .env (LAUNCHER_CLIENT_KEY, secrets, TURNSTILE_SECRET_KEY)" +echo " 4) bash deploy/vps-up.sh" +echo " 5) ln -sf \$PWD/deploy/nginx-owyx.site.conf /etc/nginx/sites-enabled/owyx-site.conf" +echo " 6) certbot --nginx -d owyx.site -d www.owyx.site -d api.owyx.site" +echo " 7) nginx -t && systemctl reload nginx" +echo "See deploy/OBT_PREP.md" diff --git a/legacy/owyxsite/deploy/nginx-owyx.site.conf b/legacy/owyxsite/deploy/nginx-owyx.site.conf new file mode 100644 index 00000000000..53b29a361cf --- /dev/null +++ b/legacy/owyxsite/deploy/nginx-owyx.site.conf @@ -0,0 +1,145 @@ +# Host nginx for Owyx control-plane (separate VPS from panel.owyx.site). +# +# DNS on this VPS: +# owyx.site / www.owyx.site — public website (Next) +# api.owyx.site — launcher API only (Express + uploads) +# +# panel.owyx.site stays on the VPN box — NEVER add it here. +# +# After certbot: +# sudo ln -sf /opt/owyx/owyxsite/deploy/nginx-owyx.site.conf /etc/nginx/sites-enabled/owyx-site.conf +# sudo nginx -t && sudo systemctl reload nginx +# +# Upstream ports = FRONTEND_PORT / API_PORT in owyxsite/.env (defaults 3000 / 3001). + +upstream owyx_frontend { + server 127.0.0.1:3000; + keepalive 16; +} + +upstream owyx_backend { + server 127.0.0.1:3001; + keepalive 16; +} + +# ---- HTTP (certbot + redirect) -------------------------------------------- +server { + listen 80; + listen [::]:80; + server_name owyx.site www.owyx.site api.owyx.site; + + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } + + location / { + return 301 https://$host$request_uri; + } +} + +# ---- HTTPS: website ------------------------------------------------------- +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name owyx.site www.owyx.site; + + ssl_certificate /etc/letsencrypt/live/owyx.site/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/owyx.site/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + client_max_body_size 50M; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + + # Browser same-origin API (no X-Owyx-Client-Key; Host stays owyx.site) + location /api/ { + proxy_pass http://owyx_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + } + + location = /api { + proxy_pass http://owyx_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /uploads/ { + proxy_pass http://owyx_backend; + expires 30d; + add_header Cache-Control "public"; + } + + location /socket.io/ { + proxy_pass http://owyx_backend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 86400; + } + + location / { + proxy_pass http://owyx_frontend; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_read_timeout 300s; + } +} + +# ---- HTTPS: launcher API host (requires X-Owyx-Client-Key) ---------------- +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name api.owyx.site; + + ssl_certificate /etc/letsencrypt/live/api.owyx.site/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/api.owyx.site/privkey.pem; + include /etc/letsencrypt/options-ssl-nginx.conf; + ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; + + client_max_body_size 50M; + + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + + location /health { + proxy_pass http://owyx_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location / { + proxy_pass http://owyx_backend; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_read_timeout 300s; + } +} diff --git a/legacy/owyxsite/deploy/vps-up.sh b/legacy/owyxsite/deploy/vps-up.sh new file mode 100644 index 00000000000..dd5511f5d80 --- /dev/null +++ b/legacy/owyxsite/deploy/vps-up.sh @@ -0,0 +1,311 @@ +#!/usr/bin/env bash +# Bring up the Owyx site stack on a VPS (or Cloud VM) next to an existing +# host nginx / C³ CELERITY panel. Does not touch panel.owyx.site. +# +# Usage (from repo root or owyxsite/): +# bash owyxsite/deploy/vps-up.sh # prod overlay: loopback binds +# bash owyxsite/deploy/vps-up.sh --dev # default compose (all ports) +# +# Idempotent. Does not commit .env. Never binds 443 — host nginx owns TLS. +# +# Order: write/load .env → --dev vs prod Turnstile/NODE_ENV → source ports → +# audit → compose up → health. Do not audit or print "ready" on stale defaults. + +set -euo pipefail + +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" + +DEV_MODE=0 +if [[ "${1:-}" == "--dev" ]]; then + DEV_MODE=1 +fi + +docker_cmd() { + if docker info >/dev/null 2>&1; then + docker "$@" + elif command -v sudo >/dev/null 2>&1 && sudo docker info >/dev/null 2>&1; then + sudo docker "$@" + else + echo "error: docker is not running (need docker + compose plugin)" >&2 + exit 1 + fi +} + +need_bin() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "error: missing command: $1" >&2 + exit 1 + fi +} + +# 32 bytes → 64 hex chars. Fail (do not swallow) if urandom/od is broken. +rand() { + local hex + hex="$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')" + if [[ "${#hex}" -lt 32 ]]; then + echo "error: failed to read /dev/urandom for a secret" >&2 + exit 1 + fi + printf '%s' "${hex}" +} + +# Replace KEY=... in .env (or append). Values must be sed-safe (hex/tokens/URLs). +set_env_key() { + local key="$1" val="$2" + if grep -qE "^${key}=" .env; then + sed -i "s|^${key}=.*|${key}=${val}|" .env + else + printf '%s=%s\n' "${key}" "${val}" >> .env + fi +} + +env_looks_placeholder() { + local val="${1:-}" + [[ -z "${val}" ]] && return 0 + case "${val}" in + *change_me*|*generate_random*|*your_secure*|*your_admin*) + return 0 + ;; + esac + return 1 +} + +load_env_file() { + if [[ ! -f .env ]]; then + echo "error: .env is missing" >&2 + exit 1 + fi + set -a + # shellcheck disable=SC1091 + . ./.env + set +a + FRONTEND_PORT="${FRONTEND_PORT:-3000}" + API_PORT="${API_PORT:-3001}" + POSTGRES_PORT="${POSTGRES_PORT:-5432}" + ADMINER_PORT="${ADMINER_PORT:-8080}" + FRONTEND_BIND="${FRONTEND_BIND:-}" + API_BIND="${API_BIND:-}" + POSTGRES_BIND="${POSTGRES_BIND:-}" +} + +assert_secrets_are_real() { + local key val + for key in DB_PASSWORD JWT_SECRET SESSION_SECRET; do + val="${!key:-}" + if env_looks_placeholder "${val}"; then + echo "error: ${key} is empty or still a .env.example placeholder" >&2 + echo " generate a real value and re-run (script fails closed)." >&2 + exit 1 + fi + done +} + +apply_turnstile_policy() { + if [[ "${DEV_MODE}" -eq 1 ]]; then + # SKIP is honored only when NODE_ENV is not production (see turnstile.js). + set_env_key NODE_ENV development + return 0 + fi + + set_env_key TURNSTILE_SKIP false + local secret="${TURNSTILE_SECRET_KEY:-${TURNSTILE_SECRET:-}}" + if [[ -z "${secret}" ]]; then + echo "error: production compose requires TURNSTILE_SECRET_KEY in .env" >&2 + echo " TURNSTILE_SKIP is ignored when NODE_ENV=production — login/register fail-close." >&2 + echo " Set TURNSTILE_SECRET_KEY (Cloudflare), or re-run with --dev for local skip." >&2 + exit 1 + fi +} + +# Prod path is loopback + host nginx. .env.example ships 0.0.0.0; ${VAR:-127.0.0.1} +# does not override an already-set 0.0.0.0 after load_env_file. Always rewrite. +apply_prod_loopback_binds() { + set_env_key FRONTEND_BIND "127.0.0.1" + set_env_key API_BIND "127.0.0.1" + set_env_key POSTGRES_BIND "127.0.0.1" + set_env_key TRUST_PROXY_HOPS "${TRUST_PROXY_HOPS:-1}" + FRONTEND_BIND=127.0.0.1 + API_BIND=127.0.0.1 + POSTGRES_BIND=127.0.0.1 + export FRONTEND_BIND API_BIND POSTGRES_BIND + export TRUST_PROXY_HOPS="${TRUST_PROXY_HOPS:-1}" +} + +echo "==> Owyx VPS / local compose up" +echo " root: ${ROOT}" +need_bin curl +if ! command -v docker >/dev/null 2>&1; then + echo "error: docker not installed" >&2 + exit 1 +fi +if ! docker_cmd compose version >/dev/null 2>&1; then + echo "error: docker compose plugin missing" >&2 + exit 1 +fi + +if command -v nginx >/dev/null 2>&1; then + echo " nginx: $(nginx -v 2>&1 || true) (host TLS — we do not bind :443)" +else + echo " nginx: not on PATH (optional; host panel/TLS is out of this script)" +fi + +# --- .env first (compose and health both read these ports) --- +if [[ ! -f .env ]]; then + echo "==> writing .env from .env.example (random secrets — not committed)" + if [[ ! -f .env.example ]]; then + echo "error: missing .env.example" >&2 + exit 1 + fi + cp .env.example .env + set_env_key DB_PASSWORD "$(rand)" + set_env_key JWT_SECRET "$(rand)" + set_env_key SESSION_SECRET "$(rand)" + set_env_key DIRECTUS_KEY "$(rand)" + set_env_key DIRECTUS_SECRET "$(rand)" + if [[ "${DEV_MODE}" -eq 1 ]]; then + set_env_key NODE_ENV development + set_env_key TURNSTILE_SKIP true + set_env_key FRONTEND_URL "http://localhost:3000" + set_env_key PUBLIC_URL "http://localhost:3000" + set_env_key CORS_ORIGIN "http://localhost:3000" + set_env_key NEXT_PUBLIC_API_URL "http://localhost:3000/api" + else + set_env_key NODE_ENV production + set_env_key TURNSTILE_SKIP false + apply_prod_loopback_binds + fi + echo " created ${ROOT}/.env (keep it off git)" +else + echo "==> using existing .env" +fi + +if [[ "${DEV_MODE}" -eq 0 ]]; then + apply_prod_loopback_binds +fi +load_env_file +export FRONTEND_PORT API_PORT POSTGRES_PORT ADMINER_PORT + +assert_secrets_are_real +apply_turnstile_policy +# Policy may have rewritten NODE_ENV / TURNSTILE_*; re-source so compose + health match the file. +if [[ "${DEV_MODE}" -eq 0 ]]; then + apply_prod_loopback_binds +fi +load_env_file +export FRONTEND_PORT API_PORT POSTGRES_PORT ADMINER_PORT + +port_listeners() { + local port="$1" + if command -v ss >/dev/null 2>&1; then + ss -tlnp 2>/dev/null | awk -v p=":${port}" '$4 ~ p"$" || $4 ~ p" "' || true + elif command -v lsof >/dev/null 2>&1; then + lsof -nP -iTCP:"${port}" -sTCP:LISTEN 2>/dev/null || true + else + echo "(no ss/lsof — skipped)" + fi +} + +is_owyx_container_port() { + local port="$1" + docker_cmd ps --format '{{.Names}} {{.Ports}}' 2>/dev/null | grep -E "owyx-" | grep -q ":${port}->" || return 1 +} + +suggest_alt() { + local name="$1" current="$2" + echo " set ${name}=$((current + 10)) (or another free port) in .env and re-run" +} + +echo "==> port audit (from .env: frontend=${FRONTEND_PORT} api=${API_PORT} postgres=${POSTGRES_PORT})" +PROBLEMS=0 +audit_port() { + local label="$1" port="$2" envname="$3" + local listeners + listeners="$(port_listeners "${port}")" + if [[ -z "${listeners}" || "${listeners}" == "(no ss/lsof — skipped)" ]]; then + echo " ${label} :${port} free" + return 0 + fi + if is_owyx_container_port "${port}"; then + echo " ${label} :${port} our owyx container — will recreate" + return 0 + fi + echo " ${label} :${port} BUSY (not an owyx-* container):" + echo "${listeners}" | sed 's/^/ /' + suggest_alt "${envname}" "${port}" + PROBLEMS=1 +} + +audit_port "frontend" "${FRONTEND_PORT}" "FRONTEND_PORT" +audit_port "api" "${API_PORT}" "API_PORT" +audit_port "postgres" "${POSTGRES_PORT}" "POSTGRES_PORT" +if [[ "${DEV_MODE}" -eq 1 ]]; then + audit_port "adminer" "${ADMINER_PORT}" "ADMINER_PORT" +fi + +if [[ "${PROBLEMS}" -ne 0 ]]; then + echo "error: one or more ports are taken by something else. Fix .env and retry." >&2 + echo " Host nginx on :80/:443 is expected and OK — we only bind app ports." >&2 + echo " panel.owyx.site (C³ CELERITY) must keep its own server block — do not steal :443." >&2 + exit 1 +fi + +if docker_cmd ps --format '{{.Names}}' 2>/dev/null | grep -qE '^owyx-(frontend|backend|postgres|adminer)$'; then + echo "==> stopping previous owyx compose stack" + if [[ "${DEV_MODE}" -eq 1 ]]; then + docker_cmd compose down --remove-orphans || true + else + docker_cmd compose -f docker-compose.yml -f docker-compose.prod.yml down --remove-orphans || true + fi +fi + +COMPOSE=(compose) +if [[ "${DEV_MODE}" -eq 0 ]]; then + COMPOSE+=( -f docker-compose.yml -f docker-compose.prod.yml ) +fi + +echo "==> docker compose up -d --build" +docker_cmd "${COMPOSE[@]}" up -d --build + +wait_http() { + local url="$1" label="$2" n=0 + echo -n " waiting ${label} (${url})" + while [[ "${n}" -lt 90 ]]; do + if curl -sf -o /dev/null "${url}"; then + echo " OK" + return 0 + fi + echo -n "." + sleep 2 + n=$((n + 1)) + done + echo " FAIL" + return 1 +} + +echo "==> health" +HEALTH=0 +wait_http "http://127.0.0.1:${API_PORT}/health" "backend /health" || HEALTH=1 +wait_http "http://127.0.0.1:${FRONTEND_PORT}/" "frontend /" || HEALTH=1 + +echo "==> docker compose ps" +docker_cmd "${COMPOSE[@]}" ps + +echo +echo "==> URLs" +echo " frontend http://127.0.0.1:${FRONTEND_PORT}/" +echo " backend http://127.0.0.1:${API_PORT}/health" +echo " launcher OWYX_API_BASE_URL=http://127.0.0.1:${API_PORT}" +if [[ "${DEV_MODE}" -eq 1 ]]; then + echo " adminer http://127.0.0.1:${ADMINER_PORT}/ (debug)" + echo " turnstile NODE_ENV=development — TURNSTILE_SKIP=true is honored" +else + echo " bind loopback only — put host nginx in front (deploy/nginx-owyx.site.conf)" + echo " panel panel.owyx.site is NOT managed here (C³ CELERITY)" +fi + +if [[ "${HEALTH}" -ne 0 ]]; then + echo "error: health check failed — see docker compose logs" >&2 + exit 1 +fi +echo "==> ready" diff --git a/legacy/owyxsite/directus/README.md b/legacy/owyxsite/directus/README.md new file mode 100644 index 00000000000..fa6cc67a399 --- /dev/null +++ b/legacy/owyxsite/directus/README.md @@ -0,0 +1,48 @@ +# Directus on Owyx + +Directus connects to the **same PostgreSQL** database as the custom Express API (`owyx_db`). +It is used as an admin/CMS UI for content and for future collections — **not** as the primary auth for the Minecraft plugin. + +## First boot + +1. Start the stack: `cd owyx && docker compose up -d` +2. Open Directus: `http://localhost:8055` (or behind `https://owyx.site` if proxied) +3. Log in with `ADMIN_EMAIL` / `ADMIN_PASSWORD` from `.env` + +## Introspect existing tables + +Existing app tables come from `postgres/init.sql` (`users`, `applications`, `forum_*`, etc.). +Directus will create its own system tables (`directus_*`) alongside them. + +To manage existing tables in Directus: + +1. **Settings → Data Model → Create Collection** +2. Choose **“Import existing table” / “Existing”** (wording depends on Directus version) +3. Pick tables you want to expose (start with: `server_settings`, `forum_categories`, `forum_topics`, `applications`) +4. For each collection, configure fields visibility and relationships + +Do **not** let Directus own auth for game login — keep JWT sessions in Express (`/api/auth/*`). + +## Role checklist + +Create / map these Directus roles to match the site: + +| Role | Purpose | Suggested access | +|------|---------|------------------| +| **Administrator** | Full Directus + all collections | Full CRUD | +| **Moderator** | Content + applications moderation | Read users; CRUD applications, forum_*, admin_logs (read) | +| **User** | Authenticated site users (optional Directus login later) | Read public content; create own forum posts | +| **Public** | Anonymous | Read `server_settings` public keys, forum categories (if published) | + +Also keep the Express roles (`users.role`: `user` / `moderator` / `admin`) for API authorization — they are independent of Directus roles until you sync them intentionally. + +## Recommended collections to expose first + +- `server_settings` — editable from Directus *or* Express `/api/admin/settings` +- `forum_categories`, `forum_topics`, `forum_posts` +- `email_templates` +- `applications` (read-only in Directus if moderation stays in Express admin UI) + +## Env + +See `owyx/.env.example` (`DIRECTUS_KEY`, `DIRECTUS_SECRET`, `ADMIN_*`, `PUBLIC_URL`). diff --git a/legacy/owyxsite/directus/extensions/.gitkeep b/legacy/owyxsite/directus/extensions/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/legacy/owyxsite/docker-compose.prod.yml b/legacy/owyxsite/docker-compose.prod.yml new file mode 100644 index 00000000000..b89cf593dd4 --- /dev/null +++ b/legacy/owyxsite/docker-compose.prod.yml @@ -0,0 +1,28 @@ +# Production / VPS override. Used by deploy/vps-up.sh (not --dev). +# +# Bind app ports on loopback so host nginx can terminate TLS for owyx.site. +# Do not publish Postgres on a public interface. Adminer is debug-only. +# +# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build +# +# Set TRUST_PROXY_HOPS=1 in .env when nginx sits in front. + +services: + postgres: + ports: !override + - "${POSTGRES_BIND:-127.0.0.1}:${POSTGRES_PORT:-5432}:5432" + + backend: + ports: !override + - "${API_BIND:-127.0.0.1}:${API_PORT:-3001}:3001" + environment: + TRUST_PROXY_HOPS: ${TRUST_PROXY_HOPS:-1} + + frontend: + ports: !override + - "${FRONTEND_BIND:-127.0.0.1}:${FRONTEND_PORT:-3000}:3000" + + adminer: + profiles: ["debug"] + ports: !override + - "${ADMINER_BIND:-127.0.0.1}:${ADMINER_PORT:-8080}:8080" diff --git a/legacy/owyxsite/docker-compose.yml b/legacy/owyxsite/docker-compose.yml new file mode 100644 index 00000000000..7caa4f6d038 --- /dev/null +++ b/legacy/owyxsite/docker-compose.yml @@ -0,0 +1,183 @@ +# One compose brings up the whole Owyx site: Postgres + Adminer + backend + +# frontend. Directus is optional (profile "directus"). +# +# cp .env.example .env # set DB_PASSWORD / JWT_SECRET / SESSION_SECRET +# docker compose up -d --build +# +# Ports: frontend 3000 · backend 3001 · postgres 5432 · adminer 8080 · directus 8055 (profile) + +services: + postgres: + image: postgres:17-alpine + container_name: owyx-postgres + environment: + - TZ=Europe/Moscow + - POSTGRES_USER=${DB_USER:-owyx_user} + - POSTGRES_PASSWORD=${DB_PASSWORD} + - POSTGRES_DB=${DB_NAME:-owyx_db} + volumes: + - ./postgres/data:/var/lib/postgresql/data + - ./postgres/migrations/000_bootstrap_roles.sql:/docker-entrypoint-initdb.d/00_bootstrap_roles.sql:ro + - ./postgres/init.sql:/docker-entrypoint-initdb.d/01_init.sql:ro + - ./postgres/migrations/001_chat.sql:/docker-entrypoint-initdb.d/02_chat.sql:ro + - ./postgres/migrations/002_roles.sql:/docker-entrypoint-initdb.d/03_roles.sql:ro + - ./postgres/migrations/003_cosmetics.sql:/docker-entrypoint-initdb.d/04_cosmetics.sql:ro + - ./postgres/migrations/004_nickname_cooldown.sql:/docker-entrypoint-initdb.d/05_nickname.sql:ro + - ./postgres/migrations/005_email_change.sql:/docker-entrypoint-initdb.d/06_email_change.sql:ro + - ./postgres/migrations/006_news.sql:/docker-entrypoint-initdb.d/07_news.sql:ro + - ./postgres/migrations/007_servers_packs.sql:/docker-entrypoint-initdb.d/08_servers_packs.sql:ro + ports: + - "${POSTGRES_BIND:-0.0.0.0}:${POSTGRES_PORT:-5432}:5432" + restart: always + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-owyx_user} -d ${DB_NAME:-owyx_db}"] + interval: 10s + timeout: 5s + retries: 5 + + # Browser DB admin for debugging (http://localhost:8080, server: postgres). + adminer: + image: adminer:4 + container_name: owyx-adminer + environment: + - ADMINER_DEFAULT_SERVER=postgres + - ADMINER_DESIGN=dracula + ports: + - "${ADMINER_BIND:-0.0.0.0}:${ADMINER_PORT:-8080}:8080" + depends_on: + postgres: + condition: service_healthy + restart: unless-stopped + + directus: + image: directus/directus:11 + container_name: owyx-directus + profiles: ["directus"] + environment: + - TZ=Europe/Moscow + - KEY=${DIRECTUS_KEY} + - SECRET=${DIRECTUS_SECRET} + - DB_CLIENT=pg + - DB_HOST=postgres + - DB_PORT=5432 + - DB_DATABASE=${DB_NAME:-owyx_db} + - DB_USER=${DB_USER:-owyx_user} + - DB_PASSWORD=${DB_PASSWORD} + - ADMIN_EMAIL=${ADMIN_EMAIL} + - ADMIN_PASSWORD=${ADMIN_PASSWORD} + - PUBLIC_URL=${PUBLIC_URL:-http://localhost:8055} + - WEBSOCKETS_ENABLED=true + - CORS_ENABLED=true + - CORS_ORIGIN=${FRONTEND_URL:-http://localhost:3000} + - EMAIL_FROM=${EMAIL_FROM:-noreply@owyx.site} + - EMAIL_TRANSPORT=${EMAIL_TRANSPORT:-smtp} + - EMAIL_SMTP_HOST=${EMAIL_SMTP_HOST:-} + - EMAIL_SMTP_PORT=${EMAIL_SMTP_PORT:-587} + - EMAIL_SMTP_USER=${EMAIL_SMTP_USER:-} + - EMAIL_SMTP_PASSWORD=${EMAIL_SMTP_PASSWORD:-} + - STORAGE_LOCATIONS=local + - STORAGE_LOCAL_ROOT=/directus/uploads + - CACHE_ENABLED=true + - CACHE_STORE=memory + - CACHE_TTL=30m + volumes: + - ./directus/uploads:/directus/uploads + - ./directus/extensions:/directus/extensions + ports: + - "8055:8055" + depends_on: + postgres: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:8055/server/health"] + interval: 30s + timeout: 10s + retries: 3 + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: owyx-backend + environment: + - TZ=Europe/Moscow + - NODE_ENV=${NODE_ENV:-production} + - API_PORT=3001 + - PORT=3001 + - DB_HOST=postgres + - DB_PORT=5432 + - DB_NAME=${DB_NAME:-owyx_db} + - DB_USER=${DB_USER:-owyx_user} + - DB_PASSWORD=${DB_PASSWORD} + - JWT_SECRET=${JWT_SECRET} + - SESSION_SECRET=${SESSION_SECRET} + - FRONTEND_URL=${FRONTEND_URL:-http://localhost:3000} + - CORS_ORIGIN=${CORS_ORIGIN:-http://localhost:3000} + - TURNSTILE_SECRET_KEY=${TURNSTILE_SECRET_KEY:-} + - TURNSTILE_SKIP=${TURNSTILE_SKIP:-false} + - SMTP_HOST=${SMTP_HOST:-} + - SMTP_PORT=${SMTP_PORT:-465} + - SMTP_USER=${SMTP_USER:-} + - SMTP_PASS=${SMTP_PASS:-} + - EMAIL_SMTP_HOST=${EMAIL_SMTP_HOST:-} + - EMAIL_SMTP_PORT=${EMAIL_SMTP_PORT:-587} + - EMAIL_SMTP_USER=${EMAIL_SMTP_USER:-} + - EMAIL_SMTP_PASSWORD=${EMAIL_SMTP_PASSWORD:-} + - EMAIL_FROM=${EMAIL_FROM:-noreply@owyx.site} + - DISCORD_CLIENT_ID=${DISCORD_CLIENT_ID:-} + - DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET:-} + - PUBLIC_URL=${PUBLIC_URL:-http://localhost:3000} + - TRUST_PROXY_HOPS=${TRUST_PROXY_HOPS:-0} + volumes: + - ./backend/uploads:/app/uploads + - ./backend/fixtures:/app/fixtures:ro + ports: + - "${API_BIND:-0.0.0.0}:${API_PORT:-3001}:3001" + depends_on: + postgres: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3001/health"] + interval: 30s + timeout: 5s + retries: 3 + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + args: + - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:3000/api} + - NEXT_PUBLIC_DIRECTUS_URL=${NEXT_PUBLIC_DIRECTUS_URL:-http://localhost:8055} + - NEXT_PUBLIC_SOCKET_URL=${NEXT_PUBLIC_SOCKET_URL:-http://localhost:3001} + - BACKEND_URL=http://backend:3001 + container_name: owyx-frontend + environment: + - TZ=Europe/Moscow + - NODE_ENV=production + - PORT=3000 + - HOSTNAME=0.0.0.0 + - BACKEND_URL=http://backend:3001 + - NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-http://localhost:3000/api} + - NEXT_PUBLIC_DIRECTUS_URL=${NEXT_PUBLIC_DIRECTUS_URL:-http://localhost:8055} + - NEXT_PUBLIC_SOCKET_URL=${NEXT_PUBLIC_SOCKET_URL:-http://localhost:3001} + ports: + - "${FRONTEND_BIND:-0.0.0.0}:${FRONTEND_PORT:-3000}:3000" + depends_on: + backend: + condition: service_healthy + restart: always + healthcheck: + test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:3000/"] + interval: 30s + timeout: 10s + retries: 3 + +# --------------------------------------------------------------------------- +# Production note (GMKtec / host networking): +# If you prefer host mode like the original plan, set network_mode: host on +# each service, point Directus DB_HOST=127.0.0.1, backend DB_HOST=127.0.0.1, +# remove ports: mappings, and put Nginx in front (see nginx-conf/owyx.conf). +# --------------------------------------------------------------------------- diff --git a/legacy/owyxsite/frontend/.dockerignore b/legacy/owyxsite/frontend/.dockerignore new file mode 100644 index 00000000000..7088babb133 --- /dev/null +++ b/legacy/owyxsite/frontend/.dockerignore @@ -0,0 +1,40 @@ +# ============================================== +# Frontend Docker Build Context — исключения +# ============================================== + +# Git +.git +.gitignore + +# Node modules (будут установлены в контейнере) +node_modules + +# Next.js build output (собирается внутри контейнера) +.next + +# Конфиги IDE +.vscode +.idea +*.swp + +# Logs +*.log +npm-debug.log* + +# Environment файлы (секреты не попадают в образ) +.env +.env.local +.env.development +.env.production + +# TypeScript build info +*.tsbuildinfo + +# OS мусор +.DS_Store +Thumbs.db + +# README +README.md +AGENTS.md +CLAUDE.md diff --git a/legacy/owyxsite/frontend/.gitignore b/legacy/owyxsite/frontend/.gitignore new file mode 100644 index 00000000000..5ef6a520780 --- /dev/null +++ b/legacy/owyxsite/frontend/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/legacy/owyxsite/frontend/AGENTS.md b/legacy/owyxsite/frontend/AGENTS.md new file mode 100644 index 00000000000..643577dfaef --- /dev/null +++ b/legacy/owyxsite/frontend/AGENTS.md @@ -0,0 +1,9 @@ + + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/legacy/owyxsite/frontend/CLAUDE.md b/legacy/owyxsite/frontend/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/legacy/owyxsite/frontend/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/legacy/owyxsite/frontend/Dockerfile b/legacy/owyxsite/frontend/Dockerfile new file mode 100644 index 00000000000..b1f7b1aa0e4 --- /dev/null +++ b/legacy/owyxsite/frontend/Dockerfile @@ -0,0 +1,70 @@ +# ============================================== +# OWYX Frontend — Next.js Dockerfile +# Multi-stage build для production +# ============================================== + +# ---------- Stage 1: deps ---------- +FROM node:22-alpine AS deps +WORKDIR /app + +# Копируем package файлы +COPY package.json package-lock.json ./ + +# Устанавливаем зависимости (только production-нужные для build) +RUN npm ci + +# ---------- Stage 2: builder ---------- +FROM node:22-alpine AS builder +WORKDIR /app + +# Копируем зависимости из предыдущего stage +COPY --from=deps /app/node_modules ./node_modules + +# Копируем весь исходник +COPY . . + +# Build-time env (prefer same-origin /api on owyx.site — leave public API URL empty) +ARG NEXT_PUBLIC_API_URL= +ARG NEXT_PUBLIC_DIRECTUS_URL= +ARG NEXT_PUBLIC_SOCKET_URL= +ARG BACKEND_URL=http://backend:3001 + +ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL +ENV NEXT_PUBLIC_DIRECTUS_URL=$NEXT_PUBLIC_DIRECTUS_URL +ENV NEXT_PUBLIC_SOCKET_URL=$NEXT_PUBLIC_SOCKET_URL +ENV BACKEND_URL=$BACKEND_URL + +# Отключаем телеметрию Next.js +ENV NEXT_TELEMETRY_DISABLED=1 + +# Собираем приложение (standalone output) +RUN npm run build + +# ---------- Stage 3: runner ---------- +FROM node:22-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV TZ=Europe/Moscow + +# Создаём непривилегированного пользователя +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs + +# Копируем статику и standalone сборку +COPY --from=builder /app/public ./public + +# standalone папка содержит всё необходимое для запуска (без node_modules) +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 + +# Запускаем через standalone server.js (Next.js создаёт его автоматически) +CMD ["node", "server.js"] diff --git a/legacy/owyxsite/frontend/README.md b/legacy/owyxsite/frontend/README.md new file mode 100644 index 00000000000..e215bc4ccf1 --- /dev/null +++ b/legacy/owyxsite/frontend/README.md @@ -0,0 +1,36 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. + +This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. diff --git a/legacy/owyxsite/frontend/app/admin/page.tsx b/legacy/owyxsite/frontend/app/admin/page.tsx new file mode 100644 index 00000000000..30724b1cce5 --- /dev/null +++ b/legacy/owyxsite/frontend/app/admin/page.tsx @@ -0,0 +1,351 @@ +"use client"; + +import { Suspense, useState, useEffect, useCallback } from "react"; +import { useRouter, useSearchParams } from "next/navigation"; +import Header from "@/components/layout/Header"; +import Footer from "@/components/layout/Footer"; +import { useAuth } from "@/hooks/useAuth"; +import CatalogAdmin from "@/components/admin/CatalogAdmin"; + +// Lightweight CMS-style control panel: manage accounts (nick / email / role). +// Deliberately NOT a moderation combine — no ban/delete/applications/trust here +// (open-access model; bans belong to the plugin, deletion breaks plugin links). + +interface AdminUser { + id: number; + nickname?: string; + email: string; + role: string; + status?: string; + created_at?: string; +} + +const ROLES = ["user", "helper", "moderator", "admin"] as const; + +export default function AdminPage() { + return ( + +

Загрузка...

+ + } + > + +
+ ); +} + +function AdminPageInner() { + const { user, loading: authLoading } = useAuth({ requireAuth: true }); + const router = useRouter(); + const searchParams = useSearchParams(); + const advanced = searchParams.get("advanced") === "1"; + + const [users, setUsers] = useState(null); + const [search, setSearch] = useState(""); + const [msg, setMsg] = useState<{ text: string; type: "success" | "error" } | null>(null); + const [siteInfo, setSiteInfo] = useState<{ name?: string; ip?: string; online?: boolean } | null>(null); + + const isAdmin = user?.role === "admin"; + const dataLoading = users === null; + + const authHeaders = useCallback(() => ({ + Authorization: `Bearer ${localStorage.getItem("auth_token")}`, + "Content-Type": "application/json", + }), []); + + const showMessage = useCallback((text: string, type: "success" | "error") => { + setMsg({ text, type }); + setTimeout(() => setMsg(null), 4000); + }, []); + + useEffect(() => { + if (!isAdmin || authLoading) return; + let cancelled = false; + (async () => { + try { + const res = await fetch("/api/admin/users", { headers: authHeaders() }); + if (!cancelled) { + if (res.ok) { + const data = await res.json(); + setUsers(data.users ?? data ?? []); + } else { + setUsers([]); + } + } + } catch { + if (!cancelled) setUsers([]); + } + })(); + (async () => { + try { + const res = await fetch("/api/settings/public"); + if (res.ok) { + const d = await res.json(); + if (!cancelled) { + setSiteInfo({ name: d.serverName ?? d.name, ip: d.serverIp ?? d.ip, online: d.online }); + } + } + } catch { /* ignore */ } + })(); + return () => { + cancelled = true; + }; + }, [isAdmin, authLoading, authHeaders]); + + async function changeRole(id: number, role: string) { + try { + const res = await fetch(`/api/admin/users/${id}/role`, { + method: "PUT", + headers: authHeaders(), + body: JSON.stringify({ role }), + }); + if (res.ok) { + setUsers((prev) => (prev ?? []).map((u) => (u.id === id ? { ...u, role } : u))); + showMessage("Роль обновлена", "success"); + } else { + const d = await res.json().catch(() => ({})); + showMessage(d.error || "Не удалось изменить роль", "error"); + } + } catch { + showMessage("Не удалось связаться с сервером", "error"); + } + } + + async function toggleBan(u: AdminUser) { + const banned = u.status === "banned"; + const res = await fetch(`/api/admin/users/${u.id}/${banned ? "unban" : "ban"}`, { + method: "POST", headers: authHeaders(), + body: banned ? undefined : JSON.stringify({ reason: "Заблокирован из админ-панели" }), + }); + if (res.ok) { setUsers((p) => (p ?? []).map((x) => x.id === u.id ? { ...x, status: banned ? "active" : "banned" } : x)); showMessage(banned ? "Разблокирован" : "Заблокирован", "success"); } + else showMessage("Не удалось изменить статус", "error"); + } + + async function deleteUser(u: AdminUser) { + const reason = window.prompt(`Удалить аккаунт ${u.nickname || u.email}? Причина (мин. 5 символов). Это может сломать связку с плагином.`); + if (!reason || reason.trim().length < 5) { if (reason !== null) showMessage("Нужна причина (мин. 5 символов)", "error"); return; } + const res = await fetch(`/api/admin/users/${u.id}/delete`, { + method: "DELETE", headers: authHeaders(), body: JSON.stringify({ reason: reason.trim() }), + }); + if (res.ok) { setUsers((p) => (p ?? []).filter((x) => x.id !== u.id)); showMessage("Аккаунт удалён", "success"); } + else { const d = await res.json().catch(() => ({})); showMessage(d.error || "Не удалось удалить", "error"); } + } + + const filtered = (users ?? []).filter( + (u) => !search || + (u.nickname ?? "").toLowerCase().includes(search.toLowerCase()) || + u.email.toLowerCase().includes(search.toLowerCase()) + ); + + if (authLoading) { + return

Загрузка...

; + } + + if (!isAdmin) { + return ( + <> +
+
+
+
+

Доступ запрещён

+

Нужны права администратора.

+ +
+
+
+

*icXi^#$~rVs4XEOt~-y9 zs`x0Hoi0oNPG%B2Ab&W?2KSXGJn-+D;^&T-Z;i4;DKMWWFrM@`BT)lGc_UFnP7}9K zw<1QsJj@k=wQm7dE!Xl_!Ic^q9TXE|Ku0a?pweqN5w3PCW;J`1dv}n}Xd;Q647IA979Xa-phq+kJ=}-&JMOAULXP0Y^P_m|lq# zHM?HAeI~LGjzyfH})+{VSM5qb{w!iTn6WA%gTR-q4wrPlWx%gO%;$Tfc{z z8(E{dOo0}B@MZss5q~#UU{Z_=oe^F;7(h4xXHHrGv?ycNN+U`wwWcJmwdTaNCnDp% z0kGl^>&u_I3`FU@etCdX+L+Th$UP?Oa%(mNtzT-MtvtcGkL?co^xj(j`Qh_pA}z)^ zofLC-bx*zByw`O(cRu@zp5vfaR<@>Kij23`c~Hp2>%XYDYPH|uv73N2M$9P5BJ8x$ zUY1}_^~mBkOk=f|GIZ3ru)Ak{7b|I{_P0N2KE(7;WsntpdP_>cC=TI2RumqWSbs<_ z7LHU6{Y1eqr)qSJAw=5X+I5TEo_yzABw1N+8zH}R3=gq6Bq39onHgW`i;1AXGywzI z*OdWOeqbbzI)tC+QE8oY;z>W#I&AG%A$0$wX=v7*!A5~Z10}vtsKIu@lz04?Q*RLQ z;I(%M`1Ksy_D~)J5osSad~l`@%)h6el?&nFwc`f>Qa6+yfDBbzm&h3@r4M@_9w6O% z>jim_=KMc|+6&lzK*U37wPF~C<7~b^d#a=r!TvE@|ITJRU`W!^kikZ!WH|9@N#b2` zT#~GCo3dCOH6Il;36;8)Tc4#b;{G}63L*Q!7wz(HCLw)}R@vIgn#~GHS^dJhNiomE z(*SdRaM-)H((?-RB`Dvyn&rkDXu^`Cnqma1lstT9>4{_d!kd=0y z_nWW|zvv6;dq!DUCI+yQBfOqa$9DqzqnTfE0ZBkh$y6rMnbF*N!I{7JMHm3fL$<#d zzoBVw9pQ2N*qY0Be- zzm0h2BRXNeqm3OtK-uJB1fq^uBx3tLMp`yM^5yg2_dW*-ISv5~iDt6|Xs7ELngVQ< zHQl!hh7$>9(l1PP2`qm22u97OS0S|~RmHqO^xN<>+gM{QQH zS9#Z-IM22%=Ic1)w0ZSIyN@8!DW#w`$BH7y72~@L^(Px6xBe3L$b*jfzzZBNZRNSG z9i1tMb)P*1bM1XZ5AQNThq<$DD!`8<`p+GmMMK{hLMO0}y}Ty%U6tD{nPMcd52mD7 zB8a}r1^~@ug_FS<@mluYO%rzY)2?&OgtIy?h;h$6mFvDdOn6Zn2YyKB`5hHyAFHcg zxKOnWO*bV-;JjclH?>)bihNoEOl7!$U&Ja&*d?9)*ap`81){J@XE{Fspv%=evCV)4 z5mA|Z(|1cwxd~a*oqjJ?C0`J;o6N^eJib`4Cp%lmPSU`L)|R;&0Z3&eyDe8)(v_sQ z;&VqrGtWTw3w&t}B3w!k28@`|SjLP;RkcngwlKne$cG7OpI>TeF8rJUgv-N49S4r( zou%(I5z&|V0Ym)~Ga572tN;W+ z@gsC(0(&dd=sn~fsl%>4#a$izQ1156GA0n!jvRXU1=I%Pn9ns^R~{YQJHm0RhRnwQ zz9Rq`3qA|*jl|ey;22Q9&DD7X;quX8KxuX0&(yp#6rd{!$q8}J4#Mz2d9ggp71-B` zPIc#sca^HzyC^kHfx8)eQP6S7IrLL*)*?X0ogej7tFrf{Jw#8Mx_tWDQe2w8R{Oo* z-$UqD61Y&c22c)56x--5;Ba`u)^v;N$!}8M&+QNAP%$yv=7+D%8+}*8SO6A3;;}1^ z==*vZL9%|R_v$Iv8XXg(6F+?&F@1yjQTHCCwnBO6MU!_SGoS7IyREnl$szdUX0ZV+gtJ4xs`Gk9Uj_moPGg)In%GsHLU zeQnw^Ivt~;GmAHo1cACzLtaq!tLmjkxd@!O=clXeG~p4x*1|qKeILp*{?xmE(4l!T zMN&Ym_t@o9|gkl&|TbWOOA!@PG?@i}WiQd{^X zK6>&yd%w|}0E)k!sdQ{AUFidD<>{5ucv88}q3Wgrq$6y3oT#KwHt>Fl4x^2pPnHxx z*Ve{=T6q&9gU(f5`+bzmnvk$r&B53w>-$cE9n>tCcst|{7Z|<0y`6KEetOUn>K*uV zKcJ6!(q}gKp!@U%&)wrGSoe4Dp#A-US5zTq+gun5FMZG~XnD8(a*5;&?@0%L7Vpc2 zt)d<=l*VLYXeD~a&$3TC*tX^Ft=mvAuG{<{=BT0uLzNezZbKVwKbd5~j!JZl!TK1>yX6Koz}YqKVI#0r2K;>NH%+f0 zwYBKyNV)JBqltnw>ggD|%g5a3mULg}Iaal4hTd@|sccK5_A~)L%=YW6-h6xA`H{#1kR8k(f6J;@!1ZsF@lRioz;*~WmrYC##(wDpj*9tRY6hoKyF_rXrJ>mzul_T zR518}q3QYYoY?>oVAV9%ezZwwq2mX8CWOWKbUEXa45K;&BaGmQ>xa7NNc{!s7E6Ma zv7I!S%WHGU-gv&>-uE3Y*pFV7C?TPNb&$#`{H%skv9Lz7=7ZH=oTP5>)%}_`dA%GC zHt6Zmju{P=?)B`}$Yid4l|bff(%HO@g0EfxcJ`A`suyA^N8|q>IZv$3_k|w$AFc+U z?wVgs7%cA$ozgJ64GIyk@}@f^9w(U$O;~B_6rsKL3(V=VTYhI$+O1cnzKq>9p_hoj ztr)%-92z;NfnmqSOMmFopdo;jY%Z}TRBu*0@RAMTnO^h z3{IB*<*{KomD{&vOU|O&+&w9j)7saiNj%pIzowRQqD?@WAz?pvgE(U7Uyu)UBJ6J< z_V5X(?BSo^uiFIP4IloV`~9OeqG=bc!@P@n$h#)VMHz8rCT7!1`S@W6u2_qUCz97ba|Y@PatFFc_BVs^2v zevE8fyi(sbzo2Ya{+%oaB2MzB;+qy@ zsprHkkABfJ^MzbiH2I69U2VR*9wFKT$f{78>khSR?09_@0_O1paZ}q-?p|q2QWIi# zb;Yk|@fQm=L*+UJ%!X@4w_Ky4qAa)r+tA7mgn~cB+@>fxBas=^wI6s&7X(C^HaEvy zkAKSVDCX@1$ZZ^a&R5OBivurLqD>LOomRtNk4C_UzKA2FQD&oKKZjhTA4Xf|4~JYR zt;;xuUBl%L;POkN`M41A74OOiYttnu5~wS>MufFVm%gaSz%ifK*wLRyJ=aG4PcU2i zYkG-Vsq9Ktcr2v*zR-3VsTPG>hbguC)^W&HTKmSaQSa%3()b7Z5Pj3FepDyxEnP^lYHfrLc}Z~gE0-t{BEJ3L;h?5BB%YK1vgNf{CA@MGWK7;;rw zKo8Ky5j#F9v=bDs@J^+Oi^zJSnRZEBOXIc(>V>264Iw}qWF9zQBKTFv2#buos%MnO ztWG)y5|)j6!e>G=UNK1As#JNsgC5S5Q+$_k4uPv+;_cLZxL9DlinM)qQxmBOl@dq= zUrxaw=%MRX?9lIwDKrblqjW?Ql9kz`l#UI?BKTr>cuJ-3YkEf^<)PkX?r`f$j=JuW zPj8^?XF+VD4rh&@{frOZ{CP^M0;q6l>Y!78t2Ow?$uTLh7;su$?I&&t^7vJ(s55L= zN2dV-r+xP2s9}O3)ESe(H;^~)sMWsQdEWjdc#2n_n3bceTu)q$FiU~=^Q2z`l9fOL zIz-?&0l92&h*!V|{(8oMlyA;3)8u7X@9*MKjyNV};;`}UBa9;t8}y@cj1jYhf66AgX`7DnrM$q$)@t@xg3v)Mlsl`Z1 z+3Vf!4m)`@UohXzwP(hTzJ51e=z$;H&K#HXm0*xhpY7G(>pGx2ff-gtLp>Fh{ZuW! zhZ?un-ls#eIGc5oj%?L>u`L>%Nfn>&9G(ZgO}-s}rO{{8N-l@l^1eAh)&Y$^hjZ%W ztTR@>KphEz42Yr`pJ&YiH`YpE*&lvTXN?M^LEo#TJYRtgV8M0 zWxyxpL7&Q@#n$Oih@E#{uh980uX$&F7C6slrqDJ`20$oM(Y6A?%b;yrR7T)herE(04p41JFY4?CLi|}sOQT3aS%keWCUC~+iTuJDmleCC?M9j;)TasX z1P$o9E{bd@G=5|5Gs}j@vOe+Ln8a=$JTmlEQgRFoaQpM?N9)w#(B1gBIBvn~Aad5n z!4~`=G9-Ebvmc7F(R@PQ)l1LA^ZwmtrcG(nL5Ce=`v?9lq#sdtFwV2WS*>|Ku;FtS zD?1Rs^i8}?HQYP)z~%FsYZ`#_Y_od&m_r`*Iqsc(llU6gi$~}P)-yxgx5UT^ukU*93tLvtt~;V!P~wDf zqyXa6bH!1kOGVyoZ!?TS)51$}27uBXKu(3yy`^VBToF9ho_fwPxX&`7*S{%#=1pUC z+0py?_tX#_)J)L~URajC58WK=nN z5%j!-oC$>ze)pw?TJ3&dq{)NRtJnfA z0a)WOq*mIM9Z^|PAgZ0xa5hHDx}r9Tgm6`>0?S?W@2iMNML>_lH=+L88@#;7FgPUM z>-D*_g0}70ny^Zg=Sv(qnGc8YG&shDXTv(`Y571PwrhWVFp8#rf$Q8QtAfM2u3AfF zX*Lz_ikJPmpxBIJql8-{tV`bt4aYHP{jBE$3m0D98!eX)gpT?(r8rNg%6+t4nbobg zVhjC|$iYZ0uNazVl+ufHs!v*8_S7*FN`xty^5OcQs`sJvt z&RuvFDqtv>ZjfQ)0EohOhX-stai=Zw{FWCw}WC+`BpJUo%L{)qXTg z=L!NXz5={=Y-~{(nbzwSq#>8GXI(b=0@1!?(3}O_wvdk3=~8hR1B?gu;UcZbNH^WE z!|+wpkC&r75&Kz6^bE~(S*mC6IM}aOn`0dr4NEYO^y@oE0na8sH2w^TjTXqTo1Pvy zY!wP+<@X~>!g6&yQyoTo;>_QH(HO-$#snsR_%W;)))RNfs_L275-q(5$EbU1fk}_t zIVSF~WenAt&zgL&YIcbPlqgDRo^Uy|Q)L@7g2B{sLZsa5VPkJ!MDMeWf*Jv|K78B8 z4zh4v^4rQo!*!g8I5rpc>DAK;8l(pvOPH}kGgz&^z2Ac3){Z54gz7ZWpzBwULX6-D zyZxLdIauAbqD>=wj|FyFl09>#p@4!2)}gUAqXM*ty~|`T?&@s{I3b(f*sBRu7=si8 z4+;(|X|-$R%dU%zOq3CxxsK&j5z1)BBO)5?UOnb-q<^~*wc)n81HI0y?_GDe1ms&8 zxzgDu*z-;bNRXPrA#xGdHULMCJDJEX*wnR}obhuRmD2Lp>c#4F9VHdOZ6+jGvBaXj z8v=$91N5Imdd3Wt0B;z>X6-1_@T20seR`X0J2f`n(f7*Uirq7DkMh!pq?w5X>Ns^~ zKp7!3gb0Pa^R`2oKc6PKXex;aWrqvz#PCx=afo(OEFboZGzMG+&eZ;5Xr=D=lvQP|X$^7aZTBzQiYLL)e%FAYF!{%i`Y8K8#*&0b zJFe}Z~^V?$Il@L#zONRoD-%f4X>yUF568U z@cY4zp1B_9UH5i*dEUs#Rlq($)1W>RK3BZ=WdX?WvAIO1QSCC;OS1z}1OABxa8|x` z*tLP3Z;-?KRVbqdGB>4)wHEI|bN2h)-jBCSZVfZa47eTk9di(836Hc7Jq?z_U5ejI zee^MRH5t0L(emKx0D(dO0lgklT{ zGmdaX1o30;=TWW+-6cbZ!J)Q`MLQcw$GS&_dSeFP9kpH_?E=U9un(QMH>tK8RP}X< zI0|Ce+-gZfX4*x|53B$56AUpxC~Cw3@FF*JBnq-I$drj`8fgrTrxl|)QVJRdW~R(C zyq3PfZr?Mu)#y*%t^J%;6i`7JK}WIpj{EoKUiQcHK5r6@jk1l0;CJI{gqg&H&vjx= zk#izIJCHUpV=)xBwQRchUHuAKATSvQ@EZjc@f?#(vQj}NuVFAGgh|XwjecgbF|PLOOQ->Im=8G0<3u%ALZP}K zB};d37(N8N2Ci=jczbLYC3%hL+SV*?>#KelxdXVSyviFjJpDiKeLj7;+@EK!Y>X`^ zm`=@LNj+FGLTf*O)>e#nOQftJ2=50(RI37SdRFl|DX>YSq>?GL!1Lqxg}g_NQldW) zPeuDre{A_p=yp0fDS9eGn^ITcRP`4n`YyBL45g1pjq0LIdhK~&j>hF_^~;-@tT)EB zC_-e(Nzbci*ZVFh)jP_1==iS+j88w~QgM0R`&BZ=u{5^;^Ma3^k2VVd%^I=08xY0^ z;oD(jTx3bneWN`;zIy6PM~hK}J|YU1pQ^-j4HFCU&^dS5T9d7V99L)zfuN&RDLDYF z3C^o@H3+?ay-L)1{ILMjbWs5V(h(N$F?Ye!pqYO8@WAZ`X?|1RQLlxMmcBSd$4)J= zcY4FItJ#VDvzD78&K!m`EK`h@iXx4RT&qG!Y zszd-vU?uZjr=)C|Ib!%xNk(ezF+>@S@u6%rOeiQm?X$?t_&pQ?gEJ3~yFi!vS@QcJ zgcZ@E;k+k9*K&>cU3d9Fb86p+>dO7oi^OV$D2--4Bm8#e^At3FQLvVYK`EiWHeEsF4y4#dZ?U{8N)X-|a-<-JH?yuFO(R8)5$MY{>3bZ!`8yIa@ zOy)TjA*!Md>Ca=%f%d4$h`m86PeH$_vh&S(`GUBrMGeZe)Y%J%#9|p_F^{0qkje=L z7g3%MhEZyEXtPXVeebvvYepP8Y}tp8^b-E%cXsx}yKXP~keI6cD&Ji!GZ}4%_QOZRu=Rb zPMB=-I3yH)VuvvEIKI3RaVF&KOEO!5v2}_|y~Mli=^m2?FFuU|LheKyKR zjMAn-Wbl{&u$4LCKIdXW};l=9ZcY9S6^^)5rM3L=7zFgn1e*egP@))8lVz?XtdfBuTVPIWJEW8v`U5YN1dK?fs1CSnW+0y81Fz z@qMG}y|5U-V<`==FolBK&ikGE-pM8iV`73qCA62u=4ip)IAbp(I?~g1{Ld~HQkaQY zcsDVEPlRF5xs$F{dz{%;a~+j&t!E#7%50~N8ieAp zXaB8uFF-UY`nGBhS_?cRqK*oZolkk%OJ`g#mwY9G*rywr+bP(vMLhH*;MSyIMzAsH z8hFrb5IpR~f7#~AqgoRnF$fE}YYJ&25O80@)8=;!{PhH3GljjlP-;EjmElXmW|lJ5 z=C?Z?ub*|(KYik2_YhS)ECd^tNJA(3LBNdE;LXV*OOij|)2~V(5b)v@K;U;htlYr1 zq=BD!w(}g4;S9>M%-zU9;hL7xYUoTowG8Z z?j)5;O3{6xzK5A$$ToAo7n;vncG#YIu1hIjs5jdJYdExej~PCcF#X~)#j=@C zcszxI3!wXkOjv7f^TSQFBJBL3ic+>WFmISHtqf~Ld@N{JWrfveG;yRzGEy<7b7|GZ z4z7tl{bhUl?M>vsj`a7wD!hCkPn}v_L&}ZbyzsC!3~3I~G0#G3&>r?-*ESmWt3Dxo zRkxhR$cY8O>VaH8sXT(3^xeSCPnXO*6#%AjBAjT#rHsrh-#P zjr+^pLaktQ-^t{&C`*b}3c=RhLL>Z^M*d@Yvr8CP^b9ATFPgUiNod6WMm^1QfjTl) z78_+~;|BH|K`loJ-6X+)=foE;p89VpE(RL;$2F|U#K#$i+? zfWs^Q0q4?OZ-O*<$f+YK9&{9P1poZS#M(ML*B-GpiRUfsWyzwf;~c{`!mVxy(Tqh$ zBK9?A_govqrC;n1XgjX$PY4i)9ZgdtwH~kCk3q?}e@dL0FjrQ2aD#`%ZC>Kln9f~P$m)i@mutu%MX6Uqw=StSg8nZTAltf0q9MAegzzV& z(t(=2u1h4VJ4YGcpaV@u&R!`*997GuV$i*dDTujb#;4edLI-Bxtyo%vW(G^T^d!mB zM6hGF_?k@HyXgXJSFz|lCCNIER~D(Vs;bAwaFRg+x0eMirbT2*|@@Tl5k47h=I0+JCKBLE z9Y{c?ibJF;1{C)7(~d@VD7QYyM=s^{{z65iXck!Z=e!bu#ZW1eN=h^#>}L9`m-Sur~VGicR|#xe?(L-idAw`Exsg1-o6 z#hv<@)=Ee7g)etQsT^8ZBnE2_4evvVDd$m|*nxr;s+3#pOK*3=wEXUDekkIt!1K+2 zRKDG{)@lo|fh}u6%ngjRN1zQ8zbJPaZr97O+8KteKIS{N`eaznSr6k$7tg77pacz) zw;L9;9(P!;71&DCSbw2`s!n7XS|j@g3mSibGQ$FE5K^s>*BFeTmT$4NH1~e%R|iDp zjfro*E7Oemsz|MT;f1g_sKgyL!A>^bXT)4SMMN6ni)4*(JsrH`!)x?q=%FPgT_o+d zQNIaBVEY4E5UBD*UU{AJ`NS_CvuyA(6n6iE)K(Ykj*Z8l4$5IOA)E=nfLCol94^V& zG;epTS}yQP^NM(NE%e-CKQ3+j+{C?dJVp|FgtcOCUA_sVoV*g3Xt}%U0w;`@>R8g@ zhR=BlY!<&@#f%RHI39obfPRo7>S?a?+C*y@x>z?_rQ$X2S#pB;x>|Jo z2IKsK+fdQ--rm9>=SlR{7ypyRA%HL8?b`(0oYHb!bTR>M^4&~1HlsxqOt}3*Xq^#% zDUZL`7+ku-KN}8QT`?`OC8S12htWvCGv&>&)#8tM$Jn$W5)+@ zi;aouf2^#CO9bD|7oi(b4V(tECIt;71O>P28{kiyTTHXCmVgZ*y`U(Kd z%WlHM>@^v{I*Ejag7%81PTw6wHY5l>|4*CSE3IYpAg~BxMj_5R?HOIB?)MZg6329x zbg2ibubieV6Y_LoS~Q_4f&!bE?A2K>-QFsM`glqt{0A5<`q9cmICg&Iy**jC%L9^e z$+V^L5hpT=A-*-ZBWKGq3Ly@CePxM^ohT~tq4~@BzG+<#PZnPrLl%0IkS!uH!@u*j z^JhNn1qexKa_W8~R=F8WWueC*%1{S`Ql3wcKfBY|Q|VlPTLjOD!t6JNMU#v>fq zoHAScFqX>F?zPOj@ZjkEUMy~IpAZ|bRq4s>)-J3m*KCf`ShSXq$Ltd zLCcZh-C?_c$E+LYQ2_M(p2uqXUn`w?PKwKK_=&0%lEX2&9LejIF0b@vVZw(utfL;H zWq$w@LUjSixxUH6eWNj|f(ojYf~ia(G*l<>J4@Lre|&-W(M3uN48O01^(l?;^%H8B zIcO|aet?*1^068PiQIEbXK2j$PHLY~u3m&syb;7)brg6%Li{?R7o~w~qM7?htAR`OC9%m45ZL%-KJzL08Cz zR|)%7)yPNDmcbKnXnoPzLg{Ne?eA7lnv^YTgj)NdVN>)DzT%`k%7bm2snj< z{j#-0CPR3T=Pfux%)@ISCuX4e=l32?D&acbNfWg#`U@}xuox!}S$j<7t21_^vW|5- zC=+WBgXt%0Ye2-IP7wAaWA9Z+WT?N#2Z>K8Zgd4&w#l5Pj+nF$SEijO5tX&@p`D>X zTBSBpt3BfaZ7c@_QjwL-dRw6f^)^ZRnl+$WYQ5$M;DD`M@TjV|=Os|+?;pLt+ZdT9 zdKEN%#_>d&mFATe6wL!s&fZU4)QRTx>R2@+!6de?EgAWf}qltB=1yk8)1Bv2746UbEa z*L6YbI}>s!SM_C+3mPEs@lOJu^%wGSXm&??=#pV84EK}ODP<7`_l!SZvKv$#BRxQj z*LT5$LcHxCx6z(joHn6l!j33}k6#c3*v{hp)QI-DbLC%LcA!fSDNJ}|<^-Xv@9BA`NA@S9D2q}FiwYtVb?XqJ|Oo+fjV-3{OwGw35f_UrBzN|2E5cMmD^ zt?kzm?-38^^@z6G1y}d4mJ+XRbYGWW1QJxsOMj^SQdk9f3O#D=1l_#Maf>n}N{v|< z42cCK(+W4p?t_7WG7Q>%NdL)-UF89P5!3hsHSymEGaYX8yiq~8z$(Rd1A`LxmmFza z>5A=!jF^Fft0wJ_Eel`#!5Oewx8M5zi2BO7sM;@DS`lgKMvw+UxBXYXgNwb$NfMHdO3DiaL1s^TS! zL&vsyGE1mWGgHKjdSQR2f-sg>xyXQ)>xo1gHhoOTlYDG7YI&zS`l-+700pJ&pOwD0 zMR@fUuyX~$%(dk4=Bb&cPR0|9=2b;mO=gQptucr-;KBU#qM-H^2AI0jnlpHq0pjSB zu=3Y?(Ih;wr-#!~Cm`rdIAwmZzq#%FCD6~HRxB}dsgQw3n^qy03Q@_97AUOvTEA!_ z*asG?%zlmhV(#^^rHee9B5v3IlSzWFH^i5W0V0Odt^04MT#^owItzfNq23>KN}v~2 z$o>|S>Bj8Fno^aQvf45FNI`!wKbF4R^&-5!D zDzn^%;6=@p@V>2DT}1u2O787>b~)n!RZfy85>E%DoVP(wzV!wAH~P=u(mKKfnp||0 zv!*5bhXCA?Ytu$(xL7+?i2yeNgEZ_{ZTnF|zQ(@K8vyy}{^mz!W0mfW0XL{!%qc+g zeUYHEq-9xumX5*xFs2D}o4$cWlBaeOFJ)}SWti?!1Rkg+{;J?#8Ktc38omQGi{Ay5 zu{lWm_PhvrueViGkz-ToSy|DE_z-sG@WOiwrTi`np19Fb`Q2H6@WN@=R%FG=*kwjx zEbX!-ozJnK<~WWUgUVzp&RR(<$Y5-$Z75_o_0JeQAB%)^8oqA>GMd0|l3=w@wrO#&$!dL3Up zUR)lqPVoZ;CBEdDB}rlVW-{>EEOwfUkB?6qEuHP3=jbrymVXNcuJ`V*Z&?a3i6kBP zAxnR^{qG}7j$?VHO#M3ABKAT19&o{1u02gn<3|bz++$2X69Su;@~+JE;Fq8NIkrcJ z8{fJ_MMKKy&srybQ6g=m+wie@Quj1TRZG<&gB%fAN>38bcu_a7$FqLyE}m)Q{jt6h z)Pp<1ESK7Ty=_0VBf<57X*H&uQb-g}l`>8RY6&2&>b1J?Oa!2x5llOvwQV}*ftK_s zfr-y@sM6q#C$){UXV(Weall}hRZd3z?RR9FdE#%-s}7!EjUK!P3+Cri)6wOdib;y- zU(LjjO;~h_n{gRL)S-0K3}$D>pFkt4sh}MdjkC?9xU)gd`)s(4e~`1V&z|K;DmuQ& z=@N$OCm%g0%DpU1nxuZbU^XQwh5xxZ(OFgpLk|x3%%e?(EIPvBUk1YyDLCvPn{@zRX-cS%`Klc8<{J0<2w zZ{GT2vn*wdLG9$jXs(Kq8A|PVMBcQ_trIdmwYlX6@xyaY!b+`w-P}sgwdHT%9I^l` zB2aPBYNK&w9rQcr(0ji>a)$(Hd6+~q^e;`&j6YiLc#}P5(e8V)aji;t5-mZJZ_1r+ zz*D1Pk+;(BwK<*(Z*f`izxlm;eJ#Sv8REPyT*cPpPhv>PwdmVMVWZcmZZ_jGM{0MV z=cq~JD2_0e$e$Jiaauf zRE_i|lW!nJqxh$BPm*i>X1AAbO%+*FTczynne~)VM#SZS>dc8z=6P zH&?cxG^~f9z-EbS|5OjqGqOJRa7m-g2W;Gt$-*v%_=5OBhoQUKje3^py2)%=^{}$P-ItQkEVrD$Dhfa<)}AtfSDJm* zz7x^y4raP@cr}6jp3%)-mIu_ym|8`H)_iPgF1%&C%5_f|%`c1d4|E0~3eGWdfS?F| z_y0pUGFqrduHCE=()gSX9Yv85@UT}RkV`E`YhA(q{+E{~2{nw&)gTo!GuW#C{>j4b z!u{=)>sn`rF>HW`6lLnGu;p*<=ePS36?^#Dcn)&mpiT4XPcq{FPn1Nnu`jvSAI(AbytC zyjrg(G{fzk5M8=a5D<1W?JW?ecXcsa3yV@8U0;#-t)grK@C12(K*pW|U?Etul@+DC znt&F2%6P5SZ}T#DNi+XdtT_p5sfH$yrvm+N$B|S*uCMWM=-FN_rPR&Pl(P2#CT0LS zPHiAuFxmB%@wjvmjfUT5+gcmIPQ`CtI5&bFO<3>H_6KG$i|OGQE@-pJ`ul)v9SXm(uDh8fu3{shgMm{kBOE4v)K^WLb7 zX>w(8>a8yHWKpMg5m9%j1vhq`1Lxbp#zH3$v+|Xq0yeQ(xVs=l?`oN+C;^(5D5_2p z`4dO09RWb#oZ2n!=!JszwniHorW=4~F~0r5+7M;et;^|Mf=%>4LhgFrB_dLGl@a!U z618%>2Ld2wKhR+;p?YcUmVQ~Kas7{wsVr>;uZDMDYTgno2h+) zNcL~a0zLocL5D(HFsX_ISUN0GoCNcM#-G%fn9+Bd`I-bB>{==kfj4&>8>gvHYK~tp zNaHc#k^8;q{ihQlZJiD9*bl)jtE4q6;3xjZh*!zJrWqQhA=QUD9$Ie{4H7U;bRDNz zF``)7E;9@a-C{4viuJByL(J-6`HnH3G`->PayBW9#o#7-i@M^7n4EAY^PK@Zh*_n8 zjhQO-z6GMNLT+qu(aCBbRgO*1|35O10j|KwY&=Inc_#Z^+ISy0S;x1}08=V;hjh4j z(Ejj8$*$q>2$UyZHdjW$Lr|i8K4Rwza7B|+L>1Ee5mpv?gE{8>Ysu4b@oGPMpD1N_ zx2*Y6xlv%U*t)-=9S?g@(zeZIufY3)-OL)Q-PlDA+iMEFr(|w@14`|x7#8qFw`-hT zofc3zreDT~q-8!z=VL`XAp&|Cm21F7^ThD%vmSzOV#s)k(+4oQZnj3Jf$gdxc#4B^+EbTm6u0RKb|xN}aok`3bO-#d*bK(<^nL1y zv6(?a+iN?|0>u@_OYvL1yW3K}l1{T}lq@(0ePk(7rCN28Ig7bjGbP9GnOJG{4~4ap zal3!6E310pih6SW>UK({>Vd=OXtWZL017U?BX7MdB%ddg{3cBBlndZVuI9KWV=7IZ-Cp#KSQ9(YY*;{Hnw zvE_XA$9MqhuE^D+bT9v{_GYAtzCV#8e-gY(+0lqnoBkIQz=ObKJ_~LG2t?;@yN5dk z1SH+ct-YIz{pa7&GLrgGUnW@33_SWkRnnR|3_r@n7;F`6lrhQy1toAgtWYo+^B47; zu#DgG+&qF=hlYK8@eCCRvDPT;w#zRDza}_1pTa+nLQ@WZWhSNJoC+gmQx~*x&G+QT zdzykwk5XRPWLL1u=Q?Scta%yO-8WTS8wSugOIWg&swCh=)=^U_se3Ubd()#(bFRLu z)zHx3=H_mu6`V4*Fg2ylr=G^bns=o>($tsJKtdS-@vPDJd$+jkyq2?Zra;rHMgc3G z$wj?JKlP??eSI9S`YI$mUUjGpQn|1=_7kwR0Y={zvF-U2)wvc=?rqZrYtWlUzMGZ$3tp59?^I6_-a25FEH*tSLg)#B zti5U~q1=io+~G#qo8JT=@N0p8A@(!e0(jVlKkOS~VsO?FIi2DGr+=>z2tDV{*_(xF zGEG`3{Li0r^DTb7JL?aFJVm{v81%M<;VzcSXaAt|C|#Q2b%Hnkt465Ht4qd!_J!o( z3X4J}<@fAQ7A?IF43q?Z&y4^&M4Q@0YaFi7U1;8Y4~F*pgf4QgQ%$ z8q60Mr#3q{I0uxGAlv2>_|^J1PMw!dofk`;TTMQl-d^9nSUJLY#?#l1$LQ{7U2jQC z?ag^Pfi{?hPgzi>!9f!`JgnLeZ`Ddg6jrpqHZ=QeDO`*!a_d_ZsrG}Qjud!HJ6akG z1h8ssstGMX!k)KuswPpfdU#y_>?AW@?FE%!s&LA_t5~pW3OPUOm z0^PM9z!vp4dXfCG&SuE_5phWfyj36CrU%p9+iNt#%#cEqWjnJ#0y5CLW!8nz_IGx6 z_Vz|NEE|ns)!e`p$F1EV*G^83{vI9$-TlV-15-?(y{}w*fYIHKAKd`mHFMTM&P}F% zBntZo1mbkZVf}&&g&<$d^{|CEP#~6fmxS8ob^NZsd;#ecc%Kl;0OPDNKv!BMLmH)! znXL@z>lNz(g@;T}Nyz?S7)$0|6}42Pr&SNiUTCT<`%4@;AQ9Wx@nU{a$RsHt_Ykl? zUaVE%;X*lhB8kcgd)Kgl*h+Q1x!gj4>oS18*Q?-P;TE^+uD%ZkrJp&||6!s)gw&(J zTzmpqOfdqy6~Ofm+M131`A}_*va3Y>`jk}xi4Eu0(=b{Jm};EU9i9P*PwdE|`GT`# zR@g4iuTF&qcuKYkQ=Gh}Plr=whim{WSE$0|v&KFz=}AFuEbH7eXEOv1;%AL{Nlcmg z-G1w`;x5#!^oB}Ae{1B%N$;%A9=Ey=98k5!YVykLKfEd_0N_>QFMv<=uedBLU-nqq zYG~Pok3l8kqvT_x>&>6DGaT5(l55xfr0ZR}MZosHL3(;mdKCf;jM{Vnp&t;(`_NZ1 zKrU?w{&!HmbPA~ZF>kcgZw3=&HClr2eECI=+~v;72f?A9<$XJ~{YW}*uX)j1RlLPE z+bd8%OR}PY|KW}uh>1>}5JLW31S+VO#`i{G!wv})Xdo+{2OI$q0j!8=exy1Yaf9w;NywFt#lw= zzw)?gqI)>r-5mwmAVo^sA1OBchdCs&F@wlZPW$Rg4V~@0!IOLS3YNQqfM25;$&UoT zpY=|dd}vaDq>mKxE7QQAfpA5<92?~3Yc~GE;TQONO?MK2Xo;_nJ@v<1eT75AXDK+g zEFjB1>B)zIyFRl$5-SR*sBZsy$dQO#=}nr)&snF>71eEuD--UHFAx$M=>jh|o13(k z;svUn=U8yF$dAf60Eefnh7U@Jd3#dp=zGDdF0{j8F<6gN(>a!x6iJ}^*d3fzYZb;@pZY4md2b)Wfox8&>3A=!@#WP zy}T;&zAUh*4Qv5Aw?uD@@}!XkiW5_3a!<7PiF}~ZFrt!;vL}kK+#6xuk{$7ht$VbI z-~k9$jne(Q9eUU&SB0#Urr)$pJU;jAa+C^@df}gyGyyOeU+o5TJmt?I9O1c^54zbd z%@U6}hnbCBK6ftED1X<5J}R@7-e*I$11S& zy%x81*B=kz(&41Ak=qwQE)KXFa4JYlkNnz7CREn-Le`|xX*!i1;qtfQzu+~?s2UWu zUlaAlH0dh3`!9GSC|lsf^m2S6mzM|9>STX$x_K9A3&u9CQ)d|f%TWir>CtH{lds`I zfl5ia53QUc1wEFVA&@s`UTvq)W$(!j^8{@W$MkP(uHAMVecXmW)M(!4Yvy$pD)7Gq z%mCn~#c%dcrN?bOmMpeYnpXCZ7|RQXy0GlFJR9}7+0~g5m$OM$H4Bt0Jl4 z-Hb|IJqG@HQ`2!d&XTb95NC0Z_$5yQ9A!Y?e?UP#9?6ppt#aPIFNM1~;g{5M3(>_s2HlXNa=4=l0J0z>YydG3n!>Y%<=v=DhnNMM(JV z1bBm2%i71Yv9*V&$19e{9@kit6ktgR4-pRrlv*?Dr7(oIErfK8(+MNZWt!J$skAUM zx-DV5##yx?Rb+mrk!-0L9;wPxM`3a>We=&g=s$@%+&R4%jMVkgaFP-?3>f)YJcj$l z?Oe_KgCue8fn%09;`{#3Jy6Zxn3~HzZztoQUf=O5bk{(5i~jf8cDz`Kdk==VqRY2y z-q=@J?zP{M+7zN};7{P`wBm690@&vEb(Gbw{I?j}^#|?J8IPu%F+J6$)zSB5fZgU} zUB;Nb&(ZS3g~fH8=H2(T7hj|B*UtWAcS+?>kj3nuAp+kjrw%P?~=x229s`^j|*KND~0d7=DQ~_S4o7p$nTv~k6)~Q|w>Nv;{ITTfL zLN(^`A$B6ao_U$dRljec`h`Eskc$ zSl@1(XDT&Wv_fn!X5Y{+aDAPBpV>b-2{>oC;sJp#-esjzyFK7`wzBJVwCnuwp?Iyc zT{wT@J~G^KGN%9T;D^v5rW--)m8gdkKhvSU~H2Q=6F% zn?BttTn#+A6+fnQLoOM|5M>K~t$DF$Zd_!5avSG={L5=F0Sv35u>j8J)g@O6b8Z9k zO26w3&!!n6R}0tpG*KzIaG;;})r0d|sBXjcU8=z$(4YBt+S zKTpqtCPtK@=*7gpGBl><0;f|m4vi8{wO^DGGaoBN2UYRodOD*RdT9`PvNe(fCLblo}=)=|m zR{c-&De7z#-zpq5Jq8SpOgAK-jp{(g_%q{c)=bOV3_c6z#uK_XnGU~<2y-)itw`vF z^+ax9nZr)$ZAj2NXCYf71TsjhRMJ?+&r^6?hP8QS8&85roM;d47HFcf4E}uvj4k** zCmuRu^*G0Qs};4G-o(SfKAFVTW&oS{i3Nj4=qz4wmj#p#W$T8iqRG+X=FMgzei5a! zaP}_Mm!8E~1&1<2;Pg*rKlL#k`T+qmu<4G!_*#HA!Jv}l&)|v~afHFsH|;hWJP;cI z%L-fb$f5G%q^E7otRG zJf`q@u$9S*H6vFt%Nu!0OK{Q-H4Q0K4W93|`)KcvB|0eEk1@PTh?JIdY^hba9ZgTX zZ1M^6qOthy;pP+&#`N#tghH}U~u3aV*pDjV{wg*{hzi`|o& z*7nEPMaU>s@E-pyri`#c5-tD$0UdUHToaVf_@3~sxRjI`AP1(3OR+w6K{LaAcw4CJ z=-OhXM>Vq1fmM%JEe)QdsW0&uR!IcEpi7}n@^^vqY4Jhyz0-df6{w_Zsd}r^Ez8OH zQXH(GicD2j$vf3xDVv*DoTM8sjj(;Vpg+LETOi_G;DY99BpX(n=et^b5VQ-+pl|0+ zVgWI1ycf*YfD}(2(+fR)OCG0?ylX3%P4n|Dal~dRi`>rVR0KNcYYJ}A7sL}(G!QEN z7gG*W(EGau5o%IgOE_D7OGXck4FI07h6p1EhkEwh*Bep z(-4LfA~Zg*4KMl|6VYAeZnmf2RT&q$K`Ihb5;X>uXE7i88rK-#WA*_u+4~M-;M>u2 z4jJKR8JiJ$qrLF_81~ml2;hN5tRGdiST;Va6^K^Kd$eL3GG=zU(G{6370b zvwK9@G__K6Q7HEP>#rpB-Qi@K)5M{k-Qis)%~PJ?+LCmJGK*S)ir*;%iqr|ioktY7 zrqXB;E?rtH>L#?fkvMX0k6;yPB77x}Hk>f}gK$x3RSKwKVbhi`Pi-I|4_)sLYr~f> zZ;ZCTgDAo#l%kuWCts5^T{1KD6Stq5(GqUv3pU!NxWs9{hOxK#jc{{s%~&sX35mM$ zuYD;BWOK(2NzoU20&#~5{rJqE{2K!l+5${J-@hh2?FV($+3~1t>W_pxL|GU!Tn{r1>F4CB&+o)`z zxy=&?S6WiW_`%}r>`LIPerpD-GZt%>X{@tFF$!E$( z{BEmm4~|(<&*aP0XDi{4knQgxXZi!>nq(VxT7177Ji>fo95t~^yA|RN^`yXDXVyL& z#7G6<<2P&pgL1tx?E-G(zjKaq*KnuDY#ms=I!vV}Kkf~D&@Iqi@YmC^J26K$dSdXq zWHZR5B7;9hvqpQ5P>YREOP6Ryx4u-n(^{#V`AY3y#1QP6neuEtbDnzJyc+V#&rcgt z<9C6^GPzEH$!u6}0^-Um`B_c!#Lr^-H4P$J#5(Lasr*R7F0<{{GbUqg*_7dBoCPrf zDxvGDsa4+E>S{$*i&ZE+HEI+k)?ivgGu4M%v5`eQWe|SQja`zQZP#=^tocI%k6lbB zcl4=JIfu#MH=S|3*l8Fs#yaaS)7@rWZm6SmkjR{RhY%w)RTKQ3?@RCEJHg3jHUcI3 z_QRY*>KlGs9fAm((#hXY>XXY$K`L9_zw$R@R#Ebo_!wX%G z7V{7*T|AxaYahD*waAK3l(Ne$5DZ@xu+l)_hSiTZ=Z>$nfQx-+bPH@V`-NX)OZz?2 zfxy=d3q!r(VLyX27_taguWj8Yli3V*k`!~AXevT}tLv;#*m1En!5aQVSrVk#7SKHOSWb8rUua4v&jmwbQ4Q@x#Om22)9(LGGG@Vzz9VDI05YD^-1Q&SB#pRJNyKKe^SX4cJO&D=&Q3 zg1P{Ybyu*DzkkxUABO;Xi1>u2rsir_aDyp#*X`x)1(*xidk#0eVgDlJGABtAdnftt zX+yKCYNZ%fqU~}cYp>q3zv0R&EL@=sJ)%C7{@x6Mq$K+3o+>iFap%MG7qIS@G~J86 zY8DZyXpp0Ig^xym;yD&=n&q(ndExz3AB`vxAtG%j<+lK?!MW5{66NqNt)C)6#HQVR z`{(bvZSam>C-E*}s`$u+hQYB{uGWGi3ApB_<{FUX>*?uj_=L3?b{MLZt!D1CzI2#@ zfF9|QK%$r1Cl#^Y?@8>hdXk_ew5XK33U&po8nA=-24vH_o*m{ZL2YK7qye{u zzybD^8q5lh>{obahH0xU?Zwyi1`tGW<%^Wd<4Kl?l5CCWw$jI6&#^cc;mj2L3nb#3 zgP+s3vB%-6vTDs5poIQ!(EwnGF0Zj#<1f$y4v5M|*M`orY4Y_D4<5At1yks)U*jiP z)@jRcOw9B;UF3f<8BLzhpCoB2jt3?j=J2{+R^~jx$Q*N*_&-`Y0|UBGM)N zxN*M(xHNptfnh@z{yN-xbqzabe7);#{FK1$p7c%GzP{i7w?pLXxb#5;5fZU1^f4Jf5+6RB>U?dFB|*Jn*IP8%?Yg%*f0vWA@UntMK(d8(SnhndB);5a zk40dQ!em9g^uT(xlzyg+&ce(8tBXZCPHU-?eA?K$QA=UOo}$(YP1{8^^UA`eEX7zI zo_6#fcJl7IF55<2B9?r z;)WMp=Wj1^XYf)OavyXJr?Q@u0039cSg`h4w9D`Jf&sqLD8eElnR#ka#XSz?B^s`UPRi zJe|Z37IZ_r$$f>8_7Ln_{-poBNq5**3P#mX8nd>oyjI%0Ea(==R8tJ!OtfpaeXB#g zz#nZh?W~H)1VnoI_Qx*) z%)oM+mygR2@YN~TD20%u$O^Z>3@=rh^{2N!0tf9k7_S25Hfw81bXwt=sm=&3f{47I zg`uU|Dyc0FKStRMq_N1nae(xR6-Al*hioe*Du;OPLfF=;Er`h}Ko2eBRhXu%;U0rZ zS1kV2_s-qrO`Npd0|VC6?}`4rpNFflePnm|!swqu-#X*nMxw*AER^G3cGv*Zx~~hA zIO<9M#=%!|7!Cj#neZ$F68WAcKU- zb(t8T4^HAtPxF*qeN4><7{oAg^mKUnRrZvhsjFYm#yV<0n2uF&4kuya?Aj~z=>m$f-WI!qATo2-|+7Pd-3dOb;l zs1O=_O`}s~rCUMKY+1##w=5q~3mzt^*p=0qZn0(M7IijJmy6iJ<50bA$TtZ zrOfupiL#^y@i5B)ex#U)ahR&?fvr5pY_ytJXE)EMz@K+zWO-WMIW9j{)H6W8-00_c z+%zpIHQD7oRP1LdxS&efsLD%WwHT^=yXDBrInGGe+a>aXy0;Lf8pjXNN4E53q$OeW zd~$z9VY-k84u)4-h2(I_%5BNA0RSogL0f7L4v-rmZvhtW(xRqxsP4?WL-uwfLMUfhy zl=)9M%NxtXGtY3set!6Od(x#fY2V0HRnaC!+k)IitZ}<^YXc+PO!Am}q^9<%|6ZsJ z=rF8^y#08IJi#2DDg5>yEMz(8p#bd&j2#6GynL-(zmoO3^tj$_Rkzp&Lb_7z-{Qc8 zI966SjC7pj*>5A{FR93b!m1*Pb?d{DPX*$fpHnP~COUv`Whmx!nH?OL4865lmL3a! z|D1(^T(W@xAwX9ph!B0fZF5W8QAfnVDmTSlWa})&KTfM%U{I|2#2wQvfUrh>p90Zk&G^6?XQ zmE#0*~x&|u&ogr!8rN=Fh`tyYuvoT)3{QhBsPob zA;m|X$i5LFc!J2vQb*u0QiH&p$l4P7yE}nK0}(B%YSOrKseX;Se!4IHPP&(y{2Q^y z|F9p+63(aOob(Vvonp$)HnvENJn^UMv9DzaFeIH94x7d4)hQ4EAbpce-VN#R4M?dQ z!a}%ulDLxho(Ozl*q6^xS3rB7X$-I^|9Eo4uwx>JB`KBpYTk=(7QFy~(;B_7c<_qf z5{>fisLycGOVvu{5`EjWAh#A`QHIx>U{p6_7 z*Gp89)))RLX8@`MP50eZxJ%6u2S0~mk1}0K93l$PD*VCC^_1_=c_9HaK;vaZv**+- zjoP98|J~Xcq(4qX*NTPO5~B3?Fc6$h0c@dtorS`Dl;^ECX(KE#9nV#+B5&dvl8JZ9 zccw#Wv41pd9vRH+=lr~JW0G#*M?&#mQD5ko1^5Py`ACVRJa0W-oS33Rr1h^!DyjR_ z8@#Pt>~XhTc^7^4u@hZRcEyCXmW#!I36i9*pcKPJDCxs+LqF!^Afye@29pZwKWSr2)Cq%4@u4xaYHO&R z%gz-~{M2y059Q8{(eY22HetGF4o+#g=WkEQv?@C2kPDz>$@gR3vg+}EdE0*R*M}V) zdU6EupX8onHh@WJIv{Uee5}uL*Wz&!6HxzX(?vioq#yWW5l_FS`$}7mqB>-fq%Ppq zPEw-<#&hi1g)jP5B$?m{Y|f(lMpC<^!gftyBYR)!eD9=u(G&gwOI>FEW)f7Y^iKPS zN)fP;qgCvbkCkd|CH|_*k*R}!F@?p`QL4J;=yaC3e|>;FcLc^Xj({!yq*Ntps+xV^ z%H(gy9HvnNw)D!lJiAyZJC$wmq(h=z_&WV4R(KBzieR>So~z*g*sBSHO1;kEi__d$ z6@vJ%W7Croh8pgH!6f_UH@4z4XQQI68>zX$|I6=eCqn+_=wF00rwlk7@VxW;j0*6= z(20CKq&z282{B|G(t*DE)z!hv|a+fx?)fdBW>nRu7 zZ$*36^AA3ct9PWR&)e)q&cw(7jHmStePhCzr1UM(n4NoQnTmhFuJPWpzlXk2sf~+j zj``F6pm`i^;yypB_Z!~KP2U?!Ynjak=Anxv&A<#=Cv^9)6)jOFZ29NP*h4!>f4Cd_S=8_1H^rPdQHW)whUs*(uv=wZ6;y(|z#J>CZ;dj=I&m!NVPE@H=Fmd{&;t{SaUpf1N~zu})v!;@SnStYXYY4DSwaZ85V7!1H1H00Y8B zp{A>7MdC*FPWt+~yT|)Iyv`n@+g5@85hP{QC`$&49rs<2J1vUE%DqzT!bBbA^06-D{iyfku`B(ruKp%Q z9p@(h+<`e85gMrYJV~<^R-~w9@ z0GnBAOzWfhkfZkMNUFW7tu1dNzw_}j3If?4v+r%mk7gFi9-F?qhPwu5NJ&_jn|C}O z2k~VprTMIrSepu6+PyHRSB|WdA=8K10ab>&xVfCBmBi2lkXAb zh@v?t_A6G|@05c|CS%Z7FZ85l86aT7R24+thf@iEDJYKd{Gy?p*0<+GspGeWGrF7C z*1nvAQMlb`W67{_?&*K_=hei?G=4tqySOrSl6}eXKlzeD->F?!m(?`OHmtB~a5p(z z&!1&I|I)&TW^Yi_%(<%i6*$zG#Ke042^uUqvU}Ywg1pvAczrD=Ovkp0o|7j8 z7&5~2T#Fp{-*%Y=ZpLgvYU$=mKH1H3i5`Z%A6|1%2i@nEgd`IZ3@F!6;)8&QZY%yo zZRnQ=+`>GIoQZ8s{Hr%_9Ul7VP*_W6_wS}5@X^t;?Ck6XH}BwJz+b9PK^##WE?DGz zt5_8mS&E0YV~VAURo_en3bl3COoX|9r#PHmcMmwG_Ju%G!PCgdQmrT3sjF_3+U{cu zNvp*EjHpSa?yaJ^YkjTLhnkd4VG@FxVRY}ZQ~f8@__~r79Twx?GOxshJSR45i6Nb3 z{YfT2KUOZ6B;D`wA(Ww5HS0bfAkVXbgWZ-s5I6PquAeLm1C48Oh!Gh)qZ8o zYZpi*l1gMLM7PRTXu6VUsbuh|b!}UhF0;F;HSsIr+oUgLr5O!-kB{h`L}}vH!hhm^G?Sv54(b)*g`4( zfXexRavx8>eLG2Q5M$oQhN>!v(xE={P;dSzdinuN1tr5lUb~Ho2ghs4m5ucA>8Lba z`A%=^%t;;v2FGLlp^Zg@&+Ps_E3>Nz>4W%DZL^s$dg=&;H?^lgg+)qAOyc(L`eAqX zTd~D+PFj{9LVz`G%f2IX%$^TlmEbajhn$ZQB28AgXd$28cM4H*)WSLUakHfAnMV~e ztbd_GF`1+(DyK*lH2MF$0F|{>F04!eSP(hcTl~mIII;K9_dwCR4xHkyz7%B%UK&4x z=J~$#M!RnJ9R_HCqJ^jP$X}*z_aSRYIpjloQr;^_$?Z~FMBADs1l z;9g4Ox^!g8Wi&&mlG||J#&dGCW;`iA)TgT3%I-O1;HppD-*6@>eDJG$-~~LwAOZ~3 ztRLO7ebWuoF{3fJw|Fa+Xr(jL(`Wbh_kaesy8s2Au{jg;kJ8j>6OUFuxgcakgc9z6 zU9jacqQ^#9kX(g~JP4fimOBNmxD}1xw~1L7POK$C1N?T2)3iq;lF5^Qr6b)qQGLKy zY@EsOE#mvqlAv@dl=pQu>Hc(qpy{HBamso!^w8?!9MGQnOZMM278@ zez-}E2wsc&()>%aBAq1Wx|=KoQ{W_H-u4t??3QjVuiQ(Pyrg(N>a0j`qo9tCL--`T z2k@f-i}<(-3(zY7dXVz-^Ydz|tFgjEeGR{lz7%~fU-M=$S1FZ7FM;Pj7MGHicB=G` z!?DS{>4Hq=^2l+qm{fRTi!Tt;hy(%>gJRFaSUR@@5z)+N0uYsH(CuiInx`(-LQ>ac z)>|M4{B1~OGf*D)g$umESpPNiG2-<Q={!-*njT(7%tZCRaIipADo9NKNNp& zIj5XrU0`FIN$#N7BfJmwtu$>bVB}{()41 zVwfVD*sSIr1HB*Np%VoTx?4lD+=qoHdx)+)i|{AveRu@v{cF{BsK%OjQwdE)xv`3kLi+yF1+j zy|ThqR8Pj!JVT&26@{kgOa;A+)6gxhLh7P@(Q%B3M$FG}q@saR(tfJUUZ#j8@O(@d zDIw`4DOiVc6)sw#c>Hd{NXOX!tLQWp9V=>)JH37BNk0X=}2s3 z(bwFYGgIpLc32|GBMEh6EbP!fl9xNuk7m(}_9X4EN=3@CfnKCG-t#f_F-0|JLCVk9 zkADr3wKo5!#e6RPPmB4QI!#m1E)D|}Ino|72{5#>qC$CDuOa7f67%-}&@xm;bF_y!n!mVg(3q2wxiMq8gL9~J#6pf|JL|^)V&eogjy4E z4l~qRtm8?~r#qHb7PL^Mb|>E!M(Gh@$n3BLytZg7Q0~@x8C0uUE&&GB@J;ekovYT` zw)_irw-iE&fn9z}m(s{E`bMS2ml2Y8|)tHbH6jvI2u>fZ~58ij@8UwtA8xD;ExJ(2Pv6&En-} zp+1ebiY*pZ`sgrYY&_#kMIF;Z&-wO3jI+F7i8n{1iRWXK_3&XdXXSBSsM~(`R|V~# zcD+|^*lVtVEo-k_3>u9J1=S6wI-U;cw$a*bMp1jm#1f3`YW#!kU&A$<@uaQAxr)_M zO0SzfCWaUhM1&`bqdSS_a;J}mOTnW)k8XMJJr7!`T_a= zl33&S-T?y;!d`bqklsg09fbfLlx2QoWCUeB{!C@C1P)dL`-tnnZ^-q&hWKU=E;$?7^p-L}3ag@Zy8%ni3q%WUq@Pu8WK6muNKA=V0_e|uf zFit{bgEzz#?AA0qoejc1Y(?62JD@no$Z{FTV!kP%e%rh*Os(c|lh{17GD%wcpxTuv zz{KBhiKju;$+W*}SmgS*x$ng;XLRQur5iFcJ}rt6C7pRP;kj2GJI|+C=zGBZVN(lP zVv81~<$Zj`JA%GCcHk<$sU;1sTILS%-lR@9K*Kg?!3N@8gp`m<)rcVeb)BaNZTUQ$NJ)s~y3A(hKV;@V?B?Gu^lw}TKUzE{#Kbf- zMx+1Z6JCPk^Sv%%ZY9Ur!=zNYLE3F*kZE4dF9<00App!cqgjHBiN4oYg?Ip_pcf0z zpfcVawXAyuliE%JYE-@~MIz(q)oX7n^*d$FpK}K5KxjlFmMNyan0LqmlC#nofSH!2 z-5izsf(IohSg&>4-X^_!SHtIx+Ue3h_VSPkt-KbaW|`y@$!@LV&W#2%W)gT=Qzm8J z*vuce!u5}kK9?Foysy)_@9`|RP5hXVRU*u#-;{O5EJ@{52yQgPLO%h;QkZ_WF;&)G z!`kf%-TiOPhtsZWgP?t($C~76x-r^6U3VP8TYGzZNB1jTw|~!9h8GgRFS53;-Gu91 z&co~rKKJC5pWoIcpe=s=}?RC@W=Lj+UC;&Bd{thFEK+t@*T)*>B^ zZcL~tXVW12iZ&fxMmgHMN`%&p2H&wHkv|qtmX3d#0cc{MRqQ&%gDWV_T1(?KLBC18 zUvIu|BJ`HDR7&c`S6bx&N~#%f^vRxSEP!CpI8LnLVo_L|+q^MIpL_fz^!Q-$uob*H z%F_jq+3b(WHD|ZMNQ*~Rzr4pw*ZV&UyKqW7G?YIXcEeI7tWRY_U6+URhNO!zD5dD&c{H11%|fK(b!QyBi}=a9${H*VCeUCZ3hf>cU> ziTps5hO$(JH2ho0!ospSoI+_BC?*uv{dU)c+mLKbvTMdL5H^CNc~J-Fd8)1JXzA=+ z^|8S>C@3gzTf{zd@d!Z@MI7K}O=}_>7J!-8yh;esE6sE2N?r`DFX_#HrfPf^0wCek zL_TyJhEc5RviMK|%7maJpT~8&$1|y$Pg0LDQja)NkNd&fbC2JFw+~2t{CgY~eEj5b z=kXeljFN%%cH1{lJpVsby<>D<4YV#AyHR7?w%OQeY}<|5*jCfnwr$&X)7WU7yYlU` z@3}Ys+R=`YcfD)s!JJU2+OWeSiHBF`AsvINLKj6k=($nfi;!Y4&kB@s!CrCAi8Mz$vwQnSzB0bd*ddmjPP)Dv07YaiDaOuN@?T-RHwlfpnfk&5K zHD;toS1;f8ACJrsDP%-=3SB+upgTUu-7uk`UZU|j;gr%@cW)<8S6AO!z3QyLw}X4F zFi=>|3uBaLp_>#5zn4?C9%(FN$FQcuK)CBH{~VLD8`yDjVM63u&zS+&CTgm5*|4`? z-?ks4^&fA$AFJQz7~h_^pSIuo^j{-^Ghu>H`+n~oE&Sb&ZF*@i>jJezc#yNXWQX4< zi_h{P<#3LTq5>WNLO+qgFC!l?Ow|`eNY#*q_QbG-TPGsIsHrm-G!=p+XqLyoXzPOf z)Z}PsX~9DXJzYGpe5hId^Xu@LZB#{PSEFR3Irh|A+tv|cS7YQ>F00?FRVC0S?hBCn zp9T*`kB|G`-pu-?&a9hn%GP#509gmc>@MNq3VNJDPg9{5sSA!5m#eMmn5uG5#)-lx z9g{E@7c5i?*vM^%tKjaP^K<*homBevPQn{qvnLjg?_Kc8HSBMT$0CpW!4$tx?px>sNW}lSMp9u-7`Bs6*!lSI|SoG8& zbBLi=f#(x+oLi*K2*tdb;gBJhT3QhtR&0(*Sxk9)VD)fSvuZOIs(i4;i1$^3b$blD zl-mbK5;+DenObPWX6bf#(SRu_9!a*E(gIJ&7TlT%@AYxG`$NL->IFbA{Z6-Eko<0neNT`+c96Q>9{z>q zH)t9p(T#I>_zvvm5S?NE6-vu2=!q-zDntl}shL!5NEAy869b#J^){Bg0UM3P4-0`1 zo%3;QRY(7C2*N$VoMVpD-YO1df{$3PaUWE}$Hou_>p9{$!gk9?Jow`bIHE0+yr3C1Qef;i&l z$HICP2^pFj-mH)y<++-gxb@m05-Cw?e6tk%80A)8WX8WSG%zA?mUb##y}}$Nowf6c zZrx9~-Tq;I_tkGM-yS=+pD01h8)X8Gpq7e&6H{<~)JEJ ztcbuExqL&xz@i8pi=*L?SsJrgZ6|)je1G7pVU7)AU)3jiHIs zrJZjSpr1_<@84$KjS|WGNnK+(b9YdK`%up&l+IoP>7~>ts$3(D9f^Rdf~AW)Qo1seJqXa8_g0auiJu?q5<> zR`z~YWAqB=7`gk8Io1=d51#n^x^vQ#l|PLnrwlh$H>3Mw{bT>*YLQdluj}Qt-;I!R z-mw!{k^mao-+Oyo<_a57W1fN3C3eWqZR)P3bpE`MGU)Zi1b+m9u~>x}Rsb7;_UXkG z%9WZWYTj->VJ$#lRhr%E>zBR7!2@&>z~7!M#Ycq)&Une)i-Sgh0YXIOz8NaQg_<<> zH}>{65^$uShQ9C);e=R!O&)3kJ+92xU(5e)2>Z=dWMO+(AucqfNT+aWY}@Y(q_8B( zWRDizXGG`EI@Fgwr5_|7KLY*F<@ZJEaJQ=`$=n$7Z)= zdD3S7>#|;_k`{Q4E$t z?j}D#$OINxo+pe=KhizK=@FMA1j%81h|W>^7M+5_5|0a{>iS2Wz2E-U<$48&%^zc- zsLM!2k-+G9lN!4UKpM2Dn|jK>eap=p@G(~}Gy{Niwt||C@(8+SthkE=uMpO-22%Bk zHZc{j+n>w$LQN96{rf%6m9}+JfLts~77$YX`uA)C0|p}HOuj27zP=k?-7mJLH@N3ryg)F`Kx`liFxTMY&^A1^E7?*;0kMGAKZQ#hCnm75st1 zYY~;KSSEnl_?;_tMd=98Lxogqw!0PelL;iL=W$xUs9_Acr4Dq`MMxhBShst;@+A7x z&y~!k2)*W9MNxWzpvWEC{QTewzjB?*st=lQt2yG9MmQd6wPR(l{|S1 zq{)W%JC0$xd=LwJ6R=qdK7C5`hpbkFMB6hP5?U_Bd4Q)0Xli>RWn5IzNyFQP-FjQU zF$B~=|9>Re|OoK#TTZx|RP(D?6MIf!>iY9T2N(w}_ z>~T2MgA99IMs%J84Zx?L!KmRQU;p`I(y3?9k>0r=jjWtgUqyCT;t$4;TOJJs5W!~k zdezIPiSvmAORYl|UnHKxV$gH-1IV>07B6-cvi~QzR<}iyA%NiWAOQl_tp3=U2j>ft zQ!+`P1>0{~N9KMF3oOs!FO$D9I_QhY{sjex#j;iYwH%s9gI9~O_zL&ga zM=B~;lZZqN!7$5r0$7{XjGA!_32Jtnml)Jkiy*e!h ziT-$Hski(oiOZFPa;rc2W131@BC2(L^ryZ?GCxlLgo{v-LzpbE-iTE;Ma{XNsUZh} zC)xl#Q&x7?a{1!ZAh*#Zpwb63@^y3sW+dQmO`nsAf(#LZmHec;|5GMo3joSwB7mmP z<$=#sj_(+?21xo%>G-z+?inlSNJ%{`)CzC{{`Y$uE-lbvXPZ2n!990ACCw%+sR!Cz zi8D`$&=0kx`Vvn|8|t5TS;a)o08ZAZRZ52&I~-ai^Ap%kG=R$T2ct=D9{~g|HcFgG z1xzKe<*O!y{RPII^9Q zUZ2T@7G=K$&01s}QcWYly&0P8;_ry>)@FG7qJ8MMyz*b_Z%d#AEe`^G@xZRd!eMyN z6jR6=Pss7tI1m&|n^khv)_Yx1{p7BUi}eX4aa1?sJG379-ZqyJ8)~39F0j>LL=N`9 z^-rdsUc37>yMF_WGMtE5Q%)5miq)yvig^lEoU#!jjT)xNn4} zX~|{jVGp048(0nOo#66cs6o*c?=iL&@b8bt8Q@=8$eoOq+?oagV$k~di4YNeu9*Sa z)Xasd@jvwE$nq%w3ZG@*Q=6=OdT+&s*VvHE4}lQl&oCFUl(Mx_;T^r069DDQoA!Ht zGmH=1u&k;~0qTf>OR$VsS(r=B>it)a^2x4YlMVx8HAB6PLbv2E)768;1E<;y{)vK6 zQas2k=xwdI2ZSrn`%-!U--DsI0uy{bu9QT={0xt_+#-TYC&xk5kvMr z@pf{_bhw7uz;ZxinSZ_n2prY^e_H=|Db&oLFk$Yuf8lOlA0E_9_w-9U*D~!ZARgh-1Pnss2(6g5aQV*X!2gmlif!^lLIab9l^g{BU_&?6( zP_<1BmX1{F7wQ2H$T)IYV<`6a_VvOKf6rAp6!CS3!kDm1IPI(J>DoIx&u>MK17m1?%J50((^d)vehmZp|{!rm$ddFXmdiS}`T!Ng6Wl%zCLc@j_ zhd)1GhIP|Wr64orYQu$AB7SP7*gElfL+iO$o>}iDk2jp`E^jF{$IzAu6&b;Xicycu zS{mFRqPkEza*}yiO(zWyOHUqOL_wbkR|I8Th@rYs*>``w!6%+Z>NIZ9d4lG$z$3Oa z0TKnE-Y8aR4(tUS0k{dyMeN8*)b6(rW=vQcz8#x395+`vL|4~h#Ns1+iSHHX+M0X= zhf;fpS->d`CS4^hav1oD`KEn(Z8aHr;G9I|auaw7`8{+md9Pa!y}qn{JoTn%yDu#A zEk<$zZifR?TeiE{M$Xo6H31s*iN`t$4J87`fgMAuOZkPT2-4Xi2Pz)d>Jc#?ovviL z!uQPcC?EiLYqd?@wR9yZ5VxZtg1r9^!A@ov4z!yl2hPwSybH20-y0WHRe{a{Dl}pd zQn*9{{%JW`*(1vj@L$ww=l~SAzCM+0)-ohYvhwmW;FtuI?9q8g1z7-@bG}!+m}U& z!^2N!yS3gmVcJtmsS+J6T)h0eViT8kms#1_^>knVNxNe^XVNRHehtH7!RPU#X;At( zW`UJl#R5OGcpEO=08gn5DfmS_N)+=Q?UaZ!fAno0(_#I4Pu`rm8GIvJkf-y$Ug=Ly z?wR8(U91B*5ZtX=$Xw#*7aJtS!jzu)Ol9oFTS)_%3g0BY1qmk@n|8k{h32b56cCAH z9y$OOa9Lxnfvcm_=40&A_x5x2aP;(a0(b)rI>6{~dJlDr_o}AmI6bDqfrnHyKkCc^ z3JLfEfQ%fra#kz^vFp-nX$`&#ahG0*4$!!7nY~uZfg&^{xmJck&T5F$?#c~KDI1Hf z&1qfJM~Ff7lJ7J!bDYWdn0e40bo7?qzc2_=O4;KjV1j)D?Pwc`#~$rp$eTrFFf&%Y zDmSP9VK5M+0J2mj|2F)!%y)%hc-W~WedwU%czS$gE6qv&gJ_x4gC5j$DS!vG#nDjQ z%DoWW7MvnbkXHZ*n5ijwzzASg@8PQj?B3v;MyZuG$xl+&Oo<-OKOQv!tO23@_n!QI zzXd0=BfQU9uBDMrc5NO{rB%u77=0y%D8qw=zhG9MQRF#|?DzhvgIEjeEqwd~g^AMB~#|#m&1FLjwaC6ypuayY5NL=If_K!n6 zHKL!Jq3`9hDT=~{)Se_?paFt zUoC*ag{t;NviVz+mCQIZBlp1zQKdJVK6@~mY(NcT6vnDuPFe#lYu-;h>#jbnlEo{pq@aJ=};@m9eteu-%WBxM9`!YYj%hKsWp>lkTs zy33HZ>7Wg)O(}d7>V4GXTsSL3L3_pcEFmPBZVS3Mvqgfg#;|l^R%s3N+65Dvb2Z|w zHY8JKIh1@#UT}l!48XlV1akvZbo)ZeT`!Jd*^t?`~=>5=>2=SLmY0!h{-+wBo zOpeloi*2R^z`cZ#xz74~SmMmVA#-^%D)VPkpvi0>L4TUqZja@u0LtAfcjl0V$2o(v zYc&_d*1X0|43j(1z&dEIK$Ql8#y4ux8}QTurp-2ORu*19a&a;3e;UX=$TGdVyFoR#Yg}v~gaMPSpk$;k0qdy^C zwCvt2Zr$$5$LX=_?ufuPiszNGdU)5) z$X+nlX22B*cMk%cu)C^rD%3a;(?5XJnR_W9xG^%btsWcO;jBg(?=a;Ztr`M$T72|xu zw@iLSIwLxGW-7P}B#uKPUhC=0M&J$dB5XGiUzDgKyi=30_fW3Bt5lk?JtsbrL?|!VbQoqR_;@*Hg#G}!-CO1 zmSgJAEhd_L1@qPCPiwGLP3}oKCsN9u!9Q6)>9nGn?)FI$ig1KoYGYrz z!6f$)%Qe>e03==E{`${5(6G+#2s%<5$Ku?{yLN3OawtiP3OwN<1E7!7a4V>D?Fa!x z4xbA9ISXceW7=rv^^o6AQmRY2sM}a`>`o0A@1n)^<2ht$BWw+VuwGcxDYDd1tZf*34DJIj76TGIZ8tl>OtPK!bUe^42yEITky z<4_y3YmF!g1gdQ_7k&nr=x~vgbMI?aC~eU`r*@t~iZ)Ub-s4CN>ZY=wNXh9>7}FtD z`d;eh!B&$Why;i50R}{|$Z&m*{oYQ(tE$1xy8ESo6MV)@Gi!JeWb^rrzrQ9y9Yge}QR$A`muD1(C1O>05>(=Z&?=eO z(dMm=y?2v7iIvZ9Qx9e~o~r+vd86D4Z)a-lLVB<2L)jj_Ja&*Cf!T2Qh3tEOC{4A|puS9+4DG3Yd(fD| z>L0t_BrTfZavsS!>|9#BsmSi93tsE;v6!014l z>GU2&jDT{3!(0QAYpUf9B2ZfSWuh~$&SLf$jZ%9Klv(B?WV~XO7dgd*zJj(l!C>5s z>`X~^jVsill(O(#P}QY61CT2O{f^R_o8$V?rG>ctMPCm2_xx|KWY^$A96f?OIw6P>1dD3`|WlTmW7Nm zphC$-i%>R6j-#?-*%fwIZlUU@lWit7udrv1NPC0h*YD3rUQcBG=MR(56mRF~zqDPpMdF)6r`so0$tMsG3nrxo-d*LoH;XF|s7l ztT(K#Xuk*ty|tWBei28u|sbLV?L-{hod`nA|z8 zMjsg>g3J*!Xg`p{Y3d<1aknnR$JWf2kpx|S>A?s^{S}np7&l8fq@aG_zA1`KGkNmP z2W=cX#A<$wIv0okJM1gCUWyLy?>neemwlJSvDXhzF_-|c{VXB+e-VuxPF=FvwTNBm z;9jZ)fE3;CX(hod{_H?^9} z6i2N8hM6zH)ug0t1P=RW@>!*;Uk(lxBJg>;nCzc4_D3}1DE&rfobQGi@0y~Xh{mgZ z`iQvjb$1?-7;p5QA(8P{S?w{jt%LaHf>!U!cT>_!8RU$|HGT6RQ9kb&CrqV0Lcb__ z*?(h24!3|p!E#0Rs(epzv^0fM(+J=;p#{9r9T1;yU&^XBPDRfKEsck8I3m2Os2+%r z-(rhk*!#3x?u%dRQrwu3w^EL3QCK%**58bbrAP(KBh2I<+Wg@t)s3xbTO6v4^Jl+t}qymofyfB>05K|yh7)tEYr zjT|)U)WR$;rK`8$h+#$7cK=75Ppdb7RhC2qq!$9Lq)AH_gP{)bN8)efznu=8n@w9- zHslg#zh^_x(5}Ob)iou@_OV2r$6u3&eUQV@f7<81Nm|jhC!(#DIj(i@Y}oTph#hcX zz{+%c6!4+ySlgOv)|Px$H)qrs>BNGs<~E0jU&GltxV2(ZDt97Dxm|Os<1pg%if7`? zb_Isxq_tL@g0SH2DYb1m@{j+V+&HnMApj-{_Xgk#E5A3YT_{q`Iy8`za8c&720$VQ zE-XZ-{?Bi`%j3nB39llh{NAcjgAd>Yy0xmx=Ia9ZP3D^-=qLWw{OqiOzOD)4V5$NW zTlaLTe-*i?YDWT47kG>3sI(Q4 zpuR~z-GYP<9TuWsF_low{+@xbF}bCvOxe?`m1BVD;UknAqMScII5==% z6B$^v;?EXjw7*1Qp1wWjkp>kq9^;$9S+^SHscGp8Ir!AyNytd%u5$x`0=>WVW zNdEvuEJpc(vZ-`hKFa$^K8CHk#uASu6-Y$`W`JU9iSB`O_0EwNt8qjkt314PO#!1p z4smo0J*}~sD;zv(Q6Bn02#MZvfEo)Cr0|j8r*o_p72i`jK9kJxp9Dt{+iU4nU(*@0 zr9?&2AiN13;Z_NKEx%^s%t9Z<0UQ|HJ7TR`Y@7Pn6HASTq5Kz#ez!|OSq1qzIxksaN{V5JBx8hge6@3=b^|wJxFsPQ)v7t=EF3)-Z_h9`4f-X; z0*7Bv$btjG8%k??+|Se+Wt0!}r`B`ZlKNawHSzU0_XQ(H@#NoAsBH`CZ|loXPmi73 zbgBgWd^H%<4)8S=*(>vG#upTh_yie&p+Ecbf--S*^=VY$eL;a9GqSzCeR$Ql^_Skb zOQD*;wf-b8()jln<54Y6D5((ghM(7sZqJO0(pTdJ^i5d)z+6bf7%?gbvP*X1D(@z? z{)&KqEy#<>d zT}pGd0Ang3oSQFYr5WmW5XD?+>eiTW(*UG{3gg%A&Q2_Edy$NGc6I`rTLM!As)Ivt zFW;k6uPcaPUIy*_dKuH_O}L^x(jZ78q#YIkc>1D9)_?e3477SFEsPM;P(EX2@) zgsCZ`gi!SIABpejvVEv)!koj-LXo8G-fpGz$Nl(Os-kqo4R1w4?mJP>M+x%SJO%f_ z5i|1U`=cII9?4=rU(Ed(JSfN(i$~uqHaVaR0K+Ou&+h`=2NRkYDE41t=b@c6+cRm{ zWU7b$w94ys8&);=h>D*6&J4z1oqNeGhJ^?x_iCi5qdu*tQ)TGe!i zLa#eib3B>xrFlEvzMq}hH0r!vy$w%#<|mD@bh|8GyiGDpI_{#!GLRSvc)0_*X9k8T zLGPyn08KwHUI&&22y;-4TOAn=@;poozLrOZlCueEPCDk`L*LNb3LrG8_kGVW+DZYm z&Lv$X2npQ4R+Iz*5y=3J`A#rekS0PJw9nonldcO`B+)5sPD}L;szOI#U6(AHU`YG( zJV#B81Wd@#TInC0l((5AQJskMUi0Uq8Vk|yQdc<7#1dd&WgHyi(1;g-)Uj13y-ceR!i|RVDbB!21Oj#W z$ZPJvl-slixTHv;fHAkc^?%3Q%6>OL8_RvXkix3$8%f=+TQTR4FSp~=$@)CajmyY< zo+gmJa&Pt}R%d$Dhcd?gdlFET^P`-EUD&ad|FX?*pZJn;_T$2Mmjo{0ze2kwz(pDC$L254WMV?DUd~8zTj8Uaw zZ5u30QDEA2Vv|KpP&{qHnLe$@(m?hYH>gm?1~@EdBQFA^^hQVez&7maW$I>p3LG^#9v}OG`vt{x<9HXzbyZr!<}@8THVRn5ErP%` zG1JxC+gl_-Z)K~id(LegJ^jBPT|QL&7XuzN88w9Lms)d{XeX$4ez+mfN_`iqogA6n z@C#Ys>ZootCZ8P$rU!ih>aV&AJ#rEG1jEN^>=jhhcH96W3!trpNbEE<`J*lAuSUPA z_?@A23^=ZVCfX+c;k+!?TJWRNHtj!bNopHm-UaI-midhJ|+#)y6FAi%y9#g3oMTESBsVpa{XJ=pbYYu(1Pjs z)0M3OAs7t+P7$b+h|5_!-H5}OV|~=^wxNqMatmBbZH^lnGN4nqYmOsfh+Ur_%@e(5 zOtU&>>{l+(+nHYI-&S^BkO%>z?B+Re>)lz9^{BDx#CB8kHNlztIObnd^XaE=kfOVz z?J+$2dGxaD&9zk{WqwR2xW*2q_Mj>IN95O_p{wCMuxJ5ylA!m!-<&4mj-Oyw@Yg$- z(~(4Ji2!)ife_z-8F$ddpK1ToL=bI$FWg!HFhQUY#CTHS{U_#Lx_H{cxUpw zxU5gBm@VMB0kDq;Ud=bT5p;_NVzGl}UByYt;|Dhn^P3J_uP3L~3i8Fd!?4Nw$=3dM z^2Hh_B62h+h?bMK$4o|i9CC!$ntW_gQPMRb)jIi_UGDu+;sBP@tQ;GNGdC4#8ohHt zgAo@%bcgpj;Zw_HSt?{|6c|VD5w`RpZknBTHx&eGrEGlh(EQ;+L^rB6l7gIAL7FJi zM^Gq{G3BUEI^iPCyCrv?r92(!X@UpK(5jB`RUWyG_)NAo_1aw_tVPb##rI({*4L;} z=i}-cquGZJU6=pQWx*C|-#55FD;n#=u-z{g#$BV`PqPXc`Wcu6DKCzF7H`}HYQ+Mn zM8A$Wlr-loy882l8=*tjfF-EujvCxzWKGe-aP~Y@@ku+$WNJ!=QhiGFxk>9Q=(BNV z8@M%Fclz2Kf>C(XFe0}9g^tR2xZrb=fC_pUS!MXG(ucz?zJg<2f5m@!-~~tA{}+|D z{YczeLtSBQH<~YGlJyT+5BGsi)ENJ`FW;R{Zuq*}x}L8NQWX?#r~my6q@z_QGi{M^ zwWYbxrXCX9TAQUwyQBsI=CIApH}Chm_x{k+bbw39W1`GnTl|N$j(o|@P{He!JRE>5VUTs3>z4MSToO$}_VXC1&n;#Q3fX&QZe%|eOnY!1FV{M{}luY5hDUD0rrZW_FQPY(IUtM z^(^IhWvH>pc0!CsZQBw9kJtvb`O)Zcm!HfLkq@vV%l2~*02i3|0C(>4;TRfbN9hgz>g*(Iu%8sIjDGLKimTkIYMfWj_WsIhrKlB%t4W$FO_l8KCqc1h*wo-)MM-^$C0 zfal`B6xx&>5~a8glbvt_ zjqSgpUK=y39pp;NOUUWt1b53ZmC|=dVMVYS?B!9C-V?iivb<|A8NOsr-U5=hx0CYf z>}*UoHzYN2EMu`4!-1w8FyLxNBD%{)h3Q$Q;-?jN@OE#!x+^P7Hat|dvjs?B_odxi zvyeLFc+)vyGn{?rjUJHAqA&x=ZzxY5f8`$qtk*wts>osf?A?(qF&MMXI?T?K(Bd(R|Pv(X&EAN|3x zj3Dfmi6R{k030P$4m6H6au=Q9&$Xk?m0U+x9qYBKGkQ9J{0y5{#g-ifkG;WR9HwmHSlgCNNZQC-uO0a>r)EY7783{Pj82y^Obx zG{-$oV)ZvG|5xbqkVUmnP~*b+{tuMS4gl11nq7%i;Bw~PW`vvv@s$h2HEq*GKgOC) zh+w=(HvJAYMb3~cAd#=%LXpDUUyi4A$gObGvY}Gd{^)m-?~%8Zp=?5mL4x$07xO~A zUL8R5{2TkR^r{-2xKx-Zr6GcA&{%mVM-*TM(85qc<-`$M!hNx>R;e)a%qmq^HfWLF!{F<|^U% zWViQ9B02tc6Y`hw`+>T?nWpQDWqQ*_t2D4Tvb8+7?4yI-nIYcDj2oktj}CoqC_*!3 z)8{$Ew4bs2nPphVPt79**o9q)Dm_~+NvSB=yZQ}h7Nvy@pO%HpeJ}L0&=>ql5Gim3 zXC{#qGfrm7-r@EY(Y~Y=+BP^IEB|rY~2mp{}32IdJ6PY;Vk2T+BxSR#s8vu!o7Fmqm<$D zoZAFOx${XLwc_mu??mA2NrtY@#`g4>w*u(Dhz;Oq7Tf>Z_d7hc2M!Cv*YD5$V4$vAkLEv;w!3KoT-D5N?d;s8d(g#BXBx zW2ZR2@1|0AR`$V>RZiZU@LBjRFpXFuewZx6n9Q>F93|qFl*9a~ppJzIK?~CRKJFRj z+nMY~eM|amT^Yv3pXq!3{&oh)o#^ldd5=bkzV^?D%T` z*<0wp?+FO-AiB3Td|6r+UuSvTQIKRL{pY=LZGGG;N*-pE+GivESP{*O!{(c2f76EZ zY5-}u%}$C08$IPkVNY+Lftb4zNa&y8Gb)GZ=S}UyM3W1&{DB;6e;uOfj?+m@B&RZR zLL3Pw#@29I3La{50`VcrjaOCaXkqyChW@qvEi|Yy(I%*Ym-YKfn+mxW&XL=ivP;@RvwFaK^|aR?I%y^<_+#_N>iq9}7g7MSU5mEm68Kd= zO$jd2XPGw`{ogWAV5AbDaABp$8QzX>11;$@C4|5zToMYb5{fgsbEc&3avje)oVXgH zF?9j7Rm%G6#P@(@SH{VLf5sWgWQ_3~R`DFFy=$@GS92MqiO5;X34&0UxJhVmV@sFO zBdhymZ_|S9`Spq5*N^HvLhcG$jG$>VIlEEA%=T?eAVI=F>=NsXYdmYKYGUG4^qdo(!AnILhKk{e|Iw zwE(hGdwNNK0ErTrbPjQ99Z3z?yw(jQ&*Ia1JCU)v;&y0O#%>Oxs_ij?$t+LSPC`ay zeE?r-!2(|eKNo&qdA`}B-alTu3Yn~*-+?XR^3_$<=Jmt(p2l{<+p&3QGAj ztD__`q5O2)cG}Gs_nxd??j3DiSvG`Z8+HLNM8w5o$CCC}=-=Bxe{kfm@rVG6_WmpD zkw94o#Fb!WsISDx`~@0A5h~As7B<0nhEAQ0EJj*)6fpbbB7MF#okPEz#0W2!tD|F` z_vNxrilsIp4QW3|%-@WPjb^fsUkjqwcrXP}&vI3Y4bftBqWi}IF&-I(^t*T`-t;J{ z9*l*16P>b6&d3t&_T!}4kJ|?*p-BRQ$xu^`bp%{_n*>D3wOMO5(fNMm*m~}tZC$O* zgk(`$(sLEfXk_W_ieL4e3+$COz94|@Yw(lD(TrRs1w*}2-TyP6 zH`xYq0uPT2o|L+mRw^SOVH9{n)a3tJ1nKNVHmvh}cIRN(;8+@jg71&}!-RgXkLT~4 z^f2;ywg`SgrQx!bKa}}%Z#7w6iB!FYkTv}Ai%3#5~RyM=sN?Ir~U&_sl})IlCSN`-9?zF zdMVw~?<7XbIssYPt2x>oAbtU40to*)Isr)cHT%{4{SP?2K^ z{<+H~u_PJ>VP3E^ilu{__Dl@{kFen zzv*O#Tt5k* zj}HfY=(F`6u%G&m!TK4p#eR38>L4E8mcs7%Ot>`0YxTamjmzYo5h8f)&H*JgDI^oQ@EWTxTG0Aj?e^Wl|lyhp&P{W~5^WyMv zMp=OcOXYD3#JC_D=v+%FVsUYC;rGk1=fExW{;`tDkbFb$BzZcvmFJPBzRliQc9Z`z zR4hWPn)7z}Y4LvY@CDk~uqkwrqtn_VNMPSaD0(Qhi!coNrw+v=^vXj7>mQkT1F1v* zMMvsnjW6HbR+%D9j~uGEf|x<@Ms^E7=A_{OH7Vj1%r4-@=Ho>5fD2IEndYkT$<5w% zLnMzc@=R^)OoA~mw=K4Vzi+C+F($@eo`W#^ww^eccLR+36-`m%RpKz#_Q9+aqw)Tg z4#&@Dchl8q&mx@L{DmK63uMCpTD0r%$mUnoLNCBMrtZ7asSNF+x}j}f^Zl++S>g6@ z*TLP6G}*w3PcC+b^K3~+bz6NAQywE*VuGKBCen_asFYz`EM8L9Pe!+lNd+} zqYW0_ZrK6>onjTs+K9XU$hq&}8bM`;J06_al1SLP1a$VWUMd<+PHp>2v*0fU3;GzNg0WwZ7(2?vSQsyJ*E=NZiw46lyyW0FVFdS}BykyiEXnLfX z-rCr~TKZ#r)7#x%0OhAPo=mBo=+t#bhg#MTto6yr%Fxx7l`o=+oJ=~z%UdB2@#u2* z^nHD;`6c)zByeXa?tS@RD}9qabtCYf%kP2A;PX!r=#MheFWLYlNE z^JQDtO6J)CDM2-m)0Vilp!`qIMZP|;8JINOtM(`9{GeSwFf}5_{MQm-K57*?41rF6 ze*-3ZBUO1|tXGjymbD&5A3MXy&tA(FE!@cAgP8g`4a4cvTjKjQyx^N#ti5kxX4i`A zrZd|TCCV>ksDCFdG;hOY&`}hC@6@B&zdx7w$J6-!CSAF+{|C!ne47yZ-!({md|2{ zvXkX7W?Z13om=bU%0pl!8A$2ph#-~5Xwe$Gkj-prsc%BF5d?Q>~5v1dp zp6AEw;R_^WP@?G{hb)KY_7w9{ZjGoxS^Mcu2O0k8I?BWtUmjcy#;Cs!!@gaIQlF0+ zN!2MVU`a;<9f9p=n$tld`!SEj>1ipZ9)WLa*?_MD5=!xWB8iVz3VU}>$0=ZucN2WR z*^KSldUvJ!CzZUDPSb)_nWC)!dSos1x~uR$A&69-TO9<<|F6dQy1nm<#^E} z(!?8*xHz`Y%wi8H09^x3F;CVa&Rp3Oi@Or1*o4){Zi=#(kdun8#YCxK0#->|4(t8=d(X~Q8{cPh--qs}%MZ$Wj{I4_d;NFJkL}BMR)9y= zoBh*zw?HwI<%AyBtI>OX+E=*oMZ2}HE{@E)*N%*iq*?n~M$3s7%ikcOAvds4MLbYR zS3rZsk`XOFf<9CGk{T5gj^pi@Zy|_5qCErSCwutU8&p+uLf6b41&l;qUSZq!4Sl@X zXk9tkGN(2e<@%gcpMPVk5@Y=Fl@Z~1EWI76`E6p*$kEa9vyTMPMdumAn-Hs1>Gzg2`qd7pPq3!KU*b^7tLl9K!|H+yxe94X-15Yvxl8re#pV&Vlx-?rE*~l zralil4+kUD;-02XZPViPUBl?~23{LhHv^Z~*%!E~rP8niYp~2bAE!nAn(bs9#&1;8 zn`K}&duxEo;-^t#HJaG+J;5*r-379S=lq`4ZTqdYT>v+>fojo$t>fI9VAg_-QGe^{ zM)1v;bZ)4G^LO+nt@>}dthC6|RGsRUWlH9%tkDm++_&f%O2DVLBeg-P-D5%&OAlE;e_yio$c>o6@>rOHnl`x)&HsTZvVT`A0&{j39jfabQ#q zc7_#-yj6asgVL$3E2(bt9EL5@(BALE!QM~j_)k?82bIRGi41juXFKh9=E1=qWi%1z zl(s}6y)BDmYoEJL~VtL-j04=5Pz)P_IYq`?FLvi30ajS*EF zj7Z&5EV>`i5q-(tWz-dy_Mwg+h-(k^3%=UHe7X&O|IJ_}ec^$Rwa#3m?6e`ea30A6 z8?2$FMSu{JuS6GwKk24QgSY*H6aFzN4C>I*?DzMwYsG>+6Bo_At~kH<3KXfmwY`Hc zJP!Ng&QM5JdLCP0155}}B7fJQrJPB>wm7kiu8Yv-^a z2#?Qr@pcg~>N(5gNxlW9M3VyMDi)7viC8_*Ai2E@k7{JUQKku-Qpbw$Ss@8(v|9bFjS6OST|5X8$?|$Y;!x0FO^5Xn zp;xD`Tj^J^*$u&5*5QmEhQ-DEaXwT!ZZ|9+w;TwX$TU;eN zqzre%6Z0PVPsAj2!I{Iq%?-V8!H}9s=lsdYleb|R9c2PBoib7~&_2aO10fP_(yDZA z-z4l7Jfct4If8RB6{}Xvx9ZGT^r5SfN*UR*HgaT%^=jX=Yt%|unr@+eajG@=3XaC`@G@m1=dAEQPkQHo}}?9h-l_GI{T4^{-H zP)QRuKPRYv>^k}%tyTx{kEu4&V~6;ko%Xe6v`7{vZC=b-uqDjBnwxhFqQjmj(wYTN zl;vvBo4V-?IkDlmwCfI^&pJ*|*imm|rIn4iFg)?TNz?g5$3l~ug7UQ!)y(EmI6})j z<9_wLOTdJ3kwUhc`sx;q>0!cf)0L!X>zZMR0sG(YSUOpD6z{JaFYQoDtUfe$3}UHW zgza6*4I8@fJI#)P3bw_8jQpph+e`{F-ROa4G{IDp`ioM#VzvUMpuGMP#MhqNRy^5t%$cswB?xk#JP?}cH%@P(*`ZRieIgWq!<>&MF z4+|4~_4CqLlFF^C2c$Pc`4}Vhx>~oH2UrBXBLfQIe1sSX84h&edc!l1bRVKdn2I9# z$vj$2(H8&4f!VBqZ5tI16%^>kWXMUbiv(1_I`Oe)y+m{cYDO+oBIa4Bm$U#9I+K(y zMhH}|D|%}IkD$)4%2eZBEY7Ha0O9TQsRVoD+x#D{l*tN;tn)UyaZx zrGW!-Q-t(fM0k+&)Y!H&Qt^yko4Y04IWij=nlwybI)PXREC)tJR-A~etS-Y$zb#mT z>0oEXZyYoMN0DFR(Mn3AUjBub6Im$;P-Qo%fqFd!7}yV=y@MB{QP5P~@> zDXs9@yzG?o&U8LO!x`eQ^mTh*m1>x>xjFJl(g@Zp|C0kxa6Vp z);7gNF^}9~G6^*PGOL02aP-iz7r}yS3kP6^AogvK6^XxcA3(Gm#Ztur2Wu z`#<<$L=95w=2+hvJU6M|9e1%0LI~T$hMbrz?q}Y_q<+H;#F2oUQOrR&YjSy64=!v5 zdNtM>mW-PmwVNpM>T1k)1dyH=e)mXzT`1#Fk9kpvSBXoLVOSnd!ZP6|LgwhlKI$ja zAO3WKuYN40j>SO|DM1Y!iHkltZs`&q+X&-=XveR#=kE6naE;8O5N?AFn%zaJ@k^!n zrsZivul;WB-M5Y(rLj(D(cMpyn}>MBSk8QTFg!R0Q8N27`0>pUJPW8eDmG;*vPWw& z!7B_$Ss*?CI1i>@t$7c&a*lFYW=P*&G`mRSHYpxNzg$%BEMwI)qs6>d`OP$7TQ4ep zv}r*g{rQBLIeGS!-H4X#{SEg!%d$cWmtRsf3@RghNq{eOgcwhxpTi|^WFIU`Z_M_dF`1m2b(j@O9kzo*zVRy(LAUZUG`AChHkg(HGIq0nYIJ#Tp4A}+w#ctj7?ZTA{BzFO##rCp!-{~7g5=&?PG={$MFXRy_(qP z?gRe|`QH^~7kN^>A$Rut&vC{nkS=KEV2U9gjiT)?%4O&n70I%hqd zs;6^C&BG3U&ym6%f_A#2AY~W<^vf z+hNsCA7fxs87&l(Y3M6(ayCK_!)W~@XXcuyR$jwW4Xi0Mtt=r5S3jwR?Ip3~^X(@= zy>KJmPP7pEZA{L_BAWtnZS`koVhlYqUA4k?8`JKtHOM5{T!k_b7P*~a2ZCZ z{^buwyx=cG5;EaTQtlg!gt(L(YCUa*L3um&yE9_)E=~t^(u|lbskE5sv~Ke1@BXUI zwsxJmW9S7bhS&FMEj`aT>ZbnxLk0xRL#gBQ$%kaaQT{iE+8wf~+fr0pOjSNnnEmi8 zk{#2(5B(=vWFGU^z3**Zn>h-(MjtLeLPVn_GZv0JQ>>}RZ720eBxBR}u(kZ}^4OB@ zI$c5&IKwGlekH>(Sa@5SMsYMtePtS|d#m)^ZOYrVDZiU6+Pa@45qpoA$R_`lHffjo z^uW?rEWSzcNfI&G*nb0C3ysV4m_k!(G9)4Aj`}pq({q&$JWY^Dcxg9E1;c+cLKbem z{IS>lepp^i);m@@So6Km5LEu8rTrTqA;3bhHy1*D4l(R4(?4_CaBp+(b*09a8ikLC znv+N>OC`EEYo%<3PHl=M)xDdK3r(Q@%^9R(Qrpe-IYERhfqyS}2PK_V=Hu^75_+C6 zuY1C*NkF<*I|*zNpba)|bA0N`j^U(1vtA=G^SX#n6mytp~*g z#0@l1*k}n9Ygv+rGcP%gS6wDa#u>0l9KkTh($)s0D@k<)LH&FYxvIt zgWaYenP6jfk}i`d_%GrLz}as@&c6V_qG&^jj@|8+tk@j4$q<(TgDQT-P>d7;9=&$i zbQ_Dd;2m}nge}n516Pr!?mb=d9c~&nGIq4dHyzVmGGhqzi}q0?T(cRpb0iUy+utus z%vI~~l-(q~ZDDTue3QdusD`TS<~<8OyXx<_<`4c|At)4VL|@ZAnV_ro zXQPHbViiF7R?$(hwP@+cqTZN}Nl*e*dGTP?<`*jacv~|Zey9=+%tMrz*qRdA(cd-h zH%x)DC4Nu8KC$%Ph2`U#L}kQL3uAxZRD~Ak zkaBvZCcz-1LgR%G9?ix^WSIxPwi(8X?rixzrvPJoOrWY6TLhGzolg*DnP}ao{T+s~ zpD#NBxt|O(R%B+zRkX#VDv2hB?c{xlciv+)lyM=5u8J1xa*m ztVhFyI}1Z6+~a>>v-pW6HsEwmBsY|Z*RM2<42f{?a`G*EM8KaY;&=!}?Fk%T zTgX&Ob8y}FFTg$s!MKrMCJdjyGeLhbTFpuY=+jRao(9x?h5!^Y2Ob|g*T8yMiy4tv z+`%Ls0~|~7#&^ZwXdB)h_2)!;e#LD83FB$nWaNRJAt*>%OXM42p(`yqmM#A0!nG6> z4hI;Quewms>HghrN_ronM`*#CT-S}P$jpVF z&-j)Z+`z8~Qxe21Qrkkf^}gC3k~!egLM0!xAaarZa(pfmZpB-PCCl(m@rUOOPho~F zlGE>#Nn~1W#mBcl0*cjntUa=YlF@}uoEb*x&IGdO&bDJ?d|@l z^gi#OT;gb|px0&##wV*#I1KsNP7OsaDYZ|(g*wqqm4W#KxGhmxrWzn6;waP{?qrtD z-qI@$)c4SW2iIA(%aWFy76q;wS$^5k5m!hSL`+Rc|AD8d)xZ-22IYZ)BQsYZ#18^N(-u-w9q7oQ^o3>JLpR9NY7$+j=P>ppNE%t$Iv;qQ#D~0!D9BjG6;J+Vta~2tSv7@lX6lv)+FB zb5`6c%8U#<_&7->NLvYuUdCPQAd;=o2qZR~d_fNjSOk^jGy(g4k!+DY5A}WLn1Xg!4E* zXZPF!L=l#^RJu+afpDP}M8xlvCpLu{atvFaR`m4F>}#jIAkAU7j)$<| z-cw#j8sg_U&r8yBJ>ke30sI^r!J)~In;=7deV9HYz8DqWRCL0@U#O9JjW`r={M^Wj z+BEqqO^4eThlfACZ}mHTS{r?kVBX8EUYGK|t7s{ib=a!bT!dG+#%Cdpl#yM0ixyaE z@=estLdN2Sc!9Ll4i-Y;0tNse$0WPa|9An0XQx`JwUVaYQo0N1%|N#!yRMc57Wc2U z4vJ)AEm4Lzee8V5m(?&W9%R8E_Ryr&*hi!3zq$6viNo0oelMdgYzD3w_fx^6FE`88 zUu_dDP#nHoF-F{Th)$7B*~Lr~Ox$kcOUL{n7W&PHJl~Edt=+&7>E%$v8s2|QN0YMQ ztoioG^NSDrGhWY>k;hi=Ct;`Y;$bNjUV-w`%Ffdn^!Y6|niSRAb)V zAXEUSZL?}xy|n`ab?fH=#@4y2FJ>7r^d6NF`a6tm@CRmrFh4d@R<*6d`CaUD)aYl;vu}rH_?i5K?D{H_PZ`*aJUR+ z&Bv=W=!_dwO6x}-sJ|tf9Wfw;8ej^gKV)_%`sj`S*WqEUbwVoA>T+h5Z`&-SwC*Bs zq2u;{v&;# z{POCZ>$gY#!VffX-dZsigIDYiDuwD;CtTqmx$U$puRJYMVsllm+2-`Rg)ZlqKZn;~ z7yIW8El6TRNp75-B2i;Y~n3QMh~C&;~?X#bVS{kOrR299jvyRUg~>oF5z8Oj^b z2O4gGTmsI=BM+Zga*+A<&5Tz5!Ol@n%8B{m$)GfmX<73$uCLn#krK4mag}&!*dY+L zHC8Pr7V3ff_xQVS%Dz~m!zQ-?DvLQW{@753xZ&{ ztL~VMn9Oh#xi`;A@|3bk39OL0)7zX19(}2Kw;|WdV}h7h7AFKE7{NXU)Aia<$u@bu z@p7zTIx>lH3-R6pc zftfa507Y?N*-trDhE`XVeAyC7r2Mk+hso#RmMP7)l=x^hG0~!R)~+!q@I$8v2^wa_ z@u_}CTcbCPjf8S9*Ke}fxUCJ`FdgfYH#v)TWMpIrb9*ez>qKZc@)j>g$!^wJtw<1Q ze;Ui^(Yu`*Xi;;~@(Sun+;i$vwAzh-GEG@G1D-4~04f+@TORe|n`~R<8f;g-DvL(h zI*ncsxUnRU1&%q!VW=cxCXMyIFd-e)mL!xpoQehb(ed(~Y^~x`tir20(yAVRc zmK2kS{j@RL^rw#UMPK#3L{!SGSv4R{99%s-Z8{?5DP)FQAu5jo7NfPMAU;4!;Wx%EaEbFT zg+E?t|Cc0_i9N~_4Q%;luHgRPBm>23-)zPzsG!hal@%^Df-0iSF_@roJ8eRos#yhx z1tTFC{_ymzad~lFB&APV&$u`%uD2nc+?1aP?fO#&G4%(glO*a7QF>Iwbc0sh1S1O^ zZ4p{R$6n6p?U#pc0s-Gd$oluof9TP0jRDo=L+l-TK%K_T5X?*}jQpSDtli{CmzEHo z0qtbV_x@wI$h7MCuRHR;ajt7!$@rw%53{2pAXcUH_r0Xv&rlD{w&D`Elxddar>!{G zz{^rEIj@Myf!wI=BUrjw0Or?Oy9LI(o{l;s|DGIH&}uU#euilT4e2K;E9_t;7AIFg zo0fhl^qpp+%IVoz2A@;SqTPT~x-zS097>DAb-jrzp^We8$OSB!+a+HI*B3_d4|RH0 z*p1trFi?2_ZZX%>veS#q#shD4X3nOLOVuv6Ie(!ejEdE_kooFsTv9mqRo!_m6*lxL zorD3;ue+dS6}L$+?-W+u_f;Yy6Cg?%s{0kg8Y0M1y)6(CA6}UDqe277n%w{&0s&R5 z^^>I^kF*d>JjNiP)&PtRBXhawDsx**eQL_H>Y3v~xe*zR9-BxSr004+!x-YbR1g(C>8)JIcAwK9OxSz;jPR+6N?#GzyRp4VNuEq)Pg1{Q~b z3Xe9TqXr*s`LJ+QrfbTaS;=(Y#QewGTOrvst;7Toyh)acKu<59DFZkkqQ3B zca6BqA(-(-lU>Rm>)gn3LExDAa|xeZG37w4UbWXjP2Xpk41y*ys%m(KL z>&H+JXZj24W?ru4lLNuO6Cm!#Z%Yb(RCrVeZIMNx=N46a?Z^V_@jsEqU&H=p(=G>z zU3ooy*R>3&fLGVqZQ*0jY_7n%wa*~Ed04b}6qZ*p)IluyWo_8}l?H_I=KaplZ0uh| z7s!DrW|#`dFp%>&^{N#qdv5{_qQsZ2KFtHKDK6m#^5Js}I}qXa+v!uu87uvdA_$kU zcdSXY2xI8A6R0<{_ym;^;KMeaH52d%zBn2WlPSm$vaz{`^lo-{ ze>fHRG4tHZuA29CY0Q+s4%tB)%6OF&DEFB{(~ogJpj)+jTlcvgNL1J5fM`>-=9ze) zj7amE)|h}%q;x&kcl6hsLp^VMcnyvyb?2BCaNz$*o~_`%QmNOryy_`O_IsB+t_(V&S8ObdM#;se$)eR=mIJalwRven4 zItoRSW)kMjEn>ScDMOlP!eMCo!k9b~cnI$_AwFJD3$(W_W@aRrDD$Q+WX3xSg&iJT zVy5UZ`dO=vD#;ym+eNO)VR6CU!;T6C9MD%VlN?iq+QnBGC=O*b4u-g17JX8nR*EHx zux=yy!bnli-q+-q8!$g|J)$kT#Myh=B$)GWx|uL{dCKHlKjSfnv5(*D8z@9av98`U zp)bK)*kw{iqR7Wpc0Cii72Zw?saq~Li2mA(fp=5_EmZtvY0`=pp?xj?GKBLFLtp1R zKXVB&B#tnHzoX8H3>hYmi3u4Ft+O`Yc1CY$tNCraBx%*x=_3eWdaas3`r%zh_>0lR z{r;!We-Kr~u9L-QV=OqM;pF0^Rrn1APUzIXqQr>Los{y22|!FQ+hjsJ%?Jt{UKx*H zv>rov4Ds}F@>H@Q^q)kdZ3hAqRW{;8n~X0b4e4|!W_(=vk%RO1Le(N|JZx}L)hG#0 zf~8MJHIUh$<8kNtDO%({a%N;GvCvIN;8oRD^VMbwmON`sXvt4zn z@Q*s_s5!}K;?7RM)6j|s-bF^3Jk^h(eLnoHnwoGYPfH^Y zDjZwkcrYx8LWH%1OdF)8rz_7ixxVCUlrEk$kWMhhJrZ1bOO+OU7x7fLn}^B^bZA_) z<6+Zp!Iea>s`T`^vQfamaA{L|svL_`S?^O%9h5{8A~zp`OZH-DFl5yxF_rmdq6gh2 z64uI7D6p247s{UR=esk*WC-TrNIa`FYD>%RIv!5ms8 zQjVLpP2ts9vS!l5)AQOInddJ$C?Qo9mPfOpz*tD^$YRN9CHFU$>B9l_^ROLaO(P z@^!P(A1Ru*bqU|;mOC`Mym;U42p^M+zL)!1*0RKsvIXTVLUB;qQyA+s3s$QYYD4;0 zlRji&)}LgVvNxtQ&&rd%VRrs&uuSo5d=$;p8gG7*OJUDA&=?;IXgJ3b9Ish#Hq0Jo zJ)!K=U20MjhMTOi6@Rl{fmf<=dO)VZN%XxO2IxGAr)Tv5Pe~=Q#JPiQZ!IA66-u15 zf|V+?v?`xes4tLgFcqW86FeCMu&Im~wlYtBwEo&?s_4QvKPEQlwqOFWyjmX+9}sPA zOP9Ffv{UFbc1nKOOt|)F{nUA!DlI$Xp@BB?_BQtcG=fitq+^ujGz^{zcNM)cS+;2k zyV;-Z3AJFgXwm7z#4UpBO4C}K;CUis;AGL_+!|(iEk@22+R`tkWhu9^+hwd2U9(d6 zI0Z{$N%#T2=T%*T@Opej@%?+{AW^IqNPnU#87B;){L2h&_MT5J&jpd7`%M-#J)y7z zgoI~{P=afav^k@fnzY285dCa_&=g2<1oIgDOp@2LUmu0UE1)u18m{2%2?wN*pjCt- z)d*Z-I!Z@KjatrrdzZVFF57P%=v?3ibkFDNL{&ZPSWe^^^1P?YiMmvUcR?b`wtQ=3t(PMr2(UzN~m*;Sacy%gf77B$XAca+e6CTIL6H zfph9c=03zQD4Y+>%?&LigSjUs8T7Jtg=pSnqfUa(nQtGLIOC(oA`%?sh&wZiChVwR zCAjbQL8mZ0!0HYzTQ=t=L4)@zd*5?`nzDYB0v`aYHD&@LgDuf8foa7N^TuT1o$@xIcXxQ2hq*5quRtw0>b8^I9aByorOP4fp;@J7Z9id`3-h_ zRaD3x-pO&kr7nd;=X|H@i#Jm#)40Vi(%y@{hO(R|IsGADN7c-flm^D?M9X68&SVu} zuSeo+qTKEJyZ!5o-pah%k>kNVu||wiB*1MqD*hVl=*aZJ z`DPWkrKM7$JgF37YM;O%I`h!Ur@&Qp8?!Xs#G57rnD7Y3@abyWG>44F5s0KYV154QVa)tyALg?J^Ksl2bSALG;UkO_oB%(X{i3y+t zAKtH_98-QaWc-#e4%8vx1QsZ-?Y+$)54LZdStYV3yBt|Jcx8`3K+H@)EsHsKlk~~M zu3{Z79)st$yZm9V3!7fFFhsf}_zN|cc-;DElk|8V#r<0eze{RcoWZKB2#=4rJgn)R zSUi18_a(e(t^K%+GGJ1SI6gJ$U&VuStzL$mP zpAz8LZBj@!?vx7xnXTVMeI!y+(E^n{&XMf+I8HbW>G6^qbzme*_e8yO1l>mPuR6g# zCS@A`ld^VGR5nMq7ZH{Z`@zRt0$ppk~hFfaeQ;99BglQZ8F#%tw?F%EwZeDm{%p@H_Pn}7w{DC^*T ziVb6gQUvaTATUzKlPJT+>%?Em`30H%s9$TMkMX6EOHk7UPE+ZDXjR(f>rso z*n{j%WE3}9qq9juU5DU$$F^51MInWH(q@RmeXLO*x4z2%CgU#j@?W1$7IC0>?EwJJ z9Y207lU#5jUW7pn|F+9oRYSl2#7Hkpf>UbOU5y3duk7n%ge1bwY3c$sS3d~=Wed3pt+M*kDuLo}!xPVRYV6m8>- zXo&1lR>ad*HjtLdMu#oz(@S{8-#^)10Avh+enAAaazI?f)YKRe;mZeHnDx_Fb@s6oKos+*elCY1(E^#i8tv8q2gk&>WUNQcC35zEV`0(=Bd>I=$N%_J4 zw^gQ3K1?@TlmUlv7T4@A)qrPnn%R;Z|KK-xr2Oh3^C(2q`K^5tvdQwcw*u<(sROZj zkw16}AIwMvBJ$PsdNa&uqZ!d$a5tgwduM`5Uyy#hffBhSj&Gtn+J*FyGD8;CYNhAX zQduN4lUJH{JRD2XIUf;610hoRh##RH~gMvgj|?^XH46@^-VuM_ysxMCXuP^cnucPeK6+jK4tbj`NE}r@8xb-q_b$StMT) zfTFagUQQJD#*6t^`foE$u=9aUVxZ2?SiDqwvnJzHWUIhZ9P4}~L*->H2PMYIwLL`o zGGa)5RY4y40t1CHjzkgsw7FPoDUdNYu$x-fTMeOL{JqF*cPkiMtoMP{OZ~m;PPhRy zlnjGny4I(9prLLEe#&+VEkZ9I$S#zyl+#~sdB^W;$;b7!=v2!B9LCF$SLhf$h~?=v z9)ld*INWOJSHq{4Mb}Ib@i7;OkuZ&fQ(Rgs%{FG%8<>5vP-KGn z9e_`(jdihh-+L+eH(t!#scjM%pDS%3jc}D&7Bhce64MYI;$a6t70{t((Eb)JMr1Vl zPkI>B6H719@udyNxVd3l^Kvpb|MJB=>`odv3`^Yto&UFDyrX(YQ(`WD3r8kiUV^i^ zd2#DZyT@5OfI>|Kom%nQFXp=0FJ&$Iq?__1*A)Ow^iPw33Vzowi*z=)LF!YOa=il9 zEBmVYo4c>EmLT_7ONHA%$rN_TB!5hz2w&4$;GfK5jWDO{w-uX%&)p0*>0GRw_5pKG zh5wol@-&FzRBo|ABY=TtQSEe7X3+W=_t`+FRDGZ7=>rGYTRSW1(CG^&Ae0KhBI8N# zJ*nr9>dlSTk4^n!_}kxl1Wsj35|ggb*%(vN(!|;#0N(-#he4mS zd=-ZfZP<3n0smcBO#J6#_M`?8o|RmSi=rNO>Db*e;x2a7@2|-M2}l-nTc!C4Me`&R zVWo<{Gs_g+7B*rkhWx8&Y~m=O3#PmG0SX zCy1an%7)+p`=%QNVfqo5+qZPM^vi4Y0Q&*QGjuaf^Mr@KGl%O#lM&S=+sK>3d+)Kca?RANwyq zX(JB#lmF~-2?eXoX5=AlpO&jNY^LiEYhTr2`qC0^} ztSr^}B=`t&)pyNn4n?`&o+jGJBT6R&A2n=!WcSFL%)crwCJA~v zr+|G9v?pDl_70k&Ut7^L)Yfm_>-j5pTe^?uOWJ;s5Ye%v#ml8gu*%VZ0s$2f#4Gbz zPba*sq9H7RtlJid4ls4IIVm5aUVR`my4Hs8p^a}U1Z5q9SN_rtu-5}H4uB53C+BUX ziL3VU)90s&@+#w21;b#va!wf+_AsyimuK`+s*m8Np#X|CPvR$ zhepNp1p;(LAPe5O-R4Mf=@W|zkbAhe2RgK=4}3!!^6A|6@sBCa9D|B^NxxhU)2o3Z zbC;HN1c*i6t*;c@>3yq-QP)FP%SN^*=YRbH7AJ+@7w8)NV~!-R?g9P6rz!ZYZh&ea zOYsou%=<8}mH-H7g)@Cbh{W2viX-m+c3P)g?Ck+&IQVcBrd}<2G=8xXi}66#=$@2- z3*K4#kiT#vDn_#byelbPX4F?DfqRYNW%xYE_Vxw?sKa{t0H)Kx8Q`2l`HQ2YvFpwm zX28Ps8TiY>`ts9Aa_7p~^?BKekwj&kJ=bzfy%O9BT5p2!?;>Z{l`J3aG97F1u_Cp( zsU4w;vidYUsmHXw31z-q!R!|ktxQRfH-o-(#OsI3MS4X{pEnOh{OMpOX%lDYoZjj} zT7cViw=m+#GUA|A4>nxHh}Zy!6Aj_C(Oc!l|M3FUuuuVRrw^WN#V_=6_mR%(5=w&} zqJJ`nqg3Y;?qBnUi&Gr?AV#cEnwO{0{Tzh`R{UZ=VD8^uymvI|6HSKaw97oKX9i!@w+m7uE@wRK6{Js_@zr-c%+meQ!+PCVa zN5X58a_}ky7q|g~Dhb>sqO!7k)Th?8I<&)oT4i&dgeI7&q18)7q>?1RS0*peoD(>KlKEXWrnrHTL~cOnr8 zF`1eLA1WI3pkyb@Fqo4Jj*hODRtoczpiiXpyX;&z;7S@#F@4G%cyU5omgUINq-=i^ z<~uJ&SU~Rts5Y@Fm0XGPw=l*;#RScgYQ z6$?7~@WGwGheG|c(W^6K8mGOcH0_O`Wlal81cfGR*gNCiL0pTk_;~NXJT8~SR&5Z6 z@N{t49)YfOC+!vm5A#`|D-ThEpiy3v=COoR6-6^pCPzz< z;lv(w1}2H3THInI>6wVBPV3YrbV%Vh*&vyUEJGm0FBV#rEPHD(sax*>O^{9SV%6M1 zD~1~@KR2ua(QGa?TMwcy{v1J33N_rR;IXjW z@^Fg!<|it2p@Lz3b@Q4H&u_jY&Vr+uxgVTxiAim2^ttpphKB9;GsDV)D@#kjhRC2@ z+aJejVf%Plp!Cv2$bI-HPI+i0Bi zIl`Z2EOvfLGBF zLH^By4aNM2PdLA`waVvCciP+ApX%#pBgb**6dW+_1Arf&jgUASo+-YRFb-+;H-qP7 z!7j@uH`C6IzpOFupMbXK^y~yyG}joT&A(=f3E4A!!l3+))L(pCURmi@ez#o@RFhXI z)`|}d(KSM~*5EKuUL|VVfaLp7k-@i`ImLX9rqdi%-42%N2f3>p9R}Ug+(%46gMZ}f- zKrnp!Lny2@Rw-u%WSu$V=nLblCzl~!frhx742jW}orVX-a9D)wF%q8F>8o0-x8BE7 zbWKB>$rWheKOlX-sBM1W)qIBng_MbjN?W?=rxkAw6Br8D1$=)QC!^&G4_C#iN5IX4 z0|T4g#+CDD*Z1IKv{jqZd%VF&untY&zMBA`LoJ^~N#*wT29%d`1sHTrSxI1%w!q}V zP9~X2RsN~X|1|!a4fE$G-XMM$a`6pL*kR{rxR5JN+ZmWs0>Zr4k{*XYs$VfFj09cm zmB85a2>{aDCW$17PlLUS&M?Eh$v@Yx-{Ggn^NFXY?r zLzEXN@Tdw*b?G(du$c)LppJVVYtR~MyD3H7`J_k|{k+DMa~;t}y%eX;E;-4A z;p5ry!;L=>v2$wR#9B#>d+@z?ztL;`b?Vk?dvs)bR9dP6bmIn<>jKAe48Q!0Zi;AL zgpaE8>!8H|bIPh)>8f?3&PNJ~%K6s4o}k{|-fxvZN<|X~C)55mGviR{PrEYGZK* z2>*&D(0subeDp}Cnx=_WjZ?|8uBuAs#@RuzFP7!XgHys8UIwjz=n4JT^YQk-fsagE z>90Q^+zs_8sy}C?)P2j6Wn>Y{qC*8M?>ZZysRsM{sbxkMml`tZrBp&&s3ovUZ8FRJ z7`$>!(V+w+*Jq>2x5s)*4s|*JE|43QlLL&5k@ZvTWEj9YP+)I5dT{TQRUiVPxuN9n z4&d3;8Mnxtwc<$|*C?F|1^&foa=pXV+;Z>2ianGF9jdC(T6z$=ZgnoebPYe{Xy*FD zXepjk-gvT~blPct#=O*Pux}#>Ea_2IT;=*fKz^0GWFFO@TD`{7=lu33mBrt^u&w?i z1SlE);wBU>u6Sv@VE*t|_VTc2)+bPK7S@Ui61xpvarr>R*1Na4C%45g$LCA&u*F%^ zFn;|gMcA4Az2x@?KZPL|+O12tkUFTbcuNcgkcAVy3o`X0bn#$Xg!)xs?gjxqfibhG z2DAMRbs69x`!FJRYuMs?pn@w|u3-zbCtu8)TW9>Z=kTI`0~gT}p$`VsQb)YNl8Yiy z47_0HEL!oVMHXQf8|yuNdl`8WKtv1)=q8UcjR7VPa~JDU%}6LU_roV=#I}@wHCs%- z+@V})^ts~|P#1YMjQbY84awnWZ~fJnf&A(fOWpr-QUM3^AGJbWEUD@_;-I+^8)`MQCxg!QBg2-LIINs0 z8@Hu$jZy&R6GvL)E=J_ghf`AINKx5v6G5>PMM~vrjqn-s9p8HPe(Mw=K=XX+wqj3E zp$$UCiVeNG!AUmhc1KvXofhifhT85REt(pp{GEoZiZ65%(YmDvf`KuRs`nr*ev`uR zf2O=YuQs%QX`Vajm!w!;DGRCLDuWe3Xn?W>xvOVW(ePM1wh(0@#_RoGvRxd-KiN)3 zYkdrXGef3;go_2ZPuDC(mL8{AbH~eFNi=qU*6fnL*!Kq+M1@>j zG!?pjg$hWrvqbg20#XRYaE)k%dB75TraDZSC?RTKJUdD;Xo3{2cHy7MK17xInEmEF z`hA1Bee}JXOn>OX0)BXcZ^u~K)DC2*D1CDp#Z-WpWZEC(g}df!+80aOG)Q8OVpz#n zX3r*Hdu74nIXOH1L)uRCHa_Rp?OVEOfviWz zND}Y2+7Ad#Ow^hk?CcGR&C;fTwRsC+LsYA2Y}O)J8%j@`FPPtCI}&=9nxkS0>~R-% z$jQK97v{MG#>^1@NC?n1DqP_|jgX7s^kt!9PqP5~m|q(w2q+!B!%{2s5 z-Gjs(+hSkt7YN1dx<^|g3m!?MNfe5I8=;jPX>@Y4gXgrKA$4!w{*jo9PY?2vU~vY) zXP(6UM0$>!aAQWeAW^aRr-0FoFN&2Jc|U-nn?eW=FNt+OX}5(^!iW4D(`@*~<6V07eu&C9?8Lr8sfu zi{JKN6XOXws?#jOWW?;r59}e6ea1A(6m)TnV@D08zhnay(D=G`gv&(s!YJjIax$vx zBI{-^^Z7nGXV(^~Xi@Oj99OkapIhsN33w*D@_pE8W!eEwHC~Yy?WF-LGCxhlWX0S0 z(+ieN`4kpQOlzJ?nX0_e!eY!3Vp|I|?W1Z5^9$f`bIt!jdSzoDnpeq6?J)Hf5Y57< zKO|rbf%c0TAkT2pQq;~|!EiKBXVjicQWbW%Je7eSN?Gz05W~-#)g=_X$&cv)Bheyc zrjoKe+aoc}Wn>4BDO918FJmn{J84;&?qZ|K@h=D&6Zf8d8Zg)@Mi_xmYIO!Ji*Z#? zQ*$-9eeHM&-vKL$Wy+(L6KydY@+ zZb<+HLb6*cu46PD!;2{U@`;;mZSbvi&-9N9S3=?G7Y=##P|g=hW1Suk5`3&3Eti(k ziJrTCNkc_E3kSaDb&IIci;eGr*!jWgW>T#^hw`jG^rY>-lVc$z)tm|q?_%gx6ahX# zv0jSB=r7LlnV)X3>axj^)mKsIvX>1>_DKciYV)EQ$zkpt(NVS%Sso*BICRn9ZliYHx}LIt+ykbUJ$?Pe?`L7eSx zoASR;>LaD}3Dw?YZQ-1X_tZ{5&A$nr^-pbdsDM%9T$rx`IP(RBtA)N8OZ`z)07r^cQEob z=Cd*dku)0WED;H+n62(IU&qhL+Vn>}tD`tw<*8CvCJw@9CEO@)u4~^htOMwR_@lTY zivJlC`5zsW=pP+)@dsT0kB=^C8rh_xE1CZc>f>2h{HK;^A`!lJ5FvZ&K96ID9w2w9 zENUq}G31^YPXd$aT;lE~aI;JD<++xkF&L^)8V-1{xCvwb245uOZF-B+wtOZtJiB5h zKOZ;+UOFLjk`zkRSBb7uUCpz%j!op~1D_$WnxFr33k*u4BwVNbeypYn3rjoZL3yw- zBjV?Y2J}ByTQRD?P3*z6%Xu{2vBl(6fnn`O!*x!2Q^tKPcu(q+hb-sQGHre*^D?Lg|5inwXRE3vT=q093OqOX zPJPSNx&ZG!QNhni0rW$vvcv{#afRZud&d`#%Cu$X6=2pZ?XT-u!eaw1J&7U*)w8^v z|60+GLXXLbyMTMJ6TY4rrSt~_Zx+>GB+g{CSh7;=Pqb<3Z+g1u018vHZxguFN{aGy zs!1QTeu)1YOF{S+?y_8Cfh7aR){@Hkf1mS3ytwDmf4o>wd9%1-w4osJ?^t0XT0$1% zA(bEp>#cXh*V?gxV_zx$37`$|ihg5D)5 z|BP>X^O13BT3AV{p>~OvV7bNQ{|J{Ila!WX-ryZ%(=Vo4HpEPEJapa6IYNskRBnVp z6?~rkBor}(ltNvu&iWu82{Z7dNX-A51pW(-+Mz#c1;<}*{=4ztfhoG(pX06)@~U}Q3QjZhIKBb3 z$lRM*o>@&`2*#t|gb22Bnv>tNUmlU^C-pUrAJC!evurM|K-dKqrFPdWzB0CWE?`LHm4=VA-B%iRlByWI9&@jZd-UeKkwprl`AN>toG>R<(rx+) zmzF{fffR+UgV%CcK7ub{5ZC0za!9^sIUR81AoC?1Cg07_(ELA?y>(Po?YB0(2?dl6 z=>`Gm1_d@C-QC^Y-6-9i0@4lA-CfesE!`cP_!iIaIcI$5jXz$7!!aBp?zQfDU-O#t zn(@l*ikT6(l{HC}3s9q&CD@_{<;A4LHHdloFb@BQCn0=t%dfAv2opgG1L}c*D@jNi zr>>AAjksU@XPZ9(9E+T)r-5>7v?mp)FYu%wzuMs`Y+ zUkg20-#ei@P-cC>F{uJ1;~J8`NZf%`E*GZ$4qLcWF+m;%pHo?| zi8zCZjYdx8t8VDHYQE&-_KOoT(^*p|ox}1(-C~9qsrM~NQZ$xqHoEK;j^uG{_7Ihb%t}B{6i;)d;LBoyatL~c!7Yi zb?4)Ta%oB&LLPqPfJHu*vzrEu1Qd5z?+>YcVxh-&oEgN5N)`PStuNpqoabu#CE^Wt zk6H?JSAm7(Pcl_=_neCfEW4|)RHQ+~SR%d8O$=Tci#_3p2oG=yud`fU>*l1%Y4Rms zdwX#+huIp;u@<3vkB9!LowJKh`YAByX^PQ;EWU5 zS%b>1)pA%~U4E)1;PQKBqRy9X2K*9wd2@Ka#W#*K=Mg$J@#_;*>0$4^aw^x8GsGrn zCy)8Kaw5loB13|tPwG;coui)u>{`P)WhWw~ZYdX9csxn2z%~Fzj3WPI@Brz{|DOg= zX?tKioM-j)UFd#ri1T$S#y^dfQ8Z0KKy7c>%y(WNO+MND;h$o)N}g|7hEZ%%b|NF< z2+^yJ+_lVWFN_}~kz@T)8v8BYPy{HmQQFaA`KpIv?pxN(zhN1bDq;*ugthos*uZwO zDSqr;IFJT?(uj33X<@;>hLNI9UiZ>WCbZ2PBri!x#k&uTUP~o@f7TYClJQl-+gNjR zCin7V#Sanw_yAY)dZ$@s9HQpmOgKJ)G28`i-}sze5tX-d?QoUr854$4;(Zw(-A6iE zo~l2-b5pHemq=vlD`w8S;0Jem@3*m6^Nm zS8((~cu5Jh7@q6Of((l>zRxYWpDkJs9R-jr#sM+Gg}Nnupq-8}G8)G5FEdR=ERF~V zb=DYcl>H>_q8E5sO;9K?hlWqBA0rQ!&qg5+R|tj&i!P#LG%Ehhj`(=#bI+&XOUg_P0bY6f#+wm^=9<^cJvwFmdyz)R${ktfokI0 z+iQ2)+Lbh^0aI~FL7;DK7)HNWpvO^$lzWxtYe9f1?4-AgS8~r=*)f0i*ruIM1zn3T z>e@<{^&6}~sg8G8g0Iva$=xBd*lDV?)ltv?#5^ILnSy$M?>;~hZwtCiA3DaEW(Vp^ zfT>VrgaFzi+Itt<`d!CBO#e8QTw!E&IG|Z!_t!f2uav-o{yBs?3ljG_ro-dzztQ}T z@`lj+Pl*<*w2^HW*HWZ`6`lsxGtdjXWBB)r_L36e7q@9dUu zh{f1%@@9N7`9)<}-Co;V=|DWtuXSE-S_4yAf5lhNWLtXd;eOnNiw}ofN#SPpV+qvc zTOcN-{miDqP@SrCj|`+_5P=6^+~JXSWlVfPEu9$vBjtk{S^1Fca@VGB?NPa_*j$( zG_AfYoLMu`rI|KYVe`g8sf2NlVv@dIpC$nQ81vzGA`W@w(%G`6{yy1dV=DRzRCm5T zIk~Olkm+UCv5e707!1q2;DT)fcUHi-m|^8FTT4eW+?}Exa)6+a&VBc;@TYGw8Y*~z zn`xx|^ys&JrDHB8DXuSm1~jz;eXEkqWCD3~a_#h%Ieyqim0e6VqLDlqi*j@=E)l6* zAPJMW3NS=8?cN-rhpYI@*iPkQJ?|9h$THy(Y^Ls8j#b9|6Hgsw_85pV#z{iLP?LHY_xUo`vwgTsR^3y4JFnFln}uSI+J)Ww8QWCPfpW- zaLqcZ^{TN*9j`<6^9Pm=svc4T6X+>j;KxIBHee_t$djld&Bav3(5TJXHU7ppuM<;5 zi_YM)oJ9&Eeql1nL_07yTa{5lJ2R~iizWqPuBN^)u()?9{Zs0vYU*l@?wb8588vk1 zsd&~NW`wt|@~f2nzfPbrDjz%)-#U=&61;`Xb&MUKfVQ8?!V^jR%|!BXu_NyPa3cy$ zLq9pR9llfI`$dtdi0zOygo}K-_d{}&SvVsnz85O~eUv7%C@k%}?en+ptjd}1JAsx& zM*q^9wz1argIgHZmM}l&l}zf@zpfjvg}hKe3<9X!mSqy&Q)&UpaXo5w9cJR0y}Vy~ zF;vLl_i7eemH+GWBNh=b&yAn;k)RL=;fc2gnJxj{nQ`WM#2ThRnW1RI2h+kyn1P)G{&e;Z=QR0{Vq*q_)e zm3-{)<3Iz_N76RdGvnU`+^xHG3(*kBLo3#zjWkkCTvEWNZ+p(BkdW^|T2M*f;=;~A zWXNX-DHH}!+`Hmf&F24{LdC{Ek)VI&!$>aBh(WrG@E^b)kUI|97B|G3!cu^h(1`rN zZA5qnH?)Oz9fatWi`s)6!5v0H#S`5>B^C|Ceh?Oo<_P<1Q&vIOK+?A$j4rG!>CCD* z7b7Xa@9OWUoz%B3z}yiP35fjrnCc99Dh&5!FDOpW^H(++VPqhE6vjdx1&Fd+VLunp zJ8mi|cJ^9LYoq@Vw*7GOTG(W~4zy7*JKC{JWK5DnpejCgv2q45NP zCUn%*8FWda`=KW?$0BJxY;95WV!U+J7g7w;!+v#iN=Td!R~6O7ht(^f9qLZBI-bV|nutXIyo^Vf%fiXDjx_hQ2M^XERP&zAbgxwwvZd zU|4JGVMYhbICI(4QwH&47q+#P)jPDO9_*J5!;VX|D1AcCyc=d7lElO2dno~ zD^v6DChAjXHhLY1Ih}6dll#3tNN!!u3*sx>n^vy$BMfwT|;=b@e8F^>KRK=f*KFA(=t@Asf5xj`4ZZ7c)v9=>Z0GKe={a z?t61LAR4)69}Oum1w&fKe=L+35hRf{i300veSA6ZP0Zb4zyb8oP*8gm9@n%l8``p- zi_^gPxx#5)*OQ}`)qC1$b3J_>F9^z-)AaYi5I$h%sLzorAIsqm6Dx%(iq7#HnMI=g z81yHkhvZb8*h(qfdAAMC%oAgg3+K62n zJ%2%Xf5YXgMdOS&PzCEZT`0R|*MpQhx#y4Kwf<%GT$0gyUlLR+pq8GV&be&&J)wH( zxPHmnuhA~@scUu4d&Q9Geo#~-5*|c!a~2HVKv;Y9M|u3rp9n<$ zzw$~fw6XFs8oaF~`)Ar+l?&@XQjf6(KTNBqH>x%a zF%^c##>Q0J4rYlT%25g&j{~jVKp^pcs)aRwfWZ&64NK)+Af2;s*ljm;l}ApWU6;@6 zYcyYKTU#d&fu`mnH1>3Q(w}pONWpMJA0;L6<%MctMHiY^u0;&vFoFHvpkMX%^;K1? zhu3k0``5_$^0~7%!t$^V4m5rCUT$vc)|MSsTm;CXJ!l|`B?%gok2MjT$*L+tyo88v zzdx_$1xB@jKr|a5!cG;>{8 ztQ`8jD>I+Gy{RZ7bsjTmnBHH{w+BW&eb0My?1E363XFCpK#Uj8kP(%@L54f0ehXEu zq6svE@^Il0&#PEA&05Gq_|)M*Nl6mYmHl*YRWOIQkSGoe%Qy@SbUpJj65dw7}+)~x%>j_1P;Sik)IYwECnoB|Q(2cNez zOAwWJ$v%oG6HiET(r0;0gp`1x_G`_T>qt&MJzzF<&C6vaA7tSL3bc}cO>xCafDCCn z7t+Z64&(Q>bI;fJkrR9o8@;@=w+J-xw>Hta$9Whfxy_do?j%6 z_&x)g^ZmFlGAOBh|KRqv9%>yy)@^Ex6P&lC{n^vy(2y9i_Y)=Kw?^)yT(GaLEwGS%FwwNbV&R- zo^{bXn^@<0(zM${{5-aC_G?;Qd^lq3ZvAKSBLN6?0Dw7)!d^4B&pgWmjPWA!xoc~( zrF&H2?U!G&oR90~v|HUygZZwyx;i5=j!#daBZ!{QD!m`Ki05n?UOK?{@h#5>j6;q= z+$v(nhHm_ySlPFm(_^>iKgcxaS7H6MW-aas-R85|lObkMmJFbb90zVR(`Yx4jx!M$ zBq-fX4kYe-kLY>MR$zvrq};()g-M;4DE4oxQZh+dS}nH$WCP~ak$0H}5;pASE$Tel zR)G_Y06$I3zWlNE>AXCJDS)X=>v)Qd_Sxd(D_A-fk!K@7)`ehzpI2|&cawe2v2%)Q zYHN+Gum_4mHFVXEyHiM}_czG-YGwzd$Omy6<8uqS>#3#R(+0erB)_t-kO zij^*X=Y z7A@9o*Vk=#{P7C^WqN?`IYks)Fnt^$lFQk8j&$m=+v4*uW(&d@_!abBzoP^4#OSsW z{Wus6n0oW91t6*WbiBM`dX~@S`12&OkAu6r;)=lSZ9~U7KJiNsXZv&gQakXS?0A!U zOkOL8y0<>??KxJGo_-cc*{roz2(xEW7 z?K?McL!MT~9~ZK8U00mTRcJ#upXNt&pR0W@Z5ec0@A7QjhZ9$hxlUj@TYRtEWPL8; zfiB|swG-z`-<4pW!>_h(J%=8=YU&GIT#Xk~$?Zp2m0sI+T+0g!?yI*xr@BwGrt$X> z6cktBRMsATocjE>oF(|c(|J-UpFS4*7HbPxA`6-pqK=> z_Le%3G}qQG!c*_@7G*?BUtc)T>gDP!?>5a#^{j=kypx-o+nnyoHDC_H!<+GC%;CZn zM6HYM>9s&WO!)eON86~vGPEUM!rZwQ9Gj1GBKpKG|&&bPSctQH# zxp{sb59O`A@yyj4&ZP-6akgBAd118_jg)c@7m+}2d;oL4n1-NeAC2gKjNk=@=b(fm zBFp@DG^>qH?&RGT_<1Ycrg^^$#pkTQzn@m;e0c3)421%UB<|_y`1J0#Y5O+4ZPR%_ zesGUIx>~Y=jg{51{QzOK&sA>LZQI)PDd(cKflp~Xm8_2A7(2-Bd{Y<{lCzg)S+VcZ zqA;x5@i3tCxQXrBvceS=ZyrN*D;@3m0$F?chW)ti3$b;D?!3&r^|o!=iUM3GS5z)F zx?r!p*TGCNir3i__#Oj%Khp7t44PkFZhd|@g!?XV!Jtnt08l9y5YS&cTc-@#yM6$j zpL%cJW?kh`Q65rMwnB9lE2_S%y=-sUdTgbyKHoG@lGXs#ds?2ybs)PX>xQQ}@ZAhX z=GoYj4|qWx^=y&Y_gEUGeIL&E45BeMrZ(*3dz*3UG47ao`9q`z7;dotYhilr>Mq*r zFL|ZMEbZ!L>8Xa!suc3NV;1C*v+aItPRsK%QQrY5ldI}JyyGs4iU*)_w~xCFjJ7AI zw%{FLb@6TG^MQ543I_r5EJGHL`^A9o=D_R9Z|sh{z%dhy4uRC8LH0Q<$A_!^zt{;1 zI^Nf_@|f&+k&|-$_Ah^yh|U2|bG4IB%z_s=;};eg8JYE1ob|X^`LsxU*N%OpweZ#t z=oGcAY;$44ar&HLQW|Ree29NIr{j4H*e(|r$Zu8u^gvNn7kCSR;Q~z4*X#C{=N1a3 zQJ;(8>vPKw-yrIJ%}H9Z3c7JxZwkKXOafSL(>6wH@C-to9oN$el#pLSZcp zZzEfeV-vNJm7Ixs6`-Oh6f*Dyzqaft1wZqUY;yS=YOZ;>xpCn|65Rl!3dTKs+oDbE zyN`~Kp*sm(m+gCyI04qf6*Zm(?x?GCzP~UAg>2oak9+*lJaJpn`z4#Hq0m3nd$v`@ zfxgK_6e$7#a_iI0(iYe1=Njjo(bS9#LeSnV1jXa*yU&#|qjbIZMz~IGRTVQ{B*PEz z%X#$63Eb*SS9v)-NKIYceauofzO1IL&HLtPAsn0WV|FTa7(my4XMAxzS#DaPZ2>V6 zoOIlefg!Kdl?g|TW;~M@k_r%HN!^F3lamuOwgZ=zN}n;HR7oO6p}%Kiy;%0CgXrbX z7O0(dygB;QRAUN|d@&kO`;#vCsnpi<@ALD`M%Qn~$8JX6UGDKHGAMuF=y)r(zx&Q?dhp4@T;;c(`RYC?RciRbW^_7)A;ti?p=2w_-X%gcbv+< z=`}9Xxh|Qbh!1Z&6J~6_{-X&@SxBT+J$cLpd#!n{xz1_3QnuW*?t)Ksy$`3)33Qlz zR07^(Gb}rf^B$xF51t7;Z+GDPr!Ej^^#%Xs9I)6p*c1k>#$UiG>`zhBY;SCAOh3;~ z``l-AATmLxNS$Rp8ZAZ_edx1yNI=IGoR zI5S{`6KD|pm@B*DaajJniyywKrltn?(ZFjzK0em8Y1#&`Cv@aV6KXWJ|3Aqz-pSH4 zJ=Eg`Cs8Uo1oizP^&G40)k#3iLF~Z<3KjqrJ#)a>H;zg?xKQ1_m;#hXL#`?!lZta> zB9s>NjxbCrh?GgxR4NiJxVr$g3TWVNb48CS;;>Co%X%t^o1a; zovDHDssP|6y6S{$y)L(vTxGVZTWnbNn*M6zF%gN<_`K`;jQu4;8RYiImA7=k3fNXL z4uop2-+|G7pXEKKy7th1+l~#4#u^zJvGtmkg+Wxtk7qn>KCFNP@AU_-Uc>;Wun&0A z4mP|n@z@Sq1n z`dqGc`d0fKu#UpQ$U@%1OH`thIEe`g`dP)5EB-!>UdR}gSz2HdktUx2c^g)zR{2e~t?wN(=50F!Asf^Ft zJL$FrpN%E}`&O;cYH~SluC0wKxg1n0NBA0y*t`*xE`)+6xOcysHGa5geD-r%&}vLk z_Nk@O({<9b&T65$wL&}W-DPFtW=UKe(1T+~!0CLD5LKKZrOh@OvSn;wut}BW6_=H) zsiYJ$S0^bx#9>dWFC+7NG<6QT^SEJ++h`CqYRfEbwZr#?zF}EGDMeQ;=C%_CMM*^^ zY+(StkS?rBYwc?uH?E1#ri6C+B6KW1ir7dJ$lHCBnfv5$>_{So$!%s=Y&A zo$92Ih!{(GpGTEaqf%gIf(F@>swA}k1bPfw+JuamM41GuM4#w|EPIdI->n=85oy>V zO3+~8IvKP2JA}72?wfw}>fC6!&(U&sMEnFJSmF^N;zZDA0Z*3~hhcyS`%zH)&Pe zuBO8vfmx8aGKOH_kYPb#IUKf&PJLL(P<|_!je1?2j2%}wYo`M^g@uLVnNPY+DAXU> zq#5s?A-h>GC_P*RQF#DsZoN4;MC^h8M#8XJT3mb$fq^H@+%+BZIJ)_AGCF+FY|vND zS|~#Vwi(5Z@2}Ku`LiuizoZQ!IrF+J>IOqpf?PsymsiBiUmoVl@NHYocSa8fWK+o4 z*PkJ$D-E__!H|M|;L-{?BMHvV&fczgGJ@uh#SKJ{7wa^&l2zqmP(ZGaTNS;%LX)b_ za~ZDQXU_yJyrKF(#`!L1;E26`IUoMHKAZ#gy?}6-4Qd-bqIU1+bbYtV8+5{Fdae(b z22O9^e~Zb=@_q4cfabTh<`pItK>aA4b~n)zjf~3z4f>tVXZ_eXJrF^3zWSqKws^QV zKuZAySGm=^(L^8^7y`-4Cfl$6dxV{iNrFsQ=Xg*(>3b`wRF9S_|W(t0?%EvK#Q zhq}>{v)CE(Q`rpJEW0LaEPuxRG@eZw zqnCNZ>GYGjj}jS#cT?YPPsC1Nh?~Wb6Ei7lPe$o)SN)YhEx_elld*mC)FY4VbdSzx z!x)#6M7yFF{e*3rQJRpJMx4+m1P=v^$|k&PiZIGC)MSKNLALG>6!mX6ly>v6b+7Kd zc*e0YF&vs~ZU*@4 zC(%*w3cGLfRxar)BJ!BR@?CO!zQpaEyDJUQJ}*5etDL9tb2?<73 zUg={DYlNhj@UT9RW9)SL*aDh#dNdF;l(4qPB7S_TOT33T4?bGl$h)BTevZBGf;W15vZPt$!HX6UE_^M)_D zprprEE>w60%*3Q5mvP=(uk-EQmfIu9(Ium8(>C(f8m&8Zd`hIGl=w%HDj;+;zBB>Z zH7&DAPu3o%+qRb!6`@XB<>%)MU(6?3qw0?X!{n!Ma<%H4u#f_W=r|;gd$cT2d8dbybGn>(Eo2k89wP z(7OG0I#`->X>`$Fx;2_q(y3ltFRv6iatYSwg8+S0XDrrd;=u&HmVDd_i(vBo{A3**Hn%g%WG(b} zfeamw7fp`4pT7NCwsBQZh$DfA&(_Xw$-A}Y@MKbBbf?uqsBp8~Z7ixihw>$P{50h! z$3?@*sR46VXv>h5r{o@cNwkuQ3?keF$hz3TM+|(Cevjx=5{q} zy3NxyAm;C07f!GsY1Pxgr0@|eb3$lN%oVcG595r_&gdDsnRo!>^Q0LjJEld6yYR4_ zQkd3aNZu139vYIrv+O;(R(WsjIuEs8T$o8+S@gqwrH-7xONaM$UkcFdw~U#H_R1HT#IHa$=*5P&nzF$Weg9*huA~YSl-Mzv6Z4$esCA^b`%%% z6gYWfg9uLwIw+y7++XYP6%c@uR!r7%sM@oLtv`3;sjI6C4GqQF>dt}Qf6`+Db%tn? z1+?lM6P)$Wib_UGpS0~VfKvFLzVUfKL=dqyn~rA!h5n>$UcDilYaY7=_?0MMemO1I z`uKuCe2;5zfq{Vp1G63$*e{Qc%F2`@4m310yBVA-+hI$m9~E?T73YJ#9N)R+n-I zA_&>c&dxS^-Xh|}#KsE9E6F$5ym+604Mn0c2^Bsrxj)XIBLfG~pHYL4t{qxIYi~>} zD2CYbzG?&OC(xxsL>QNJB%@MEj}^KQWjGK;Nkv7A2SOWHH8C;K3jS(lS`_5P`;vfr zns^^tS};$QcF{|o8aTP-Y{*|PbtJhx`_SE-8*d-`tLZmQnBqL2hW=Wc?o?Z=+LKC=t zA?=W=)Y5s?b37VElDe7qeijUD_!Et^xFiR7tTC|Aphhim9ow;^g&JL-dt;CuPJUB$ zn~|!ra^lkQ2Uz{Rm~7Dc^&hzeLcf;d8{ftin+WFd%URKq^agz!*X98X=pwkE9rrsU zw(a-mpdduT`)7!wgQFvwVBniTQ0FByC`5divRCw4osK~Oe%S{CW?^OJj>3T5ctTly z>42PKH8edx;4^kSvha3DN&Tr%_XO@~HC=i}2Jd<;6y)Z3hYL77sDMn*=RRgbk@w#^ z9hXDUdR$HykI&tvrl)a(?5SF^JPz!~dYnJo1tSw$wxzr$g8P}o2(iAeUh7>}3je@} z%Wi==V9(9X4MKev*qcJbO2B1DQf`}7P`#Q~$iIVAga-W*2o>OzNH<=5v zyF1fAzhPl!W>(fx3aJ`beGh_xLqZHL=^I~dgM@{JaYY@@wj}o@9b6J7@-=S`TLN2v z*d8!Z7ok2eCiq+bt_i?}*=BpBgiB!WgH}t)GC>=>>Y~tJo zQFtw!q2qY|BwN5t96w1dECt+$>cg zyuHa|HcZYaF|Dye`q4#6ndrmXU-##xT^*b+E}IF(0I-=t@tde5r69c{V-^MR3v?g5 zE@!*9eoW8M^ww8s4O4;qb?G?S=Z|l!cb))30?;=I)Vwr{_B7v8P*bO6+95Y!;L(-~H9JEZDq? zsn_56(|2}V3rWM51aVf8nh)1UXy}PlKc-jHuIfd`2eWHGl1Aeu2); zINQs8!DDli1Mrm5Gm{VmVq&dqF}d2CG`JhTy8OLVa|`PKHocG8Q;idJf43D41^u}x z6>sR#w*Bca^Z5S$zU$}NL=Q@a>$AIPNlD8s_3z)mKNz+H*9&GtNn)nndTDrMgq4Mb zD=OXnX*8UnebAzg@BD5HxQCk$&iGzBx`GDK!t$!x&dM*(Fwp+|l{&nAk?GZL)~j^L z$s+$%3$Wazs_TdZa@w2N7%I$c-CgxGOOuh7#@b2&>OpvHPqgeuBpKTb<|+tfl4(gv zH*{-ER-VRvq5Z~8PUo5FU%AcGm7;98CWCgf(`Iid-AEKM*ykxI5)PSQcuE(&I#k!hfaQ+3@fZo?6&@Vj`8v4bS-)d;LTAhEvJ4Y@GdR9+}x>KT;Y8ePp)gK zMBIO!n!WkPe-nPWyts7BJY8v-tKRN-`wgmeHZ3#r_t?l+(5Vs9vh zTGH_{H)IuZ^0c(}97LV)M!eoN?awKS{Ns+r4S z{e|>{13dlu)H;}SH)8z~nn?D$t++@VB7g|7lqiiZ>1Mb-t@m zD5kD zpr|Rc17k#+>(psK$cuS#5Mz0>H);*RAs@AG)qg>S{sf(a3Sc<`$nJKsA`u7>!;-9<^A~Q zD~fQMI_%=!i?Q{ryVadI^rT~e$lD6=7A`Fr1^Yz29x|ycO};PBz#sKfjwzQa8?W%% zKxIWy`Q4g;#0qL$|AyP*dRnDM2cI1g5m8oFmXLrM5VK;F1@?Ugvbdo!!gQB`*d`D! zz94;6L36@s2M34G&IeAw6;#!ASB@aT_!5?5rmkHQ74}1`3Kw2|oX>K2XDq#MmwwTz z{wm_?>dL8QrQPLtF%q9Mtk5rKaD2KrWJ7%}JZUN+vUI}esNSC1RjanPJcmI}BF;|< zT}eT3+D`aWsPgHEZ#JqKrG2zmjO1m(7o4;wX7e|K&W1<(X{rLU&wEf9sC~mv5?V&p)mfVUXJ*DGuBKxc3 zY6h$6?Clz?os4YIXmnTtT@06S)g?H{PyyyOKCz?$T+o`4* z+-_%j4NKN_8ixlKP<}Z_*gwEe+p0S0EXHAd2KqQbyLU+VoKoQ1A77sBRpsTgN!Aa< zY?X+4HB?kS!V4O^NgMP$sTnIPOQ_=lPkW69`e`1dPk^noP6{ELZ`zxiAGV_T(s&`5$Lnc73?nn^b*A)1_jydqhm@@HDK!8PO zF|rw*#Q@@fGoZb&jgfScCTZ7O-8;|eT;E~H?)?3$7tzO~6`+W;;8qre!osK=*jMo( zZAix9emFkrh* zqc4C$AwXq{x`g4kv1!;m38eMaRXpW|?gZI|(QjMZeU8sR>B50{UBK9fBMU@ree3c7 zf%wTqGjx=d)thUCyv@SUAFhf2I&i5xS82&>uI19g6>sx}$d?VX;q0`5pvxcL{0W<1e3=i8K`i<)s{BeMZ7Vj!%u^IXxndert zRIEt=8|5HXLf&pkQU1PP88s{I1?>4*y1n=q^jJ32NQ80jd#hfalAYQT@lBw~RGEHk z>)662?bcI>K&||1DdeYSal2fIu{tC0nSRKq9uj;Uzx4N$z4Bv<=y_zlQwns0f(3<- zY+Lm2=tlr5Tt6vj*v1uiHz>K)oXwh3j4qJ*=H3hKCCcRcR(sVJK;bdR2>~5zc7(!M z*%QhwpbR-!dt=*b_{j)BpXe1JCzY}zbuY_>t4}8-XrQ1x??0Q+X>n7J4(_=)@%TQZ&4+nTC2LR&fa#!WK>>kE}YelA>6NqB_gfC4&f z)c^>GFo&(8bTt1MI|F;l8+aND1@Vb^1yB505buH+M#*G#6Vu5D){H+N+Eif$)4Ks2 zD<4ZOTR~)#ZqW)IlNVE{sTGA190YDE*O--6&B7?xI;!BL)rQmY7)_8mKCX(U zSV$NmJ-aq(+yw2uUseD+vntK;@AVu&1w}YCzY{k3$aX#2GSjL+r;948;9(F2`uC0?R z2s3p50D9J0%uLkmAd6sV~>8OdEfvfoB)E$w6Asi&Mwpoyav~ zB?*dPc*mCiM|?6RGXZxLHTD7zf01U~?G37C&=MX!0<56qEB^}kAZqVxLxSbV2k&2t z4Bq@5^MySRmx3-`_nVtF9!zlB3{I2MktN9zx&=O_l1O#|=H!tqyN3_6Tw*cJ_BIH_ z!ZDZDp2n_Ypwq19M2Yb|nx6y}o(jAFPeRvE#&6e1Z`+zN>xxY0Vv?A1X=HgkV7#?h zTYgr9>%KK!|CUc^qGU}WB@U@(!OmS~a?7X3GCm|XEH z&uc~qzL-)dG8~Cj%wad2PH2S7uZWaR&?#~#{Zqe7=+_oO=z#p%a6u8XUQpC#Y$OA! z@VI`CS*{$Z@F?-mW)V8iHMMUtWnnh5ne$8+DgDM$-(?@jflte=w!0h7&voCK##onM z)iRv7VxX6YE9LEAmC3aIWI*1^1j`xU(n zGYJGkTyIP&1$20-FF-EBjEc?vy7Atf2&0C7?2nQ#f25C>wBrh^(EYE!A`0nJo2$Lh zhQm8#I@5CAX1!Oy8-s<;zBWhLl~FwC{>)M_PixqrDP{h)ZHT9i4VlccIm6`7ndPu| zz(N7rpY>=-4pmEp0FL+Sf?^~fwuP73UKaLXvL1?)4OgL#I4c;;1%BHo8Gt-nxlv8w zC@QSRndIYUNGnWWs0^h*DLRZ2D26BYkqgt?7i&X_Pw z@0t4e#?tR*i)Sh2^#TIMm=+Rf@fR_c?;+&EAq#^&9 za{xwU6}vIhUbvq3_pU}YIraA!7qk6{LLFwbIHN0{@~Q&OyVqw9N2whpGwQTSt3rYG ztG4h%YZR#P^su3wWVIL?3=8_XJvwrV@r|@b>5`ij$wf!uWyj zXmZ?z(%_0J&_-4{lSsfcRiB`_COP7}T)T`0u|B?Li~-%M|6e1O7?+!*Q<)ZHO?gmA zwsjyYqNz_B`t(njZE9*Lv0zECqHTeD!mN(&>Q?|9#A2@LuB8N1ZJLJS|1?tbtdw}c zvHAZpQf^R=mzo2)IBjT);J4>1RYSa=anwl>4V@{~O(An^O2qG(c>!w$n2@(dchhu2 z^RFma`r_cKHTnX!@2f_c8hGP=94j)cmUryieBD-xc$Q}alb45G@!S$l zo5K{{DI7;ICiT}O zitW}t9tFIQO(j55sLskQ$5a$w&Q{ORqPNEvB&k&eV8(x9v$yU-*LH(9>i0f_&C+Ke zm&9VAZzg%)ukgkBa{;@2%h}9_xMl798*Bd(@a!u}!~CB2%-0@4Ktba~&Q2a!qRkt^ z3Jg$0Ab1kx3MJW%vOD;R6E)^mIqKbHI()!oD3T1@Bu1*LV9TM^iiA7%lw~gu4mCTfEBrd!|~8!3i3*t!q#hk!_+eg zWNA;uBIAs2OIXJiYOBL~1 ztuenhX$D#ewj+~=t5(PKxoS}TLuch*k=A?a0}FXhJa=e|m!uIxp(kDV@aS1o8p#-T zNX{;ke64&@%te1XH<@#!+D&^EY(~i2Cv(w6$r1i~HVaKwlR>N`N_(msV*iQyuFqh( z@+J6-zi@&hKsqQWzsh$wFFVIv#thH=t)lKusp7;@eG;Cbr})=lQ`77GO;vbN*R%q} zTeU+VB6G|+ksgF4&CU=2B(fXv*3yA7Sx7G{&CE=FDsqu|KIZtk0F6D6vi0ZZN;UfzP0?%fi27|BQ)E7~?n&}Mk%8X$B3L-T#zsO^hd# zU@6+u*CK8O{OBF~KR@*|^%nw?v?QJho2+2zdE2m;=ps^}#1uv9*-rUqYU=n+@V{#f zAH{qS-z38RKN%`VdM{y)H}gdkopmuQDj6?s6;o}#mtk>6l}FJm)7c(PtLjCR;AcV{ zj5>s(3i(ULS77aJG{Fj?u%}{!;d+RkC?KHPUCK>9o7#_;Ycf0LY-9BE(d)l4H& zF`_e(aCs*N5_<{RjIYF@%3n{pZE z6$b3vOAt`J0-VgpG;cEcRRCPAu3GW_TT;wKDCCC0vps&h_ksH3Mo7{GmwEkvGHPS9 z8qnEef=Q_8@OW$^OeQ{zW7%S8X7rKOQy07;jIUtc9&J6ubwvAYS$v8r_o>aFEW>A$8oD3EdG_yASzp*mQ@sbc>>!_^9FE#fPywA zr_+}B;_?2}-Ua z-W`M3vG*6mTwPCV1;p)X=QR=|01bZYL;)jM3RA=KNzm88lK0L+m5 zNJ~jQVc}-aS8dGs&@_T5EIHAjv-r*tpUK zebprupgQZa0_baz!}rRdD#yrq-$Hmb)Oop(-FuOv#e$OwAUc4&wQNWHClCKs*ilV& zJPTK<(7azKHA~yFcBW@uZZhU#Uu_y)6a~&9)Y+&J#_*&49A^jqvT0gD3+(IDr^oSg zE&Sij7%SBx&FY;bX{^Mz%m}@L^ih0%F`!1F!G9LIw-$4DV9IHHMVuePQ=%fe?w(c2 zhXem(FNnJ9n_k@#OHDO8ItJc$&*#t$_tnF4l(*mMHNr{Yb!?GFs_8W(mq;<+-FrC` zxKO7vINVYr!{w){^&;oZ<}{<=FKH+Pfi z=_;TLD+i~){P;RFt33?3;}BF0gsWnf~YxAyi5EwcJc7 zSZ7~yj7eVCC6>RF_}zV;EieANCPjsyXgtMc!!OdT2ggg8d|AP}U)vrK2luD)bIOh= z+L}kdP9}_*T>hCOrI5L_L|%T|(}2tN^u>cCy;eHCT_$I8uQtRuTnT-Kr8?JyiiAGY z$XBf{RRsMu#L6xEx0RmFhg3k7`_!8VD6t&Omr%G8_7Nyx3#MutU4n=n1r9gK-`M2l z484f#+Vzy1hh&Zlk?tLt1-GAqya`TWwQI<4Yb|y}!zJGd;$aodjr8G*sr`v z!sY{4rem{KTrZ9nACUPw3dOW$A=0``vx%i0IJ^ewfrhswEF`%7`B(e|Fc=&6ro26G zdCvEqILu^{^8?m&JqN(Vd;cF%ZygoY8+Hv3lF||a($dm`bfeNCASIn5-BLpe(%sz> zGSV@mGzdd?cQ*{o5byat@AtglS}YcSan8Bpy02^ReeHYFu`|#QX(jF(+nYdT8%yj; zyL0Ug3djdE6^V$z&3jE)&WvMc-gXD)oyjOA?xdY@LErkNS5EeWzD9!2WeFan?aDZe zLE$738}0rM{fFSP%a;UEuk|3ujz=>Z(Ea7(Q%P~@uE$8`YOn8B`MakoAY)$8(iFqeyeK}fbRVTF&Vg2FleE}xo_J5+AN*0MT zgcV0mPN0`V$La%+9&_UTR~ps{U_7TY$4>+aCAbh-@X4FGD4t73&Jy!*n^Htv38UX*GiFZ!(LY|HEPEkGk}>&D4GMA)KYylC!FN zo0MN=*87`&T}sK?wRctPP2ZEx*5F2tcxL-ha>3Woe75r6bJZ^^rp@YK!uOJMR@g|e z2PKI@#(wdZmb%FUD3#V0)T^j`=v%cmO_k7#=;+vdhL0jyqnw!nkIfgJAi_2sHL=UT zmO6&qh`hyj2kUbt7tc3vdnfqcL_KJF&nSJ7rk*TfAyvZLfX(JN#QzyGk;TRlev884 zkCiabCRoMAj0q%U@hep<@&$xoPTgUsZKYrRa> z(k-ay(8$e0{%*4}O6e*>SuH}EDn;VzM~dv+0(rBwd6@=Qv}S)f1T0y7R=PH_^3gb+ z_@=Vq?sqWg5j_2^LdbBiuO zVkX=H_$tj;HiRteMX$fU%R{x`B4(1sa!lJD3zcRdc%Md0u1EH&Q|9{h^wl0BZ7?Vx<8L0tRBg(KGcIP9#H zocPSt+@viG!h4C_<#j?)9+%s$fpzHA2tIo7#B;n{!l-D7lQdxvN=HDqb&rGRU|SqG zH@3v4Vx%urhJFSTW8%`BAeoI^DRo^XHbw;vyHJtU=pBo}!gL**4v)AZN`zu?FuDh$ z>;zJMKNqg<7Ju!tsznc$=JG{!I;g2b-*2=0kcm?97#UE-rWR&XJuj?O&30|s5}{I! zA&>zT6%wM+ufa_T6AS5~;?nEsf60fDa=rv+(I`~?KV;S!lKpFifbpEMYQzzvHS5;- zIlW==x^&_cZW@)Xn%c^rvn$(0H^QS`k+Mo*E=@?3m@wM0mmp~5Wfb90!q<*RDXhQr z(XM)OAAFMTA5QsG@>!P@p?Q~8W33(Q#AVX*iN+Nw?0kYWGN5`s+svRegboXs)d1q+ zkqjxm3!Fiv$*Ax2)mgbEl>*T2Jcv*XYCuTHdq>0N;o2uWkcUsfsxc<0+3RjvF6O7D zzWt5BKELD3sD9&Xr%LPHuP5Y_Z@Lk=Z?Jipxopdw8?+6mNd=fUQzN`2n)%aS^n42z zUMSFhHFy3oKFl^EWsKSJBUXq9$l2t@0!yFg1+Qh{X&a?8yFE`e_;NI}Kk;B4Ms@8-%yiHJAa&UVSlRq55g zrl&9VTm?(yI&Pm1_XOYEiBY5re^_oQc2|Z#Ad9sXZm<*T4I;)EOHt231$pI4R&EI7 zcj;Gb^C(`Dm!7g%)N_rJ8ywoNMU)V^0z#stIF#7Qc8lIlPYyPE#KSclhlk^}jt)lc zy=I)EZcdYkYpP)l5<^`Bi+X*6BT2$D%pOr|0TM;nzrC~^@ZOrVqn|kF_Q8EQ!pD7t z+eyUmb8@n%XOb3e86YwQ5#nOtL>Nkx==`r10Glm>>&{kF+r!~h!tdBa?!#SveT9xb zXACOl4b1D%T`f8+-@e()>v^~W;B@MCI**DYV`ymTrI)@yv2{Iz(mD3Rd}5LhwC42T zF5@%%`_za|oKZBLMw;b{H|*>~1SBLLu#=_Y)}yh&2TbzN^Sf^%yIb32B*i7g)81lG z&*P=W#;JWbCGnl>8OA0N+*cwJzs*0|+mE!j`P`hWtUEFC;!d{7q{fY|(y8$Wj`kz1-X`}h7nC<(s|kUD{lTR5!r1^?UWEh~PQ z9)rhtz9h^-M*pk4 z(%@m&1?^=R-_Z@xcY4A~_LFfzZthj9Mq05y{tpY1X5Z0Jd?jLs)8BsI8>@@iudmPX z^YJ)cuAN+$-w@`i)znT{Y;%MeDf0z~5vVCCK_oPq-7k0aWBb?LLS^#XACTrzf{q64 zobj7pEBh`UhelLqNcgE}C(oH$&We?T#=SXg3O|%j6+>cI9jBdGAHkkrB_k^s23aHd($lR z<0F@1DwAG!%S1#(<>lqyVrJ_!X|)+bkD9P!Z3a!K!!4fx257&BeI!rNurx(u7_X>x zTjhOYC-VwhS~;}(CAjsmj9AoP0VvOV0C@T97*V0VW*?_BL30neRC>r;JJ+AJ3JLG> z;>;*&p1wWTuUV&FVoqohEId_^r~tU1IM(_k^BwYQZ;Xo3PfBk3!)7ZlDw}md>Z1Hj z9NLlnnr$8<uhmr1&Q64P@8;$v`tw$BG zovO!6&(z@&=fFdUdmkB@jeCfMq%{J4kc~~3@VoR}tMdbpJm-By$Xhav@KDjVp7dox zw|3Bj14DXx{8yd`KTKu{R{7ry%5kRrN)j=Gl*+-{`M8=}e|@Q*leGJpE#!4DSxe(G zM|>ZMa86`4bh(>mPvO2s`gP02H0W{|`@Z$m*>6zCV$Kz|AJUtgm=H0;4al3>)T{Zr zK5P7sG+PCbQr?DJ=kQ)v9%WH+m^cUbN^+$=U6-O_;J57t$^l6wD|wc{!#(i%1Jy_V zIbh%Z1|pQOD*{P912V6fI*P=Sta#0v?bz z_or>19?2(eLRrstPFmnyh6b41mG>0+%2& z^!5T+_YH;T7|(#+>GwF_e|!@XFr$zT?;yCqz5q%bDy&;{>868)L$(MBk4i*LCZteT zgydrR>5TY8?=t7h$hnFyjmn7IU}4hjZ4am{p%b01;AP2T7%t_BlMqOX@T_Wr8W5Xc zw7mh>GOLMy0fWgNn${K}lIQ{Zd|U^!Pk?W0rl7}t(LdE}P%s_V=VVg&${k#tXW%@r zq6*3@&an9iJz*7fQ;+J##yI3|IjRY_R$i`i?!JWmE7)f&J|(A*v7D`XbUg|IE`iIr z+hK>H3IXzdu=IIAU~nw0XoKl;hC*U#L@?Gcf~)DaCNMa(^?E@`$=?tSG`n2%)SFNA zH3QgNKpon2HZhEY-4Z_jI#9}FGt?c@er7kfI^vuk2hYKzIn<_Vk0X@XWX?X{m!nOw zTLe^VyiNcn1S6X`tl%qAZQhEo^)-U@n%$i$K`yD_kg&(o6C_QI{_jAkJe}P32MpYv z0Dr_fw3)Vj5qxRNhVj+BEG(ysu8}J)B?;+C5~|oLH~w`Vi@%ckf5~2co+eNGRJ=>v))V{@~V{ewHm8U`jB=@XfKOX45mocemvhmn=h_N$r!&40v(^Sg@B|c zXH+P)W2wZeY{8GfhRyVv{H;qU@g07g@rqy=5sFLccQ-w&$B{xhoH~l!YrBxOG`zfo zl6rbFG1?nEv4C)Cg_(t!EPV!zi$xVVUP9@x1fYI%KjT5)uW8wB#cA{#9wRM-e|%W> zxjIQqN=i!Gdb~O0?#O*|XC--apq-U!{Ku)wH=-s)W<~VW>uYDHG*rrcCvY2v^mGW8e{(k-6M(IM$gs9!u}Xh-=>XC_$nEX=P_Pm)GNLQ zAO}g!9sP2(8MLsFQLwQ=Bkq%IhpgE79!=-8$*im@ugt-5&|p0aG(mZpBOCt9dJJ23 zm{>e@8?B0$Pu^oy+r`PaZLfEy>*+~!Jf-$Z9<$DC*BnDokvICk1?JcPVD0(P_zJN@ zFGJmJB{JdT<&xS>iHT5B_&;tAqxLIn&;a+*Oq-mVr;AJJ(Wtw7J=8PVVXAq^C^x8_v(%FNHe=}L%8?^R4q5+ zLiSR^*B?l5IbN2?K~{h{yZ0J@mSH9&;WkruX|HVyHl=@g_UPyHv`}NYx}xFriGvb& zUp27lr}?g6TOGh-11Q8{|A1rv-D&4z8?FECN=h^(Hq`wvY1!-FoHM_Q|HXJ%q(6dp zFk4GkYl&Cf{B9!mx3=go1}w{?ec6HgNZX*rwLjs5WXj20mu}ip>-~wi&pqN&CZpy| zESA^(G?>8iAd4X<3GZ;m!qS@TC8_5Kw|=!<_@e@wq{ioM50)>#Q-HOz3LH11$4sK0 zcAH)|k6|?2Z%*31HbY^%eywJAjzOJpNqdvo*8Ad)#~z*rsXUJzl}0>T;f2HB#??oS z#T^`F5*pLRwnjiQ^8OR%&GB**IC{e-2c-kz18L`TyoWBY-yTeQ0mp~&ClA(+KfgS4 z+gHKjv;nmI7T-TwX@jNL&o}!e9&QVnBK?8!$j+WDmV-$QgTJ7G!oyF33LNIMMIpKk zA*Oa%D8m?#mJ{ZPf)&5Z=#0&N&hZK?JprNZN}H(Oi>XS?e$}+4V%yo%jyody(9LI) z)&>)`I;WC496;f5x>7hBbIb%pbBqA`?vIuhR#k?zh|WiG5Z%+pKQGaP$Xf8RVia2{ z`*{_TMp;GW%WZe#D(ndXOCILqtM$G)V33&6y#Mxe`9yO(U*QPU1wgRsIBGP$2m1r1 zg3r}a+xK-iiRHRGR}oDc;_zyER~MwFqT(qN+qYs)0+DPs>?1(XBBnFGQ{j& zXW;SpF&$XC+t#kaRv$I+)C;P;qjiOWvU`bK013j+P!$nB@?L}=Y z2`WETu57d2XR#$ojcbABQ5ji zibgU8B%c0pI3w{6wMW3$%STyU`xM!pr-+IcguI6bKIjhzPUkhHQ^w>z!gkmy29Daf zmfsEd2bdE)YA$&$8dIWnb>8uDQ44z?wK@e?_kLS$v78)+J$+f~TX!?~KDaGx=u-T$ z#o#2Dj8k4-o>Iu-*Xl0PZUxhvz=!Wb7c5MQtIVzftn(G(Rvn z?BS}rv6XO$n`5rS@pLEpkjxj!1hSj2o5{`+JC9-`GxX@Sc3nkoOgnURCnd5!Kk9O8u>ZzHHg@_%X1F-ZN~zI5Pt2xX)tkctA|* zsY$M~K`-yfjBciPT~XFrC>@XIc>SP9MMtdjkN&X|KpckwK^vlb6FH+$eetZ(bh*4> zAv0_c4F_H|8XOB4)LynMJ3()Vb#HBH#!w1@5v_k9=wX_x&mO&6?ib6DKcxHE3&Z7 zdop8i+v2fNweP;QYwszJoo?en`aI@Lrp9wh*5Y>1p+f-8DDP>Pxo4ZEy@A1FXT2RAUu+}s_zbLYer z6|ugT+hU-+vJwgH8a!eMbV!I~crHR6X-qQ8@l^&*n>~MbKHT=?rI`;zsshemLQ2Y9 zy%H}FHc`itsPm71=84)7W)8WJs4mc* z>Dk#1G34sYzAje-#jwh$x)`}P>_8HS8S4BqJs-&W^}u`g_kaHug~Zff%he4T(Wrfele}L5g zQ)w*JduN2U6)6I`+M5pBY!Y@HMG2_#5;x$QJuxiSG4x3!zx%-p)HY(U>-|;#6}fc` zbu3QgHQ9fiq+SOqT)OQS-213qdjBS z;UH5&1;tqA=3LW(cLy{_E)H9Ivc3G4kUGQ#2@~Zdnlcc-w5o=o2bO-#uuALd4y{6% z+k9$VQBAdlS7ig+okU!YeDjzo^X7!@c)B!qClI*R3;-vnd2WLuxzv&%e? z&H#|=aWbcWcwXdwlolV~Y&{$E;G-nyxWuy_#RgzOB!2e0IsT?}YsTkDM_%Xy^3M4B zWEP^jWLGixfS1QuQD}X3AOGY?-z@w`+1ST^l*RL$|sImHpK*Cf11cVPEFf{ zRP%GOlza|#mq^yJwmPzlcxPD?(RA-^YW^0?R*zOz^z~e(u9w|!>Yu_=_XkSFuZe;T zXfmP!|4Eq>o3vvo!>aiIQ|?|X^@Y}q1G>TjCO{Tr>r(jwZ!9sowlPYy{71_;IbQ=r z0eQPs;zvUY0{s*`qn!CY0wl7_)zlykZCkoEH8nL^l5IFrmR|d@l2^?huTMy@<1l69 z1!l^<8NZ*YK-xVy16l#BclR>O=aC6W{u}4*_(#-9{*tps5Pg?k0$-Ly2Z!Px5}m(y zJIShr*75hufPi+lP&%ynY}Xpm-2rxNv}ddcG&2smJQPs=8R{kpfo5cQ05AGWprNe#VSi(Yat_m0UZ4OOeON3N19#%C7w@IuunXvH&0Nje z${pYXZ*ZRxqDe!tsc44=qMUE3MS!0Bq0RHD>FHr&eav8#;Nit}Cy>ecden=!(vnc~ z`CnKJQ7BUFJrlSWkw12Y0(W^|(rx4bTXORS&}`LpVTvo&@IFSQ$zKw7sai@5VzmHz zU#R-MzI_9|imCpO+j!}!6+WOAfr1|vOm-{rfRKAfxv9=0PyY%uAyR^}RyaL9QM&PC z$TiCd5&;{<$u$mnZ(Y%Kmt2s{2I!ujbqaj>8|Jz~{?5t{Na|45uFkD3EUdJXQn``t z)gvh;zVG{EY4xDq)AN%hxd1%k(7SAFE8fBJIQX4xJ`l$Y@^OL9&lzYqGOyRi#HV?) zYD9>Zv-vdw0~EH55>QdGMV64_$%eS^Thu9~;S_nysJ8eML&7Ue!|E$?t_X;qX3LmT zrVCgAyQ|kN=mOiSU3SYQDhOsosp?S(Q{dPTA?C}#JZa(wV-*ff*Sv@jak-JR_hA-c zn>iMjTC5jk3ke{<=lUAws$z; zj^phIALR|;<`qqV#Juw@D6-j^8{gC=%u=$zkd-!* zC}TS+hbRFuDGYMuHW@25UYqQ-xt~(Gn9pLMD&+jMEMbI10hW3x)w&6q3A|?;NIO;% zvj>nAy*+AZK|0WYj1n}|9Y))7iob6ka7HAYIZcW?{q%6-|B~b-P_rIhry7+*B(Xu( zDw)pfOsVhq>6TiZ7QYT@7;;Mbj&lbWo7oI$Yi_q?GWa}hrLW?Ot^0bIwn=7#j|}b z#1gsiu7UAV0veGl)4dOpk4}4QMw^Dpod7|0hFtYM-sa4lc_UHCN(s6}MFCCmwiVtp zoY++^vz&O|Q+&d<0W2G&9SrF>+2E&XxS?~kFSB_#&~^dOUY!fu{@igche8r_Rt=-a@-8CMM|}Vv=*xKyN(74T#cVhpxloj)tn>9po;|YEwdrYU9E`Sz<=(wm zhR?|YnQc#<(*F@kZAJv@DgC)#rZ*L*xKwYoY5}o8j8-xbq-sPgV<|i_fILqXWZK!8 zFSzOfpWhwD3T*|&Wi0TLVE;CJu=acS6x#5tGml;tT@P~cj3A)*4+Eree z(DTkOzdb;v7wNkZVX-K*RddEVI++vs-E-lIx}&FXWb4W+kdXbDdgasCpoohab=J8G z9a_+t_n}M|9f-v9bdX2cYo7kM_@9|v2em{0qUc_;=Et2yy%~U;@oJ+1k&C&J|4`pv z$96_NFSpr2*JxlD&)6;TPsAA{oJ=kHo59ohhO%8>^qh^k761REWBMGF`& z=?`vBK5W7zi>Ua@Sfn{qXsVniGl>FsxVuoI+5`}vCwiz0VgMkJ%Ub!a^M~< z$x1o8;8#OLgOWVcG)9FLW=3q=Ul9#ca2X4uG^e@h*dWr_&m)6+e&#H^Z>gnN*;ca3w&w;?}PbW^_o1Q&}zr|y7js7LWcgVoSEv)^^2MZ zq{o7t$9aSAG%b4;*Q~jk`0_hQ+P1H?D%51bi|l4^y8nwYZq!~<+)W}H! z9JIh(aMurFmRxG=yB7G7=YH}m?yI-TLv^Is==K7OYxLcqfK6G?r3WbwkC;xurLfuA zX_U@CFA4$O#XNut^f;BDtxMin%(iZ*5BSW~;gnU0r4>pMHy=v( zhaR8c4^qoTy^=g!t*sStpAfag_n81{aQoE;PN?hX1Hs6%KYys&fyx6&_$$iA?z^Cn zMf=}~UtiC4fG)-L##ML!R4#NNO$DD-mtNpRydlu>y&Ejmu9*Dh-u|#KEElT{KlWcB z)iH+EpoEEE2g(7L7!N(#UhV+6*#zgSPya=$V~_qVJ{XOl^S9MURM4*vl3-|sn>B#A zK~Mb1rPh9|k3pk471IMS*#J%JDX#)Fy87EMzb2(2u9&_a zF33&cc(fTOSfv*Ao_qB$@b_aUPYis;yR@OfYAnu_%*chb9}@(W{7(W78%2PNR4$~? zN=di%3`xzzG(Rs)@Nl@lwZ#!*4N3QM1=?>PBvt_$sb24$w!}xo8;ja`3_NQ59mEh2 z!nin5LRxmVjh#pE05VGHIBf>(r<-vu%_|d)tEBnm#ldsFwmUxcL4mNYqe_`qU)Y$H z73-r(Zq7gaGa>Q9!@#K3O4TY{XhI)Lz7PcZqYkA2HSGe+NK->=_~FDhZJ=G8CT?PM zT#cu`SU7YkocO#jePq8%(wyQ_wX<`RSTjSq7Hvd;QYo&DqV}UZ>ekEOZZH2W_P1Q; z=%TV4&6bWihU@;X7J#nK6*aDeEi`}oFg8mSeju3&*zl-|`u8!V8v6~B>Y!re!jQuo zAAsLd1{bv!<3T6l-Zzr=V}M}EZ+?3A`{BV%rP1^|Zf;&)1wL8451(+mS+#}7`Bf&P zwu%v!=V}ZeW1Erfn1nJM!;kGpjZ;%~0EioouK&BCn-mj%JpayQjWD8Q#djNzmsQs8 z46t`moVY>pA&BB)3g1P=-SPqTG6QbND@MfMV51KzwlgFr*EklEC}dB57T04cgZ{;N6Gx!zg^ z)$-%7`VU>2bsirh7mp=e7n*?@yZiI(GKl<}t+?dF*#khPZn!j~qC7pV_`q+Vr~C6z z*pozdEU%Uh?cM!kGobg=x^kMg503=j(l^=~0q_SvYn5Mrf4rQkG@(0NS%ggR^I6O} z?Vka{h>pkm$?V0(7K1^7Kip6D)gxBfzB|I*p|Mne$Bl`B-_}6ms;@gh0KTc23WEXC zspD{%_$36B#;fL6({5NU7#kFDeqspSX}!h(sqpcm1)8R%87V~+P-NuWD2nXkPSW+- z2A5EXv`_$pUvv2b6x6i_un|!dqTsQy^#FQuY~aj4-!dma4Vc`17N9-=pQ+$Ba9@tL zRubw|a2Ra3vkru$pP zyYf9Z|$6P^nMIXXCgjn}EU2%qsx4Df%T3n@C6)8dszLrs;{X66y$+^Dr*A=+x zU25(N)WTJX9Gn6Ln5F^o)$hJ*k?sqW1uR%5Uu;(3Ei!Q#wNBRmtsXe}8jXGKB5bQ9 zcUy5rg-@TMt-+B1Omo@C4vUPn1+X2!O|IXe0~rXc;@10}Omd!=XI;U_j{7TfP#(oA znIW7(W#jNL27&=1%4Uo4zbL4f(YgGVOK9tnYCDfjYql(tT(!;pR8G;w&cfgLa1WJw zjp!BynK?~WdM(qx%BRZ?Ne!{wkZ2T+0DAt}1fWz7{-07gt&6Si?aoMp!hEaBG&e;* z1K=%~^Ds`Ouw;(#?mUyq7`}hY{RN9}c|yqbj*+42Haihep?z*~1x)sQTOChnu;1N& z1vY3xujJI!6riS2C;5S*la%@dP)s((2_q?Ih+%HkEHNhGVp&#l0Hy5&09!R$&(Pj) z;`)Xo1Bt$r)ChU^K~LwQdIQk#tcXKxhODafCDSeufv7&B9{)gS zIT;zb;55mv13we&zW}P9Ud+T#11%QkY5;wuLGoG0mdqon&% zfZNVu^XTMCx&IPb*ix=G{oK90TlxCmCHPz)p=oI7-cnKmE6oL*S}pn?x8pH^6~Jfx zc+YFzS83GzHW}N4_4MRqxz4mZ*%*0|Zk@X-T0$meyjmqGdDgF7BATx3;bvj%WwW2% zxZ0}pyl?r&mRXqXj#A^6S-jEXAZdTfhR`;iB>@(H0N!9I>RBv0QRa49uk&PbT~12O ztc<44`qIevq&b=0$mP+SF5u+E*}uhqyrtfjKDbK$f zF-sKAFGS;iG_EsSrB~~nTq{*mTWdX1{@L^4=H~J7@qIxzGU;&=6@GIQvs`WNBeMMI z%{B^8pF`_o2B0MtG2Q5KXMq7+mEaz5nX>1RTY^uP4*U> zFJS~?WApQg@{G8WNy^r{h}jwNX}KfK_dR;RA9|_UPqb5`jB$7V)DM|ingjOsgpoUK zVYtBWA5{Y^YsEq2vewq8c(aDJS9fGq|FV(?EpAShFL#l&SrWF0(d=IO!zUiNgZnsNpLvuIJz{^-{sG=DUgnj+zOt=8^; zmq*Oq`V)8)@O#J>uop28m!W?e2qrilnf?ggb#!>1 zr1-Jcx5#0<+-uHkr{tL*wv1$tKm5&E z1JhK0)ls$TxpWYabUR@ssuX!hSsw=(7f9InIM^z!n)pTlw`+Vtr<4RAIK`T>u4P$^ z@Bs_&`}&>rs1MBQ`0A**JZ@sS6sMclO0qwm1MumZi`6gNBZTz5{$FpBrZ-RsCbIuJ7 z+fY%3^B8Hyyq;_M_i~)Moc=lS*+&JI)Mj#@)2M6nGO+G~!#1dTW!iOLp~Wd$W~GR{ zO?I)A5-R+DW(NH8EznM{_j?2q{#|7z5ZI~=MsxRTCS?W>qM>CL%*m<*_$QX~R#2ZT z<3`2ew>*Dlg=GX558Ze-lNB9I8a?B*YBYV3f8#ORs5SPl*4Aj~@~Mhso3&n5J|vBg z$CE~kH%&$=wgXx%=Ryw;P?VMFcg*qf zS8({lhE5|X&JQKY3-I~C20EFl4(m(IB;-#?k~<%*vMn*3b1rwVXsh4b^fe0M-4)m~ zDLFaMVhyfj4B~L*Qnv@{i{RjG#p~Tnd5ejCH;E21dCS^m)MhF<-uS(<0v9L8Wo0?F zx5;SgT*;R|+EyRC-kJAB-ObE)G+0fSSJ`QMy*}R#G&YKtkuZKkP@-Wt8u8blik8*g z%}w-&>U6EOZ->yRW6Q1R9#v1`MVM6aUrbE+_e&i)5%$pL?An2jsZiTuAJSbhNg?(1 z51LD{u6Hzmq~!smlgENbeg(8N2kMoqu(0LX@gm~_-~8%Y9@iv2*z%_Cbhg8w>U0BsKdiT#^)xiB z)Zx1A@9BOcV!!tDMXY3iCEwFRzj4L}@3ZlA(~@{E$%3#t{trv_T`@eu7LKqMdtqrp zS=fL=8sU5B+CQ(2a@lO$%=dmOtm}sgdfEBe$K~lXj}s>uxVqTES_?1YZ|*RLfB1jc zHxN8&jG`w~SL?ifb(Gp_eY^kqcZfZD^y(bixHcL#(*f8kO1^j^`aV41MIU91gh0Bo z*j*0*>3YA@=T%<9k1r2Px@;1bD86KImc9y$x46Rn`irgHNY8|NHU17QPb@K?7#!H3^Zxz&E8ORSO^;c@x-swJ zEzQu4VqZB+5Pe3UoE$NHJd`Y(3Z2!_(8^b!#K3bzjXn7-p#cwh@{99huDe~#)8T8l zc#0Qtgn^Q*AX|;=w>|wq0e-Ces$ifNN9zE;SOfmk)}KdhD+ABe|6m+WwC686BLLL z1{7Kvf*>Wm#)tAR0yvp~64E;4J=RALVo$THaqub)aG*%sq)JLps@v7YkKEkf1%3b( z?oIENG!s{;Z2kOy0dGL(R~`LSy3_vzytpEvsT~bby4{-heiJuKGb!y|w_24%DQM&0 zSOY!~uJcq0t=gPyXq{40gb3r zv`YEl)4xVDp7(h+FIp>D(-pnvtdB@&*h~VJIY0Ap#PpZcepcFik7qUW+>F2QHgXhA zx{k!M@Yh(5W}xL=R3PsTSFdM@eP6cFOV0+KV#(XruNY1QKYq3mw2fGQlZbo7F(gDE zc9wK5A!~;-ah(+ZP$2AWIU0ijGjoswo-b7)=DP%g;%;!{q&D>cv%ijqgTFG-T5aT*jv6YdHFb^9GOe=AzBkPTl zsggSv8FtOL@t4sdyu7T6*7Ehu8N5Peoc%A+7(s&P#VK6w%8!*OHvUq~AL4s($m8&D z9MvTlQW;Zk_-W^F6!9IOx2)@Qw?z*U5TQvER?Ebw>1E(;EC1%#cZv8kYVsq8ONs$J zctH}Mr7+F)G1Z{15Ip$fsoY^mFO05ZTRLoTUAu)TexwXwOpebRbN$d@{5!1d<01)! z!t+Y@zXMGm`xIoA-yvENxnSr`IEpNN1(w5 zbzBad(9*BF>dTC0OJ1&XV$(kvZ(XaSq`tRn-`f=Lgo`R z-Wp(m1d&_e9@Dq&YbMgY<#&cC(DRc1+U89)XogKM_81yTP;A~AQ4=K;ePwNae6}!a z#MW)GQ|eY~F2HWuyQr+nDL~d8jW_K_v$+T;P=m;`SqpVA*g6b+=~#-BDBj8rz46$4 zEgD}_`{!-+MX#2z>@0@p;Bubq&Qwn}-2zp4=j)H?ymo~Hm6=VLMLLbI?arAXN8T;n zY2+lue4z^lBS#rchu$r=OKH($CV29cNpdC{>Vp%;Gw_(EgEIMM<6|%L&+%M~+TS)* z0V1&nS6IT*Mj%PEHVc(c-qK}ULRP!6jxm9>Y~h0so7fH*y3JRiii!u5cuo|wkN#1Q z*fWTHUL6!kPRd_1wUosW!I&wb<>*SHC)iG&vUi}RvV=;6c=r02#Q=zL@NW^GtSiL` zYnTX{s@rWo^U3?lwJbOszKw|)>O+Snjmt2SotAX@Zg!x>)%>UKJ1ef&lcocm=taVj z^WPw!MNNWN(JNI;{6FU%wY|`TpJACA^z6Em9aC~LEXE@?*|##G{UI2CN}9^zsp8b9TYR4goMFg zl-@haV{`)fU1`=$i5Di-)M|$htEzA%E)t#PCwU<*y#Ji z1EENbH={(2-&~tttwIwGDY``i$&0sKpxoaVMJ3PHWBv9DQ)xVIKdF>;Z%{ov_yIr3 zF2(1C_1w({#$2wa2sJj*YoB@tg+tLfk zu@<^~O;OotxC>kuhN_bt+LSVO4V(5KsS(lcVEivIf?i7F@&VzP5mlU7nBYCiH_kUq zgG)giJB@Oo2^DW{K93lD^ASFhPW1kyEjhT(sQ2p4g2j6zlajDSNp0;xZHU!n=xyod z^56z1bsX9Y$~nMj6tM2gk6W#CmVKM-aORZ7ka~!`CwscAfjx9+$$3xp{c&k-pIo_3 zc{(jW&2>AVAnAU+fMR(y1a8-Qh06O#6gMUs*ObRc5I<2J=lj!6iNj9q-4+YEp_=zD zp1#?s!3u>X5_?WDh%S@{!5-4{D=(ZKMrlybC4p{=jjLQBpfUINUbBXQV%H!k1_gV7 zhkN@&`?naCuL0ZS=uV>)=2ebo3VCm?QRuKJN75K1tZafWu=1rV)SsIc`hN5RxkwH9 z{t{`sK709VxPz_w?OqRSDHIA1@23H8REMEhh_q<#YZV&|?qW_*r@w#A%QHrx1uD|a z-j9j84Kx@aNEz~y0}B7i{cl^tW$PKdwliy;CSV?8)~iTZN<^`5{;F4&qLs*73hQc5 zfRay+NRJs+EY9NI%A$TtJ+HMure2}-<}NT0TQTP7=tzM%aRWc=5-2&EHR3RL)Hz5Z zix19;D+_BYl)Us5i#77&)JjF4al;7kQ`onwsw(-8Way3G;EAX)5vMC#Tf38!;+y>K zQK*IIPA-bRTmwoAYaKFkZCX7vUPdQ{A-?*P9~TBx-|GJV9PM6%LA&UHfU`)Dh*_aG z&Fh-m8MD|t0A-#?M+f89vgx5JXPWiJFoY6~_u~IMs%MTBkGVOhJ19^m!QX z&ld7S{4?NcwA;r4D&Y~Uev#bEW`otGJIs+ZVV_(-_;RfeeDdjgjpOXi$;pb0M8|5D zu(-K*cIJJaEdEaN5MbCY;4l}bT8cy>y<6bIJAg7!Ijhdcb9Lce#Z0As&d5!QVlmrf zNz5@d)M_MyQH{FxEF_$m#eTVEyLUHtwH6AgU_ZpIH{b#)J8`?NaX#yjlfAvUde>cJ znnymlW+-%aK3}5@7xzebty31B$tRe34E7sN*@kc|Hn?kg!gZ~~44zg1gl0tY>^3}+ znE-bS01w*kx5=O_-l)z%b<6L*Fy(i%?72Ae8~E~ry#b*`Oqb^7%iZYxV?WFJ;jGKR zz~xEn6G6`t6l4r-hc)~pnLQQqrM94=f{bcVYojxm;FMal%7Dw$vKEuZS63w4sLiE5 zbBpdL`NUeb4YBaXtHB@s>#O97bQh#=?6IzCmQJsFc&HfJ@ayle@{1SFDet&U!q@3W zqSf#m@e}Am$ppanQ|mO{>Yc(cH!Ei4w6njLu#(C2bsBu>_nkb^;pzU#Q^KVP?7a7N z++;PT*fwDMsBuzjuh~g@I?6z$N60akKEDvRT9%moY0fgBB53NDspC}%54nP$>V4l} zdqU*Lo-9>AL=1DII-Q_9`okn24vlI3gch^K5ow!Q1RL3+o{u*-nY4blT_-2iK+Lnw zM$X`Hw=^|2rn>U<2{`y3r%;0HEzUJTPl!e^kL}Il-924EOiaxCw|Dmm)`0u;(=(^O z^xf9&tjkhZ)*w3-E)Yxv^lAUrcV2`z>NZ?81Fxkjh#>I2-NaE7V_IB3 z_I+=^)U@8%xOyMkA(=7~Lrq1M#_M_mJn4r*BC}{>-w9w=+_qcgbJD_)NzHDQ2-KHt zPxtw?qvDQt?A-pF9gw{vDgfOA-eYYohxYLZu~NM$an>FQ0zLuOt8m%={$#ikqC3pSJ8y|qcmXF3F8%uYvzxDp;l;6?%CW1iXrGoM1 z)jw)TXda>qTHPyZkd%zw;?oB>Unp88HDJEZkkNG5F{|dWNBrxK6?&Trs8ZG7sA+ts z0m1kZ7Jqx5FVE+!KJGO5oHked<@J9=LBg^L`l+l|RiR$NcaZSzH3rTe!$t%y2wcufx_ zyY7xiUj0F5H_~f&A5PIK-$^A`5^ua6BvzBKKd9RWfXBr@U_+5?3i7#!DmWN;DuEAp zuok#v6vC42-G^Lx3cO!iE0A2e4qIJqcDZB!Z~Vr(!hkUMncZk7Ya4-NCzbHJ*s{(A zAMCT_>Yfj=D;fLdYgGMtkIVAREGa>rnJ-=WX+=EBD?8}eRX#o{FzqVAQu&4UdN|Fy zj4N7fMH@#SA;U;$KfMI3e99autZ)OS9 z_XG(RW99q&*gp`TSG#%$Y@ zUjC2;@hnD4gTq&(naC_UGu38;=Is(=@yn@Akk5WEQ!Q{+gqY=lLTT1{V}}Hq$x@T^ zmj*lV+6oj!>}hE-eN{JI$rhotorZ-`k9#9oTm0*wz7M8BYse?)?4&-MM3e zakU^-LEK_+pmhY9b(d1Rde`pX^04!N*m~#azM`&c^cUM`*w{v6Ta9howr#618Z@?z z#%dZhXpF}8J$at@{q8r$y(9fA=@@69efC~!t~ux0`-D4Dit_$!<+=I&!NUU7nl6)} zf42hczG+}KE7O>IFTYw4Id1i@wRFG5)%v>`)}a{6V!xB6j7{=x^)=4;ocP6@fjj=Y zqyh-KfZGWJ$M}o+d5Vyb5Ql&R9|gX>8y$xyia_8X^HiDPHGe;odiJ)Pu;EhW%RmSe zTI`r03GE8iO2xk9;h8+Qvqyl;9=Vpy1L!{xGWWkak;1x%l`^odqbUojlrbIqr^SW$ z2mHVcech{7n_B(1(s!<><*@sAK-uHrbU&#V9pGne z{uNKYgJ~Ln!=(s~D}+!K;2@$+#>``uXbZ==|4tey0asOKPa0cKxYqjdg;#8uOsaZ& z0U=}Q>o)8L_q#@9=!u@8t^6ytf^s%t#|Ek`PZgjMq1G7 z;VU3`h{?&&aS|^My!w#RXwQz``>!?L^pNw$nFoNBwOeIBD1jSE?|nfB^pN^A8MDU; zrn}qQubEs<^QkmH)O+|$e*csEeti`1Vq#b~b7JK-rOP zTRf%;4?5rj&N!GTg_8X2b@CN-F(1Q}<2r7&`Sg~cK_B3C^1FJ5N$Z28H=#dmUb&Jg z?Kso9i7-hJ{0oG;JkIyoG`jRW-_@+=nXFD=uO(p&ski|O+ zcmc--wd>}wd3**@k)}(LgSZ?7>tvFMjp5j2Q1*85kE>kYg!yu(c9$c`8u-Lb&q;id z*JK^Y<&vXW5d3I;S*xOaBKy? zu83Ve(y?rV$-Xv`E`h&Jo7 z*CxQfUuV;QIT$L1QlUnbwk+qZ0gZm?f4u-B!!vw-gG{y4=00hoG-)!Ro|i?sGP&Gz zDdw_XFbLYTXpFszJPJ?!JVW{{DbV5ZG5ABvlEEjG6Y++p=jZQoxw;jq-vN~9HzMbh z-`_8Mz{!|$)P8rIkA#fO$ah&nw&{o%s3PyPv%2`B=Is(iwlujd6jg{Pccb2KVjQcs z3)uVe0;f$MQ|&+UjW*|fFDU{fm(7|4W-=Pb`?o}8SR-x1Ox~b6QYm`g-!X1?p!dQ7 zkplHGn$|9HJq)J_KJ+gtW*laqr&WE8C_qyh2Y zpAkpoIw`?V!OTke-x9Q2Dbi6>$HSU`WV|2xY(hF7A30>Pxa`AG<$I4?Iq0^(q>U2! zaOIxeK<|sWa7h9H<*2NO*<<6yjEUiO1*Nyw<6ItepyzqXyLsKy*9q4}gY4)C3V{d# zedDq!daz|&I^dHcpVw)%m!(W$;_KZV-RzY496-6CLW>=={q_C+`rF(2K?D=me&QgC zf#Xn;Brt=mdN0%89NIY2uGFMhM$n_;*MR#BFMwt5^lR=Kh0ApHChNq&?{+TYJ;xB( z#HXOa^r>&XSHlVu2giqpcij~43e@>CWy%$OMdHDhbgq|#l+ujS>}2t5L(*JfC{D8J znPE3|3IjCoe_ry`UAxX~{xCEcrMpZr#9@5NDBHj0H*fy@3>3Z+a?)AX8m=gFLuj7^&be_Ov$pLW?DzIKmKyZtGa}Bt+Q()78 z8W9{v(BHUF(esHYV6)T1f_4RLD|08l7BT?0sW<-{M>P}XRRob2W}t3OZQ{&2t-Np;|d?7M1w300q74jrkC(ODhLLuQi`W$?6m1@0gw6H5~kaOjEe&} z@uR`SYGuZJ%*~}bn6Jm;?((x@8L6LUul%5$lbvHHi3>B%{thJjh`uab+W+fAQb4sE z-?qrh>wbSL%fI{{!{}ezXtrPV>RH-g{5T=RnkHkn)={Bc^N-j6g-Y;xcwvSM!2T{E z0Ak8fy8LrO00VZ9Lcp8sLfK4}=BU%>uJb&NbcSyNe)}44&*M%z-_ys3QG5?~A{e-w zi8G$p2{|ozyg`75ve~e{Ztyyi_Iw&(Sf9#!Kj5M3Ime44aC7n2?GvHEuDAIK;4=Au_j_M| zhhG!&sMQfVGdr_fU@SA3iL*YjnME=GH1`eoMf8fsm&?flgXi|jAN3Eq{_wULW-iX- z!xf|flp8O=?) zeTt!1;F`e#7=0&`_kj=2GH|KS+uf2Rw%~QiQtELH0OJQ@81)^0;mdP9rV6fmY*u1T z0Fr-)g5TSfC^9eL3ej(b&krUjafG~ge-JjGm@<5K4Fn$09RF>sd%P2!KfdO+^1QC{ z@_3&aG+EyHKhFTj4~UaB>wbPV8nszmUh@xd7_^JYM$?Bofsvm&@RhmO!nJ8?0yrE| zVP{qm8;;`3mCi|CXn|a9D3`2H9gR=1WwU*@hK@HlKXy#~f?oe9B5d|=s5}_Zzbs4o z!ww70B-0x%3u#-WdWPsvMm`N*$zoF$%2Y)y`v$Re)tYOyc9^-a801K?PB+adMxn`D zSllf(+nl|vJ3u=_019=IT+h|~Jg-Bq*V1&Z{*gE9+~qDtz*?KpYh~JmO2ss=gJ$%4 zwOZY8fm#J{U4Zm`?A9?7__y60&(A(TXGnh5Z8e|DdAuHt#clN78&{=mblL%~j(t2b zLWr00a0OP!u!3MSaN>$8YrV?>GAKdt?(m1rQk7QsxR%~e91|%)&&{HgGJ& z$z!G#2bn}~=bZ6^mq7UX&X!J%d6mHTFuU;w`5fiN%{?B-^h7oK&BgR6n%1_V<8Wp?%=UB1_GR87sXxKwHKu*l!%&BrGv1cfYSCqVAU z!TAXknnWEP4JQUZNK%S7(UvZ@|6rD+7+(K{yt1`QcI}!Us_l?0|0}D~s6(cmu(2@)qGfT##sBgH_*kM^GS3@0G`- zyq13-S7~&&%>AZo2`X?c2Y$(etok;eU}^>yyN46u~bv ztOiVPUZ41XTo|v@0=c=}u||f5oQad>i(d>NSwb&VdHBuc&eNyxb9qK3kV~^F+{7hV zsQz@p$wFc(zpr-8)I?&9PheWt!kw(jyU9V$VJkvm3lAZ1Q66W4E(~_ji7j*WGk}^#O=8c>v zaC(}tK=#jk+G%)Fe7u}w1XE1Z=x6}+VUtLUoeh6B3K3`9z-dDf2f*g5ked# zM8ws^Y6X2D#g3P*erx)+FnHe`0CE80Kh z$$pI$bZjTXssBz1?2YQg_peMd8w+2-hcl#u3&wFT2aowrE-^N2?;%J@F7=1m&#xo9 zacz}Gl;N)?maxmzQ}8&4RR%`P%l0IGOL2oQ&{*{xsNODI99pL&P<+J_TWcoCe1yD4*(Nx;^*Nk%F!3C#$4i~%bPYIiQDx$<`pkC7mZZF z{U7Q%OdeC<=zMM?l=5t`5s$+7F)Wx^f)5kW%E*#>e$d&dO}a_^Z*(M2ZjwCF3r$QX z%OWpKVRXZM!P(I8lef2IG$G8aRU?-Ml+mDgx&6ms+3_@Ap2f5l9XBb|Vz|=&E%*8U zd3ne8_97X4k<(BT2N>ySG6#Y2hD(V*Jrv;~?3@DPR^q`I0M{)n_Pzf>BV-iQ;)_>d zPg{tA_ulVC(T+XU#N!ZCxbDyZA4T|f)-X(oqLi4HMlO%lH-W2+r*lmGIawR##YS6fL=+*rx**dyNeyt66R*@2bVuEr64HKLI98>b1QF*-&hhPsBnH6Wu}HCWto*q z9_re%DQSk2U$*j}_^ilIOm)C0@ZkVqpF@m$ZQP1M)R@NF*`}POL={5W0+w)c-Ye-n zsG%H5US7St&zQFO1ggxlk0j=QfX@)phjvO9mzvM61f7STzbJjaDFl^n@I;%ZOM`8? zSj2z_XQHf>sz3T;RWWy!@!p~TfgIF&CCh;C=v)P+b$^+)sZsA;UHRgFI?6QKf+&g1 zU;8X3m7NO6xWp1z<8Z1+@u_O_&Rh~%Mh!Pq)pva5gYvK=i~7!U%1;y-rp;902Mv5Q zFoj|!Rcw>9IJOCasZoDF!3X19e(0%j>}`ze0)?hY_R--4l8SLH+$6D)55}5B8Y*9$ zP^3cD5ykNW$+a?VFCGdTO4+xK$H35luOYU+EZ3k*#(<$Mv->BlyGhKSiHFWi{uff1 zu=0pUc)@AvU*e$oTM5%f30YJ!2yGE5)Fdl$1BqvisK)GH_v3XxH!Gujgm|dX-qI*k z8(N0-1}!PVf{sl6ni!XNyVU7*LL9;P;nFapo<2{(ZG6{d2fQA^#C)z8t-6tbU@vNz zY-Aa#ey})jnl-zoO0v#Br6roHn#aGTEv|q7%hBe}_1*nvkcCZ|m3~e+mH{?wFbFVt zh)vElq?H z2bz!?hKB{BGsgWY#8-cfzfHo^5yZxbA7iM3vjf`oN?c0;1pF0Vt4ioHKCO8kYR;4f zc_t-Dv>EO=F>&+Tht1?_HAgiAc2Rs55fJiEOd-0-C#7XSMt}nqDpw0q^{ToUQvNZ5 zPngTk2IIYZTsF&rmwcJR^!*C2va>~WeMs*pF@zFk77!!1p+6o?pu>FJAr;L}IgE(j zcyff?S5w9t%PpbgO;}4TeTF>aRgee*l>D^^SeGO9oiM#|GUnbXWB+ehiO9Fz!h;V; z_0_W&Rx`50r@$J3Bq_)dN;~_hND=3aBuz#+Dxmf|5i|COu=Bf3`#T#V-#j!s)a#;#?SKR%CUjpM35o)bj?FIf_M-c)p&`YJqGdQup6nkq>S zOZZ_I!7IhG!(*@zJ9oMfe;dy`n{FIeHTnfgSp`nq$6I8rYn0&#qa4XgtwmDRi=xo3 z>j^A8_(JX(v4!_xlM&-pzRxK~Jk-QC7EQj5>$2C{JPOtq`PmhnOjG(S@+_7;&>{88 z7_5AlR;W3${HIQdoSIl1l_41LhLHX~)JCkkpgap&R=1lfSUXOZRld@YxwMB@aKA+hmSOB?BSs#5w~!gZP~*<_OC zA-$SCrBNGKVRkL(5i+KH+kEOM+s0I7js|27EW7a(?cWuPE*`KD6s zm8aMS?!nA*S)(-G^j7=@>`2)kCIR-

+ +
+
+owyx +| + + +
+ +
+ + Ready to launch +
+
+ +
+
+
+