From aee84d07b2af8dde91cc5942025ca818b8b01565 Mon Sep 17 00:00:00 2001 From: Jayen Agrawal <69493224+JayAgra@users.noreply.github.com> Date: Thu, 8 Feb 2024 15:45:48 -0800 Subject: [PATCH] Game APIs & Swift apps v5.0.3 (#34) * game api start * add points and make bool avg f64 * resurrect passkey * game data storage * use method column instead of access ok * game data storage * its 2024 not 2023 * 5.0.2 login views * iOS apps v5.0.3 * remove main form for now --- .gitignore | 3 +- Cargo.toml | 1 + README.md | 33 +- data_auth.db | Bin 61440 -> 61440 bytes ios/bearTracks.xcodeproj/project.pbxproj | 40 ++- .../project.pbxproj | 22 +- .../AppIcon.appiconset/Contents.json | 2 +- .../AppIcon.appiconset/IMG_0804-2-2-3.jpeg | Bin 96532 -> 0 bytes .../AppIcon.appiconset/l0_icon1.png | Bin 0 -> 24414 bytes ios/beartracks-scout/EndView.swift | 13 +- ios/beartracks-scout/GameView.swift | 7 +- ios/beartracks-scout/LoginView.swift | 121 +++++-- ios/beartracks-scout/ReviewView.swift | 14 +- ios/beartracks-scout/ScoutingController.swift | 139 ++++---- ios/beartracks-scout/SettingsView.swift | 61 ++-- ios/beartracks-scout/StartView.swift | 81 ++--- ios/beartracks-scout/SubmitSheetView.swift | 61 ---- ios/beartracks-scout/TabBar.swift | 68 ---- .../beartracks-scout.entitlements | 10 + .../beartracks_scoutApp.swift | 53 ++- ios/beartracks/AppState.swift | 27 ++ .../AppIcon.appiconset/Contents.json | 2 +- .../AppIcon.appiconset/IMG_0804-2-2.jpeg | Bin 99118 -> 0 bytes .../AppIcon.appiconset/l0_icon2.png | Bin 0 -> 24345 bytes ios/beartracks/Info.plist | 6 +- ios/beartracks/LoginStateValidator.swift | 8 +- ios/beartracks/LoginView.swift | 126 +++++-- ios/beartracks/MatchList.swift | 2 +- ios/beartracks/SettingsView.swift | 65 +--- ios/beartracks/TabBar.swift | 110 ------ ios/beartracks/Teams.swift | 19 +- ios/beartracks/bearTracks.entitlements | 4 + ios/beartracks/beartracksApp.swift | 89 ++++- setup.sh | 1 + src/analyze.rs | 20 +- src/auth.rs | 24 +- src/db_auth.rs | 34 +- src/db_main.rs | 22 ++ src/forward.rs | 68 ++-- src/game_api.rs | 325 ++++++++++++++++++ src/main.rs | 270 ++++++++++++--- src/static_files.rs | 14 + src/stats.rs | 38 ++ static/blackjack.html | 4 +- static/create.html | 6 +- static/favicon.ico | Bin 14653 -> 5343 bytes static/index.html | 21 +- static/login.html | 2 +- static/main.html | 105 ++++++ static/passkey.html | 1 + static/pointRecords.html | 2 +- static/points.html | 2 +- static/public/css/float.css | 59 +--- static/public/css/float.min.css | 2 +- static/public/css/main_form.css | 71 ++++ static/public/css/main_form.min.css | 1 + static/public/js/form/form.js | 12 +- static/public/js/form/form.min.js | 2 +- static/public/js/form/form.ts | 10 +- static/public/js/homepage/homepage.js | 12 - static/public/js/homepage/homepage.min.js | 1 - static/public/js/homepage/homepage.ts | 12 - static/public/js/main/main.js | 77 +++++ static/public/js/main/main.ts | 85 +++++ static/scouts.html | 2 +- static/settings.html | 2 +- static/spin.html | 4 +- static/tos.html | 1 + 68 files changed, 1693 insertions(+), 806 deletions(-) delete mode 100644 ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2-3.jpeg create mode 100644 ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/l0_icon1.png delete mode 100644 ios/beartracks-scout/SubmitSheetView.swift delete mode 100644 ios/beartracks-scout/TabBar.swift create mode 100644 ios/beartracks-scout/beartracks-scout.entitlements create mode 100644 ios/beartracks/AppState.swift delete mode 100644 ios/beartracks/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2.jpeg create mode 100644 ios/beartracks/Assets.xcassets/AppIcon.appiconset/l0_icon2.png delete mode 100644 ios/beartracks/TabBar.swift create mode 100644 src/game_api.rs create mode 100644 src/stats.rs create mode 100644 static/main.html create mode 100644 static/passkey.html create mode 100644 static/public/css/main_form.css create mode 100644 static/public/css/main_form.min.css delete mode 100644 static/public/js/homepage/homepage.js delete mode 100644 static/public/js/homepage/homepage.min.js delete mode 100644 static/public/js/homepage/homepage.ts create mode 100644 static/public/js/main/main.js create mode 100644 static/public/js/main/main.ts create mode 100644 static/tos.html diff --git a/.gitignore b/.gitignore index a05b0ad2..026332e7 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ ssl/*.pem *!fastlane/Fastfile *!fastlane/Pluginfile *.xcbkptlist -*.xcuserstate \ No newline at end of file +*.xcuserstate +cache/* \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index c3e1872f..794d241a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ build = "build.rs" [dependencies] actix = "0.13.1" +actix-files = "0.6.5" actix-governor = "0.5.0" actix-http = "3.4" actix-identity = "0.4.0" diff --git a/README.md b/README.md index 202b94d1..fe98c058 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,32 @@ SEASONS + **EVENTS** is a comma separated list of all events the app should use
+ **SEASONS** is a comma separated list of all seasons this app has been used ### ssl -an ssl certificate is *required*, and must be placed in the ssl directory, with filenames `key.pem` and `cert.pem`. for local testing, one can be self-signed using the following command (run from the bearTracks directory created by setup.sh) +A ssl certificate is *required*, and must be placed in the ssl directory, with filenames `key.pem` and `cert.pem`. For local testing, one can be self-signed using the following command (run from the bearTracks directory created by setup.sh) ```sh openssl req -x509 -newkey rsa:4096 -nodes -keyout ./ssl/key.pem -out ./ssl/cert.pem -days 365 -subj '/CN=localhost' ``` +For use on production, replace `` with your domain, and run this with port 80 free. +```sh +# new certificate. run commands from ~/bearTracks +certbot certonly --standalone --keep-until-expiring --agree-tos -d "" +cp /etc/letsencrypt/live/.io/cert.pem ssl/cert.pem +cp /etc/letsencrypt/live/.io/privkey.pem ssl/key.pem +# renew certificate. run from ~/bearTracks +certbot renew +cp /etc/letsencrypt/live/.io/cert.pem ssl/cert.pem +cp /etc/letsencrypt/live/.io/privkey.pem ssl/key.pem +``` +### running server +To start the server from a ssh session, run the following command from the ~/bearTracks directory. +```sh +nohup ./bear_tracks & +``` +you may now exit the ssh session. +To stop bearTracks, run +```sh +./service.sh stop +``` + ## iOS & macOS apps @@ -38,13 +60,14 @@ The clients are broken into 3 apps- Data, Scout, and Manage. Manage is intended | iOS 17 | ✅ | ✅ | ✅ | | iOS 16 | ✅ | ❌ | ❌ | | macOS 14 | ✅ | ✅ | ✅ | -| macOS 11-13 | ✅ | ❌ | ❌ | -| App Store | ⌛ | ✅ | ❌ | +| macOS 13 | ✅ | ❌ | ❌ | +| App Store | ✅ | ✅ | ❌ | | Web | ⌛ | ❌ | ❌ | | Android | ❌ | ❌ | ❌ | -android users may use web (pwa) + +android users may use web [Data iOS](https://apps.apple.com/app/beartracks-data/id6475752596)
[Data macOS](https://apps.apple.com/app/beartracks-data/id6475752596)
-[Scout iOS](https://testflight.apple.com/join/0LzEHahN)
+[Scout iOS](https://apps.apple.com/app/beartracks-scout/id6476092907)
[Manage Xcode](https://github.com/JayAgra/bearTracks/tree/main/ios/beartracks-manage) \ No newline at end of file diff --git a/data_auth.db b/data_auth.db index d4cdffb9f7c477ebb148b45e75f664dfb18361b4..36115981c3b00744638dc04550f5b7a3eab621c2 100644 GIT binary patch delta 653 zcmZp8z})bFd4jZ{6$1kUKNPb9>8go3#+p_PdfpRxxmPf7axydXv2pF>UBH{ovy;1= zlbMHs`znt%2y*0bzQ@69#Jz&?99WlYNn%n?YH?vsQhZ5jZb7rL z6T7&$IAa?`ytFvAs2EIeO=jghh-&7=$ve5;v+-y%=)w(V<2M4U=HuC@>B1(C5a)%6 z^JqFFiSn>=^Im1>n_R$Q$I1g_c~2JLvEu}ZaR5VvVe?KNPi4Mq49xr|nD{^NpWuJY zziG38!6JSe{%Z_k9B?bv`{PnLGqUSZ&CSfR5-Y2fk`s$kij}OQEkQsBL|A}H z^H?3FjKsVY98%?(c|ctTI!ZbD#l@)*W=STLk(6H%pPXNsR{~T~tCCohK6#eEw6AHl zcV=c`ZfQuQvw41|lcRrGSZTPUijjq*Z%#!)T5zFhMzVXjf0kQzv5BFhL9SbVdZMFG ziF2WaW1gFHWxAwpgz&m~pZm6d=9pG2s9UDB#+sH4dfpRxxi2$tavWghW8>P%yMQ;F<2An>%F_>VTEX#Qi)98zncXGXF)3io1gpJn-tb>pDD#J5pS+LPlx%mZ}RBhPB z^&Rcm#6$HR9ofWz4$_%Ck4H$81E??y=y8T7K|6MFSy{$rh~))|#l_jFmBlccYw}GV z1EEGo2cR+fj7^4M7XtmTc_)vjGT%c6X8sdQ{2%zQ@t@#7v{}Gl5&y&h9s@0o;zFR& z${fW!(#*2_FtZFeC78we!R|BwO7n8UBsRaZmkQV{9PkFDn~e+PEP>5}0q;Ou9$qjP z7+v%E?SKJq#9trJ#LeK#D6Pz-t}f1zA7SF|?q`-6X6X~|WA5VVT$W$v=^vF_oRn^1 zmYosARFayQYi?%dl~}3Zm|m1vo|wb*&(Pe!z|7FX+`_=p!W_ggH!w8>bJ7xXic{km zkt{IEGWNBI$_>j3%y#v3&-O8M&I}4ObEz!!DGhhFNQ(-^V}rScrKP!%A;bm~BQOVS W!=?lL3Y4R diff --git a/ios/bearTracks.xcodeproj/project.pbxproj b/ios/bearTracks.xcodeproj/project.pbxproj index 0f5c8f01..5aa23a3a 100644 --- a/ios/bearTracks.xcodeproj/project.pbxproj +++ b/ios/bearTracks.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + F5081BA22B741D15001497DB /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5081BA12B741D15001497DB /* AppState.swift */; }; F540A13D2B549D2500611384 /* TeamView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F540A13C2B549D2500611384 /* TeamView.swift */; }; F540A13F2B549D2E00611384 /* TeamViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F540A13E2B549D2E00611384 /* TeamViewModel.swift */; }; F54E76C22B527D96003C65A2 /* bearTracksApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = F54E76C12B527D96003C65A2 /* bearTracksApp.swift */; }; @@ -18,7 +19,6 @@ F5AE2E4C2B527E050033DB0D /* DataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E452B527E050033DB0D /* DataView.swift */; }; F5AE2E532B527E170033DB0D /* Teams.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E4D2B527E170033DB0D /* Teams.swift */; }; F5AE2E542B527E170033DB0D /* SettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E4E2B527E170033DB0D /* SettingsManager.swift */; }; - F5AE2E552B527E170033DB0D /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E4F2B527E170033DB0D /* TabBar.swift */; }; F5AE2E582B527E170033DB0D /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E522B527E170033DB0D /* SettingsView.swift */; }; F5AE2E5A2B5288FB0033DB0D /* URLSessionConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E592B5288FB0033DB0D /* URLSessionConfiguration.swift */; }; F5AE2E5C2B52FD430033DB0D /* LoginStateValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AE2E5B2B52FD430033DB0D /* LoginStateValidator.swift */; }; @@ -49,6 +49,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + F5081BA12B741D15001497DB /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = ""; }; F540A13C2B549D2500611384 /* TeamView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamView.swift; sourceTree = ""; }; F540A13E2B549D2E00611384 /* TeamViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TeamViewModel.swift; sourceTree = ""; }; F54E76BE2B527D96003C65A2 /* bearTracks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = bearTracks.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -61,7 +62,6 @@ F5AE2E452B527E050033DB0D /* DataView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DataView.swift; path = bearTracks/DataView.swift; sourceTree = SOURCE_ROOT; }; F5AE2E4D2B527E170033DB0D /* Teams.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Teams.swift; sourceTree = ""; }; F5AE2E4E2B527E170033DB0D /* SettingsManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsManager.swift; sourceTree = ""; }; - F5AE2E4F2B527E170033DB0D /* TabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; F5AE2E522B527E170033DB0D /* SettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; F5AE2E592B5288FB0033DB0D /* URLSessionConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLSessionConfiguration.swift; sourceTree = ""; }; F5AE2E5B2B52FD430033DB0D /* LoginStateValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginStateValidator.swift; sourceTree = ""; }; @@ -100,8 +100,9 @@ F54E76C02B527D96003C65A2 /* bearTracks */ = { isa = PBXGroup; children = ( - F5D3D3452B5A17AE00A88A00 /* Info.plist */, F5D3D3402B5A098D00A88A00 /* bearTracks.entitlements */, + F5D3D3452B5A17AE00A88A00 /* Info.plist */, + F5081BA12B741D15001497DB /* AppState.swift */, F54E76C12B527D96003C65A2 /* bearTracksApp.swift */, F5AE2E452B527E050033DB0D /* DataView.swift */, F5AE2E442B527E050033DB0D /* DataViewModel.swift */, @@ -111,7 +112,6 @@ F5AE2E3F2B527E050033DB0D /* MatchList.swift */, F5AE2E4E2B527E170033DB0D /* SettingsManager.swift */, F5AE2E522B527E170033DB0D /* SettingsView.swift */, - F5AE2E4F2B527E170033DB0D /* TabBar.swift */, F5AE2E4D2B527E170033DB0D /* Teams.swift */, F540A13C2B549D2500611384 /* TeamView.swift */, F540A13E2B549D2E00611384 /* TeamViewModel.swift */, @@ -212,8 +212,8 @@ F5AE2E542B527E170033DB0D /* SettingsManager.swift in Sources */, F5AE2E5C2B52FD430033DB0D /* LoginStateValidator.swift in Sources */, F5AE2E4B2B527E050033DB0D /* DataViewModel.swift in Sources */, + F5081BA22B741D15001497DB /* AppState.swift in Sources */, F540A13D2B549D2500611384 /* TeamView.swift in Sources */, - F5AE2E552B527E170033DB0D /* TabBar.swift in Sources */, F5AE2E4C2B527E050033DB0D /* DataView.swift in Sources */, F5AE2E462B527E050033DB0D /* MatchList.swift in Sources */, ); @@ -274,7 +274,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; @@ -331,7 +331,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 17.0; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; @@ -350,27 +350,32 @@ CODE_SIGN_ENTITLEMENTS = bearTracks/bearTracks.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"bearTracks/Preview Content\""; DEVELOPMENT_TEAM = D6MFYYVHA8; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = bearTracks/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bearTracks; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Jayen Agrawal. All rights reserved."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UILaunchStoryboardName = ""; INFOPLIST_KEY_UIStatusBarStyle = ""; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.jayagra.beartracks; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,6"; @@ -386,27 +391,32 @@ CODE_SIGN_ENTITLEMENTS = bearTracks/bearTracks.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"bearTracks/Preview Content\""; DEVELOPMENT_TEAM = D6MFYYVHA8; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = bearTracks/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = bearTracks; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2024 Jayen Agrawal. All rights reserved."; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UILaunchStoryboardName = ""; INFOPLIST_KEY_UIStatusBarStyle = ""; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; + IPHONEOS_DEPLOYMENT_TARGET = 16.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.jayagra.beartracks; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2,6"; diff --git a/ios/beartracks-scout.xcodeproj/project.pbxproj b/ios/beartracks-scout.xcodeproj/project.pbxproj index d008f718..92f860c5 100644 --- a/ios/beartracks-scout.xcodeproj/project.pbxproj +++ b/ios/beartracks-scout.xcodeproj/project.pbxproj @@ -7,7 +7,6 @@ objects = { /* Begin PBXBuildFile section */ - F509F6B52B54D7A8006FD9D5 /* TabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F509F6B42B54D7A8006FD9D5 /* TabBar.swift */; }; F509F6B72B54D7EA006FD9D5 /* StartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F509F6B62B54D7EA006FD9D5 /* StartView.swift */; }; F509F6B92B54D802006FD9D5 /* GameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F509F6B82B54D802006FD9D5 /* GameView.swift */; }; F509F6BB2B54D809006FD9D5 /* EndView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F509F6BA2B54D809006FD9D5 /* EndView.swift */; }; @@ -22,11 +21,9 @@ F565840D2B54D52A00F587C0 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F565840C2B54D52A00F587C0 /* Assets.xcassets */; }; F56584102B54D52A00F587C0 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F565840F2B54D52A00F587C0 /* Preview Assets.xcassets */; }; F5AD47CC2B54FF0500345122 /* ReviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AD47CB2B54FF0500345122 /* ReviewView.swift */; }; - F5AD47CE2B55050E00345122 /* SubmitSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5AD47CD2B55050E00345122 /* SubmitSheetView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - F509F6B42B54D7A8006FD9D5 /* TabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBar.swift; sourceTree = ""; }; F509F6B62B54D7EA006FD9D5 /* StartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartView.swift; sourceTree = ""; }; F509F6B82B54D802006FD9D5 /* GameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameView.swift; sourceTree = ""; }; F509F6BA2B54D809006FD9D5 /* EndView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EndView.swift; sourceTree = ""; }; @@ -41,8 +38,8 @@ F56584082B54D52900F587C0 /* beartracks_scoutApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = beartracks_scoutApp.swift; sourceTree = ""; }; F565840C2B54D52A00F587C0 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; F565840F2B54D52A00F587C0 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + F58565C32B7572B400C1606E /* beartracks-scout.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "beartracks-scout.entitlements"; sourceTree = ""; }; F5AD47CB2B54FF0500345122 /* ReviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReviewView.swift; sourceTree = ""; }; - F5AD47CD2B55050E00345122 /* SubmitSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubmitSheetView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -75,6 +72,7 @@ F56584072B54D52900F587C0 /* beartracks-scout */ = { isa = PBXGroup; children = ( + F58565C32B7572B400C1606E /* beartracks-scout.entitlements */, F56584082B54D52900F587C0 /* beartracks_scoutApp.swift */, F509F6BA2B54D809006FD9D5 /* EndView.swift */, F509F6B82B54D802006FD9D5 /* GameView.swift */, @@ -86,8 +84,6 @@ F509F6BE2B54D8F2006FD9D5 /* SettingsManager.swift */, F509F6BC2B54D810006FD9D5 /* SettingsView.swift */, F509F6B62B54D7EA006FD9D5 /* StartView.swift */, - F5AD47CD2B55050E00345122 /* SubmitSheetView.swift */, - F509F6B42B54D7A8006FD9D5 /* TabBar.swift */, F509F6C02B54D9C0006FD9D5 /* URLSessionConfiguration.swift */, F565840C2B54D52A00F587C0 /* Assets.xcassets */, F565840E2B54D52A00F587C0 /* Preview Content */, @@ -177,8 +173,6 @@ F509F6C12B54D9C0006FD9D5 /* URLSessionConfiguration.swift in Sources */, F509F6BB2B54D809006FD9D5 /* EndView.swift in Sources */, F509F6C92B54E554006FD9D5 /* PressModifier.swift in Sources */, - F5AD47CE2B55050E00345122 /* SubmitSheetView.swift in Sources */, - F509F6B52B54D7A8006FD9D5 /* TabBar.swift in Sources */, F5AD47CC2B54FF0500345122 /* ReviewView.swift in Sources */, F509F6BF2B54D8F2006FD9D5 /* SettingsManager.swift in Sources */, F509F6C32B54D9DA006FD9D5 /* LoginStateValidator.swift in Sources */, @@ -317,13 +311,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "beartracks-scout/beartracks-scout.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"beartracks-scout/Preview Content\""; DEVELOPMENT_TEAM = D6MFYYVHA8; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = Scout; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -335,7 +331,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.0.3; PRODUCT_BUNDLE_IDENTIFIER = "com.jayagra.beartracks-scout"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -349,13 +345,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = "beartracks-scout/beartracks-scout.entitlements"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 10; + CURRENT_PROJECT_VERSION = 12; DEVELOPMENT_ASSET_PATHS = "\"beartracks-scout/Preview Content\""; DEVELOPMENT_TEAM = D6MFYYVHA8; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = Scout; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -367,7 +365,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 5.0.1; + MARKETING_VERSION = 5.0.3; PRODUCT_BUNDLE_IDENTIFIER = "com.jayagra.beartracks-scout"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; diff --git a/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/Contents.json index 8b5650e1..3f620ad8 100644 --- a/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "IMG_0804-2-2-3.jpeg", + "filename" : "l0_icon1.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2-3.jpeg b/ios/beartracks-scout/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2-3.jpeg deleted file mode 100644 index c47e0212e8bc6db3e08d687a3d63abe8aeba6ef1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96532 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%0A2~UeXqLv!&cu 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 XU+fCIftE@F{xe%;Wps5V^QZp<^5)h> literal 0 HcmV?d00001 diff --git a/ios/beartracks-scout/EndView.swift b/ios/beartracks-scout/EndView.swift index 3d36409e..157f75eb 100644 --- a/ios/beartracks-scout/EndView.swift +++ b/ios/beartracks-scout/EndView.swift @@ -8,7 +8,7 @@ import SwiftUI struct EndView: View { - @ObservedObject var controller: ScoutingController + @EnvironmentObject var controller: ScoutingController @State private var scoreTrap: Bool = false @State private var chainClimb: Bool = false @State private var buddyClimb: Bool = false @@ -16,13 +16,6 @@ struct EndView: View { @State private var driving: String = "" @State private var overall: String = "" - init(controller: ScoutingController) { - self.controller = controller - self.defense = controller.getDefenseResponse() - self.driving = controller.getDrivingResponse() - self.overall = controller.getOverallResponse() - } - func loadPane() { self.defense = controller.getDefenseResponse() self.driving = controller.getDrivingResponse() @@ -96,7 +89,7 @@ struct EndView: View { Spacer() } .onAppear() { - if controller.getTeamNumber() == "" || controller.getMatchNumber() == "" { + if controller.getTeamNumber() == "--" || controller.getMatchNumber() == "--" { controller.advanceToTab(tab: .start) } else { loadPane() @@ -108,5 +101,5 @@ struct EndView: View { } #Preview { - EndView(controller: ScoutingController()) + EndView() } diff --git a/ios/beartracks-scout/GameView.swift b/ios/beartracks-scout/GameView.swift index fc4d87c6..0edaa7a1 100644 --- a/ios/beartracks-scout/GameView.swift +++ b/ios/beartracks-scout/GameView.swift @@ -8,7 +8,7 @@ import SwiftUI struct GameView: View { - @ObservedObject var controller: ScoutingController + @EnvironmentObject var controller: ScoutingController var body: some View { VStack { @@ -82,12 +82,13 @@ struct GameView: View { .buttonStyle(.bordered) Text("match \(controller.getMatchNumber()) • team \(controller.getTeamNumber())") .frame(maxWidth: .infinity, alignment: .center) + .padding(.top) } .navigationTitle("Match Scouting") } } .onAppear() { - if controller.getTeamNumber() == "" || controller.getMatchNumber() == "" { + if controller.getTeamNumber() == "--" || controller.getMatchNumber() == "--" { controller.advanceToTab(tab: .start) } } @@ -95,5 +96,5 @@ struct GameView: View { } #Preview { - GameView(controller: ScoutingController()) + GameView() } diff --git a/ios/beartracks-scout/LoginView.swift b/ios/beartracks-scout/LoginView.swift index 4140197e..a4df9e1f 100644 --- a/ios/beartracks-scout/LoginView.swift +++ b/ios/beartracks-scout/LoginView.swift @@ -9,32 +9,91 @@ import SwiftUI struct LoginView: View { @State private var showAlert = false - @State private var username = "" - @State private var password = "" + @State private var authData: [String] = ["", "", "", ""] @State private var alertMessage = "" - @Environment(\.dismiss) var dismiss + @State private var loading = false + @State private var create = false + @EnvironmentObject var controller: ScoutingController var body: some View { VStack { Text("bearTracks") .font(.title) - Text("v5.0.0 • 2024") - TextField("Username", text: $username) - .padding() - .textFieldStyle(RoundedBorderTextFieldStyle()) - SecureField("Password", text: $password) - .padding() - .textFieldStyle(RoundedBorderTextFieldStyle()) - Button("Login") { - login() + Text("v5.0.3 • 2024") + if !loading { + if !create { + Text("log in") + .font(.title3) + .padding(.top) + TextField("username", text: $authData[0]) + .padding([.leading, .trailing, .bottom]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.username) + SecureField("password", text: $authData[1]) + .padding() + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.password) + Button("login") { + authAction(type: "login", data: ["username": authData[0], "password": authData[1]]) + } + .padding() + .font(.title3) + .buttonStyle(.bordered) + Button("create") { + self.create = true + } + } else { + Text("create account") + .font(.title3) + .padding(.top) + TextField("team code", text: $authData[3]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .keyboardType(.numberPad) + .onChange(of: authData[3]) { _ in + authData[3] = String(authData[3].prefix(5)) + } + TextField("full name", text: $authData[2]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .textContentType(.name) + TextField("username", text: $authData[0]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.username) + SecureField("password", text: $authData[1]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.newPassword) + Button("create") { + authAction(type: "create", data: ["access": authData[3], "full_name": authData[2], "username": authData[0], "password": authData[1]]) + } + .padding() + .font(.title3) + .buttonStyle(.bordered) + Button("login") { + self.create = false + } + } + } else { + Spacer() + ProgressView() + .controlSize(.large) + .padding() + Spacer() } - .padding() - .font(.title3) - .buttonStyle(.bordered) } .padding() .alert(isPresented: $showAlert, content: { - Alert ( + Alert( title: Text("Auth Error"), message: Text(alertMessage), dismissButton: .default(Text("ok")) @@ -42,38 +101,40 @@ struct LoginView: View { }) } - private func login() { - guard let url = URL(string: "https://beartracks.io/api/v1/auth/login") else { - return - } - - let credentials = ["username": username, "password": password] - + private func authAction(type: String, data: Dictionary) { + loading = true + guard let url = URL(string: "https://beartracks.io/api/v1/auth/\(type)") else { return } do { - let jsonData = try JSONSerialization.data(withJSONObject: credentials) - + let jsonData = try JSONSerialization.data(withJSONObject: data) var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData request.httpShouldHandleCookies = true - - sharedSession.dataTask(with: request) { _data, response, error in - if let _data = _data { + sharedSession.dataTask(with: request) { data, response, error in + if data != nil { if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode == 200 { - dismiss() + controller.loginRequired = false + loading = false } else { + loading = false showAlert = true - alertMessage = "bad credentials" + if type == "login" { + alertMessage = "bad credentials" + } else { + alertMessage = "creation failed" + } } } } else { + loading = false showAlert = true alertMessage = "network error" } }.resume() } catch { + loading = false showAlert = true alertMessage = "failed to serialize auth object" } diff --git a/ios/beartracks-scout/ReviewView.swift b/ios/beartracks-scout/ReviewView.swift index 03ff4483..46fbe089 100644 --- a/ios/beartracks-scout/ReviewView.swift +++ b/ios/beartracks-scout/ReviewView.swift @@ -8,7 +8,7 @@ import SwiftUI struct ReviewView: View { - @ObservedObject var controller: ScoutingController + @EnvironmentObject var controller: ScoutingController @State private var submitSheetState: SubmitSheetType = .waiting @State private var showSheet: Bool = false @@ -16,12 +16,11 @@ struct ReviewView: View { VStack { NavigationStack { VStack { + Text("Match \(controller.getMatchNumber()) • Team \(controller.getTeamNumber())") + .padding(.leading) + .frame(maxWidth: .infinity, alignment: .leading) ScrollView { LazyVStack { - Text("Match \(controller.getMatchNumber()) • Team \(controller.getTeamNumber())") - .font(.caption) - .padding() - .frame(maxWidth: .infinity, alignment: .leading) Text("Cycles") .font(.title2) .padding() @@ -94,7 +93,6 @@ struct ReviewView: View { .padding() } } - Button("submit") { showSheet = true controller.submitData { result in @@ -153,7 +151,7 @@ struct ReviewView: View { } } .onAppear() { - if controller.getTeamNumber() == "" || controller.getMatchNumber() == "" { + if controller.getTeamNumber() == "--" || controller.getMatchNumber() == "--" { controller.advanceToTab(tab: .start) } else { if controller.getDefenseResponse() == "" || controller.getDrivingResponse() == "" || controller.getOverallResponse() == "" { @@ -168,5 +166,5 @@ struct ReviewView: View { } #Preview { - ReviewView(controller: ScoutingController()) + ReviewView() } diff --git a/ios/beartracks-scout/ScoutingController.swift b/ios/beartracks-scout/ScoutingController.swift index c3f55206..97559520 100644 --- a/ios/beartracks-scout/ScoutingController.swift +++ b/ios/beartracks-scout/ScoutingController.swift @@ -9,12 +9,15 @@ import Foundation import UIKit class ScoutingController: ObservableObject { + // login state + @Published public var loginRequired: Bool = false // tab selection @Published public var currentTab: Tab = .start // basic meta private var eventCode: String = UserDefaults.standard.string(forKey: "eventCode") ?? "CAFR" - private var matchNumber: String = "" - private var teamNumber: String = "" + @Published public var matchNumber: String = "--" + @Published public var teamNumber: String = "--" + @Published public var matchList: [MatchData] = [] // match buttons @Published private(set) var times: [Double] = [0, 0, 0] private var startMillis: [Double] = [0, 0, 0] @@ -32,68 +35,27 @@ class ScoutingController: ObservableObject { private var submitSheetDetails: String = "" // getters - - func getMatchNumber() -> String { - return self.matchNumber - } - - func getTeamNumber() -> String { - return self.teamNumber - } - - func getDefenseResponse() -> String { - return self.defense - } - - func getDrivingResponse() -> String { - return self.driving - } - - func getOverallResponse() -> String { - return self.overall - } - - func getMatchTimes() -> [MatchTime] { - return self.matchTimes - } - - func getSubmitSheetMessage() -> String { - return self.submitSheetMessage - } - - func getSubmitSheetDetails() -> String { - return self.submitSheetDetails - } - + func getMatchNumber() -> String { return self.matchNumber } + func getTeamNumber() -> String { return self.teamNumber } + func getDefenseResponse() -> String { return self.defense } + func getDrivingResponse() -> String { return self.driving } + func getOverallResponse() -> String { return self.overall } + func getMatchTimes() -> [MatchTime] { return self.matchTimes } + func getSubmitSheetMessage() -> String { return self.submitSheetMessage } + func getSubmitSheetDetails() -> String { return self.submitSheetDetails } + // setters - - func setMatchNumber(match: String) { - self.matchNumber = match - } - - func setTeamNumber(team: String) { - self.teamNumber = team - } - - func setDefenseResponse(response: String) { - self.defense = response - } - - func setDrivingResponse(response: String) { - self.driving = response - } - - func setOverallResponse(response: String) { - self.overall = response - } + func setMatchNumber(match: String) { self.matchNumber = match } + func setTeamNumber(team: String) { self.teamNumber = team } + func setDefenseResponse(response: String) { self.defense = response } + func setDrivingResponse(response: String) { self.driving = response } + func setOverallResponse(response: String) { self.overall = response } // functional functions - func advanceToTab(tab: Tab) { - currentTab = tab - } + func advanceToTab(tab: Tab) { currentTab = tab } func advanceToGame() { - if matchNumber != "" && teamNumber != "" && currentTab == .start { + if matchNumber != "--" && teamNumber != "--" && currentTab == .start { currentTab = .game } } @@ -139,18 +101,14 @@ class ScoutingController: ObservableObject { } func submitData(completionBlock: @escaping (SubmitSheetType) -> Void) { - guard let url = URL(string: "https://beartracks.io/api/v1/data/submit") else { - return - } - + guard let url = URL(string: "https://beartracks.io/api/v1/data/submit") else { return } var encodedMatchTimes: String = "" do { encodedMatchTimes = try String(data: JSONEncoder().encode(matchTimes), encoding: .utf8) ?? "" } catch { - print("serialization error") + encodedMatchTimes = "" } let matchData = ScoutingDataExport(season: 2024, event: eventCode, match_num: Int(matchNumber) ?? 0, level: "Qualification", team: Int(teamNumber) ?? 0, game: encodedMatchTimes, defend: defense, driving: driving, overall: overall) - do { let jsonData = try JSONEncoder().encode(matchData) var request = URLRequest(url: url) @@ -165,15 +123,12 @@ class ScoutingController: ObservableObject { if httpResponse.statusCode == 200 { completionBlock(.done) } else { - print("server non-successful response") completionBlock(.error) } } else { - print("parse error") completionBlock(.error) } } else { - print("fetch error: \(String(describing: error))") completionBlock(.error) } } @@ -181,12 +136,35 @@ class ScoutingController: ObservableObject { } catch { completionBlock(.error) } - + } + + func getMatches(completionBlock: @escaping ([MatchData]) -> Void) { + guard let url = URL(string: "https://beartracks.io/api/v1/events/matches/\(UserDefaults.standard.string(forKey: "season") ?? "2024")/\(UserDefaults.standard.string(forKey: "eventCode") ?? "CAFR")/qualification/true") else { return } + var request = URLRequest(url: url) + request.httpMethod = "GET" + request.httpShouldHandleCookies = true + let requestTask = sharedSession.dataTask(with: request) { + (data: Data?, response: URLResponse?, error: Error?) in + if let data = data { + do { + let decoder = JSONDecoder() + let result = try decoder.decode(MatchData.self, from: data) + DispatchQueue.main.async { + completionBlock([result]) + } + } catch { + completionBlock([]) + } + } else { + completionBlock([]) + } + } + requestTask.resume() } func resetControllerData() { - self.matchNumber = "" - self.teamNumber = "" + self.matchNumber = "--" + self.teamNumber = "--" self.times = [0, 0, 0] self.startMillis = [0, 0, 0] self.buttonPressed = [false, false, false] @@ -220,3 +198,22 @@ struct MatchTime: Codable { let travel: Double let outtake: Double } + +struct MatchData: Codable { + let Schedule: [Match] +} + +struct Match: Codable { + let description: String + let startTime: String + let matchNumber: Int + let field: String + let tournamentLevel: String + let teams: [Team] +} + +struct Team: Codable { + let teamNumber: Int + let station: String + let surrogate: Bool +} diff --git a/ios/beartracks-scout/SettingsView.swift b/ios/beartracks-scout/SettingsView.swift index 35bc639a..58d8544b 100644 --- a/ios/beartracks-scout/SettingsView.swift +++ b/ios/beartracks-scout/SettingsView.swift @@ -13,13 +13,13 @@ struct SettingsView: View { @State private var darkMode: Bool = UserDefaults.standard.bool(forKey: "darkMode") @State private var showAlert = false @State private var settingsOptions: [DataMetadata] = [] - @Binding var loginRequired: Bool + @EnvironmentObject var controller: ScoutingController var body: some View { NavigationStack { - ScrollView { - VStack { - HStack { + VStack { + Form { + Section { Picker("Event Code", selection: $eventCodeInput) { if !settingsOptions.isEmpty { ForEach(settingsOptions[0].events, id: \.self) { event_code in @@ -32,14 +32,12 @@ struct SettingsView: View { } } .pickerStyle(.menu) - .padding() - Spacer() - Button("Save") { + .onChange(of: eventCodeInput) { _ in saveEventCode() + controller.getMatches { result in + controller.matchList = result + } } - .padding() - } - HStack { Picker("Season", selection: $seasonInput) { if !settingsOptions.isEmpty { ForEach(settingsOptions[0].seasons, id: \.self) { season in @@ -52,34 +50,37 @@ struct SettingsView: View { } } .pickerStyle(.menu) - .padding() - Spacer() - Button("Save") { + .onChange(of: seasonInput) { _ in saveSeason() + controller.getMatches { result in + controller.matchList = result + } } - .padding() + Toggle("Dark Mode", isOn: $darkMode) + .onChange(of: darkMode) { _ in + UserDefaults.standard.set(darkMode, forKey: "darkMode") + showAlert = true + } } - HStack { - Toggle(isOn: $darkMode) { - Label("Dark Mode", systemImage: "moon.fill") + Section { + Button("Clear Cache") { + URLCache.shared.removeAllCachedResponses() } - .padding() - .onChange(of: darkMode) { _ in - UserDefaults.standard.set(darkMode, forKey: "darkMode") - showAlert = true - } - } - HStack { Button("Log Out") { if let cookies = HTTPCookieStorage.shared.cookies(for: sharedSession.configuration.urlCache?.cachedResponse(for: URLRequest(url: URL(string: "https://beartracks.io")!))?.response.url ?? URL(string: "https://beartracks.io")!) { for cookie in cookies { sharedSession.configuration.httpCookieStorage?.deleteCookie(cookie) } - loginRequired = true + controller.loginRequired = true } } .foregroundStyle(Color.pink) - .buttonStyle(.bordered) + } + Section { + Text("This application is used to submit scouting data to bearTracks. To view this data, install the [data viewer](https://apps.apple.com/us/app/beartracks-data/id6475752596). The data viewer may only be used by users registered with a team (i.e. team code was not 00000). Team registration is free- to register your team or add yourself to a team after account creation, send an email to [admin@beartracks.io](mailto:admin@beartracks.io).") + .font(.footnote) + Text("To delete or update account information, please email [admin@beartracks.io](mailto:admin@beartracks.io).") + .font(.footnote) } } } @@ -108,14 +109,10 @@ struct SettingsView: View { } func loadSettingsJson(completionBlock: @escaping ([DataMetadata]) -> Void) -> Void { - guard let url = URL(string: "https://beartracks.io/api/v1/data") else { - return - } - + guard let url = URL(string: "https://beartracks.io/api/v1/data") else { return } var request = URLRequest(url: url) request.httpMethod = "GET" request.httpShouldHandleCookies = true - let requestTask = sharedSession.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in if let data = data { @@ -141,7 +138,7 @@ struct SettingsView: View { struct SettingsView_Preview: PreviewProvider { @State static var loginReq = false static var previews: some View { - SettingsView(loginRequired: $loginReq) + SettingsView() } } diff --git a/ios/beartracks-scout/StartView.swift b/ios/beartracks-scout/StartView.swift index 55110166..002d7365 100644 --- a/ios/beartracks-scout/StartView.swift +++ b/ios/beartracks-scout/StartView.swift @@ -8,68 +8,59 @@ import SwiftUI struct StartView: View { - @ObservedObject var controller: ScoutingController - @State private var matchNumber: String = "" - @State private var teamNumber: String = "" + @EnvironmentObject var controller: ScoutingController @FocusState private var focusField: Bool - func loadPane() { - self.matchNumber = controller.getMatchNumber() - self.teamNumber = controller.getTeamNumber() - } - var body: some View { VStack { NavigationStack { VStack { - LazyVStack { - Text("Match Number") - .padding([.leading, .top]) - .frame(maxWidth: .infinity, alignment: .leading) - TextField("required", text: $matchNumber) - .focused($focusField) - .submitLabel(.done) - .keyboardType(.numberPad) - .toolbar { - ToolbarItem(placement: .keyboard) { - HStack { - Spacer() - Button("Done") { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder),to: nil, from: nil, for: nil) - } + Form { + Section { + Text("\(UserDefaults.standard.string(forKey: "eventCode") ?? "CAFR") (\(UserDefaults.standard.string(forKey: "season") ?? "2024"))") + } + Section { + Picker("Match Number", selection: $controller.matchNumber) { + Text("SELECT") + .tag("--") + .disabled(true) + if !controller.matchList.isEmpty && !controller.matchList[0].Schedule.isEmpty { + ForEach(0...controller.matchList[0].Schedule.count, id: \.self) { id in + Text(String(id + 1)) + .tag(String(id + 1)) + } + } + } + .pickerStyle(.menu) + .onChange(of: controller.matchNumber) { _ in + controller.teamNumber = "--" + } + Picker("Team Number", selection: $controller.teamNumber) { + Text("SELECT") + .tag("--") + .disabled(true) + if !controller.matchList.isEmpty && !controller.matchList[0].Schedule.isEmpty { + ForEach(controller.matchList[0].Schedule[(Int(controller.matchNumber) ?? 1) - 1].teams, id: \.teamNumber) { team_entry in + Text(String(team_entry.teamNumber)) + .tag(String(team_entry.teamNumber)) } } } - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding([.leading, .trailing]) - - Text("Team Number") - .padding([.leading, .top]) - .frame(maxWidth: .infinity, alignment: .leading) - TextField("required", text: $teamNumber) - .focused($focusField) - .submitLabel(.done) - .keyboardType(.numberPad) - .textFieldStyle(RoundedBorderTextFieldStyle()) - .padding([.leading, .trailing, .bottom]) - - Button("continue") { - controller.setMatchNumber(match: matchNumber) - controller.setTeamNumber(team: teamNumber) - controller.advanceToGame() + .pickerStyle(.menu) + } + Section { + Button("continue") { + controller.advanceToGame() + } } - .padding() - .buttonStyle(.bordered) } } .navigationTitle("Match Scouting") } } - .onAppear() { - loadPane() - } } } #Preview { - StartView(controller: ScoutingController()) + StartView() } diff --git a/ios/beartracks-scout/SubmitSheetView.swift b/ios/beartracks-scout/SubmitSheetView.swift deleted file mode 100644 index a881b993..00000000 --- a/ios/beartracks-scout/SubmitSheetView.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// SubmitSheetView.swift -// beartracks-scout -// -// Created by Jayen Agrawal on 1/14/24. -// - -import SwiftUI - -struct SubmitSheetView: View { - @StateObject var controller: ScoutingController - - var body: some View { - switch controller.submitSheetType { - case .waiting: - VStack { - Spacer() - if #available(iOS 17.0, *) { - ProgressView() - .controlSize(.extraLarge) - .padding() - } else { - ProgressView() - .controlSize(.large) - .padding() - } - Text("submitting...") - .font(.title) - Spacer() - } - case .done: - VStack { - Spacer() - Label("done", systemImage: "checkmark.seal.fill") - .labelStyle(.iconOnly) - .font(.largeTitle) - .foregroundStyle(Color.green) - .padding() - Text("done") - .font(.title) - Spacer() - } - case .error: - VStack { - Spacer() - Label("done", systemImage: "xmark.seal.fill") - .labelStyle(.iconOnly) - .font(.largeTitle) - .foregroundStyle(Color.red) - .padding() - Text("error") - .font(.title) - Spacer() - } - } - } -} - -#Preview { - SubmitSheetView(controller: ScoutingController()) -} diff --git a/ios/beartracks-scout/TabBar.swift b/ios/beartracks-scout/TabBar.swift deleted file mode 100644 index f73399e0..00000000 --- a/ios/beartracks-scout/TabBar.swift +++ /dev/null @@ -1,68 +0,0 @@ -// -// TabBar.swift -// beartracks-scout -// -// Created by Jayen Agrawal on 1/14/24. -// - -import SwiftUI - -struct TabBar: View { - @State private var loginRequired: Bool = false - @ObservedObject var scoutFormController: ScoutingController = ScoutingController() - - var body: some View { - TabView(selection: $scoutFormController.currentTab) { - StartView(controller: scoutFormController) - .tabItem { - Label("start", systemImage: "backward.end") - } - .tag(Tab.start) - - GameView(controller: scoutFormController) - .tabItem { - Label("game", systemImage: "gamecontroller") - } - .tag(Tab.game) - - EndView(controller: scoutFormController) - .tabItem { - Label("end", systemImage: "forward.end") - } - .tag(Tab.end) - - ReviewView(controller: scoutFormController) - .tabItem { - Label("review", systemImage: "magnifyingglass") - } - .tag(Tab.review) - - SettingsView(loginRequired: $loginRequired) - .tabItem { - Label("settings", systemImage: "gear") - } - .tag(Tab.settings) - } - .onAppear() { - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - } - .sheet(isPresented: $loginRequired, onDismiss: { - loginRequired = false - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - }) { - LoginView() - } - } -} - -#Preview { - TabBar() -} - -enum Tab { - case start, game, end, review, settings -} diff --git a/ios/beartracks-scout/beartracks-scout.entitlements b/ios/beartracks-scout/beartracks-scout.entitlements new file mode 100644 index 00000000..82b9d1d9 --- /dev/null +++ b/ios/beartracks-scout/beartracks-scout.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.developer.associated-domains + + webcredentials:beartracks.io + + + diff --git a/ios/beartracks-scout/beartracks_scoutApp.swift b/ios/beartracks-scout/beartracks_scoutApp.swift index 0d85b76e..8da3a814 100644 --- a/ios/beartracks-scout/beartracks_scoutApp.swift +++ b/ios/beartracks-scout/beartracks_scoutApp.swift @@ -7,15 +7,66 @@ import SwiftUI +public enum Tab { + case start, game, end, review, settings +} + @main struct beartracks_scoutApp: App { let settingsManager = SettingsManager.shared var darkMode: Bool = UserDefaults.standard.bool(forKey: "darkMode") + @StateObject var scoutFormController: ScoutingController = ScoutingController() var body: some Scene { WindowGroup { - TabBar() + if !scoutFormController.loginRequired { + TabView(selection: $scoutFormController.currentTab) { + StartView() + .environmentObject(scoutFormController) + .tabItem { + Label("start", systemImage: "backward.end") + } + .tag(Tab.start) + GameView() + .environmentObject(scoutFormController) + .tabItem { + Label("game", systemImage: "gamecontroller") + } + .tag(Tab.game) + EndView() + .environmentObject(scoutFormController) + .tabItem { + Label("end", systemImage: "forward.end") + } + .tag(Tab.end) + ReviewView() + .environmentObject(scoutFormController) + .tabItem { + Label("review", systemImage: "magnifyingglass") + } + .tag(Tab.review) + SettingsView() + .environmentObject(scoutFormController) + .tabItem { + Label("settings", systemImage: "gear") + } + .tag(Tab.settings) + } .preferredColorScheme(darkMode ? .dark : .light) + .onAppear() { + checkLoginState { isLoggedIn in + scoutFormController.loginRequired = !isLoggedIn + } + scoutFormController.getMatches { result in + scoutFormController.matchList = result + } + } + .environmentObject(scoutFormController) + } else { + LoginView() + .preferredColorScheme(darkMode ? .dark : .light) + .environmentObject(scoutFormController) + } } } } diff --git a/ios/beartracks/AppState.swift b/ios/beartracks/AppState.swift new file mode 100644 index 00000000..48d3ea93 --- /dev/null +++ b/ios/beartracks/AppState.swift @@ -0,0 +1,27 @@ +// +// AppState.swift +// bearTracks +// +// Created by Jayen Agrawal on 2/7/24. +// + +import Foundation +import Combine + +class AppState: ObservableObject { +#if targetEnvironment(macCatalyst) + @Published public var selectedTab: Tab? = .teams +#else + @Published public var selectedTab: Tab = .teams +#endif + @Published public var loginRequired: Bool = false + + private var cancellables: Set = [] + + init() { + $selectedTab + .receive(on: DispatchQueue.main) + .sink { _ in } + .store(in: &cancellables) + } +} diff --git a/ios/beartracks/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/beartracks/Assets.xcassets/AppIcon.appiconset/Contents.json index 17505af7..17435e7d 100644 --- a/ios/beartracks/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/beartracks/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,7 +1,7 @@ { "images" : [ { - "filename" : "IMG_0804-2-2.jpeg", + "filename" : "l0_icon2.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" diff --git a/ios/beartracks/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2.jpeg b/ios/beartracks/Assets.xcassets/AppIcon.appiconset/IMG_0804-2-2.jpeg deleted file mode 100644 index 4bc7c9428adc27415abbd5002c030aa47b210069..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99118 zcmeFYcU%+E);1ahrAnlCf>fo5Gyy3QktQM{0#bw0LAvyiC`u6o1Ox7uf<$rJgZAfYbFwszv_fb*^0xmF7P%=@FIsqW^nHMSkQT{giTPQA2QeC`6O+!mZ zPi|0s1#p3alJWu-<;9Cs?|NY;}#YC3t0u>b{74=`a zC@uv26`YCc;#HYT%o;}2&%9X#Wna^<-c86ZZ=)5GdyHXw?lVHiE-b$!g8eJnKP3C- z1Pl9@B>OMH{#&j&fF|I=KMLgq@>8OuBtI!Ca=A!-@o%A~q5emq`Hw>Pk3#>qT>h^@ zB6mVT?t^^tCGz(&Ej8_b9s8#@Nb}@@bcZwxV4$QR4<wq-+Zyk`v{;dPj_`h{Pn)tU4NR$880cq;rI{3GL5DoaZe?Zp3zx@Ni{}KP7 z6w$H3fHjNGH0wCC?pl_sg86)#W*Z4ecKQ6m)jy%*rkH@A5Lh=byRdDP2msh&I z?^a>Dt?gNcN?bzOBtV2Kc8Wj(xPVX2;6xdS=ZJo0R+W;Xbadr93`s~-zxw}fqDKNS zOspVJiKFnnLlS`Sym>Jv&L47yNcD#YogR2&#Fn9QeXPOvA4csKO9q%O2?J2FkqMU6 z1;4+n6i`PW%o}#73y;`Zme}bvmxX6&S6I#I(QycT$j-bY{OaLt6!*ChuX|oacy;YxQ`TN1o(y@Y@Ki4>H=Owj-Z8>7UMxnf0d%^-E z$&VpBwLQJD`0XQsan_qo^9L;Q8ve0As6X}yl>%A6#Zz*%;btvHs-{xn|G;yd`dH1( zmmwE$wQWRmEPI+lo)1d0-u$ZMTv@ZdLlTTNv$59JiL>b0!3(?oU z4E`UBLXqZ}sW!tXevt#vE_lXBCt=++1buRIZokOg<)Nnit)UF2Mj^I63+dglr5J+> zw}#|}T*3RG7gyb%1$L|JKo-ElycNCq)bE*+Zs_qZ03*F|$wM^e0m1M#0x(8G$6!>! z-PON(WVcj${fVr+|A^|(D_7{*?mVOraQdc;9OV;R+IU?hUu&(XS*}wJm%X0FmhR^@ z*AX=8k#x0zd4`wb)g={igmWkxBlYLWYRg~=q7<^1Fg>Qu0o9zycME|47ln#AMAwB} zKT$FA!=>~#{=CVsUjeN65?MXFq|YwESLcx=06+3q!*$=vkw_}k=*fmCQUB0sBcE_> zF&c76MFR9SLWpWQ|IdFR*)NTL_LBgQy}-lLKi~5?yk8?9qNe5Zv{(=u8Vw%^o#Z>(ARL z>})IkqPfJfCEFMAAgmpNTwFO1^_y zDTT6hK`02mOPwLb*OJVu8Cw-TIA(~V3M`lv9V!!r4lbZpQTC&W>Yh9uPYJRniRR6NDB^oZME7aJJ4(RAw#CE$ooE-bTd~1{4@q(0Myi^-PQPkw8xLHNd}6 zDgVF406&tJ^4sQ}dSEss{)^8>sOD_!I>(AO0$=M2pklwytx;uoiVx^D@+m#wdtsoZ z{nleFFyyfX^Ky5=x6#cMg`-fv+&9 zmz>oIV|wD#MfP?iKXko+6hFlw8z7Rr)HA(4t+EU72T0VV7@XUaPW%CZV*puxE*e1Y5QNUtV3GuT=RX9Mujes3z7Z4EylpOVMDwFNlK_tMoT-QBD-DQ0(f6gYBA#_}N^;aI+vw*^kN}Bbo+gzg z5DTtmV>gR?^v}_CjSl+2v@L6eE~9k(4x6@2E1N}$hMziwrEB^f32;GN zVh_HC1BnDm9ACpo&X$zq#}G7&taap~`pR|P)%};?lTtlgs6(Ya$Ws?Y8FF{W_KUUi z$?Q8mgP*xxdFRl`w=k32D%v}Oys{rO4h5TEgRV3w)nHXCWs(!jM}+LEqp040pr&3Z zPUdG6QyCQ9Lqi4(d$IoK@8OQA*7JFZZ!r zR$Xv;MBs-nK|^8&-SL;T$?pInT|TVnO<*~zZ=N{GN{Alz*1 zNWmuNT8N(ICh!yDbM!f1PO7-teN~q^ei8Y1uds`o9UJmF#SBj(g^=9{r*-r@h9_%4u2$mGf!b87b z)#kF=*}3RypPr1qE5;0I;J^w`wNFk8H~8Z1E_RQ2rgG2+A@||y!yCuT3-oou)eW(t z5%$ijaas&beWa8lT@kIcgK+)2*wF6~Dj zO?Y+E&y8?hcoyhmoCCwzRAejG;~l&CM)~`a-`7+I+)`dpjCcQ}7DlsSDhCuh|YXG*@5(+V?KugkH=VATopNNdSWe zLCd%R;761sTq0TBqI9i$_Xw$3?0<`6Hgokh?6arT{6xpwXd0%x6dg4-BMnEfUvzza zm51MJBQb%}F!B9AB*4R%g9C9R$V;fi`5X1?xL=xufy=rC&^L7+hxXI6H-(3_rWaHX z)$NL@Eavd#Y8|ceO@jl;N z3+IuRtJOTyA6MoD8CXknr_Ksh!(Lcu^>MCo9o240zjzWs&;#^82l z@~xt{P=_MM0dJon5ELx_YLZBalDLxHLidS7 z{j(X~o_0`}@xsF_VeC+DhdVt9kn1uA0$FU@Br&i`0E8sUd84PSO^mYT@^MNoE-I@;Y>i@uscG4Uzm zqS5@PS1Re}+&C$`EY7Zt!@pSw_uAck+4{aL@6$p0r+4A=N(Y~U>#h^qS`~H|fiUhs zE(QR8TlYoO)p;-Iw62V3v-7}^d<7*ZB^pkUx3oi-Ghvm7CvpoWjx-t=uXSiTHjWrrBP$es0?NGfm1+~UHAnj zUdm_6Z~4?q3E}foB$yXX?^q0` zhlkzH%_;T-usd-6q)@e`TQBZZ^~2wV%43A|Tzm`QF5672JZdT|x65|-61cAfhs{NP zg=Q}!=jgi|VpP>x$4cY_AKo3fIm#i@U+sR*>=m9GkWXMa3@)}> zn3=hO?^}Ky>frU}K-g?0t{&^V>=~67SF&uat>sbPqoTn?0@QfFFdS_A!~o(u?G{?3p&nygs+h*a;oZjxvNy3j$luy!~hE{x{ zaqyKkq&foD(?Za~vU++l#y=Bp7^E7zeM`d-WfjM0D7LBQwhWAcRPMbcis;<<>Rgz& zGcDrz+%VB`_r?`F7`*xB%J}Q(le6p9zN(^vrQG*lIyl0v2Trv%i{jwlnkTST4psV?|yf25mO6qMR+&5-@{#>>qLQwQPlK-Q${De!jcnmFJNr#t)uIasWZ ziKoKJ{t3EKT6J00<(q$^o^WM&=6sxaS~Rnsm~fWfxBTA+2OdoMQN?Jlp}Y8Em+eM4 z1Ux7%aipUEOI`{%MC>9DQxZVM^YigjWfUcn1kE zC$#SoeXc|Tyrph!IlSQl#!*s}08Hkyi1x+E^eTE!za>1YmKSR7o)koYX`pSbocDax zJA>Dr0qp!VEsq?(QBwBE&bGMSH|T&gC}UoQFDow3xxuU9g0w~{_Q3~GgLqDtCM->b8J-6R2i z_ViSlHEhExTRK%}*xiim3hKSSNw|fTQc(R7^?T1@byX7*Zx)^sD&~EbB)%g6*Sc#<1F;6t^w2 ztY8o*@#f9^q@R~`&2;=EE4hqOU&Z#FVn-mF@D7E*9U{C6fj@49BZ# z1ZYR-!5DQim8HcWbgIl;x1n+GZ*&+F#l?Kcn=LN=*>|cjU z&;r5Jw9l9H?3Lz)V_(7RA4da$CCW9HisNR~N_|u~&av1Xwvi$q^4VPQP4L$3eFKWVk zM_weJ13xxjAogUbmtwP96J%Z>Ikx4wG6L*^eX%5VWl0PhR=IaA1@qHFgkOtb;KfQwSDISHo`Ziwab zp+XhSit~_gR--3@&$NON?}@Sm30$xZm@6>+soe3lQgF^jqihZ>IxAL+j=w65yifq>!z`;)S_~K+~#m zn+s~~P0Slx2}ik^R5*RvxL=0rEyhQ|(Kt{C9P?=L&1|lu&DGJP61HJ886Ce1BtUC! z(jXxh`K^fqdw^Q(WRC;U;%W^V>r#27>{EBA9vJ4aM6H3t(p_=~Ivtey>5g3Ff5_t} zBaud0tiwwC!_lCNL|%gJC<#yr_07`?5WH>~GED;bg}7&7A6!Do{T%x!ws#%b3yw#W z*TxZWa3;_I0IiA?Bu` z(XEXd3w&9NH+uF*ta_rG_?Acjt}P@vCM~>qZGaU;p?a~59FsCfiqq~+cU+JKqRr4k z_$ymBQkF<=0w{t{&Qj%T{YbZ9?dmlnXwPx-puJHljAwjQHQ0$d)Z4n9=K z#~~ro;FjS5GAf+A_CF1Tf&W_e_D2$Gufq`c@F=BmBIlEHit6Cb{`Uh0wpZ#JT-3hF zee~T=8mcc(Z?!FnKX=m(7x5p~#Q`xDzN$92v3wOY7d*!V()4^*!)ld&0stUsFX5yn zJDQ=RF1B3|WixOG!2^Xmq0qur?2A}z!2=`7DJANI)MY0$+X^zuKq|Z`Uu$GhzBp7J z){jHoAWbP}$7{8E@^Do^z=MXksz{pjl7{E9 z@U5o%>Ja~j;2Fwvyz9^Xu}9U>XYI~^+&AuE^;xK6N9q~A(^7$qAmPdA7Mf-y+~*~S z?Kz=a+1d9`>&8|+IMi&Ieb-u$m|E`)raY(Lrwnu9OY+;O!_Wrs!^PBWJbiYo()MJ_ z>~O`nE<+?272_TCPE2U=CXfwh*kJ?4Ol*V`44v4&=4~6jND*5zHx%FONOn-N_Y)`t zkZ}mgwgoxNNxZxgRCB2~+t*E+;kF*@o9{l-CVs<0SS~7--34ZB-kFe8EY{_P-b$lZ z*3Pz?&e~q~>5;47_2HtAFawZ+770MLjC&#KkLbERckk)PdzLR9tT6PPbHa=`u0ys) zY643oD#Pw%w&&efwF5ur+DLJ-Y7%@G|ua6hc=keI(*+w z4{dFzu1^rA7F!oq#J6H}CdpVT5Z&}s-(nb}I!lH%;H@X18->fxWQV4ynpoplwg*OK z!0Gd-@!-x`f>`;d*+DRNS_s)dkXh!0YUR@>yv+iq1h(Nzw!t$Vx%+5qKHh>JJX|J* zC;`6VXNVJRqGBI`25*OmOs4RFG4l1CBtWxU|4|E0%(H7pVAMH%GQ2S7&@?5)#d5QR zUTpmcub_3~iQnk*U_Z|g_({vX_>H|za0LgNX{mMC7lr@ao2nG5{!}`EV)H}qD9rV8 zpyQ7v5F5?{BGh?yBRfwo<3&q#%1q@HXY!Nvmi*v2=Vx{AP<2`<$`odQ!Jlm!RVMue z{;!ORr7f`rVC|_>#DF#1IUg~^Sr$gR%MScJvRueXcr>eaDF60)ff*T z&`(h|zx9JK_6KRW`5i}ToLD9&_Z~C0SY&AjA1aMeONn>&U?Ceg(A$Qow@~S2wGFG$ z5^4Lu_xvx)3e)VAmqfY`+n#HfQn4hw846Ob#^1&PjTS{yrh=bj8R<@5hi=}>Sekca zME7wS35HQ~Dl6c{RzNs0#dvwt0S?sJ;9tqT8s%vhLfcE+PL}KL`CS403Qb;t%#cCw zjzw8RR-C?3*n(BMR=g$F{XO z76?0DG}F>jw**%F{Ao!gUMU|)A2Fbtw-4y$!nRz&$#vPV`7{fR{*nB3yJthz<8|g# zph=o94`2P#(*$w?YibM4IzF?pjFY1_wvhFL2NV1VhJ6hZhnk(>i$wmwaL$@f=`Xw3 z*xkYGU3Y8#2t9fxyc$Ms8H|x3n~Z3<6Od`TPoXE=BYPYjImF9yGi+zw=hiB5tEQCJ zr!UJZ_m#T=NFsLWfgdoKJ~PPk#Ph`Jv^o0Bw{5X9qBx{xue%m9gY_l8a~%+A!*{GF zt-n*I>+npg*Q0hp=BY|yR@$0@aiHDMThdh>y-jKNYPF)N91l1h0vOheU46WAMI+^H zDBqSRk0wLBgZ56~nepLG${1u%*7g0>v8uwHnxy_`zAx2>fvJiTf~jo@fYW#HmAjQz zo#qa~GfC(77DOgnS~e`FyN+lpg1{Gifkp9qW|L2zC|B-yL9f34T4FhLy4k#T_Iux* z9u?n_3G7Y6E8_14DiY652j@;U_PRQ$0Vvqsd&-k~r0$q}teDp8l9wS8AvETLv3ym3 z)8iMq9s%?K3`ebOlbbf2Sh46E%^gdbqIlE#m6Kby_O1Gc@iN8SXB-`nawM8*`B7qi z_}qinB*0o}zW3!)^>Vqi$aAc5vD(`*P7zOkkdL}ePK%a27$*km4Ea*BEY0dX8>psL zWEePb#PEUPoKbCO;t+uoT@25rKW|)dze~=-bIeHQR1<3Z)YMJAO_rfG+#&jBq9lOk z{^RKLiZL(>0lx6v%kzfc`Mr~aJ;6J08r%28>g@*b?mPVL&GI0BB12W3s>7aWUBmNG zc&NndLjWE0J*v1nkdq*8xY}Y02eX_J#<}K*^RGIU&q)BAYw+Rxlibs~d_mRH^6szmy(T7H!db5vSEmjweeudr z>PF!KloW+8384D@c?=0~$D~U%7OzZT#1N4#NauyiV^YXn2XplL(>|H|k>cB2(SMA4 zl~DW2xib|lQ&5GLNC`sxXSluR%JqM?2{aZ$Ls1Jd7eaZvS zsiV5l&lL#FNXx=hof;HZ67zk>G`OXs?;>lTaNM<7^QVFWl7l^TMasfSzbGK7psG}K zKW4xW1rIZ$|0s2NG3pM3+(=3<@0+a+Ub2fJGqUN?o#t;2;W3{1WrNH)QXj$%;Ps#~ zI5Cf3xI{cUeL!^cWr(Dn{|xB5_lL4<;^A9+C+FufkR%8P{6$Ml3(H!1&x0mUx=qhy zOFmg`y-c7>X~Ya~LK}TK&35vB@)~+QH$Z`yty*iQ$T(^s|IGDshA57>Qa(_XyzCA6seMvV*v08{6Cx>Zd2oKmk98+>B!CM)#80F9& ztMbT?RxWGugjcv;_2N}wv77*8o2&T8bXA6d$eV$kYaZqSkfNQ_Q^a@|8!i(MCeHE8 z;5Qk23L1}p2pdS} z=theg1Ze73?QzX?5n}^l%NL3m1?q(gdT7NK4E>gy>vAGWy_RJBye3RsZw!G3*6VXz ziQE%=@|S~0E%~(D9mCca9Oi_5uC`IZ1(k#ny1dn|V`^eo__*DHR*^$tkTmna#OnYR z``9x7hK)D90v|LUYn%_ASHc~qVIqP4kf;S6= zUwVf7YOxP1TnEqL5`)g`fi{j!c`c>!*{AULllr!1BIZQ-jsPO zr=8_6{w_?UJ}HgIe_WE{^ikP-`4j%+{nXtP6cXLS)VCb7S!?c$+Ycx;)$ak_P`qlo zpL)ZqEqTzfdGY)D87L3qVcDm*B3hjiGe)E*#IXCPDxP>v&)gfcvg%FHVrHo9T@^3j z>mvu&&zdQ4%c%7I%mapgykdx^X{et||;*5;VUHX$u z0?-Ucih?i+t};nKg7B=D6V^dz&cCC2Jf0p>6gGmS!rBa(%#CuYoycYl_N#cw$Qu<; z^^nKh*6zm-%>;Yk6U_yvA9#QGe6R6zSUAx@$Usi6vE0$|ZwyDqS4H0mC%SN(n`h3) z$jJ=I@#_ii>&f?bH6n`F>fI&Tq@4_5$T}lqOG_&oD=ilnmSNRDg-w3SQj2|$0YurLJHpeB%HKeghO=g{ znBqe)Se>5$!VY)V_Yj1RwItuTCq1ek^e>ESQK$6>&EM$^0GQ2X(VZu%(q*Vvx-gAvOM-N7p^Dl#0B+4X?AmW#)ucpS z;i*EiR|J&_SX*gmoMsf#Y~c8S<0E(wrm#1m(`VNB*(acm{DN>@v<-}D&*H@Ty&Hp? z4X$|1uXCCK~EYEf; zzU0x=B^2~7>Add(@&tIFFo>%sTRCH#w2I#HkDEhZQ|H)A>>nH(CcUCZ$v+5@jDCAe zR`>8kce`ZwXWR?Dp1qEyA8zNAPBcgv13dT~ydjS1YE&`T#b&n?u^g8}V5r zfEY0VoJuEgn1B5FJPE4cSzx#f4C}Sa4A2YBE*zw2Kvc*mo9=viXjZ}2dY>?x&Q-D= z67tsh>$~XNO5*+fUK-RNG*EBM73>Z(8s)NM^U>E@OeXjvF~iFNQOz7XJKvoXgHra{ zECG~L-cBB}F{38j~axP;wUFwvTb~HOW9oX}2h<%Hi#y z)EIQfw&Kuto8LD~*=j3zp77H<>It33Yixoa#_bU4q%r=gF$UC~Np_8GE}Y;~`JThv zG`b*mbn;a_wT2V{HJrqj&pvC`hKuxLGbN@(hzEGOI17${#_*rGE`sAd=|$zD-# zMgrs&5?<$~G2;Sc?i2fn)Qg8^y|dEjF8poRuE#6Z4WsjQ7mnLe4EU<+;_-z7X4N>~ z6~lHgd$J)Tu1D)f^4Zm8m6g^_7D%^#?5} zxv0Oq$$bzXlnMvN3g{AVU`i2wzBdAFv_LbZeQJXk){iTt^h{_76Z9VWMtxms`5pG! z7n#+HGm^_D&4!|qW;~uf+NQQ0Q9e>Q3(yi{9X6)USn+CUD?ra|H?PB0z*oowuDw_g z!@Ww}=MFOiJ9fR63ebzHS@65O$bb~^&KFIz4G(0z3%Y{UKYoIf!2U8wHM=qSg%Jv4oPGB%tuq;wHxX|9h+3;?RAPIQ!m2c>eZVt8k_-EV)f#oNSDR+#Abs%8%ezHu*u3Xl`P@)3>hor>RLj7f>O+{Sv)?EwjET>d2GO zmL7|HpMztr$DXVm8{L4@-Eh~Zw?JZ0i#ab&TqRa6TOJ>sBjlIce;$}jc>kJxdV6E* z_ziH!CKOIa$a!&gT;LfP=TxbhDjBBMAOXG%N!_pyX5DA#4l#nOf#nYGMiW{a$?E^O z)oVDdN}-xt{@L_ti&k}FnZw_`uDft=l!QG9y&Xpa^v}5X3Vl4s9&s%_$eBn%~iil0b?G=ir&4HkCOOA?R%*p2^Q8+#Ay zl+HdeKQm0@t(KK+=NU=ugY2ufi@+jPshA zj_JXzBZ)JRYD--D^4^kIN64srAXoOJA14nHoM*$mAWD6HH;XUwtfTex667E_T7vx# ztTJ`&u+^Qw?na+&Xq-p3IA^-BTgEcZ>1lUgK0l=M3i#^|`WQ%mjFB0*LGc&pDy)6J)T{SY%`gp@lK@(CF=aNgX!i5&&IG)lK!)b4gB_z4~frc0c7FVJ63?7fo zvgKDx!xJ3iDWgq5?T0V~2DskdeD^#DdQn(We+8}T5e*k#IKR*++e`6uT`ZaAiKNq? zS8Xt?Z+taW^UHP?`;;H>@{ZT%P)+^%l+kq|0&{y8r&C=o>QE?sRRPW1(HX3;9$xqj z?>22A*7|s$F}D=edYe}^k&%;fwmha1Y&=wUrDsV*e;t7^+$leG&~n~Bvp>605|TSF zD?iD>Jf}O7_^9cIQFJ1OKtlH&CA9fOJ??wX@^70>vRR;|yO#6npQ+&g`6{O$DyTm( z=k-_~?eI}!w(s4?+EJmym6U=UN&;6u3MP7IPE#>obHrIN{%{_N+jj}wm|J9oN`c-G zc)o2e7$*4$nj)UW^WtOk+r(6F~i);s-Bf=8m{{_*0&vUmCQ4aou#!fRRN zP@>>O_?37`C>(!D$km>Ot4jWtpd)@a<;Iz_WF?%QJWr*N+$_ z9T7|$%rbO?%%%%(rk3v5iy(q9lW$|BCR6PTLo45S`>giK7jHj!KTVz4cxUsX@1J;{ zDxd4xk2NJ2uIN0M*v8{~tMJ$NzTrP;kAgyTmCmw~_e&-QYg1+Ce+KBuRhFOFC0Qck z#K(%SKMbzfJIM;g3iSkgb|7dVf%!%qpEw+vl-shFaB(t6s^z<1vLetia!w1n91%c1(^U=`NY<(Pgc!JsZ|Y{qy#|nNxncqdewm zfK7g1Kxn+}Ioa#5#{d=xiO1%ALES@BTwV|n-ZJ9PE~bH%Ex4?uDp!$ zXPKEw27e+HuXUShUqeMa)}SsB{A83o5veKp;eJwQm(4B4JU@nf0ixfLdO|@@(N@jb zduy@xGL)4spW%3;PaijgN_5Rm#y)=`X|EL@Jcm<~gBGW?5+?xe)Da;HNT3%|x?}6u(?w4%3b$&fDOLal8e0O}tU+gitie1+Z z$RB@y2^8Tr;$BTJG2mHaG0gkHHc7B-R%S~5(_Yp`uKvp&R!Bi?d|Y|U{a>p`<{qp> z*T~b_wH&gDu`K%pY?vqR_)8qAc{rny~*pdK2H1O;bRajov~y9j zK&?@dAj|8(FE7QtDqeU02J=`U2GYBV<&L10viY%JipNe%|E|K(`NC?X1^CbEpT&)f z$5OU^HGE6ZE83z67Rg-w)g2lwaZzYGOky*hp7}!$?M1 zoEAA*V~EV4UH#OaKYmdbV;-T7rzJh-=g8J=@%ovi=Yg8ih2L3X_Td}8XOW{vp<-5* z20HhC)Q(FDa*%_HEC50g|1gpJt2}gFI;{N46i`9h8noRa zbWDuK_{_#-s= zfhK|xqYAAKPrut$(^v;=ogluN1^CynkJ>;C_*cu5B*u&~p;jvnq(NYYKH+2XPQ5ARwqKx0+$s$>aw`e(khcLxcSCTg!^ihzAPL z6D=J%b;RXFlrx+$u_X(+7a%#mVB^XG41lYq%Jur}53cLj{Tb9#u!z3SpQG`=0HFT~ zg#P2#rUa9Zs_m41KRbM^6DGf&DJWnKdGNsBzi56fm5MU%?lq@pnMGc1zsW(4=Zv%s zZp51-8v4+26w1ePpv2>$a7i;FZcd1Tf=WK`3a~#r&Yw7e({JbJ#@u-0wiHjZ^~)vL zAsrpPaItmR|GCdk^hD-6N7Y0Ft7pEe2S3H~-+IJ>77B6F2QWy`zF0eW+HA?`_4CNb z*ai}y{n__x4DDO~F4)=}OZ#`!FZ!SIH<~t&mzR}~NePyXxi42$hx>Oi(3E#atB4l> zfVSfEflg$1ZB}dv-e&n+)x0ohHdhq)^0TBth=7p5$6luEyQ6Hzb7IkB_h3P$&2l%3 zK7P(X817pGeZQ-PbP~BS)yTOfgW{)K?7xX;XX`4?xSa#tey|0>0hfypgqmY>hwM-- z((T-q4raS`>E~1D#gSH5_wadlZ+j?UBT7o#xX%yMvl`*Pg*N&FzpV!k1{ckI2H`A^ zH>S_5I4+u{uXhgV^tqA%0|#JOwdd^Eu^*Ym613uWokrMkR3fHJ>Ci1Oj~b(p=81P8 z4h7s0gm4L_kN{Z?p#)7tKn>*)veiO7XlA#Rw$0MKpIA(YU*OYUirme_-^&}@lE_}% zW^7#8xmy=Ec}`1IW@e@bouPSv9v5MLurYXr!BlIeI*`LTy>$YrLVf{UYp*{4QJbRW zq-EP8+;76O{wR;XFwSiyN-S&AzOE)=IYpL>kF)qXAC1rlw*V_L5S6uR4=f+(@Ua=IR>MTiMj#c)&TqJ9*vdN-`KkS5 z)ynV+Ki&-KnLV0ELul4UVf6tM4#&U@&D8HUbVm9M7Dy9f2 zpuYyLmM1XO&c1m4L7W7rmJC@Y0bWlXjF}s_!m8UpkpSOqKZ-QTpOVS5(g|1y8nomh z3Dt31E)Mi|FKjOx7Fbx^dc<&fhR5usn8%XYM&mOq3tSRgi^}?{ef!eJ+HL&QamZgn7m>Fk zVEq&^8xX)@>Ax~CdymIAsqy^bE_RA@MbxSM@VAKOtfNfoJ~>BbIFz*rDFa~)5x^}Q zE}Z*!-0+hu9ybJ&t03ot(jtq=w)=%#%5CX-8tDCK0vt)Eh`qV}AXvH`N&mDPaQT~t zS1TO01wA1Fdh!&m{Khj%7r)@nYaS!8w`9hb!mhg2#OL%l*m?7IZ)?w`+#IW?r9;>WT~nW!Gb2wAHRL?SSVuZAJo^RQd0s!@ zCUs^?5u3)bV=CC>xP+%do#$GcIIiGPh$1p)f=InF)YW+sz&vl&s4xF>RCm{BaMwpq zJuhQi-smZ)JZlQC4i&A(4P$lgW4ss}0_}o|9%OKSw-xAnGn0`VYv|||?AVecK~JxC zqkHkeShl{KzHTDT)%WhY%dvNJuJHnj0FROhG`v_^gtR4yihpPiiLiHRS@Ry+xy7%U z2Q;%{j?NO)-rqOG-fOlD^{E?P(V%PCh4vZiczd(@XtBnle|(Cgt~jgR--BqnG&rOrIj5M)M6DPO#ryQs zD=1`UR)<$un0E_C$b_4av$09PPm1MvlL}VaKet@9|%B+_>`rnwq9wLNAT!j8nf!B8gY_Q~1RwU&Fwpcs_lx?vsj4c^ zd*&H12aZ$YHAm**n@kHu>Pk7y^X2E!sv3T(rU!vp{i4YevNfYhJaKX-lRsP+iL~XV zG9-XLc0SLJn6`x!JIK67K6m*+jmiW8bP7siHQUOZBCt4hUIR`;eVwlFij1vB!B;Bv ztZtQ%Sx0DGpELbda8KmXMLv$o(}qUKL+nEidGRw+1H;kf8P&odefi|o5q{|E?{(c}uj74$xxfc`S*AH3 zUNeM|2HW-aJS)-CM!8z-MkkzyU@(b*V1FXLixzI(<+5bDmydh?&YM@C*nf>{qr{ul z=+51YXKXYQ!sH0yBAG^f=OWwq)&e!Qv^2{xY3cm&5m2RM_uEI9b424j=r{nkhP+p~ zl|?g|bql4MQgQ*iccbm$V0&QEP275FvCjJuh}LgnAEJscxnh0+cVFK*E$oc~I+5AX zy~K;>@N4z?$7Ut#io9Tvic|rhoN@U>!%1(gw4VnLI0(deB2~-a>Cb5VCE&E#am?p) z$5;pI^Oxi9!^Br;V*@-5>=*XN>X`hN;fe91w;)1b!MXFABYaNj@{cOmA=FzdRIUit zgQ$Xi__~34aqwl&?f;_eJ)@d>yLImVn|UBBDY-c5VV zDmCjAad%3A3I76xFQ;l)m4DZrf|wJ#{M0)^_mz7A`1`*#IKqnYGVwvtq9M73nR9DX zN{kcQ?tDw8YG2(O zdMG}Ed`orftoGqU%`eC+deFKeP0rh2NL-3o>Wo0sj2oyZ5j?|cTirwZvQ3? zdXwEXdr-8RhEbm)K?_vMh#k4KCH#ge$W9#wG5Op@6@_^;yzu*os=HC(&9doD-QrA7 z!M}Y-?slCv&kG_y;MUj>3b&=Kcdi1GIAahy=lNE9&aDnGG0*WjTkcOZdC}0~r|Rf% zqWZLTJ}iUF)(I<)aH-#%t~+sfuc@iQo#*%P0Z)~zoAKi3H&%WL?gsp2rf;vDMFt;Y z1%ie@2Ew4bfJT|`_x~&S|7irCNNoTuEL`O;2o&HKbPvyoLPl;T{%UNfRC6|!OK;M% z{FbFTe&^M`vOi^zBfMP-Z|5v0xRwQ4P%wSb9R9LS&-c+1UkVq@#z#NP`y4TzwkVs2 z7TUUrdF%9C(B|~i4>2TofyC~t6kvVP@a{~S2#CN^uU=C5OXhh;*U#m>s|=B_agv}% z@OGtUAu&W`BlL5QX60U^oRv!N($DJnJZtQ;v0JI-)ZQVFiMlKr?w|FV2^Kq} z+S2{98_)zU7j>eIXq6kJEW7H(Art4=-&92*(H52P5JLP)jjpmokmdjG?Ehas;r}l4 zM)0(HwII481N9fwIdx{g*@N?J-mv-B?-FcG&6Ab77$ZZmVrdEelMz(7%?dl?3@zMl zb=w8r5!4!Tw!aynM#)AVedTH`=vd}f`HHc))!cn*w~R$CjK1p`0lHbi2z z4x(dS7KpH8FAmmaie+?y;5l1K7vYztjzurA#aGGYU&i)@4+hTYG*V}-p7-UU7;(O^ z7%&TlyEMQMZ7?f6Ut;!z`cmT8M(o)A5$o8G_U=}jl4C($Kw0CPWK>=A6WJ8pGe(iP zpceluq*OMpgmmJYf!`T?c3L&W9J{p=sIbMUHdX$Phq5E7)>$qjvr9F^nER9!6PR>g zKad{odPVF5?l{Z5iFy~lO3v;pBa!7~lTY#Pm|I^ca3;8SB5l`ELep9;^2!NQ1#fvw z{m0>Bs}O1d0@nqiTaEL7L8t7~ideaCMSOfsGOQ=C&oZ4R_LVy>b)2XK>;WtAMnA9z zfu@>UA*dR-*G@iUAD9PDK0$Dzz3Q1-%EUM8j_z=)tuH-vk(PruYm)p9`O_rrcOb{O znuCC)zEiy9sAJWdpE-STd47hASlioylkG$nY%~2>rxv)Gj}hS-fhc~!>Npu1nsBh* zRfzTJROA945X~$Tu1hS}b2|ljt=Z?1w3_9Q1vuM%PCWby# zcYb^rW5B=bUrIr%sFNbtaIEad*O_5nR_k8ax7^Ue3_7LbAIR#m@kg7f#y(4isxcQq`p4@5HVye4T)!`c5d5*W;DQ1MRCD%l3qOCoab#&32eGL@?k7XHu(N2v9}aBp}%i#Ed>VP}g?1 zS#=U-5ZIvXiI=}PYUs>fc=ghWR-PKLKnhHP6_i-IvAc76HMarj#Q#btU~CmWb9Cm5 zYRpqzHL8`KW=YpiGp(AzM9=r*^B4~s`GN!3R+9`+OCg2!ib2~|)nNF^mPeJ-G!vnnCASsGRQ;i(pHN~3o7pz~j-My)pcu6^}fW}h$sl1E(MVgn~ za}3&`wp3EYaG2Dzb@I@;Fx)UxohL#?FRIt7DuHTpn{*UvzCukqXLsajU#z)l+DH7o zi;f6EYY%ra`#2Z1{pp0}dC$W<5Y@%$pX%bzJ-b7v2u^I`^QqOEkQZMD zH)X36qVnQEmu>#jX=BRQnDfhGzn5bc84p-}L|!FGaSL6VG2O~bP=$>*KiB4T>@-Lq z-0b`O^`Jh;`sR%FG>2Myg+Rp3Xr9=7yzrV&fQA!ynF>qx+`Xr6NC_8xbbC7v`qCm0 zg{k@K@mRP>C5u<13||&r=Z@#{-kD10>k7OhZcwQSU#f@_;meV;0czM%2%;L zoWUDvXy`r0EMgh4COUcV$==1oyUm?lkn0K**a8;M5fZz^YD|()ZkY4sC0%|90f&GZ zLUjfdiEU{6xW-3iJa=Du7xA`m#D)g|R`>wQY4X7wh4R%Ms^{h9({p!77vC8|xp%k_ z$<3a?UAm7A$roI}l3P@wi8T_055LTqWhtAb-myL$4w*x~+Aelgtqxl=>xmpMn9f83 zMuau$nWi(}Nd;OTe?2rLMo76R!t=AqeE%DD*72Sjt3*9R4QYxkb(JK~0^1Sw+xc(w z^@g4Rk;pdC%jdnRF+KX-(@6k+Z9`;Ublnushqc0KMM9F+zzn|05^uw)Nq!O?ND}=N zD5E9YkPQQSOs@(Dk^;$W6Xz)KZE^FUsh7O5mdmq^YNVT&_nK(`P~-MD^D&**=2`>F z@()L*r2K`9odK9fdI;r&5sCJJy4yP76dhJWV4xmV(c~qTmZ*SiS+;_5fW}zO{el>Y}05f_ICKL+Z(a`rum~$ybR(C(t+G}j+)9`=-sR6BW~a884-tf1PU6jw=;j3 z2$kA)+?~7FIs*)U@l2hBj?urM?azDshe7FGUoMX4iqEtU?Xzgclo>0rqyJ-n=D!K) z6~x3rHx`5PeXRAeOi)XSW#$4r(^C@DkA*BhQj0n4GtjAlG9Rn=`VHrtFHnjVm~g;E zR^cb|)hnStny@1)f^S%iCVmR7?y#NxD>6C*00@FA5mSIaB|F z3U0#2x@F$Tx%>se)qNpD7gR{v0GO;9w%WAe-HXQP`K;3CJxG@aKxF$~d7Y*HptAQ@9plg9$@C!^M=~BOArIpYa~`B$(ALL)!R7pN4eo5 zo_D+sw&mY%3pk1Bro3n}{kZ8T^B3f+4eK5Mz}c&8(_dk)`>a~N<5im_>ClWqXFPUF zi14UdOL!$g+v^S~22udB#8#d=biuvEz(apQCVw0VMFF0Iy-oKwkJ{$Ht%In3GCq9| zW=)P~@Du_eToJVO@m4=0pu{CIl|&WS`Vo4yXwF2Br=Ob(iTitH_B9(|b%NeIvs{ zqrfr6&y?ilAEiud>)sWA*3)vx%bJO`6XC4*^ElKX20UE=vNQ16s%=&^%8&76QN7jP z`%`LU!!Z`U)a((+w~wNG;OwpP5q^up*|~y>v|+>n6-lXb`Qn?|%nOv7Z1Ju<*|utB z_7uanq+drY_DnJoRcBLlVbN`I-4k7=SoJH_08flufri}p!q7Q=r7w@waBneRg5!i7 z?MhdZ{* zY^*|McHe1Pq4EJ-?oBO!c4YO4CnTKp-dyqzk=J}q`OUuPhSK;?h$&V zk2+p_%k#IbJQF|NRC0ADSrBn@XB}h+apa~5<`;`LtXI&0dJOjn{&bR(>XVPHm1uHi z#%i9De{gq9sZ9Ox@z~n=FcBYnA=i@<;Ia6039nLhK?Sys3MQRK=Ir}s@9H%+%AdDQ z;mYem*iF6*c+=lPE*pJfCjI?wg)`*1qN90G51U^2w8^87r@>7Ic{pl&!UtBwR8)7$ z9Q%a7xZO^yC-`;ai5n3GCv^@nE0wegj9wM+!0SAL_JQlNx>r#nKwvDoaAb2YQ|Lr& z{z(xvM{}a`O!z=-NagYy^HFkM<-y!W&Ou2GupT z8+~QG;t{;x6)%Rale*Et%1F~7AuB7VU1lRsuc;dfA158C83J?vZnVkQqq8%-6CF1`98rpjiekn8 zMvPLwPnoKRQ=DG1?P&&)%D!DW)O98^cuorpBT#+WwzY1w1ywfisSA3QF)9C&%`2*?bN zt<6j^Dt3I{xq+V@pGJN zB{m3*@$;_~cVtaQ>d{sje~^3YcNkLs1SsA(3-e|ZsB*h|gS zYj7pss7DROiMJA!N!<+pkr8fqv{EP7;WaERd6-fh{fkMxchXJ~bUVVYJ>IPmcgoTe z_A=G*ei3UyoF?h9blndg3$G_AZ9kTvo-Cb|(=0PpCfX^9E<*PT=JRja`KmpTWY)$U-zB7=7A50#vdx|?k>OCl>&WWVQkb? zdDx54;+NTJ@AY!VYCIz>PFdH*y&*&TOI}9K6Np_Dl1_6=az8#{)VI9W27;#JAOA4& zNIjYfIDdRVdiAM?lpv?+XK+LOwXe~?)R_PHcW;?Qhqe~I77raijCm~(sG7sMaxA#H z_`JjEF~Ofa7D@DlZ-VNhKW!hPbgxT+&qzonqb@rHY#){9U-QiU;vqQn#>DIL*vAMP ztgU^CX<+%`9iIbUeH&X6Z>bRhYTb~29F%lreqNTE#&je|*YeI}<`XhK{W#xkH&XFa z%EH=wSl`{M=3slWzGv|omj1S4w@tLBDvOjEPf`w8E}!{$uRubFhOJxC4|3QjMKl)& zIWq&=+HDQV zpjACV>|`Rp!QL|oe-Cg)QC3B*clp`m!>cJf)RuG82r;E5wp;A3BFlQQi9j4;g(QF$ z@D|ZbCXcN2Bo>rfX)1Lwt;8Cw2CvQ#D63k}5d$#neZEg2yB0T5Uz~<$U=E@W{642i zL#w$X5YL(jEfsJbGvk>`;kv$Nth`= zvSu9bjN@cfW-#pC$oa2KN&nY%(tj7$C%7Lwo2Y+MBkZVrTzO{tv!eOe?Bdy%+4^@< z^BcC((uag52_z24$9ep$ZVU%lmS*J>Cw;WM)~ z0$G#2-JVU~q=*JmdLQpS!SDg0IKaf_Od=T(#M)mvr`mebIet~^^0;Rqx;i%7Obxz( znDB2hLOAhOe+@dco0Gsj><-8&vCqB#peEy~xF^Xyrl}gBbV9G!zv$Lkv43RF{HMGP~-p$7@dk2T|(KjY` z=T!pwP3D4H%IvL~Zo73M7f9~|yU91ijsZqi{5OUzogwiT)3KO8y8fOPHH*~N()Ur1 z?cv#=J3iSDC_5fu9`VATki1^PR(F{Me`#n>M6Ggl2buFu>VNQpf2GlPP%6?9} ze~$cl1QypQ1<&Pe0T=K+R3zjrXJiMCVT)e#UIe@B6c$mgk@6vqjzbv0*_bc^) z40$6;1j;v)3Ul5~)mI9QNgBAuV>rVX+!Z6rj*5?+7o zi(S%$tA};=AA^UMrC)w=%G>M>u-ORtO_XTH$UqeFZWVZVbrJc-!V^QsQN7F?eu?9C z1!F?_0QvS&=F=?nu)tK7)0u{T)YbZlB#^NVf8M0nFB6-#y?wg(i%oHSNtj8RWMYPz zXGR#)w@&l}9PM5AQa_+JiwzK+PwUW5i}YocU`QMK_7ovI)eP7SiRKGy*IN{Y#Ja4TGkyu>Uk~^h z|M>7=6eP9llAVU-URyqJFUN)*ZoR<1q#Owo^EM1WaOU-t9{b7Xmr=JG&Kw2M3<|&U z=((w#|6ozzV?9tekzZOy1*vX>4;U|DSk)E0qyj6dNeSVDBvBYDZ=7pKws`FNzMAfT z`4d>;o+v^hT1C*|p96f?*hUzA>ImiQg7ts@^KO{(S```0b6Y)uD#y zKlH-HiA2q^Zxun&UpBrxq^Xs+IS+)dh;aR51GEG_p8xhRJ)HNM)Hs{bRbKNQ&V^n_ z;l+*ciZPP1;e4Pb?1(K!EH~nvfoYDX&#PK+1R$_PHSbg%Gd$yKvgCrKJaV71#&_V<$bn*hT?htf@*l{iJe<1sg`~}|Fl(<1WxC|^Cl}| zp@)UV#m3unua^+t`|i|K2AigC$kXxbH&x>Jd6B8`+t`S`Zi3)c0MtKTp&ITE=i-xc zOl5tl5aLBb@5f~} zb&B_JNqL#gYn7;JAj{1sk$>W#`r4R5ll=+{!qX9?UcAzUf6w=HkD*7ML%26>DJ z?>hBhn}#!4JSOp{u*6G1gDa;F`LCql|NA=R-(`IXx_6pv5LnSSvJj@uB7nWFn@))~ zo&k?O1g)qw0Ow@T$Eh-gn`W}1&hpmE-F|oCp64_+yA}VDn9wOPPL0hiNtPmxdw5NX zSUl%IK0h#}+tb-1e3!AM>$Z!kr{i5sioPmUp0|Lj^tG`O5VYlrAw&3FeN(uH=!lK7 z0He((GA+K@N|?kC-`@9D8jMe$c&3)Z`CV`;kVu2jIa+gY`_~CzL_FZCJ@MLK-pDOH zXpkBfjr!&{{W5oZ4)LkhQJz$(HsM?cnJRoxzQ&emY$Ihrw2+m3WaK$|HBc^YO0{Zk zEROi)0N06VfB%{*_%YeGBH{)%o+HAsa)01z30W#%b}Uk2RH5QG;T`J_g`o9u#OJ z0kko_!Ph+kRz&mloVW7TRK|4NyxvV$@wA*^9xZpZE7FgZ;+rhG z4k&Yfg=Iv_(22~Y`*b7nu6X}|a z0DUFKXn{k>fJLXI20l5mYs_&^IhmI#hDh*!AJ;J%_jj>fe8^P-{Oz@s?E?j7yndr~ zPLxu??s!5^XH}>4MtV@+mDM)fJ2HN?+~sdG zMtVhGl+@j*uP&+C#zFQg5*N znbl{;f^=NW`>J;_4VYLZXO?yHhX7asfN=R)1f##z>sTXa>v~u?727`__lbb`H6YC3MQ!QX!)It z>?ro@rNw-20Cr-V|Fun;GsUmYXQ@M@p!AcXHYrzYw&^HGRx{CkDxCG0B)f^qrXJd(8rVWq0 zDJUnymufs*=5Y{BwdFo6T=V*Hq9D~aNNs#o0=G-24(6o0yzylR5`p=;D0b=QzM*<< z@<&JdRtpWB%|(hrb(OQUWLM@-o@?puIi2~EdEe_ad#x?+cllWxGS}MHa`o!MXHe7B zfwosgG%drCNIa2kH$e<75>x9dj-+4e_jS9t#k?k!SfvuOsmvL&>*nT|oEy=1B|#H) zH;=?77-*5Rfja~A|9BCdr4w$VS2}Y7I9t#*J9W7R`LUZTsy~z$#j`%SnS6hp6Tbw11-ORK4PEKI3RXs4;#V^*wFk2!bDhFF+Cv?trs8aFU^)nLgNu zox6QkFc_j7a(||+@7i}rrN8=tNV=kE!No!#q;rs(gEwP2?dX_Lub_ODBL^wlQ=p2u z)JpfPOMKMWSWA0o&k!AKV0n{M?TwI>dDM`0pD3y}2w`U0?oFIrubV$Q6wMyrmlHo0 z#$v2ZOyi=s5&@)r5G(iPNY{LYU$Ojlu3s?v0iBCami}11<=))}d35i2W&2xF($Up* zp^E2@9F&={gY|V4k&=qq4mEqnoCdYrxIe7&TW%` zc#-GJ>R>Z)Jj4q2UJxzPquRT~S9>BSzFM4=r+)j<(k?e8`!i0KyTs~T+gjaRVd9sz z&$uTl9t@}b1-;7s3+e)l`zM!8nT+TM1Am0y$ZqwA`6TI_QDi_dBkLB9LY19tzeLMi zdkRv&t{SNFB=~@+3R}x2Pt!FWIyA_;2OxLCmsB{I{bLEWL5e{$V1_rNA{DLFc9PFe z9zg0Iym}`gMUlJ`6Z$2DfB#|2j6uEiX4N-#bW##o06xXN6L3LByWv%)sKZZh8V5)h zsd>@%&hwguh*BR?J+nN!h~*>tQv%o=8*l`Aa&1a=-TWFwWyTqRW6ZkMB|}6$b!|1Keyxj5d@s$VCsC~TF!I}CfA$!iDPGhtVVTFM=Yh0kEFJLBydcS1b@Sq{)a*uqJo?Zbm}u8#hF_t zBjHQeMqAl^9F{x%D16iizFU@ZgP%WL>wr%HuTmlJH*Zh$zG`L&KaE_zPPcEGA^m_B*(i(uf^|xoe zPqS%$(-8crSj72VEn7-+OWdH?*M%)mM)tMeGX`LJRk%=0j^HnvgF~c07HChy1_)W*} zF4JLT#U#Dz^L;m9v==iS+mOx$>B+g(^a3a05}};GT%=QBs~sVE>Oa600KP(ZG$RA+vC62H>5PlAXf4q zQ%%qR)!GOSH$w{wng`+6S9zseWJve2x`J|Bn10~ZS^M+MY)cMaVJLuUudh4pg`L~cucmOS?dL+Jllk}yebkas8wh2b!W9+4CiC#8!`Fzh9CiO898(0I zVuEnT=g4@1&0qqrRJ>qb{qDr#&jPn0Wv?fMvrf&wEA~dK(*%!cTLVqb3;utwQG9%(9^k=9 z^mN$i0hLeDk3_o$p`c;k*_eFr;mIh0vwfmOMf(dzn5cWsusPz>8hKg3sPqR#7J4c#OY^q*p=kp^NBG+PaNsr2Mtar-> zAm)?6c!5FOkh#7lSaf$j3s+9;f1h*NLK>~QE)qsy!`kXj+a}pw62I8j-z4(TC(Vg8}>fyHE_Nm3Km)tc_# zKv+@_x;kYwXQS>#-phL@J&;(N4jF}p*IsdVn{dQ_79;=C{JWN)?$4ah$N;+UG4*%( zPjVq~zKnR}^bTyF7QI>%Z2%mFl(uz6s^^`hl%UilsVXeos;&I>^{9(n+mrr;3cBq8 zTPB-OYB^T){xXaCp-IjTaDpI>UP?J*hNl1 zHPDJEbZWw|+zfwoGom=Gob@#GJHf=9Q_^ljuPi@I@1Y`xB4_Ouj3IynK-wTf5Mp1U zp8HabRa@X4TB6X+c(_kN-XKS5la~}D&gs$vPsw>5T@|2?x@!GJ-Tk<-L7!Q}Nt+~} zvtxzmF3|e(Y=aOXf|RM3!nbNf*};;tY1PL^C#sv2-OXo-{f?e&onjBh`q?84#wJ#i zzN`e3wUfp<0FcYGk0|IF-=}r7a+K-Y+Ng{9+vFT;)akN10vDy>ELKBnN-%lD{sp}M z!*=bPpE5ZE!K-6e?aB-tCFj&XaB8YdaGVGH6<3aHq>&zo8$Ny_k~))zdUG^EyN8<@m1EpG=CQAd zr-fmq5R^9TBRNTC0Xp3{ z404-s@brtUY=B>mC(6M;L}?|iI8*b^Yd*Nfc?|L`fQVHqKw?zy#TL3qU2g(Pwb-5# z{Vy9^l3pVeSGfw0jPdkXTliY8E(TCfM^Dqew|=#J;mD8Kp}C=oA+MLdi_8qv&_hm% zvz5aPG7b^WZxYtle6_Zcjg6|CI5)p0IPN0m`PKyk46x;{g*$*nlQeWF&GXaCFUgk6 zJEAeY{uPtl!Jmp65D9`TvelSOmVwsd(3ffFTcxMl$ch|g2K_8GZAT|pe|N@=d?&G! z#%=~Xa#?^P@tr+Ey^Rq!f)ZU7MszISD)Uy0t#G*Wdg2YUtTw76{4#zEd?2Cy;@U~p zeg^8BxmFP0-j6^0#<}CxuAOR+tIVv&q@MveO4r@&>1Bg5?g=av|F4EEjEuH2GX3Bf ze|0@V1|^s~ffuZ>e^~x&vYI(n>9+P)UKN*_O|@wIVB<=(hHhN%cc$ef@ZIaDJG*)28~WRRYk!h3lwtMcn-6 zn-p6iID&rz9~Vv;VAJf5j=ML^5h`33Ru^iGJx+CHO`I`VB~huqjFz} zprRk)FGsIN+hN{QV_E-#qOHvoh08{qAI_n_J#(lr$U(dcqSfBMSWUv z+^jczXv+5WFh|N~IPlXUbtU6onpc5S@e|$;4Fn#DuXfH~5Gx4z&-}=2I-)+4JJ+(zhP}T#mi9UUKVL4c=2|%6SfiHT#BBMviU&Yz8J?Qa=cK;GlZh z3T}X0h&n*Z1Ds&CL7f^|k*rOAK7Q+%#+tJA2AmwXUJ3hIzB9Wx^RV!z8Lp!mr`o(|Cly_hw zYrdTKfg=U(;xWfdaDjC-5y=Gm|U;6e0Kk2Sk=ZNZ&&+zBZApSL~Hc)FX({n ze!(AQ?FTO&UQ~}paXvb-m}IAUHjGyJG|t{&0IJ0Bc$NW7UcN3F+ZjXHy(#4+qo}Cw z+{CUuls8%@8+^f!r+rD^i?f`%mX@Jc%kih5ZV0I?w)xpaH1Ty(zI}LnC~WLLQ5|yO zB!0lelsnL~)W^|5mLPOG+)bV}9$W;y&>qQ(TBgavI~8G*^;31?DIC;JGa7?DI_V}IyMTxEUcBcW)zQXZgcWK+L>OB zp}VgE&okrf9Q2y&Leb8gFGM6#HeDy}b(=d-E3VtN8gVN}@-0JZ;yn z8JyVV*wn4j?a8Y{T#&y;&HxINAC4==%W+1cLJM=5Wyt2I?-!W zNU=j;{FbR<3glyRykgWg^eSSCD9Va}(>uuILSUtnCyQfsFs;1ZJIjjvV4vH zpgCdtcHZC#H&37SP55BT6y*0C>&mY^v&W#z$O!nR%(W~?xKOnhS~jI~Fe)ze{ve({%~(O)w6`EeCC9HU(n=U@pT(Of^^lWI zlgxv=4w9`GKZ{=|1NQb4>>F_;yTdZQCt1Czj~8|2Of?nd!CKsY(Ug=V(O;0cB4Xyb ziwXOJZS2|CPpej^F$4rY1>kYnUzI5cWqr&d#mGPHa27O~g0C4AI!SpXdn(v;{yes# zXggi5;jBHa4FU%(!Wgt;f<%y^Z+VvsunH1CbczI~t6o*4@0KxfAF*JH_-uUTWK#m2 z*_iwND<|=d0kddj23@19%22=QcIr@*tRC1W94uJuYOG!M0v9?Eb(J=7mtx${mRP_x zct5YjS2$=nsB`&-Y9}(xab4bmGHoj|SvIdZ0A;_P?sKtiMla}hsN-w$y|lV}q#9EE zibEMKe;WZ$-m0>|->XBNWsszVyfQkyluBTJ8*a27Wl3xm^o}$rupc3paQ{wxZmKZ{ z6^oH&uq=(^UfQqbvD0$JuKK#T;q~{!AJREf_abKSp-}JUS~=NvRxzkIfC`!WV6^}C zlhrZJcYtqjYh%TAfm_b|VV&fq1oL9o=Exnr6pMhnVrWj@*4ZKV}|Wd6@IL>{|0l-cr=dMhs=V{bICg*XV;95U#dBi=jZrFW6LO30O}*<=iQfGC@< zByCaIb6NvijLQBm2#?21wh?FgZtdTEqv(A(o1O!1;k}v$ylBaTJ+kt8%%iVKWvBa_=0KU)n*XEg_b>LF(c=#l6F($Nv54;99mwnF$G?UtSMX!2xbpTyS_f-5;S<&6m z$)DWRyr&u{dwkh#SSjvE-ge)}zA44Ho5_eG{$1l2^RrOu14Z)I5d^?UC>~5)dY?v$ z+`_`Oe%>}rR!azp>#9Cb$aCca7kDtRYSo^80@ej)65rm)vLR@(Pu^yR3w+4}k}Np3 zmx9(mQ__|=sXzJ}_F0vOb^%9WqeGfH_8%3H{@Jd0@0+-S`%0!$2r=7v8ivSEqq=I?x$C{hKFfSi+ zOxOGuq+HeOR;3;*%F*?z@3c%3;#6vqMCPua5CsjSrpZM@<$zN&iPwJLRXYsg!In6F zmJ+eg?YaBJKek4zY>4{GRq1F4qa6mZ(VpGwXlI@8V4C|lIAyN8(YmDS&OSUAq()*A zqTo*7jlHEc+MJc}8(oRNGTbZ*lhgRl?@!5#+tgN~tVsYC(|}^cj;%V%`=bX3a>j%+ zz3447tja|B#;7c1#LtSDtZKQ>=#gXHOJKwgB3N&tRHM1fPwZIp9b{|24M6lOya3*u zF@>bA++!*r@%{=+LkZV2(7M$6jgiuUYX+?ATJQY8rWve`s65x`0|r}^9sgbXip&<7m0fGc zR-^o1Ad%_6raYXnNe-`L%s1ZLB%XBbmudUlevmmK z-uqrzTj12AZ=_}zRkO#LyNZZg*!ER>IpY=COIfvmy?M?0x)RCc$4VLP2G<@O(Rvtg z1rN!%sP2>E88lY?j2vb7y2~XvDtE0f1z!qCT|N`Am{Zyvq47`%zK0l^>)sxjMS13= zZte^oltTEb@m>(#ZG;-OdKHR_jqxOBe5PSqFIg8XZZxVW`{>s9`~%t_c5Ul-+(5+8 z^r=3)H~mu&fq|&=$bZa%%>Q~a|9Lw9ix>FcNuA@C&t9XB$;9D|1K-UvJh057&N?}- zzcOC_eA^w;Kad%Mn5^x=%cD-P&~_7*(8rCxoZqo}dO`2Ybqxv}YJUlhpLrnK#-3TU zqy3%}1dt-r(cv8gnq!ge5;tuO@`+oaA^00&#ncOv#%f;K^r&jVQJ&u(n+W!&LoLmhLp2q;ziEP|Dpyt^whbR99(Y5m1n>_d)S`(>q8C3k?yj-}C z7g9E4D0H@%Ie9r&=yN!rK0dxSVWQZNaz1p-kS~H=W~t;YRP$0J(xdMdmDDL;G3TP7!1s&9?`S@t8L6M6 z5$+Pa=9FLeN4D}Ciqv6qJNNy)FyHbGx^`}rb*{&BMe!kh7)Jf}o4X+w`ZYRYb2Hzk zTryK(Ipr-fe>fyHn(HEc8=3{8@FYgi1XAfi&X!8!QyocZ@i!e=>wMSg!jh5%)6yhP;}k{xDRx2ajdqNuf4VCv5F(UN@?L9f zm<${yT|u?1I$1G1?Fucc*&hOy_6w>gzvHBn%1?N7JeR{s|CB zng_)%5p9@M=3^L*IyY`^P%2hE)38)@8zTR4s&lhl0o%J{al*=@R@oy_0xBW31S~b8 z*l0ipWJGBUT4!szuFYeQn>^Z>Mjrx)bvcKw{&-$u;T`5)IX>u7aGRMD1U?JBrg7f#*&=myjOfdc6jB2hw@}C?|~WtjQI2XUx)rW zz)vt&%P8$#xHrB}My3!Y;$o-h0ten{~b!X#9xW^y8Y7257bsZfd!swm!{xYap|k)2dSv_?!W;9Y2PRUf>agh1O-8*2}myy5fBj&kzOJK z(xgdm34-(zih$BW5dkR?=`}QoH0izf4hba$NOFJMd%kDhXXc%m_nALf$s(+!Yww-w zIEl7Oel*B7>F0s>W{;Jl6YBynZb>n4Gb^Rza(q|mpBB`gA4og`a5m%t zQay^?fIArTjQY&AgaWl_ClJQW0wHJU#dnVmw2z!|TGY%?pp83|hrL`WD3eu!YQn%ulZ{ zN076&*E2w0$KJvamYS_=VUJ~5W@vW_y#aQ@&NVm{NZhq6_4ZA5XE?LH=$sJdGh1V~ zry9VtjKtsB&Ct4yY=_V^;(uxOIhaSIVHFQGc>W?Aw^16AN*E08D*x1Er(88}b5e0k zleU*oe(_v0kS<=g!Zg!(gy5yDPzIlfZOnNMNIM%R)y6%(f zQt6X!gc{BNy?ZkLVx~IKomZ?+M@}g*{L<^&r4EsP{6K9?N*2H(LUxVv#~Qx2wHGEH zFoTPufRWf0h88w7fp1DFP-z|rK4yXRHeGMZnW|++nDhe!`(T(hBYwWsoAxRlOfw-p z=qm1p0EWSwQ%}V;_z9me#zY?~V)>^=Thb}Au#o}K?_a@}=3L$-*nhR36L{}d{~TPg zH@$@wR5^Wg_fVj&kDIj@qlc@Ni$pbG`~r7Q1(#rLFwOuT>@~b2`Uai7Y>(-0gksgm ztL5I{XJp&MykQnG*Rd9EkODx8gK}bc4`Wea@LY7^0zizPS07<6XHBF#23v4W1Y{v7m8!BU-l)xADvGNQNQAf_ssLSD^{@Y?FZz#C z+&{l#cId?IYXRihx3}#?oNP1}lj+%Id0%z6;CO;m^>c$9&LqyX@rqcQ;Uz@77CG7= zU&X;IYFrHYq-?p@n~8Ws|CPkZs}tl?WVZ`m0MfBcx7UD4(oJ2dh3v-O7u&q$6t^aZ z*cVM%piehDL5`-)iEI#bWLpAt*yIGA#`C5La4tL%gH^gixQP}0a6|0&49>~Ts?*5A z6pEwe&T}t(q>d@)+CJ^#2?+th8DMhrmEplu?fbEF!k87^Q?EASzVLP0J2g!gmn0$2 zqxt*4jc9o)RRoKrjkKY#qFtnLV2uX&k3Rd2vVZuG?(Sco0sO}a)J8=Hz<->6+wh3Y zXAaGos3e3OfnT$8^+|0%3w!VO{q}KVe7H|XuC(QWMrA@0hh=K~JIc!n!yL-K zb;H#y>&oO(UPRQ8BNl=Y0&JW52+sfR^8e%au)qFAKfGWK-U*O@w5crjUDLFVdNQ|r zJ6V7u&&TQTL7^He*RL2d-b)#rv0Ex$Ke< z^J?8&Hx4)v79?3h%VYC3cIFqVV8Keiki)=T1ifz_EcGc^QtX8Ze`K=15u>J@_>MmV z{^(l*JP(0B+Flq^(%)s|);!cDjuP$tLj_O3FZLEU!lzc*sqwx&9t}uZ*^2WmV0VIn7f~;mQ4`JFADA@y!-U<1BR&uX9@Y3h6$&)>4%Qsl4<%lna z$8GS4JofpJBNUaX(Pll5(c7Evd1|VEo7`D^{*CHe5E*6NR8!#=i(LLpYN}SM`|yvr z7Jr&NQ$&Q+bOVi`iq_D+r(=Snb$WX7wYI`zs|iEoMl<7Z<@X=IbJtefo6y|_#N+yD|G;UP$I(44<%v3Qp5q-Njg)1r;;+5H`u zirFlgpH8TP*{`mz4#rJEoF|SFI&{o)S6_< z-RC&#SIVHVX3w%<$Ti2Sn}eHSugiI+jD5TrL)8JA zG+prSFg4cG#f+Av`tr!T9DOk5_+Uj)@3|<;K=e>&K2p7IRL}Zt#HLS83(OBwgjIre z4wv9TS-f$-iNMs_L-AqVu;*i~;yaKg&f=ui-k_MWC%nl5@k;*4*}ur9L)tZ$7$(zN|?2Swgi-Kp*3cw=PEJIwTK<=k+Q!s_-LXkB|<2DVnmUT;aepYRtMV{Sd-l8?b5 zT1jkBfurEp_ZdfT9FD1b;bY9qlWYDLx?WPbp@EsYMj@O_!-{+`m2zhH+bNX7% zsIw*yfjv=c$8)(NfS>*;Yvd#f*n;``d+rHtBe( z0R(f;xOagG9NUmPf3QfY?Sj8j4Fp{^3iEnNiKqMK=szKKh-Q+Hp#+Sqvd<3~pD#Up0S>xs{$eMb2Tq%a$e@-H$(f$HQD7{m{R*&pT7G5*_UK_PFh4IDe zT#4jOfW-f)dDnvlU+zK8Kie3^&}l#I(T3*<dv854ry_;oE$858M z5GQCyG{7ZwiI^VNj)1;{V~~-K`zX9XhJoQcv*)f9);lCeaw_LMKfCU| z>@hlhxXG5Qe*hl~5iWL~{|440a4b4CNXBZ&E@sCz_{oBPL6wp>NB)qR|4&cjLny_k z1$qs|VnE6dtQos~iwN?n{?KOT2nFS`uN$i))bj-Y525dh(yza%^J?89^bEc->=JQsuAmU^dFPaKL%vg*ZYw4Jv(qE2= ztT#8+y*>nD_J*~1x%c)o#ZLGOhnJ!>zC5v1O9Wy%a$_pQ7Radhk|0lfcya3Z)8)eD z`f^Oilv73!lY6n;L>a>)-lS{y6_t&C6;<_rK}P01k}kf@ytWfCsS1tSgkiKrBMxs> zS1e`T7=+K6TG!U0m%8Y+fGNxg&I@bXLT9K`H7-(mtOz#HVE=tKAujkpKH%3Z$4AeZ z0yf~`{l!BswA^lMbniGYmOZkk{16aXKRNz?DOCRXa|TVk>~ay5ouG>uk4@-S|LVXb z`FpO^@#euE3yI=NEy3|jQ(c3}IyOX*th;4}(T_1u@YEi;k%Y6u`eM;7NGiu4sLyhn zT~@9gt1)Ajrsbs@SZkoNrFSb9eCDt04R;_hs6J>xz2S-r;ktY4ycO0vw9)&brKCJt z<>UmtLXW^9V@(6!3WGHcIerg6jN8M&34AEBeNUq#4-zM;awL^}?O-ytGGyb1(>iem z_bqYYG>fz2oVG1}W44(HmIsCDpUz?t?fr}U5q`OggiKXnmAz?e^SW&%C7w{*a?Lj? zJ7$5tNoONAApKlx19Cut6}k`WH|2<|0oL0m*X+T^6Dy(>p!$0}$4ZCM-|IHmU3%FxYf16{Z0CP;X*7Q5K3|lst`c6xY3N4;UV@Q>Rg`#hB|WT)34nBD>gU2c#MN zF7-<>$XjzZhO6q1!oQcCoiJS9$a^|$U~kC6!Xv-_4T!f|kX1U)Ic=@Tw>L;r%$+h3 zZKyl{Jy$@$nt1%j-Y!!gts&EcYuP?C%r=&Qh@T0o9u9e2cU2{&@)JTBF0XT1Yc@lMU9ogZlF_WDtxQLPm>%Byj61g&z)03DII-i} zWcOXJ|6C7!skZoC{GGas!+PVTYH^1b`5jLWKQLU8miI!WlYjN4QuIMu{;g7D0OQLS z7nl0OxP>rdeY-_=<73zu+pCQtygYuz3vf3`pCU|;nJ`K)!$kWqEWx4_c=USU&qked zf;{?~4+d%oG`9+{C0n3uS4G&;AXMiFmgByVQpFGsy^j|(sk`~AYP@p&GaS=l`*0oe z0rq%uf&m))xKtzCxo;5iCJEp0u?9y_#n=O&Mj0 zX0<&pc{Kg}mJ_8hM_Nr*WDw&T(C;#{=nXoISFUZR($#z>|wVWJ04sXLoP@@!jwkJb6j@;CP6yw`*B`$BE^@7 z6_l_0J9(zRlHe_ zBaZWS0I#PnSO%T{YLVHFVbp<-`Q_~k=m6D|y~*>0^YsN6ZoKJ|)O&_V1p%KLuS7x_ z%FD>Q^Vz$Cmu?$=amqZwfyJ#rk6W^DlIvn;!FCrZnQ%yu_|vEQK)MC*u()1JgTCVK zcwf}Xn-RRV`Ya}{_LYjryD#j-Mj`@iw;v8+tNd6#7_~v-36-9;tN2A*N4}OwC3CoZ zLM9GxEbjD-DT7*Nxz3th^R)LLIX|{Qtp$p{Jig*mHL2q?_n0TpA6oSeh&9l;ve}y3 z;E19&@ADUm?_zJ;GqROslkF6n-Zsd_Sd*tmr@B}_M-|OJWNp4)ci^eRca%v(;#~uH zKCAPD>u>NqSeN!GZ_G5_OBTgeR;EnkWj;Hx%CWBx2)5(pSB~e3-EitWH|rk~f(XE>#Tki~#jr7i%~uoa*Oc}r?B?6b$73Xd#U zY>W?pT))b~GF~_HBfo)P7Z2K=Yv7-WP1TU=egM3wCC)VPpFt&gb!Q^(^lvF_h~uZA zX5a+w488StE2P&4-3evIP=)U`>Mhf$aY;O@H0x487b!Abx5=E&%?<82Vr~Z#My3}K z!Q5<4u%F%>d;GN3>>hj^>0K`aNAw0M)lM0@vrqWQ@jwE}azUJu3_fC8>2B>oN%or? z?AAi6r5UzALQcN$?*E#X@V`UD|DycJSb#wv-IHapt3)KEo*pTpaM8r_MnkOqUV!kz zvQ)_8t!GZGPBp39!_xExt1%enlonc5j(}9lai4QdFZtQM@gJ5Fs^iOJYzs7+wz(HYc_~yvp3HI(3#gz`}B1 z{VGXa}HCz<@M3V}`$gYpmd) ze>lWK5DQ>!g8>9|)$B;`;?Z`r2IK#cGkHzB^4k4el0dZlaZS2+V2Z8 zyGFun=UyUdKVKEF5(^sw#==*d{*VX5|4|10cdwv-75K5!%xy1PieFb5HkcJj)ZDPJ zv!2q;j{K11%y97iU^LQVIfz;YIeZTx}o=`*d z+BqC%UFY35>GnqyVD#zDIJcC35UxT>`-c&D{`IiO_5HC5Hn(0)n@riqqmWZvYaba3 zlDMIOBw>4T9xrebj{2cQp;WdVJ}#NwkUiV$8nGL6Mi~jr5FPjK)$Rn?UNywk#Trgd z?-|gLT!1fcHokwEDnO}DMxfgM~GhCKo^Ha=;-ieZUVc)>|Ic$7Xp z`WKnsW%H3h4KfBl(wj&jz+``*QB)WRB40c%Ha-;{B?SX@(C0Jiqw$^OMbz$mG_K}A zWTR43GkUFGYvr;YmQG}mv}8L{zk2o+c$R$qKpk#)!%V{({M?Mz;whw2B$1)t z<-h?;LpFgSPL_|o-IEBqO*6lT>V~O69vSuq#Vd0%S(KodgmAHAiR+w;sikCo!p!e; zed5sO^wo=bDPk$H*bKiIPiE9Z3MlYzw5lj^H-}?En)p!r8^QsaZ+L25!K=8AOFi7v z*16-6E9PNh)XyjtKhH;Qh>ndfTHg@1{Mc!jec#LOBwZuMUzZ#y?3WsZ@5(wMMZ9v zb$kjJdNJLN(FQDxU#00fV%nsuSL@V+tLjpz#%tY(E5~nosNEw&s)v6l`TI zXHD}&AAJdFElH{X8}zv{buQW{A5V|x5ETY3oG?jCZ^E(OEpm`J4}O}|^4+=+FO#v& z`~0CzgZ13fcWGsAH36RU>%~uBu5I=im$CwS0=A6t=tj^YlG_Km-$oK1UL2|H8JQNk zMhk!Q;{LBKUxOEHIy@neP;e!3XS$3)g=Nf|=qdCue31~AUdWW9wnEHWCZkAJS7}L5 zTWzH+K0h(*j|l)R&VziM&)X~nD>Qc{bR&K~5IrrvyHyrWTOw;f7WG+ey)Mz#^FFhG z>mEvf{S?vbWHwyIrShaX%uq-Vw z7B2Dqz_rkTe*UB)r?x&u1vI~mao#WbCcI_q^7>f^(JR!?C+cabv`@wHl?Cwbv2gt~ z-fG$J!7nK^H_D0ITwNJg`#fM`pHId6+qD$r2pxm@V1QP>>2?-(bInNQdF4DsUrDsk z3(<Z8A?*{>a zqx-6aGgH3F@%^lw1`pWksV``VnHd9bou6)BM8|fpt9S5mGmTDPS%3QTs4IO$E2cfG z_9KNZ`jb{*pS`yu%!zq7W^l%|H)lD8pMj%jL;qvE@-bzl_WF8lFD364rDu;#VBuX! z68G+U-_%#;O9~>}b3CoV4=$_X!?C76mBb^Xr?*T#?!QGB0ag@O+xc$QKgmhcwTDGCxmX1N%J^i!X(@-HU7vpTQVheEtEe zXS&fOM?$z7ek0If@8MOJSwaF-1>c4Z8&@1o;DU`Wy+gD~IUIZwl-S+Y)4zG|-DGj# z`mq=QBs-S~a2!$+CrAw=l}2Kh=)^CVdZxc<|7{vE?vh!9OjVLDrWb#@e$R13u%Sou zim{8!dfe39C2=4_i8q$XSE#pxjOv}12S1cKqWxu#!Al2GU-=t?Yk(s28ZHSF-V%E~ zzg0`KqsA@e`;aaMtw3$d%P*t6f07Y%XCe7?etCa)esQ0!-E9#b;&h{;m~pVHM11di zwIcNg5FYOaT#|2`oVCA@UFO~vV*xtFvyP;jO+a#ni?#TS*^F$W2ImRi89mtsB^luN z)&nB9)!V8BB~4jN>1QFQq8;=25bTwosA~ir&!v5~dBtO5S4%%rJFCE3U4h53?rrdQ z09-aIx6J-55C?VzyZq$!QMn({a znz6GtpIwA!XGfxG86Smd+)nt-%w%}`b7Tv75~LCagrUS15Cm&#u=DW6sFR-u**-in ziClM$JXC)9$G8sBv+NakIWbIX;$D2mD_gR}D%f8)gi16-uUc>`ib!*!nO4{$WD=E! zKdRKYgQxXNtVR*(SkTq_zC~B$%+~p-sA&K2yFUb_J9l#9GSbKnkg1_S`EAuSa$on0-e6v&#*+!p+Y?vwwE`rJwPq0| zm@)%QEyP~eL~nf11A_cRwhq~B`!Dv6f9^Z|hxbhlxVP8~7&IC|?$A(ucT9MftKL#H zvie&qzKUhWN@7h02-%300-{Ou6n_3cV z@F~l78tjd}1=6>ShwCFE@gF>V~Fi*CFBKxc}eUp zGzHfBsdE?yXNs7??@%p_d7l5Nc61)@jV4KYuIv8(&tMk0;Yq~dl1Qzln zik>r=k9a_&f0Ozfvc~(SD`1H`>D8;{e|KjjlPof^DV^g$T3y-nWI-xNALoj7wRLUe z?f8{MsI8aGhQ#~#?=7rM@(yU7Kvoe&ny01^cR;W7x%VG~zW?eK_OG&E&JZ}u@~T9@ z{mq{K)%jJ}*yVYF)i|$&3@aH~v723Ntjlb&XSik$Vw&&*gwjD;lb!m@$eeWiow+Vf zG3FPuPhRXi+_=K&DS6~jEPv^trq~}ctWl3UPKo_X(Q0L?KdPzX>?ZN^gPV)+6$=d` zKeUsJlsfVF7N`xyzI}HOn%P=ecb{{<57_x{p8@6P^FZUXp7YywXidCm!5s6Hr(;h~ zf7v8mGwgsOP}EGcE%4eo)xv&|Q}r$jH+MxN!TCfRcJ#)v9$+mjPL@LKV~UjyV4t^8 z^yN6m;rU*j701Et9w?XgrJ8DVv5+%(fiHyc(=S;f=${V)|9IbmRRb@An)(Tcq})cD zrk>8EhyX>obxMQBppyZCBg#f8AfLL_Wrxd!6d(fIABKgJd2j=dS^P3=oQmXV(P!bf zkV*dhM}3lRQ*1Uws562fCZsID^^kSnBKdC#At)AH{7@9=zmczhiy{z_n-ypangQr7A5A?BBr^N(XxD%;?73JS!^;Hf-`vs{ z25_$gPp1K~XL|?evVvzJ9@L@n*$EWb)bfJ2zUo~-(J(QUJRzy-yTUyT-zl_hlAEav}TKi!JAyXdxC* zBfCNI*X??zvWh%&Revl0tNku+<$&N0xB}ZLeCY^fPw45& zH~Xd6{YKWdI+fP)wJ$GiY?oj|8n2*T*OCb5+4NZ_$MRMKP#l7xcE|{V#5pwJ@>rhE zZuMvY_%69mLxn^qLtv@Ho7alncX3FIVX%YC?3tCZr$Qgb{V6(FbcJw3e1kIGjc?hW z;CMrxEoRZ5ae4i!yZEH58=-#>eI|}n#AjmK+rTUe z0`7|pY$k!ZV=h^D^{yzEEHG9)THz|IJGo?I#LUO`(b<2JK2U)|+jv`RufZ3&t#?|K z+cdvivqN0gd9QR+ihbqHp?bX+yI1K|CW`JjuNsKRE2Sgr_4*Vub_{UdeG_&o)4`!s zz~_4zx*f)(09)9|ns2kXJ$hvHg|E>s@Cf&-<3y07P+%r%xiEXkHD+9BbkP6B$g%Ki zoVku+L)O`W*R1f*-q;5}q>JSfd!b(o2UW>6ZvWxbkV{r-`I}?LveRn9Jvo~0o!x(A zHmQv}yrbxfO}0dodT{gNld;!2Z!Gl#(Zyq)>8>i5UG~@OBA5m~BupxUo-WyC_YH-l z%0D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 WrK9q5?EhYyKDD3Wa~y}CNB#~;c!V$j diff --git a/ios/beartracks/Assets.xcassets/AppIcon.appiconset/l0_icon2.png b/ios/beartracks/Assets.xcassets/AppIcon.appiconset/l0_icon2.png new file mode 100644 index 0000000000000000000000000000000000000000..82da01b7b9faa757766673248f11e724f78dfc28 GIT binary patch literal 24345 zcmeHP30REl+ka<_&V(4El9tI9mFiF=(r90lkV=&7osd+dZJIeqPE?0%k%lO=2w6(Y zoRg&!F-loVCA3J3_HF9B-?H>P-*vw0`d{Dqf1mIA=D5yfJiR^7bN}x9{@u&-ymQdT z+EikM>mJj5ax#Z?>``RNyn6 zpd9#R;1?+HFIo7XAcpZM#4z}q0)Ge|_3KY*1aH{)&*X!JZ$8Qs1dA{?T5P+A^69mn z^^}rgv5JxyIbT`Y63&@3*CLdDSK5~w5hB}Wll#{xf>P-5x?IQ(*mUX7hsl|lLB(uq zYNV5YQd{Cj_b00Tj{SWt9c%lhus8&TN~1HFgC7h=_S)Cfjxt3@>AhDu1b;8~tQdnq zj7r%!W!#tF{W1xKvjzL@QA{QwgJ;FMg z91h{anKtQnbOJiDaM*WQ$o;qw6bhfPoI4qvfI;jL`zG_i2R=ciawx~Q84Upge!wJ} zMt#L*@E5og8jTpH_9_Hjh(%OPL~)=Fqtgj7hwEd-kqH3EIVcV^5s*WW69M_f0>L5^ zD4VrN%MBjCCw-x!r@NsfGeX^?r~P+!h$Lx^y!n(E!qt76>}1rUx`xw;E~{wFjiMwO zgx2kG5@Uy;%^|qGVEDap)|hkVi_?jy)dzzIjsC0mu-Fs|i@ib_b$Mv}3LzC@H*`W)Sb^?ZOzq)tW^JN-eaEP^xJjNhg|5>tej3rOXt;{1vFbh1ubQ zegUb!ml{ppzFGYe&h^d}-CZ|(CXQn9Zt)-Gue>SMtLGHl*IpmHL}?`$R#QK95v5`o zVvZCMZ4PxgQT+Mh`Tt5F&o0jH@0EA4o-)qWv7)v)qqgt7mXEMkcGGw-G8D5+xF=30 z9EzX+QJGtEJ3PkOGn(KUfGOJ09Veo!WV3=r*sNH)9UC=+QPHzZ8xalzhVk#iq2fh% zM@;s9x0!}KUvB)PmMZ_puPWMFwmx}x#<)VCS{HhwKcI0Em3CZwTbcfeH#O?ierA)W zSKFAzkhbRf64ONP5<})ieq$L#>-Cv|SSY7Kz@?sDjm2yYh}q6_ zFD^y>AOg~3GrpH98k}p4A+kP-Yc)sL8wWXp_#XFZXr_`0IkMlY$VJ$Cze46fd76YJ z1JbZJjnf6n=z3;QhD@zUJBCL6*2zqwX48spEUgg-L1+taV?sN_-ZHmY#Gvaj7eh+I zskTFf7KB2Ual)$hD7xNM5JUv>U?~4Pkl9H={aq!NH@f9aftCZ#tn1gSZELBsX(^W7 z9k|mjAvK*;fFOlmCA{&rp)$4I(`&+(lf$N`1@`DvIF%Xj5;;qW$TqvfDD<{q$+qk4 zBhk^w2@KJ*V7ek426^b8z@hVIpRjtzvAo}QD?y4|W*n0imBD7`@3NJyPSkjkUbEup zAcL?Lar1k&Waa4U)PAVCvRA$3<{l{88a0*oOE!sfJXE!@dgkN^IuSQL8R-)cTo2$X z(X%2PzC@*e#2$LdzMqfZt7FG$XVsssc8fRDc=7bA@yFEV8v}P1Tc~z3BaB_{W#2yj z=bNlRwalVGSiHubyXR@;wU*l&~l-1yNp77tJZ?sn7^;4KmfmqWoXr zIU5ar!u+Wn_Ez6$b^u+ExeB8Ek{SYw@>vk&h4Qr#Xi%97f*cW-M{^k3Yv?efW>1mF zvWkr$$n0~&hL&?seDuKH+I=nJ5 z(>)Jk8*96Q+j5+q*4IUobGOr}wMT{?vfKcuwMIA(0A^_UD z0mD8|LHROd29pT6vvLmB?A-zEvxCXT_;M^T6KGM3<*L5e;ypl%wy
I0J3t6o#i3-v=ok?_xRhpuE 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 Tf;RyK{AX@#ZIo=_@+ - LSApplicationCategoryType - public.app-category.productivity - NSHumanReadableCopyright - Copyright © 2024 Jayen Agrawal. All rights reserved. + ITSAppUsesNonExemptEncryption + UIApplicationSceneManifest UIApplicationSupportsMultipleScenes diff --git a/ios/beartracks/LoginStateValidator.swift b/ios/beartracks/LoginStateValidator.swift index 4cdd4db8..42adaa63 100644 --- a/ios/beartracks/LoginStateValidator.swift +++ b/ios/beartracks/LoginStateValidator.swift @@ -9,14 +9,9 @@ import Foundation /// Ensures the user has a valid session. func checkLoginState(completion: @escaping (Bool) -> Void) { - guard let url = URL(string: "https://beartracks.io/api/v1/whoami") else { - completion(false) - return - } - + guard let url = URL(string: "https://beartracks.io/api/v1/whoami") else { completion(false); return } var request = URLRequest(url: url) request.httpMethod = "GET" - let task = sharedSession.dataTask(with: request) { (data, response, error) in if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode == 200 { @@ -28,6 +23,5 @@ func checkLoginState(completion: @escaping (Bool) -> Void) { completion(false) } } - task.resume() } diff --git a/ios/beartracks/LoginView.swift b/ios/beartracks/LoginView.swift index 121567d9..8f5adb1d 100644 --- a/ios/beartracks/LoginView.swift +++ b/ios/beartracks/LoginView.swift @@ -6,41 +6,95 @@ // import SwiftUI -import SafariServices /// Login sheet view struct LoginView: View { @State private var showAlert = false - @State private var username = "" - @State private var password = "" + @State private var authData: [String] = ["", "", "", ""] @State private var alertMessage = "" - @Environment(\.dismiss) var dismiss - @Environment(\.presentationMode) var presentationMode + @State private var loading = false + @State private var create = false + @EnvironmentObject var appState: AppState var body: some View { VStack { Text("bearTracks") .font(.title) - Text("v5.0.1 • 2024") - - TextField("Username", text: $username) - .padding() - .textFieldStyle(RoundedBorderTextFieldStyle()) - - SecureField("Password", text: $password) - .padding() - .textFieldStyle(RoundedBorderTextFieldStyle()) - - Button("Login") { - login() + Text("v5.0.3 • 2024") + if !loading { + if !create { + Text("log in") + .font(.title3) + .padding(.top) + TextField("username", text: $authData[0]) + .padding([.leading, .trailing, .bottom]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.username) + SecureField("password", text: $authData[1]) + .padding() + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.password) + Button("login") { + authAction(type: "login", data: ["username": authData[0], "password": authData[1]]) + } + .padding() + .font(.title3) + .buttonStyle(.bordered) + Button("create") { + self.create = true + } + } else { + Text("create account") + .font(.title3) + .padding(.top) + TextField("team code", text: $authData[3]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .keyboardType(.numberPad) + .onChange(of: authData[3]) { _ in + authData[3] = String(authData[3].prefix(5)) + } + TextField("full name", text: $authData[2]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .textContentType(.name) + TextField("username", text: $authData[0]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.username) + SecureField("password", text: $authData[1]) + .padding([.leading, .trailing]) + .textFieldStyle(RoundedBorderTextFieldStyle()) + .autocorrectionDisabled(true) + .textInputAutocapitalization(.never) + .textContentType(.newPassword) + Button("create") { + authAction(type: "create", data: ["access": authData[3], "full_name": authData[2], "username": authData[0], "password": authData[1]]) + } + .padding() + .font(.title3) + .buttonStyle(.bordered) + Button("login") { + self.create = false + } + } + } else { + Spacer() + ProgressView() + .controlSize(.large) + .padding() + Spacer() } - .padding() - .font(.title3) - .buttonStyle(.bordered) } .padding() .alert(isPresented: $showAlert, content: { - Alert ( + Alert( title: Text("Auth Error"), message: Text(alertMessage), dismissButton: .default(Text("ok")) @@ -48,38 +102,40 @@ struct LoginView: View { }) } - private func login() { - guard let url = URL(string: "https://beartracks.io/api/v1/auth/login") else { - return - } - - let credentials = ["username": username, "password": password] - + private func authAction(type: String, data: Dictionary) { + loading = true + guard let url = URL(string: "https://beartracks.io/api/v1/auth/\(type)") else { return } do { - let jsonData = try JSONSerialization.data(withJSONObject: credentials) - + let jsonData = try JSONSerialization.data(withJSONObject: data) var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = jsonData request.httpShouldHandleCookies = true - - sharedSession.dataTask(with: request) { _data, response, error in - if let _data = _data { + sharedSession.dataTask(with: request) { data, response, error in + if data != nil { if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode == 200 { - dismiss() + appState.loginRequired = false + loading = false } else { + loading = false showAlert = true - alertMessage = "bad credentials" + if type == "login" { + alertMessage = "bad credentials" + } else { + alertMessage = "creation failed" + } } } } else { + loading = false showAlert = true alertMessage = "network error" } }.resume() } catch { + loading = false showAlert = true alertMessage = "failed to serialize auth object" } diff --git a/ios/beartracks/MatchList.swift b/ios/beartracks/MatchList.swift index 48aa9510..bc30db98 100644 --- a/ios/beartracks/MatchList.swift +++ b/ios/beartracks/MatchList.swift @@ -16,7 +16,6 @@ struct MatchList: View { @State private var loadComplete: Bool = false @State private var selectedItem: String = "" - var body: some View { VStack { NavigationStack { @@ -93,6 +92,7 @@ struct MatchList: View { .navigationTitle("Matches") .navigationDestination(isPresented: $showSheet) { TeamView(team: selectedItem) + .navigationTitle("team \(selectedItem)") } } else { if loadFailed { diff --git a/ios/beartracks/SettingsView.swift b/ios/beartracks/SettingsView.swift index fd76892a..9c288994 100644 --- a/ios/beartracks/SettingsView.swift +++ b/ios/beartracks/SettingsView.swift @@ -15,13 +15,13 @@ struct SettingsView: View { @State private var darkMode: Bool = UserDefaults.standard.bool(forKey: "darkMode") @State private var showAlert = false @State private var settingsOptions: [DataMetadata] = [] - @Binding var loginRequired: Bool + @EnvironmentObject var appState: AppState var body: some View { NavigationStack { VStack { - VStack { - HStack { + Form { + Section { Picker("Team Number", selection: $teamNumberInput) { if !settingsOptions.isEmpty { ForEach(settingsOptions[0].teams, id: \.self) { team in @@ -33,15 +33,10 @@ struct SettingsView: View { .tag(teamNumberInput) } } - .padding() .pickerStyle(.menu) - Spacer() - Button("Save") { - saveTeamNumber() + .onChange(of: teamNumberInput) { value in + UserDefaults.standard.set(teamNumberInput, forKey: "teamNumber") } - .padding() - } - HStack { Picker("Event Code", selection: $eventCodeInput) { if !settingsOptions.isEmpty { ForEach(settingsOptions[0].events, id: \.self) { event_code in @@ -54,14 +49,9 @@ struct SettingsView: View { } } .pickerStyle(.menu) - .padding() - Spacer() - Button("Save") { - saveEventCode() + .onChange(of: eventCodeInput) { value in + UserDefaults.standard.set(eventCodeInput, forKey: "eventCode") } - .padding() - } - HStack { Picker("Season", selection: $seasonInput) { if !settingsOptions.isEmpty { ForEach(settingsOptions[0].seasons, id: \.self) { season in @@ -74,35 +64,31 @@ struct SettingsView: View { } } .pickerStyle(.menu) - .padding() - Spacer() - Button("Save") { - saveSeason() - } - .padding() - } - HStack { - Toggle(isOn: $darkMode) { - Label("Dark Mode", systemImage: "moon.fill") + .onChange(of: seasonInput) { value in + UserDefaults.standard.set(seasonInput, forKey: "season") } - .padding() - .onChange(of: darkMode) { + Toggle("Dark Mode", isOn: $darkMode) + .onChange(of: darkMode) { value in UserDefaults.standard.set(darkMode, forKey: "darkMode") showAlert = true } } - HStack { + Section { + Button("Clear Cache") { + URLCache.shared.removeAllCachedResponses() + } Button("Log Out") { if let cookies = HTTPCookieStorage.shared.cookies(for: sharedSession.configuration.urlCache?.cachedResponse(for: URLRequest(url: URL(string: "https://beartracks.io")!))?.response.url ?? URL(string: "https://beartracks.io")!) { for cookie in cookies { sharedSession.configuration.httpCookieStorage?.deleteCookie(cookie) } - loginRequired = true + appState.loginRequired = true } } .foregroundStyle(Color.pink) - .buttonStyle(.bordered) } + Text("To delete or update account information, please email [admin@beartracks.io](mailto:admin@beartracks.io).") + .font(.footnote) } Spacer() } @@ -122,18 +108,6 @@ struct SettingsView: View { } } - func saveTeamNumber() { - UserDefaults.standard.set(teamNumberInput, forKey: "teamNumber") - } - - func saveEventCode() { - UserDefaults.standard.set(eventCodeInput, forKey: "eventCode") - } - - func saveSeason() { - UserDefaults.standard.set(seasonInput, forKey: "season") - } - func loadSettingsJson(completionBlock: @escaping ([DataMetadata]) -> Void) -> Void { guard let url = URL(string: "https://beartracks.io/api/v1/data") else { return @@ -142,7 +116,6 @@ struct SettingsView: View { var request = URLRequest(url: url) request.httpMethod = "GET" request.httpShouldHandleCookies = true - let requestTask = sharedSession.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) in if let data = data { @@ -168,7 +141,7 @@ struct SettingsView: View { struct SettingsView_Preview: PreviewProvider { @State static var loginReq = false static var previews: some View { - SettingsView(loginRequired: $loginReq) + SettingsView() } } diff --git a/ios/beartracks/TabBar.swift b/ios/beartracks/TabBar.swift deleted file mode 100644 index 3cac2ec3..00000000 --- a/ios/beartracks/TabBar.swift +++ /dev/null @@ -1,110 +0,0 @@ -// -// TabBar.swift -// beartracks -// -// Created by Jayen Agrawal on 1/9/24. -// - -import SwiftUI - -/// Primary navigaion element. -/// -/// - iOS -/// - Uses `TabBar` view. All views called by the `TabBar` use `NavigationStack` -/// - Mac Catalyst -/// - Uses a `NavigationSplitView` with a standard `List` sidebar and a content area made up of `NavigationStack` views. Some of the `NavigationStack`views will call child views the manner as the iOS app. -struct TabBar: View { - enum Tab { - case teams, matches, data, settings - } - @State private var selectedTab: Tab? = .teams - @State private var loginRequired: Bool = false - - var body: some View { - #if targetEnvironment(macCatalyst) - NavigationSplitView(sidebar: { - List(selection: $selectedTab) { - NavigationLink(value: Tab.teams) { - Label("teams", systemImage: "list.number") - } - NavigationLink(value: Tab.matches) { - Label("matches", systemImage: "calendar") - } - NavigationLink(value: Tab.data) { - Label("data", systemImage: "magnifyingglass") - } - NavigationLink(value: Tab.settings) { - Label("settings", systemImage: "gear") - } - } - .navigationTitle("bearTracks") - .onAppear() { - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - } - .sheet(isPresented: $loginRequired, onDismiss: { - loginRequired = false - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - }) { - LoginView() - } - }, detail: { - switch selectedTab { - case .teams: - Teams() - case .matches: - MatchList() - case .data: - DataView() - case .settings: - SettingsView(loginRequired: $loginRequired) - case nil: - LoginView() - } - }) - #else - TabView(selection: $selectedTab) { - Teams() - .tabItem { - Label("teams", systemImage: "list.number") - } - .tag(Tab.teams) - MatchList() - .tabItem { - Label("matches", systemImage: "calendar") - } - .tag(Tab.matches) - DataView() - .tabItem { - Label("data", systemImage: "magnifyingglass") - } - .tag(Tab.data) - SettingsView(loginRequired: $loginRequired) - .tabItem { - Label("settings", systemImage: "gear") - } - .tag(Tab.settings) - } - .onAppear() { - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - } - .sheet(isPresented: $loginRequired, onDismiss: { - loginRequired = false - checkLoginState { isLoggedIn in - loginRequired = !isLoggedIn - } - }) { - LoginView() - } - #endif - } -} - -#Preview { - TabBar() -} diff --git a/ios/beartracks/Teams.swift b/ios/beartracks/Teams.swift index 94acfc06..4d8ea940 100644 --- a/ios/beartracks/Teams.swift +++ b/ios/beartracks/Teams.swift @@ -11,9 +11,7 @@ import Foundation /// Shows listing of top teams by scouting data performance, not RPs struct Teams: View { @State private var teamsList: [TeamData] = [] - @State private var showSheet: Bool = false - @State private var loadFailed: Bool = false - @State private var loadComplete: Bool = false + @State private var loadState: (Bool, Bool, Bool) = (false, false, false) @State private var selectedItem: String = "" var body: some View { @@ -43,7 +41,7 @@ struct Teams: View { } .onTapGesture { selectedItem = String(team.team.team) - showSheet = true + loadState.0 = true } .contentShape(Rectangle()) #if targetEnvironment(macCatalyst) @@ -54,12 +52,12 @@ struct Teams: View { } } .navigationTitle("Teams") - .navigationDestination(isPresented: $showSheet) { + .navigationDestination(isPresented: $loadState.0) { TeamView(team: selectedItem) .navigationTitle("team \(selectedItem)") } } else { - if loadFailed { + if loadState.1 { VStack { Label("failed", systemImage: "xmark.seal.fill") .padding(.bottom) @@ -70,7 +68,7 @@ struct Teams: View { } .navigationTitle("Teams") } else { - if loadComplete { + if loadState.2 { VStack { Label("none", systemImage: "questionmark.app.dashed") .padding(.bottom) @@ -117,17 +115,16 @@ struct Teams: View { } } DispatchQueue.main.async { - self.loadFailed = false - self.loadComplete = true + self.loadState = (self.loadState.0, false, true) self.teamsList = [result] } } catch { print("parse error \(error)") - self.loadFailed = true + self.loadState.1 = true } } else if let error = error { print("fetch error: \(error)") - self.loadFailed = true + self.loadState.1 = true } }.resume() } diff --git a/ios/beartracks/bearTracks.entitlements b/ios/beartracks/bearTracks.entitlements index ee95ab7e..d2d71196 100644 --- a/ios/beartracks/bearTracks.entitlements +++ b/ios/beartracks/bearTracks.entitlements @@ -2,6 +2,10 @@ + com.apple.developer.associated-domains + + webcredentials:beartracks.io + com.apple.security.app-sandbox com.apple.security.network.client diff --git a/ios/beartracks/beartracksApp.swift b/ios/beartracks/beartracksApp.swift index e1ad9e2d..277dfc9b 100644 --- a/ios/beartracks/beartracksApp.swift +++ b/ios/beartracks/beartracksApp.swift @@ -7,21 +7,96 @@ import SwiftUI +public enum Tab { + case teams, matches, data, settings +} + @main struct beartracksApp: App { let settingsManager = SettingsManager.shared var darkMode: Bool = UserDefaults.standard.bool(forKey: "darkMode") + @StateObject private var appState = AppState() var body: some Scene { WindowGroup { - TabBar() + if !appState.loginRequired { +#if targetEnvironment(macCatalyst) + NavigationSplitView(sidebar: { + List(selection: $appState.selectedTab) { + NavigationLink(value: Tab.teams) { + Label("teams", systemImage: "list.number") + } + NavigationLink(value: Tab.matches) { + Label("matches", systemImage: "calendar") + } + NavigationLink(value: Tab.data) { + Label("data", systemImage: "magnifyingglass") + } + NavigationLink(value: Tab.settings) { + Label("settings", systemImage: "gear") + } + } + .navigationTitle("bearTracks") + }, detail: { + switch appState.selectedTab { + case .teams: + Teams() + case .matches: + MatchList() + case .data: + DataView() + case .settings: + SettingsView() + .environmentObject(appState) + case nil: + LoginView() + .environmentObject(appState) + } + }) + .preferredColorScheme(darkMode ? .dark : .light) + .onAppear() { + checkLoginState { isLoggedIn in + appState.loginRequired = !isLoggedIn + } + } + .environmentObject(appState) +#else + TabView(selection: $appState.selectedTab) { + Teams() + .tabItem { + Label("teams", systemImage: "list.number") + } + .tag(Tab.teams) + MatchList() + .tabItem { + Label("matches", systemImage: "calendar") + } + .tag(Tab.matches) + DataView() + .tabItem { + Label("data", systemImage: "magnifyingglass") + } + .tag(Tab.data) + SettingsView() + .environmentObject(appState) + .tabItem { + Label("settings", systemImage: "gear") + } + .tag(Tab.settings) + } .preferredColorScheme(darkMode ? .dark : .light) + .onAppear() { + checkLoginState { isLoggedIn in + appState.loginRequired = !isLoggedIn + } + } + .environmentObject(appState) +#endif + } else { + LoginView() + .environmentObject(appState) + .preferredColorScheme(darkMode ? .dark : .light) + } } } } - -extension String { - func separate(every stride: Int = 4, with separator: Character = " ") -> String { - return String(enumerated().map { $0 > 0 && $0 % stride == 0 ? [separator, $1] : [$1]}.joined()) - } -} diff --git a/setup.sh b/setup.sh index 42f3f9ad..ff39b447 100644 --- a/setup.sh +++ b/setup.sh @@ -17,6 +17,7 @@ chmod +x update.sh # make i cp bearTracks/service.sh service.sh # copy service management script chmod +x service.sh # make it executatble mkdir ssl # create ssl directory for certificates +mkdir cache # create directory for server cache cd bearTracks # ~/bearTracks/bearTracks (git repo) curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # install rust source "$HOME/.cargo/env" # source (needed if rust is newly installed) diff --git a/src/analyze.rs b/src/analyze.rs index a01557ee..7ba73c3b 100644 --- a/src/analyze.rs +++ b/src/analyze.rs @@ -238,8 +238,8 @@ fn season_2024(data: &web::Json) -> Result) -> Result = vec!( + real_bool_to_num(trap_note) as i64, + real_bool_to_num(climb) as i64, + real_bool_to_num(buddy) as i64, + intake_time as i64, + travel_time as i64, + outtake_time as i64, + speaker_scores, + amplifier_scores, + score as i64 ); let string_mps_scores: Vec = mps_scores @@ -293,7 +305,7 @@ fn season_2024(data: &web::Json) -> Result = analysis_results + let string_analysis_results: Vec = analysis .iter() .map(|float| float.to_string()) .collect(); diff --git a/src/auth.rs b/src/auth.rs index bcaba57f..bbeeab73 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -39,14 +39,24 @@ pub async fn create_account(pool: &db_auth::Pool, create_form: web::Json, actix_web::Error> = db_auth::get_access_key(pool, create_form.access.clone(), db_auth::AccessKeyQuery::ById).await; - if access_key_temp.is_err() { - return HttpResponse::BadRequest().status(StatusCode::from_u16(400).unwrap()).insert_header(("Cache-Control", "no-cache")).body("{\"status\": \"bad_access_key\"}"); + if create_form.access != "00000" { + let access_key_temp: Result, actix_web::Error> = db_auth::get_access_key(pool, create_form.access.clone(), db_auth::AccessKeyQuery::ById).await; + if access_key_temp.is_err() { + return HttpResponse::BadRequest().status(StatusCode::from_u16(400).unwrap()).insert_header(("Cache-Control", "no-cache")).body("{\"status\": \"bad_access_key\"}"); + } else { + // insert into database + let access_key: db_auth::AccessKey = access_key_temp.unwrap().first().unwrap().clone(); + let user_temp: Result = db_auth::create_user(pool, access_key.team, html_escape::encode_text(&create_form.full_name).to_string(), html_escape::encode_text(&create_form.username).to_string(), html_escape::encode_text(&create_form.password).to_string()).await; + // send final success/failure for creation + if user_temp.is_err() { + return HttpResponse::BadRequest().status(StatusCode::from_u16(500).unwrap()).insert_header(("Cache-Control", "no-cache")).body("{\"status\": \"creation_error\"}"); + } else { + drop(user_temp); + return HttpResponse::Ok().status(StatusCode::from_u16(200).unwrap()).insert_header(("Cache-Control", "no-cache")).body("{\"status\": \"success\"}"); + } + } } else { - // insert into database - let access_key: db_auth::AccessKey = access_key_temp.unwrap().first().unwrap().clone(); - let user_temp: Result = db_auth::create_user(pool, access_key.team, html_escape::encode_text(&create_form.full_name).to_string(), html_escape::encode_text(&create_form.username).to_string(), html_escape::encode_text(&create_form.password).to_string()).await; - // send final success/failure for creation + let user_temp: Result = db_auth::create_user(pool, 0, html_escape::encode_text(&create_form.full_name).to_string(), html_escape::encode_text(&create_form.username).to_string(), html_escape::encode_text(&create_form.password).to_string()).await; if user_temp.is_err() { return HttpResponse::BadRequest().status(StatusCode::from_u16(500).unwrap()).insert_header(("Cache-Control", "no-cache")).body("{\"status\": \"creation_error\"}"); } else { diff --git a/src/db_auth.rs b/src/db_auth.rs index 01d1b9a9..0a8708df 100644 --- a/src/db_auth.rs +++ b/src/db_auth.rs @@ -72,7 +72,7 @@ pub struct User { pub current_challenge: String, pub full_name: String, pub team: i64, - pub method: String, + pub data: String, pub pass_hash: String, pub admin: String, pub team_admin: i64, @@ -124,7 +124,7 @@ fn get_user_id_entry(conn: Connection, id: String) -> Result Result Result, rusqlite::Erro pub async fn create_user(pool: &Pool, team: i64, full_name: String, username: String, password: String) -> Result { let pool = pool.clone(); - let conn = web::block(move || pool.get()) .await? .map_err(error::ErrorInternalServerError)?; - web::block(move || { let generated_salt = SaltString::generate(&mut OsRng); // argon2id v19 @@ -219,7 +217,7 @@ pub async fn create_user(pool: &Pool, team: i64, full_name: String, username: St current_challenge: "".to_string(), full_name, team, - method: "pw".to_string(), + data: "".to_string(), pass_hash: "".to_string(), admin: "false".to_string(), team_admin: 0, @@ -234,14 +232,14 @@ pub async fn create_user(pool: &Pool, team: i64, full_name: String, username: St } fn create_user_entry(conn: Connection, team: i64, full_name: String, username: String, password_hash: String) -> Result { - let mut stmt = conn.prepare("INSERT INTO users (username, current_challenge, full_name, team, method, pass_hash, admin, team_admin, access_ok, score) VALUES (?, '', ?, ?, 'pw', ?, 'false', 0, 'true', 0);")?; + let mut stmt = conn.prepare("INSERT INTO users (username, current_challenge, full_name, team, data, pass_hash, admin, team_admin, access_ok, score) VALUES (?, '', ?, ?, '', ?, 'false', 0, 'true', 0);")?; let mut new_user = User { id: 0, username, current_challenge: "".to_string(), full_name, team, - method: "pw".to_string(), + data: "".to_string(), pass_hash: password_hash, admin: "false".to_string(), team_admin: 0, @@ -264,6 +262,26 @@ pub fn update_points(conn: Connection, user_id: i64, inc: i64) -> Result Result { + let pool = pool.clone(); + + let conn = web::block(move || pool.get()) + .await? + .map_err(error::ErrorInternalServerError)?; + + web::block(move || { + update_user_data_transaction(conn, user_id, new_data) + }) + .await? + .map_err(error::ErrorInternalServerError) +} + +pub fn update_user_data_transaction(conn: Connection, user_id: i64, new_data: String) -> Result { + let mut stmt: Statement<'_> = conn.prepare("UPDATE users SET data = ?1 WHERE id = ?2;")?; + stmt.execute(params![new_data, user_id])?; + Ok(db_main::Id { id: conn.last_insert_rowid() }) +} + #[derive(Serialize, Deserialize, Clone)] pub struct UserPartial { pub id: i64, diff --git a/src/db_main.rs b/src/db_main.rs index 4a46bebc..b6622a34 100644 --- a/src/db_main.rs +++ b/src/db_main.rs @@ -243,6 +243,28 @@ fn get_id_rows(mut statement: Statement) -> QueryResult { .and_then(Iterator::collect) } +pub async fn get_team_numbers(pool: &Pool, season: String) -> Result, Error> { + // clone pool + let pool = pool.clone(); + + // get database connection + let conn = web::block(move || pool.get()) + .await? + .map_err(error::ErrorInternalServerError)?; + + // run query function based on provided enum + web::block(move || { + let mut stmt = conn.prepare("SELECT team FROM main WHERE season=?1 ORDER BY id DESC;")?; + stmt + .query_map([season], |row| { + Ok(row.get(0)?) + }) + .and_then(Iterator::collect) + }) + .await? + .map_err(error::ErrorInternalServerError) +} + // incoming data structure for a new main form submission #[derive(Deserialize)] pub struct MainInsert { diff --git a/src/forward.rs b/src/forward.rs index ab48a9af..fe376cfb 100644 --- a/src/forward.rs +++ b/src/forward.rs @@ -1,54 +1,28 @@ -use std::env; +use std::path::PathBuf; use actix_web::{web, HttpRequest, HttpResponse}; -use reqwest::Client; -// [deprecated] -pub async fn forward_frc_api_event_teams(req: HttpRequest, path: web::Path<(String, String)>) -> HttpResponse { +pub async fn forward_frc_api_event_teams(_req: HttpRequest, path: web::Path<(String, String)>) -> HttpResponse { let (season, event) = path.into_inner(); - let target_url = format!("https://frc-api.firstinspires.org/v3.0/{}/teams?eventCode={}", season, event); - let client = Client::new(); - let response = client - .request(req.method().clone(), target_url) - .header("Authorization", format!("Basic {}", env::var("FRC_API_KEY").unwrap_or_else(|_| "NONE".to_string()))) - .send() - .await; - - match response { - Ok(response) => { - HttpResponse::build(response.status()) - .insert_header(("Cache-Control", "public, max-age=46656000, immutable")) - .body(response.bytes().await.unwrap().to_vec()) - } - Err(_) => HttpResponse::InternalServerError().finish(), + let path: PathBuf = PathBuf::from(format!("cache/frc_api/{}/{}/teams.json", season, event)); + if let Ok(content) = std::fs::read_to_string(&path) { + HttpResponse::Ok() + .insert_header(("Cache-Control", "public, max-age=93312000, immutable")) // 30 days + .content_type("application/json") + .body(content) + } else { + HttpResponse::NotFound().finish() } } -pub async fn forward_frc_api_event_matches(req: HttpRequest, path: web::Path<(String, String, String, String)>) -> HttpResponse { - // generate request url - let (season, event, level, all) = path.into_inner(); - let mut url_param: String = "&start=&end=".to_string(); - if all != "all" { - if all != "false" { - url_param = format!("&teamNumber={}", all) - } else { - url_param = format!("&teamNumber={}", env::var("MY_TEAM").unwrap_or_else(|_| "766".to_string())) - } - } - let target_url: String = format!("https://frc-api.firstinspires.org/v3.0/{}/schedule/{}?tournamentLevel={}{}", season, event, level, url_param); - // create client and get response - let client: Client = Client::new(); - let response: Result = client - .request(req.method().clone(), target_url) - .header("Authorization", format!("Basic {}", env::var("FRC_API_KEY").unwrap_or_else(|_| "NONE".to_string()))) - .send() - .await; - // if ok, send. else, send a bad gateway error - match response { - Ok(response) => { - HttpResponse::build(response.status()) - .insert_header(("Cache-Control", "public, max-age=46656000, immutable")) - .body(response.bytes().await.unwrap().to_vec()) - } - Err(_) => HttpResponse::BadGateway().finish(), +pub async fn forward_frc_api_event_matches(_req: HttpRequest, path: web::Path<(String, String)>) -> HttpResponse { + let (season, event) = path.into_inner(); + let path: PathBuf = PathBuf::from(format!("cache/frc_api/{}/{}/matches.json", season, event)); + if let Ok(content) = std::fs::read_to_string(&path) { + HttpResponse::Ok() + .insert_header(("Cache-Control", "public, max-age=93312000, immutable")) // 30 days + .content_type("application/json") + .body(content) + } else { + HttpResponse::NotFound().finish() } -} \ No newline at end of file +} diff --git a/src/game_api.rs b/src/game_api.rs new file mode 100644 index 00000000..1ad9b82d --- /dev/null +++ b/src/game_api.rs @@ -0,0 +1,325 @@ +use actix_web::{error, web, Error}; +use rand::seq::SliceRandom; +use rusqlite::Statement; +use serde::{Serialize, Deserialize}; + +use crate::db_auth; +use crate::db_main; +use crate::stats; + +#[derive(Serialize)] +pub struct DataStats { + pub first: i64, + pub median: i64, + pub third: i64, + pub mean: i64, + pub decaying: i64 +} + +#[derive(Serialize, Deserialize)] +pub struct GameUserData { + cards: Vec, + hand: Vec, + wins: i64, + losses: i64, + ties: i64, + box_count: i64, +} + +#[derive(Serialize, Deserialize)] +pub struct ClientInfo { + id: i64, + username: String, + team: i64, + score: i64, + game_data: GameUserData +} + +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct FrcApiTeam { + pub team_number: i64, + pub name_full: String, + pub name_short: String, + pub city: String, + pub state_prov: String, + pub country: String, + pub rookie_year: i64, + pub robot_name: String, + pub district_code: Option, + pub school_name: String, + pub website: String, + pub home_c_m_p: String, +} + +#[derive(Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct FrcApiTeams { + pub team_count_total: i64, + pub team_count_page: i64, + pub page_current: i64, + pub page_total: i64, + pub teams: Vec, +} + +pub async fn get_owned_cards(pool: &db_auth::Pool, user: db_auth::User) -> Result { + let user_updated = db_auth::get_user_id(pool, user.id.to_string()).await?; + if user_updated.data == "" { + db_auth::update_user_data( + pool, + user.id, + serde_json::to_string(&GameUserData { + cards: vec![99999, 99998, 99997], + hand: vec![99999, 99998, 99997], + wins: 0, + losses: 0, + ties: 0, + box_count: 0 + }).unwrap_or("".to_string()) + ).await?; + Ok(ClientInfo { + id: -1, + username: "none".to_string(), + team: -1, + score: -1, + game_data: GameUserData { cards: vec![99999, 99998, 99997], hand: vec![99999, 99998, 99997], wins: 0, losses: 0, ties: 0, box_count: 0 } + }) + } else { + Ok( + ClientInfo { + id: user_updated.id, + username: user_updated.username, + team: user_updated.team, + score: user_updated.score, + game_data: serde_json::from_str::(&user_updated.data).unwrap_or(GameUserData { cards: vec![99999, 99998, 99997], hand: vec![99999, 99998, 99997], wins: 0, losses: 0, ties: 0, box_count: 0 }) + } + ) + } +} + +pub async fn open_loot_box(auth_pool: &db_auth::Pool, main_pool: &db_main::Pool, user_param: db_auth::User) -> Result { + let user_queried = db_auth::get_user_id(auth_pool, user_param.id.to_string()).await; + if !user_queried.is_ok() { + return Ok(-1) + } + let user = user_queried.unwrap(); + let teams = db_main::get_team_numbers(main_pool, "2024".to_string()).await; + if teams.is_ok() { + let team_list = teams.unwrap(); + if team_list.is_empty() { + Ok(-1) + } else { + let card = team_list.choose(&mut rand::thread_rng()).unwrap().clone(); + if user.score >= 100 { + if user.data == "" { + db_auth::update_user_data(auth_pool, user.id, serde_json::to_string(&GameUserData { cards: vec![99999, 99998, 99997], hand: vec![99999, 99998, 99997], wins: 0, losses: 0, ties: 0, box_count: 0 }).unwrap_or("".to_string())).await?; + } + + let mut current_user_data = serde_json::from_str::(&user.data).unwrap(); + current_user_data.box_count += 1; + current_user_data.cards.push(card); + db_auth::update_user_data(auth_pool, user.id, serde_json::to_string(¤t_user_data).unwrap_or("".to_string())).await?; + + let auth_pool = auth_pool.clone(); + let auth_conn = web::block(move || auth_pool.get()) + .await? + .map_err(error::ErrorInternalServerError)?; + + db_auth::update_points(auth_conn, user.id, -100) + .map_err(error::ErrorInternalServerError)?; + + Ok(card) + } else { + Ok(-1) + } + } + } else { + Ok(-1) + } +} + +#[derive(Serialize, Deserialize)] +pub struct CardsPostData { + cards: Vec +} + +pub async fn set_held_cards(auth_pool: &db_auth::Pool, user_param: db_auth::User, data: &web::Json) -> Result { + let user_queried = db_auth::get_user_id(auth_pool, user_param.id.to_string()).await; + if !user_queried.is_ok() { + return Ok(CardsPostData { cards: vec![-1, 3] }) + } + let user = user_queried.unwrap(); + if user.data == "" { + Ok(CardsPostData { cards: vec![-1, 3] }) + } else { + let mut current_user_data = serde_json::from_str::(&user.data).unwrap(); + let mut cards_not_ok = false; + if data.cards.len() == 3 { + data.cards.iter().for_each(|card| { + if !current_user_data.cards.contains(card) { + cards_not_ok = true; + } + }); + } else { + cards_not_ok = true; + } + if !cards_not_ok { + current_user_data.hand = data.cards.clone(); + db_auth::update_user_data(auth_pool, user.id, serde_json::to_string(¤t_user_data).unwrap_or("".to_string())).await?; + return Ok(CardsPostData { cards: current_user_data.hand }) + } else { + return Ok(CardsPostData { cards: vec![-1, 3] }) + } + } +} + +// 2024 only + +#[derive(Serialize)] +pub struct Team { + pub team: i64, + pub trap_note: f64, + pub climb: f64, + pub buddy_climb: f64, + pub intake: DataStats, + pub travel: DataStats, + pub outtake: DataStats, + pub speaker: DataStats, + pub amplifier: DataStats, + pub total: DataStats, + pub points: DataStats +} + +struct TeamDataset { + trap_note: Vec, + climb: Vec, + buddy_climb: Vec, + intake: Vec, + travel: Vec, + outtake: Vec, + speaker: Vec, + amplifier: Vec, + shots: Vec, + points: Vec +} + +struct MainAnalysis { + analysis: String, +} + +pub async fn execute(pool: &db_main::Pool, season: String, event: String, team: String) -> Result { + let pool = pool.clone(); + + let conn = web::block(move || pool.get()) + .await? + .map_err(error::ErrorInternalServerError)?; + + web::block(move || { + get_team(conn, season, event, team) + }) + .await? + .map_err(error::ErrorInternalServerError) +} + +fn get_team(conn: db_main::Connection, season: String, event: String, team: String) -> Result { + let stmt = conn.prepare("SELECT analysis FROM main WHERE season=:season AND event=:event AND team=:team;")?; + get_rows(stmt, [season, event, team]) +} + +fn get_rows(mut statement: Statement, params: [String; 3]) -> Result { + let data: Vec = statement + .query_map(params.clone(), |row| { + Ok(MainAnalysis { + analysis: row.get(0)? + }) + }) + .and_then(Iterator::collect) + .unwrap(); + + let mut data_arr: TeamDataset = TeamDataset { trap_note: Vec::new(), climb: Vec::new(), buddy_climb: Vec::new(), intake: Vec::new(), travel: Vec::new(), outtake: Vec::new(), speaker: Vec::new(), amplifier: Vec::new(), points: Vec::new(), shots: Vec::new() }; + data.iter().for_each(|entry| { + let game_data: Vec = entry.analysis.split(",").map(|v| v.parse::().unwrap_or(0)).collect(); + data_arr.trap_note.push(game_data[0]); + data_arr.climb.push(game_data[1]); + data_arr.buddy_climb.push(game_data[2]); + data_arr.intake.push(game_data[3]); + data_arr.travel.push(game_data[4]); + data_arr.outtake.push(game_data[5]); + data_arr.speaker.push(game_data[6]); + data_arr.amplifier.push(game_data[7]); + data_arr.shots.push(game_data[6] + game_data[7]); + data_arr.points.push(game_data[8]); + }); + + let intake_qrt = stats::quartiles_i64(&data_arr.intake); + let travel_qrt = stats::quartiles_i64(&data_arr.travel); + let outtake_qrt = stats::quartiles_i64(&data_arr.outtake); + let speaker_qrt = stats::quartiles_i64(&data_arr.speaker); + let amplifier_qrt = stats::quartiles_i64(&data_arr.amplifier); + let total_qrt = stats::quartiles_i64(&data_arr.shots); + let points_qrt = stats::quartiles_i64(&data_arr.points); + + let intake_means = stats::means_i64(&data_arr.intake, 0.5); + let travel_means = stats::means_i64(&data_arr.travel, 0.5); + let outtake_means = stats::means_i64(&data_arr.outtake, 0.5); + let speaker_means = stats::means_i64(&data_arr.speaker, 0.5); + let amplifier_means = stats::means_i64(&data_arr.amplifier, 0.5); + let total_means = stats::means_i64(&data_arr.shots, 0.5); + let points_means = stats::means_i64(&data_arr.points, 0.5); + + Ok(Team { + team: params[2].parse::().unwrap_or(0), + trap_note: data_arr.trap_note.iter().sum::() as f64 / data_arr.trap_note.len() as f64, + climb: data_arr.climb.iter().sum::() as f64 / data_arr.climb.len() as f64, + buddy_climb: data_arr.buddy_climb.iter().sum::() as f64 / data_arr.buddy_climb.len() as f64, + intake: DataStats { + first: intake_qrt[0], + median: intake_qrt[1], + third: intake_qrt[2], + mean: intake_means[0], + decaying: intake_means[1] + }, + travel: DataStats { + first: travel_qrt[0], + median: travel_qrt[1], + third: travel_qrt[2], + mean: travel_means[0], + decaying: travel_means[1] + }, + outtake: DataStats { + first: outtake_qrt[0], + median: outtake_qrt[1], + third: outtake_qrt[2], + mean: outtake_means[0], + decaying: outtake_means[1] + }, + speaker: DataStats { + first: speaker_qrt[0], + median: speaker_qrt[1], + third: speaker_qrt[2], + mean: speaker_means[0], + decaying: speaker_means[1] + }, + amplifier: DataStats { + first: amplifier_qrt[0], + median: amplifier_qrt[1], + third: amplifier_qrt[2], + mean: amplifier_means[0], + decaying: amplifier_means[1] + }, + total: DataStats { + first: total_qrt[0], + median: total_qrt[1], + third: total_qrt[2], + mean: total_means[0], + decaying: total_means[1] + }, + points: DataStats { + first: points_qrt[0], + median: points_qrt[1], + third: points_qrt[2], + mean: points_means[0], + decaying: points_means[1] + }, + }) +} diff --git a/src/main.rs b/src/main.rs index 8fe0b72b..494e98cf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,14 @@ -use std::{env, io, collections::HashMap, pin::Pin, sync::RwLock}; +use std::{env, io, collections::HashMap, fs, pin::Pin, sync::RwLock}; use actix_governor::{Governor, GovernorConfigBuilder}; use actix_http::StatusCode; use actix_identity::{CookieIdentityPolicy, Identity, IdentityService}; use actix_session::{SessionMiddleware, Session, config::PersistentSession}; -use actix_web::{error, middleware::{self, DefaultHeaders}, web, App, Error as AWError, HttpRequest, HttpResponse, HttpServer, cookie::Key, Responder, FromRequest, dev::Payload}; +use actix_web::{error, middleware::{self, DefaultHeaders}, web, App, Error as AWError, HttpRequest, HttpResponse, HttpServer, cookie::Key, Responder, FromRequest, dev::Payload, http::header::ContentType}; use actix_web_static_files::ResourceFiles; use dotenv::dotenv; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use r2d2_sqlite::{self, SqliteConnectionManager}; +use reqwest::Client; use serde::{Serialize, Deserialize}; use webauthn_rs::prelude::*; @@ -18,9 +19,11 @@ mod db_auth; mod db_main; mod db_transact; mod forward; +mod game_api; mod passkey; mod session; mod static_files; +mod stats; // hashmap containing user session IDs #[derive(Serialize, Deserialize, Default, Clone)] @@ -141,66 +144,99 @@ async fn data_get_meta() -> Result { ) } +fn access_denied_team() -> HttpResponse { + HttpResponse::Unauthorized() + .body("you must be affiliated with a valid team to access data") +} + // get detailed data by submission id. used in /detail -async fn data_get_detailed(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::GetDataDetailed, path).await?) - ) +async fn data_get_detailed(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::GetDataDetailed, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // check if a submission exists, by id. used in submit script to verify submission (verification is mostly a gimmick but whatever) -async fn data_get_exists(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::DataExists, path).await?) - ) +async fn data_get_exists(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::DataExists, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // get summary of all data for a given team at an event in a season. used on /browse -async fn data_get_main_brief_team(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::BriefTeam, path).await?) - ) +async fn data_get_main_brief_team(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::BriefTeam, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // get summary of all data for a given match at an event, in a specified season. used on /browsw -async fn data_get_main_brief_match(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::BriefMatch, path).await?) - ) +async fn data_get_main_brief_match(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::BriefMatch, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // get summary of all data from an event, given a season. used for /browse -async fn data_get_main_brief_event(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::BriefEvent, path).await?) - ) +async fn data_get_main_brief_event(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::BriefEvent, path).await?) + ) + } else { + Ok(access_denied_team()) + } } -async fn data_get_main_brief_season(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::BriefSeason, path).await?) - ) +async fn data_get_main_brief_season(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::BriefSeason, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // get summary of all submissions created by a certain user id. used for /browse -async fn data_get_main_brief_user(path: web::Path, db: web::Data, _user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute(&db.main, db_main::MainData::BriefUser, path).await?) - ) +async fn data_get_main_brief_user(path: web::Path, db: web::Data, user: db_auth::User) -> Result { + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute(&db.main, db_main::MainData::BriefUser, path).await?) + ) + } else { + Ok(access_denied_team()) + } } // get basic data about all teams at an event, in a season. used for event rankings. ** NO AUTH ** @@ -214,21 +250,29 @@ async fn data_get_main_teams(path: web::Path, db: web::Data) // get POSTed data from form async fn data_post_submit(data: web::Json, db: web::Data, user: db_auth::User) -> Result { - Ok( - HttpResponse::Ok() - .insert_header(("Cache-Control", "no-cache")) - .json(db_main::execute_insert(&db.main, &db.transact, &db.auth, data, user).await?) - ) + if user.team != 0 { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json(db_main::execute_insert(&db.main, &db.transact, &db.auth, data, user).await?) + ) + } else { + Ok(access_denied_team()) + } } // forward frc api data for teams [deprecated] -async fn event_get_frc_api(req: HttpRequest, path: web::Path<(String, String)>, _user: db_auth::User) -> HttpResponse { +async fn event_get_frc_api(req: HttpRequest, path: web::Path<(String, String)>) -> HttpResponse { forward::forward_frc_api_event_teams(req, path).await } // forward frc api data for events. used on main form to ensure entered matches and teams are valid -async fn event_get_frc_api_matches(req: HttpRequest, path: web::Path<(String, String, String, String)>, _user: db_auth::User) -> HttpResponse { - forward::forward_frc_api_event_matches(req, path).await +async fn event_get_frc_api_matches(req: HttpRequest, path: web::Path<(String, String)>/*, user: db_auth::User*/) -> HttpResponse { + // if user.team != 0 { + forward::forward_frc_api_event_matches(req, path).await + // } else { + // access_denied_team() + // } } // get all valid submission IDs. used on /manage to create list of IDs that can be acted on @@ -422,6 +466,16 @@ async fn misc_get_whoami(user: db_auth::User) -> Result { ) } +// if you aren't D6MFYYVHA8 you may want to change this +const APPLE_APP_SITE_ASSOC: &str = "{\"webcredentials\":{\"apps\":[\"D6MFYYVHA8.com.jayagra.beartracks\",\"D6MFYYVHA8.com.jayagra.beartracks-scout\",\"D6MFYYVHA8.com.jayagra.beartracks-manage\"]}}"; +async fn misc_apple_app_site_association() -> Result { + Ok( + HttpResponse::Ok() + .content_type(ContentType::json()) + .body(APPLE_APP_SITE_ASSOC) + ) +} + // get all points. used to construct the leaderboard async fn points_get_all(db: web::Data, _user: db_auth::User) -> Result { Ok( @@ -449,6 +503,51 @@ async fn debug_get_user(user: db_auth::User) -> Result { ) } +async fn game_get_cards(db: web::Data, user: db_auth::User) -> Result { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json( + game_api::get_owned_cards(&db.auth, user).await? + ) + ) +} + +async fn game_open_lootbox(db: web::Data, user: db_auth::User) -> Result { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json( + game_api::open_loot_box(&db.auth, &db.main, user).await? + ) + ) +} + +async fn game_set_hand(db: web::Data, data: web::Json, user: db_auth::User) -> Result { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json( + game_api::set_held_cards(&db.auth, user, &data).await? + ) + ) +} + +async fn game_get_team(req: HttpRequest, db: web::Data, _user: db_auth::User) -> Result { + Ok( + HttpResponse::Ok() + .insert_header(("Cache-Control", "no-cache")) + .json( + game_api::execute( + &db.main, + req.match_info().get("season").unwrap().parse().unwrap(), + req.match_info().get("event").unwrap().parse().unwrap(), + req.match_info().get("team").unwrap().parse().unwrap(), + ).await? + ) + ) +} + include!(concat!(env!("OUT_DIR"), "/generated.rs")); #[actix_web::main] @@ -464,6 +563,59 @@ async fn main() -> io::Result<()> { println!("[OK] starting in release mode"); } + // cache all possible files + let seasons = env::var("SEASONS").unwrap_or_else(|_| "0".to_string()).split(",").map(|s| s.to_string()).collect::>(); + let events = env::var("EVENTS").unwrap_or_else(|_| "0".to_string()).split(",").map(|s| s.to_string()).collect::>(); + + for i in 0..seasons.len() { + for j in 0..events.len() { + // cache team list + let team_target_url = format!("https://frc-api.firstinspires.org/v3.0/{}/teams?eventCode={}", seasons[i], events[j]); + let team_client = Client::new(); + let team_response = team_client + .request(actix_http::Method::GET, team_target_url) + .header("Authorization", format!("Basic {}", env::var("FRC_API_KEY").unwrap_or_else(|_| "NONE".to_string()))) + .send() + .await; + + match team_response { + Ok(response) => { + if response.status() == 200 { + fs::create_dir_all(format!("cache/frc_api/{}/{}", seasons[i], events[j]))?; + fs::write(format!("cache/frc_api/{}/{}/teams.json", seasons[i], events[j]), response.text().await.unwrap()).expect(format!("Failed to cache {}/{} team JSON. Could not write file.", seasons[i], events[j]).as_str()); + } else { + log::error!("Failed to cache {}/{} team JSON. Response status {}.", seasons[i], events[j], response.status()); + } + } + Err(_) => { + log::error!("Failed to cache {}/{} team JSON. Response was not OK.", seasons[i], events[j]); + }, + } + + let match_target_url = format!("https://frc-api.firstinspires.org/v3.0/{}/schedule/{}?tournamentLevel=qualification", seasons[i], events[j]); + let match_client = Client::new(); + let match_response = match_client + .request(actix_http::Method::GET, match_target_url) + .header("Authorization", format!("Basic {}", env::var("FRC_API_KEY").unwrap_or_else(|_| "NONE".to_string()))) + .send() + .await; + + match match_response { + Ok(response) => { + if response.status() == 200 { + fs::create_dir_all(format!("cache/frc_api/{}/{}", seasons[i], events[j]))?; + fs::write(format!("cache/frc_api/{}/{}/matches.json", seasons[i], events[j]), response.text().await.unwrap()).expect(format!("Failed to cache {}/{} match JSON. Could not write file.", seasons[i], events[j]).as_str()); + } else { + log::error!("Failed to cache {}/{} match JSON. Response status {}.", seasons[i], events[j], response.status()); + } + } + Err(_) => { + log::error!("Failed to cache {}/{} match JSON. Response was not OK.", seasons[i], events[j]); + }, + } + } + } + // hashmap w: web::Data>ith user sessions in it let sessions: web::Data> = web::Data::new(RwLock::new(Sessions { user_map: HashMap::new(), @@ -547,13 +699,15 @@ async fn main() -> io::Result<()> { .build() ) // default headers for caching. overridden on most all api endpoints - .wrap(DefaultHeaders::new().add(("Cache-Control", "public, max-age=23328000")).add(("X-bearTracks", "4.0.0"))) + .wrap(DefaultHeaders::new().add(("Cache-Control", "public, max-age=23328000")).add(("X-bearTracks", "5.0.2"))) /* src endpoints */ // GET individual files .route("/", web::get().to(static_files::static_index)) .route("/blackjack", web::get().to(static_files::static_blackjack)) .route("/create", web::get().to(static_files::static_create)) + .route("/main", web::get().to(static_files::static_main)) .route("/login", web::get().to(static_files::static_login)) + .route("/passkey", web::get().to(static_files::static_passkey)) .route("/pointRecords", web::get().to(static_files::static_point_records)) .route("/points", web::get().to(static_files::static_points)) .route("/scouts", web::get().to(static_files::static_scouts)) @@ -617,13 +771,21 @@ async fn main() -> io::Result<()> { // GET .service(web::resource("/api/v1/transact/me").route(web::get().to(misc_get_transact_me))) .service(web::resource("/api/v1/whoami").route(web::get().to(misc_get_whoami))) + .service(web::resource("/apple-app-site-association").route(web::get().to(misc_apple_app_site_association))) /* debug endpoints */ // GET .service(web::resource("/api/v1/debug/user").route(web::get().to(debug_get_user))) + /* robot game endpoints */ + // GET + .service(web::resource("/api/v1/game/all_owned_cards").route(web::get().to(game_get_cards))) + .service(web::resource("/api/v1/game/team_data/{season}/{event}/{team}").route(web::get().to(game_get_team))) + .service(web::resource("/api/v1/game/open_lootbox").route(web::get().to(game_open_lootbox))) + // POST + .service(web::resource("/api/v1/game/set_hand").route(web::post().to(game_set_hand))) }) .bind_openssl(format!("{}:443", env::var("HOSTNAME").unwrap_or_else(|_| "localhost".to_string())), builder)? .bind((env::var("HOSTNAME").unwrap_or_else(|_| "localhost".to_string()), 80))? - .workers(2) + .workers(4) .run() .await } \ No newline at end of file diff --git a/src/static_files.rs b/src/static_files.rs index 4f06c9ca..6399be9d 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -5,8 +5,10 @@ use actix_web::{HttpRequest, HttpResponse, http::header::{ContentType, CacheCont const INDEX_HTML: &str = include_str!("../static/index.html"); const BLACKJACK_HTML: &str = include_str!("../static/blackjack.html"); const CREATE_HTML: &str = include_str!("../static/create.html"); +const MAIN_HTML: &str = include_str!("../static/main.html"); const LOGIN_HTML: &str = include_str!("../static/login.html"); const POINT_RECORDS_HTML: &str = include_str!("../static/pointRecords.html"); +const PASSKEY_HTML: &str = include_str!("../static/passkey.html"); const POINTS_HTML: &str = include_str!("../static/points.html"); const SCOUTS_HTML: &str = include_str!("../static/scouts.html"); const SETTINGS_HTML: &str = include_str!("../static/settings.html"); @@ -46,12 +48,24 @@ pub async fn static_create() -> HttpResponse { .body(CREATE_HTML) } +pub async fn static_main() -> HttpResponse { + HttpResponse::Ok() + .content_type(ContentType::html()) + .body(MAIN_HTML) +} + pub async fn static_login() -> HttpResponse { HttpResponse::Ok() .content_type(ContentType::html()) .body(LOGIN_HTML) } +pub async fn static_passkey() -> HttpResponse { + HttpResponse::Ok() + .content_type(ContentType::html()) + .body(PASSKEY_HTML) +} + pub async fn static_point_records() -> HttpResponse { HttpResponse::Ok() .content_type(ContentType::html()) diff --git a/src/stats.rs b/src/stats.rs new file mode 100644 index 00000000..6f07b69c --- /dev/null +++ b/src/stats.rs @@ -0,0 +1,38 @@ +pub fn quartiles_i64(data: &Vec) -> Vec { + if data.len() > 0 { + let mut sorted_data = data.clone(); + sorted_data.sort(); + let data_length: f64 = sorted_data.len() as f64; + let mut quartiles: Vec = Vec::new(); + // first quartile + if (data_length * 0.25) % 1.0 == 0.0 { + quartiles.push((sorted_data[((data_length * 0.25) - 1.0) as usize] + sorted_data[(data_length * 0.25) as usize]) / 2 as i64); + } else { + quartiles.push(sorted_data[(data_length * 0.25).floor() as usize]); + } + // second quartile (median) + if (data_length * 0.5) % 1.0 == 0.0 { + quartiles.push((sorted_data[((data_length * 0.5) - 1.0) as usize] + sorted_data[(data_length * 0.5) as usize]) / 2 as i64); + } else { + quartiles.push(sorted_data[(data_length * 0.5).floor() as usize]); + } + // third quartile + if (data_length * 0.75) % 1.0 == 0.0 { + quartiles.push((sorted_data[((data_length * 0.75) - 1.0) as usize] + sorted_data[(data_length * 0.75) as usize]) / 2 as i64); + } else { + quartiles.push(sorted_data[(data_length * 0.75).floor() as usize]); + } + return quartiles + } + return vec!(0, 0, 0) +} + +pub fn means_i64(data: &Vec, first_wt: f64) -> Vec { + if data.len() > 0 { + let mut means: Vec = Vec::new(); + means.push(data.iter().sum::() / data.len() as i64); + means.push(((data[0] as f64 * first_wt) + (data.iter().sum::() as f64 * (1.0 - first_wt))) as i64); + return means + } + return vec!(0, 0); +} \ No newline at end of file diff --git a/static/blackjack.html b/static/blackjack.html index 23fec1f2..6b11d208 100644 --- a/static/blackjack.html +++ b/static/blackjack.html @@ -5,12 +5,12 @@ Blackjack - bearTracks - + - +
diff --git a/static/create.html b/static/create.html index 5b770cd5..72e58f57 100644 --- a/static/create.html +++ b/static/create.html @@ -5,7 +5,7 @@ Create Account - bearTracks - + @@ -17,9 +17,9 @@

bearTracks
CRESCENDO

Create Account

-


+
00000 for no team





-


+






diff --git a/static/favicon.ico b/static/favicon.ico index 86c47f3cfde73ee36cc5a0f89f37f16549f11d13..bd41d270b897bcdf19987a91c112779243a23d3e 100644 GIT binary patch literal 5343 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 E2b?y56aWAK literal 14653 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 O0vRa<$r5oxzyAYicPIe> diff --git a/static/index.html b/static/index.html index 41196968..1cde7545 100644 --- a/static/index.html +++ b/static/index.html @@ -2,30 +2,31 @@ - CRESCENDO Scouting - bearTracks + bearTracks - + + - +
- \ No newline at end of file diff --git a/static/login.html b/static/login.html index 86c12d0e..ee3ccaf4 100644 --- a/static/login.html +++ b/static/login.html @@ -1 +1 @@ -

loading web assembly...

\ No newline at end of file +Log In - bearTracks

loading web assembly...

\ No newline at end of file diff --git a/static/main.html b/static/main.html new file mode 100644 index 00000000..ef084c6c --- /dev/null +++ b/static/main.html @@ -0,0 +1,105 @@ + + + + + Scout - bearTracks + + + + + + + + + + +
+
+

bearTracks
CRESCENDO

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

+ +
+ + + +
+ + + + \ No newline at end of file diff --git a/static/passkey.html b/static/passkey.html new file mode 100644 index 00000000..5903c312 --- /dev/null +++ b/static/passkey.html @@ -0,0 +1 @@ +Register Passkey - bearTracks

loading web assembly...

\ No newline at end of file diff --git a/static/pointRecords.html b/static/pointRecords.html index 3b5d7ff1..864fb9c6 100644 --- a/static/pointRecords.html +++ b/static/pointRecords.html @@ -5,7 +5,7 @@ Point Records - bearTracks - + diff --git a/static/points.html b/static/points.html index 8664955d..e9c8fcd5 100644 --- a/static/points.html +++ b/static/points.html @@ -5,7 +5,7 @@ Points - bearTracks - + diff --git a/static/public/css/float.css b/static/public/css/float.css index 993eefbb..1d57ac9a 100644 --- a/static/public/css/float.css +++ b/static/public/css/float.css @@ -1,14 +1,14 @@ body { --fieldsetColor: rgba(0,0,0,0); - --bodyColor: #121212; - --textColor: #fff; - --transparency: rgba(0,0,0,0); --defaultInputColor: #fff; - --inputColorSelected: #ffb600; - --gameFlairColor: #68c3e2; - --cancelColor: #e90202; - --returnColor: #ffb600; - --checkAccent: #68c3e2; + --bodyColor: #282828; + --textColor: #ebdbb2; + --defaultInputColor: #504945; + --inputColorSelected: #b8bb26; + --gameFlairColor: #83a598; + --cancelColor: #cc241d; + --returnColor: #d3869b; + --checkAccent: #fe8019; display: flex; justify-content: center; align-items: center; @@ -87,46 +87,22 @@ h1 { max-width: 100%; } select { - background-color: var(--transparency); + background-color: transparent; border: none; color: var(--textColor); border-bottom: 2px solid var(--defaultInputColor); font-size: 16px; margin-top: 2vh; } -input[type='text'], input[type='email'], input[type='password'] { +input[type='text'], input[type='email'], input[type='password'], input[type='number'], input[type='tel'] { border: none; - background-color: var(--transparency); + background-color: transparent; color: var(--textColor); border-bottom: 1px solid var(--defaultInputColor); width: 80%; } -input[type='number'] { - border: none; - background-color: var(--transparency); - color: var(--textColor); - border-bottom: 1px solid var(--defaultInputColor); - width: 80%; -} -input[type='tel'] { - border: none; - background-color: var(--transparency); - color: var(--textColor); - border-bottom: 1px solid var(--defaultInputColor); - width: 80%; -} -input[type='number']:focus { - background-color: var(--transparency); - outline: none; - border-bottom: 2px solid var(--inputColorSelected); -} -input[type='tel']:focus { - background-color: var(--transparency); - outline: none; - border-bottom: 2px solid var(--inputColorSelected); -} -input[type='text']:focus, input[type='email']:focus, input[type='password']:focus { - background-color: var(--transparency); +input[type='text']:focus, input[type='email']:focus, input[type='password']:focus, input[type='tel']:focus, input[type='number']:focus { + background-color: transparent; outline: none; border-bottom: 2px solid var(--inputColorSelected); } @@ -169,16 +145,17 @@ textarea { font-size: 16px; } textarea { - border: none; - border-bottom: 1px solid var(--defaultInputColor); - background-color: var(--transparency); + border: 2px solid var(--defaultInputColor); + border-radius: 11px; + background-color: transparent; color: var(--textColor); + padding: 0.5rem; resize: none; width: 80%; } textarea:focus { outline: none; - border-bottom: 1px solid var(--inputColorSelected); + border-color: var(--inputColorSelected); } code { font-family:'SF Mono', SFMono-Regular, ui-monospace, Menlo, courier new, monospace; diff --git a/static/public/css/float.min.css b/static/public/css/float.min.css index fc5696ae..9a302040 100644 --- a/static/public/css/float.min.css +++ b/static/public/css/float.min.css @@ -1 +1 @@ -body{--fieldsetColor:rgba(0, 0, 0, 0);--bodyColor:#121212;--textColor:#fff;--transparency:rgba(0, 0, 0, 0);--defaultInputColor:#fff;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--cancelColor:#e90202;--returnColor:#ffb600;--checkAccent:#68c3e2;display:flex;justify-content:center;align-items:center;}@media(prefers-color-scheme: light){body{--bodyColor:#fff;--textColor:#000;--defaultInputColor:#000;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2;}}body.dark-mode{--bodyColor:#121212;--textColor:#fff;--defaultInputColor:#fff;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2;}body.light-mode{--bodyColor:#fff;--textColor:#000;--defaultInputColor:#000;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2;}body.gruvbox{--bodyColor:#282828;--textColor:#ebdbb2;--defaultInputColor:#504945;--inputColorSelected:#b8bb26;--gameFlairColor:#83a598;--cancelColor:#cc241d;--returnColor:#d3869b;--checkAccent:#fe8019;}@font-face{font-family:'raleway-300';src:url('fonts/Raleway-300.ttf') format('truetype');font-display:swap;}@font-face{font-family:'raleway-500';src:url('fonts/Raleway-500.ttf') format('truetype');font-display:swap;}body,html{font-family:'raleway-300',-apple-system,BlinkMacSystemFont,sans-serif;}body{background-color:var(--bodyColor);color:var(--textColor);width:100vw;margin:0;}fieldset{border:0.15rem solid var(--fieldsetColor);border-radius:0.5rem;margin-top:0.25rem;margin-bottom:0.25rem;background-color:var(--fieldsetColor);}h1{text-align:center;font-family:'raleway-500',-apple-system,BlinkMacSystemFont,sans-serif;}.container{justify-content:center;display:flex;width:100vw;max-width:100%;}select{background-color:var(--transparency);border:none;color:var(--textColor);border-bottom:2px solid var(--defaultInputColor);font-size:16px;margin-top:2vh;}input[type='text'],input[type='email'],input[type='password']{border:none;background-color:var(--transparency);color:var(--textColor);border-bottom:1px solid var(--defaultInputColor);width:80%;}input[type='number']{border:none;background-color:var(--transparency);color:var(--textColor);border-bottom:1px solid var(--defaultInputColor);width:80%;}input[type='tel']{border:none;background-color:var(--transparency);color:var(--textColor);border-bottom:1px solid var(--defaultInputColor);width:80%;}input[type='number']:focus{background-color:var(--transparency);outline:none;border-bottom:2px solid var(--inputColorSelected);}input[type='tel']:focus{background-color:var(--transparency);outline:none;border-bottom:2px solid var(--inputColorSelected);}input[type='text']:focus,input[type='email']:focus,input[type='password']:focus{background-color:var(--transparency);outline:none;border-bottom:2px solid var(--inputColorSelected);}select:focus{outline:none;border-bottom:2px solid var(--inputColorSelected);}span{color:var(--textColor);}label{color:var(--textColor);}.gametitle{color:var(--inputColorSelected);font-family:'raleway-500',-apple-system,BlinkMacSystemFont,sans-serif;}.gameflair1{color:var(--gameFlairColor);}.checkbig{-webkit-transform:scale(2);-moz-transform:scale(2);-ms-transform:scale(2);transform:scale(2);accent-color:var(---checkAccent) !important;}.smallerInput{width:40% !important;}.lowerSelect{position:relative;top:5px;}input,select,textarea{-webkit-border-radius:0;border-radius:0;font-size:16px;}textarea{border:none;border-bottom:1px solid var(--defaultInputColor);background-color:var(--transparency);color:var(--textColor);resize:none;width:80%;}textarea:focus{outline:none;border-bottom:1px solid var(--inputColorSelected);}code{font-family:'SF Mono',SFMono-Regular,ui-monospace,Menlo,courier new,monospace;}label{font-weight:700;}.uiButton{border-radius:0.5rem;border-style:solid;border-width:0.875rem;margin-top:1rem;}.cancelButton{color:#fff;background-color:var(--cancelColor);border-color:var(--cancelColor);}.returnButton{color:#000;background-color:var(--returnColor);border-color:var(--returnColor);}.actionButton{color:#000;background-color:var(--gameFlairColor);border-color:var(--gameFlairColor);}.actionButton:disabled{background-color:color-mix(in srgb, var(--gameFlairColor) 15%, var(--bodyColor));border-color:color-mix(in srgb, var(--gameFlairColor) 15%, var(--bodyColor));}form{width:95%;}.dummy{display:flex;flex-direction:column;align-items:center;}.w3{font-weight:300;}.bigLink{margin-bottom:5%;}.actLink{all:unset;color:var(--gameFlairColor);}.credInput{min-width:16rem;}.centerText{text-align:center;}.vaMiddle{vertical-align:middle;} \ No newline at end of file +body{--fieldsetColor:rgba(0,0,0,0);--defaultInputColor:#fff;--bodyColor:#282828;--textColor:#ebdbb2;--defaultInputColor:#504945;--inputColorSelected:#b8bb26;--gameFlairColor:#83a598;--cancelColor:#cc241d;--returnColor:#d3869b;--checkAccent:#fe8019;display:flex;justify-content:center;align-items:center}@media (prefers-color-scheme: light){body{--bodyColor:#fff;--textColor:#000;--defaultInputColor:#000;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2}}body.dark-mode{--bodyColor:#121212;--textColor:#fff;--defaultInputColor:#fff;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2}body.light-mode{--bodyColor:#fff;--textColor:#000;--defaultInputColor:#000;--inputColorSelected:#ffb600;--gameFlairColor:#68c3e2;--checkAccent:#68c3e2}body.gruvbox{--bodyColor:#282828;--textColor:#ebdbb2;--defaultInputColor:#504945;--inputColorSelected:#b8bb26;--gameFlairColor:#83a598;--cancelColor:#cc241d;--returnColor:#d3869b;--checkAccent:#fe8019}@font-face{font-family:'raleway-300';src:url('fonts/Raleway-300.ttf') format('truetype');font-display:swap}@font-face{font-family:'raleway-500';src:url('fonts/Raleway-500.ttf') format('truetype');font-display:swap}body,html{font-family:'raleway-300', -apple-system, BlinkMacSystemFont, sans-serif}body{background-color:var(--bodyColor);color:var(--textColor);width:100vw;margin:0}fieldset{border:0.15rem solid var(--fieldsetColor);border-radius:0.5rem;margin-top:0.25rem;margin-bottom:0.25rem;background-color:var(--fieldsetColor)}h1{text-align:center;font-family:'raleway-500', -apple-system, BlinkMacSystemFont, sans-serif}.container{justify-content:center;display:flex;width:100vw;max-width:100%}select{background-color:transparent;border:none;color:var(--textColor);border-bottom:2px solid var(--defaultInputColor);font-size:16px;margin-top:2vh}input[type='text'],input[type='email'],input[type='password'],input[type='number'],input[type='tel']{border:none;background-color:transparent;color:var(--textColor);border-bottom:1px solid var(--defaultInputColor);width:80%}input[type='text']:focus,input[type='email']:focus,input[type='password']:focus,input[type='tel']:focus,input[type='number']:focus{background-color:transparent;outline:none;border-bottom:2px solid var(--inputColorSelected)}select:focus{outline:none;border-bottom:2px solid var(--inputColorSelected)}span{color:var(--textColor)}label{color:var(--textColor)}.gametitle{color:var(--inputColorSelected);font-family:'raleway-500', -apple-system, BlinkMacSystemFont, sans-serif}.gameflair1{color:var(--gameFlairColor)}.checkbig{-webkit-transform:scale(2);-moz-transform:scale(2);-ms-transform:scale(2);transform:scale(2);accent-color:var(---checkAccent) !important}.smallerInput{width:40% !important}.lowerSelect{position:relative;top:5px}input,select,textarea{-webkit-border-radius:0;border-radius:0;font-size:16px}textarea{border:2px solid var(--defaultInputColor);border-radius:11px;background-color:transparent;color:var(--textColor);padding:0.5rem;resize:none;width:80%}textarea:focus{outline:none;border-color:var(--inputColorSelected)}code{font-family:'SF Mono', SFMono-Regular, ui-monospace, Menlo, courier new, monospace}label{font-weight:700}.uiButton{border-radius:0.5rem;border-style:solid;border-width:0.875rem;margin-top:1rem}.cancelButton{color:#fff;background-color:var(--cancelColor);border-color:var(--cancelColor)}.returnButton{color:#000;background-color:var(--returnColor);border-color:var(--returnColor)}.actionButton{color:#000;background-color:var(--gameFlairColor);border-color:var(--gameFlairColor)}.actionButton:disabled{background-color:color-mix(in srgb, var(--gameFlairColor) 15%, var(--bodyColor));border-color:color-mix(in srgb, var(--gameFlairColor) 15%, var(--bodyColor))}form{width:95%}.dummy{display:flex;flex-direction:column;align-items:center}.w3{font-weight:300}.bigLink{margin-bottom:5%}.actLink{all:unset;color:var(--gameFlairColor)}.credInput{min-width:16rem}.centerText{text-align:center}.vaMiddle{vertical-align:middle} \ No newline at end of file diff --git a/static/public/css/main_form.css b/static/public/css/main_form.css new file mode 100644 index 00000000..0ae87815 --- /dev/null +++ b/static/public/css/main_form.css @@ -0,0 +1,71 @@ +.VStack { + display: flex; + flex-direction: column; + justify-content: space-around; +} +.HStack { + display: flex; + flex-direction: row; + justify-content: space-around; +} +.continue_button, .time_button, .cycle_button { + background-color: rgba(0, 0, 0, 0.3); + border: none; + border-radius: 0.25rem; + padding: 0 0.75rem 0 0.75rem; +} +.continue_button:active, .time_button:active, .cycle_button:active { + background-color: rgba(0, 0, 0, 0.45); +} +.continue_button, .time_button { + color: #0a84ff; + min-width: 20vw; + max-width: 25vw; +} +.continue_button { + align-self: center; + min-width: 15vw; + max-width: 70vw; +} +.cycle_button { + align-self: center; + color: #32d74b; + min-width: 50vw; +} +.counter { + color: #fff; + font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; +} +.ios-switch i { + position: relative; + display: inline-block; + margin-right: .5rem; + width: 46px; + height: 26px; + background-color: #000; + border-radius: 23px; + vertical-align: text-bottom; +} +.ios-switch i::before { + content: ""; + position: absolute; + left: 0; + width: 42px; + height: 22px; + background-color: #000; + border-radius: 11px; +} +.ios-switch i::after { + content: ""; + position: absolute; + left: 0; + width: 22px; + height: 22px; + background-color: #fff; + border-radius: 11px; + transform: translate3d(2px, 2px, 0); +} +.ios-switch input { display: none; } +.ios-switch input:checked + i { background-color: #32d74b; } +.ios-switch input:checked + i::before { transform: translate3d(18px, 2px, 0) scale3d(0, 0, 0); } +.ios-switch input:checked + i::after { transform: translate3d(22px, 2px, 0); } \ No newline at end of file diff --git a/static/public/css/main_form.min.css b/static/public/css/main_form.min.css new file mode 100644 index 00000000..c224d66a --- /dev/null +++ b/static/public/css/main_form.min.css @@ -0,0 +1 @@ +.VStack{display:flex;flex-direction:column;justify-content:space-around}.HStack{display:flex;flex-direction:row;justify-content:space-around}.continue_button,.cycle_button,.time_button{background-color:rgba(0, 0, 0, 0.3);border:none;border-radius:0.25rem;padding:0 0.75rem}.continue_button:active,.cycle_button:active,.time_button:active{background-color:rgba(0, 0, 0, 0.45)}.continue_button,.time_button{color:#0a84ff;min-width:20vw;max-width:25vw}.continue_button{align-self:center;min-width:15vw;max-width:70vw}.cycle_button{align-self:center;color:#32d74b;min-width:50vw}.counter{color:#fff;font-family:system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif}.ios-switch i{position:relative;display:inline-block;margin-right:0.5rem;width:46px;height:26px;background-color:#000;border-radius:23px;vertical-align:text-bottom}.ios-switch i::before{content:"";position:absolute;left:0;width:42px;height:22px;background-color:#000;border-radius:11px}.ios-switch i::after{content:"";position:absolute;left:0;width:22px;height:22px;background-color:#fff;border-radius:11px;transform:translate3d(2px, 2px, 0)}.ios-switch input{display:none}.ios-switch input:checked + i{background-color:#32d74b}.ios-switch input:checked + i::before{transform:translate3d(18px, 2px, 0) scale3d(0, 0, 0)}.ios-switch input:checked + i::after{transform:translate3d(22px, 2px, 0)} \ No newline at end of file diff --git a/static/public/js/form/form.js b/static/public/js/form/form.js index fced84fc..f7cce572 100644 --- a/static/public/js/form/form.js +++ b/static/public/js/form/form.js @@ -10,16 +10,16 @@ function themeHandle() { document.body.classList.replace("dark-mode", "light-mode"); document.getElementById("themeMeta").content = "#ffffff"; break; - case "gruvbox": - document.body.classList.replace("dark-mode", "gruvbox"); - document.getElementById("themeMeta").content = "#282828"; - break; case "dark": - case undefined: - default: document.body.classList.replace("light-mode", "dark-mode"); document.getElementById("themeMeta").content = "#121212"; break; + case "gruvbox": + case undefined: + default: + document.body.classList.replace("dark-mode", "gruvbox"); + document.getElementById("themeMeta").content = "#282828"; + break; } } const waitMs = (ms) => new Promise((res) => setTimeout(res, ms)); diff --git a/static/public/js/form/form.min.js b/static/public/js/form/form.min.js index f167e3e3..7feb73b5 100644 --- a/static/public/js/form/form.min.js +++ b/static/public/js/form/form.min.js @@ -1 +1 @@ -"use strict";window.getThemeCookie=()=>{var e=RegExp("4c454a5b1bedf6a1=[^;]+").exec(document.cookie);return decodeURIComponent(e?e.toString().replace(/^[^=]+./,""):"")},window.themeHandle=()=>{let e=getThemeCookie();switch(e){case"light":document.body.classList.replace("dark-mode","light-mode"),document.getElementById("themeMeta").content="#ffffff";break;case"gruvbox":document.body.classList.replace("dark-mode","gruvbox"),document.getElementById("themeMeta").content="#282828";break;default:document.body.classList.replace("light-mode","dark-mode"),document.getElementById("themeMeta").content="#121212"}},window.waitMs=e=>new Promise(t=>setTimeout(t,e)); \ No newline at end of file +"use strict";function getThemeCookie(){var e=RegExp("4c454a5b1bedf6a1=[^;]+").exec(document.cookie);return decodeURIComponent(e?e.toString().replace(/^[^=]+./,""):"")}function themeHandle(){let e=getThemeCookie();switch(e){case"light":document.body.classList.replace("dark-mode","light-mode"),document.getElementById("themeMeta").content="#ffffff";break;case"dark":document.body.classList.replace("light-mode","dark-mode"),document.getElementById("themeMeta").content="#121212";break;default:document.body.classList.replace("dark-mode","gruvbox"),document.getElementById("themeMeta").content="#282828"}}const waitMs=e=>new Promise(t=>setTimeout(t,e)); \ No newline at end of file diff --git a/static/public/js/form/form.ts b/static/public/js/form/form.ts index ac61848f..f9381a3f 100644 --- a/static/public/js/form/form.ts +++ b/static/public/js/form/form.ts @@ -12,14 +12,14 @@ function themeHandle() { document.body.classList.replace("dark-mode", "light-mode"); (document.getElementById("themeMeta") as HTMLMetaElement).content = "#ffffff"; break; - case "gruvbox": - document.body.classList.replace("dark-mode", "gruvbox"); - (document.getElementById("themeMeta") as HTMLMetaElement).content = "#282828"; - break; - case "dark": case undefined: default: + case "dark": document.body.classList.replace("light-mode", "dark-mode"); (document.getElementById("themeMeta") as HTMLMetaElement).content = "#121212"; break; + case "gruvbox": case undefined: default: + document.body.classList.replace("dark-mode", "gruvbox"); + (document.getElementById("themeMeta") as HTMLMetaElement).content = "#282828"; + break; } } diff --git a/static/public/js/homepage/homepage.js b/static/public/js/homepage/homepage.js deleted file mode 100644 index 65771da3..00000000 --- a/static/public/js/homepage/homepage.js +++ /dev/null @@ -1,12 +0,0 @@ -const getCookie = (name) => { - var cookieString = RegExp(name + "=[^;]+").exec(document.cookie); - return decodeURIComponent(!!cookieString ? cookieString.toString().replace(/^[^=]+./, "") : ""); -}; -if (getCookie("lead") === "true") { - var url = document.getElementById("additionalUrl"); - url.style.display = "unset"; -} -else if (Number(getCookie("childTeamLead")) !== 0) { - var url = document.getElementById("additionalUrl2"); - url.style.display = "unset"; -} diff --git a/static/public/js/homepage/homepage.min.js b/static/public/js/homepage/homepage.min.js deleted file mode 100644 index 4f86d384..00000000 --- a/static/public/js/homepage/homepage.min.js +++ /dev/null @@ -1 +0,0 @@ -const getCookie=e=>{var t=RegExp(e+"=[^;]+").exec(document.cookie);return decodeURIComponent(t?t.toString().replace(/^[^=]+./,""):"")};if("true"===getCookie("lead")){var e=document.getElementById("additionalUrl");e.style.display="unset"}else if(0!==Number(getCookie("childTeamLead"))){var e=document.getElementById("additionalUrl2");e.style.display="unset"} \ No newline at end of file diff --git a/static/public/js/homepage/homepage.ts b/static/public/js/homepage/homepage.ts deleted file mode 100644 index 280b4e09..00000000 --- a/static/public/js/homepage/homepage.ts +++ /dev/null @@ -1,12 +0,0 @@ -const getCookie = (name: string): string => { - var cookieString = RegExp(name + "=[^;]+").exec(document.cookie); - return decodeURIComponent(!!cookieString ? cookieString.toString().replace(/^[^=]+./, "") : ""); -} - -if (getCookie("lead") === "true") { - var url: HTMLElement = (document.getElementById("additionalUrl") as HTMLElement); - url.style.display = "unset"; -} else if (Number(getCookie("childTeamLead")) !== 0) { - var url: HTMLElement = (document.getElementById("additionalUrl2") as HTMLElement); - url.style.display = "unset"; -} \ No newline at end of file diff --git a/static/public/js/main/main.js b/static/public/js/main/main.js new file mode 100644 index 00000000..6a9ce170 --- /dev/null +++ b/static/public/js/main/main.js @@ -0,0 +1,77 @@ +import { _get } from "../_modules/get/get.min.js"; +// get events +const API_META = "/api/v1/data"; +const API_MATCHES = ["/api/v1/events/matches/", /* season */ "/", /* event */ "/qual/true"]; +const API_WHOAMI = "/api/v1/whoami"; +var match_schedule; +function init() { + load_events(); + try { + load_matches(document.getElementById("event_code").value); + match_num_entry(document.getElementById("match_num_input").value); + } + catch { } + document.getElementById("event_code").addEventListener("change", () => { + load_matches(document.getElementById("event_code").value); + }); + document.getElementById("match_num_input").addEventListener("change", () => { + match_num_entry(document.getElementById("match_num_input").value); + }); + let adv_buttons = document.getElementsByClassName("continue_button"); + for (var i = 0; i < 3; i++) { + adv_buttons[i].addEventListener("click", () => { + advance_screen(i + 1); + }); + } +} +function load_events() { + _get(API_META, null).then((result) => { + result.events.forEach(event_code => { + document.getElementById("event_code").insertAdjacentHTML("beforeend", ``); + }); + }).catch((error) => { + alert(`failed to load valid event codes. ${error}`); + }); +} +function load_matches(event) { + _get(API_MATCHES[0] + "2023" + API_MATCHES[1] + event + API_MATCHES[2], null).then((result) => { + if (result.Schedule.length != 0) { + match_schedule = result.Schedule; + } + else { + alert("match schedule is not yet posted"); + match_schedule = []; + } + }).catch((error) => { + alert(`failed to load matches. ${error}`); + match_schedule = []; + }); +} +function set_option(element, value) { + element.innerText = value; + element.value = value; +} +function match_num_entry(entry) { + let entry_num = Number(entry); + if (entry_num > match_schedule.length || entry_num < 1) { + document.getElementById("bad_match_num").innerText = `invalid. must be between 1 and ${match_schedule.length}`; + document.getElementById("bad_match_num").style.display = "unset"; + } + else { + document.getElementById("bad_match_num").style.display = "none"; + let select_elements = document.getElementsByClassName("teamNumOption"); + set_option(select_elements[3], match_schedule[entry_num - 1].teams[0].teamNumber); + set_option(select_elements[4], match_schedule[entry_num - 1].teams[1].teamNumber); + set_option(select_elements[5], match_schedule[entry_num - 1].teams[2].teamNumber); + set_option(select_elements[0], match_schedule[entry_num - 1].teams[3].teamNumber); + set_option(select_elements[1], match_schedule[entry_num - 1].teams[4].teamNumber); + set_option(select_elements[2], match_schedule[entry_num - 1].teams[5].teamNumber); + } +} +function advance_screen(screen) { + let panes = document.getElementsByClassName("main_pane"); + for (var i = 0; i < 4; i++) { + panes[i].style.display = screen === i ? "unset" : "none"; + } +} +document.body.onload = init; diff --git a/static/public/js/main/main.ts b/static/public/js/main/main.ts new file mode 100644 index 00000000..6f70e6f6 --- /dev/null +++ b/static/public/js/main/main.ts @@ -0,0 +1,85 @@ +import { _get } from "../_modules/get/get.min.js"; + +// get events +const API_META = "/api/v1/data"; +const API_MATCHES = ["/api/v1/events/matches/", /* season */ "/", /* event */ "/qual/true"]; +const API_WHOAMI = "/api/v1/whoami"; + +var match_schedule; + +function init() { + load_events(); + try { + load_matches((document.getElementById("event_code") as HTMLSelectElement).value); + match_num_entry((document.getElementById("match_num_input") as HTMLSelectElement).value); + } catch {} + + (document.getElementById("event_code") as HTMLSelectElement).addEventListener("change", () => { + load_matches((document.getElementById("event_code") as HTMLSelectElement).value); + }); + (document.getElementById("match_num_input") as HTMLSelectElement).addEventListener("change", () => { + match_num_entry((document.getElementById("match_num_input") as HTMLSelectElement).value) + }); + + let adv_buttons = document.getElementsByClassName("continue_button") as HTMLCollectionOf; + for (var i = 0; i < 3; i++) { + adv_buttons[i].addEventListener("click", () => { + advance_screen(i + 1); + }); + } +} + +function load_events() { + _get(API_META, null).then((result) => { + result.events.forEach(event_code => { + (document.getElementById("event_code") as HTMLSelectElement).insertAdjacentHTML("beforeend", ``); + }); + }).catch((error) => { + alert(`failed to load valid event codes. ${error}`); + }); +} + +function load_matches(event: String) { + _get(API_MATCHES[0] + "2023" + API_MATCHES[1] + event + API_MATCHES[2], null).then((result) => { + if (result.Schedule.length != 0) { + match_schedule = result.Schedule; + } else { + alert("match schedule is not yet posted") + match_schedule = []; + } + }).catch((error) => { + alert(`failed to load matches. ${error}`) + match_schedule = []; + }) +} + +function set_option(element: HTMLOptionElement, value: string) { + element.innerText = value; + element.value = value; +} + +function match_num_entry(entry: String) { + let entry_num = Number(entry); + if (entry_num > match_schedule.length || entry_num < 1) { + (document.getElementById("bad_match_num") as HTMLSpanElement).innerText = `invalid. must be between 1 and ${match_schedule.length}`; + (document.getElementById("bad_match_num") as HTMLSpanElement).style.display = "unset"; + } else { + (document.getElementById("bad_match_num") as HTMLSpanElement).style.display = "none"; + let select_elements: HTMLCollectionOf = document.getElementsByClassName("teamNumOption") as HTMLCollectionOf; + set_option(select_elements[3], match_schedule[entry_num - 1].teams[0].teamNumber); + set_option(select_elements[4], match_schedule[entry_num - 1].teams[1].teamNumber); + set_option(select_elements[5], match_schedule[entry_num - 1].teams[2].teamNumber); + set_option(select_elements[0], match_schedule[entry_num - 1].teams[3].teamNumber); + set_option(select_elements[1], match_schedule[entry_num - 1].teams[4].teamNumber); + set_option(select_elements[2], match_schedule[entry_num - 1].teams[5].teamNumber); + } +} + +function advance_screen(screen: Number) { + let panes = document.getElementsByClassName("main_pane") as HTMLCollectionOf; + for (var i = 0; i < 4; i++) { + panes[i].style.display = screen === i ? "unset" : "none"; + } +} + +document.body.onload = init \ No newline at end of file diff --git a/static/scouts.html b/static/scouts.html index 5e026a50..2b411cfb 100644 --- a/static/scouts.html +++ b/static/scouts.html @@ -5,7 +5,7 @@ Scouts - bearTracks - + diff --git a/static/settings.html b/static/settings.html index 4ce20f19..1f26120c 100644 --- a/static/settings.html +++ b/static/settings.html @@ -5,7 +5,7 @@ Settings - bearTracks - + diff --git a/static/spin.html b/static/spin.html index ab56eb54..1c2f80ac 100644 --- a/static/spin.html +++ b/static/spin.html @@ -5,13 +5,13 @@ Spinner - bearTracks - + - +