From 86fbccdfb81c6c9da9c72a24bc3c4ac54af034ac Mon Sep 17 00:00:00 2001 From: Gematik Date: Tue, 23 Jan 2024 14:02:49 +0100 Subject: [PATCH] Release 1.18.1 --- .gitignore | 2 + README.md | 34 +- ReleaseNotes.md | 6 + app/android-mock/build.gradle.kts | 3 + .../ti/erp/app/DefaultErezeptMockApp.kt | 27 +- .../app/di/{AllModules.kt => AppModules.kt} | 74 +- .../ti/erp/app/di/MockFeatureModule.kt | 78 + .../app/info/MockBuildConfigInformation.kt | 71 + .../app/info/MockBuildConfigurationModule.kt} | 8 +- ...acyTestModule.kt => PharmacyMockModule.kt} | 10 +- .../erp/app/pkv/MockFileProviderAuthority.kt | 27 + .../pkv/MockFileProviderAuthorityModule.kt | 26 + .../res/mipmap-anydpi-v26/ic_launcher.xml | 2 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 2 +- app/android/build.gradle.kts | 15 +- app/android/proguard-rules.pro | 2 + .../test/compose/EditableTextFieldTest.kt | 71 + .../gematik/ti/erp/app/DefaultErezeptApp.kt | 16 +- .../de/gematik/ti/erp/app/di/AppModules.kt | 2 +- .../de/gematik/ti/erp/app/di/ModuleNames.kt | 5 +- .../app/pkv/FileProviderAuthorityModule.kt | 3 +- .../main/res/raw/analytics_identifier.json | 487 ----- .../src/main/res/raw/animation_courier.webm | Bin 219085 -> 0 bytes .../src/main/res/raw/animation_local.webm | Bin 297859 -> 0 bytes .../src/main/res/raw/animation_mail.webm | Bin 124076 -> 0 bytes .../main/res/raw/animation_pulse_lottie.json | 1 - .../src/main/res/raw/device_lottie.json | 1 - .../res/raw/health_insurance_contacts.json | 1157 ----------- .../src/main/res/raw/healthcard_lottie.json | 1 - .../src/main/res/raw/nfc_positions.json | 1713 ----------------- .../settings/usecase/SettingsUseCaseTest.kt | 9 +- app/demo-mode/build.gradle.kts | 15 +- ...emoModeActivity.kt => DemoModeObserver.kt} | 21 +- .../demomode/datasource/DemoModeDataSource.kt | 121 +- .../datasource/data/DemoAuditEventInfo.kt | 4 +- .../demomode/datasource/data/DemoConstants.kt | 1 - .../datasource/data/DemoPrescriptionInfo.kt | 24 - .../datasource/data/DemoProfileInfo.kt | 54 +- .../ti/erp/app/demomode/di/DemoModeModule.kt | 1 - .../erp/app/demomode/model/DemoModeProfile.kt | 63 + .../model/DemoModeSentCommunicationJson.kt | 1 - .../orders/DemoCommunicationRepository.kt | 10 +- .../pharmacy/DemoPharmacyLocalDataSource.kt | 4 +- .../DemoPrescriptionsRepository.kt | 6 +- .../prescriptions/DemoTaskRepository.kt | 4 +- .../profiles/DemoProfilesRepository.kt | 29 +- .../protocol/DemoAuditEventsRepository.kt | 21 +- .../erp/app/demomode/ui/DemoModeTopAppBar.kt | 10 +- .../demomode/usecase/idp/DemoIdpUseCase.kt | 10 +- app/features/build.gradle.kts | 15 +- .../app/{debug => }/data/DebugSettingsData.kt | 2 +- .../erp/app/{debug => }/data/Environment.kt | 2 +- .../gematik/ti/erp/app/di/EndpointHelper.kt | 2 +- .../app/navigation/DebugScreenNavigation.kt | 28 + .../app/{debug => }/ui/DebugLoadingButton.kt | 6 +- .../ti/erp/app/{debug => }/ui/DebugPKV.kt | 2 +- .../ti/erp/app/{debug => }/ui/DebugScreen.kt | 124 +- .../app/{debug => }/ui/DebugScreenWrapper.kt | 2 +- .../{debug => }/ui/DebugSettingsViewModel.kt | 6 +- app/features/src/main/AndroidManifest.xml | 4 + .../de/gematik/ti/erp/app/MainActivity.kt | 176 +- .../gematik/ti/erp/app/analytics/Analytics.kt | 75 +- .../analytics/mapper/ContentSquareMapper.kt | 34 + .../usecase/ChangeAnalyticsStateUseCase.kt | 35 + .../usecase/IsAnalyticsAllowedUseCase.kt | 32 + .../erp/app/appsecurity/AppSecurityModule.kt | 38 + .../erp/app/appsecurity/AppSecuritySession.kt | 43 + .../navigation/AppSecurityGraph.kt | 126 ++ .../navigation/AppSecurityRoutes.kt | 43 + .../presentation/AppSecurityController.kt | 86 + .../presentation/InsecureDeviceController.kt | 59 + .../IntegrityWarningController.kt | 58 + .../ui/DeviceCheckLoadingStartScreen.kt | 87 + .../appsecurity/ui/InsecureDeviceScreen.kt | 134 ++ .../appsecurity/ui/IntegrityWarningScreen.kt | 176 ++ .../appsecurity/ui/model/AppSecurityResult.kt | 27 + .../AcceptDeviceSecurityRiskUseCase.kt | 40 + .../usecase/AcceptIntegrityRiskUseCase.kt | 40 + .../app/appsecurity/usecase/AcceptRiskEnum.kt | 23 + .../usecase/GetDeviceSecurityUseCase.kt | 73 + .../usecase/IntegrityUseCase.kt | 48 +- .../usecase/IsIntegrityRiskAcceptedUseCase.kt | 38 + .../gematik/ti/erp/app/base/BaseActivity.kt | 271 +++ .../cardunlock/model/UnlockEgkNavigation.kt | 16 +- .../app/cardunlock/ui/UnlockEgKComponents.kt | 4 +- .../erp/app/cardwall/ui/CardWallComponents.kt | 4 +- .../{Navigation.kt => CardWallNavigation.kt} | 22 +- .../de/gematik/ti/erp/app/core/AppContent.kt | 5 +- .../timeout/DebugTimeoutScreen.kt | 249 +++ .../timeout/intent/AppRestartIntent.kt | 31 + .../timeout/ui/MetricChangeDialog.kt | 202 ++ .../de/gematik/ti/erp/app/di/FeatureModule.kt | 9 +- .../de/gematik/ti/erp/app/idp/IdpModule.kt | 2 +- .../navigation/MainScreenContentNavHost.kt | 5 +- .../navigation/MainScreenNavigation.kt | 130 +- .../navigation/MainScreenNavigationScreens.kt | 58 +- .../presentation/MainScreenController.kt | 118 +- .../app/mainscreen/ui/InsecureDeviceScreen.kt | 219 --- .../ui/MainScreenBottomSheetContentState.kt | 19 +- .../app/mainscreen/ui/MainScreenScaffold.kt | 14 +- .../ui/MainScreenScaffoldContainer.kt | 158 +- .../mainscreen/ui/MultiProfileTopAppBar.kt | 33 +- .../ti/erp/app/mainscreen/ui/ToolTip.kt | 27 +- .../navigation/NavGraphBuilderExtension.kt | 66 + .../navigation/NavigationAnimationUtils.kt | 57 + .../app/navigation/NavigationRouteNames.kt | 32 + .../ti/erp/app/navigation/NavigationRoutes.kt | 24 + .../ti/erp/app/navigation/NavigationType.kt | 40 + .../{Navigation.kt => navigation/Routes.kt} | 31 +- .../gematik/ti/erp/app/navigation/Screen.kt | 60 + .../app/onboarding/ui/OnboardingComponents.kt | 105 +- .../app/onboarding/ui/OnboardingController.kt | 96 + .../ui/HealthCardOrderComponents.kt | 4 +- .../ui/HealthCardOrderState.kt | 8 +- .../ti/erp/app/pharmacy/ui/Navigation.kt | 4 +- .../ti/erp/app/pharmacy/ui/OrderSelection.kt | 112 +- .../erp/app/pharmacy/ui/model/Navigation.kt | 14 +- .../app/prescription/PrescriptionModule.kt | 2 +- .../detail/ui/PrescriptionDetailScreen.kt | 4 +- .../detail/ui/SharePrescriptionController.kt | 2 +- .../detail/ui/TechnicalInformation.kt | 8 +- .../detail/ui/model/Navigation.kt | 20 +- .../app/prescription/ui/MainScreenAvatar.kt | 4 +- .../app/prescription/ui/MlKitIntroScreen.kt | 26 +- .../usecase/GetActivePrescriptionsUseCase.kt | 15 +- .../GetArchivedPrescriptionsUseCase.kt | 16 +- .../usecase/RefreshPrescriptionUseCase.kt | 7 + .../usecase/model/Prescription.kt | 9 +- .../gematik/ti/erp/app/profiles/ui/Avatar.kt | 2 +- .../app/profiles/ui/EditProfileNavigation.kt | 28 +- .../erp/app/profiles/ui/EditProfileScreen.kt | 22 +- .../profiles/ui/ProfileColorAndImagePicker.kt | 26 +- .../ti/erp/app/profiles/ui/ProfileHandler.kt | 81 - .../ti/erp/app/redeem/ui/Navigation.kt | 4 +- .../app/redeem/ui/model/RedeemNavigation.kt | 12 +- .../ti/erp/app/settings/SettingsModule.kt | 29 + .../ui/AccessibilitySettingsScreen.kt | 13 +- .../app/settings/ui/AllowBiometryScreen.kt | 50 +- .../ui/DeviceSecuritySettingsScreen.kt | 4 +- .../ti/erp/app/settings/ui/PasswordScreen.kt | 20 +- .../ui/ProductImprovementSettingsScreen.kt | 28 +- .../erp/app/settings/ui/SettingsController.kt | 134 +- .../erp/app/settings/ui/SettingsNavigation.kt | 28 +- .../ti/erp/app/settings/ui/SettingsScreen.kt | 69 +- .../app/settings/usecase/SettingsUseCase.kt | 9 +- .../local/TimeoutsLocalDataSource.kt | 153 ++ .../timeouts/di/TimeoutsSharedPrefsModule.kt | 83 + .../presentation/TimeoutsScreenViewModel.kt | 159 ++ .../repository/DefaultTimeoutRepository.kt | 52 + .../usecase/GetInactivityMetricUseCase.kt | 27 + .../usecase/GetPauseMetricUseCase.kt} | 12 +- .../usecase/SetInactivityMetricUseCase.kt | 38 + .../timeouts/usecase/SetPauseMetricUseCase.kt | 37 + .../troubleshooting/TroubleshootingContent.kt | 14 +- .../observer/BiometricPromptBuilder.kt | 127 ++ .../InactivityTimeoutObserver.kt} | 83 +- .../observer/ProcessLifecycleObserver.kt | 35 + ...ricPrompt.kt => BiometricPromptWrapper.kt} | 20 +- .../ui/UserAuthenticationController.kt | 47 +- .../ui/UserAuthenticationScreenComponents.kt | 143 +- .../ti/erp/app/utils/compose/ClickableText.kt | 11 +- .../ti/erp/app/utils/compose/ComposeTags.kt | 24 + .../app/utils/compose/EditableHeaderText.kt | 76 +- .../ti/erp/app/utils/compose/ErrorText.kt | 37 + .../ti/erp/app/utils/compose/Toggle.kt | 76 + .../app/utils/extensions/DialogScaffold.kt | 35 + .../app/utils/extensions/SnackbarScaffold.kt | 41 + .../de/gematik/ti/erp/app/vau/VauModule.kt | 11 +- .../src/main/res/drawable/ic_finger.xml | 57 + .../src/main/res/drawable/ic_log_mail.xml | 10 + app/features/src/main/res/drawable/ic_pkv.xml | 10 + .../res/drawable/ic_prescription_refresh.xml | 10 + .../src/main/res/drawable/ic_qr_code.xml | 10 + .../src/main/res/drawable/ic_reset.xml | 10 + .../res/raw/health_insurance_contacts.json | 29 +- app/features/src/main/res/values/strings.xml | 3 +- app/features/src/main/res/values/themes.xml | 9 + .../data/DebugSettingsData.kt | 43 + .../de.gematik.ti.erp.app/data/Environment.kt | 23 + .../di/EndpointHelper.kt | 161 ++ .../navigation/DebugScreenNavigation.kt | 28 + .../ui/DebugLoadingButton.kt | 88 + .../de.gematik.ti.erp.app/ui/DebugPKV.kt | 112 ++ .../de.gematik.ti.erp.app/ui/DebugScreen.kt | 762 ++++++++ .../ui/DebugScreenWrapper.kt | 26 + .../ui/DebugSettingsViewModel.kt | 370 ++++ .../utils/compose/DebugCommon.kt | 131 ++ .../{debug => }/ui/DebugScreenWrapper.kt | 2 +- app/shared-test/build.gradle.kts | 7 +- assemble-mock.sh | 21 + build.gradle.kts | 19 +- common/build.gradle.kts | 8 + .../de/gematik/ti/erp/app/db/Migrations.kt | 2 +- .../ti/erp/app/db/entities/v1/Settings.kt | 5 + .../usecase/model/PharmacyUseCaseData.kt | 12 + .../repository/DefaultProfilesRepository.kt | 11 + .../profiles/repository/ProfileRepository.kt | 1 + .../ti/erp/app/settings/GeneralSettings.kt | 2 + .../ti/erp/app/settings/model/SettingsData.kt | 6 +- .../settings/repository/SettingsRepository.kt | 25 +- .../settings/usecase/AcceptMLKitUseCase.kt | 27 + .../settings/usecase/AllowAnalyticsUseCase.kt | 27 + .../usecase/AllowScreenshotsUseCase.kt | 27 + .../usecase/GetCanStartToolTipsUseCase.kt | 31 + .../usecase/GetMLKitAcceptedUseCase.kt | 31 + .../usecase/GetOnboardingSucceededUseCase.kt | 34 + .../usecase/GetScreenShotsAllowedUseCase.kt | 31 + .../usecase/GetShowWelcomeDrawerUseCase.kt | 31 + .../usecase/SaveAuthenticationModeUseCase.kt | 27 + .../usecase/SaveOnboardingSuccededUseCase.kt | 34 + .../settings/usecase/SavePasswordUseCase.kt | 30 + .../usecase/SaveToolTippsShownUseCase.kt | 27 + .../usecase/SaveWelcomeDrawerShownUseCase.kt | 27 + .../timeouts/repository/TimeoutRepository.kt | 30 + .../repository/SettingsRepositoryTest.kt | 8 +- gradle.properties | 2 +- .../kotlin/de/gematik/ti/erp/Dependencies.kt | 8 +- settings.gradle.kts | 6 +- 218 files changed, 7470 insertions(+), 5179 deletions(-) rename app/android-mock/src/main/java/de/gematik/ti/erp/app/di/{AllModules.kt => AppModules.kt} (64%) create mode 100644 app/android-mock/src/main/java/de/gematik/ti/erp/app/di/MockFeatureModule.kt create mode 100644 app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigInformation.kt rename app/{features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt => android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigurationModule.kt} (77%) rename app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/{PharmacyTestModule.kt => PharmacyMockModule.kt} (87%) create mode 100644 app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthority.kt create mode 100644 app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthorityModule.kt create mode 100644 app/android/src/androidTest/java/de/gematik/ti/erp/app/test/test/compose/EditableTextFieldTest.kt delete mode 100644 app/android/src/main/res/raw/analytics_identifier.json delete mode 100644 app/android/src/main/res/raw/animation_courier.webm delete mode 100644 app/android/src/main/res/raw/animation_local.webm delete mode 100644 app/android/src/main/res/raw/animation_mail.webm delete mode 100644 app/android/src/main/res/raw/animation_pulse_lottie.json delete mode 100644 app/android/src/main/res/raw/device_lottie.json delete mode 100644 app/android/src/main/res/raw/health_insurance_contacts.json delete mode 100644 app/android/src/main/res/raw/healthcard_lottie.json delete mode 100644 app/android/src/main/res/raw/nfc_positions.json rename app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/{DemoModeActivity.kt => DemoModeObserver.kt} (68%) create mode 100644 app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeProfile.kt rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/data/DebugSettingsData.kt (97%) rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/data/Environment.kt (94%) create mode 100644 app/features/src/debug/kotlin/de/gematik/ti/erp/app/navigation/DebugScreenNavigation.kt rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/ui/DebugLoadingButton.kt (98%) rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/ui/DebugPKV.kt (99%) rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/ui/DebugScreen.kt (88%) rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/ui/DebugScreenWrapper.kt (95%) rename app/features/src/debug/kotlin/de/gematik/ti/erp/app/{debug => }/ui/DebugSettingsViewModel.kt (99%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/mapper/ContentSquareMapper.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/ChangeAnalyticsStateUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/IsAnalyticsAllowedUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecurityModule.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecuritySession.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityGraph.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityRoutes.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/AppSecurityController.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/InsecureDeviceController.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/IntegrityWarningController.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/DeviceCheckLoadingStartScreen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/InsecureDeviceScreen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/IntegrityWarningScreen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/model/AppSecurityResult.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptDeviceSecurityRiskUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptIntegrityRiskUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptRiskEnum.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/GetDeviceSecurityUseCase.kt rename app/features/src/main/kotlin/de/gematik/ti/erp/app/{attestation => appsecurity}/usecase/IntegrityUseCase.kt (70%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IsIntegrityRiskAcceptedUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/base/BaseActivity.kt rename app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/{Navigation.kt => CardWallNavigation.kt} (54%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/DebugTimeoutScreen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/intent/AppRestartIntent.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/ui/MetricChangeDialog.kt delete mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavGraphBuilderExtension.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationAnimationUtils.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRouteNames.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRoutes.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationType.kt rename app/features/src/main/kotlin/de/gematik/ti/erp/app/{Navigation.kt => navigation/Routes.kt} (72%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Screen.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingController.kt delete mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/datasource/local/TimeoutsLocalDataSource.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/di/TimeoutsSharedPrefsModule.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/presentation/TimeoutsScreenViewModel.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/repository/DefaultTimeoutRepository.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetInactivityMetricUseCase.kt rename app/features/src/{debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt => main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetPauseMetricUseCase.kt} (73%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetInactivityMetricUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetPauseMetricUseCase.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/BiometricPromptBuilder.kt rename app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/{ui/AuthenticationUseCase.kt => observer/InactivityTimeoutObserver.kt} (72%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/ProcessLifecycleObserver.kt rename app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/{BiometricPrompt.kt => BiometricPromptWrapper.kt} (90%) create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ComposeTags.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ErrorText.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/Toggle.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/DialogScaffold.kt create mode 100644 app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/SnackbarScaffold.kt create mode 100644 app/features/src/main/res/drawable/ic_finger.xml create mode 100644 app/features/src/main/res/drawable/ic_log_mail.xml create mode 100644 app/features/src/main/res/drawable/ic_pkv.xml create mode 100644 app/features/src/main/res/drawable/ic_prescription_refresh.xml create mode 100644 app/features/src/main/res/drawable/ic_qr_code.xml create mode 100644 app/features/src/main/res/drawable/ic_reset.xml create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/DebugSettingsData.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/Environment.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/di/EndpointHelper.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/navigation/DebugScreenNavigation.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugLoadingButton.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugPKV.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreen.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugSettingsViewModel.kt create mode 100644 app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/utils/compose/DebugCommon.kt rename app/features/src/release/kotlin/de.gematik.ti.erp.app/{debug => }/ui/DebugScreenWrapper.kt (95%) create mode 100755 assemble-mock.sh create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AcceptMLKitUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowAnalyticsUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowScreenshotsUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetCanStartToolTipsUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetMLKitAcceptedUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetOnboardingSucceededUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetScreenShotsAllowedUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetShowWelcomeDrawerUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveAuthenticationModeUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveOnboardingSuccededUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SavePasswordUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveToolTippsShownUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveWelcomeDrawerShownUseCase.kt create mode 100644 common/src/commonMain/kotlin/de/gematik/ti/erp/app/timeouts/repository/TimeoutRepository.kt diff --git a/.gitignore b/.gitignore index 6d16126f..a6aa9bab 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ documentation-internal android/src/androidTest technical_requirements_report.html keystore +CODEOWNERS +local.cliactions.yaml diff --git a/README.md b/README.md index fa3c595b..21851be0 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,30 @@ This repository is an [Kotlin Multiplatform Project](https://kotlinlang.org/docs ### Structure ```text -|-- android -| `-- src -| |-- androidTest -| |-- debug -| |-- main -| |-- release -| |-- sharedTest -| `-- test +|-- app +| `-- android +| `-- src +| |-- androidTest +| |-- main +| `-- test +| `-- android-mock +| `-- src +| |-- androidTest +| |-- main +| `-- test +| `-- demo-mode +| `-- src +| |-- main +| `-- features +| `-- src +| |-- debug +| |-- release +| |-- androidTest +| |-- main +| `-- test +| `-- shared-test +| `-- src +| |-- main |-- common | `-- src | |-- androidMain @@ -95,7 +111,7 @@ gradle :android:assemble(Google|Huawei)Pu(External|Internal)(Debug|Release) -Pbu *Note: Currently the android build variant is derived from the `buildkonfig.flavor` property.* -The resulting `.apk` can be found in e.g. `android/build/outputs/apk/googlePuExternal/debug/`. +The resulting `.apk` can be found in e.g. `app/android/build/outputs/apk/googlePuExternal/debug/`. #### Visualize Test Tags diff --git a/ReleaseNotes.md b/ReleaseNotes.md index eaeb76a5..36a8b5a6 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,9 @@ +# Release 1.18.1 +- Optimized performance +- UX improvements +- Bug fixes + + # Release 1.17.2 - Added Demo mode function - Added function to change the name of scanned prescriptions diff --git a/app/android-mock/build.gradle.kts b/app/android-mock/build.gradle.kts index 973500a7..a5364bed 100644 --- a/app/android-mock/build.gradle.kts +++ b/app/android-mock/build.gradle.kts @@ -78,6 +78,9 @@ android { resValue("string", "app_label", "E-Rezept Mock") versionNameSuffix = "-debug" } + create("minifiedDebug") { + initWith(debug) + } } packagingOptions { diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/DefaultErezeptMockApp.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/DefaultErezeptMockApp.kt index 8a327f4f..c28ca8ec 100644 --- a/app/android-mock/src/main/java/de/gematik/ti/erp/app/DefaultErezeptMockApp.kt +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/DefaultErezeptMockApp.kt @@ -7,8 +7,10 @@ package de.gematik.ti.erp.app import androidx.lifecycle.ProcessLifecycleOwner import com.contentsquare.android.Contentsquare import com.tom_roush.pdfbox.android.PDFBoxResourceLoader -import de.gematik.ti.erp.app.di.allModules -import de.gematik.ti.erp.app.userauthentication.ui.AuthenticationUseCase +import de.gematik.ti.erp.app.di.appModules +import de.gematik.ti.erp.app.di.mockFeatureModule +import de.gematik.ti.erp.app.userauthentication.observer.InactivityTimeoutObserver +import de.gematik.ti.erp.app.userauthentication.observer.ProcessLifecycleObserver import io.github.aakira.napier.DebugAntilog import io.github.aakira.napier.Napier import org.kodein.di.DI @@ -21,25 +23,26 @@ class DefaultErezeptMockApp : ErezeptApp(), DIAware { override val di by DI.lazy { import(androidXModule(this@DefaultErezeptMockApp)) - importAll(allModules) - bindSingleton { AuthenticationUseCase(instance()) } + importAll(appModules) + importAll(mockFeatureModule, allowOverride = true) + bindSingleton { InactivityTimeoutObserver(instance(), instance()) } + bindSingleton { ProcessLifecycleObserver(ProcessLifecycleOwner, instance()) } bindSingleton { VisibleDebugTree() } } - private val authUseCase: AuthenticationUseCase by instance() + private val processLifecycleObserver: ProcessLifecycleObserver by instance() private val visibleDebugTree: VisibleDebugTree by instance() override fun onCreate() { super.onCreate() - if (BuildKonfig.INTERNAL) { - Napier.base(DebugAntilog()) - Napier.base(visibleDebugTree) - } - ProcessLifecycleOwner.get().lifecycle.apply { - addObserver(authUseCase) - } + Napier.base(DebugAntilog()) + Napier.base(visibleDebugTree) + + processLifecycleObserver.observeForInactivity() + PDFBoxResourceLoader.init(this) + Contentsquare.start(this) } } diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt similarity index 64% rename from app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt rename to app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt index b5d322a4..b013efdb 100644 --- a/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt @@ -1,33 +1,3 @@ -package de.gematik.ti.erp.app.di - -import android.content.Context -import androidx.security.crypto.EncryptedSharedPreferences -import androidx.security.crypto.MasterKey -import de.gematik.ti.erp.app.DispatchProvider -import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.analytics.Analytics -import de.gematik.ti.erp.app.analytics.usecase.AnalyticsUseCase -import de.gematik.ti.erp.app.attestation.usecase.integrityModule -import de.gematik.ti.erp.app.cardunlock.cardUnlockModule -import de.gematik.ti.erp.app.cardwall.cardWallModule -import de.gematik.ti.erp.app.featuretoggle.FeatureToggleManager -import de.gematik.ti.erp.app.idp.idpModule -import de.gematik.ti.erp.app.orderhealthcard.orderHealthCardModule -import de.gematik.ti.erp.app.orders.messagesModule -import de.gematik.ti.erp.app.pharmacy.pharmacyMockModule -import de.gematik.ti.erp.app.pkv.pkvModule -import de.gematik.ti.erp.app.prescription.prescriptionModule -import de.gematik.ti.erp.app.prescription.taskModule -import de.gematik.ti.erp.app.profiles.profilesModule -import de.gematik.ti.erp.app.protocol.protocolModule -import de.gematik.ti.erp.app.redeem.redeemModule -import de.gematik.ti.erp.app.settings.settingsModule -import de.gematik.ti.erp.app.vau.vauModule -import org.kodein.di.DI -import org.kodein.di.bindProvider -import org.kodein.di.bindSingleton -import org.kodein.di.instance - /* * Copyright (c) 2024 gematik GmbH * @@ -46,6 +16,22 @@ import org.kodein.di.instance * */ +package de.gematik.ti.erp.app.di + +import android.content.Context +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.analytics.Analytics +import de.gematik.ti.erp.app.analytics.usecase.AnalyticsUseCase +import de.gematik.ti.erp.app.featuretoggle.FeatureToggleManager +import de.gematik.ti.erp.app.info.mockBuildConfigurationModule +import de.gematik.ti.erp.app.pkv.mockFileProviderAuthorityModule +import org.kodein.di.DI +import org.kodein.di.bindProvider +import org.kodein.di.bindSingleton +import org.kodein.di.instance + private const val PREFERENCES_FILE_NAME = "appPrefs" private const val NETWORK_SECURE_PREFS_FILE_NAME = "networkingSecurePrefs" private const val NETWORK_PREFS_FILE_NAME = "networkingPrefs" @@ -55,12 +41,7 @@ const val ApplicationPreferencesTag = "ApplicationPreferences" const val NetworkPreferencesTag = "NetworkPreferences" const val NetworkSecurePreferencesTag = "NetworkSecurePreferences" -@Requirement( - "A_20184#1", - sourceSpecification = "gemSpec_eRp_FdV", - rationale = "Bind EncryptedSharedPreferences." -) -val allModules = DI.Module("allModules") { +val appModules = DI.Module("appModules") { bindSingleton { object : DispatchProvider {} } bindSingleton(ApplicationPreferencesTag) { val context = instance() @@ -89,25 +70,10 @@ val allModules = DI.Module("allModules") { bindProvider { AnalyticsUseCase(instance()) } - bindSingleton { Analytics(instance(), instance(ApplicationPreferencesTag), instance()) } + bindSingleton { Analytics(instance(), instance(), instance(), instance()) } importAll( - cardWallModule, - integrityModule, - networkModule, - realmModule, - idpModule, - messagesModule, - orderHealthCardModule, - pharmacyMockModule, - redeemModule, - prescriptionModule, - profilesModule, - protocolModule, - taskModule, - settingsModule, - vauModule, - cardUnlockModule, - pkvModule + mockBuildConfigurationModule, + mockFileProviderAuthorityModule ) } diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/MockFeatureModule.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/MockFeatureModule.kt new file mode 100644 index 00000000..370fede2 --- /dev/null +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/di/MockFeatureModule.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.di + +import de.gematik.ti.erp.app.appsecurity.appSecurityModule +import de.gematik.ti.erp.app.authentication.di.authenticationModule +import de.gematik.ti.erp.app.cardunlock.cardUnlockModule +import de.gematik.ti.erp.app.cardwall.cardWallModule +import de.gematik.ti.erp.app.idp.idpModule +import de.gematik.ti.erp.app.idp.idpUseCaseModule +import de.gematik.ti.erp.app.orderhealthcard.orderHealthCardModule +import de.gematik.ti.erp.app.orders.messageRepositoryModule +import de.gematik.ti.erp.app.orders.messagesModule +import de.gematik.ti.erp.app.pharmacy.di.pharmacyRepositoryModule +import de.gematik.ti.erp.app.pharmacy.pharmacyMockModule +import de.gematik.ti.erp.app.pkv.pkvModule +import de.gematik.ti.erp.app.prescription.prescriptionModule +import de.gematik.ti.erp.app.prescription.prescriptionRepositoryModule +import de.gematik.ti.erp.app.prescription.taskModule +import de.gematik.ti.erp.app.prescription.taskRepositoryModule +import de.gematik.ti.erp.app.profiles.profileRepositoryModule +import de.gematik.ti.erp.app.profiles.profilesModule +import de.gematik.ti.erp.app.protocol.protocolModule +import de.gematik.ti.erp.app.protocol.protocolRepositoryModule +import de.gematik.ti.erp.app.redeem.redeemModule +import de.gematik.ti.erp.app.settings.settingsModule +import de.gematik.ti.erp.app.vau.vauModule +import org.kodein.di.DI + +val mockFeatureModule = DI.Module("featureModule", allowSilentOverride = true) { + importAll( + cardWallModule, + appSecurityModule, + networkModule, + realmModule, + idpModule, + idpUseCaseModule, + messagesModule, + orderHealthCardModule, + redeemModule, + prescriptionModule, + profilesModule, + protocolModule, + taskModule, + settingsModule, + vauModule, + cardUnlockModule, + pkvModule, + authenticationModule, + profileRepositoryModule, + prescriptionRepositoryModule, + protocolRepositoryModule, + pharmacyRepositoryModule, + messageRepositoryModule, + taskRepositoryModule, + // mocked modules + pharmacyMockModule, + allowOverride = true + ) +} + + diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigInformation.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigInformation.kt new file mode 100644 index 00000000..5cc21580 --- /dev/null +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigInformation.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.info + +import android.content.Context +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.runtime.Composable +import de.gematik.ti.erp.app.mock.BuildConfig +import java.util.Locale + +private const val DARK_THEME_ON = "an" +private const val DARK_THEME_OFF = "aus" +private const val RELEASE_CANDIDATE = "RC" +private const val SEPARATOR = "-" +private const val SPACE = " " + +class MockBuildConfigInformation : BuildConfigInformation { + + override fun versionName(): String { + BuildConfig.VERSION_NAME.split(RELEASE_CANDIDATE) + .takeIf { + it.size > 1 + }?.let { splits -> + val secondSplit = splits[1].split(SEPARATOR) + if (secondSplit.size > 1) { + // Removes the R from R1.20.23 and makes it 1.20.23 + val tag = splits[0].drop(1) + // Takes a 6z&hj4f58dzf9j0890hfj4938that509z97h and makes it 6z&hj4f58 + val truncatedCommitHash = secondSplit[1].take(9) + // RC-1 or RC-2 + val releaseCandidateNumber = secondSplit[0] + return listOf( + tag, + RELEASE_CANDIDATE, + SEPARATOR, + releaseCandidateNumber, + SEPARATOR, + truncatedCommitHash, + SPACE, + "(${BuildConfig.VERSION_CODE})" + ).joinToString(separator = "") + } + } + return "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})" + } + + override fun versionCode(): String = "${BuildConfig.VERSION_CODE}" + override fun model(): String = "${Build.MANUFACTURER} ${Build.MODEL} (${Build.PRODUCT})" + override fun language(): String = Locale.getDefault().displayName + + @Composable + override fun inDarkTheme(): String = if (isSystemInDarkTheme()) DARK_THEME_ON else DARK_THEME_OFF + override fun nfcInformation(context: Context): String = "nicht vorhanden" +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigurationModule.kt similarity index 77% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt rename to app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigurationModule.kt index 8ef9b496..5eeee5bc 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/info/MockBuildConfigurationModule.kt @@ -16,12 +16,12 @@ * */ -package de.gematik.ti.erp.app.attestation.usecase +package de.gematik.ti.erp.app.info import org.kodein.di.DI -import org.kodein.di.bindProvider +import org.kodein.di.bind import org.kodein.di.instance -val integrityModule = DI.Module("integrityModule") { - bindProvider { IntegrityUseCase(instance()) } +val mockBuildConfigurationModule = DI.Module("mockBuildConfigurationModule") { + bind() with instance(MockBuildConfigInformation()) } diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyMockModule.kt similarity index 87% rename from app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt rename to app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyMockModule.kt index 78db223f..b6024e1a 100644 --- a/app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyMockModule.kt @@ -18,12 +18,11 @@ package de.gematik.ti.erp.app.pharmacy -import de.gematik.ti.erp.app.pharmacy.repository.DefaultPharmacyLocalDataSource -import de.gematik.ti.erp.app.pharmacy.repository.PharmacyLocalDataSource import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRemoteDataSource import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import de.gematik.ti.erp.app.pharmacy.repository.ShippingContactRepository import de.gematik.ti.erp.app.pharmacy.usecase.GetOrderStateUseCase +import de.gematik.ti.erp.app.pharmacy.usecase.GetOverviewPharmaciesUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyDirectRedeemUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyMapsUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyOverviewUseCase @@ -33,15 +32,14 @@ import org.kodein.di.DI import org.kodein.di.bindProvider import org.kodein.di.instance -val pharmacyMockModule = DI.Module("pharmacyTestModule") { +val pharmacyMockModule = DI.Module("pharmacyMockModule") { bindProvider { PharmacyRemoteDataSource(instance(), instance()) } - bindProvider { DefaultPharmacyLocalDataSource(instance()) } + bindProvider { PharmacyMockRepository() } bindProvider { ShippingContactRepository(instance(), instance()) } bindProvider { PharmacyDirectRedeemUseCase(instance()) } bindProvider { PharmacyMapsUseCase(instance(), instance(), instance()) } bindProvider { PharmacySearchUseCase(instance(), instance(), instance(), instance(), instance()) } bindProvider { PharmacyOverviewUseCase(instance(), instance()) } bindProvider { GetOrderStateUseCase(instance(), instance(), instance()) } - - bindProvider { PharmacyMockRepository() } + bindProvider { GetOverviewPharmaciesUseCase(instance()) } } diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthority.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthority.kt new file mode 100644 index 00000000..0707084a --- /dev/null +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthority.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pkv + +import de.gematik.ti.erp.app.mock.BuildConfig + +class MockFileProviderAuthority : FileProviderAuthority { + override fun getFilePath(): String { + return "${BuildConfig.APPLICATION_ID}.fileprovider" + } +} diff --git a/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthorityModule.kt b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthorityModule.kt new file mode 100644 index 00000000..fbf165f1 --- /dev/null +++ b/app/android-mock/src/main/java/de/gematik/ti/erp/app/pkv/MockFileProviderAuthorityModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ +package de.gematik.ti.erp.app.pkv + +import org.kodein.di.DI +import org.kodein.di.bind +import org.kodein.di.instance + +val mockFileProviderAuthorityModule = DI.Module("mockFileProviderAuthorityModule") { + bind() with instance(MockFileProviderAuthority()) +} diff --git a/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher.xml index 5d5c99d6..c456ce03 100644 --- a/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +++ b/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml index 5d5c99d6..c456ce03 100644 --- a/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +++ b/app/android-mock/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -1,5 +1,5 @@ - + \ No newline at end of file diff --git a/app/android/build.gradle.kts b/app/android/build.gradle.kts index dedd7fa9..fec6660e 100644 --- a/app/android/build.gradle.kts +++ b/app/android/build.gradle.kts @@ -33,10 +33,6 @@ afterEvaluate { } } -tasks.named("preBuild") { - dependsOn(":ktlint", ":detekt") -} - licenseReport { generateCsvReport = false generateHtmlReport = false @@ -126,6 +122,17 @@ android { } } } + create("minifiedDebug") { + initWith(debug) + applicationIdSuffix = ".debug" + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + resValue("string", "app_label", "E-Rezept DebugRelease") + } } flavorDimensions += listOf("version") productFlavors { diff --git a/app/android/proguard-rules.pro b/app/android/proguard-rules.pro index d10b8ab7..0a860ee8 100644 --- a/app/android/proguard-rules.pro +++ b/app/android/proguard-rules.pro @@ -116,6 +116,8 @@ -keepclasseswithmembers class java.lang.reflect.** { *; } -keepclasseswithmembers class java.lang.Class +-keepclasseswithmembers class de.gematik.ti.erp.app.base.BaseActivity + # https://github.com/square/retrofit/issues/3751 # Keep generic signature of Call, Response (R8 full mode strips signatures from non-kept items). -keep,allowobfuscation,allowshrinking interface retrofit2.Call diff --git a/app/android/src/androidTest/java/de/gematik/ti/erp/app/test/test/compose/EditableTextFieldTest.kt b/app/android/src/androidTest/java/de/gematik/ti/erp/app/test/test/compose/EditableTextFieldTest.kt new file mode 100644 index 00000000..1e1520a9 --- /dev/null +++ b/app/android/src/androidTest/java/de/gematik/ti/erp/app/test/test/compose/EditableTextFieldTest.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.test.test.compose + +import androidx.compose.ui.test.assertHasClickAction +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.junit4.createComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.compose.ui.test.onNodeWithText +import androidx.compose.ui.test.performClick +import androidx.compose.ui.test.performTextClearance +import androidx.compose.ui.test.performTextReplacement +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.utils.compose.EditableTextField +import de.gematik.ti.erp.app.utils.compose.ErrorTextTag +import io.github.aakira.napier.Napier +import org.junit.Rule +import org.junit.Test + +class EditableTextFieldTest { + + @get:Rule + val composeTestRule = createComposeRule() + + @Test + fun testEditableTextField() { + val text = "some random text" + val newText = "some new text" + + composeTestRule.setContent { + AppTheme { + EditableTextField( + text = text, + textMinLength = 20, + onDoneClicked = { + Napier.d { "text is $it" } + } + ) + } + } + + // test existing text + composeTestRule.onNodeWithText(text).assertIsDisplayed() + composeTestRule.onNodeWithText(text).performClick() + composeTestRule.onNodeWithText(text).assertHasClickAction() + + // test text change + composeTestRule.onNodeWithText(text).performTextReplacement(newText) + composeTestRule.onNodeWithText(newText).assertIsDisplayed() + + // test showing error text + composeTestRule.onNodeWithText(newText).performTextClearance() + composeTestRule.onNodeWithTag(ErrorTextTag).assertIsDisplayed() + } +} diff --git a/app/android/src/main/java/de/gematik/ti/erp/app/DefaultErezeptApp.kt b/app/android/src/main/java/de/gematik/ti/erp/app/DefaultErezeptApp.kt index f21c6cdf..80e72a1b 100644 --- a/app/android/src/main/java/de/gematik/ti/erp/app/DefaultErezeptApp.kt +++ b/app/android/src/main/java/de/gematik/ti/erp/app/DefaultErezeptApp.kt @@ -16,6 +16,8 @@ * */ +@file:Suppress("MagicNumber") + package de.gematik.ti.erp.app import androidx.lifecycle.ProcessLifecycleOwner @@ -23,7 +25,8 @@ import com.contentsquare.android.Contentsquare import com.tom_roush.pdfbox.android.PDFBoxResourceLoader import de.gematik.ti.erp.app.di.appModules import de.gematik.ti.erp.app.di.featureModule -import de.gematik.ti.erp.app.userauthentication.ui.AuthenticationUseCase +import de.gematik.ti.erp.app.userauthentication.observer.InactivityTimeoutObserver +import de.gematik.ti.erp.app.userauthentication.observer.ProcessLifecycleObserver import io.github.aakira.napier.DebugAntilog import io.github.aakira.napier.Napier import org.kodein.di.DI @@ -38,11 +41,12 @@ class DefaultErezeptApp : ErezeptApp(), DIAware { import(androidXModule(this@DefaultErezeptApp)) importAll(appModules) importAll(featureModule, allowOverride = true) - bindSingleton { AuthenticationUseCase(instance()) } + bindSingleton { InactivityTimeoutObserver(instance(), instance()) } + bindSingleton { ProcessLifecycleObserver(ProcessLifecycleOwner, instance()) } bindSingleton { VisibleDebugTree() } } - private val authUseCase: AuthenticationUseCase by instance() + private val processLifecycleObserver: ProcessLifecycleObserver by instance() private val visibleDebugTree: VisibleDebugTree by instance() @@ -53,10 +57,10 @@ class DefaultErezeptApp : ErezeptApp(), DIAware { Napier.base(visibleDebugTree) } - ProcessLifecycleOwner.get().lifecycle.apply { - addObserver(authUseCase) - } + processLifecycleObserver.observeForInactivity() + PDFBoxResourceLoader.init(this) + Contentsquare.start(this) } } diff --git a/app/android/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt b/app/android/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt index 3f653a7e..a4616382 100644 --- a/app/android/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt +++ b/app/android/src/main/java/de/gematik/ti/erp/app/di/AppModules.kt @@ -76,7 +76,7 @@ val appModules = DI.Module("appModules") { bindProvider { AnalyticsUseCase(instance()) } - bindSingleton { Analytics(instance(), instance(ApplicationPreferencesTag), instance()) } + bindSingleton { Analytics(instance(), instance(), instance(), instance()) } importAll( buildConfigInformationModule, diff --git a/app/android/src/main/java/de/gematik/ti/erp/app/di/ModuleNames.kt b/app/android/src/main/java/de/gematik/ti/erp/app/di/ModuleNames.kt index 99db0cbd..9f25f6ee 100644 --- a/app/android/src/main/java/de/gematik/ti/erp/app/di/ModuleNames.kt +++ b/app/android/src/main/java/de/gematik/ti/erp/app/di/ModuleNames.kt @@ -19,9 +19,6 @@ package de.gematik.ti.erp.app.di object ModuleNames { - const val cardWallModule = "cardWallModule" - const val integrityModule = "integrityModule" - const val networkModule = "networkModule" - const val pharmacyModule = "pharmacyModule" const val buildConfigInformationModule = "buildConfigInformationModule" + const val fileProviderAuthorityModule = "fileProviderAuthorityModule" } diff --git a/app/android/src/main/java/de/gematik/ti/erp/app/pkv/FileProviderAuthorityModule.kt b/app/android/src/main/java/de/gematik/ti/erp/app/pkv/FileProviderAuthorityModule.kt index deca5d8a..3977bc00 100644 --- a/app/android/src/main/java/de/gematik/ti/erp/app/pkv/FileProviderAuthorityModule.kt +++ b/app/android/src/main/java/de/gematik/ti/erp/app/pkv/FileProviderAuthorityModule.kt @@ -18,10 +18,11 @@ package de.gematik.ti.erp.app.pkv +import de.gematik.ti.erp.app.di.ModuleNames import org.kodein.di.DI import org.kodein.di.bind import org.kodein.di.instance -val fileProviderAuthorityModule = DI.Module("fileProviderAuthorityModule") { +val fileProviderAuthorityModule = DI.Module(ModuleNames.fileProviderAuthorityModule) { bind() with instance(DefaultFileProviderAuthority()) } diff --git a/app/android/src/main/res/raw/analytics_identifier.json b/app/android/src/main/res/raw/analytics_identifier.json deleted file mode 100644 index 9518c43c..00000000 --- a/app/android/src/main/res/raw/analytics_identifier.json +++ /dev/null @@ -1,487 +0,0 @@ -[ - { - "main": { - "name": "main" - } - }, - { - "main_createProfile": { - "name": "main:createProfile" - } - }, - { - "main_editProfilePicture": { - "name": "main:editProfilePicture" - } - }, - { - "main_editName": { - "name": "main:editName" - } - }, - { - "main_scanner": { - "name": "main:scanner" - } - }, - { - "main_deviceSecurity": { - "name": "main:deviceSecurity" - } - }, - { - "main_integrityWarning": { - "name": "main:integrityWarning" - } - }, - { - "main_prescriptionArchive": { - "name": "main:prescriptionArchive" - } - }, - { - "main_welcomeDrawer": { - "name": "main:welcomeDrawer" - } - }, - { - "prescriptionDetail": { - "name": "prescriptionDetail" - } - }, - { - "prescriptionDetail_medication": { - "name": "prescriptionDetail:medication" - } - }, - { - "prescriptionDetail_patient": { - "name": "prescriptionDetail:patient" - } - }, - { - "prescriptionDetail_practitioner": { - "name": "prescriptionDetail:practitioner" - } - }, - { - "prescriptionDetail_organization": { - "name": "prescriptionDetail:organization" - } - }, - { - "prescriptionDetail_accidentInfo": { - "name": "prescriptionDetail:accidentInfo" - } - }, - { - "prescriptionDetail_technicalInfo": { - "name": "prescriptionDetail:technicalInfo" - } - }, - { - "prescriptionDetail_sharePrescription": { - "name": "prescriptionDetail:sharePrescription" - } - }, - { - "prescriptionDetail_directAssignmentInfo": { - "name": "prescriptionDetail:directAssignmentInfo" - } - }, - { - "prescriptionDetail_substitutionInfo": { - "name": "prescriptionDetail:substitutionInfo" - } - }, - { - "prescriptionDetail_errorInfo": { - "name": "prescriptionDetail:errorInfo" - } - }, - { - "prescriptionDetail_prescriptionValidityInfo": { - "name": "prescriptionDetail:prescriptionValidityInfo" - } - }, - { - "prescriptionDetail_scannedPrescriptionInfo": { - "name": "prescriptionDetail:scannedPrescriptionInfo" - } - }, - { - "prescriptionDetail_coPaymentInfo": { - "name": "prescriptionDetail:coPaymentInfo" - } - }, - { - "prescriptionDetail_emergencyServiceFeeInfo": { - "name": "prescriptionDetail:emergencyServiceFeeInfo" - } - }, - { - "prescriptionDetail_medicationOverview": { - "name": "prescriptionDetail:medicationOverview" - } - }, - { - "prescriptionDetail_medication_ingredients": { - "name": "prescriptionDetail:medication_ingredients" - } - }, - { - "redeem_methodSelection": { - "name": "redeem:methodSelection" - } - }, - { - "redeem_prescriptionAllOrSelection": { - "name": "redeem:prescriptionAllOrSelection" - } - }, - { - "redeem_prescriptionChooseSubset": { - "name": "redeem:prescriptionChooseSubset" - } - }, - { - "redeem_matrixCode": { - "name": "redeem:matrixCode" - } - }, - { - "redeem_viaAVS": { - "name": "redeem:viaAVS" - } - }, - { - "redeem_viaTI": { - "name": "redeem:viaTI" - } - }, - { - "redeem_success": { - "name": "redeem:success" - } - }, - { - "redeem_editContactInformation": { - "name": "redeem:editContactInformation" - } - }, - { - "pharmacySearch": { - "name": "pharmacySearch" - } - }, - { - "pharmacySearch_detail": { - "name": "pharmacySearch:detail" - } - }, - { - "pharmacySearch_filter": { - "name": "pharmacySearch:filter" - } - }, - { - "pharmacySearch_map": { - "name": "pharmacySearch:map" - } - }, - { - "pharmacySearch_selectedPharmacy": { - "name": "pharmacySearch:selectedPharmacy" - } - }, - { - "cardWall": { - "name": "cardWall" - } - }, - { - "cardWall_introduction": { - "name": "cardWall:welcome" - } - }, - { - "cardWall_notCapable": { - "name": "cardWall:notCapable" - } - }, - { - "cardWall_CAN": { - "name": "cardWall:CAN" - } - }, - { - "cardWall_PIN": { - "name": "cardWall:PIN" - } - }, - { - "cardWall_scanCAN": { - "name": "cardWall:scanCAN" - } - }, - { - "cardWall_saveLogin": { - "name": "cardWall:saveCredentials:initial" - } - }, - { - "cardWall_saveLoginSecurityInfo": { - "name": "cardWall:saveCredentials:information" - } - }, - { - "cardWall_readCard": { - "name": "cardWall:connect" - } - }, - { - "cardWall_extAuth": { - "name": "cardWall:extAuth" - } - }, - { - "cardWall_extAuthConfirm": { - "name": "cardWall:extAuthConfirm" - } - }, - { - "troubleShooting": { - "name": "troubleShooting" - } - }, - { - "troubleShooting_readCardHelp1": { - "name": "troubleShooting:readCardHelp1" - } - }, - { - "troubleShooting_readCardHelp2": { - "name": "troubleShooting:readCardHelp2" - } - }, - { - "troubleShooting_readCardHelp3": { - "name": "troubleShooting:readCardHelp3" - } - }, - { - "contactInsuranceCompany": { - "name": "contactInsuranceCompany" - } - }, - { - "contactInsuranceCompany_selectKK": { - "name": "contactInsuranceCompany:selectKK" - } - }, - { - "contactInsuranceCompany_selectReason": { - "name": "contactInsuranceCompany:selectReason" - } - }, - { - "contactInsuranceCompany_selectMethod": { - "name": "contactInsuranceCompany:selectMethod" - } - }, - { - "orders": { - "name": "orders" - } - }, - { - "orders_detail": { - "name": "orders:detail" - } - }, - { - "orders_pickupCode": { - "name": "orders:pickupCode" - } - }, - { - "alert": { - "name": "General Alert Dialog" - } - }, - { - "errorAlert": { - "name": "Error Alert" - } - }, - { - "healthCardPassword_forgotPin": { - "name": "healthCardPassword:forgotPin" - } - }, - { - "healthCardPassword_setCustomPin": { - "name": "healthCardPassword:setCustomPin" - } - }, - { - "healthCardPassword_unlockCard": { - "name": "healthCardPassword:unlockCard" - } - }, - { - "healthCardPassword_introduction": { - "name": "healthCardPassword:introduction" - } - }, - { - "healthCardPassword_can": { - "name": "healthCardPassword:can" - } - }, - { - "healthCardPassword_puk": { - "name": "healthCardPassword:puk" - } - }, - { - "healthCardPassword_oldPin": { - "name": "healthCardPassword:oldPin" - } - }, - { - "healthCardPassword_pin": { - "name": "healthCardPassword:pin" - } - }, - { - "healthCardPassword_readCard": { - "name": "healthCardPassword:readCard" - } - }, - { - "healthCardPassword_scanner": { - "name": "healthCardPassword:scanner" - } - }, - { - "settings": { - "name": "settings" - } - }, - { - "settings_accessibility": { - "name": "settings:accessibility" - } - }, - { - "settings_authenticationMethods": { - "name": "settings:authenticationMethods" - } - }, - { - "settings_authenticationMethods_setAppPassword": { - "name": "settings:authenticationMethods:setAppPassword" - } - }, - { - "settings_productImprovements": { - "name": "settings:productImprovements" - } - }, - { - "settings_productImprovements_complyTracking": { - "name": "settings:productImprovements:complyTracking" - } - }, - { - "settings_legalNotice": { - "name": "settings:legalNotice" - } - }, - { - "settings_dataProtection": { - "name": "settings:dataProtection" - } - }, - { - "settings_openSourceLicence": { - "name": "settings:openSourceLicence" - } - }, - { - "settings_additionalLicence": { - "name": "settings:additionalLicence" - } - }, - { - "settings_termsOfUse": { - "name": "settings:termsOfUse" - } - }, - { - "profile": { - "name": "profile" - } - }, - { - "profile_editPicture": { - "name": "profile:editPicture" - } - }, - { - "profile_editPicture_imageCropper": { - "name": "profile:editPicture:imageCropper" - } - }, - { - "settings_newProfile": { - "name": "settings:newProfile" - } - }, - { - "profile_token": { - "name": "profile:token" - } - }, - { - "profile_registeredDevices": { - "name": "profile:registeredDevices" - } - }, - { - "profile_auditEvents": { - "name": "profile:auditEvents" - } - }, - { - "chargeItem_list": { - "name": "chargeItem:list" - } - }, - { - "chargeItem_details": { - "name": "chargeItem:details" - } - }, - { - "chargeItem_details_expanded": { - "name": "chargeItem:details:expanded" - } - }, - { - "chargeItem_share": { - "name": "chargeItem:share" - } - }, - { - "mlKit": { - "name": "mlKit" - } - }, - { - "mlKit_information": { - "name": "mlKit:information" - } - } -] diff --git a/app/android/src/main/res/raw/animation_courier.webm b/app/android/src/main/res/raw/animation_courier.webm deleted file mode 100644 index 449c50b104dced2074cf3aace4a49302cfe23707..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 219085 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ℜgG13Nx+DE0<_NwvPNMzAyyoa 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

w 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�Khni+X9@Hca12~nzKdzJfbp0U2v8RV`I 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 z%0D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�K)u+IfJe(xx@WJyhFML0S6Eo$;#k ztZ(~caH=}};k$NXb>tk?7X%513hMrRA)pnWonkKzYJJC~Z$MGk@2n#I(RxK*%R(Oa zg{>TOmIr0lBwX2J%Y)X;%JBl{SWLRzRRh5XV+{tJ?qdXX+m%(F12VdA0xf2^k0zRo zEnL2pYt;^&YpAwoCh{h<`p0nVxnfbzCLL{l9|q$7pOQ^By?DMP=5Ovr;-WaCs3T*V zzrMZhiKh&xAdKWrb8@rXEsn?PUaNMWN)ZC9??y(Su>P5Z zxIpxs#~ZK&+7)L@u@+alBXjwVU%6Y^BQ%s%G4hRcvq`u3dpk;m4Bw1DA0(O^C~S$7 ztRAJ12{{e7e&YICnM7^B0*QJDQD*^X| zvM95uvB4ZX`hHW&0ol<$g4HU!VPO9$w@TI^tV%*vXycSN z%h-1RQ-8&ni#GSLw!9^V;V!7ZUm$VyS`PQ0utA=pVBvghb;~;??ea(qY*p_dt#&Aq z_@!OeZ5M9%cU>3O-~=7~oWAkShP{6Ik?Br-i3QQW)pD&xqrDICiO`!=BX$M#=*0fE zolH#<7i-kDetti96pD_0MpgM)=yJ^>k>vm=)c++3{ttboGXEdQ{@+m6W||lL<}Ltn z7fPr6Gp2Mcn|?w6qdvya!<5s&PPz;I!&Q)xX>ab+iR?oG`Skv^j9Fw0#mddktkLTk zncWj9!Xh6o6xvgde4l33{8NU?x2tB9ANS2$0xHy+&tgCqug_`<8A4~w`=|#c%-PP} zAvS&*PU7Hqss9Kk(SFuIHGX$R@F)^zfzsCA4s6$1mn(cKljSiw9CKZ z%oD;0ql)=!gCD6zS||sL*sE ztp{6#6wLDeQ8ZYD=wUOyR_}ZA+OX)l<#K6cZz_|`O`=&s4iOV2i=Ns8Y=(z?vx`xk z&~$shq;ZC$cDn?{hAk^i17{`Oxy^N^4Lvdj@{vsMPRl%;Q{7qhYMmes!*}TxUchX7 z@JBR=hqV1GKR`-sU*nA^kO+I03eTW1kIf827plPfw7YDRt8Tvj@MRftI8!8>R#?s&BYAH;>_!SwtMU4fFr zsN)_2CUe6-P?!$Pe*~SEZ%v>$YaiE}R3FhDaal%DTXGS4F z%cjQ%rS>CU>*mf{9N&*7zn6n=S-rX|xj1pb6DD406c;HjN0>n`H-%XwGCw&=SD-4AwJ zTn{>RKJd#+YtPX$$6_0z_k@jBPk-kj6YLHamny-)mTDg%A*5}06kEUW!xO8~3S#~B zWIg~yMC(}3(wf6uH`y;aevr|2z?Ri%-RRKh;|v|OIeof^*a5pm0z>a zij(?gxU0Zbg5LCiWt3xnQa^%9RcIfP!QpBTo#Nf+OzmG(5TYA;8c=hkrzwRnLfP84Qy%TK}7a?cK(Zf4eW zGw?^HKX`|1=L?^Rj4}ZiPSPtH32rNB3rHU+^Hb22;JjtA9u7uc?=h6tjT23pt=rmnHsXUlirRX+t?w(8whRhHCQ{Bn-Kq*T1!oOfPwEd^CU4XM zsU_FK{s-s!M81iSP()PJQ6SIuZ+Xwyq1?k_4oZ3DO7)1QDT4ZyJ55e;UFfoTZ%%sx z(qOx9G#g$gZ?9N4)$#%Ykg5!G_;61GQ4+#9VG?)ikzmg>DV{0ED`c6t1G0TrKxpF8 z%vf(MzRzcDz;tk`!CaS+2l?QoOxGA)9sk(k@DZSY`( zw=sm)|M4jtUUsoQ_R$?iw!2pPs-s7(l&`Sg?7_Bvaf$)aIfy=IATB51B6-9A7q23( z{>rrKf|4va)S#fCJDHK0uGuu^*yo9%+tU}!zxQ!*I6c%m{db7NYa1$b=QS|kTVcN{ zwgr&1aR|_j7__-`5nCgxt{$)NgJ^cL5Y$eN=|AehK;f?WinHVo3)(pm`5wHRWB2*1 z`+>xT&&(n$r2r&-f#%Gn_TcGt0nX~7CJ=y>1{gw)0U-5~QMynev1?4Px6V z^Wdy%sP`M%`4~o-Q)Q=eTHvKhCrGx$gKs-w9@_tmd(C4}gQ z1Iw8rZhIij?2^6#?_CmEM(^^(r zy`TE0J~yhkIx8FMndZ_9X`bTVbW>{_MNJ>m_Os#~tBRTeaSe4d_VwbGagT#qYX3?| z6OA%cBdH3a899V578Aqf*R;qR3Pe?eeN~iamI~MODB=91aBqU*TkF0_J2Cn_z)KU- zDPFyoR;YIdyg&h^qpmY4gk{4swj5pL%{LV-MnZsj;&W8JFc9h^;y)dzsQ@Uo|BbC5 zsuat0twSnxLlx|-`9-%DQgw_8uCt@P4y*USctf?b-qdr}xHVz$_9SeL;p5IC{_in? zopM$&eEPGn72~TTO4IBfM-+&<7ftuxKUDhy_$kq!6By4H9%Y}49hJ1n~3415I*!#ayRM}K4dR+Tswof0$V=25FgJj zr>Hfa(bmub+M$6aEqmM3dcXNA9wG%L1vlI3g#~w%OjqEl_Z#%6ABZX4`6DVPSK-(F zSw4PRoX;*JoeL&Vj5{QHo{+t#gg3w|16r z95k2GQF~U@+tt+*vaAGVkFD#YBT+>394Xv^Qp~|}YGxe0p!+}CVIqJEK~O{di{+`? zfuWj8Lir-y#|0aXnL%w!_up{Iy7<=>h{pYH5>93R-idlY;pW8fDqlut0{u&M$iayg zRVKS%coa|Xe4iFX+GU-g-UJ~B2+9|N% z*)Gu3IdywTu=lVzI3GN8^s;}H*B50?=P9Ab`=}4Zn!b04JQl(e;yIt)HjA`Es-XRQ z-UNGl5_W+^5t$*IJXYy!i>4!pO*S-q&;yjD(Pr_8B7; zXaEOTz_F|R#kADj`u9Q6{1C>R0vy_oaZM_gWo;4{r%W8Zx+v)Wz()+)Rvr*} zD+Xj)SkKQ@6kysZiCd>zIC=W`o%yWHLkoU^$wa8in+OnDfmTX`s07?5)r zCitlmco*j|KtmQV+TRXA28i=j*6nVBSH|&8S`E8-5$M#JAyH2S!NY(&u_kj;?+MH)-6sNksJx9l21;iU)p=Fz*`YdHQ zR1EeyhA9k}H>L%XeBjK3D<#(}Qj3s?(S12oWfR=h42qfqt4{Dp_!2Ab#uEoNlyXF# zb6CUh-paa(;Ahl-mmRX)H=*b7`$_)#HE?xFk$h4FtCo}RsP4b&bn2+nfnCPAC2ix- ziY}DI`yNH2u<7yBeh7$`1k4Hl+o5v#@@PR>aGjAwQmvZA*70dsCN<+x=r7Nu7_Kw| z_wMjI2g}W$JkHVIglA<~39A|#?=4ad;|FNLDk62qzxUosR=wxCbM@`vQ})B-fFTsA z00#clw*|l!0?{arC85~y{%*=zI{2_W34Zn@mBDlp+FT%>)x@j8peAs4;F^ykoX}y& zTBz&$>mKI57$s{mD(&#d;oKgg8{Dq6)Ra74t%TpsDnYe7)W&X*8nJc&l5_~T4=gLQ zhGt5noM|nE45Hbn+CcASIGXowVTF2uI^>MoQi;d0HNd`i|dJ{YR+TG^U;aEKN}-(3M4(h3XExg8e{kZ@Y`O~vVSnG%9M zt0L+YSeJ>5e!ct9TeYh%Ok*GZ{$dbQ!)X~mm2Ax^-p3unIc3v+DFT@~GutM;A&Y6s z361fsgI$RqWLi28y$vdM&8mk5Ez&SPp2|h`!<61_Wf)R@xvPCoPXDV(cBafci6pHM zu14T`(1VyxC;Y?`g)fGM!gD%!vLAQzp>P%P2)cd%>A z(5nOLbn@wU>Hwd>gj6Ck(K}2x>T1Boh;(Wp$F-?<7 z{kcS~ggjHoCdDm_yPN3&qe%Hs(HnjeJquA7yZXq@zYyx*#}3Ll2+Q2r**7^d6sm@0 z+&>~9Mc6t{<6(&r6sCw2VuMt?U2B}$_#P8C2jN_*MU9P0ZhYNC+uFx-r@|RXec+VO zv$c==&B^A>V7*_Fg4&_eh%dz@l)RRBf@V2;R|9wZzydtqcGMDo&y%L@LMBA(!xM$v zlYg!U1UsDH^_z0gPKv2t_$sFz>~ysuyur+MG=W3NO>-x{maL-dD;c(3SGG0-+gM89 zpl9QY0GMK)${3dMS}6e{qLlQXn|~7_#z6v@WO-2Mw!9%IfxJ?nz>FRf=^x>)6NJ7k zK~$WR94^ZF^xMo7TmEQqK&`VEzpcg1}E`u&zZ zN-u+;6Ose(j4oELZhKrQYh3KRV9v#@OTz;hD3~K25bB9?;iseU5X)wBezRj+?n^R0*ksTpT-#P zkz{ux;k8_XmlNBy2yHZYpFF|p)-EnCBmWm5DQNvL9cp-wznuVzL@py@=VR?E6%HYQ z1;cuXCCV8#`mxUeGWNAxGF2t?bni-l>^6O)S5dwr1$x@oTu?{RW({IeU3LIEF)HaH zOoJ@Ezbhy#p=(K$LXVrzvEF2Zs0|Z8oi2Ill~RY#wpF_>lY`|K*gY%QSkQa#kNjs@ zP%1`DPdty+@%3iKK>Y$|T4UZqcY`xKik|{+N)B-MO#vZMVp&xEdr4U0_bzxvdrXgp z1tXYEzu)({NtXs2z)d@4?$+FV_c9|w4!#k!9cu0C)|gA=Ug`I+zO6&R{E7nZPB|;R zQ}MVSt3xW$F?DW}^)C@;%)bWrTB(6R(~v3b1X%;KNB9&HJEUcOiPoqYH7Ti&!-nz# zV}|#q_kS;SlofxC@lS};BPqM8)_A$dfDr@^P8<5%Lc6T!%{){ffz;QO8QAI{Ui{0}b20)KJu@c+ zRgxKFizTS?Gl4Uir4X@_%>I7rOQiy234)?Acr~6^FZUHAIK4npnx|0v35(*nTFrJ# zdQ1Dsl@{F9R=R-m;DifI`xLrmXDEb1c*E`wi6U#&J7`*QcLR-^6eh5V_^NZJXZ{R&t3GeE$n@&{VuqbL`G{_XX|OMM zh6Ti%sLP@19FhAad)c*8$W>lu=D1yo{;AWdhJHbe8bR%l2pr)Z8Ee|xb>TPXZ`$kP zBm~K{LSh8fbxd4s1K`xri@UVj`~EdkOB^T5Cr4KxR~L*jt| zro#MW^Jr1^;iOk?yK3*} zn+3f|J0p{GSl5qfRqPV6pW;6xFsoxDbT>xDB!n>ebS)dmHB#H*ibNFypxpnbo>BVY z3LqSmRd)U>QhwyBB=A?`Z~yBLg0oZ7O14jZ!$;KY^ZyZ)j``Wg`-ROv^tyJ@-_Wle zvJSekcJlXxH?E*JJO$<+JhKzQ$h?zNE<_@t3Uqe<6XSKeMYNhTMbSWL6*t3JaH8ZI zinLElE5b{Beb&43SQBM-FVm(%iEa~!Pp$tKd!>&;d`%8rtWYjFyPeuA-qCVe_FSH! zcY=foO9%u3NS}u8*9K3Layd_)W|C0E#i8SpEDIi^$<7!c92d=i3j$EIqi;+qj|J9~LL^McF4 zh-nvv47#{bTo0AxQre|!&)(?p=04IMJ8|!rg&%Lz+d7*9ZhHLN{~DcU7q;4RPY3M5 zP)&T7>Q*e*BHof!KHkyau1_B$saj@2707$WGxWoo%q;lfdfu0mo@@vhrlriOk%xX7 za7$oo_%g8X_JNt%(6U+|eyoR?l!TZ;gPYUM^E9gpX;d}Ah`nz=*v z5cEg4wj{(T;g<#f`a8q$eeUF^|M+V@ns2#`pO(0IyJW+c(7`YD01Vc(bcq&X@3svD z_Pg-fYW^G-OapO&Avg#HeR}lfMHWyo5wHuUb&}ki#A0r^(#V!4@(;)~TkYw{1=m&Z zsF(=JyJzo0p2J*#t-jJUZ5W^CQS1KByVF@1Pgz^J$m|OukafT@%Nh~aAq1bqJsX*{{}~J zXOjY84W712h)Yn}Aa!7PFqdEf51JT(e6qFI%a!kmso4Vd;H>$QZA&C-Oca8YQMQ;N z@LCYZb5-@MO7}MlK8HXvTCJPHwR<~mPUd#yUQ~qFbkS@oC@hlOZR}RW9olQPiUfsQjYHU*Y?sCo1h-+<(v6rc1rH)0W<-MUNthSL|)!1Sz{ zYYGO7g$(kQZ7VjI3W4I?Np2P{q^msMO>F25FIv<%>AZ`J@_85&zZQw3 z20*3%Z%X<3uK?+w=-x{5zY=)=|C|E#Uk(ve0ge9A;YzSmG6*z?IHe~GeGkmq(5n>D zAc9DZ+U-2g>zvn{TQYSmEgy#4koYGzA{@IQ(NUi@Y4S3f>y+gQbPo=L`uCt;Nda&u zBqL9W$at>Et`|b|z9qzi`D?~r@Z*lSo^Qk&taVRMASH; z;=58)R@d&29RJItC3{Qrc#^FE%ZsxGyv0r5t6Gt^=$C3X|Woam^wpt(tRgJb%xwFW6 z%Ju8#!m=xov<>(^RX8$$+6dKmF-eA5e+}Rs5YS@Xfk<)q5!L`}>O!6nh>}lz@x#&A zq6EQ45+M5GFywaRe=&%4UiF`lt*p?_^` zM1N%p%{1~o@#;JGJiHM%xnq|0RdwNhR!26EG|kD^?WsF|3mFys5c#+Zeu^}!wo^^E zTB0N_Wa(uq0n^ipp#11cec;HB52YQqG>7AHmUO69%iWdM|Hed8tWKC}rtmZOf}-&b zJLEyxB|D+#&(8p5sqHQr7P^=llax0d+WD!%e!nV$9{E~jdNVMY6ee?stGBRuH-6jd7) zWWC0%wn_5a?Fd)}z^^2FUNXqgY>iJ$)5G(yvh>JlXdy9u%R%a}cVgsJW0yqF%-iDc zA$Sgopkmg6+?)*Wr!8p=ds-^!R_===ya_*iEl_eeTQ0Zx+hE z{mlx}hO9Rvf;jm`jB9)y4kGU0t~cO0fv-4BQcv7P*4+qP|cV%xTDy!`LIYrXfrb#Tj*=GSN(WU82{Uc^ZXj*~rqV!bmct79Ius&4mhrCg=UAWtt`q zp%C4OUb}YS@;?g9Q$9K~SIwlZ0Ht=2Hh?7slUPG$WMU`~{R4n%``=T+;D2ZhXAnSW zD7`=M^8X7pQEU{f8o3aNqmts4d=VKwbtC@+oY6MQD)Y8nLux!EpTi|28>K#5nxBK* zQ7g&1hxytDT%^}Mp{lH>#Qz}D$V#<6A^A_Hp|T37yy^oF>RaDy|G7t=w-EMuQAy?F zH5@0=Sry~W@wWuB`dMR$Q6+*>zby9FLBTK0cFxy7skF^s)it2py8RAkue{Ts9YTHG z>eplY?QP9+q(!zC!%$!H)Ni<(u_AnhgeF?OMN^n!kWeaNQm=-3Hsn}OADS;aq=P;# zl7b;+D?fG9b*5k|dBo;DkoR^%3M(2);F=!+EU+Q<6!9WL01DZtrTc+3)is%)<^ZM= z7mG?PgT^h%c~BCw#3+c& zFf)$KOmy6EG4LUWSg&Zk!yiuRdf6&@g@Nz?%d28Y?WB~5XdG!GL-sp&xA}zxIr?Ij z@%MBc?POz$bu+nKX6fM^&?+(E=E{P<#KcxUhhc$MY8XiE6xT`*>n?b^D@B{D?AeV7 zKj2l(R%94O{x@`?9^w(91~bd7$@%_zj^n&zRxls1f&7+I-_5U?32H)fwLCY4MBv|R zS;N4$G(-(O3Oes2-bX_nfAbqq?o!}uMvQSjJ>6Vc+UZZ(cHkx%jNC*$t!nt|4Rf__ z=0Tym|6sZm`Edggc>exe7oZ-RlmNQaavQW`+Sc(z#pR3-o7FmJ1>xh-LiZ4+@B;xw zd*d#GIDg)OFu(^h)!zVa0vYVir6A*1n`LBr;G7AbBZjvL*f=8BVodGyi#8w+LXqn; zFo7|?*M@fEy;O0BDRMJ}|Ff2Z+wjUOmFU^9g?V8@kA|j=Hc`O&w5UC!nI7}(gA^Uo zjIh8i{DH=RA@JYsI9W&cyTIIrFEwBy&idI0Zna$EV1^>8onqyIVQflI;R0NdXC>&pT2o-n*Lo|(`QqilcqktZoig4Talh6jK(ecuHz zFB%o}iiR_>6!{HR4!nPh?ni6#JWDQ0{O?run-$G}Z!19s8wUc2eD*s0(mU`&ICGli zOvCxM1l?P%?VF;{t3Z^|&TN5&_xqLmQMH{cLRVhQK{SSllu3OkMt>yYSo2uR$&`T8 z8|qmz^8*ZQ+EY;u^}vA_qzFjVt9vSye=&obc#h{|YO?X@MHL7#K#kpPI3`I*vBr`8S`z@AiLf7)Uv)e12;h*R|_Y4;+}ZI?;bd4w)K35G{=q3^K)h>EuxWAHw#}5jrpQaQLMK=!O-f z8BkxLL!x#^s*Qm?p~erqKt1sUg=O3RQb$*HK}g-tw(j*lAc^29N~zPl(X&Du@1r`r zfF^`)efZb8gMVn3s7Q0uEx5JZ92#~h=R{IRDmQg0BZgJK=zO7Exg_7CmvAc3=7@2 z;(uEz5R8pDVF%5_(+N)OkA?6b+LpL>^Nm!s@y%oS!Q5p(nA@0V`Cr^zPaGKA2g|ws zJTk)OR+0B>R{_?z#WkKyml)o`= zBtU8%p}#jBm_&vK>QaBBsr#0EzkY9R6YCOul8fI}8_lO8hb7K&tP^qQ$D^x3)dCXP?e9*8LxHxrdIgt8W z$!5X9C}AnhnLn_3MgkoAq}e3R@UYb+guj|K?YYVnv$p66w8u~cW+{r?V`13~m`U3b zXKw}OlD1xX8S(4Dps-y1ZnumUwI z`Qy+*S!l#Fa>S?Og8uCFhrUFSFZxjn;AzHxS)S?7751ridfXWp*@X=InnruFSgLjg z5+D?YX>TD^DIZpZ`f2C}fxXgfc+8!l+IpNWk6_L8(FwDjqI!IupIR|MN@KO{-#%7<}%fy?6niafdV)wTNl zWI(aX2o8;}e(0^G5xm1(A}YTG#-=UB=OX*DjF@H&X;+MIfW+a^3PbDjJMr(RcMbS} zA$xF)4jD5~39+PjABM|xM2YuKE;IaGSu^iMHeE{Ms>n1}U^Ojc1*HYd>qT@-z5CXn z=ZzwG+Hrd=h+HjVKxAHg&HZ%`--#{xsC43u;3sw>?3Lu>Uf0iwCcwT67^4diK ztv|cKJ}TR$r63p7WEwtOe&q}nHwBM&!jItwXQ9wZy`dz zY_qgk9G$k6(%a(ZF)k4-1-?+>pdIO5nO_X0eWP9wa-`%V;%HVM7OJ4UBNjqjVFb<6 z{e&(b8i)hBTd4)EyPfxAtvVkOIawo)fsSMopbaLa_s9k5k?Use-8>5ZA3pJgUU&4F zz}=`2Jd0;Od7Rkeq6Rc%mTGR@%#MRI?2R0^f~%`5D6PW`kn7l*A_s+rsFxDeQ{6dd z7*`)s?2hf}pl|aS1ji>^7inxCRq#2SvFob~VdaX(%J9;x#iZ6DX*#2??1<(S5lI!M zkc|y?>}-8zNM4}@u)T=$?VVekU?=#Nd+L=sseA@!*@W+^fdP7VeSpsyeKrClO%6kWpD)V(}_d0t*kms z5ADboU9(44^%QuMJ=1Z)n!UpY7$G+0EmKdprjDrX>-Fz_l1asz#r8-&fYI2devyo8 z`zJ52Q}tY~zOzF>i=ldg+31#f_ms-555)jNzOHQO zU#Ovf+CX5AQWV~vrpE)@V@-}SL`A03n0zF~y_E>|qbAmi-5b|)>q&>;_N@|yArE~& zVB2F57JW=ExD{tk%@5wig%EnG<6n~vt^s%K1?r0ZOa9^IXyB_JE=%`hF(M@iJy_)* zQ$X%OXJXOpxa{>Yo3rkhuZ>Kd{dqGg0%bbm&3E!2QtE5ii1f>R2dpegcSkfIZ*~~{ zq_G)jC#GkU8r>iv+@Lu0HxiqAv3URKuYK-$?yMPbcQP;d_7xq4<8u4VPfG^doO^2* z7|hBhDU!k10bna?047;R1Iz)?KCxsf;$Pi{-krIK@dmtqC%Y~8%6A=jP^PH~gNP`M zzuU3gm^#`OH$Bv%klF52($&2!3b1P|=U{$RsSZPYYAUysm2mGd)H*hX8JzacmtFi{ z5FwMyYB+DvH!&XPBGEk>&P9}$`|DO-n=ke_x;%y+k}P-yAvYDVoBg~u*73sjYT-2e zR4@L%hXoJ&a%qOWgvLcGnB6G&HDJ`-CF44^s@?X2SC^ToIn@uH6+sO!yV3m#j$5Jp z+bj*ZpJz=q{i;eCu=`cb2A>RP2`EHWfMvImA&6&;Ka4c zx7#qm$dVmfNj3tS2J%)dM?m0OJ`F3KBsk^0W%+WA%XN3+II}e(q+jjb$gYO$8KtlENmNq*h1xZ|uJGnlX@bsLO)x&InIVB!a% z9>B^|Mo0*|?%oV!ge*`+K`W-KkE1C~9FmgL%ut}wZ6x!SI4E8Mc*jJ{VIocLnuIG+ z6$$gpjaGz8D(6FlR|~^G!?#P)OZgKdbxiyf->6-zZYZzwa1#(xy*OOZP>aTt1PMNNh>4X2n8H!e;2D3-xj+Z+QK+Io&Q7r6&?&F8~JB~&R z`0W@3T`-;aFVe!5GHrc-`b%(#>>V4il|n$Y-BCx`UUEF|28%aNP+>u1l(r#oe7#l& z^J)CFc#0P+Va1kj3prkD%w4)=G-G3gPx3?@iGe7e@+=MIv@v<_jDH{iL@Zk#V&3Cp z&3j~xunl=_qvLPHF_8k61KhNg8YHHi$?zNOjCoV^OTIM-NUNI^%G-xo>AVW-jomA@ z6tm2i=d*TZ!?KPZihLqV(@7UF`nN8pL zgZY<@$cZ0P#!w`0zn^?wv_b(C%gx8NGK?LOyo|_|O0SfSm5S4JzAR9I$PfVPST`bgZQjL4^ z8R$k#l&q@fH5-V!wDv)`6o#KNSL56tq8TC2o%B97rH2Gv|8pw&IyIvm>EdsTM!>S^ zM1D4gJJkbXJuE#FkOX836@_O8a&K8hnHtbi$M|Qjm?Y_u7a5_M56DDO%};OpmCsJF zW4e@Ufed_>J1Bz0e*P_QC47qb)e&u#?>De*xu%0=5d75R-O1&`GXo*R zq=<%)i}y#fo_o_n|E&O)re3veGCE_FNe&gWZK$)Q({Ane6Lcb4L@rqOk^BDU$p0z5 z4~wVkQ5tMa8Wb1*ZM-+bZMNo)(Jo`;)o*ntKA;~H`)S%YI7+3JWs6%=OU8FL3r`KcjoaYgA;BtmdC=#&AnT z$8R0DzA6O?s)?ixSr&^ywEk{YRP`5Q?t8aH+lKiSP&S9a zy=gIN?Sc z3sQX_xIq&PSr-k)N9Ey7dX+JepGJ*3E(9e=z+p+wPLJP8CL5cdZ;PT)0<)NaNl@~< znZr|f`1V-fr7G*@qV>unvQDhHr8+1|(B(2O1Ubf1EqU+1>^9kO&lYks`EdsYR8j(` z8UzL)C#O|JOt@#n!GE=*siLm)1?N~`Ux?#;5oE{}oWdGk?k!JF;yJvpzJ^hsGR!;S z#;nBfqG&U~n20FKXS)>Kew2}(lg`C{m?f?J@_)udr*Rs^9d5x)nhv?(`UMV2J$L}a zz}w?M1@bTeX#Agz?5F?!Kk-aFSHmoHQYFdUX0`3Y4Kf0b9fZCc-*T@a=iL9<+u&`) ze`%PYDG(q~xnTU)oUdS`5b~xGaXH9B1V*{~`nOLvqGyI8p9@Nk`wY*XR0=8=4{QO` zw4MNFA)jyk3&h72kARvi5OUcE;EXY6?wFwpm*Rkpe)-XU48eex?dURF^=92<`n-AAaWrk)z`%fOW&!cXi8&C z454?LQM}R1=^fBvKjsRzHZjs#jch+4StOL&^Fin7&eTiI@wMiz&mtN7DJV33KNNxA zIKdTS`vZTaIK|a5boALum=K_$Z5g^@rrJXyCD*&M)pnVgm54p0S5U#k_28G7^#60xKx%zUmEPc;UGRMZ1(?M*FhjW zJ$LlQdwv86hNjV z*6=R1lHWg@lI1~Eldl*GC3*^Hqi)XOWEJ1GsWJLH&bcAYn8u^b`;9eVzj7M4k^#rs zP#)6L?j;1|3Nj&lb%dU(-R{Xyg%;R=+#u4)!RsJ*07eP~x-jrq?gs&bY9E7zbqCZz zfjSGgtHD;=&Kedy+N>b=OX4%V_inB4EZNn7g49)`h8j&U+xtT0VSrSLw^U8?Kv)wa zlwKqfg2DCsJ@h+2aK>6$nz$;s&f;K{zye%o%lO~Nq#*-O*X*h!PM_Axf^z90{tArkGI)P^r9jjh(h#iO$3I7yALF*Cm4 zU9h~KJf&Gj$R?@go5Fgm2b!?6zuElefFJK+5Hh_&^w^wIn$i)^JQQX)K9V^uI=BL6 zeDA-~0{pelqH9>e#<#Lq z>#KhU&p|1_{(@O6aJg4Fs2Do-IlG&5E6A9iZSXRNSbJiOpL@xu@E0sMFDccaEs zl})=rtW_~RD|%)s7V%yz^cMrPxWpg?*irmdQ95503VGHEEaj{*g|T z%|`xHvC5ox+H125#LHSJp*)=XsgOnmpl$<_OJ3UMS_Wu@W8vT=*AaIrzaoS+Cen-s zKZVH`_{o?jvVi2ZorF3n$=OB68aD(-Ks?Q};T|>%C11nShf%T90NuaVHrQ8|u z+U4%+o$!*1N8St8u6Ufi>hWS<2S#k?L$Y$hj4;C~5s=Q)1@v2U@d zh|pWcNx4HvM1d7pUK8}FTnHb{2kg&abW4e0M}N0aql0kQEKm zhhcVrnvyzgdTNvU%c6^3VsIm$#={UBfz$xD{sjq&Cdme~Pvj@^mARpgIu`rz7WTpS zBa%<9CGZlZLb=(cw~Z1K4w%Or2U_k$z4}Q)s%*U+9nZwb(K8jD+@vo}J# zdQ{%eYB?{tnqUr>$O&@7Cc%yT*P)^JGgO%qa3oaD$S{11jzLE5`8`%)D<-*t9Gdg3 zzaBaK4SyY7Qen3~ZWuSuUi;{0E?1rF=w*dG(*@3uO(wfp>Fl%ZcU=U=d<9fPKCd^T zRJoo;Ny&9eZ7A?spMOs_l7|}Z522Jd^0YcFgJ4W;>k-UN?iofT8~?s@sWw9aTZq!6 zTbMI8-(Vb=vXo|-CTyk3Hazs`Lf0^ce?66%m0U_W(W|v~H__5|5gOgYUTe5;d*6 z-e9SEg_Wo-ydHO!P-rdmVZ+(+$~|u|%tgV)0fu8`$l;~Nf!NFWNO)n}6EA_SQPFRM zo68}+@RsvH%_3~aKftzXNti#J!h-Tc3_gTPhnUtae$ZvEn8^Y};aJ%SjJiEyqdua4 zw5&9g#5}XmyDN1vl+?4Eb`cOMLv`v4;PE-d4M7%Mlk(V2BZSM3=;;f)Lb0_|eFx5W8TKLNpjI}1s z4I5A=A}P`L*|-kCLA}?0pfvJx^>^a@W5gQ$M;_mE5rD+3%?aITE`m>)Ep0mSL&D2i z$d}2VUkQkc6~fqicl-_FubVa&&75Y>&bFc&bD1zB8N%n-8fmks2_o|MswEJgzDdnq zw=e6+2BLPKq!l{D>xg4;fzX0aN)wCBbF3=h@&TXf$%Ej)O=qVc8DTp#2{GW+(*O(4 z@!{QsKD6!~zoP2m_#|&jkwJjyRzbd*oT(t;W4sq&!gw)~HF9#Z=JT)P zb;bkucsM=Zu0n8Aa1@hSG|~Z4qV0H9&8ZK6gB|NbUG0Q1hx_t+MpB8%y?iqN0Qe8+ zLDM@mAqku^zdfA|Et;M?9Y`rfJkybj|3nx~=x3f~J)Cph^*&+X3|t0q3nQ)_-Iz$o zXFtjeA|WU!v~r_axmO$CJx0sly{YK<(7U^be}U-BEcI+ab#oKb3~iH)9e>d7B)XLi>@y8x0l3%_1Mu~*en9$e7H>~#&~6c ztPqm;qITFloHDOX2-~P5NjUzhOTxZ|-@B=s1PN*3Wz3<=>Nvt>bgT18m*vTHO~!$K z!L=)tn>iNkPh z1aqiK=S&_LtOSh&+}T|y;Z_VhA!^^RAX8LYkRBQx&Obxb!`atYloPhg_4%PXC*P;s z*a&4~!J|mSW`&YTj`{iBLN`d;!wk2sWoVB@pQ-OdbN6;gNu6a~gXk|4B*<%ve>?tU zF0E!Ou5!D6`4Nc zEYT?BBrRTzQu}-L)_a#&FXBy5vsd`E{7>tE`!{9nf z?ko3VBysY3a#U;mabX#e>~5b$;~<>XxXmwtca!^dBv z9onIsvUOmkuo5pYKqDKI0kJ#+$d5}xcfkShFI(s@_hZg@31#eb#WYmvVoSz$8kq|Y zj@L!hT+g3Ib%OF>eKoy^W>xN`o;gDCi~^ws;DtXS{dX0o=D{`Og7mDOgQ7^!&?r>- z=?aGa#A9*EPC01nj+#J2znwVBAcFPKtDz3jvM?PQOHrPevrVIDZn?ryXJa^>N?8)rX?JMv+O>rtSBddFt>D}$SbseT$oId%W*Ruey0WO254MX;hkzitxS={ zVQsD>2X8!C_FbUisf^EU#ATBupIaYNgZ|K~xTY(`r?$tBWN7x0vd!d>aEp`*q`K)4 zTzA4cDAqHex~%>6Qv)G{!A5Ee)p(3yrpz$_CH2#pflO)zCh={~DO3Lz<6P zTs(kVEgliI7204Ov;3>H=x+C?Le;*lRW!z*0^_Se<9k23cO{>{+6MJ4KR!`J5Qs^N zBf6v+9RVMpB)1%mI{6Ce2a~I^hkaEuh2jych}z0p->5goc*y6BZ9{a=2Ed*HC6u1R zt`@HS8(%9;)YvuH`)4)!&ApUANU+ic`x5HrHvkrTO$fgldfaiX&ISaFiN69B<-)G9 zzyb(s{WZiy9F`?HvmHr6&XWcpWg7LE1JGJJ%ij%?NYV$3HPfe$*nTf#D?WLvdVr7W z*OuSs2ssxI)AR)oZ^Ly5CbN!EVdAU{kE7~Zdt@#7+-d34VOCYST&yK5l?3UN{7e ze0!b|GkTsxrT0Fv=3Dnn+y;f7Rt^iRXcKjmFAf~4~2$| zuqzNQ20-)w-=Ezdq6~toP#!XwLXHZ(9URe5UjE-qQ}vd65gfVyD3#DQMu?tUC)$fI zKZeJD#>q6+s&TI7^SUUp$D+IEc(rWez&^yYXTboe(RfK&P#{V2>6Tm{-Hgxi+2x9h zf_#x4u1W*bS>Yv0ll^ntXacSPID8@AY$*m;HJxX!t2#n00$Xq~`kPfTNj}X8q1wy{ zBljPo5-d(l1XJFc@jqH(R>D9(U-qsk4N4ZmA-n1)u{KmLD6Z2VGrR%=A`->J1Ftq_ zZ38SkQ{o#1oR}^DAd?;zdM=s^X$>P8i3Ca2oqQYauudo8k&S2rZVt7G%P>TTDk6k0kg2dW+#cIv09#WC}+zGf$4r$ zhlrsJ(~;&45G`);4JxHCF{0zOM8xzEoNb$_Y!-RQSy_}&w9#Mvx8m_`(*wJDlBbqrLxu%Zb0K;FX!PeF$jOzVep0NBZDzwLa-H(k-VLLf?)#q zlT43yVqEURFpI&p(;DyWO^Z`jQ`ZKX?LkL3Ka&l$drrWfP1QY^IQz|$ltygt*h0R@ zQf`fn>zH{OLyWR|P(gQPs@!F|e5U;CX$ zH@vVAOFHmjOT%a)>%2~tm#}jdP`NUiJE(~P%$2Ou=$710yb5%eFvFi^+J39*DC(74 z8Zh=*(Gm5H{JWX&WemOzPU4$PDNTG5cMlUxyg4?;$uO5i09pY6^QGAo~zjoVV1U-8=1} zBn`+;t9?X6-01Dy0PQ8_$%n*^gG*HQbkDEZnl5EMwOFCC}Ed_h@Z| zIt(=W)saIDi0@~|cd;%2gjdG$4t^FAST5P1Mb3?6e2L3yrTxtFa6jvTxokx8Yt~ve zhX%t1nsYbCAeg*}XS6Q2E7R0?Yun%2cME|mwiB{lo$Aj}$lM4-oQP4m61xmU{bv=D z#xCXQA_CjK$F%KObI;kgTh||(4rBfQx|f3h*cR(GA=W}4qfiQ+F7)) zt0qtXaltL*Vo>^8NcXAkSv`>=?^2?>h145VcXQMplTCi3g@mk#f~B+(F%b^9Fq zmDmmX`B$`1{MXW0*1>zq3K>Z=Owl72nk_LP(h2~{gL(i_y5>4baryoWpP5W{Fi$}n!|D#Z`6P7z47b;vvG4W7SWb}ukwM`2&tjKO*=OdO(b2d0N1I zhSGZ)J6XpX56|MKP$x)&AYHYt+15CHU8TF)0#;iPzX)~}Qlv|o)4|TG3Ko(+uy*Mn zX51i5%9V-AiW>_DxR$2R-!$d7I*9S-48_^Z-0Xg6tgm;Y=kz&+I~No#x8Y_lVrURG zHQ8(H(mbqFCaEo(tbO;8-{o#fxf(y%FF+8XqMr)bQKhDHK5fAuv(=my zsF8n~hKym4_vhx`Fl!pFq~ZnU2AT&!s~Ym}w;{&~+dFk#uZU+|O-zg;Whsg*!MJNB zkV>8^uopKb1>`5HFpsN3HcAy<2hT#sNBLk*IeVfqz@|KewQL?|H8iHsIkMMEXK_d zp$Pjr6|<*9IEAlcWbE%EDW{ur6)g3hJ-oKh@=2>YmXY^7vk_l(ENeFjkI0BbwP{7+ z)-Mw4HF;fJkDcx(shmz?^%c4f@{d%P!(T5L?jO1>NJGNEv3L}N zO}N~&gnSXQVQfqSK10rxh5p|EXpd+(YWG1Ax(3~l1+Yt_d8*xMm1fQ}YopEuRWYur z5lilc(K}?8Ye1|jXWx0`=y~H~7`xYMmIN0rO*~!VfJ;~JXFD;D|CwdF&UxFFMs9Hs zhXrERJJKc)E!^N>(2mLnKnzG$9yP}IXk33HvXeW)@5MKG0ez_2{PF@;OcW_xA}AVo z03dmLKAudwsv@Ui!OdfL9FcYvKoVa;xL*l?yk)B7 zw@&@Qg$u|Q{DV|nKJ?$KkCX;b)fcDY*BSDh+fUGE6MBgznT>3UA4su&%j3Q&p)0~& zVOmx`^ZP39SqmZgr{Q;r5uMw~e4wswvs5dZ7U;xA47=5?bHD_lnMjr4n#(L?mgnqS zgl>DbcnAEkHr=Da?}pOvCYnvlol$|~OH z>%x(i4+Ttk&`b7BhGe&vYw3pp?jr!J0T@k++o`F*aEqH9_;&(|aJEv>wFCHQoI~md ztG^T|BKtCl+P~{n2dd)M$A?RT%hT#d@?+>U8lt9@feaYFoHPkLU~PjU83qTf7^-&G z=<4{FX$3aj;6JQQ;&?yg)ldV{H+H;s{pl4EseBG%(m#Oq1ujj01lWUvugFC>?nT&H zq%!sWWqGKj5=&nlD^qEdiJ@Ok$%wEa@OT475N)}C(G_#of|3MyuWtegB8liRQ{8*5 z8V(baMw6X32t4%U37)A4Sk*c%8I8N?lw4s>rEIZ7Id(*=Uhbv^pAozEH^8H0#7n>9 z6}~P~MH(*q9a@lpCP>tmm%df#-=gpV7=!@nn+9?N7zS`lF)Y9`Ve;N{$?H^ppr>9O zMSXPQ#7!@}dfr&3!g>snpdyEh76^QP{G(umY^ofPMnzW>ftfhyFIv-i<^DI-8YC(< zU-Oxx&{OUM;|iy9whUZORE4KuCd*0FIrW`7N?ihZ60=vB}{>KS&_I3W-GcKJ?=Zd;zUeBkX@ZfdClP{_F18$xxL1$TN^ z`r+qGPHMF~aVA%WOXc-%oj#w-^4^QuW%l9qksDV=(~n6UD`v}1RA!eNVx*N4aolEh z!YCFP<$KITF`oH4dT!|8q>>{s@5#~vo}SX zILCdcrVCE#u;WJCbN4BDd52yI%oeH@4NSAQS3y&LFIER4J#5y2>%b|E(Gh^@kxp=fixCgPw0@O$Tr=H5_f^+*KZ124zZdDpQv}%XSy?JA~vX{iy8UJhW8QlAbyIS zO{puWSx~e7WP7@RA#Zieq3#|GYYbb$SZmU_AZa#iso^|WXD5l)mPv6gj9BKV9g5hh z^p55t#6?TD1e=`pbwu3m%SXu-zJzG3WK&8>m1l|{%fr;eiYA{VEdc_yMJZF}bI(!h z09yWjyhPObUXsQ9R_m>r?Cfrn)Xzi+92~>%yW--ajJrkPqh8O(Dq&HPYOy2J2!_yY z(2Eg-R##K|4yTQ)bXT>$2-)%&cfC?)=fV%Q2bY3YE#n1mit}z_RKQsek*KucQDhOM zl*CMfN)~`aaD8p`=Qf3yrGBW&V>j&`wal22A&psE=;63Z!=Qe546SPA7KT_IAsKy#kc-o&uqpD9uF=i-h9bbF{%d`qVL zfYLF#Czas~j`7Q!hOR4oX(so2ciEKFU{T3l+tc{<`H<&`8|iub(b{Y&**zp#L8B-? zFX}o2$5Y@2qf`MZYTt{Hy%hixvjPvRfO#ir0y`KIR8W~F)eyKUll6vx7ngUpMm37Z zwq{xi9nP_{q{R#azEu8K;}MA9-G3u@3mfS+ybv^ZqTh<8Lt)>)n(3ts-j~8K*F+|! z=_x)|*kk=)y8L0GNjYC`q9s6;!Hkd6ZsQ*Nje(C!Sf)Sa>6=aJF=aav{gX|Wx#~Bkc?NZAHtibUsQ{j|GS%vQ2=)oMjCxXpypE-MJD2bae6z^G+B$7sUZ~tzM#5RkWzc4 zqv~EN2#AIiDfepf^ka*ALLm3&#a*Xi;j1}52@Wp!o1C(JX-n)^(*x1*WE`6t8$}^T!|4o|& zf9e~^K2cBzG*o>kHgB<@9b7y=xzSIFL+^Ky6n5s!f7dX2Vk8510d>QwK0g-rk5vun zbD0C6m{rtha3;U`R3%{DC%*Rkc~Fr?u?`4zeR=#7od&7c$s1!Ft&4?HwGJBha?+qi zM>s;B>KUmQFVXc0U$D(5OeHk23}mjQm_zoepMYtJ!|yq%yWO*OV!jmSuirK|+vU1D zDckeJv^rJ6AHm=IHwnDBBj5OhC|d-nV*CXfO>!~z3);J-+Nyp3>fb!b2R*ZZ-bCY- z)ni!cCk%QQ*a3t5cDJP9aK+_KJ>%yQfsDuHp#}@^wL>lzMn&0_`jTQsj>+5a?uw#r zdiTZXW0D^QIZC&ocm=g>iuPj6$sZA{fLKs-=|I7UGC>*mi=e$vZFVxAGTv0NYnqZ% zCKnX9g4K=0aYp`tE$-a}TEXR*E|8Oz1dK-Q;u;pHI@cn=PJ+}>8BSnB=AiQhHc2fH zGIXWWN1t+p;oP7e=w}{5euFL;$s#1K)MxXTp*vxI4c=k~5?ru!I0fIXpGN&ZXek!$ z>Yc4jbAm5lPOk4|(AFW61o)sc4Iv8Bxrpw?34IPFO^1GZ8Tp_ zuD|Es5<&zUV%G?DW`>@ZT3*xhhm{G(+NI<4%KBF<=~y40yb_ZaZ!W%WdF?Z=Pz4vJTm`1#v3&P zH)tlc8oBc$o1GPIT=+@Ehu$(olo?|jx5SP7M8N<6y5Rq!;HOC%!hUAuKWG2{yFT=P z&JF`(HSu3{@23;rq6p{iABj2PqM``LMlZf5*3M<_Akcq{5^p9%zl{-;VVW3Mu{z?U zLEq@BG0w%=Cs)1R2*@$=YtMV<(cz-p+92#nnQWB=khPY8z_mW9-R+fkIz*^=4DLz% z=s&7g&BCUR2RIjw8NDh5PXDS_&~|TxQ~L|gvLy(^6IoDx)tQ=F8l0B*a*zm=dbWY_ zjc(r*cb^5;@M#S)DQGx@=UeXD^%C2s@z!%o5G~xw}#2TRQP3}ZZA2X@60yN`z8RENbSZ~^fPSWOIBM3Ytef<{m+@dfpnav`AjxP zv71W&+o-_DXl7&IHj zdKVI9saXLMUo*q{u-)0XD7ZrhxK$cw$0>%iAv-Q9U>k;mn25lR*TrHNIXda(fHp0g zT%WKEx(Q|WcJC%$;LQC`91p$DqI|;dX+fxb$pEoG1Y|FHk_DQ`QHl4fNhg#76ftz6 zB_m=H2%SkNU?0||LJLLMC!=y8=)JI+CMG-dp*;t4FH}toi$EZ)Pn-vM{HkvX-K0!1 zb|X~-=tXrVG_G1_ztmJ?>NR`G!K%=C=lWenHyr&#Y8J(H6L*l-<>a9)F?wQM!Q*c7 zB}=MiK^9H+YO*zAx(HzKKOb&(22#j!wZUFkXFKT3v>~U*-6ip@Jf9xqrITdpEI(qi z9yN&S(xm=mv3>PVd!AH}$VV90_1dV_f85yL3sEQAV9be*9Pw3!4#>%_Jk0%4f;Hk2 ze|jX@P?IjBoN3q8Do}o25*$C}jSM)r15gNk92X!)x^PLPLh3a!G) z9hU!am{Pgo08ajvjkv)RnvYts%U}hRicD*iKQchzyqSUE=_UDB=`+KGv?me%jP4I# zFx9)|2Tfr$aT$a)U*G^o@&|Ie%j3Kkn;X~et6=;Hu`^xWtbKe#&6_l!lN(#Uoq(a` zm&TIUOS-{!fBbVy3-l^Av)kt>1y(rl%b4?j1eVy0CN7oP#^cX4;Ix|31ht1OqiJuT zVr1H%?|>~g1G@^{5zqIJjdin_9-J#;jg|nA%@UPJ!zyz7IXOkoJnb$&DgzL|U8F|i zRAMD<_@{*aBjuOEQ*-5KkVQVNkdn!{1tmCAd-FX%D|d5FOeJ@?cI-M3Rh^wYyc8f+ zI=tVuH!Mysk)|=bRvPN#ZG0!Ui`cmNT5>$@*zid&_34CRdbiKG;f_XB0v^b*3WE>4 z5qgaAz^$2e2HIm)554OC=!Ds|J z*=Jz>y!$^mt8F_|czW?ma)?iinm?-G8G-q0kfznNAUH!=ixIT`|jS%jv5@EgKro>zzyq3TCNm>4xN*#e<<)&0O-U2bHJZA z!2cWc^*`_l#}fWOZs-quA`MH#KT<~gG5*&B@vM&Y9{s6Q$nw$d!O=`cbwd8<3^80h zqNNy(u}#9N1RuEAPfrEH&|K)#Y)~XZggxoxuB8@&aMvruTHQ^{R&!#*CpqFj590k% z)TyZexaDJlhh>m1?qwmd?g<)7ueaV5l%#`D`dK*L+4gy5g^SlvOu-*zU(TB}6hl&y zV3I|FKb{vG+FBP;V6}%$%k20i+?wTnF&pw{R_xAx!^GRT1Vss+2l10Zs|JfzZ%FME zf7PpXcIb{{V}jU0jB{|+DUo+X#i4@5&-;uE0__Rv+mt%SO^`ueD&CZ&VvBWEszBou z{o7R8=YdjGKuORM|2Mcp?vKGHvzYsDkkrx6ueei~et$~T8Un+EzZK%ewkD&KHUq}I z5(`2JEs;m>z^Kfi9Y>Rz#R^G5&}=CasM?{bdH4YX5&s_pFFfrs4yMRb9fiX6#Fnmy zJbf^abW20wAqQ?Di6gAwi{IU;y~6w5F%FBk0hfWQ0k~U|6mmenY1Fa28iYS zs@}Iosrc8|@5oCRg0iMK2GG9(?ej!U;;3RGZrr)0!xc3N-g z2vwtW)(j|zHGnMZxRCzrz7?=91}cQZ)2mtJSRRrsMVCHH>{<_n`l|>j_u#kgSC$Fl%r zfajV`$%%kalAEi&iL^hC*Y15y8bz2tae=V)s4q%P#LD7BK^eXZO;R=x{sg_N$D@BDxhPn6 zWaT!@52$*7U{A09MdnGV_d_hb8N!*>v3_Y(P*_6$<*Z~j-LAVMi^{z9S3ior!2lzY zbvEJuVeGBr;@Y|X(ZSu_-QA(Z-JPPv-J!V7AVrH?ad&t3BE>0E+`R>gJ9jwe{ND4t z&y~-ef3lLvH!E3LE7{3j*%2W3gTd-Y-slZbVX6tt%0K-=^1-Nm3(zJuO_7_q63o%3 zFj6yHMMwJX%do7~{6JKZ)J3L$PH93T<}ySKL;_^>xP;3mXS%gTHA?+=7XgMRc{7l| z8rqMR&1Xrtzng7bq^FcRHqSWgS7&RqjBUv2>>ZvDly{nrSgf}hF^Zslq#qDehA2KE zOi0fvaK&Y^E7PAi7-Uo%0u+e710llw=VUd~`!*y1;0(5+D$WJoNO*%kudmNhTW>Ui z!3Ee0{0eZE3nrjl%;ET27Rb=zpoDL)0ymYR6`Cadjf36~3*)yy&0G)5X+X>!+9IZL z@!sAl!DLvT$KfO($rv5Id^fzSR3FJoEHz@fP8+o>TVb7+b=9PC??VLxb&IkNt;(aD8`ji-nsr`3#wPq7CDrdHHyZh8YN|CtG91#6=>4zhi1bo^ zOl+fljw9iNkP~ZecT>jLC-ZdIfWq>{->T8(09BK9nNL!ig3=lH4+&bthYX<9DKt3K z*T{+S91?9diz$3|!SEJOA&tDAPMpzJPBXRS;5y^PWxNBYbrauA{`@2>EE7g-)7OMx zfps#b!iN}(U?n~a(bR&;$qVMV&@CHqKjhG1~}TOOym82{~@Jlb2w2}*k&^0cDLe=wPG_{(f7* zvCugK#9Jz*Cdvy6o-|^`jnZZPP^0wR!A8pFk8bP4HH-d^quSF-5@rCc`wC$fDXBTL zGE1U5v#?e(wqHqWd8gq_;O536%Zy*ZKYfXfUkN&z2-A_p#w#d-lcMGVmamlE*l<~F zPH53TQs=z5b_mF|JJ=O9% zY^Y#WSy=bqx|pxT$t&+ZXx?z3xUdNuGP=%xinX8U`}3=B){cB16ag%d6ayjJfd%r< zSrbH0$5(#hA3uO^CJ#U{*viWQUN~7|0hmP3g~6p0tPzhILR}m~@%FQfX{rxs;_Qvp;G0s5Qd!fR|zNlCuNd)a$;yYS;NK*B*d^|%mRefhGEcl$EN63vUx&iPf<20op^)q=6@Kn$l=J~;B1SFkdW*cKf%A{meDAj1+T!&# zL+O05N^N300o1(T#vzWp-rcW523y@&2Z_vj7)K@&?GLVy+-^$}6VgD+tgGeKx2j zAwNTkcrl*7tec%P2@i`V35fKTRnjCp5$AOM5FW@eIBNwM*&t#JxGqG|2;05`@(=T* z2RBf-04^Ql3^(_6ORT&teawg_sHF|f4~dnp9Ah+nEUg@PKYZlI$wb?S>xL7?Vz6ge zA}~e-#g5kNB(aKcG(Yp0MpP7UZTwu#yB;#fG-lELfhp&NayhsHBjIDz_p&$(6%;A zTo~sH@FzvUKUl;1@>rNR3eIr2i#&@R_#Y%VMfguQZt^^UE9&8SZM8y_QxBeQxWkZ%Nw7#bzRrd*x!N-Ug$23k-&=$?7FU=Ti z_eW!hS@<(F23POH9_@WoH7)En_=Lj|{Dw@TEAsDZb^!&KAjGNv5Uz2F%9}(1utsU{ z1$uu|Rf@fs;b0Qp2uu+ylK{YBu$$*0m00A$@PZT&CXL)8N)b=#&S@VQ;@|x|iAK)z z&J2*tA?+-I>Fa|IUSbPpU4OKjNwF*$YBO0dE)b0cA)f!mH4|P*3V&KDa7m<&a=yp5DU<~T{mXiT$XK znWmaV#EX0dr9${;m)}6#@tepc{NO?2`qv1wWM<($0#4Ll{H*fb+M6zX?N! z{6}ZQf@TmB*FQkzEg+zm{4K}-9Rp|RfU9l$6JVIoy*cQp1uUomA!+{05CTBkCi)l9 zj2ZIpP!{a&1un=;HkH{-7MHw0G!lg5{*TP$DS(io#tS=NEC(Flas!Z!CS{K%Lb?Yu zeMR5mNJf3)m=dQNGG!z{aFoS}mFYOC!55Cq?{BcL$39Z*mYLQ4J5 z+EdWHbsD(YCXk|kg{g?G;1Jd@l^|W?$}klZd{L0tR}fMw7zBP6pa6TYfj`H%ru~&Q z$bnV87b6p#8GxYMnJ|zj@|5@%;nAnh%5E8|q&$uIs7=my)Q^V43i$K-3@vl=2@%_b z3K8Uo(efF-EB5k~QG}K@Pde~vd0G_gy9RA|!#ymyPO+3m7BOcQ4TVKo3zIue7@0W# zP+)5MyX?KiWnA2;dF-)zGA(`(-f%#twXNQWPv7{u=@ZP6_q8vxgkzvkBC)0xVML&! z(7df8Lyz|5jO?WWppcue6xK_fA8xz7$$kuic-|K7ct~mmBM6R^sB>cHko0<&+Ex5Z z4_00Wmkcyt)bp?6+25wUnq!d7E|*#Kz659qAfm%N`;D-`h^2sYv0qeJyTx}b@Z(5P zVVaiqoX_O;jL~kUFyEdwf}LDb^kJ<5pOVifV(KPr#r@3c9ISgXjFQMD9Xds_GmWg*4sNWa6cvm_r9gT8>Vij zM2@Wjz$uw8fP(KJq{n}h5^TtTUgNh+|ARv{d^A)IYWuqJk%}_|uM_+awk3+M(UUKA zEhHKSvRld_M;BZN`9EbfgOG{;t;D~k^xt)WGwg6T+cW}KA*aDe!mXeKge>$A?thu! zf8&r08;`yFEO^G0kO7955jZ8{pYFhhk8Je+hbgRK^`u6AquU_wu4S2fIH2GO1a_5t zo0XygU~_~38V_+k0pA*rYl7wE^rT#aaf-+-I;D|v3uWX&`2Med%<&Os&FX8+YkhEf z#^RVPWL*?2>q5YPkyva7sY-&*yA4A{701F9qj)sYxRs}B?X_Y=<-@(!y|GILj_Kj% zP^p24&;xOW;6gTXUn z7zhOhj02lJ2H5Ojj7i_JgEdLl6`QpBy!Va9*Y}~uY+YM6!0|aFTD7KV`+6(Q?Ne*? z_8*t-hNB;ZLurjyJlc0T^^6R(!UO5bR0OY`xZ!3< zsH=MK!K3bH6faFzY7H9RvA!F4teXQAG=Na({%rsRkhTpb9r(rq+BBu)jes_dES3a^ zFs6~Oa{$xGa)Qk_knI11#QqBbZ+hh=D0PDh{2NpYLb3Um)BlL-zd--VW*&qR^$+4r zn|kS5R{{0C;JN_7(?EBK!sm>Uw+O27ZR=#4eiW2QT4xA&^$1=>8kQB1UQ4<4#4RD5 zMfAA77b7!C+`Z74Y?mZ=tHzouSGhF`%Fh zgfj6r0`Q+2@?QX0L(j#>N8sNOFq5-?AYdl{)7t-n{LMqPu5uMvAQ}QfMgON>|1oUH zKYaZg><%%b0m(a0eOk&%4*A1y;P^jsR~n9vUQ+;n2uhTWORA7+POqo?m6s09?9 zfKWO9mCpYeyu|ce@pW#*M3=7nMe${HuQ{Y=Fyz&}8m0%E@C=}7Dq3KKV~k1358^Pn zefr_puo9;&jP7oUJIho};zv(A?|Z@Q|68&VmMU)ByM}S{lL{PnC1vC39Ois|Z;_u%BAH1izv@svKP-;}z z*F{;fac{gE;^bs52#1}a1C-S0>yQuLN#$i0(YUL0ST?zQgmJa@gA^_&%f&K1!>YK- zy9lLgolm)9P{oG=Lhe#fRIk(~Mk$P3iJ^LhnC@n|6iNC%y>y5TxQ6VkmT{hvGvF7z z+$<<`m{(0XtCuE>qW{sNzs>pRs(eZuImsX#M1C9;Ci#WCxo8m|-(g8X1oU;f4h0JtM7Y>+w=MQ^OO-6Wb+dLaAj)i>>mD zUGO_%Ir%ZM-Yx=CiLf?CDYuukU3yFT^kV+=yn**;2p7x^`^pdBDurLVznWpL5b!yq zXGHPTg{HgQN)UUHLnzUTsiC6qd1&`{ht25g1NEY!dF|CuxVDa?;1Zsk`2|E!2b**@ zr;x8nK)C9Az88OX?5_K4E_O-K=0i(jsO)&B#3Jbq(TgZ?L{|%wH%g$~!lGiD0=I5W zTy5b#u#K)6XvKzUHZOi5raY-Nbzy3BId>6zSXowY)>Q^Evz)zO5l zoFu6f!hqcD7@aC-pAKNFsk7*DJXSYlNtH>UC}A<^6`S=W6!p>GMnFvRt`2Jn+eZkf zrI&7Y9}eEhb#wh(!fGWOO`!%#?=kW+GP2HoR0#4iuY06xWN0q$i~X^kU1KH7y;u7} zVC53nPiTYgJ4C3ClCXp*@T+Fj&PX&(d5rG#_l+J~3?^%lBDd#a$N)n9kdWw<2~TkE zkH{p^wMH>UOgNi##+zG@;ug2pPh3n9%SXLc(-@-JnMKA4I(UK9^G;Yy_dNXQ;2~(n z6Re~N(-7bdCs8m3XOtfVD*?3$CP_>`hS-Pbe(}5wDs>!1ar|wH6J-@X8um4JT_qCW zhVFpyg<`E+e6H+$Zh<%)2-WQ`dy9sD8;yX@G@`RWa3K)O*5$V3H&A_vu}FOEVRPZT zCHU>~#-|&|b@?p^V1+>4(RY`#HpAn{wGM))jLX1w)@z(zap~Ik8}~2JtZ#pc>dF1K z>~4${ejJ$KV)2Cm&QSP>#+~rA#*th8Xc3MriCB1jR^}`kd{@zlEw_`g_gA-h0`LWy z#;S+j6B$GsFNqqPBW$ID1%iBm3(Weh&x z^x8~hH8;I}3#&_v;Me;e!fBXeJ2iModT6l4UkSXce-9^=YT)oOa?#ro?ei<8HkE-9 zCBr*}#o5#{6xI~K#rBx{0O_X+0x+IP~-MUq2Hj8(GbvQjBUU3ryaim?LaglZBCXV>S^&n!SNw29%d*U+`a!b%Yes1 zsZ|ha@?VmFXA64k#f4lZ(8`b{6Tj3vgze7IcKi z`5UgURFiM|TKeCuS<$17Q(Nj>#InfaqxV6a&taGTVKJIVRm2UVQK%wi>mL2#c7syz zYpinMbh()`ZeDejW4rvvO$x(mt9OF=Z&-+{Ni1JR9{oAy##)w`X7xRHs9>L;WpnS} zZ+KMh`=2}BFw`vwg&(+_Z_M{9F%<$CvDbtNyUlt}Z@5=RIQGP{z z)NxdIp#f_lO4EbD#EgC%YVvc{QX_{DE0MjZFzGoLAvgD8YjkxXSC{zN)=E1^1}$~Z zPrbBSqpT|;27Nxx&lV-4l5Z!(TvA(+9&>{1L&s|MT|*+%S?8yuks#yeWhh9G)i8r*#vXV2(idx|B@h3YMa5bE3P z_r>D^F|s{GWLm#DBlrqjxNb3jATEIKBF1O)Ac{N`o2U`YfO!3`)`S{CzsLFBW(2xj z)+jPY^&?0XOtu(RxS*R)e-#cv7JDAe5b|^jzs+bJw%uf2WGC{TVK!!J*VY z9rFD=I3{SR^)921h6uSVMe*+EUU>AON)M;%S$1EqCyoC4h`aeOAk-TCtSq7y3Q6WY zr4LQ{T6zgbgnnS>kI4D*TC0>}_CamM;DKBOK4Wn+C)%oh-s~x@CZKn{q+o;+gakqf z&4%;1m;cLYCxPz$S6`%F$-DvB)Fe+(Z0DfGev{QN!c&srhK(e_vN^c&UE+H*G>S#k zw9nb(C6`d)$NFEOJyZPVArIFRE{_W*!ph3v3()!YjwEoN8E>{4aH=s=&sMJt+sw?< zb&v;CP?dhhQzN;J1(Nnj>S+~QKDk=oPdplXbjqMIQyrRhv5mo=L= zr3Eu0r^@uu;KK>2TK@SYfJV+l9WqY&I*Sdy53^1yTh*3DRk?m8C~DNHsFOTlc^%Pg z_~gnTI>67Pb-5lr+fJ)%y7%f8Xl`JWgUMwt@)gc4)zM}rznu0p%kA!fC*XEU1MVs4 zL_otow4$EE8IO6N`Xb*ShdHC!JW2Ma`yBHvuY^<8mNRBttb0S@w!RUM>*{CXZ4-F1 zdyj`4T@raz!@1`_&vqukF{uV8LS8XabG_!X{`|HsfO<#{x>zZ9&{KQ8_RlNzNf}oB zQC=2FYf!7D`4m_6WFbEjHOp9tAuXG2(xfZDsCkNaD7Pn^PReb>@8X5onvu5K407NO z<^GsHl~CZ+ng2}3+*ioH{TOBQ>)IC+Z}m!yCIPrgSm+|5t?YsKWR`l5bvE(O zQsJ*LEY8&=>V^;E2GPU3z8FTj&x?*o{XU5Ty-QGV)xkU8`>EPUBx1b22{?^GCUlQZ zLJg(#zvFY%Snaf2f^0MN#=gP@SuoXJA@uRiJPuvL`7!1oE%V!E=gplx!XKzPCHpRH zkm&(AiRgg5Dbmkmb1&*hBjD*$|D)3avo(~o!-FN~kCVsTd~+y4M{_&hpVa+Qsh1I3 z@!*fOaMR>Tq$eA3q{16S4l2@lgBJ-fo(${OtM9fJ`P_@ zqR0Hq^<^B=W0ihT!8<3xjV57a|Mi;))pr!583m$&~NcIvb z`0<^FJcEBlvFsxu7K;pP$ulRNyu-ak%~;$3PDpJcn*MBI=3;|RUICf~;s6k8%Rj@r z=-ZC1e)?NU5Hk*!M|z@IKkdfNcz^U&{qZ=2Y!njEX<=)fc_+bR>ml^Iy3g#dx5CQ7 z1Ba)akRAndC^c5WKz3v?6yE|n>r_9C*Qd!TbN<<0QBD}L?IUBHu;zmwGfv5q!p>Y* zwmOBRS5f2KYswJmE1BL(r6_M`~t^XKSb?$7e*K@VEEGsM8rS zAr+=15v0`KzUZaPSh&%ld4X)Trf%Oa0@)MTZiCpxcY5#B4>%eu1>4awEH2$u==Zot z-36n~2Yoh!msO7Ly6&eJ0^(2}y#^){`XP3;Do1fpr3D6rBzc?Ed^}@)=$Np=a2yVA z#zUK%zEFz-pfF#5Fs`y)d|s1SqD#8!ctQB+)oMljk>SdwNPc}TiF@sx~3wr{-(W1os*3H+NNnP~;btihZ1;&mX@pMR?W2Y5dm#(C(k4JF6`huhbl za1VY4x3LC^^@`DPFU7?rwT!m4aEXkwr+a}2euFH{tpntIb zn-WZB13Vl%`Z`1$gEn-ZL{i(S!=;CW#MeW8}8zNKt`BdM4*}IZa((ixh(iRlUDRAHRP)Yi0a<`-aYtWzR zhStX%dtZycw=b0m@IUx?VQ1<0Ikm@WCVGsnXofn#%#r?a9hUC!RdDx!C7RPGi9D7q zJEPOGg+AijaC5>9r6QW)kcN?0z?_;XNJt-4sEs`mG^S!E@x$&Vy1f`<4nMwmL9YL$ z?xC=XvC#4Gnp2gNA9BG7y5!u)Kbc{_pA!q~YN-@s6_m9!g=P>DIIYpcipD zk<+v3$KFK&w8K|Xu$sc!_u6fOL+}oieeZ3CmR{TDTZ$;KK!O#7djF5kf`_fY-{C;M zI_&Pm-Y_PxvXR(v{)iIRInnx-`SISIi~G6d)Zk~>o^&HHM1RVMhzx2sjz)MTDgC>c zW!mD;>0l{)v9wutA7nAe#*yAn$tnhmjF}UNB9O7}4)`=%B}@~7ZEZ!?>V3pIT{I$d}u!dkprE{LzhE_v9+(CBE!GsJ8&s>mR$V#tt@Y zX|PT?66u6&5@6?B;5{eiu)ixoW%;Z`p~U&(IycBw?5V%| zsU&*C3g9uFAUiGXnoKzUK;&liJZrPtePI z&XlOn*3P2m>!Q#;Gw2ka=khw#Glah6GZ3>aWtG<&@to4+ zwf@#@_5G6Xl~Z;W#H!VQ?CYWHA4ACNFPU2XMNmujS?Uk(_Vsfa+d*6Z=?m>Zz5v(M zd_-ojJ*<{r?oKM~84a7mQOwyv*qGKN`$8qoF!mNGj6t3rnOftS8YQfKNJrJ4qvQ-I^~PA! z9aKZ~*XbMoIzLjY^vTEc=`@SkXvT};ToZZLt~jY~53UhYn6B~A>%k8ss>(qTdEDx5 zYdjaJRH(2GWW(V$Kn%XL?f7%5*{P)CY)z|DMqJtbQJQ98f-O?anw5r+mAyx%+xz8; z4dR6y;gzB&b)M+wpHR^y%Ck%crk53@8@VCmK#ie{%5lUG+EAzCmoEJT@Mi8Y)9~5| z<&^oz3BoKEo#ODhGy2IcjQ5SuBGs&{ayP`hZC$zrC&qk z$J5$6)-YaWB%8B>Uztjj6#E*-?2Vrz@xF?I(`}`17kJF z3J@jJdFXGOeeTMbq%^xXkqndg#SWH3?QqL)vIw;Nq~>-YucTt-kF!~Y+gZ^)=J;Z& zi8Htc2qj`d-8!7MNMgX?-nY^2Ne!#`@+7Nj z3EM5knSGR=XSMM4hnuCwE@V^J1xZQddNFPQ%0kewNt2kRM>}Spmt&>h6GqZnGC#ZW zC0$PfJ(yGDPUye~H#H|eq%T`Js!&5p!?g+c8m707Z;mDO!<<2TYV&r1w!FL6WH8_* z61QVa9QyYre-L4Eqm|HJU@bLcZ1$gsEeKp6(hEF>TTeFBO(u1RZQ6?QSxh>Jea$Pa-G zK97KvEcUy$q9K<<38X1)q%^S@r&@ zsJOOq;0w?azY`~&PlB*NAf8QFa!BI(;o|ktVGi{Exw9xL(`g7!sh00R#3~Tq4be_x76a zz}TpyA0Z`viX8D6O2;URD~10WtA|=Y`{TNQ7;5i2(=O%x?25a@FDOyUqIqR5!GY0% z9MhT(;z|y0#DNj6Mb?2B97!6X$#3t#7mP}!$nbSv}xhHqoB($Dss8CZNocVLNxB~f;T2`S@GPLPM5FHj?__U1N=*GF4*mU| zwwSn|s-ANo*VgMUvk0^uj_AAM?NmrEk;_h;V~g?m0*Rdw!|8IR1>iRy`EN(jQ|1cI zG??##I#X?T)gZjpR|`Tluf-7&*AE=bMf5f4V66GJ#WAL@#5}DKDoD+|Fi4tmsu14! zb~2F-%{E$_E%jpc1{`(e|BAPOF@~Y6g?rC2J#N>WE;!Cv*{qK+<%x_|ZAa91l!F;l zT@X4g`h3*!sD!bexBI3N|8LWY1R4nK* z7mW5~f?&wm%-(Me?+)2-iKQ94QNg0A@oshA2IK#R1pyG>6XaI1r) zkMc|7TU9z`BHsV_+ye3+1vnky@GU-3j~>^cha-k9h5P$ekj2NF`64oY5`+6u)O84H z0GEeurXv@Luh22a0RJ#RCwHCn6+bnMH`+nO?BqRMm4<9pOiN7-b;McxNmXXC`u@gp z+v@F%rzk5?d8#Q}{!vfD>PWRs9riibaM#D_X|+WR-lzGa+|lHSo*d`Yhe-3$6(ECH z5f&ZiMw|KOit{|XLCV*d_a)Z0F7-c1zmh;2c5%B*Y{ZQlNXk`|rpcA~&q5%0uJHQp zeZe@Io9lwTwuZqbzxsjxIRnGv!osuyC1RMu^6DFsy23GyZ7*6=9S?eSuD>b@gG;Wa zvMEd205Vya&5aDYcNijCGk##QJn++5d&t^Bl5`C~K3CY5-(#*C?uHVnZ2mJxk5Qhr z^SxcoFxV%AzH_->P>qE&ljM3|+%D}M$dgG;=tkLmd%H~97&@$w$VKn{-N#XmAFM$r zw$;}x6KYI52S&B`NPK-sWf|2RC$@i018r>T3 zcvYbj!>*LyO9DLjqf?mfc1*D2(E;#vCYLFdVQwN*QC^c0`>y&@(0lXr~`uzMU zQ1qV%EU_UFTHt?5)jz+9 zL|KVT$-5+Uh$%#MH)%ac=pe{p5L3W*Z?M&&6z?JaDS@a4>AR#$>ep~8M~PVEGUzL7 z&66LTV>K~~V0qpR8%bO3S&Zq(%O*fo;WU`AKdAJ81f!#+>*2xF?p>kM##T&~_*e}M zyi^SQ!ag#Zmm9Yb^c%C|9Ju3Al?%Ue&Ua+RFi*tlp!n>Z3x>dGV8-{d|B?z$NoRHwus6$!Lv(dwfVuf;hWkrP5wM z-gDt{vvFol4cc5|bjJ+vU7~3;q}ZnY*BMot47GyxYA*&6N?3KN1E1Zn7Ad3ZvlbA_ zY8F{#QWRgCLG}M*Xp@lwq2+=*@*h8Fc;_m|C+@ed1i+fxD|hl=qwSxFZ0%1798~Ye z>a#%}Vbz*JQkDJU$6M1NSo-QjSmFxF1RTVvv1-1+fzrqo8h+8_H6o2i(yR4VTl|@h zY&9|t-BusmAyrbG`Em)xR!1N8?q`N3zS;1&4K8YBc4731eBmCT`t~FJ1B|sw-KY>R zwSmQgNBtK-P(C*rX+>UmiTlJkDn#Vgcm8aX4+Foy9+bv>EtOtrXKmbaDz44YX4xxp zr4~bJ%54uBiCza(+QI~FW7B=U6ylCC41D1@R=T6tb||*DI`P#dRBxjQc&=1v;b_7B z)kImv7s8poLL2g7)ISEtKxH%F*Ha@_p;mgdPrJ3B)o*NhV=T z^!&-@u7PfyGVql!;`!49V9h4Rfd6+JrMYV0ph;a>`vZw$;>RpSfA{9!9$U_esZq`c zG&!ihqXsd&G_=IBD3>89p5r;g6#e=5ngbxb<%Wwa*a|#3-?>`?tDbmX9RsCKIft z{SL&C+bzx}VM`MnPkiWfhKSR~1eDT1PkNe*K;9k9&?Iy*a@!?ax;ObVp8duhxlV zNh!wQ&qKW!dWdx!Lw2w)T!g4TegeM^3 zsGNCs4?zwu^7YKsg@8*ORXMNTPUWnJe|4Nlu~7VimOp>$z^KmWbCc3BWTL8c;VNF6 z!`h>Y7HLM5h$C$p9agk8CB`{7I_zFC;@-YZXU>eG_X9J<`_o4zW1L?njI@^48k196 zW{-tbYp$<`COhUtcPVxm9>x>+dGuhJ_R$Gc0=$nJGVd|r0;RrSR$KXX6<4D z@cdLsenn}1En#=n-QNru6Zy6dIKS?`9x+o-F4_J1+-Yr+d`G%LgqO`{ZF8Yx==OVR zLF~jt`D}Fvd`04npcGx~V3@Dk@DQ?mX!Wi2^z7W@LDuyu++eC}<~Z+VP~t*}xb()u zA9{X%qGs)B^8gzL&B}a#$y~?LvFeb2has zT+oO(gEIcy3T(O>uz#IF)f=AIG`xPKck^vIm)JZ$=F7R+Ba+5?dLeAq3S{Rw{h>Nn z$VWV{iE@!SOH4~qp*EvU=N+*g%cwq83E`?z850@&&=f)XIz)mKO;_B2d@C;<7f>iE zoZPkFZ;+azz}iKOIgf*0#d;6p{)2{FJW9?KWuuX4Y}@i?CUBbQ=kH(Yc+z>Fz|Cc6_-O}l0Cj<&V2PzGjRE<2eID09 zv>C^s>Ge^um}N6X=tIo6iH6OdBgI}=-zijb;Xpwi3NZ~gpzbD^TZ3B^!L2&alX4kF zd_cj4PTXertT{!HNE8gwb;OAKo_3EiA>v?ShrYC6xQJjzpAZCuz1jUa&Vh0NCAi(F z-l0};mmY|#Ru?3padoOGAlr1277?`~2lYoO1o?GMZEPiD^?{8n;H z-FYnbu(9LgA02;Rw|`u7vLu%`O0#Vkne0OwaDneoI~lDXQr#s_`0=Lzf`}m`%*(6= z&v}<+UnYLyI}sHIL^}#cndYs-@&#w(UZd}{n(FAP>iqMj#s7o+D`kcRd_s&Igtqf{11SDIC$MAp9fKjaJr#?J;8hFldC1PgUV@!#-!> zsJ~xVgwz$6kha*?X(b+`cto3a-xq6u7O5G*weLWALoKkE;$>R+|5YRO_KxqExQ+#FZ}fE8U&2hYa-_V0B4gW-Zu%K{f z2?!e8dP2Gp4Dj6Aik*7hI)CC#+^0?g;xGM4ooo0Cd#NGur&n`cx9TeK1I%=44Wdg3 z`3oFOK({5%`LZ&RQIc<`Ccguz!Y8{W zm6J44?BWtBrepOea^sL4_>pch}2WgSpeC!2yS}LX<)~T_STcg zM#|X(8Qk+~*o##@xt3ta0o@DMoKM%{@w4ISwg3D1tJsf`91>9%q+x3Q+d0W{sHwkv zdK!;~Pf8#C&+fC>1nHLD$!unCV_S~-4TU?(efF7*KJHbWWQ0AB-H|aF>2w>W{WlaC^ zQ_&->`aN08{(f~rW4d-!YkREOIyYXG`3u>fj;N4lHsj6>s5Y%1-6wSwbSE8fclA$D z(j6CXaunnD&U$?fC>42qL3n+_&l#2M6!o{>C(EwK!~abGj`usYiFwa`7ir%IG^cy`!0bteGMET*F4jHI{v^(EI(8%%Z_cMts z4pRc0K3{DA{9;h0%Y+_ry3hby7(=}zGZ*-i8k=P=<$yp{9ax-&S2P`#TEhQ_rIR20`Yq_kGV`iP-VD;QE6CUXMpIFgtzMg!dR@9Ph= zJHGlz@t6fOm)eeBawhFdjxY|fyuW+&klT0gzPr*WN#DeGWDg>gxJ?38qnX1=rt4y*R5{WdndEp^JOO5TmEx z=~)(Yo0<`SnhS+yyHAcOVOIfRGb+uaM-!y*dX_uqS{a&t*=38Sq4HYJTNC5A2t6+G zIrIfHp|;fBOZ-xxtxcZ%G}9AcFbzEBDRHt@R)iAQFOiflQte{jDEHiGgE|V%VJjFc z{J1?S(3-<3rQKKtG+SouatRC86c{{2E?|`u47E5A8SDU*k_I8+<6z6d z8(E>5D{#{jga6tRj>gd!C45Rc5Hb};zDXY<0Nl&uo+C&7B@;<>YV$0<#t(s&ma7mA z00hE|=9Ewj(<;-{p=RpGNCLZMA$A4%!3+Qpa?qGJ%?jl9l`pSndkPZ4w+_$(6G|mK z(}C(+xmU^hyaS^>t1Qf|9x3UcbN;cy%CCXJJts}uyeB!S9y3391(%X>una!O93GKt2-Fe#Uk&NGQ z>@XCLc#d$gP%CT|7)V^U<8fx@&Y8mH;OVZDU_qs?Bwp^_3R@?J1`6fI5_NSJUtn8P z(jei#7`gc5#u>mg5Zi+y*)0574;2q#)}huj{7l6Jb>p&xrpx*?&~$iAOZzOiL}x zKpeQ6GjyyZZ*pAKHBHkh`RmHAB(`kA?7CD0TIB|z4RZy6Epjq_4A~szDH3LfcDL_D z!>c!Y?`_1tKj*rZHr)6DreK19}{@4DG>`HDQt<9Qmnd zk>OL(`@rnBonZ;gvd5Wi1_B|n+~yYsW+g&hXGyfvQ5WFTXeam#I>fF5j82_`;iq&{ul9MK?b@Y!qIE=J4Eqlt zn{1@xEIi=Pg@oEx;H9WnCwSa1b8P@OVh`U^Rpmbl?J=yHe9P7DiDsWTIo>G9q8Wib zL`PRMri2D7BqTa(x}gd|AFKbvXOu%}_yK?uzj2)X)vj;b8IykQ?2sh9^{xJ01*+*8 z^p2uWauRv(6>?NIdtmVZHTC}mWI&t0C>At|0ME0jeadr9mw)A=r`_!nfyGB+1FwZi z#RhN+9wN~PBp9Oa@d$7glckK&R1Cb|j(Rl;;nY7h&e zO?8iYouk&9(qE6R{nNF1=DU(oZ@mq1Hb1?B@_5=^eW|Aj@_AfDB4x9}h8EBV=Rx%q zG+L{~G^GuX5=)vr1&wV#4=T95F6}eEBQ*61C;*I|azr=`!N3Y1pAjd%^JIlkLF<_O zjO^TZl52}z6+|i_5m%og#I#oS&bmEx)kOGdegO-rZeJK|PQ0NMi zjAd2dRW|-vu};lIlao~ay~}lz_(RDv0=Ksm*-SE2B7IGXuGC3x4q5?qJjx;JyOyue zij{rrliM<33ayGWDZd=X8w=@i#Jx;rlZ*(Z9_Yt1hcm}i&w*a_>S&osm9XNJ2dYsY zVxV1Z3$jcx2=#)-^8f!{-_I-*UmpGBS&^NtKzz9RP&}>G3kcXJ6@0qjGdR{Xwuj|* z0=+Cez)KyDE|6s+DbZJ$(B>}^)05FAh%;i#%kD$sLVPM6*YH#GYqnv4@5JE8oj zA%ff)oSb&{E@*Ag+@YIv(TZDD7!z2+p}S7qqm`5ckMG1P;U)d4t4>n`y7NE&y-=V2^c_5{4`y2&NC zX2fl?)h?R*kUPh- z1(m&q$oI2n*{H)(Y0Br=^NXiTRqUEk8lEX*I&otEExQQs&!++$oeNW)w+FV~?FKiB z>O3+3;Cx}W52DDcEuh!t%;#&pqVSjH9p)(#q3Ee=(5@m($>QNwF^^Acyfx{IT@lty!CHP8sdLRn>`vRtxm z!QW({PUKdL9h@8ZUB>#B;I=~`C(cUnn{5nIhk^&4kJ4Y!un-pmzdBY=rB^8{`hdCb zy=w(rt1iP=G*jyWaXCx@_OL ze0u74;1?)mK3W?T--=+ySN0zF#!n|vytu8Wr#kYxiizlCVz>jLa}odC;$v{WmP72f z-7*5<^Vd`f-8&X9$DjhAEZfx*vLZ;s>BMgOm$%39*@hpYWNxbQ=M4D$3L;_O4|ZGE z?zdm|y^VHtbx1@%P=EOOw_Ei6Hf8@76YW?t2WhL+THIR>!85zGNTpAfhTbl)IvV``h(#oW*K$b1H5#5AHFkIJ%#?|md4lVuGGrmj z0N~WPyPcc6lt+HapqwGWq|YN2Farl{vf;XFCn0+N>o@QP&Q6sPmya15G1d#LG+{|z zf)F{mm)L^JCOL`>6T;O&rW*&P=-dn&;dW3fO9=bFcny|XZzFKxV6P|*Wu4g!|Aa~T z+(M^99GidR|3+G3b2nTIPFnbixxa3|7t`DJRDG=FUj6>W{uYs44Cdn{7x;_X`BrTC z)kJ(E>udV+)friV9^M;oCN*R{m;v(OYr8|Nkgowj5hJI+EIFj*G5qZVrIg4OgVe3H z8KAk{%GzzL+qb56CJ(K;RV`xNPD$S&vuQZNo3vV6l=SmuD6in$l^&iD)FS5!iJrJT zEUtYnrHn{9Gt<^7aUDMuzgxM_Ejeu&REAOw!a426n^EGK6dhczITZ0kxIaxlFa%nw zcVgtdOQj8|AN71KA-~%#m+PFdGlXQzDcA@b%Q9s`k!MK)iTadq6RP~2$}W#D(MDk9 zwl_b$`T+s#dzK(?oeL(QEreS>te&Xbv6;*R_--1l8%K5}=|iC)S*3fU4@iV1+5B4t z=T;}XUdI9A{kcc`)8ZfK&bs(?z{%J=j$Jy(eq_yr&%Q<@?5@}-^(pwOSS$Ry? zNbvv6x#eAp5q8hgog*Z%JSM1*RwNPYk={MV;=JRXRE%leP}s3RUg{8d)ADSYWF7y& zTb(&-UGm)H?_bTg&pQOW*F*h|f=+v!&Z}8(_ibi8#Oq367YqMBT;=uqC?Zr(yM01$ zl7Guz(mdzltP~4}!W)a7CGU~V=fZC#!4z&mOunLbpmPS!&MT=Q+o7DPkaHQ5bq=n! z7hga@MW8gL!oHqlYksC961?f}WDCe_b{yH3VBg=3=b)#BQ6mXaMrE{xC z3fy~T07%H6YE!LqF6!=X*2B!{%fi&~@9qB4lCH!CuUBc0N;5!ZhLMlwZpxO8Z!Z7* z$-0$jvG8(v(R{xkMW3QhVtijy0sT(M3%K93)B8`5aN;@i8Bjla^b3U(9cj3_wM2CcS^>gjI(~DX81Pp1 z^}mjhD)9=3!M>9J14B-0m-f8o#xpbWWR`KVOr{*M`aLoPTKc*^tir#WzXebDq*s6N zTb%a6!CFA0sQH7c2fZl`XMs$lfxTgH@Yu~c@8Q-*2>dg|HNOEGhBs$lNf5303? z&3X}d{>@(+92BM-5hyKkBY-rs1k4lo)6eP-xf+}N&F#aA4>^pKdMAkb_*1(tw-)vr>R6``SWNu#g&sy%F$ZPH z#)`qHeFNtGQIC82D-~d}YP#$HyE)z~)Xvs?qA{cJR_7fRPy5<{!UmY)`Gs4}S!_^* zH@d`eC^F{g$?v4xri`&L<4dP43&w;$lv(|(KbUpI|1Uvb)CzJguN*HEhx?>x;E;_R4!Pt5>aUh$Sc>Y?lf4t&1wskBSfcLesvA#@4)qGLS@Kda;&2dAR3B zP#rCUvzP!^y`eLmr1BY8H|UY_Mu~Zfcfx+R&B#F&fqq{(z4O)-(K6{&C!XOy9gQU! zV*kP;C>Wqy9vbxj6^72V@4M-74-!{gPZOZ&V?d763_4WW<#hCE{;!$y9u~)qXCkoWyHb9md%6*>e14S^% zHHuy^=p%E1P{f=IFVglwb;u$p1aLxeoc;~yCW()DjRVm~Kz47ouy;+J8vGaa9a81- zc8t!UTF7fAQ=-pUiNA#^(cygjD2;^&DVMY7P(QSdcH#ks2+5G%;j#Cx)!52M>fJ1H zE)7j)S3d z&{~^hHsEU z-=FVILr-lfajNrln64?_)ILi&`%89{C_h}zSb2?)yibpBXJmy`vq8=qJghZh`?=n0 zst$lMj>gaxMGnOtok`f)%1W9Wn%wzY#ZZfM6{Br8NP)mru&ZgXu`Y`mL9c1A##~v! zm@Yr~>;-KI?fVKGAHxLTyUL+vUd^etW`?`-h0Ct9us6NoS6BWe zwy_4}lTPhdZfx@pnCiV4!7#fL1Zwl%kskJM?;sLiLsuIFQj$FAsf&!2VG1|4c6l|D z;D?OqVig)%7py!eCzbs=q`;sw5kkS641b=P}v`dy!KyDAVwBu7Xaa^ zFB=?Lc4f5hGV7J?=&KGLJ#o|W*O~MOP30$={qGo?4Lwl8?yu_y8GL_4gyrZT!BY%w zYIyrSk*|)9&VK~Y9T6E}|KN!+Wnu)AqM8c{DY9o7KjcqJD1hf1Ub@n-Sw(w07v#5D zX93QfnSACt0~g(3(pBwBzF{!%UyTY%7|@@ZriH>qIl&wPsjzDv(;r<>-mw{JurJro8=}(zYJ}Q9`xsx{SSWb=U6@r`VX^2`g)Vr$C1l z=(^t8cWsbHH&!?~UQ*~dahA;BlbsLNz0m%_=ieGZgkXDNlI)jz#tkZFCA>|SOYqh)k<s{6G zS>6K|J5-!lb_5^PWLNFAwT&XYYT9e#8+P8ds7kjoO0u9IetRl*``99%w*pIxOIV(c zE10c;kcen@8~UvOc?kw3YPbiLwglL-X6WTGl;J63wgnJ;Sy&U$Vl1%wI>=;nqIXiy z?W7DRaw+;0v^*fb1yh|CX}0p>WD3B6yGR_=LE~NWa@?M2@yUB*Z}k9-Fw@I^!FBZM zosB@@lW5un{5nCH$aKXut@3wwQvh{_e4g&O(598MtpIe$vj9f6qlWq~Tu^Wd1F*DZ zS%NeH){t6QU<7q=R92|@1yeubba!nW#0E9ox=>@i;m*@0n zrss%p>7i8h9K88nRnUMx>H!IIwcoCXjfob&9Q{j1fdxdQCJSR{2R)PwDPxdsqY%GF zM007j`Aj?+;11%|wEU-**VH^6B3S1^vN^8X@kR~zN{nEM3QwE|{%9u$owy34n=D8$ zLK8PSOLddPce;U}SH~^738>lluo?F)i*OK($JPRUp2xPuwFMe=V^C^jOvZBYJ|_ju zrK!+`93$3vn_NBn-*Z2J#W@5%}Kd2LEw(#{EBy4#Cs8j^0=dG{wu$dAlP1ySx)x+X12Uk z9bv#GtJVOxqMQHot5igJR>Q9Zl$M7{fKFMsOy^0X8bICHj!WUk(((CQ=s<>!_ZYP3uG!ds7*ZN ztaG!E&{FC!HDEa#3DKr%1~}s-Ff^d)Lr-T}f7_)nTY}=C&aHFL>-dm)iSN70Hq2Os z{bupChVO7#7b4itF+4BWA9=8}Pvy+Bwb2yaF5B~L{^pjwF$QRSf+b-fMXur! z7BuKxvs^cXDm%vH?2w@agy9)&b2oe5z&bClW8y?tske$^+xZxtEwL@I3u zVml?ef;sGD`mnzg)e{h~np7dm^o4RX7SujN!{00%HEI?D3Yr3^!ot}M0##*Zkg^Ml zLF%nIaXKm11EG(c;HLjg0EV*u6eZFmG))Div6x8AF8rUx#D2~$+|a)9S27~V&Rd=e zV_;7Von!Iy^7qcrPBUs#aEhNENL!k5)={)^&n3X!brJ3c2_d~d9rk#NEahrMQQ}xp z^b~495^s14ZdWQA9vwuxfolWigk?>H?N9ZKsa zx3I;|r6-<~GC|gcXfU-(vmFt#%HSVgR85Q*k2|Vg1D%8H6jdIYwMS6A@;6W@@GOWn zhEuoD9U7u`HxD*f4&83-TUY8Ey??fZ({-8qR#S|i?PQoRM+P1e$&Z>b0=k+};~}lo zKL5?nN&3o-KC?@`YFvr2j<*q^Zy}2E1yvf75=Xs2LDv3)D}XW->+g{aGkVl{3Yrzy zJ7~Xak@C|?v49T`O`{!qE^>DFm2iE`{;ES9DO{1O`ShNQ$x_-oz}oeuoa&``rKv5r zphQekzB6)cSHRGrgp+uWX&ab11KowX*@wv3dru!;tt9*c%P@OtG#@!)yo5Oq$*3~~ zBZ^;JXM9AN;P3tOO4i8*jS~QG=ArmT{jS7TqQQ=g@8`i(@GLF6B$DE7Joo2=C+}IB z5*Wp{nT%4)I(n`qoFud-5pYI|vPFx}G|cTMz0D6Itux5uty^|3*xF1gab+E83}IV`(9-CF%?02mGF%%jv%-jI*(1 z=sr5X0XF)~el7gZyF<=DmXMc>q9VtODVv#*=!540+)mK7{1`HNM#8?HI&kx$6QH{tEB+y^-->hP8ffwd(H!IC`h5Rox@@bPZA;X zIEUrTMm#-LuieLxHAY!D=>!ueATDZ~q!Y~L29_&+0CMlM&^25tKiI_ng7&{aQ|fL~ zllgDfw*yUag_ah6p)7PvcJyuZ%{1+1Q9g^)tszz8F=V;}cjtlCq`?f$Q z&zCYw-|-q??Xx|aUzYrv6U%FYTugxZc>7+TuMMOIG}+Jp#=i^|QOGLMyIaI2`9stt z#wkybZ`{mX0M{SQ0H-*LKbbfnAzdDphC(E{pyaCzaQO<{#x^lk>%h)9UcVYfmgF=3 zO+Jh7gO!F6E842#d;i1TZkCdMUpAL1#c}Cy-e;=G$f|RgjoB6Y_kyJy{_UNfW+`Jj zojC^3fx%`HWBXs+A&KJBumak&xbCoPIC#K(e1Buv85QO9<@&U=)IF}W=fhkS$8|NY z5PLcw+a}T}2dpO4z=cWM<7ZZyi&I}S{|iTXj>y6dh&k$4dPw<&s41Ce>M{+0v4}aR zDXw#U+5zqXHXD6fJp4h8|8oBc^+DS4&;Vq!_xb7J>%2F0vfR z2>D$EJXT?Q!1j}J*P(K<6D4hO7k9}$?|q6j@w6Ad z+wxrFIp_L#QN$6(BPQg~*%67WkcI8XW1h?6KZ6`C69ZpU=P!jlphu0cmk@;#V;&`6 z>QLgjY3tz5PlfvPI`-FL9eM_(c&AJXtNik2wdWg(6+Ag`DBqa+1t`b9^v0=}ITW#D zM><9)wGPj(vkZq>AkgfGNR$VWAX4lbg^l>1v?eky_q@4_X;x?TnFAnsg{fj2G|uil z!5ALSh@Aa=acue8b|K9=ow(T@KCk zjLRv;3=qh_^(gs=8&sbfHmraE6-@4yh&1N@CPb;cM{hvPQ; z_nea*E5O^}bQ(2w@LJBwD!joIilamr-Jm$D7ow zY%qAVx!Jx^o5W@hgGt6}hC^9U|42!UZF{0f)cDH*U^D`&;U!?L*{cJ=IJ~e=UZQ>s zX|7-g3P_X@j6ejbfDm#}b%+jW9QAJMF z!e%wA6}T9L_ZEjt65xC1kVG49#Jj3SrIz2(nLHlu`+yT7+wlpek z-KaN3Vf~cfdG!cGM%n;9Ub`{qy)JKA#Yz>W^jv4zV(v#h2$Z=X;82k1XjSw@aOBe( z$~s6x;a@^BQAcV${lYmi{>Fq!msSoFr5N08a`Yya)}Dgn_EjISWa!2OmJ-k|=#Uwa zv!uZR7^fCx75WfJYQXeFs|s)5`A-mg!@YV-y^8P~qrU<|7x_0H&z`-inJ6B-F9p3a z)h46*Pet0W)nZLQzlm$4?5xlzeo>Z|u49xdfNo1XznSXeBJMvJkPCoz2^19W}{2>sb)`~X;a1dPyT3T-fDi>|8n1i+R9SZ;x z9_{kGl<7Wav4t0Iqgza+T-aM_*jU&U)HZz`?pznL;bMOjtS6$v%%f^oOBh2}{(4bk z?CGfiHn4F{33WgewmTt32mk~=pLvEj;B1%}Gkd!%OL{jht(V1rQx@B&Juku9x7!d> zV4#c&g$q0GJtsoyKX8IB7dsdj(`T7UpSG^1yQ`sfcO0`F8B3@@BQK_S!OAD;nU|OMe~Iu;rDoqorOc7Rbq>PH`m=fSwobpG7A4cT zYu`lkyLvOYBr7i@tu%ZNZfYn+c!y1QGVr?T3XUINB>Fz)nZ2kxih67HiqmZ~QcW63 zu-Bn~pk;FuZ+OcUxmf9rHGuC`j65lPDZ@zLGjqOsNY;(8i~^<(iwuh#)EK(h%zP4P zlE4M=i&t>Dl(26YJCEzo4+&#U1huOZm?rF<#eO{IGT3LtzV#RYSFUVWs|^I-b@q(r zS8MlvZbxUXx2ifA^8IIaenZoB-GLP>(*e6M;?_+Tx6$Q#*Y?tZ+1FwoJ++f4S)7nB z_OHG@a^GkI*Q9f4p5Y05%ng3i1^uvcq1fCTj-aNT14I=~m`~B)Nln>mzDSs+TL(RC z<4f|LjDB?@OXEXGcuXW0pCqGE3dag-0TZT()Tja`tyN< z@fiBVyK%8tPC0M=*VjTD^HB%a@%nP$?~3wxvjuC;~VQ7 zG4{|Y+S?hrYp}q$WPCQ=4{nQ40>K10h3Z^eY(21BU9>PeXMeLNlo~cNuY|*^%?)ax!I%gD7qh6-zj+gM;yZIPb&;8A29E*K*CM#h$}@Vfz@GRvAD z-z@*u8?VTc`J!~db>WLm#*$|)fGb~$Y5)}f!`x88ASl;2Z5zlvmz#I=-(N-kB7@@p zoUv@Zp923>U>18?G91e5^?cRgDmeyduA96`#now$0Op!Oaw%;xm86M}FO0ZLv(~zr zrZ9n3f8)F+KaZo_r*Cg69?wt*NYL8jyrt$EIua+Yk5~QFJ8y7wbtJJ|0|!D zE5i4O#IgQy>L&@^vQu(>Ni9i(x!792pjxgM#J}bv7z1F(_p%Z0O??q_^*YCz*=9rG zrpIaDRTDBQusLn=L=QDxMx?%dp*z0`*TXwa0vv07qd}@b{Yq|zzg(vRSLDS1{q=ug zf_?P|t3T%8+MCD2()I~5XP+LQ6y^wJDl_qV&nf3FP8%Z+4p9{G9|(VXlqd^D@fD-(K`zV!(%Pi1rki zydqLjkb6WQtaHt@Eu#PU2LRQ$FXUOq1Uk_;S6LBKs z3R(aNX;JCj7y*%j3K5>OcfHBt!tT!3OYfL3-xF_&ttuh#t0BucZucJlx`Nrpg_a`$8-a=);V>0TnvSpFWh8l@FdT4iRtSj9&K68{5b3NX3fW9`Z}sAdH_mO1C-}1p;Xcl zYIYb_w{5P9F8IRol+?t!E|z<8V+njj&np>XU#SU|--Ri-t+C6klbCt^gw~;8eG>)D zn}VWafo;7+1;1q$Hs-f?`Tux9l;KmBC;~&h-oCVZ?;#{ng;MBqq_v~1kZgj+K7J2` zQV}pc^y7ExQt=I#a~PrX&4PQH#tQUsJ(GbdVj$%!agCot&?`PJi^CRM6s+m=Znpg@ z-H+ZFQIC^@`tA5_Eks$ePgsOXH-glP>HhMEW!=YyKo$4*>n}@g^~~_KnvqSH(G)%n zPRHGtH#&$v$U`qr0j?QSyBmVfyIY0sn?!uSKT*5;8i3eES33*euj2bxvLu)jqad&4 z`|U;dXh%PcA35ZvXJlIZR*tLD5Wdw8{D%))vW9q2Il9L-=u%=F5nmON4}IpDVQkPd zK~2a>`j~8^+BUJL^t^SHind;{dAgM#KuL=?!2N6WO-iGg*_&ok(f%FdR}fYB@H5mHO%iC2_&U^ z`M#NTa6_$eckQ?Nq1al=o(LtYa_)-zW1n@^(nq@1)jHalVur}ZeV=YKr48$6e%%Um z$rTUVj?AQ9pH$$<-Mh#bvJiEHx=pp+UaK>1PwAWaun+^L^OFQgs(Fx%)y^<~cw@#y z(VoMA?L@GCpVMjh)hK1UfEIpTqQ{--?zXAIZed8CVXFEocyX}P1m&EMU{V|R#tDH0 zEOiW+#6IL2@xYu+0`KXhToQ}OLCgY6__AkZ)x$6T`xkpGtF*AA9Z!@Tn@w(#h}Qn$ z^fg62WsrB3aOa#81Hl&H>aEL3ni`TyliinkqS`$HlfmGHu)D$~HOaQ~8)F`5D*F5F zxjPsHPvWY5#idE>FkIRA=q&k!P!opTLYph;^x+xO`1jP0L`yQjN&h6WA>I>RgZtDY z*^!bES>%p*)Wb^H%!*|I!86b=IOZ}>a@pfgq}hh-K1(y?)9oDgmd#ndAtMrRsGNtr z?zkRXR(!>&&9WdqGsmQ^oAT9tT-AFEZ6PQ~TL;6y6WE)P{d5@#=3Z4S#f6ef@xX@W zL6{7Xp_8SId;e4FqRN#t>he%(fj~(p#f|E0Gp1`iWmuWRlnw7G%_CizW~ZIJzj#70 zZRK+&9r8hmP8(c6*Wi!A{(A=~KjX=6%efDQZ*m^h`QQ*DTSI~O5#8A!vM|kipTazP zj^OBCk?j4jHDY)i_8(FjAC&*Yw<%1g+Udv13vm(cW~i_-0+&=)>_~1L5$4Qvm1}|r z(6k3(e2}&wL)MXuIi5`Si$G5eUr>x|R$Fe+?<)g0P}

A;nk{IwEjp#KRY{rXyp5q&0C1j~G>Hj^&DlRLsx#FB{v)0*kKmC+F6% z)B#T&f_l2AKyQ#*Q|gS%6`-Ruo3_B|5%g}E>N;X2$t4n+Q(^io6G3MgqCfXbRZexk zYd0?*(HFURKC__7!A>l^Cgz8cZb_QU#y9~1aq&##p5Xc2w>6VNm7|k@PLu>AmyN=iI&mm zB##Bbo=`@|k*xInV@N~Fnt_%sEtKZLM5QuRQ(5ylIrJZRb)^LRvlHO`)Cqs1zmt8# z6JW4=97WKC62Ni3fnIUXG?nZoO-p#)JDFaOs|1?)@0muJfbsb1W2vYuEmY{~LmLzU z?9h&CKBg-_#Tq*EkX`fJWKxk&+wdbd3Uu&sC7qM(`FDFfIZbE~en*?Q!)1O!#1Edz zAg-mP_4oWBQvk31#s;FiTjz*qe)u;(UoK!SBTmglx zJR6-yJ`PW?^?k>%KB9jJ`X?G>aSZ>pm7+A7s|--;j)Bs-N;Z9@xSm+uEZF(Gpag)K zN5q2HJ2@IaMa1CrL+`mu^c zDiKl48xP9aPXae0TIC3m%K2Deq0!1@KVX{P6pd&yD*V#zmKw(`^o%V0H%t-?N#UTR z)s=RN(%Q#-nc{54q@y$laF<1QkrJ05ByFA?VNr@=Nrk?D^9kE^#;>%ltSg9un(RI{ zH9*8mJ^?NIf(4fKIX{`Fe2}pL7PMYu`r=CdB~FfdWW?I2sryssIk$e&_{fJK>5@abuR-EgiUe1ij7p7&!h*F;X;TY zTMMYw$8eo~PNGaNdszM{Q6Lq%GN+HNGNfr!HzQ9shxOJwAGAw&CcD&lWZV$o&ZxaD zU~8jZ3dwg32AO`p*fQ~eb;aHam0m?6L%=&YIM6lVReD{{yV-Qubr=$cOSPZ)HYqG1 z_8yh$P?#6A9glVs0%J=yDz5E=jDMoF&v<8|>Pl27jI=~!2o|trMnT?4ty_c5SnEzk zu4&vPRAOf-&9Q163N)z(TVi|&`P7;`xE3+Opjguc*D`uS>>G?h5+UMW6fvOMvXRzn zfwnD)7V!Fb%2Ek}`9T#ck1j|qL}anKdnHdS2t^0OJKlCYKRgK5`h`TP9E`v_pzU`G z+^QEvmKDw*Y$a!>bMbyi%$l=#AgTo<>PZ+RgvGceQJ}{lVcRQp6Ep_n?Q*q4|F|o@ z|2vu$HV}RVQ1SJpGV)d7g?3VIPGXQNASLnhY{xSdOU2nXJ8;Y8?dvX|DW#?fA(8l$kCs} zeYxQn50h=$U%`V%33M}N+=w;6&L4S`n{ix(iP-Ulb$M% z)$kz4fj+P~Vv_-sYypA@H1a^p%eSpFO*elrf0!!=KZM~d|GfCIamjc)#GbcfZxTd0 zHIkCidGBwfOO~f}Lu_YFe`d4N1#X<|skN4Bj0K=eWX*Rs-^tO@;ET7?ItEk}M>~Xy zKuA@iF8!DcA#H!!qBY*%&v~(}a?4(f_@W>6BXUiF;GRsvCte?}D_6JyAIPP?<&7gz zT*|l99mQ{pLEjSK91@zFBC zt_v2YiBg3a3$hdHqxt_EoTg7DR4Yfd7fb|*8Q+LY6%2vEHtLeHf@pbj4F)ScoOhYb6*Y}bX>)?29?QPF zYl}hh?8<(HxL}5|$?siA+OfuBrHWtMS^0!a{h0+oX~9Bejohw0P5`$$LU858BTp@H za&4UX%}Ntzw#BPb7ft~ubNfUeKD~ax5J~fRV99Ip`vT*Cq)n&pzVf6-Lv~76sqr_mn{X7pdg<@rbRU< zhX4T!0vMa2_x|;ZHag7?RYZM!D;d>4%vA>Rv`~(8DlVn!Ktu#^ z>g?wU00QQRg(2N&ayV`8ocGq0$@#RhD$6?VbJyrFwm5^g(hhFbRWjE~5j=;hSJ`*` z1>5c?fHvohe!x((bwtf@)K%hOHvFsX=52^b{&+67CUvpY%u$^XW z(a5xwWBO4>1~A7K7HNm}0ejYh$z#AG#>E>~hrH|Cfs40k()H7Cq~9%(was9NPM;RA zW7KIRMD@LxsMRxH)Kp%U1500;Har*S<_|C%#u_^_&hNz!0D9XU0^n~m!Tx*B6tXFO zbjMo%UGSf@htAr8G|}9F*d(lC%Jm(+VW9lk zHdAcChP_`+AxC3UAmeEQR#q1(w{!L#b23P_9&6&>bfCxZp-lS%U;DpO?^4hG%@%|*(Xw`s7UctN5Gv4f;R);+5eat$)n~M+R z8YuNY9#Qyj(C|K{W|ukD?0AWSGhB4I0&|M(1FyO`UR<%z?!<1LIxcji1hX3C`9?Rh z_X9(5_iumVD^tMIAY>?M3}zV7QoEQ(L|cE-uWN0z2d1JFVcjR6qiocU%yc@g(Zf!h z9_*oyp*+EQLVobSh{Ak_hmpt|W%p*j2E5Jg^3D3|1ug&KPtOcqJdk4NTLf>C=L|S4 zj^-z!?tUuLjQ$8P!ex{{F4-aGg~#OrwYarS6Wi3JYd^u z`Ttd8=zvlc%K0xA{*uE%>C{d^@JB$JzS>Lt-aKy`<$%_@hkTii1OvYiv5}~lq;xPJ zyD$JKASMiW3Q7U+Uw{DcLC!EB1gd~I@C3A>e7#BZy!N6iOCy3dS101dMGjF8ImBeS?nd@Cw` zhzL0xRURZ(7`1rtt%cIar~m)}Q`dQ&|NnldKmYy-|NI!A$whJ7czr53AzNr8jt5fS zwxy%AO?g1fbWTv7yl4acG3071ZMjsYydE*eN%!K=7_Vw!c)3l!*6W072#~bhT$ug{ zWz&tt=etpJN}W(jYR4LI4Wt?{0uqitv4!BiS6?aS@%R6mucS@ByPcyEL-d)H`iAWy zSupU2J9uFjDMBsv=M-g>X5~p6LUnS8Cm#9!!Rtq%h^_UI5;AN|*CsGPB%lC(<%dCZ z2U4`}W_E9Db-I-_deC%O`vx8mQ+eNoM76XXOzd9f!EC2(?`k(a9swaJyJy;1NE3I? zoD@xJn+lJs{v|Sa4AhfS6jUGa{mgQmr`KMv??2zKbcr+4utcl@2x|>Ob+WlY`_g;b z=COj6)&ozN9`JOmDfgBL#2fEQhg-UN%_ zp^1w=i*>hAIxf>oWx-<2b)yryvnLywS$=5}0DS zVQ44Qcu(t6!B=4(YtYtnvWXv)3G&$qp14k8&|x;^^B}j}8_%idrF8!({HBiseF5+C zf9T-iw+ud|WX(Y7)5eV~4+aC9xvO(NYfa*v`HCH~4Qk(S?qn?wM6#--5=a$SWoPoDw?(VZ3^y;&^ufs>Np!-cA<%8p4TK9JGmaJ%h*$q+^N+>YuNkB@WHAcJh;G(-BHx6OaE(sqAR0H^V}&od`26nyhywQT;-&6^fGMrZ3T9&a9fF ztU`kYH%RSjeFad~#;>~m=79an$+zsYQ<9J_Yryc7pk=GoKqlfv|DSaW2GH@Qd}DT= z4Y?9>@D&-xozjcUIY5f%1MZ%+sb2ebvAS|870lC6XVf%;-@F9Ezu!PcRP3(enjKX5?Cu zfbGbzM5A+aa0U*R@5Kx&Oi$}yy~1D=ZVP3~_(S2ZxGI)tqKtc8Z_j{78k~$^5qqDO zd3)VG6D*6tQDM`XOXvu2>d;^C!VWu~>iiTrNMdKFDH#j>Y^vU=T!Z2mY%H-^oRc~z ze70p-N`C%gWl2wM_D1u{#UxVrjQCVa3RYYG)0>Qx>xutf{hR?r=-HuF+xJe< z-Trz!su`+eYS{S@;S+!+Sc3-cwTkqH&~|nqOvHmVK!@NuR98l5uHE zZaGXXY|Ca@V2?y5Y|;UN*Jb=$zc{d2PLB+fLo7_KefcMPCjKc{|N3tV zN{i+@J8K^T#)sdBRGH3DB=Exl0w#|jAV)UAB2|}d2u&yJ4CW%01n8vo?%E?p0CheS z(I#ku3lFq2vXxDdJtAPlD>o+oi>FyxBJvk2bPkL8o zcX!*1)wjIZo@;IOLeb_rf8u+6Uh(&&G0a3c1EuLVDfQQt7Bm@3@hB~Sp}bwcaQrs* z*?yNjQH9WA1*9AJUw>~e|B`n4UX_)vjbcQ%*Bsboo5p3yHl7)CDt@>pT+EL#&JN{V59#@Az4W!(RGzW3qE3sP)J0$%lpv(T**q1CRr;$ zZv`ew`}Y{=3zgF$#{lsgE+_ikJ;huI(7gYM^ncsWD_Akb$Wai+oiQR&Ay*j>+LB7C zfqyGgw}pkZiP}hHfQ{PE1b_H)8Afdmm<}#r3ac0)DqdcCR-Nw&W-*4-(oJ~B1fy6N z@_c@cB!h<2N@Y0co*t`k?MLVp`?@y8{iUI4n|eDDKwq09^Zxa}l$g3e7BeTpB zVl=)pNOdpn$E_;?;=@ipc!qhH5XoH4^c8a|3Nj+LG^MW1D1Ik!ua5hrTNVi07alsS zy|&*U<8DZ@hZ*SL8$w@V(Df~3n-3-k!1bwfY3etYS40#Fph1yEJ(Vl~E*vdxm6(1H zp#S+ExJ5eEt6cV`cT>T>fEIM@1P$Ni`*8QgmSqcD&Dxjic-*L)X2P7HY?BYuhkpFj zx381{x|v~-jVm9JO+6*gz2(Olh1Q}NkurC1uJLP2_`Ey=5{`)B;W1$$I5VeurAbu$ zOWD@-X%zT7KjluaH5O3s&((v3A|et5kJUOl@NkzwIMJXuIp0VCeH3PFyLtrSr7P(^ z1+dgwx+L^%)<{a4Sa#x#jSiM9RZ)=yD_db%A24xi7p~NLvQW#p)qrXf-YzHgR08t#>pB9UwEgE+|^HXHFUIi3WJ zFsU{-6@Zs#S{@Q-CzZDXo1})njS}1Z|JdDCF6mWziNhy7#^5M7)h|7Ue9IG4cGznp z#o557^^JYxO)~T_#QvS4J=-Y4uXvgea8A$t#bLO-ho01}i7DevP@ zVl{|yQ@!TG!GYXe|L->@LAIU)Drzm_G6LUsh58&D#2ni0B$G5F1Y+x1?5g4zpC7RKagtNfcshrlg^4hq>7zn^0X?k+XIfp$Iq1n zzidx%XF_+i(1U-Gt}9XMu8K-^Sl1uL*S;d*2d%3B1n_uo5%~!aWVXcC$&dI2sQ*ihmC-ET*zqhd%)qq8~v*C)BpQwW5OxXD4un6O0>sLxh9 zPj-vdD{ZfHT}TV;iN~9AM(-VjYPgm#%E`rG%QD#uKq5RF%F5wi0O0eVgN1m05{vC_ zerHO!##E$0#S5ChuCQu&_dL2Z9Jl*r)hFGG9F%uDtx<6~npiWi%HBe+srhusfB+*_ z1XR{#WN}x&7H1m+le}6S>vOV0$Ex7XmiY<8B4lW8rNoabD^eJ1IfpGS(|9`l^@h7IYe{_zFiu~`p`OO&) z^WZJ!NB>w`5j5q#fBx_nQxi}ubvX`;Xs~fv0X39X!I-Hgjcx>&c3k=Yr7y1; zpXMNnl}9tjJ6LQYx|d4;4;>2f(K1ty@0;yI_wZxZYE{_uK-)N zg3%9%{$c&Iq?13vXJ&A>IlR-Okz_^HV!~a-FX6XyhTH#GOJK5>ReG|Lw~1JZ>$IG{ z6UTDh|8s^C3~E)o!X-_vnhF!oa{U7S&6BJOy#W`UX%+Ms<%8}APtHowg$&vyaokc! z`4UAn^gDtEYpP=|`$hpE41oxQ;PHbY*fM{!m=X|wtPP1vLLtzdJzJ~_dDLsMV-`J2 zMk-zd1xJN!w6e!z<%=|TzUn&d?;__BG-yImYSn2}JqTiW9zCg#T(ogV-5ztfxxyTB zQ{4T$1K#S%<7|fz%YG+HUT1hPIXN;h>FK6AwLMAFi~$E3r4CqSxblUQIl<_FXe5+J2Q}$}XQnCqOS12|4;8y@N@N+cd}j6W0|Sz;%%Z zz&pg|`;aM@gO&yKgOb_3Z(xX#mmO0!qm7w8UMcU2{j4yV=yd&3{DyC<3x6QRKt2|& zEys&G5L`4FP?u3%?~OD0L_}ld_D78j+Jq6klzSg{*?7xG+mobvnC40Lr8GmcF8hx& zI%3K5E8_Zw#|iM9;yD1cIM_DkNJT3$83dp4rHNcYvbji?GHtl5cTOEwhbz}PAPdc!c~TYPrcV=%D`84 zIImzr|H1w83b9{|BE`mzb!_1Q7TSfLe5B@9!!ByJQ@ z-R1U+9z5O8fl!wbQU?rchb`*20dhXSTh_ z$$xpVvF4Jv{nw1qV)_G6DH+cNIrf(0rs>spkGvS7Lru0N{V+e{$HDm(-{NKVg7M+( zELhD@clxexs<@b_TiB!`=iXD5l+b$0{L759U^A8xB!K(5z7d2li0Tz zGYpTvj-hEl*YL7kJX$-_2blsUVyIv^SvwG?wIq(9*{z%Iq} z<(NwP^uG*1&T@tI127aT*3N`jW8ar5?7#m!Rk$ZY7@YXNDB5}s9yFUngY|BGRV4&5 z{tt&G5{3_qw#=~2;-*D7&!_e z*3ZaHbyp8Co2r)+kWqpsi7p0UQbB;C0`TZ%z9=xBCuflxrf%J!?9*Kg;wtsW2~PhVJDDZvczg+*p#~} z|B{3(0HnD@S4q!`=W`vlYeoW;NDbk~kzLU~NW<(E49v6`aLYCvF+#r3lvKfDOS=Xr&dr%h^Ws z6IY7^JjhuSS1#r<89K=z=$f9!{yuy>MZXm6rDHY00&jir>{&qfE*ub)9J|_@j#B zp)~a=dJTwP9U8FI3}Z%Q%;#6bbS*NRolV6PGcAkeQAAZJcI~=q1O7Jb*-3~-%p$0z zo1io+K^D?I?`(Gp2|4`lfvJK_E3gO=yczDXf+qY51|+=rzHB+diF`$Zv8R+#Qz*ys zFw%7ujQ#!%6IOGgl|Nb0I7b_xtDkwe17&`{FWdu^_m(dJm!|+oZ65AYT?FZ0VJ6ewy*vgD-KQ-Jk> zriq&FhCo-y=yl#v1>0Zg91`oK>a^eCl7a0i(XYKha+ z!-#7#`iER?z7lj&gmX!uo9%h4+@=jQsQvMZ3_4nfW|F>8IAx~{D}9q09WwBAEF%Zj zUhM(8U~p*896b!ujq###+pl%-6k2q9I1Y!fB78oQ1hmYicb}AqIe)IRq)%V^+RcNo z-%KXq)~@WR38IuD1|xyWF<8ykLO#TKOvjLYp`(bh;ffTfnPe6&KU;}~xpNqAl!;sHt81pI{?3kbnUTH$&qL4w@Y9pH`D>ZL zXjhD@GQQ;ub_Vd4X3ZoXV(4L_axJPDM;m6O*{b9J(lue;w~YVD-_cRE!(X~QsI>R# z?|_V>{DQBaU-c=pI(b^=QaYV&qb-Ftwo!5$&BtzNYQ=r`N=5ik5W{Ia6`}naVoWg6obGmdU@pQJGdW zb1fFeJ;{|(yeMjhlV*!#cksLr_QsF4jG<6q-1`EN3F_;GZHuKTmMs%eVI;325*FJZ zrH`fMC#jA_8Uu(6-NZ>CL=Ftv(D}j`Gc??mS5AiySd1yW^(e=at7ZK5pquBRKeq5G z-|3BC*ppO2^$S$=2O$6wt*=7WDsw89`h*{d`nH=Sa>(v1Q0kOVVV0sFe0q13z$d|ys`R8-DF$E**8>JHGm;7uw=s0|0f+wFH z*k?q9VFQ(9_$YBhm)6C+=kO$kV8)7;Ki;v6b~b-rXBAa7GEtXk01b+ywHypbiqYQw@Ou z*$e;<;M5N+>zJbT$(ef#<&X~1k$_DISA*Xc32)JH4Kq{^AG`NhsN4aAm0CDkPxRzX z;Xxc;tji7im`wFF3dLt@Zh6Xo^curGTw#*U5)|a9V2yM5pXwb7jH>*8Z5``s{i9cu zfTqcPNDfNG<59bjT1Y1>M#y+tLB?3eU*Ul#Q%c48P3AS$T=n-kCte9gkK%5rBdK{4 z0FORS!Q;35--buP=8&K{LFj*Y?KWq-o9q^Um(2Yw4XoxQYy0{qW)7yof6LJoz=I5_ zmyQ)`?j58DjOAbFYmZ&kU(wjD!1;1hiMp7p5MnCR{(5Rgn~~VwnSKOz&DNaN&;K-K z8d~ow6CYV3P(>4Cys)*J6#X%@fVoD*D}7%%d@Ff9*PO`y*+JX7&6dg%KZsFr$skId zMy#!InKsxDvmkQ{pQ|!G*Nuz8Pd~z!(UqEDy|0_!(n`3`o42{?h_?c3rqkc4;*!6o z!0739bADJ$_qbuG0k5ZxfS*L=U0^5Fz=e5&RgiKo9m}UArRtFjc50nOKarR2`^l&5 z(j=GjY%O*()+-XD-dn!_1Q|XabMPm@Ui{v5+$ zR?6@WDojlEN|EF=Pcf#n%Vi=o?>FsY*1_LwhsiufoZ~kl6QaL{Bw#7JbqG=t$P!jl zlSN4d1^9^$e#K>F7WI@lj`h3pF6L0@c#vG-^Bn51xdpnot$B7GHt^QhMyI8eVwuz* z^Iz+!l0;x@`s01Csi}9k_1@>jNHu;3>HdoNeQGPW%~VbOfjB*0X6KI1|DA;FuFNj0 zA49W$&$jr8*vG)SBO`*lBj0@C7zrAi>LeIRwXj$fv@nPbDItyCJfrXni~Wz-{^JT} z@eD_9V3WTn3d~ewiV&UBR}x+SdSI;qL^=OiBs@LLoO1cWZp-NFYol;GaWXfa;oHm& zU?P2exf-t=l~(_~he5}r2OI({sP&*W#d;U(fD&cyi5S4lPH zwJJFG7Q}S_?t3sMS}*eNqY2SoI!iN$)i5Q`sMXQaOij&dy(?>c`h8Y%CDR`ai5%39 z!VAdl+H-?o9(66e+DhuP`|Wb!^|FhgBTB|TJe#}q!Fmd8YMs+ta0-bh1uG%?t*y1xz_Gm7?c;!xBZtIA-i=620KI-mQ4E7Ue zD^vSu?!MbEjY;7ambXF#%ON7&XX-?#gQL21y^_cs*Z!VL8xaHA|ZYIJ}6QmIbMmj=?+ z)`amT0DaB$Z{|^EF$k8BBvFd^wg@SlRqO=T6#@!56;}ZVRA@z>an8%RMHz0oI_uWjy24DdHff0u+4o+V?>B`sWA79t=Lti>*a_jZnsFEK3ezc z^d}*c$JPA^E}4Dei$r6O{H67FeM~g>5M{DUm`QvwoFxIL-iXR8EZSbW-XU-R%-&NFGrErsy&`tkqM6i+ohPl}k(0pOAoAqV2t zOCaKkW4->M?K~s9#WDsFkB;_zJD;{3`PLANs9m;X%i z1U^Cy6)O$N@+>wyyU0g1;308-39{dOgZ>r^^%qLApSZ_xu4eSRzhe>;4e}+N9oh*q z2_FD!OEvG|+^KSIjaU8?j`7DE1}L_V=YDE-I#ved6nIIFzue;4u#?)#|C7s$Pu7(z zU2~iKMAXGM#B!hE9RH5gP+j&;7U(A}l~)jNf*AO46XTkM2AfpXICRuvlERHQc8idi zQ206adf&34fvd;y6yK;Hn@Y6|h=4ja>n$y({Z%jP6f%+9_8r;IZjZQ>lI+k(Y-OU` zZa&fCYB^%!(pt|Avs?(iB0r=YJ!)5;Hz8(_zD~ zQ3>80+1Lopcpfo*$7hJ_KP?_Z=N!3Xxb~27^4D%gYdMt)$mh@<8?r3`DlG7^iwm+J z8D&6#R==T9;ry%Gw4vTCQ+!zj2gcB1&>jQYR*Tam?NhU^kLpk8o@(mwrNjJtd_A=G zijw?s`C7>GMUGyFG`f~~TFgy3<46TAhT1bmHfBqr23W{VFnsRVfq^BA|F|5nCe9)d zYLJuX6kL}$vsKeOvq(^IkMEm`PFj&XYco3{S7|Ss`7(-&BK}BLeE;C>%UM$`SP{xPy;MNu(e{awa8X9oKOFu;P92(|5fUoT|uA{V%Esj zU-Hb)he*V_lx)1HW(Ym6G?cxCq!nN@SBIpr*niU|ECk3lwb5L>D*RR9Fyt=v5~^I- z({vo5A-`Xwq=lnYWAV>nBfYj;sM{k3!QQG=;#LDb;>HA`LP^9tS5v2!)O%tH=&JL&4AvCLj*9m1GY$Pw78}p>D^Gi1RHlZ=?5YHG%Y2_RX>o8Hw=ePv5BF?ci%B$@hax)w8qmvML%Vbttf{;c=K;x3Qs9+%Tfh{A|2wv z%vGzsrYToqYXF#UYL2jG6Sywj={-?A4Y+TZZmY`Ws;rLf7*IK{+P`XYCEyMs(8ZeT zhhodfq~^{i|LJe%KN{eWX33d$P%In6aT=ns!_zWF(`J(>#Vn-v5YMvCy^*un)KkuQOppYoZgd^fi|4=o04pJ?oL|LL#oxQK>6 zx5#h1;Os7lWYUyO+Oy_=;&2pK@kbei%X`(y=?c$4|xnIUr>$YLx@} z5OhhxR#tt@**ay+H zxtdb^%ABVw8{q!DY3Kb}6zvP)gqPdCXU7Q~o!f#2<$H3WTHg5~;j04KbBKy*3#1 zo^GQ^0$*kE_9T8Jr)3mg(X&ssXj`@XAc(#)Q~op308Y2I>u@N|yn!OP=%cw{KhUHH zNrdE}*-q8~hmvySE3=BJ(n<)yxCA=65bq6m*M||-5U8e{dNY+G^6DhURbn1tvd^NE ze=>0p6MZ(1AstoL zQB&xTiw0nYeYyD1(8wi9%70UUKlwjv)kA@5AQnCscC3i{@JtfD5R96_GFBczN&i z_96Ri1rz4LH7b0Rfh(WvB#}xoy{OSOiiL8E(<1UlB;~`MxvN`p7PO8AzGrnb3gG=e z1crwbU3{qVSdvQrAEcy-F_`1hgJr1AB4vOW7&HHU`dD92~xpCJObvwGgT#kzzF5>BEfDP^|-Q?TH+Er_w{Kw_&66U|pZ4eLhl%OF-gds_z z#RZSnGJ6|XtV1aj)Z|I9TdAb3@aBLg1G(=q3n%2(D~~iO%G=^9E(yQ~2)06+PE4zw zO>0iZ6w+Mky-#C~(O!`AAXZTa&hB$)rIpn|t~R^7hr(uW{i8n-dLd+{A&N-pfbb}` zL!EtAJAN-5V?&i7SMJJ-OlqE8L+g)UX)|7e(&8WxW?>USE7V_*Z2@18?s2&OQ=>p zV2jVOo1Xf$oc@oSu|Nm`xTDPcBhndD5zv0i67gst32!Y-OAWEc<_lHKW~u=Dro!Eg z02Ao&|Iw_6(Q}t|{jdJY*Twpf*NSX#Fw~b$m<~B{bgzCHfs9~tgxpeEGHV~4*>?Q5 zfiE?&;*O8jvSXfD8XCSgCjM#Nou;$1T5ak8*7`*KcI zTdVOg^AO>DwW!~AjNkKhH33{ci^9`+HLyaKoqK<5O*!i$XGDr-2QLR+TVJJt9Cgs$X)D-R` zR&xGyXDljb8|+(I{Yo$2ht-lLU_xKzKs^zg40Cr?>P%>V(U%MhFC+2XjL>e#rG#Uq znv+)v{GzUAMLpQArdVS-jMm2NGn2|34Czzo$*aL;7-mCLzQ@mRtalc4=C=ZzM&0&! zmu7!?ER=z)7mgZR77Nh4I1BD@HllS5 zpE3*os~6|iCzF98+jQFgrL~!)_QKtSRIEM4&4vS2W;x6O=F`nHC&nN-^J)xUCr+BVN&x4>FGDf2Mm6ss; z;2s%M;9OrDEws7V$;_R&*RHXf?a$E&tLbOGVn#2jUEuJ;-WQ{9Aqzxgmgc`?6it)e z5x=m4-(#2;|1ZeMq1-yOSZB1dK54|f%@q%wBZhO30?i_yG%NY%QyPonF(cCR=~?KYA+v zCc%`X$KbLCG4}sRE^yWP3gi8)qgA)}%rg#+G#Sq^e64Y>qd4rjUC!g_x=^e(P8qdp z70lY$@!g)umUTm}cF2+j;+O!AZdI@@{;CpN;#^BF)%KLE(V|yqQgPM*2C;SuHsWnW zu!Qf`U4p@*Fs@RB2)Y#ktiGz`kI1jJP%!v#QVqgD#6SPO2zb&!kbTeIUSGzllZ<0Y zu&~>pkR^XzR-pit8q$O}!(b?9mCstgn3dA*+s2ROty82!dwXhKR)tG9)4Nlg*73&6v;oB^Ic?rram}KUy2#-7bFX(BKK0?=e=4t;Y5_fAwM_bO zRwZ0r%d5(QPvdz?Y<-rp@#Y>6G8D|F<`5_%X|LT&S{ zV`pp>@-Kj-7l0L^my!Z~>lB_3)7l)``LXJCwYES$=JGYf41QOFZ0hhX)-O?zuZlr# zmNB<_h9BBoKgMOp10N@#Pdxd0MdqAmc!V7QaouO^37i*Ri&Deq0J(H7_$JEaSH$QC z1-+wwALD*;nv8K{_XA~W`~N^i43?6;`$Pw`^W%m$7oIpbIP8`3ynkA)<9mZPr6oqf zj|IwFc+VxzFDm9@E3Q_szT2xwfTr(vYYv6l!~Rc0_TzpT!!(yTXFxXWDmj~PP0@C# zSS(Y6Ro@XTLiST^smfp$0V@Nd7!Bk=;S>WkT7ruZHzd7GU5WN#KFd?#({)wmKL~Lf z=~3vpvSii}2tnM+KO!*TCx5Y#Dz4l;Vf@VpZWV18^~p$vC@typpQbr!koGm(yo{w} zqwDvXs9+Z0DVh{Yx>aHQ5I8xJCaapz)cBk9>Y*BUK#puFJNc?1TzQ;#ost?d7$4`<+bvc4F(WpqgZU zS(m?W6cAEiPE>8meaqkEyA;#A4pFlAoYSSOQb;fyXZfSqx$o}Z>XF0J|L~%e+4q*y zG6OWoAeK;p3bBKHW9*;*Fo^K41a9iR0mfU_r+H%be3qK-9jPHJ5lTA0q{4dD%khOd zCB7vR(c!KV>uZ&@t^o`rYAcfbO+bwC>?N6^i3Uz{0NI2(GP2J7y3^2>)n|tqQWYv# z_`tEDLno6qB!diB;y0@}nJJjFA?zoc07{EK^=LX%$d2^#WvB-#dS^;O9nOEG8?jkgo{-gm;EP z9fhQk%^GbOcSZH%EJ;95`>sep=?a3SF|k2z6eJSpSQ=SlrQ!dvy_*E>MeAnmD;hL- zkyJ-&VOo3OOffCC0W|&{Qygq1>HM>0++m7nEHMdKoTO8S$v{;z1URnI{?LVi0_A{f z11?~2C0S<`(8hDlR`7WC9X`IGC#j`(2r*1!=di`Nf$T^A5<+v4f$A>WK4KYGa=XV>F@Hdn&~#f(;j25E05*&KU?6t#JU=6<0dPK9Ut|}T>28C+dRR`ryWN) zU7V+Gn~hsRHs{VS%`U>QlU{d7L>RRWXWYuWz^mLPV&rZBc8L+k(U5{?C1Ttmww-O= ziV89w?shZ`Qb7Q1wLKG61&;2In_8gkon(8|_@-Ok0xIS-L!avLxQ=ye<4-zqVBA=- z;039LnCIh-beD^|7X2a(AaEanE|ql=A})C2Siy(OGUb$kG%0m_A|dDxJD!9q5Wq5= zRrRA0oL{-S4V@(`N)2n*TSphSa`#TB)$9ptZ)ymOVLq|-5&Z*a479}#VHv<3yOU#I z%D550q}V3229V^T^(ne^SD?CHv0+9>_o{-a=P53YWq{QXc%0v(z>2ILAQW1Mz|C zQ(Qb@Jl|47v{_`dR%gSFMzr~ispk=ID8m}n+9>ZDLR_M={gG#hCoZceGtug1^fo*& z2s`uob=M%qdSY$R8j$R%HI6qq=FLmojfBkM(B{3_~J zE8PD9@E5@!|nO&$6dOilg=^0wcj#Ea`}ua+`U5GvafrX?|&E7uxY7cw=9 zLL4fRH-mPN?V0K3ALc4Sk7{Oq7T}S+qa}1>>QzW%xu63v6g&#i=S8GOzQ(%tM*`Vs z1F^Jl%q5N=7w6i^<=6tnph)?$dU%?o!v6YQ@xe_Y=7Tb+Cmg~w#)+=@Yv70zp^Vjz z*D#(>_+suWcqE~WmIdfr9W3E}(8N;-h94PFuD~@j0Z|}>9?R_4>M{WjNV$YF>R%W0 z^yc%=?cr95B~C7{k|3E;D0PAVVuECMqfE)4feBKE{OXM6e7|Y7Npq*Ns_x^fT2gSf z+RP#CeE^a1KW_Dutdup6W<5o8U35q#A-g(~4Gm_UPN!fXlATysioZDjMCu+mr3vFX zWB+jbGX-~X0iQ@aFRfYlcGM<>jpMxjb&&9Z&JtnsFwV!qsz2CAg-EQa$aT~!Qi>wa zD&(ZapRN?E9tVu{6K3nN>*S70NQ>FnOGAf)HAkd4f8_ij+#`QfSZ>4Pi}IYSe=UP9 zUStX)lUA}rie;0400w02XQw>oT+UHrWSD#Xm4}{+y6tg`Hb2!&eq5!{oUj=35(a8} z1h8Yj$6Df6;jfmRq#Hk_KFT8?Z(xo`vJ%HB@x3u96soeb9euRLn*u(Is~w;ozUIt( zqlSLi$vZboZ^O^u7Xlv)`ECqm@_MYgG`+0`ORVVu6FdH107D#}zEW}yi*J+Cb$OZp zUlT2CW+TvTeotK@RBM(X9QMk)i`d5nLo@>Mj;jlk?Vxgkh<9|)gP>p658;tDz38RW zI7R8a@F$%` z)=s}Eb(h31V$7|Qvr^B=1Yzb|gyCnQb?o2*9VoA5)C`K8esaG;m=PT}DoioFM3-+9YOsWEQ(E2Z1*96y zTCM=JJt9U8W~qqK-E&{RMN8b^(IlX|`1g|c|L7j)7MYx$2Fh>LZjEu8nUcr3TxL1h zlb#v-=J*|XsgSq>1qvrEMjKv=D;u30vNAT{xh{got~!3Bd?$Wye(~O5U9{wjNA!8A z!uMv@7>hYDC)L)HNrEi_)4Z!YU)`&vuiQ5X&?B!~awS+x*j9Pi-*4U5;R7sH=C zH8}#&q5O)h1P(L+|CMA}r-CtmLD1cb29Y|N^(R-NbnXY=v2TxZ)c385NeN+nT3l<4 z;g(Pi+QH&aV?V9P0gh+mX5RyPFx18xzMwo}hTn5q;P0Q0V)m=<;eW+N`U)#P2i>H- zyjmU)H85fWZ%g1bDy`-bBBxU?b&e;f$1=n@tTx0XtQkN3v@P`23NBKPE&HNZDYdi7 zd8Yv^CEYqIl4?c#$co4p7%=_Se=jK zeLL~%eRKka>EPlgq#Hnlola%JhlnrVh1Sn|Bv-xuKPhG!dPc|VlVV40k^6QFe3Prn zFVDJMsp{>{!%_w!fJAg@7WBBRj3COwt0O1-iPaU1)wqZMSs@-b+u6S!oD3IM%SsNE zZu_TO_3wJH4bUhX?C87&Ptj z;36f<=(>4*_Gi8ZIG0fNLpmTfAkjZ^j{A3vFR|%m|KO)#v|2qz$O9QBT;Eib;kY^K zQ)@)aI1l7>2rEA?y&>BjFfaU!4#+;l8ohp%VMclZG!Fj%QN9Bi?;UdUEdF|sMBF|_ zSA!3(=W+Cr%_v#)arz+$(aeeZ3> z*P|yiMF#1VuNZOhmQavesffekoD6R6V%~`P$G1Y_;PW+zesgPZv-JSsbB7jkt4+1Z z8Xf|HBDcD$WW7>yY{?;(|F2R))w(&BP6!g?THLCrC>7Q)SP;$;a{lZ_1GP7;`W&^) z_qC2H&64f0*#ig@t8l;$P1R(Ya+_M!N!l@nyntv1Oj@-09sM?ueUi_q0aP zKhKTNF&abrQ7R{VR{rNfolH%q4e*u41Mnu#LEoNmn3WxRe^~EOb_c+cTa^}TW!!8s zNu#2ilI^V7U{QL&H)nxYZzo+dK>&9e7w=)?&BUhbu zJ3Jnhi5(J8qnUt5!OnAd3Y0C+Ed-?65kSJq_-yK~O0ELhb?)~uWp;ReO~jhuq$4r#&qr^m>w9rSP(3xWI&HGFaufKJ4N zRE8UJ%;D{vi97ndUeFe4)E;qlcMMqBG3`DiK=_+t8s<^$NJ_ofc~;eh4EyxjeiN&@*=a%Dg~bY4ThDtax!DvZRcsOXh=dwpw2)vbbU6%=aY2~t-Q zRUDmEL+$*ZEu)?hC%;`m;jkRiP-fFDRJ&b9W?_HOEGE-qI zLC;dbxIfdR8YH%*07vC>jZ_1gBDHVU?;8+ZY>B#&wHnHQ-<(CC)+(Ue{EGiZIFD=M zA#AMy@bp{#s_R<;1CS`+9X|D`wMk0)(oF39PfI3luK1W+j4+L0TTLQe3VA=|_Nj34 z$iIRI)ryQmJ^Mrk;8+>fin66p>yIiYdDHTMSOa~SNKDM*Ph?Avn2JLf_rl;{-c+%v z7RAK-cR{ua&Kb;nNmAZj=l|6hl2Kpa>(eGv!XpY{9HeOrzP#>z38t$)-Px>h<80x5 zXvIZI|;9aRZpUAi~m6iJrei3lZ?4*=-K znDtMp%Qfe9QS5Z_;~G|uay+0)I_9C5UEMVhe0MGZdENTY$=_bwi9=CooD)Uv!JzAr ze10l72@PyHyU{*HL@Gx;l#|5uC5S%ha;%RxLQ^%~U(O%H-`6OKXFP2sl80A^0{KEd zVxh5dih`&@s(A-ylq6y}j4pIbX1%E8u<52sDZMx!rvz&1#XUHY=)g32;RhhU!Djj* zchKf_cs4VH?%ARn$y9&2hcy3}MIKqR$%E;(oec5mWDo?AIV9C|;gB@En4z-QdT*R@ zb!DE_J2-SB34|wxytfz7X+c!UnmRR-lqMVO48Ui!F;%VE>g$q_s0(Z4;zlbrwvb{}i zgVQ?OLv2q}M?b#jF=vNd4Cwzl7I2wWGdxN>QW&uC{}C76w7f}JgJ&l=VwU)e0D!E# z%)Ypy7ZnT~ub4SPPxa6ZuaF|t#1whp9j;i znsz9QYikiZ&bFk>pZw#X+-QUKEzGA?V9w@1I1~=eDwJSOuCmrlMLiZ?c-wQ*@&(|> z#eN1YVBWDqAU67^wRHY7^!T*w?zl*Gz$l$P0OmQX!7oujgXy))iLPZgW*Y%DsCq&o z0$9hM6AX01Oo;Zh+cg@N?YGAWJFn(VK?;;#E~%Qq)G>T`oBul>PcKilg+w$X6z;G5 zSGgrYMzP|R*ac;`U*T#IYwaBn7>+-8A?^f!MKX{- z7N=_lk!dDrk6|TcJ87i7qD3r$a8_EOw&-C*iFn1#3_w74Sa;VTG!zGfhKM*`fYZ9k zw#!HoEv}R4@}~S+jZH+t!EEK>nXw^YNk4WQ{VQ*>rzV_#(?uEL<1J`?GMHnPzz51qi%kdegec=|ARAL{D@ zjXPemsX471(R~gS*|`KJ7y#V17J*5HDwJ4?$2(nF-*nGkisC|;zTK=xG$|SFQP7Z% zkc0bmAo;;@XZt1|-5z zI&KWdQWU;`nbWNk5@aAF;gFJTbuUOoi4Np#G$lpYio5X6)WN-bJf^vT%SG-!>%?Qs ziQfexKHb&qdt`6ghlJ5nQ4aEhSk1<4Qp@@dwSNzl^L1q&`fbPxJ4Zi`J=ft;lH0bN&nkhTDMK!(2z z2Ni>`FK}V4LR(08BDZ&R3Klsr!eZ>)jYXm?qwibcsMcv<2vEu`YjHaiz_KkIuChi*@>1c5;rGLvP=njT@2-Xh5A zXg=qYSb(O%SN08Ff{(yDtksNxmN}@kr$b& z^(nMIg*Epy-(gT&EMH*pV+~zD*HEKdVBwooW&2}=a5+g$f?eK&DP`vHeP&@)XB;vJ zP-K=-0_2TR*SET=wGDgE6=^DW`V)0ep{%T%J4SH~J6*F*RU*pD&HTRhbc#3cicw0Q zJbw`Pb>;1Q1^c5V4Gs2X`$TME@u&Wn{VnH;!*B9s9gPBh4d)dD=FSC9tmUDH)Z#6Z z##>)-KF7!v7-s}nS{xj#|4Q6gJ|T1r#eA_?$6&2$Nk>u%e6>?6*;%W`HR~K- z)KoGMyXVIb($9KyCHj4$$4vc@4}QkEdK)H5C8(Ip6D=(pYShnZ!ciS}^V{=~t39_=F-CLX2{=&~Nb zn+l0Hiq@x-@{6n7wO9E;*MRr)xQ}?y$jb%Qqwd#=N+5-C6;Y-Hk?rS$UA3PfY%^L+dcHZmh4Wn%8KA6pC>lG zI&{+#JOxyi>Q|XAdSJak08iT#05{j5CUdCW=uP+%GNE*-zkJCke0A*X_?XOi54mEQ z7SfV9`zsvF>qYA^r-5^k{~P^S@hmU`sdU^u=klnrZ;+mXUA!Y^7Xf;C1-r}1lP!5D zeLyeV1A*LY@Amp`bMQdEc`4N#ru564FsJK&lCp3S*PLr{l4@TrY$1@g{(>}&K0drD zU{LBX9XY=UaV*-yF<=_Eo{O5beogMVE;7}OVBcJ{vWbuty%?m_>$MQckH!>`aTdUX z)`UF9rER3jloE#pM5OQJ8pR@ADNdy(J>2`Lf?b`EmO^9}g;KROI@&y)Gw%(WfIdvM+Z3wChSLHYe8ca9zzjN}4O-{L(OH;On1pLygqJ}4ryp&+9d&=%3d~+N zNIa}sv>m8_pR%aboMFGWhNI_+OBP#Fo*x2jm;$UeJ(~YuTzk1b$E`;z_`LIj${}l{ z;I`y!aUX?60&k4YNr&?Ivk*eiVn&ibGJQ&Mb*NQ1+BYw6n$|fMf>DH|@OHg$G#*-+ zv{1~OVGZl=FV8oy$y8{vRMM@ZAqKO#Fc0pAkx=C&OjnIey_%jZiF0A`g&+9i&xeVszBdGjz;O*Sr<8 zTpo#2?!DtL?b!@FnCMt2$X8E0Z?%jAUY+HYmLDxfMDm}A@5)+-A}EL!vpFRn>M+ss zoVCmRPl1k^A7+FH1N5b!7xs$)w)!`rzC$7{P%!|3L|eK4R++u1*};M$Y&O}wb`u)q zg$VzcZfEdlM_xg41IH0g&iZIdO$sQX_ps+cWxFNKa(B>D!(lp&%{f@#^|KQ*i+tf7dtjfASuqX z`XjYJfRsqh-d90}0V-%&EyafaD}TJA2}o0r9U&OM$)Z_+EH-^jxijXt4mcfOlbs}tnBIBXt8 z8E+%B(tK-5JsKA1Mz9)Z!DC{+JAEM^GKk`z6<`Ll4=PTm&zdPH9x-@)J_et!J*z`0 zFA#v)lT;71wH|%-`K-ky@rTgpD9hF*(>;DZ`GvB=<;WUEvO{DX&7%WRwvb9;^{ucH zd&5@I83105@FA1Ha-`WqB1p*M?j_uWCLkG=*B%HN=S}2C$eS;$20=HevzE7tFgjrB zdV!fDK^u>S9>h4eV-fmw2nLBS#Yw*j7 zw(h^gp=>7?cOE<^Hk{*d#-~DzP*?!zc5^0963mm)o9UDR&Ce%`LL;69>nlw772R6f zbwoDSWU^Wp=@G%&MSpiKmvbm8ixq5xpfzxC`q>BFGo<~LQup~cagwV~Xro?QOB;cf zD`Pg1yvD6UYXM}_iC1|TK076JqoR6>aw)*(wlzC&hKl*>LYbB34Q{aQ^>CT&u{?&_ z+?DsvQWk`dsKV)u|GB7?HzmUV`RbfhqfW_M0tg9WYbC?eMp-VcuvgZ|s;H0Y7zw9T zdH}zk=^9w;iKq0TOa(S2iVTE^;k+TD((ZXl}u+qPtRrTT&d_*IQ!+MA{?t`e|Ae;4Wgm*7-oAcIUKz z2`M70ay+}2WL=Eskxa`bdgs9WRHy}0gR*Na=)-r1rd=Xsiv zVl2H31r;xeTic+GbPVIZ|Nj6gQ;PAwE8}LIq&5c6a1;fRfC5gO(O^7yPzZUBJm6Bc z6=JuaNgb>)R`T%Bl2 zr3cRP$@?5p*36C)-ZsGrkp=ZGea*Jq!B_?SeaL^qGII zXF|7YGP+=QGVRHK9Ea1l3QR8wK*A`65DPJm!}3N_r3J}41lE}(Xg1tQ3MlFi?o7jpbwz{r41y|P#;0A*(+iBpEkuqy z4_NriC#_P70!3h-Tn-B-v$``)ZX;d0pa6;D#g^2-mHmu25al6mD4bk%yCPkkbHF7H z1-kvdz2uB|wI-FDkQ7;Y5cg)fDjpJNh64hh*mo_8`uCMQyIiJ*@kl-%u{w*+S`yFRpTa^kyF)?Vm!TEQPli&XVf#c)x6|U7QFyE5 z`vaonu?5k@ZR779|JMT`Q!9yGQ!#Ej8YYj(7mQAtZ);?@yXK`iLZI_TK}2G;78zA? zgn8W#<(>w>T>5t3VvDcwUGgUmuJsoL$BGvBv=5jT1c&4M=_~YQk+0zuy$RB~#fX#7 z$>I*O?IDtSnZXEFsN0V~10-Yl|q*kA`yyB0o| zX4=m;$mCGD0OTv@X=5!UY(aF@5%`6daMDHxsl3*`R1{3c=%iCBRDyj1I@Mmx1BW zWAnbBeRC5VW-4H)5C|`>@(}<405+?6o&W!Ss6YSy3IF^UpUFhys5ugRS32BuETtcd zs0^8+Nauwd7_thfo<1wv@m!F@CSC;J|NeuePzd>1t2`%FH0EYRY`_Dw%|M-W*@?34 zbl#p~xT{R|gl}lF!`!;zc(O7>hj+qtaIBcVRW)}*B@0#8>h3^&?h8GgP)<+4Tb(PU3(kY;;bL%fck{;V0rZ%JpNa_ zq2e$D(d0#o>|Kh9TRrlD^dvf7@Jy_ zK-zouZHBWJNPM`~X<{_S$H!21 z+Z!shOP8400000001na5!kAL000000lfyI-(m^Uu4n)NaYDHNwuaiaD9NvGKQlKzz{*UX zUv5+Cn^+qC<2+Ni*=?Rb(|`H||FZAOJ~a2cKq3y=9v#;~(T%1q$6=BHj}*z@*ipfN z_smdYu|xQ&0`aKd)?KG)lD|h?#Bjq1MGsHv{Ik$?1~vA|cMR|Z-w_9lW$#ogAx_mX zO>6=1(l54vK2^D2UwvD89F^3Y9zwX;(gt^$`0Ch6>qS0pKCkh#{JM8PkO_G>H9OK8 zD_>|_13J>L;a7dvG*v*%OsP6FVvoM0{sO3 zH)y`Kn*N_iHtfrC47xW;YwmAd1vx{QSYGV?xG_MQeHN}e_p|^20Z}E(CSI$hjv}&P za8wOx@1|UX=_0hpkOmWx(9=yElfb3W8R4kOkmmKwX&*SWyAnNXJ8^=&`6>?3sx^P} zHr`LNO13yuIPJCARjt6&eukHs3gYa8cH+q7NG_$X$&KNH`%v^7dFMy6DpWzGO{>&9 z+&{wNz^B1NdqIYp44s7Q;U#{iPO(Q!&&7`EW-WO5*}A-2U{BWrOGECdCPK!+^^Q+Izo*;@1F@ zmk~eHhDjl4QH$ul?kie&FnWbVE9p?KSZzK`HF2$hSjTik&oHy2T% zB&e;oRo2mGh>bAC_Cj@6dwQX4P$K2IvyI?|D=-F2LGWL53rf?Em}%zi3ml`dnlu8k zirT5ILE8b7z;tc5nJB;g}K z=yTh|iSEWm&#D3mWAjO>#uU_*I!w6oTL1|M=8)YV6PxApU2qM3R2OwXkvim~g_i`d z2HbRn3k_pCqznojw7lC#XefkLeqH-&C0q7(n${pe{IPHdYREND1Lx99%B{W+`5~oq2A>@DU{BH{W2bN3?Ihch6 zVBFTLK`g4=Vd}ptoPPI}X63qypb$TM(&NTc_X3eU273 zWZIJyCYm1&PJKYmd%Qd$`Q)%FK|Z>y6h0IDM$I=g%Pn8;_^_<{mUB<%8O63X@eSLdIYsyp?Y@f zYX00X2`0@D$b>TrWaK;)n8D{{VNfL8Mf)DB1w*EGXe9S(rv=Wk)J&f#Y+4qPCXOzp zj>cZQh(TYLLZQG>2vC&f#{sl4u!bY?_spX2y_L~m)eDB&SV7f(PJfH<_RX%46Zigr z7VUBe7)SO|4ZX&q7vW4%x6X}(w=IO3;_e z40Ev_;d3zV#d4)`eiry25{Oe%2;)agNQFr*qxP6rCa@dB$4||V^0Yd4+R+u^+vHL; zELUv{w$Ll+@P)cKtR$`#0evHTB1y?t`w;Lvc);EWdZ0zTaQV3GP_Z~Y@Qw*So(Q`# zK47B4QZpdh(6HnI6h%= z>5^G8(PX+O-S8ZyvdJulNZuV>J*}Kt4=h?VH$`FqbobjpHtEtZoJ8=@`Yqv|hI>i+ zrq?b204d{Rdd5shf&7mi!HQ;^S82esWQQ@GEV21IcSMW9o753A zpX!g}N~5q~X%`HMWTN5kz*Ql2H0J@RySwVs$xI(#Al0{GvCXt6-O03*zYGxgJ{vhH zB~OhcM#ZlwPLHg6xcrUgN?3nnviWXjRj8{)8!kz&K10Gg;8@g1j=F*{`b-c-60fi9 z+_kZ9A5_iXF1yv~7gfk(PH!-iNVle_>kfLwE!rpzLO}|>{P}D%%LeixLO`sWIg)+e zo>lv;?RRGrbKP&>9N6(X(XR${tvyY(l&R$%4U^9+G?}Fr7J-f?0p|o%2Mk|(C+9rk z^;o&CSNhv5z!LGd&N+_LLr8497#ppoZ}iwRh}4 z=bB&q1t647;OWbb0Nmzld1tP^?PzuR)y0zCg5Fs++FK29p*!I;$ByG$Y#{YjGJzVM;jcTYxVrnn|8jAwwYl(8ee6|*CBqJV1j#sst zA;9D~_#&Kw0=ZW!($rlIMevF;yKs%LrRvc&4fc^HwRq$MlQql+jD<1zeLMwg7xB!| zvc6^C2wWW03Jc>*i%zWz>1S=pAARvK7tM?z8KX##lz(*6~dK*SbF>g8c3>j%cjaA(*7}L)n zF5_|MKR4y}cPxAh%z$bLZC-_((z!+(ldp-`C&l-))O8*C5Ji^v*V1cqGF6 z6&=eOilnK}lxTzd($ylsuEftl^xZGRE$0LcIzrfnIo}G`2!O08V;=XQ=fzz5{+*|L z3xdm}Vk=tJEouL*U-^#Vx)EVxKaQ))##p({s%`g{-b?`mZvcAj#@ZBy>emW3xU_49 z^x}aoIh*;1BN`adCaOh0#k3~WY&!IU@hZN9n48x|VH5hn8{k>Wx8$GygClv4&2X&a zMi3Hh#Rl(-y&l%Gz-R6acZt(b;zQkaxhDYYR|B}^Zw4G112dV-7LuH3ojz>4?Ltrp z8$|65rU4#9SzyM3X;4I}1YPA8l|4?~K!3@kFqB0s(VQz#1%SLct>lWaFa6eQDi4No z99$L34+|EY-h5lu{d=l|JB!+3?rw^Rq#$(7fbU@n9$m|t3N^PUdLYV!x)mq?_MzAl z-uUO0d;%3f$Ym6JYC_-RDks?EP z|EJkI;?vNK$beFXXwa*z#mh?(E1W@)`okW1-8lk9npMORf8=`Nh;gUABssJh3`z6s9KrsL*>z(8s>!MRhVn+=7Qd()NLH0YgWJ000cI zCry~*<2|sb!vlv*-tiBcU;%21qy^{1^cy5bghVP|x$vYuLDc}G5a0kw4El}vXiU6SE?Kj7X} zo_gP6VGgJ|m{Nc#1_QXj2m%2TSu4?&iGK>8J>mRf#VO@;6ddRVXkb>u%(#`($qRR+ z6kF;^NE7RFC0j0Mhbl(xQed*O$Jbx467*7-*TZJ7`MaM0uBQZth<|uD@7I}6WpK5Q zQ_zO{|H>GD`{H}#zxL|)C;Y!0+tL3UhnahyHN5^$opQvnG5>zKVmMA8$ls(LU+&b3 zj!|iY`SJQM!u=6!_2$oyXTJwqdJx&4qg71J%QqvLkXKWxe#6I|5qO)gIZU3?+r@X(d^D4h)~>=Mj%vN^$}#ag~gRXIxF=a*+I z6FD=0*KuW2bc)Cq!aDEYU-AlyXyXLhP)! z8F5$HHqgGZ(yQoa60RNo@NUw&zUT>()#Z*@wJ{9OIo@oPDo)VVE*vaFs!r_4^Ev!L z2P%=_15>`IAX11mIP;yf&g0CTW)7d>sZ0T_XceQOjdvnKQ_sseGF$JBTBq2A*AF(hpWkP{Vzyd=qM(j1aQSp;b{A{{kgxt%Fp{ zXCBOwpb-Vx|Ceg~&(Ra8&|x>kw@X(Y=+_K?!hP(Z|D`r@K*kHB&xL^Ys(F{Cm6z2) zQu;7$HTr}iiHWD*hu}Knl+dl^7Dsb_VW6NJmOF!fQ?rsB-Wz)~3!>fI6iMkvWhlZA z@T<;(dKFg^R4z*Qv)t7>c1K294D^bEF991d7ho{Q1}5iVhY-@{{_Vnqom z{Y#=FmNygsy3R8Q2@`#}$hkT2&~KMGVx*QRS(m*$PGzK8Q7%?H3Ia&C1u-z?;R8}g z4;5UDsB|ju?=awEouAGw=wVd?tHodkJ^pAOFsIH;l6ED441}vX%RQcc>t`%bn0G8F z+{#8EX~Y)+G=)bn`DB!^D#j`fZRDwyiJr>haRc*)(WQ)U!Z2^d5QEE2ONZy_9vL`P`G+odL3p}}6gs5C7jfU1BgU`>;eHm=- z5Pz7{#Z%G{o1RKB9}eKLW^KjWvlaEd3uH8P6VaUmO%et=s`mPx5(upnz|(x51b=#9 z#ms{t4RaR~@Sz!G)`KED58b2{;a}cIqM8&y3<^9k>End21)lUWIz93eNf>xhtlFiY zSxIrUKl(l>Ah5R_TzdpcDIdHQ=!U!rn1*)kv-Pqlg1|QG{=xa<`h3rg!-WO>b!1%R zNFqvT^v;sJm466J&uW#wYlcbu5?q2gvZ%W$L4f)cbeOxf0|7LgLuq06QpXr=tmykA zSZSlBJMOVO#Vsxh0N*QZ@yrO?YWwD|VZ1q!8$AxZ)BpBrJ%K>-r8?Hutd=PD57jZZ za(9t(Rt7&!cxl^G|L^(}_jJmtGmBvff-zLjXmkmgZ;XjH-zy({^E>VTjRzoOCty1h zaIdIQhdwBg(VJml$Y@2E>dQ*LH$uI-THCUlSw(icR#HN{ zN_O8>;a4f(YGl`|WzouG#MxR@wEsoFf_mf0+Hl@6FP{sY6^}IiL}8XP>SkkQZWo{2ljbDf!_+IY@Mf zS7LT7O!R-9-M-6>a?3ToY`Z+v%u8o+a?AePIo!HH}&s!O3?r0AJiJ^H%7re-4u7R^za;5@yBBgt%kIv2(CX*+nH2IG3g7Y z2_KDHjxgy@ooKr0=X#!K2$~Xly z(un*U*z|oob#)~kcjV;3Eo@`JI5ouvBF)YIIEs155#Z_!$SmH&4J`1}q6L&2?EVl$ zL$M#INEM``ESl3%DX!|)mP;;9sRG4w7up z2<4cnHGY&}CZx8hG#is^-1F_A(VEH;^Y^;gbOi(+25vTDoeTjN(O_!^uXxcXGwB4B zX>c|e@h>EhH#a6Qn2HCWS?e+N?(9r52YYVwi~|xrVl3HpCK#`3B~O61b{*^X)OSr` z!8@!~sd>3G^}e(I8IEkiG_`AKK-t!)v2IpQy$cH9Nle5T^|Frl+Ir@}%fwg1dWy6( zIvs-eTGAWg(z7;T<8p+=U&g__oh8#U8DX9NjWf5SUQHoD6? z7oc4^YTLcL`?a^BWktHh@1k=X$r~n8kr-ed6I&#>bqkSVMu967;>bpXL#lEVfoJ^8 zh-xEzQxVpM`%2Nw^sbvNqOcbm6R%c%v;2q2JFT8}a{+UZ#^IoeI`R;I-E|ila(ETJ z%}*@h3?`me`~X`>;T~=q`@trtDDlC4IbH9?q&xJ%Km8^V997>nn~A=$j#ki}QqcgN zY-Vk+ZzP2`JtQAIDzDIMrg5CTDq_8{OrqYDWtN6ndcc$N;+sJLeHlJfs=m#@>12++ zJ;5rrW5WqT*;OH`lf6jwX;&wT}I2y})l|$^evxn)td$rhzGE}9c zHDXI_x(U9z1Oy8myHh|P||?;EuKQR#y> z$B=M{0_^TYL@y4YfF6G0`*`D0j;z!%6-D5h&~nR5dYtMjZ47S#1K*}VHljVy+y>XsW4voc znpUpbE@D_d@EwOs6V4M|kf1q6^jUiLc*6LrY9KtwAm}9zp468|^c-^@%g#5L6xE$a zEiq@69+xwX;u@+G&D8jd#`#+m*l0r;l(az_HNZatk&m^s!~VsPdi3MHHU`2<5f9IV z8GIiluCE%6tB%w1EYhQ#NDTOChPZGaF)eft^Q&KLPbwYuqCO4~PtZe?Lfk^Pb`wI~ zb`mzs$;xCy&O?Z$uWCeKC$9Z108RH|3WZ*ZAyAsKW7pNxU=*0<(A+F$FMAwKK+LtZ zm2Z~_|B#fjC&llqi;At8(|b2)H2g{p8-XTAs`5onW=iK&pau7w;B~+26Y3JDcypLD;YT-xS{jc{3 zK5yA_mydp zI`>Lbz&7$(>ZUSIGP2sk@5-}o5c+F*6B@9wf5~R ziLl*~o{@flDnX>750zboc&?gCWtK)ZIm3I!2&q>MzMoAneAbYm5r#?W!KIQ`Ha2`F z_5hD^%83?ZjR1qZLi>MLE(>ST-(gNE+39&NHZ-=|^p{TeBC!KmdY6Z`Xoak(*HpCv zAtcl?+9<3236BJgG>5Oy?^~uo#pf#>H?OnVE>2R8?)uIMuyuLx75fCk>Oi|w3mZ8k zK#Vu{FIh)0L?>4fpGK z+g73^geJ=1!$5K?YgU+_rF$X3)jAZxvMHaoM)9cSR`>_;3@9aqDTn0w&a{C{vNG~DHIN@cVs!$dQ&%}+iC0P)U$Xl% zi4yej#;Rw)D+-dz97fu!*Rx%lsR#yy0xR;dd!NbAu-b^^%XdVpaCb3@c%;qRQp%i4g%LT5!q=~?qdpHAebuxnc~7AvIr!x(g{`6A zS^`s{_o9PTI)?CS?n#;GWAW2v)Hdccgwh-)@VAM~!hz{JUn-?c_Fi1>rtZ(D=3uCA zFGA9PEYd!U#STd#t6-1QBG(9uvQG;S2H{tXn*`Qd5Ryrlj zOh;{RX&aUHH!QRftm2xD=+N>_1XTY3zN2;ND$2Ux!C(L#MIh6GYXlYbCp$S-jhhO%>Y)LVJo2XR*8Z&-8=4);7T^vpt6*)|l?kw%YWHOGYyskT&_V3DRC z(uOsO{~*wVKD7~zThLE6L_93J53PYvM(a~rrlFhM3nb0`lsl(_oktrjA5j7b6eaEX zU3)l^I^uz~co=#CXSW!<4oqB$?>OG>wgB)c z+ziSvcwS1fNcx5K+nAFg*Dhu_mWukCwm@>ngsvJ!KB8IvFY+M2QjhDczFFj;IL~=( z12JYgE5ilQL5P3;zlw^~v2I0$Fs=gzqsj#1+iBwOV`Kqbo{1rPz^rTW&9hsS08qV+ zP{R_#_!Q}8X>sw|Sx-DD*t=R!gPf@vEMU;@R!#TZL@tr|mg?%7)&ZAfd_Jipm+3*Z z>77a)5mm+x)Ui0>C3Mr3=URZh=Nrs@ef}iB5A9C+{w|$tQp5sksb2uEl2l8TCQeLA zQp0>Rigq~dj@v>C%NG2!QYlViSDo_o!E zyNDe9T6XPqFR;u9HUVJW8)PZqujd}Z!ST_$)Ns_BStPO#K`~ImMKyvC+?PT5*ib$A zIE^Gs>Gug)2lHtF$#RIEjdAM&u~F@dWTy`^Uy{TPBaaIGa?7T`zfSDKy49GC+%xBN z0-Os~P@=jUz#qAF3+M<_mXP&g9=I;8Rky6k>M}r%%63^Qs_%$|HZt>sQA9a5RIX=l z?n7jewSW&HNL6uD(#v$Ta&7hEMX_+GTv2-T(~{8RUkB-LXc@;VSD5X^h+I6!J!&;L z2_u`nv7%?}D$Q2K#g%li!d`E})`)WK=j$nLnwLPT3ucu^XTd!z{?3Q?N2>`5`_O%8 zC)@5xr3JVA^cjpPdFtBOJ_5#o1^=&yH%n){NLUCO#n z%{aU1HV*9K3)SwI?z|fC1#f@mjU2hU21?Vq=82BbFU-XpKbZSZs)1EauipaBx@!#Z zu!S#I(gBHOB#KtjEHz^4JyEOIuU`eA-9D6bO3|{dodZ2%l%h=_IWO+sEZSGBuR3YS zfC&~wNxcrK!1gNa&9ny}%pN^VDth(u#BUgcO)}pt*|4lX9$EGjUfK`NsSGoCMK$c{ z+HBxY7nbop!u`X{M?c`g{V&--ra~J?OuD|(wm72iolfnhW^qE_4@T&?T}@N^@6Pmx z#A8Ipb+_U8)YiNxbmMHJ!py{}Up1pi9r)1~d>oRY8B}4YM} zAj?6QM#s4P-(z9c(sk_S5IlA74?^&DfJ84jz2>E7YjAtU(D?_Bp}{aXK8KxR9=-EH zkDkOX6;qPS92XgU7sXLMz@d0!)Vkn_+H zk~e8gNuBwe?+a*dz#%`wYD2SZ1hfx$TbtOnP-~2$9zl_68|Lxr={cJgQsy5*e62#v^;3>@Toz3Cf8A-;PWOz@2q|84jBG$RY_ily9Z3R ztgK13UWg3C22tzrhj8(3R3695Y-Tmi3!iouq&wSd9Uoy+U*vafXA?HKk9|@j90-qZ zkEr8uYl@MW?JY+Sx@o~~1!;H)6s6uV7V;2=9hHj7ZTR6{fid1CLm3T33rEieq9RGj zcHNC1NTFo@Yb4zV+3w4TlxtH^1B6&d#_G1H)YxIR`a;6JLH%B@38IhJd-Qy_E|xa{ z2HK0=rUIA++e#p6iXp_{%TAOF0j@5m8SwIYL&OfBGd(%UZ)L8ZHR5USU|<1AvwfIR z(+hEUcYPzI2|aUr*_H8-0sd0Ww9Mz@YI-C|@z|_`J9w#O$j9dTFIJ(ufBGGQ6#XN1as^<2kB2u3 zs{%Enl%TC_kZRrQ!xxobOwo0)93pg3hJ*$MT`=oRw+f40HxTg}BVcN%tigVNMjN|- z(CuqciYg?x2vEZ-bDxl;c{gJ{mOZzCU~nGwsb3T%(dm&~|A~-%pj1BpXFfA@`wDti zDxBnVwDH{oI^xVDqhokq{QvCn#H?@UdM?`bR1{-iY`TF#Ig|fAjrwg(c=Su(z{YJ! zrIewvKkw`27gWuaHGr9(*AnID%$(^PSP962Xvk}Anr~1tk8Us>G>#Ogk~cOaYX0N+ z&&tgX3pOu1g)<&~80SaAk!qAbGYwGxCMwfw<9@Lb)5?lU6CP!imh0eZM8Xctiv_!SPFTSWBr6rpE93d%>M98tAB``hDSgSuz> z<8LqgLpRb#`4ss@EHD3RI2-`3cRR31eTEYv{ph)wg)p1cNl!$wI<`Z>iR$;OgZ}lJ z(g(-D8xFT9z`O35EnWET*Qg-Cw654(@12hVy=n5ifaSPbzBHzZQuLdzeNmeon7l&l z96du+s+Ls6BI{#nRm&R}E)VAxhD5R-mKN2qVTTpQ(XE(avmG{X{%ZjSq zpxSz0qPWC1=G%nq+Us|m*OpJrk2{ONgD^xt6u!5&OnE__(NZjzwtLa{C-QC^u3ds< zts6cGxh!(42khB%uK=eq7V>!J_;?|?;1WXe@^S1pI$Of^`!Ai^zjW%7T>f>f4zN-Y zh?#U+EvPHb$A4_(UZ1rfcqYM62euSkI*=^z)Pg-^&)C8EqXAI&kj?qjD85X-M+F%n zY=Obe(pGY~0OOaiHDM#^mx3U0MTO_iJc|^)&%^@lO)$Hj9gmO9{ zk-n>5CK`XNL&7+}tMz1n*J+_*=CnJ-g!8_dIajOvAZEpGC5^mAD44%?^f_A;+h?Z- zCzag^6h+@?8|IVtT_{xPLX;DThoc9z_U~%qDPK$P^&<+RvcMO>{1$ke$EPqGZO|unSy236V zKZD7P48)odqXlYovC1MYa@xmNuolq;_QUQQ4hV_(H~{a`n;vb)N9|gy4{evSl#fm_3yDMmFB8OO6X|qiJW2fu0eWtd-)is@ zNl7cT;ei`vjhPs&7-UD}nr%!L$A)Jg$sD?71C!Dq#y(lZ9mf>>U| z+z8J!3{T9lB9xb#LLn$2bfQSIEXzyJl|NhZs9GlzI#j+6>{vd#c>Dg=v(TxP7ar!X z4Xcks9#blVx>WeOl=N+wegsg&Xg;e!?IVQvyK&a#Hrp(^iFySF6S3QCX7TO*`c#Ec zljB+x9%}}2pxCI0-Im%Br8*Nf!JG_E%UEMr(VQ^8boed}ee>dr07bz7000D7FG(H% z6ov7?xucT+0G)&oWoXvOBlDt`CIA3Y>BK=q#)};Q00006qykg`0El!oCK(PLLeYtx zghRWd%$humRP=T-Gtod@vIajQPfE2%8Iquu6yD!9O8aZ1(PiR?Yo!EVhvyG)9n z>e0tp)eOaUm{iM8jRC>kVDsM1w&Aggha7sBcYXK;Vp?+`MYNfWI(R6}lzj|GBYt;_cQ;F9mAohJuI=-QH(6UWR1Q za9BZcLH>j!|T-Gb~z)&Ire9^NsfCj|L%VtydSdd=<2OzFcW_8s9+6W0!d-^bbNW zf%J~nqLa`zv@^HW@;kt(Q^keaMIgQVc7_td_i~)4AmlzQIgpo))#?% z4&TgnBU#xN;Z_x$^_?)e8|y~KA=QgSh{j+Kx7rsv`+{IYf6!blG-j+VIGvy#?O}3c zDWsX1Y9&l?D3B#5k)-8{pLz0Hh8l)aZM}p`+m8^qq|}IRn~S8h_BYqw23I^i_wZ%jJ>o$=@iy^%X@^Ty|7n7WVn^ z+FsN_YSU!=Vj*|e+ZJuMpHP<4v*d<7`Ov439ne+KqstC;?+6+|q7HrIjbMe|nvZII zI>l4643W4%w3N@V*9u+*H$aNl+Y`R;t&kJ*089R?=>GM(@+vy`Ix1-(N+CrnMT)rl zX;}$yaFP0PU6~yCjW6ej(D#T5)JQLVo#{DTRo4IryUAYPhj=4HzyCB8SumTi87*iU zlmANp;XfGT#P$Nd7j|xFpWgI@YoYFS04&K13BlLlIPn*u*&kUy2DT;x%`96Fy#DpJ zpbT}D&F)e8;AYAm1^CMIvlqbIec27#xQ1xge4IXph)YSYCiH`{x|hA+zCCxHJ1yBF zQNMHr5P&A!zqlCSfMi{ zxPOaSQ@NO58jF=r2!d5~Ty11}^x4Xz-k?$~9a!2#gTFX3J33~0ffr;hufZQA;VF^u z_tYdx&nLB_#zO3t;1?w`1DaYHhw6yIjqW6Pgnf2XWVN`~1qS|$jkGx;j~OI`%e{Wx z*ca>O9}lY?&RSesv8v4-P3tjwr|Wtzd|GCj&bO9h8a$I(>HP=1Zzl8!?vp{_T7I;d zxv#-lk;p+(Prs7tHC>+!Te$bWcFB2VKJ?JVuhh}s%dS$QtZX3#I_+hLk__3@c&S1# zMCQ>HJ2{#7(?{bYdP!PD59&nhTyTDis4B2ub5;Zel{}P%RR4@H2S>CjpZ2v8>obBM zmes~Wd#8Cf$01_@DW7l=Lhn>Ui7KCE1VkZA}!VCZupKtW6-=DF>`E?FX>3OKR{QG9q3?Gl=oKJdG7Z0eoUbhNK z(NTrmYW+kK?JG4;Piij`*LqZ~skXRY@d3s1!8>vD6SZiZZo0`Vso?Oza^35uLqaU= z^z_3&-uWDZx{|`}T+F0uW?C?VdG*7>kl$(c`er0Q`+Cj`lLtm(mh57(p2xCQ{2n#_ zax`eP9)&Q!T)V|tXEI+=7&&zr+{q# zs#f{0ZDV4bcYM27&}qr7IyUx8Iq-7kQ3 zB+u$4Jn1Q7oLj&eVwYVJ_#O0{@Fm?I4T;DHX3`*Wa)b|aTR zMhX{%tINaju;wdUVG(qZ)LXrd1$Uz8TC1^_0q>(n#rHL8Go~Gv0g>8^GGzWGivc61 z_=)ca%z7xQ+6dBi^3Okxm)5VnX1P`y_68F0N!?W_=@>pOXsc%A#NwiG<%wO@ZB*a5 zq9+)QWSF#3IqhLW!i%`*VVgc0pxV@-Cx8y~fKw)kGfG2()#c~;p8Mh6zuV5QsWA*WVsa<9^^6^35{o%=B zby)g?#TEdEj6A_s^g*frQ#Fq2d69=o8TqR2Q-=PCMDHzx zO7f;V%?8>qJ6OgCu9@d(6=>ByhDiYFpER zG1=VljhX{lTumqsj(Vr9jiGS`5EpH~n_b6bp3DgNiDW(rfeP{t5eAhONx#BB3qnQE zP^ONPJ0EcWsD+5PP5QP}tO`LzA;5d7Vp4>Ww+Q8TWkYwEK+e=HXW!@H1xVrriUWTl z9p%trFM>O|_&jiMqKCw${~9y3{5J9iwIrE5wi_+^75;*%x-%HnCBhjxkwqO&g>3U; z%^QZ|EutB>57}WN_R9j{?<;w){7LJdJ=8zMQPFm8w2b6JAw#E07F3~74ed#f3n5VBl-O6E&yOh&=UVo8sQYl;|`e{ z_?Li>*m>dk4JD=wqL6bJ3V|@HM#-T2a3T!&K=?qZAG>)V3UqZ-+n$R9|E2&i`Juh8 zc@)%n(Dz-+0Px3c0Q4UbmL$P#fCy;25i>|bOZsf?|H%pfkb-aY{7piX1Hg#Z+2j0KgIk88kvvEH$iVRbJ*#6dncw$N*sg;lwORWiTK_kMUdg;79o0 z{4WCImrYRNAOR5m206tPbzve-?$gKet{xK6RS9k>Nb@5?!p~Uf3hc!y$sLppQsn6M z5%h~FvFggVa`oH96CeZ>%j%pLo?oaWExZf_i2l1C#T_7^2P9dbi%Xoi47~9RlimHQ z`9%?x4U=~0G3eNx)v&w9VVXVa(ZJbaAe@&23Te+vHRSJZlbm4hF%@Foxt`mfR;6-55GGCCK|$_h`Gh^fyWwPgOk7Ynn4Ww-zw0g z;=+qFQ2}Pop|n}pCPtzFRV9wMSR`6*Y^DU^!pT5D$^Y8~Jkhl~`ZCp#Tt_T+{QkLo zGSQP-^}?_?PWAsP8A0qAf(utD*wL`M-zPr2#FzO^;b*{ad|_5G5>D>phZzww#ec|Y1w`0;fw7M zi9p2&ZwG?G|NA>-$v`6M@*?ySc8}Jx z1(>n&glfZZ&0|mJsI!76d$ufl(0oVJSKC>l{#Ju1#di_TI<%a4($udEq8Sy~A)@<{ z%)Z!04)it!7+AW?JO!qbv0p(TQ-HmNz^>>xu=4a+I+rZFl3Dv&h!p;U|8AVcoR zi3H7b&T3$bfRQn@06>fdWB6AKVgE}uVZ}0S*$N*I3qVyti3N(v{QU+3v9u}qfO}7S z;hvx10bfy2*T3=t4(b4m{%=6Bu;n!Hc|f5EMRxg0JL*n^{2n@0(iJ- zourCF#AcB=Ve0QLLqg2UMw#>W^Y^FL18Chog{Pph;E&v^0JY;IIh=a{d{@cG5F~$6 z&XE4TjKCc*Pq~cfUcm_Ymu%s0LOcUF@w0vcNXeRN`e5=1j0+pPAX3w%=u`Pol0ybX ziL7=`Fv4p9#s#mmC+=1R@cmep!!xN)i{9QbKo7qJx>$I%NDZXwN!nV)P|@t+s- z5mfue%9PhB^75~AG&_H}zipl(QRp*9x#gFxysI?b#iA2<6HDMo`|#Hy7!Clv22ZT5 zM3kH?SJv$o^J%z|@K-)Q^0?vf1G=dDn3k;4?Him>uaD&VM{BH=_4VfY`mH3^2YMX4 z9ISSmP=%z-PBdTd@(V)?n`Y9+F?_vnb~SoGt&_2*%L7zCi?C=hT*0YNk!i!;&%J8Y zCt!g4hK7!9xRP7Z7rGxWz7V3e*FuF@JR?{jS$6t28p=A z9k&1;mqUN$0swCvBg~I>&VZ`<6IqpfEj7#iktOnJ zFpJ?W5=V2eLPUqNDlJRmU&{#XHrph*_K(ldFuX8kg z?7Dz@b#{Q2%thV-{hP2Ys5!xEdSlVzge9z+&*9#06lk%)0~Q5t(7*lZ zhX6oMjwL#xM8FqkeCXVHlq~V?1|pPg!Ot1ee#vS-7+o{KTN>uI-^6tB<;qJK!Z%h& z46R7ZRQ|&twde!(=LF!lr) zR|ocw1ZrO7p3A|1bcC7ZZ609OCZ=@%7~vQhhG_|c3o3M#Y)GwCy>tEZxg9zdZe zS|Hf$zYs>_3;X{gyk#cG6cvTUMO3g#KK+BMHHB&Fjt_p%i%DfeM*1b7xjga(cbR?! z7fy%)?gqJ?RFdwS)YQ1*BC>C+X1b|iJMvv^Hi}&6AIOFe!COYiy#h%j*s<4CBZ!XA zpjD%{D`#?b{l8}o$uWF?hHXnH?#of(^_QV3H0JLf#wjAukb^;s!Cv78Ntg*cd5v20 z9ni(q^FF!MxF~$D_rTpwFw5!Mfa39_Fw=oVTT@INNIvGu)@IC%>hH+>LZtq+Dd9~- zmUm|bk=Ir5^{j%TmdoH7Gq$f0lc#v?T+0|qrKwA%s*Bd~7^ClWf#Tc2%sK6wuPc_X z4JSXTK-e2)9tB*W7~{PEz?=1?LwyG=6Qx{Le{>*v#6SXJAN(u30Sc0B`|L~MrplT{ zmT@A9N9%|ZHa`2z?!{@aOHvXuTb3OxR$`8<_LWR^k3=)|qM{Bs3Z97MG!TZ`Su9P9 zoj3gS(JRxMa1{F^Z%U(pg1-3|@BxkER5~1q4EC6&Yujq9D^Y7?MP32;b0J6P23#Ck z;JUf#JNYL)g-t_+?83P+p+kh>Zjk{M86qz4BI_<$Vf5jGFW=Tkk5x_E>}(8ssApwD z#U*75nIR0EkJ4maf8G6<5J%jTf zP=fUB|5iM4Gu3TK1tZRc6t>liUxt>I=cgP-F`%8D|B@&94a;*j!f1RasO>oB8b7`cF*uML%Uj-ilZO`W5 z#KgbzAYR(~-8FelMe`aN4vxB61E+qYInbtw(mb@~eDC~yk|7u0CizNZ!bL1eJJF65`dkU|gK$^3c@i(=UofLL z7job3{9;GS!N8`~$#H3Zpi?^3&Y*{!{V|XHNqhK~zh8mo8zFP#b6H!rAAO-)jXE0& zyV4tCSUi6std(`%tad-X#nGqW&pk=Hryeu|(6{z7Pk+%faK41 zP{tBS>?hfHzX~0RPSNdlI>L>^Ry!xCG1W<45Vd2AkON;t+7ol&jP zK$PQ=&N{nX`RwrY{nGjeQHK(qI>iN9avSg2+P>++kl>JK=v$lH`V=URxnF+aSK`oh z|DU-My-5}hh8@@2*ZbXPbSjKFeoB`3{MhgM7QrNU&RBf*pMRV~@>OeJOQ$BshB;KP zybcEsT6J*EpeH47M*;Ii^`5Mvv@g;I;-GV}JHZukJ};`bSL60ub~KggT@RCpPU<4m zn(1Oc*hxklyr`4h3)Kk26Azl|effrjCF#_d(F&WQp*}Y4JNr{;=R2P$%F0Am;L(Ge8 zy81|rX|@<&%^X8zb~9syMls0IIOuXk$oA@tJPebl?ctKLj>pbbmQVxY*TYUj9^Q-Z z_u;IU>Kme^hp5A7x291^llwI4naQE6)>eI?6*VO3LVk-dQ1CA_K#eAI4^1q4QQm6~ z{v6wQ*HX$>MMmDceocxeT~hE3qZ&i`l?*#5kVP>IPoFO?bcS;!A? zOtlzATK2oW?)lAFy>YfywkQ@9)Th?FEr~1ue*7_dx`wAy<67k$m2ojqgBJRQe~H3j z*;Oo`^c_*i5BtRx>oHviCoAzJh!A|{Gb*_+e|!xU`GOE5`FJZXb~@}xXj#T6r8B2u z(-GzcI{ih%jvXgakj@{uT=B`~#_YYTXT`SZwz2^_GUXHbOySph2)sw|DN|GM6<%{@ z+SY_(Fr_M+tZQ`0u^&AFj@Lic&rHfNHj)g(a;Ay%O>718P;sB|1EO|~Y*=d;o=L4b zAVie>8)VDF{X4L-lV^1YzUum``*F9dtB8+E^Sp?pv;7Ety^Klb1smU=Bi*?o8lFqw zC9=ip1}Yy8mQ=_Rbl{j78X-cY!}Pjw5d{FNl5qp##O(nwvq46kR1%TUko2w9SklJv6hBldvZ za=OFh2X>n=q*O{g>@)L6keX?89`ZQ^Zk$xVl;NozRyI^sOGkVE&K#YgCLTyi+x2jq z{P{Cgsj{w6L?RHJ^FN&&lrsX;KPDE&tnVG_2Ui}5fCjmj&dflNe~AtU_*`153?+VjKE@SB3^L7oNRr|jdpVRp5%3@L%rcY4?(0%}2obP6`wsD&%RmAmG8 z1wpp_Y}X-!FCC>D0n}m4+6zMph(fL>_R2@6Se7+*%BS*kP6zAqa*9znrYkL5=tLG~ zYCRf$pk+bAb+x3bTgUuqMUjLXr;@ht=wQ!W1WPUPOMG0B3{lBRj5IgjU6HkfYz=JT zzd^Kjo|QX*neRfepYQ3Y_+kYa;6)K+V66Z?2Imr=b;=@SkaKKwi`) z`6qeM)05Q5qNZ3qnE4s89iI%RO>dfWTffPA>sGg@16x^I-inSVPr(7pf&$-9Y+K=o zKKIWYg0OLV|LZ{F27+t<8%K}>3GKZ27dp@d4RRI~d;XRB9~`&LRM$wpEZ0~qRUEg( zZQ1XB>Dx?!_3JJ!%pVuFZlS!X{@S3raO`Wq%UF^rz;|f8Zy|kc5 zWA|-b30PxW-9k1u`HIE+Ikf?H;*&vuH3JSG%=T%a{PKgcKe;5dJSDtn<^vb}k06?l zfr#dAdG_AH?Gns{}szU+NKD*XCrV_d;SptVzi`x>{S*l-Dp$SiRMmhrGpH2W9r zD*{;iOpjz~nXC-vXO>sJl7N9vq55dk9sTjl}^?R!u>gL0@y6 zE8MkKee@w828mzk@woR|LQ6bsO z5x?#eX1TR?y3X-b491lcce1iteUJCA&0!=oPqgUz$$b*kj*1YY8O(`??jvTGuTT2-2oI!3t4CC4g62P+8X-Nyt8^Ju@ZkSzc zxitd6lIc-tOSq{-;6EV!jvMUed{1Yr#Q!qP%+@itp9DZ7ZH&7R+%;n6?(HeWyA2L@ zSrHi?cZRWnJz8M({st+FKzWBr;043`Ci&8;qbFc^JkUHA#hp|bP_83gjbwFsT0Aan zCjHyx&G$5{o02jI8p$o{v2{WR?TRuLdtr zSWLutkYz1jJ@&LGf!iCg(>RJ?7p35&^6oe6e=Yq|uI{HY60Q%UZVixdfR+*fhH=F@ zjDfqJ@mZ?C=0kfau3Dznv-fSNXG*?U*Pc5L>xNTt-->=0c^XifKCbYk`z`@+{SJVZ z2@^JxYWG2A8v+zcu?B)?g17*hY9j-=lvpl9JsR-&)xQIA#ONUIMLIpmd|1nc>%wxh5UHEb>A1K!bUIsC;ycn0NN40 z3v*SpgP&xOtK@oG*DuAGLO-kI-Ty!Y1JR z+9~Z7#d`MH93qD!-NylIX|pA}DA4-J3=?3_>5h0>-Zw`O1VUA9jxYrZ5 znKc|Uhts^D|8k`p&Dj^>FoA&1sw4Sot^m(5?ejYmciqT&#Y1qaxIoxs7G85Z!jkbU zz8IpTd}X;2s}8$X@Z!jqtI{alfMt^scAv)i*9^&3%_q1Cg~IhBT*KFUnQvNjEy2?@ z!;!KVxj^>BRCvQ$LlYi_xF5Wlvdk;t`O;^0X8MJI)>*|vn(+}F$)Z+8r$6nniUfho z@u7$wwt+8e5YZmQ%V}Cai$;-Fg$SmVZ0P!6$lktT)=$N&GE^_~?KWXm5r>dY`tRu_ zv+Vb+uRG563`DIJMJ+`PVes?2OoJ=X7U5n^Agpw7-skr#2g5l}BW^#$j$7@fPLnnH zXN~O9pg*3~__a=Gg?lS~I^ZIRqa~O|4&gcqoTk22%#+Fgvpl@{KB<3Boj3E&`k^Q6 z+^!twQO&w<+hUPrbO`sZ(gM)ZY8tCPuh6jv4yhw9F}6$)o>f@(^fvw z_;2JXv_hbHrEqc_h48DVmLM zJ{n5H0mqm{QX(2E~m*) zoTEywL{|g1?SolYLYSYQpBy!IYo3x%#8!I!oy=JFUDVvWYlMWmZME}Q`twgFO$zG< zPW@Fa66i*s&lor6y4|)DfN19SiB^j?v}(}}%Zg0Kgs$?o4>M*OpGbXKB$A%?SF(0B zM-x6U-T#jgHd=u&8>cg>bPaWT_?T)SBjK8Z$!0eyn^{Wj}=Y zXCx=5pMo_a?q~4%keA{U4AyAUO+$S08t(S1SN!_5B7z{#%$#>aTE;P}8e!{nz>R68 zQc2?esF%^l!XmJzox_bPq(ETQ$51XhOxpLsa5YBLd}39&y{HK&qBk^;>3^8D6p%>z~Mt!m#?<YE>B08=?>Fq=V7ZN>pf zzB5&!LSsp6a3$*5LZmc16RqX7MT?8W7x0b-qP?6EO=*)A{sHMWL4N>o^s#sFqt;1T zu#X^p%&&J!_l^aGq4#tKc-*zlZwLeOkmVRHS0>G^R&+hiDq+m7+L3w2)$FnK4O(?C zo=W$HWwXr_Q=K->{o7jz-%s8?)E z5;a|4QZrXne%-w2Q&PQQNSCpQoMtonj>jglQP>Fhk>qx#2?}sX=^oAb8n)6>@MHR@u zn%ZJ$U8>2td?0L5LyCNogCt-v=>7b4%-ecoFHHBk^7URIOkU;gd@ln_kYdXJUVn!nP6c@kqc4#ax`@6$lL#^5#QmjY-o|?pQ&6Ra5YrYj2c>Jt zNY4KHiH#(+o^4I^tidY;KpN{-3a1UtW)!Zd@yMy*+Nj6T8HKfJTdPD2F#8LXJ7}z+ z69~TXpRodx^TpB4@%);Q4Ag}2UqrFZ#${n%I$efPc?duO7~(#b!}<&DrsiBF%<7+OW8$&;S_fMoT6xV zlb_=`dWYaJqI)b?0mLWwFolt#8+!39`lA6GuR^+LQCYSM)>$=Q_2(%z($mF`0th$L(o^MkE!wb^&1Q>bT&ON@jZi7xauEMsBL?L2hD6nLDiH_BfL z-TCx!WEW`PXChhnH!l!QZS<~4LfCMRED)oEkSy>QGwVU|2Pv|!E7JIiSrgh3H1Ahy zTCNy>4p2TdNr9O7`->69AgO_lq*BS&1SSRT+; z*yxcWv`{fb^xYJyvUmBhb8pK;Jzy})GIatN9k5E-5GxMC4untG5?ALkaT>%Jauf4~ zHHMx>(R-I+iA1*VnIkn55gDpYGW!dro`;iajBsMFkH1 zSQYRwpn~19lu07DI@GurVz*5Tu)wOV75(XZMlgnT#jtPT{5eU^%4`8q>P{p;{t;!6 zh!Hw-=}_2m?!=D?c)KbTF$@HM|BuH0`>!Hcv+|wKwAACqAQ^%)bH!}M$`srLxw~K# zW}a4m_Vo6dgueaYqYZJo!sxgZBzUL=D}NDM>U3tvhU67kk>&BRLZ34^fYRkuyES=1 z$eDr_IH%42Q+5$^7%64^HOwuh$ig?fu+gy~LJH$0`a@heGYYcRwFM|%UFbpIY6@AdeH;k`k4C3&9 zV=uP~lipxxmFu3qHl1?D;~6`*mX$-zP_?wrcG*3bL(8{lyBL#ZWe)xIR4G}tKShx0R12b45bKCLv#l#Hn4 zD))@v(Y!2N^w#jHr_Xp~V`FLETq`jqlMYeu0=!^zVmAPayOXhI+zZmD2@|g9g19vK zLZPv2@E9Fx^+#Yo5(k26L%nZ3^bck~0ao+CH^B~;Q&<8FqxDdb* z_9CpdO5zC1r&9hpu-Kc}(jhLur?$WLiCB6Y5BVx}G^-y&3)Zb>*X^+g=@9KBURWq0 z9KiRIzACGA5Ur(Bft8+O8)IvbV~HE7u62pe zX#sPyHqLhBfZm8RXUj^+LblF2G-(YmKsVq_OqpyxlS-BWQViU;F#rA$ z=A>6CUiGPGM(My7>YcSm-{U-=1y4#B0g3}Im0TN>kR*)51>Ahp8_vuhON9Ep^Ss6W zsM|TV&kb#6Ys2HPhX1!{iFk=0Im3hSSIjgGH>jJ4dNz;6E#q4-*wNIG1k7(^YmRmD zt+HxU=?SGak-J0eP3rJPu`(AqRQ!61Iz0EoJ`bBQBSQ9skqaEGfvAqGo*ic&~1)lkEQ|B{L zNihkdI+!Q>?FFs)S;_|f2=t{f6Pj4W`Q!sZhMocQkQ?E1h!!P?suHc)KU%|KqZfUI= z%Drp>Z{d;Bo?TALO)JP`_wkpU>ha_PR$5bYBaPmj7fWDHK_DPV)gQ(&nCScq4tG?q$X2v60u1oEv6h8s!>m@WnO_r>Dl<}5I&nxKPi+z->BuzNJ(^6&fHDWfoeJ4&Mnsh zcy5W@(-Do<*P%Z+mLfjtExiEY-32`Zm<=_Lwka^EZp0oAQ_=bR|>b`i{Qj&SHI5B+)^i>s`$b2bJyop2cFcBd5F!@0)Z=lgy&V`^6P+nq-(F5m7kEC{3(*8H3h-yr73`g%f~e#`3&Fvo~kCEz<{ zXneM}BDwAm5QHDW(q)p^O<2lW<@=D$Y#h}OlqaM?wGk2IKEqkMbyyEc5Nt0E`-Nii zF)2|02(3KYi}*MtHEBm$C_)(sA@Uz*4%)erCF7q-N;nH+osJG*bqvTO0Ki$0AjBEG zSStS|jx0z?VfvbCXsIcKS*`p?N|S}L4F2%-!w=^0A9*x&j6BU+Ox5a5 z$&mc;h!8;2fTKu#V>TW3%rO$9+T)c^t2g0#F>IsD0IE=Inm@t{Gk4|Z#qo9PR1n7U zL0s$0i6k{}e!C92C4NVVKK{`tZrl8>)#aplBFxr8mSGq=Yb~0dniz5SQ z7*YclBV11ua8;t%(K&t>+!w#qIN>h7p0*wOsyk0Bs954TgLqv(yLIeo5s6YBzTZZ{`p_KmxqKS>#3pQ<}w@$OvQ zF>P!Epu$VLj7woOCA%>Lzz>K$*%~Ylvg+zKg!-fv=8gZ;?3Xv+B+!BcIk94ETrH#{ z!#)~$mW9>1P{bq0XkhX{d?T|Ur#ub3 zFf$9?iXvDZLGO;yofz|3w~uV*<+%Y9Gkj_&JEIYIh~*1^WK!c}YI}q#LZ~I?4X(YL zWStctaW=*I6(iX>C|QPdV_()_)v2w&hEr`3Irh{n&@vxh`8e@L?gd`1uFp7_lV=T*k=->;QhFzQ|>!EB6d=pC^gniO;b&JwK4n!avM`r>t_ttP`FN_hZiNk z59&C@;Gs87rwPoUg{)vTj_G~I4jWthynrt4Sge{iV&y=C=6BzepTysc;gdjz zizWM9+Lw+t@ld-7X_ZH*^~mwz-{)bbh=)AaY$wI}j!#3f9+g0gzNM)z2#XM_U!&ml zFb!uV6oA)f9nsIy{4N2Sdh@Z+{~h^jd>m!s@!pu6^gb8LKOcSV~+n_ zKnV92;p^V!>Fj@j_2H6W+C%ndt)0oI|on z7y!P1z=fJDEw#*CWK1|HEcz`?9DARp_e$;iny)eFyxP8*9l_dB%8j^}>c_8zhQJJ^ z7m#`92!t5=kA;A8cJ=xzu>fduf(K#Mzq=CP%z5i%SwADg%Y%pybAGL7gZqkP#zwPa zy`d$D24=O=+&8mwsq7U|r8$NgwI;U@5i<*DaN5Dq`Q@LuS&`7~Bn|0X5Y>TG^YJqh z_Ct8#59j@~TbwBPCpljiyiS3Ourk}#<5ceO7mmbDiwwrl%DdB3e-=D^&L#~jcpQBY zw=N&yH%_gij!8^$;$*=V?k<=sFMs!`xDJ1Es~~05nCnS=KLc!f?&}r&x+8QA5NA=E z&qDp>lNg04rHTc4c|QB`hA2_ez0eJ<0E_C1DfF&QHBlete#h7?VYN=;8|u5#i6%?E zzHRBbO#Ez63!T1Qo%j5TD(&93Y5Dkvtzt9NlIUYlq45sYoYxQbO%}8!L24op;uwV6 zzyI>Y_tn9~-2C0{lQx6%yDb(8oyG)QGwWo1l70@F#;kI@3p-1BcyIjKBz#sIG1 ziF3AK4YZ$sA2XOf#|}cQe24Q#qKxrWw-EWP^pC0 zAGar|bswzasg{i!1{pc?%`N(CsL&V?iAzJelfvM>C)xq%)qSHMg;=*8h+0(bKSkog@ zp4i}!8qlKFd)M<8XJKCE?{vH#<<2TfXzWVZJmK@+^_3srQ78_kvln#Wt^aJOYy~(C zrRTJe!rpNj7bPvTl{|MRXKlpx2mSd;?fdJ9f|--NBvc_JdP^&q5A0*#_f7sI*V9?s z!?Sg}B6;wWM|+3PBMpX4=(^nyI%obOk|rc0d=}>qix7Q;>!Cz8b%=d@OIBo@iDXjd z{6l%pM+%$X4VJ|du^rE|)WKjtMD2XmqR9vEkGi+eZx!w$Gk0X@;xnXuA~@)hQCkd! za0hClCzr%=p&YzlI43r;K2AhqIhwZ8E_qH0BIE?0w7Gntc%qiXCq7U}?0_0GCS{(* z1m-k0+a8;uT%fHF$%!Fqkq{pU$cUpFT{yR9I-$eoN_(Z-utuht2bU*JHPYxyhoL7# zr9ZZ>tCuO9#C27dn3NUDCd%fAFSG!J5<$z0A!;idWEbmX+#~ zG;hYUP&X6_H6|q@xhSp;IWP-GQBtujr3q09wnN4Sw zbn|y$zCJfZL1Z%$W(w@jrZQIhZrxk^M8b=TjAws*3nsv$u{|x44;^!D~Y$&YYN$nMRY&~&UTAotL4kKq#ame zJ>vQ~8l^N8qGb8NMB8C$W2BF5;Ij*&tJ=VSbs z;w@bnr6}dfyd)bdh_28@AUeqE9ri@0QB!{ONeZZ=maBj9K+Gsz+5+DgRJ;^)44o3v zB)FVMX&{rr@()j2RZ=f}R3v%c0~|N{;G60$N))5n#VHY#Wp1k?nLe&rf1EYgtDGQ< zmYw8SB9qVFPo;%`eF;T=e8_n020M`1Unfh$jT$dk%bXhY)~D8c*n+k6f6936%k&dM z6nsb5V&{^Qa>L6N~0g_VhxLVz-{V+H}BL{nw+x+|#%+RyeG z+oj3%qYv#?ud`A4Pol57WB{W;xPb%-0EPfSlJEgQ1^@?e$wUD=Y5)KL00v&)6^b12 z00007Uf#c$$}m6x004nr;nld-<|~8imF6{BcU)DkLUW(%Pm5&v0^Wn!-Gzwa72rGV z7X)oS8L}Otxfp)Zm=ApxJ017fP%08@Zb+3_~;KI7!c%YY+x-I>JKCs><@&l|3IODj>5Ts8Vk>q23kHHjqFw#( zL;wKl|H=3Nhy6!Y1LbOcAiN;Ij9;|0zKaP9J1rY4EdxEhn!x|<3x|jC50m@-N5+5T zAJqJhIE__*K*!;*-s);e(r^cjEPnvP=Bz+t8`F?rRb5qijzE7vqQk%-z^^=&z5k(* z)&+pnbp!y7WcUNA)TOC(_yelc|3l|LwEsivKeYJ+{iiPiW{!^k!%8*m^D`a$9|uLG zFj7W9Qch74wMeHTLpYddC!{}M1o3PVL?h2(@q6oo_o@5cOBV7Fmk zq~ZV5iT`q`L<*zC|A~|qQPh8(k6|1l#wMZv5f5_ZRPpH}l*_?!DKM@ATJo@T)iS;frqgIy3c$?>qOo z7yjUj^Tvm7{Ks_v+g;UDZigqf{@izOvli3imWs}N;oIf@f=y}F-N567#`at` z`|Hp;xBKVyJ$Lkd~c!5yFT+V`!_Yq##sO;7n9 zXK#mQ?jeru2CHw`kKFZdTW>3;C&_KJ{}Py5d}Jrq@dXE2(AUiFvv;rm4!r;7^1{zz zQ|;<~PiLJc$s1U-?ctZ+zZ1Z5=^py~>r=+}dn5OAw|D&9BCx+~KIC$c6gi2`b7p;k z4}VF5ceNL<@vf4!hxCU>aN9xz-LK{IelJQK9&YkMT;_G(ip`Jag$bi6LZ(*lP;YJe z#-=?^lq$fV$c|wUsDJvDF+baBl2Vx-0FV}>S*b|;3-s?uj#K50fw&kyB(YE!KG$s> zInb6%y`J=%@4yMckIBU#*$$2gR}6~9#Pst%mS$Gef`%AAt@v*nkAcwSNG){jThWJG zJMIFOsGtnQWFb5=$8Vx9h^7a z=b$W6_*QWElfRWq9KJG1R-}e3s_xWeDTcB9`(V(@og>) zs~rZl@Q3NV8rOctdO+aOyYKI2{)FN}CO59&Faf7UE}}nPFVN35ZC*$Q#5=gwuXCX* zy(h@}B8sH4{7{h2^(9Od6a!jrj%z+>8(ySwIQJ%rEpmyAQdNhH^F7<}0)x#u=}OzA zX^&N8@rb;Ry29gPjm~#An)`eubywA}9Z_GfJXll_21MnQ?Y>s)_HG8)nT?#|9b zt78(Dr%ypc=m}FY^YDdWL^O5ftoBXIJBML6J@y?#s1GZ`Sw4ri zg9~+nU(Uo0zke(2pzyjg@co%rx(9*h+)chPv)Uy30OajNEoErAuHk6ltQ^`!N~1Uc z&i+{Qw0X+F`rGv7M4pst{dBTp9J7qsPWTeR4>>+zg~X#(lv9kLQQU6&MiPAVP*`wc zn>$Q(aFRt)osiH71pVzwj3PFPm0x*POko}EAM!YaMXn&9xT%3a-}(ejo7kUZu)+){ z`s}GsRJV$D2aF!?s^H zb=UCv8-SF^gc$WEUWt=*21>6 zti&qX7#r||i+4w1D$lolP^B4(MFvWA@uHS@Ey1j1Z*?JbCx$0zYCABQX@ z-AvNL1~vK|ZUVGFL|n`)^nzD%U(RY)RUe4N8kS~rL=AcUiHmS=$Qww|5(nuz_?ta= z@y+}I`|CHZnNs-pss!@krc>k7>2CP`fItH-_l!_6RlbNg{Q}hMk|rm{Q_|mZF9$if z4h1LJ`S zyvHLE;TVT40h0@qWwJyCm9#~AjNuOx2$8!|nDvp6TEpyVJLn+?OcugnYzXJw0Zxa+ zqZe#r!5GxjH6;+ck=|g_ay^=2Ijt0UUaZ{?K}Db#;153llk;OdJ;V+$u4ZCFn!ZdT zSr5b*bf=Y!`WOKDAeAZ;x@aN>jpjO)3}n64khW~e{iOpu>g7ubf)*h>k>&W{Q5i!d zR3nOk1wH|i6XMWYr@ncBl!gZNK@#Vgj>}RNKB(ulotcZ85~m={Iba?ldj)ph$Cs+qZ;Ah%&gOW|xg95N`_j zZ#xZtq4RiQBAE-8BK*}oH0YaDo`hA$akVsb+#p|<^yIn!JG4S4VG;!AeDoa9`}qN- zj~$lf&E=9y!_d7}>tM*YCetQ1$dc@3UO$AGUoN!u@UT?LWGp`3GiQ4jd|zhhX)0Iu zO;`HkaGllrfcfuF`D-9k<(}GjR!fFWda?|0h;{30G_&bOD-LM(4QFyS33;k@Y1=au ziF>Yn1id&}Tq!yDLqZiA2Wdk@=!q4T~@+>9G^yTV3Wes=J zubcag8h@a?6#se~R|@#$#=Uv&xlW8YCC`UOuJ5!0Xsd4!u!lzI$4;FL8ARbZ?+CBm zK}`ug9u1aG^Qrjw5rr5Jr4a6p%-tspYd?}@(pHof}5fdPY#WJ`07Wgb46Et#*M4M%hyXYQoZCFJkz;^Lg#&C$?61}t{b=b?(^5nx(ulk+xsY$ge{TkJ_OiwP8pY?f{H33{^L-7^Cq4-6kTGYInPq zUuB<5mf;q#L&kUt=t!fMHjB{nscMCO_Vub!JY5;GyzGt)hi=#~ucd(yl^i-zX2}_S zkTaTqPsRIXzKK68o-hQ@p~tKu$LN&-T|RZ~YA?ovl}oJ++ZA!?Ov!B%`J@>>TsWMAyxbf1A?O5+3c8P z?h?XdxV+_go>-}|md?qG+eTL$?)6GGazYT^L^og$dV))T=zopdqZJ#iemtPm`Jw@! z;V)K3cE7yt&-m|af8JU*MzhIaf)V*X*6Hj6Cv1OWZNpQjM+MI4N>|~;v@vTUcPX2yaY#9kMYKsl1nv$gn1PpL$L(3@cdRdqmi*?9~!2r>!!l0|C30-_(EdW^QI9 z=B-fYkn1|zvcHt*;%22xITU$Et|oPAw?pds_;e*bPMD-C8u8(aoN%nkw9D08H8oa) z28_?4iWZ5k`bQ;ED7S#Hi^%Pa3mfg|*Kh%`rch93A?Vvn|RZiOeK>Q zzQZWWu5g&iTvE-+#2S+duEuAj(`vk2fgx7+Bag;*WY8@)6>!$v3pyVbH@Pn046i@0 zX!6yON?Oj0w%f*qQEuD*X7FMr%@Yh8r(tGC9EtfQ#L_R%LI$103J%IpUVi#4FZS#vE??&&zvps99l7EtEX z!g3#wc*6@>%OmP`5TwutybeZBQSix>JSy}?JJ5?R?=iXDsR0PHgK`<`E&S58oS|P- z6OxjTbywR{?duB2bIDYf5=#RLPy(Dwiq&P>j~+B^U;2A8jHF^8LZ@h#GK8j|Wx%Z~ z&_Tn;;aOG{(sn(Ds2E7&67OR2vc(HIB1R+KfH=al7m}EejRRZq+i;A5R2+vumk0C# zfF$uOLtdlvI1h(0C*?({g7Oy(4snT!a;M>8thKk3YtZYQ&i%b`BkTm?N55X;um?$N*q*4`fpkha17q%4{o2CpA`vSIROgrQEfW!-)a!Cww3> zb{HDh!o9s!t3`IsV$ks*+Q5bQ1 z43T9O!DwDx7&YD0&3TV_MP$RW$~&)=i{PRatSBu=j`E#k$8G$klvS%2IcZNy$%u_$ zpn^lsslH@9pXfAx-;~@Ii&3q58YOzZX_Z-f1!ahXP`alFa3oqvA6ySuM&Y3V!e>XJ zfa1Q!aTcwe{#1>QBK_QcDMH2PGWQ^o5zyb?@u!RPnBHNWqAX-8Q_nP?F9W;w6}#-Y zf57NKXe6WM7Hv$ck)|0YEVoIsET z(kS+7l4qSJv=TOPD3b~^g0ZoTei7U^#g>rT&#i{6BB$9YteOOE3-VOqY1lyypMgb> zIELc-%_Wfd)KOn3==D8edOGZP!*L*|HQe7=A|#xVYtM`a{MZv&?YWiY(td&AhFWF> z5ay*Dt0?A;+J5z3O@b^Lp6pzITbQh-@hE=%;4Dx5M^pvgJ;y3ZYM4^ z#ibc3pREs~^Lgdon(X^#O(;4t=Ni~*R964UPEmvuL@$-$)%ed0H^jPA=+NYDf;pGP$Ra&;wa^o;EXw=-i{i5#%fjWA^)~4=I3BpX>v$gioXpq|JGCOEW zq4K;^yN1zx$Ur66(k3K+!vyeKnu=63MAoW{@zLdlS27Ze5vTGP5+i|SkU z@B233gi?v44YhZ~C5f`i2_XyDw4I>tffgifbfQ0N+%#Mn{L$~`HOg;-&urqywW1$D zCln0(j$*_ZVfUrh2)iO+6ZS(&AK)P$g1(L2ab#Sw178h-x*M~!J{M!6To+BGN3$P{ zJpoKZE&(2qu<8aS09s~MJWd2o|L$}y;fcoXwXGG@R``A@Y$v{PBCq7%h3$uCt`}yV z%P@BTDs*zQyNv_*BX`X#HvAO#;`KS-Q(@wLkVvCrJ>VOe#E;zd6E$gCf}&Dt#rw>e6a1#Oh5A80p;~1_V?o)?VsX?P{qE2D3_Xiy115-+|Sc$=W6iICYox3cl5pgbjZCuwIMN2nLO`6DP2 zaAiM_TL&Q0O)>N4eLKo=;_Pyn73Xb;LB%xTz4~3J`;*U(3^3Q|kxn7mt}+%_Bu0ZL z+CR@>b64XIF}_aqIgnfaXywm%->fRSX>cU0=mARcA@RKV=@;r^D_5;}?5`EOH9x8p zs8(|BnX^oSa{qw4+mh606QnrW9&^7}cO+|TI{1@lMfw_95zUE{34(vZAdvS5w^_}x zC4gcrw=+nsjp!`AK8Ed|M{x*MN6w7gjM`mMP$y}oBQHOIOk~VWo`0;oZF9wg7P}x# zm+w=(9)9Lsn*pPg4(qmtv#(O=X#3fMLz}4KEIE8S}FLr0hDPs)3K&88Wop zY%f596V!bo)mnfbWpyRJLuoB;7jrmN@Y_)mT&!Z}8=Rn`PrYLILm+?)=m*&qcN+cV zJR9VU%9cB2EdKs=lHcMAc2Vwt^ud;zZ2a!p3k6Ljo~~ELwTMKVPWG%5?Jn|YD2XI2 z&aVj)5F3+3q3#TJ0Uhi4*$4@ry+MoR77*+2^x^p0)L{HDBh^3Si`pmtes^c+VP3!c zB*=T|2`^NJ&7i*B(+hFY{+FdNr44{L&)nT1>f|I!$7{BR;P$8?Cjue19f4;%_1U%k zN+`9}Jm(IKvINf62cOq#cbP)!?C6eQm_>tsPEH=TrYBq8xc`8Hb=9aDQ`l9Y`=$wl z7@hjW?BT_X2hIY2%peBX-XY0l?pQ0r+`bnvhetay8s?tE@6ZExxA8TCL%0lhR#6!k z7P-7>AQ)!E6#R=`TRYGue<(N#^yyGaQ-*sB{U4WDV9V+#lqP~s9+!GE%s)DI>*L6H zo%M~X{bUGAjx_j$ejY1AQ`*L7#^ zx9j(KcVaf;Qm-(d-u%iJjlX$-5?x#Az%dP$J&=UWZMd)b?Z4E;#0bnD1lZE}U;8M3 zwy`c9)i}%bc<@BOR$&@uWsXBDy*bg0Pq^sZ-Vk2g&c(s2VXb4#J#~Yh%<;E0IXlRp z*M}lFTWX8$9U1thq7cUdfm3$?gj2HkA0ZaSCKL}3xKb2olG!#w31H9pbVZPTd4cPa zb`GuduNMgOK&q_2w6Y1kRxy>KZ!pms$TPyPGzlk)i+oq<;HAuQAt zHej#NmNq&t;d^`Qcj8Hc*5nDfhNdr;=Ms8=pNb%m?(&zFcb*sECY&aLrNPr}!Gm}7 zH2^LO1aM(6iR4=d9U%v&8~9DJ1e^h_vJk~5ELD@zk?fVh{iQL-;5>!Z~w3Afa+0Sc*BOtwHc*rq8px;<=`+a zdgvPHYV%mrEjPM}Y|^2vr8&_@#tg;r7yNw>;CbkKZab8-uiPuY_>4H7dsNgHL9-*+`$g~{2S$~6r$*l~wQI+X5OEkpZu%{L{he6M`qZWBuLKO}+4NuFm-ZM9Dla zM{ZZw!sho!bNmEm?JgI}`cQBH|9*7r65Jy{WfHAlx9PE3j{_JwnD6*OkZd_DPLtNb zcig{k?o`(*LxsDDq9OCc-``}-%O@9U+lLC{5L&-LK4t6Cq5kc^-{|j{o$iz>Mvn=< zs0?X(EsU4HpIUBQW_%I;CXIxBti!~!Z|4_Pv7 zKq`0sA>177c*s9ntP757Co;WbOHGVOmB5YRT29UUb7witKnaasqH2Pte$$5e@5LLC z*2E*Dq!wQ3+b34cm5=G*O%_;aNr}S2h9meoDyTL&+C7YDP)E`0)SWQT#=$*ME#c+d zkrG^?;m{OaBHrj9BYzHe36t!myyqsvl)RMFem99jh|3gRwWS#=3wBIkK89)|=ik{K z9B>|;KYFPdff^?!?<0%KSL2w)?lYjH0Oup$)PRLvJQsR;ihQI4lICg+%#1QqRXZ4EMGHzs2ZxJb1P#1*}ySn7sJg6ku! z8LbM3LORz?e^0MEhT-wRso9fPASaRrecEHjFAx=Gk}wlInW6HUF&yUJOxG`U&hR}Y zcy!$~{Uyd_QIw2x4ai1xyQkh4Uuhx;H z9vHnIakVE3^G}&GRqi(Yga{Ov(o#d5?-GO55jN%%sd#-t(^ML9nTb$vzgVEfY2OAP z5)vATDhn20%3SPR{@w2|TA+m>iQ1$sIFpqC!s{uMu8qf?o-%-YSMNwWXG-^3crW@= zW^znqVlN@RTP(+Hr{20MNP(*4rQ#3RX`~yh&?MrYRExJ#@z!~?$xVtZ<>&jafqnyzl)3H0~9hw(NdRjFls@j-1wxr636=XY zKKGvdPQ)ej0f%XG95k_ihhZ!cFh2N3~UZ7~l9@;@o7GmazmXgtpH6^0~+Cd{f ztjJ66_E!zJDUagy%eorO@^CFZVTLqVJ|Rkbmg=B_kNcg}%~N)~_AgTRdBp<2MnA^q zA-dSXZ`EKRQ8cNudv>B~364^j@AW!-OQa@5u$2HbqQFo7Z93Qx^xVLvI~U7R@vkon zBvQguGOibALSmncbkTwSYv^q6F;NNsv((*N3A~Vev#es(2Lyqh zBQapvWB1tj4G4U&p|Nw4dUegYJ+%DQew{1!kQvX_W%d{0`U;-XEe``G9zkvuS@W%{ z?S4XBE}e&Byo<{!`G@+_f~W@(lQ5nn-tqbQ*4xwfKFjWtG|M+;pzVpPn3D|%KyB@4 zcWI2^7Fem|j$IAE~&CoWpuLE@-yq^=c-tXbl6{Ffbavm&YC#1^T%Va1)o(pM1` zLRKeX2%`Pe-?eyI7ei?&@T```Ck=+Py*iV|yYqnwyGnaK9bQ>hwIvLsiLJKVFligi zD}0FxPa;oVs}7Jb(5$2*fI=V|7`GWRY3YDErWj-2^scr(P2rSDg=l^B9B?n3w=32P zv?w5d{M2@_$ci?sf82^^6pU7bucHL7fz^pbEhESqW9b=EqIx?}x=SYN(>$&toNFAPgI+4;*3sM@Gf1ya3UHWJa*D=j5(>MT7CyC zE6-P)xAzCX#R62xf3fQ<%!E4mnd?;zWyKYB)IbG0B^kjoHx52&>4w>llSYAZzZ1mX zhX3;=+>MI!&5JNIDs5tgK( z5_xY;3$n^(5b`j&4sdma{G!rGK{JU;b&aLhA486`H7C8OAJ!Sp5F|C6wL>J>9xtEM zr(n=ihLO2pdr#`4-LD^N~ zQ3b!JWp%1%aYvW8OY~wXL*U2WYBn9r%ivsYg2PyFzS?*oT55loHGJC3eMLcH!d$5+ z+?5@LzgXJ32tp-UBDn}hFSc`bj{;m^pOBAOANiaG7+Fc`Im`*gxgOz=@1FK;z*3t6o zTJD_`tZ368vDJv1{q|)7_S5O9aXZ#BLV^@)0g(VlQVHK72BaJNnj~z}4)6M{QKn z;WEZJ-Bga|U4XAdl>R#1oS9v{flz5p>j~NcXdfm7q|M03xJjj?SAlaeW85s0AhE~K zCKeB3B`AWBD7W7cTx0IP#@#eQz&3OcGB1%7`}^7|z2xUOll&{nzHr+E)hd(wbEj8V zsY=c6ugj*6#t@a+uA?ESu5V5y6`kC$u=x$x2V_mI*TIGNr`V6iee~q_w_;MF~pq8fqSigsz z(FY*5Js=DSLD;s~CHdDRlh_&C^|7CaOX-c&d0``Cs(5!(M=5p+lb%^QLkuXO831Qf z5mq>eysE8c&q-EpbDj2PZ0AB?veZkC3F^zmXLn-z1h@qBy@Dc`(LVfV+cwP!Ry_H7 z*hC_8c}}6YB8Cpz;xreKc9#SA7eRg;Fo1I3P9xHlXv}fY*}2T=KO&&c2)Gs#1wQo( zU49BysCawRoy1a6v_RACE&fO<3H_}JP`Uu+eG))xEvM_yY#FJKL9Z5NgI~Q1zS7Ru zlUknhImHOcN>C$?KSt+Smm7qd=~z88#wm)t4*`>aavx?ShRW{P!wUnP#Dfp-VUpTH zXUAkQQIn!(kR%mriChfJ|0pY2eb-B1e_*-4F+k04Qu*r$U<>OHB`Im2LhBC?psMHW zM?08=>uMvRnFoiLJCB^NY*W zPY460fj`<`;F%Ea8I5;G zFb^9QK99qjwqLd&3Vtyd!XV8;%G6Q&>rejW;sg{z%cL>yW%!ekWdo?bTDki)t;i}3 zv|`bWL5CghyjFWEAG9&pZsl8HGE@H!1#z6Bg(CWq;SJ3{nsGNEf28T-><0vds1j8w z(Gd%K-y*%LV=W0CGYkA zN!D=5r*s-YO^G|A3AdjXQC&empqP_z^Rm8r*NY01?xrdIXgW@{ZF~l}Ri-o3$qn}t ze2z_cuM7Bb5;STkCZs2lG5Nao^`Z#m6vYnn!vbsr&X{}o%yV562g8BxwNq!)vusJ= z2>fta@a2F@{n`qPne^T_5|Wi#lF*K_nO;oc+>3#ur$5Qk&?7p*K2^L+mfJ>q3o6q^Lf>vvFN*lY&H<4vCg7t7^-v zH>m7lGv}J`*~_X%2bK8Xv#a6teW9k;MW&{?$3;S&$^c}!53m|4vMwfDDux(OWgSbz z$7C%Gn8{)RJU=nJhs(xf<5G%lBDS&wbC^edUctA4c~ z8Qn^$rtq5w8eFxb5|xk;qJbqL&p;YozJbHj-?3?HHFptUlK2up?BqXO&WWTwDQR$7 zAZup&atSxHox7rP++PhMkPT^&R<^f8esshg3OlR|h!Y2!y0TU|)P_AQ498DTQEZ-|_!W+(-Jvzj zVMv6D6|r)bx90A#?9Gh}d_~2_SkkcFwmF4EQw_UM(T06n$np|`tuqQwp}*4=9MQt; z5QtZ1ZZ9s{aMDm(^p>9wOEX|&-Cw1tV!ryiSDs%rj!gGMq|^C)|70t){i(VN`gD&# z{sKKpNJc4do50mJ&NhElMklO5+kP*3?HD4rHB7ru9b5^5Cfbb;|9;)Ck1BKOAFZmn zi$9X2Vb226V7jz)?~*VrfSuk}xo1NL5@3+xUMJ;WJnf$7y2Jo0R2@cF~QL@}i&kEE>Yxmeg3lQqYQ{sUZ z1xK-eNT-V&HzZh10;?C`Rpc;nA2A7xN8uj?x3$5d^d`(NtW8srsKQwtQv4VEFOZW} zO1nr|2En2?np#Cv*))A3S=Q+?D+U+{nwu^me7^Qjr|CMC1dsx~{Ru{Fs94qCg<3MQ zp2MuV?bj%t*7Y!wuEBHX999Hx;x2vyO?Q{|w6tqkV&II~Q&x-yzbNd2_|ibZ-zecE zy|~_4hd;E6A;96IX16i3T1{I?p!R0klb^TyAYJuXEm(WqakGUx5eG3Lm`1`Kaq*zM zE!QAT?nMTr3XQ0ho1}+pX07RPKZKB9CNJQbGz?It(lDt5*hpu*8kWbpjPwYDS=Wz3 zdemU{-c&(EDMxHQL2Qdcw%W9L`yhmstjm&kc&t&iQ#wFzpKzcKBK4qGe30Y`X{%jg zj2-!<@iy??B5h4g)EIdJV+_~(pifAnzN zX?bP!;@zssJ@urgS6mP`4Fl038}NSxSI4%=2#tt-OEn#AEeQk+p#p~t*#V>nf%Jfm zaW}Jn*59C(eRiLHEN)qHVIskKHgH0GmRdn_1lTZAaPOV522BkSWzNk#fjr z<7UD4%f$TMhSh`b99J}bLLc?lF2}6T<${RqbWXYO3KCL)i^7*E9|Hcf{sqR77*Ajy2O^R3`MFsa6{S=ay2M=heG16Nx9r{Y&3nm)6M-y0H4#ExQD$ z?h`mQOR_M>Nn0_8?tA(fY$o4%x{eES4zB?+Ooxvi?tKc=(Hhvoa#Q%^TwaF++slLE zyST`>olT%??^SE*EJ_YdUdI_Lhf_NQA$psdkisDl0tkcl@>sOur`dY3XHp-m=l>hfvIxcI&DSo1@^GQ89w z?R83MNnK{~9F|#~Ba(HM%CR|o?265R+glY^&oUKd-ew3f6jue51R2hM} zA~tFX3ka5fZKK$#>lm3{W!himr5L=57Kbhp+ha@sf@~Wx(a(V|4H#04Y&Ct&AL5)} z=3(V3mi=i<3eL*;(#BuCr?Q|64(_3bw@`|Jk(0<4?zv<6Ag_dkIbV@HiVv_rCg(D| zm(DxsxI>}Dtr!(@;st!F_}LsH_I!pDt-_d{XU)tN{R5H--a_PVEn`b>xjAg1M6rwQ zJIgB!Bdr>tW$!-yDv?=AJxmU12W=!U(T8Ihu#5d8!i5`-USM79B!tfKXF*%K?!2OS zNA?_KGaV<2zUDm1y~)x+08$;uR*;Lkk3BG3^p84Ab7y4^g%dPbYN-b!++Vr%gkny>jy@Oq0pP6YPAc9eV3lxwTV_27;PV<07Nh^Tlk@+_Lq>su=RtH#41 zc0{}q5qemt^~=x~X&8cNV$6Ny1!8HwtvbuSKey1!DCL$}%X+zH^6<>&+Ke98pgT~A zFU$;OQswrdX3fZ~sT-i`sOD4ctx`f|?go$YyS+Z=b0-Ee>r4sN^i{-d3x-yc8M>c9 zmzxy{R|hx@_sbgApOjB#p`F5->_?gQ_na(JYl9|w@L;b zT4ZG~e7`Dn!8$|HYIO(742UWF%9GhNAjSHJg`C<&A}KmcxOe#$M1Au@A{6G=mT!=q zWX+U1?2B=m6rFvwMuRhKgH@yyv=ELFseE8w6J{DA9W-va=eKJT4kwXSUl0!@BRSTF zPKzHXpah!D~qgoYWw16p(={Rh01AZ$_clcB!Pm(-6VjiAQ5QTCNJNRW(VyvKSqAdgvGph`o5lT5ec(0m{l((^G zGj)Z!@jTQ12-Xcl5}L)&3iB1TZZHt7ITyl{xu>E!z|%q`h@9n@k;K)eq)3{E?GHgQ zZv%ncQ7%6$oFr@}ipCBoGKvbxj73Y-CfbzrmU)T_cwOGydHI9`ky>%er-`DV_jk(9 z^9PRsQV7pn7V-qYc1c)b#Vm!dw`s-`Bb{NLazzRQIthw z6LARKwhmjTOkomBBdljcrCKE1Yx71Jl?D$l?~L%l=_?}=@u@70f3Bb)33jW|5Rr0% zl)j-by5LU+R^6-vPJSGdICsO01P(a|v%$hsS5nId398 zN8rJsYDgI~)BMx)K8Da#m#LqG$Fqz=f>#Y2zUc_r+oD#I+_7`2Im~5GQFU<{jxH=ZB=yXCa8w08+v?TgE8O@9vuyGW< z_A={ECV5n=y_+Y{U9)8dqw&*l3eQK*n3^}oDAjj-ZZ8O53Ts=%xXnw#*Vqct z(#_Wd+y_jMZ~Vh>%M#yUFx3(EYr>&ozN3kOGbvPSt1*dtqpz*v^sPl9meG`#n4aQocxWOAR)@&SK3{U$sh; zbn@G%_u=PFdc6bhN~Ui{y}kz0>}~_Xqo>J@*W~|v^tb3ORRo=hT8OF$H9_+|F0pNN z$4Bz0XPKR>s!c!Yoi>#Zd^GhC!HyKaLRGn>V_}J>u057JAmD)m2c~qV%_R!637EHL zA=%oIA<@(X>`+1)&2CJ!0d(>s7`KOOfhJ!HWML%SVL<`{`EdXekN<&o;wT|g#|IQ| zgYsup_btpvv?(aR!_8*f_hUu5|{M3~vC#XP8MXp(>?htKs zLHh%DF%OFVnUEG;vnlpkU~@9)W5OD;QB8ZKw~s<-gGRPKxdcP7Cf9gmvXIqHP_ z=;=nNzagZoCPT-+$S4(31wNDe%Gha(ioqyadYHt5gpoNHg=zI^=G8ejs+pIJTpZ z5Dup)P7DsVhv0utAg=wZ`nD*hel*ve0-o#Fg-%J6`C(mr+y`3`WjBV6wUqqMzb50p zB|aLz^Iu921c+Ycb5vukfv2l4bXQaKKNSbQgy;7JDk@G5#>Al3(}8Y@SlR*R zE*~aA1(z>!RKi;=cyll)N_FkjBnWCo1)t3dLu^FMO+$8KaF{At5sHkD51LPSL<0Pfp~1|3hoUC=wJ9uHe6zs)PG5hMH~tp@CqUT0JmxCH-)lxw z(VLr7E&l_(jo7+wuU?Ts1uXWzw_vzY0p8cYKy{T>U$@%8BJQ43M+;yx8eGEgD{HfLd$f zHTZxeBtQznS74Y>ad$eqJN4xemSZTQd>yQN#)lp;Kkn=IvpKDga;Oz1M6aBU96~61 z(@`eR0`T(JdOyFa1zMh`M3JB7Hq49UAbfJVF=tU>U~7+N_S7tn>ym(3AG+0N&F&7T zEX=hxkct8P`QZYfx;wMFgU$OSodT0Yo@XpDmq!%?5Ly}lie?`|0``h9^?JNi!7RZM z+eY0`Akrh>3`RvTNUe;ea2MIx^x;!bQ?(M_a`Q%Z00QpAGbvPvwR(tX?LVLJ+~S6E19 zC)D;IUmpIE$8gLx{c&}Nm6i3HZ9Ko-dn`rcGvqC5kOoGe-dlH6bp|4@LAn0&}} z$OF5Yx`XM!0xkF6yANl%1k}b0z{$INTiBTsQGG?3f22N+L*9ZfYid)$cQME9;Ei%#Y0h_mg0d`44J$H5Lys#|W- zTxOxByaHLGNe!P|0#oDBx=_c)VQkHu|6gv==Vg%kWS{hjwlypn!(lymchd!>*`hdW;%?= z&$B$2>G_*li^&yvHkPWVbPqFaE7S-;oXakYO4 zr!okc9%^{h0Q0W&(k*}=@}}n|xU`if|D<_}%a3J>kTvj*6^z3E$S{?JrB=OVAS#7G zof@n+aIhK5cQ+R>knI%MeJ;(c1rwr{VtKY?Pp;dd7d5lw)f~baaS($peB9YPbwj@B zo9vl3lvJZ$xOkBi8z7GKn7hY_P1@pV@S~^$cH@$xe-roZ8aEnXX_EZBrY_P|(cDP& zng84|X;n{C2n(tR8q5KFL@oSK2a}acCutaC3p}u;G-7>wDsNY~48ARc6NhuFmX(`M z4i-j>+o<)E4@lYv4BLi3EycDhQjV?sP1)YAAB)E%%ONUoNHP*#ZLfMdg2A+9Hi>5E z!|qx^F>O2BKQ(T({yFN-4YUfMpgxBj;7Po3{iRVXtH+Szk9SPVz#@w!@Z9p-VisO@ zwETc%eFaxl-c_L4*+XW&a@yPH=<*2Bl&?lN@Pllv#;Z-)E`Y#06ihpb8EZq_PbP)7pd`6Erl@tYLOgS*hivhKp$B-*V@5mDA+#d z5X9_57~({KOvf-yxCbQoyN-$jX#&MXkiyCJ-alPGES^A1tLuz;qb7EaJoG3KPQNOQ zSV(nFWCE~Oqf;9Z+gUxxrTsh3x~zxn2Q+59ZVPw~tU#}!`W{pZ z$aSFZaZI|>k;31cQ3G@ib?(i4x1{cI4q_;%5#w_s(x<%g=Gv$?|L~Mak^zP>Ox3Hz z%#kEeIu^_g+fbDWpCA&)r{4zcxcYW2EfZV? zq!y7Vmru&O3nDSgix4XQ_QNAbXQuRSAvyG~hy~aV2p3mm{4T{K8TvUj`N;EPZ(y{U z36r9|@n(ZjJo}&DEkp|EJ~2H-ptqIgXOpe^W>)5!=I2(*F0&-VO4Jb^2^=Rdy(B^* z05O@^TPILDlN(q2SN;^#{Z3+kbgw6xx3wRqfmIusUQ?%x6n5>bw+mXIUlzjzLw=_C z9hrY?rQ;xty>PFYW9ws9B8TAdhZS8209n878J#fps1vGx>j+Bd$R zq%qTHis70+gBPJ*2Cw^*3P#uld1(yk+lpYo-8@AChf_|nkyUJoK-)Sw)~Sv*@&gesJYUnvtiZCwIEtFrUyo;#e_ay$xAd<9_FzDe_RLCMsop2H$fh*HCGWKrHEAne5;AxY%aP(xeZ-{2fPf| zEz1bHVyfbY82y7LkRyv-NrOQT$bBsqYqBfIN*^;Swt)ZRxg|f}i{iPS={}8}L(Dv~ z4Ws0ZV13Nio-veP1F;5LKflK7P)5TvC{z#Bh%pe>0wx25>-aq?`s5naqf;~u??>VC z6v|196L#Sg={3dm{Uo}~!}^K8C)^>A`<~~01G&nvM0|;fLBFdmEyJ6xhiy&zf}WV6 zzFg5ydLxS55g6oErLXa^*j~|K>tosNln9>U3N&JK&Ka+hIM_ z4l!Q=L-Rncrz}SU4ii#7H@WT1Wr{PeC9UKgUvdNXrqY~jYwRaCd(s0@uP)nZV_bQn zg5*|gzcp7+>e^H9v!Na+VlY5Y;x-(C2T%bvI2_{&N(m=r5Z_Gh9$eFUy{pCN{$b*T z_W!5;kjd;48W;D?E=sDMf!jwsNxA@D+oct8-004*0S0gX$F@DbJs0Gy_MG=N)6j(k zhE}-8E|+af{}(}+jR&&8sqo|}!!iG@fV7CeEO$Q^f5G}|`TAAX<*XB9#V&icFLeIP z&0d}>4amvmjWmzkNl7Lv;hug{!z{qKk6hQXvtm@)fvG)g7^PGb>G*D?o6w0Lex;Rv z(7XK0BD=^6qFfEvVX$pjUVALj=6`&u#YhCqk0i}rxcMhLVE(dUrwR+9i>}Rj%|RsJ z&%??z9OX(YHk>|_KhCVml@YR#7l@f}+Tw;aOarjc@s(K}3?|`!;~nmmszog`&&jM2 z3}w_i6xb-U`aqQXr%{yd=o%YfREmgCHTWRl>k6BF$WM8~P6=%fJ5NXgzs3rNfp9bb zMhzGF-yfd#Ww41sK;s>JiW|*xQ^-NL>fQsLc_FYc2ZojHUo=6(Ub7t1OIM^V@BWN8 z5jXNR6b57NBPDIA*D2LL@u>d(f3u)ZL({3eY%|1*wA=p`uP4J84805S2h;P-)2p~Y zO|(mDy92SI0G*Gj+u$#R;$g35zV7NBL7msfLon%Tv@7&BkZ8pk+g* z__NtIKv{Nue)^%X#nE9-JElM`9O%%CfO-F{@)n@^>8HymR`oxIVo|(l^Ry^n^@&FP zsiI)fV!Z(;6e^8)Jr<{exWaoOKz+Y$Wo&sKD=qW2eYL;s4c>jD^!l#PMH2^WRjx(> z`nFuCJ=uO9FUF?~`c zA9GJ&+Fixl&4bUALtZGP!v)rdS-x_KZ9h_@8@?xsE!Qkz?e7q$zkBDA^j_hS#nHRMJI zHn;4a4{9wD#)C11<-F~vKYyvZSp3*K^4?JHdpy12pUK(UUDZfDFdlLX;Kq+oW>xGp z$;!m|7mVq|%l}mrgnMC?|saQek%ZFc%X#gD;9F8uqyFW&GbA_3-2% zg&<4+_4 zcKwHbro0EQ8RI@HH$LbJ8_1-qnYM|&SgVh+L$=r~&`WnmF;~Spx z&Xcc#o}zq;2Fa~k-_co(UZeYs{z*h;m(1h-;IKKHfvFMhS(i7sVDbAok0uXC{3bQh z=KeTmK!0En`;iX8*JdT@r;tD`9@wZmTB4`Z>MT5* z)H4^0Z*g$3{Ox~FAn6s&#hl;FY6iBwXcALOs8 zJnC*N|2e6KB>&ftL>81N)%A&otTZ`|b}VNhNs(ZE0&<8XldxA$Y_ z>LWa0JgQkPx9~($Dj=*I%2gJiHW54V4GA`O#!6R~vnoHvsZ~4gzEbQ&KA9Sz`;aL* zCsB{k#6K{#q72Wha$=KsYq5tz?cu^^MGzVNhHXG*Qlv-7Mc7CLFBUW!=<4{kCcbEh z9nJDy;(0htx}KNughL3a2uL|Jjah*w?TV#M@8*9?40NH7X1A?8R4cKjPdnIO7W5tV z*D(~|rfVD<8nqpkud8h(u|*i~Ted_0$9$FMXsG?`h~2OOEGXo8mLty*Z#ZCx8oB}e z;f3OacXQf9Ks%Tg1o%*mH-F{+Mrbac00Yh#YqS;>#kkb~XIPmS7$b7-LsP#i2VLiE+)+i>Ho>>QdI#D87MQ+WR4#`9l}wtnZFT z;~2p~9Rd@jHWoQ{uK=FORdqdYTYECHt*=5Hd-f-~X*KtK)dUFV9>rlq<@2FX=C{jb0U6LsY5q1 zn_5dLkkpH~yM+~vOmNQ4Jkfv8{w__ff+eIc4Ed#1Yh3Nq4=5 z9k-Tm z`v3p|wmGBw#kZp2yGkO~-`*!{wA8EhH4sqtMumnsRqTF-FoOe&p$xJPh>NqD5*O|T zi$tTwFR$*EZoDuIXq|3&Bpd1eDFTgq&WX<9q@;pQtlW>#H{#1W9;0v zv(SS8A{|UI9OYve1O10fATwZQSONOQY6vCRqfgPl#x*^7WPJZ^s~dFqQ0qc1YL9`we4-W;_kdCWuM7a_lRm>i=X)@<+1SN zt>ew#dOW=1|1ifsG>lrXEhiO2o^)Um_duL*)?H6@+~O+t_E`J~MXBIL2%RW5(k&3D zpHq*lJ$y6maIHl^;od*oB|J$j1t>H_H&#F3N8o)@7B;`;N!D&Z*f9 z`+&E9?W9v1A8X7aZb_=M>O1oZ*yNq`^jw=*lym&x*R^stATQJz*$n?Nmi$J)CGZD; zuA7#Jy6WZusL~@2@4iFWvG2fP)~fZ+3Olh8tu@LCR_--aH_gjjZ_@h7jeE)m6Lw7O z&}P{VWF;rc=DaK0Mwhsnc9ec01B__*#T5z0SXcgU&1S0_#HiuiW&@URU1mVf_O`_VcKOpKc33mHxu(PH zL1>e7xBs?|aQ-avU@CcA3aiIa*R&Y&RO`)>OOQP%l%atlvgB=t&%?I|pPaYeA?`iC zq$F=n)E?&JXn}3giH;W5EWQqo^_j>(QL1XDTscKKv{Mp6UlLbw*(^F)8;7qR6y3kk zM#;_4mLL>qclOit^*UZRE)_J<1D#-08~$DYK?3yU!_GC+@j1Z*6!+Y>9sfm$kz)ON z>|jLe$bAy&08C_3i#&D^BS3WOa*YH-&H%tiyy>MiYYHQCF4ufy{=)_-Qknf#i7&jd;4Es z-LRad+ciG1_L%X4hj~NVSt3pseaTkeOT+Oc=u)=CTmJhO54wrw8-~VqQ4VeLVC2Ln z36RX_zLjs1%mm!E9(VPgPMkN%5p1RYLKbX881a|A&TL#riNAwhlI>S`YNZ>uNJte= z&fdH|F2+)`m&F5`kdmGd@D8CrvFwtY4BSc5%QjD{4i>2y+^7{yXongvof1m^@H$Jn zDM}N&03fo`OkJZ}$(KYsTVzgp$L3a>vK^1l9i$DyxY6A2VzC}8-aS`=Gp-1+ru3>7%d8lZtQj$whW$>8BBsV!QIyl2P;|Y`K_^K0q%Oh_Y;3>3cv1K zJt+!tH%Kiuevw#DdnNgYSB8^vV>y~t`gkmOzU>o5I464RH@F}Fey5TrZTt6n@t5}J z&VdM|a(N5S)gGCKfRo;o^N5HGCp8wdQxPczfzn#0uj*7Kqruxe8S9UZ>*eQgw)v@g zK|y4xV;AQ&A4eTXyLYZLQa!1V6@*|GLAnWi$ef*)=@C<@ZPzJ^PlwCo2PS|vPT)FIAZCIvu;7@9eO7Ed^Ivk`Y@4pO1Bhc1inyxrhjnPsm{SV7q8LM?9F=Cpz07PsW} zgWr9rQXyQxN(_A~F&rCkRlxD7!_%j;P+Y%+<^SrfgS7J({SJCl9sF;|l#lqI5LMzs zap6$N`3+w0`n3QPQaVJy5gY*__&1<*t3Dn;UmL=R!(5iW5Y;>uA!Z;HewE!&$L|p= zGqN8Rm1`Y;;8CH6MmKp<_6sjkv8_1?Al6ydSf7t#befg2eco|#nUXg*-*Do4_wLcG{ zZ`^8dkJ|f^=Ww{m%XS$|*o@q2|1?H9NBLaI&`SXo#Grq#_He9r!@IQ?+C0~eSM=MaAae=?S^lq}E4m%wo-${-+Xq)Q9 zC3WU{P1*4-%QF>o0qrUOIOA6urT_Q)CI2pCDQ^Xt@hEpAT?uzge&d>+N;m3dDQleg zOpbJjD#ptquzgA=7VYY0sYL?*7!{L!W8tPifR~g-n2DdVJFo!&3mEGEtNRx;;*F{C z+tr!6uOun&RuLU=Uw4+ej1+Xe1o9K7stLcSLtdejJ|ENo4nOsubI|yUU5~!gk9N$F z!Gu47g5Q2E#(#`u1Vi4T1`)8PaC90M8#?%mOeAYKVV_r~~AbgVN3leaJf5nvGb1oi4I0m`sDz|K< zZREmZRO0&X032G&rJdJY#VTg~)ukclVX!KZ{23sc!rHMpRGvO>!~QME#r!yynAFxj zG>hf|b|b$BhSsO=*~W0Z6?T1E@DZl-Ex|ppI*tgC91sd8-m^|Pqaz$h9q3gSCDyV{ z5m#NhfZlOD26(o(LNop_fs_>9B5b7#fU%`9il{H)TY@Hk`A?BijcILWb@2jBiiv7R zHssJdbIn`#HIIZeoge0Gn5re6S=?Z#x zD2y{mHRZrJ95A-})1Fc&Rc+AVZmHGV4@4QXn&e$LQk{!vwp^Y3u4ZRq&Uiu%0)nhE z@D)vr;6&dTQLx+e8C^EpOM=s+W6d>D9kvnN5HO!&aeP}MB*GIQY`s0;LkFX+1Ia9h zb?D?`AF#nD&JZ0m%H-0F$5sdAe+~rd0YE(bP0k8Wa^8x`hLG63S(6U8^8;Hr#IF&aC#UTz~9D$6PwTQG9`;aHb@cf2or7UDCBGAQUp$KnkVOHU%-16oK(Hgf1&()N`sMo)UCz~21Kp! zhxf3}cOg6Z-TKLOA?@l%M`4{n$!O8x36pnp&xI9y`9f&+w(Bd%PQIf&Ydia~oGM>Zij7bw%?KZ|0@EE$j| zx6BrFequXpzkm>Q8(!=`-_Y2T|5MU5vPTB6eCrHNFf~IIRX+1Pfx-Vd zP913&{`elFj<+%2Iqa{g+;&X?xxKE~ygj~j>;3+YIdG>MJ;3x|)W;35P@$EUpCAE% zrcga>GGl5Ei!EkFABfV#>8{R*0rt;iOBcSAL6ep=2gK4IDJHp{P-|^lqL3xrKJ!7^rtw=d`%IZm;u>i z@83k6_z1ZBv9+6u zM;e_J6x*U}-~4g)E|hB(%620Fp*s@bwcCf~o!eR)lU~QScT}xY)g`2*aeq90ti&n_ z+BCLeFa!V<+&u{RdHz%T6QTJqc)yh|6XZY4KRV5%;KOJ5Oiw%XR=#MS!*|4%WCZj3 z4xB29OkjsbJ#?&mtbjH9GZIUqZq_z=WD{1_Zib>5?(i1wIjpG+AmQ%%*OwXkGTaNl zi;_^^zzvzp_DgaDWUW^CG!39l=C)0c&f|$QL!6_NgLikjEgwX@(yIgeqifirGST|v z+X;8#j|Znb$X9xv_}|DIJRamU(oghvDx)d+=O4p(Uvx1>aI$I;IE7}cgea-|3!l-( z^eq~YKoV_LK|uM1pA5j76LEf-5Jz(6RTqb~^$^(!s>{yseOJ^)!}ZRIZN1>11=UO( zN(dQYY73PYGSQsQa5;zI>7$}Bc{U^0{<|%nOtLxtbUZDzeT&;@K0pp;UT0=jlD$q< z`8#$%sa$o1wIVnEj) zW{=76k3iZT%KEI@F+vy5tVc?0#Y)X{gC~0A-pEzRVgDA2RokEi;7elko$h!;UBmy7 z6W?#f=~V^2=ptqX%yUqGlPE8^ly41SM8~rRbPTE~i1#mrr~{A=5$y&={++5@ASZo* z`{QhqR|^U1SZjrysbr6=e2=L(`-W9nsp}7MLRD-Q%(CJS%!Z}|^gHdLjc@+(RnQym z1iaB`+j;zPcoqy48=?bp+{B0*-jln8o=VuRkmFdf4Zv>cdD2^%`I-N{*h#?D<6_kU ziQGbO+y-u)m|Egx3*fXTcRT&QnRjn{IKGJK$npwth0xfw(~S0akcS5>xB-0jQ|89t z(cPOgt^ko?qC4Dk&z(Y282;;L-HuZv-!l7KLk_Txb6!r=hw)l89rq2qEa6{M-@!+# zTz138FX|tlREbsxhY{m)r0x{J>3|nu^DUX}ARbSm298SYNNQx!#KBx`U|x?rbDpkf zsz&uN_unDr#6U#B$;)WsgKJaX2$y6f_dFE|b-j-@-!^mUp=h^e$vPz{b8N zIRJY8fcr}a%)%X+hCw{QK>=y`g01S6{^IE922FiAl{OW6KGH1n3S%sM#osrqRN~n2&3f#$i*=+%YNMF4&`ra+ z>>LzDBJOZ;O1A`C4d@bZ42WN(5%p-Wp2={L8bN3tHZ26P@fK4eiAf%c%)&rCL?&fa zufUJm6%xp*{iecc!HS2UI;Uut0Z$9t+W2D}`-0j#)aZ&)UQ)v}0qu|KjG-$5xm4aa za>3wqFAKgC%>paaJe-mr71x+!c1nRXDq1oi+WEpnMtU)CPXImAE$0)$9vK#?Y0=d5 zt+cl>g2gmg0oy~?{=9+&yU2~{(TCB&o-wIGG9NdKHvf)JT*o5z@mRUH^i!I?Uwk=+ttY9=Fc^qT-Mar6<)PB&W#EXc&i9G znV)BFC?VkF91NI0u}JB-oiiT$MkqSl!R_$8PJiW>Ow4nAm9j)9>oD(d9Pgk(0K~{^ zg@r&we$Lw*aa#C()Ai_ql#)6Atnb=vu|Y<2SrM7?8m|fgNHZu<0eMaHX-&z=2_X49 zt2b5QC0=eWIpPO~+rvqzO$LCQoSoIbm5PXKDqNWBA@ZJu?8z3+24mU%zqN|yXmD8# zAPtb;YduaGvC9L;^}?HK&ZJvBzCKAG88^E9BO$13s$HvwvqE=<2p+}VTveQ6&^LPR z+O7h>G+lkSv*J}<>gqO4pt5E1`!h4*O&Q9Bzta&O2v!pwKR@3aG%BmXRS&I|9fgSE ziRhY8vPH*ttd_~Dzoab#*kgX0x&F7theq{lq_$=o$ zOINwuK2N9g@g48$D(}ThN6Z^v*mmUkW*y*Ns5soPsxaEP4K7;apb*(~-9SnGf*_wg zR_qGWaSQy6M`S??OJwFOS5_2mYbM=>3o8ePd+!-1sP>k#^yV97eVQ#>)0PgjM`&nd zmZ6U%9XIE5Y(gx+B_O`20)-2n|Mg|N9lqs3PKE{49V%qkD+U#u5PU&v^^mzxEbjk- zALA|4FL7k9J71P`@5}1eDF~d>xSk)u*e_R*>x?eQse74WkCmUNGFex>8NzDjj3B?N zq=$09 z(oNGx<&hAQty7Fr6{B*?D{m}#@^gBHCyw_({`sW#G@S%!%)dd@ri@~BXae+$qgmQU zEKhjxX5S^f-!_2CQ=<$Z{ukUO96Nu_G|m$qlUFzQ=?Ny_^tm!+-!6WF;@J82J+2S5 zc_DLu&i8sHfScw=JE7~d!WCPcx=+A+W^H$4T6W-GcU2N*Z&B`TtzSAyZ@vrct2|n9 zzqozJ60h?NcmH%unos8IXimAhA#wMcX9p*tSl*AWZ9}c;fMMYZ7U5g{3V{5oiiJ3o zxIiB~Ftxu_tQ>!oyWzB%wX~@Ylg8x*OH`b+IC*6j?R8Gg2RiWa;}&C40!zo!J{ETC z8RUCnzQ2+$YKKeah}t%o32Nxtmmzxr23}*d+f_;h5;gM2M4Rz3R@exU%fP_4&LaiGu@K@fY_U`H#}&(hElvkX6=9ckOlr z^NzRi$xVO}#g_L!iJg?Y@L3<>q)>rC*+KN~mVr0qDx2;rl-+BjG$dZi+C&kCB4M_x z=RgXXRiwYgyR21!R42Z&{!QWSNQ-4>9tsPU!KhxV%g%l;gU-VkUXwA{#xa77gqB?O z1E>L-{S@Vj>bO)0K>(f-3BJfve!u%PEs5Qp(OwzbD5cA2fAOO`}% zuiV&1>$^TMc-d~gKj5EIdiktO6=(NPW2=aZE{9`2Eu9Lp+^K5MQ=2W&4TgZ!9qCJ! zNk{j*Z$|g@?uF!&%W~MA0why624*KJ_vMH0`+dcM?2{_lJAQCgFD%t{;u7vg{w6TH zG*Ur`3bCq?-T{d$XjE>zt5JkV8_pWa=CH=sv9G<#UyJkS)a=dU{Kg4;vgOR6Z>nxc zjl;m^K#ab3bJGfIbGbVT7V1Cb*%q1^Ru8^E*Au=NB?@>p`vhYb*lZKZKdq|ff5Yd) z+ltu4E3oI=GiAdYzU18|L`)7Sj1sCCYf z$R%c;-|~~KiJh0LxCOqbd_jqmJ@So72lL%m2bPh9R&b!w9Jj9eac8XWeQ^6x_=%}& zSv0;KBXyB65(#|LBMkB#QhD$EfgL(17REs)6G0%x;CWB_cXQyV@6}$G)Na0JDEC!P zt0@<>Rp}0&k_*aDlq+YN%sjlu<5I`a{gu?>-iA+Py&MyMQexwil!Zn5uTN z61ws_<+_@m$-gISWzd5k@OTr|)*38cbofW!Ilrc7qNxC230y5=LJ}l^NA+ghNtp;T zo)Fc9S|B1K!+jC}7zTA}Tw%bCQ@*!lqyY$DlJCunWppPcUQn`#xNr)C5=1XZIQ#4V z*Y@i}fa`%`@8O0xW_&FPJ1M`Z>S>q=6t{oyC@`m<_1SLe_>S;3DV!A9NxKW0z!Ya z5kZEK-pg0eWeYjG$QnY)8VZpB$>8G8!4;Hc?tC&*e4Hb?seNl>MsSiyDbluY-^B(U z-(wG?KRWpfjmMBJSDU>G41P|UtWNuHkMblq=bEPx8!vwU;7sriFfWezCsh^T$te9T-ZB<^%+Paf6(0j!4! zEIPKo2R;T;3wVUuYB(S#t3P%~^IM zTq}B0x7lvlJ!2+vF|&(?yUQ#`&q3oC8RF@L1N%g`H=QC>-k6#DFbrG4a(2S%1ZN)t zl)pDr?|#HkzF!IeoiizCe!!_?tj}$nis(*Uh0Md;IiC&&n3*t9=)M&>AE7y2*qTJuElYq5xz$9&dfC` z9c#l(uVm#yc14HtJJ6Fjnueli8ydLUQ0RlILm8WT-k4JDHb5+Ov0|`MwsI*EJ>zS( zpiU*$=1OZVs#!2F1SWAAnq2-GL+q?=iLa%H1ctn_sy|$1Ujq?(5RlkT*T(sFBJ4t7 z1Vi}JAy$(`TMJDIDVA+!Dz`%YiS#KY%_IZPY|>8)nK^y*(evNt)8IIiNIFY+*+isP zFC}2MuMy@<<}cH;ju|s`9Ow_Mb~yq+AWNjVaQU=L#sKt|t~$Olgok>Jy(f!V7?+~?0K-kv5=PC+TJvbE=y{eYw?A!J`k%Ifa!g#_R%G^o)dBC&!mF1<< z#(5v_@mXc-nEw7+T&l-^KRsCMOdYN5&!YaxgF5VAf#6G_xZX}#9T3|$C8tM)MSP|S zn#>lc348p~fqB(t;-sj1L=CLxs0D=2%2fq4hp!8U2;0v3mIMg?G*v;&qhEQux1f#| z#hHwH+t)c-Kb*MgDoWgNM8mcVL5(6ZpFd!#BMCA8|K->&-cr)+Pc`FyV1#eC@2^M- zoy|hQ#E+*DVHAsm$w^irkoBC=;DAoKXd^%wyeqq^kfDZhYM~+MWt4q}sXIHH_WN4> zD?l4hHBM~XoI5MO|Nq~vI+Wnv8B(@QNyYuEZ^xAn|3rB%<@L#GA$A${ zBBX}!S1JRy%a?%~OzYAneN08ZU`RGAAhXTjQa#x-(+LJyo@V&<>+gUPK0JvaXdC## zT?Cfwesg;MifzNFO-N=9Uf{~J$8c2ZPufyo!0|2AvARip#0Iu6NhoVN8wWoL z7qF`ZoWE~47JQgx|2>+mJPU0M z2X@?eU!QC8Fcp_{3ll{JZIqED<>BE{h++Q@f}cLzDB=aQm@QT8@YdX`>qX!2bWTH` zF#qVvo|*<{tOoHqwYsKH zf=Pz<00N=K!gk@hBf5LoxAg`>glz;nzT0OJn!nl8ce+2ICu?uCz?~fn)eUU5OA1J{ z=Ww#CtlatWdsiv|D-`%Mjl;Fqqa2SG7bLCe10lL*DKk09Bs84_bB)`F7#*PLEG!9=8<*^9e zd5Z}kHiiQI55<(&6y&5%P&;n|`cXe_+&3LC!EpReL^}A)T+KfkD=Tad%6?c8#ArCu z7$5lV^mE^;@F5f{`qQ-2qN_pP#;xBsR95m!rKXH3AXuv` zddbS!!`<1;Rxi`whUD8ZLi=&3v8NBDOxZeXjVMaQhBpI;|GijJv0iYXqr?0Dz5H5o z^3mM~^Kz_&{qbJUMSpkHkYulu#5m@lC0ZgnNaDM?rs%=i{&!8VIi)(m0Ay=o0ED!; zbGO?n!Cdr#lIKDjk7oe&O^P9H%<0V$_xED-A<6e>t@=9cSKN;_tvVWq6Ef$*-bt})+?b`$2%v{ z0q)O}pqAb4)cur@kA@zO!wrM@_eH4DnT2Z5UXUUfvyOq|+SvIh zr{u=9qTqu_c)p^!nCd4nWJ4%PpD5~tD%qm1PVz^X97>!|v`d_V9<)PKFy6#che+kB zMeX02aJ$r!LSXgb-&7G@suTU$lk0^hK)Nb20wx;nHXEw7W2HS&#nF=l+Vu=eGNPIt zis1eq1{o%z**wT72Rh9N{obQo;oRM-wfj&y$Phivgpf0D5sL?K5zApEQ8}u?u`M5K zS7evmpqMTk^!}hAEd*IT9ufI6Mrd!?(X@V3yUBjwg)yi#JpieKT?^*OuhCYe{9k6r za*x=9Y8nA zCktWg4Ijr*W_{eeGsfN=af39tx(E^a715rKVA7sy-D_ls{BjqoTmR5fFb4*zw=hxT z89m7J&ST>WYeGo-TI}2`gRywq{+b6X?M7Yh=?R44juH+7@j_eBmTQDSqK?YC*URU4a4^&f*cU&8Q^<|R zBEg<#ag~;4u0gM8K}2N|>Oq|1H2@EvmvBtKf=v*bdmX#OtqwX2R_RnUz0^5KYYZ_z zxm9oU47Z9l)1y@PL|3jlY&F`0&3)GX$yM}^Q@cxQq?=fAck%IfKA_|pYvdH8OWx0k zNt|anQ{)ami@Yt^%gHA_yyru{LyZwk0g2gfVW{p5YzX_9ch-P!l|3bgM~be4Uq5tH z)926^FZkloxz5!~e7FR3&sQ4SsZGGrP$On3gdrxoO;Z{q>j=Z7jtb)wcjJ#(nQWB< z&5SDTcI;R$gM1o-l8q_qKO>AC6rZUJFDj?24ZNy6>A-6ag)oZ_8lx+r9_*ByVg{`J z9HFoanT1+~$3bO4WU1M43TJnnm}8>6VXU{r>g6X}jMn)ZO6?3%k;WXeqwVR&L&W{pZ*`4Z{|gIvU>VuIKp@Fiel_TU7e+_8K=UJMo$AHV=pj zki;#@A9VK+0Ue%-!pcme1Jz2YYPIu#;IM+0D)kxaZd_ZA;u#^>^39<`tAU5X>IPMU zOZuRT`mJ0H;ESys`0x+?n3iPMx#I;7*m2g~?#YJyz*q@-VFEHv>JG9jHSe^ljT znp_XObYX{az=17e_YU_6qpoGo^aylJ8Jcb?CK@M@YaniJ?&0Kl&S%#1tZao{Px zQCEWgtE^;^UqGx_wOx-_3eL25KejC0CDFWsz8i{_w_ndb%>FLW`DF>M>9_rm2mvWO zfo0Tpo!xFC-EBa{9}}@8hKUT<6&Fk>2Cw=pru5>^&_QWw!xbsQO&3lD^zU@rGI&@> zojcwLuy~i~^j9BL$>chC?LmRrr}k0nUwEhMR%?<*VL8nJa6pg0@2wd4gbLDIc|M;r zZ4hyenW6VAKmp*yF;q*&tX6l`6Wx4JQ!^f`phMXM>Z$m?N^*TInqTktoTU7!5J)Hq zc$5Z;ZL2KIr~uC0q-;DFVo{DpE4R^LbyiO1cWZE+w6)Nq_Q4ScI)O@tVrW4dDDo-j z8E&?*9|a34K=U)^XysE);In@;fi%lfNUZ~AO80iHW@eaBm`Kuwm?RRYJnR}EZKE8wffpxSt=haP=7Js(54x zV~kI=QOay{+OLOJH8#(dS~lcsvWSGYO|Hbgh*yKX0^rR0R~ewP4bp<&rGL$Nl~J-Q z@EV!7ffXye=^S>x9HA1d1tguaYI{CTV4C=F8hAvhllNV1e~IT$33y?gBpWd~z*h4F zsh-y7ueBy;9_Nrfe{wg|ixkmtcN`NJ{1TZVFY&HjJb;U_Rg+gFI+eF7pAG_Ow zm50`zX?RckT^^A(fWh6?D}9V#&m0ktVR(#a2E$nyE+uG*X#0rr5JA&81T$Fjg9^Ww z9b&^}bWQMy4%cV_o1by_4r8e19KFiNNbTC83^M#ad~ijc2z7NE5{y*gTO@D>bh=4S zZB;wp8N2yc;zK}CKr$Jw#EwS-|KjOb0;?O~*t)|U4OA*gc3r@a1^k)Rao2u5yT;oy z*nClWpUCu1+-1r&JWE`NBzX6Cp9yrJO%rB|aA6L4j^P0hpkw;#54L6-K0c_{P}spP z#a)|?4n1mv!xHU-{^c%q_PBtXR@!2Ua8*$UZ zeDccC4qog$J_WK(g>y`HC^!2YWY$REAx3as`}UkO6M$Ywzehu2Ya>LQU=5`pm7mOT zK3=&ddJ_>$tw$pk*KSlCknf_aRlA%xK_^424cr$q7ahAk3ui(1N!4@bgR{raOn`pB zx@Nw-ws=zM$+=Thog;IS9V%J8#Q^F(Y*oz`0nrhYGMM{@?QZQx5}jC^2*(#`f#8gh zBXDWq?J;BBC{~?=ST(4^3pS9wfU&ZeIZh7W02&_}Y|OywevholXWG*{v;<+bC^m z_?c#xz<4c5ch0jk!cmAdrWT=FQ&n`^rI_#^`#isqNtvgw;eww{(Ql;Myst0&2D9uN zU%ze*>+U}x$3X_lwFvs3gE$11r`U9jakB1*Sf`n;K7TZsD9kHypwyw2?YlcV6`4t- zzz38Xmmac3!qu;z)7|-Z!jw`Z5aX^WYru_pS4u7Jr#4I#x!~stQ2~U-Po(wLN`Obf zDs<&}kVy|UPk$~sgLEJwmDmqK1JLn;7@AU`_u8?c`;Gmq$>S_|VK&x*br7v?p!T@E9v5^IK(T^?F{O5(rc@}Hkf zEnG_={_aZ<_6~J=7by45j^UGC#xg5}_z{k45R0Qi0OOR&9Efi>t zl}54xC?!Yzn`}UsbMeiWmO@YRWteMFkBR*ZI1bqK{>_3~*Mb3UxpMMp8$11n=U~5k zC?gCL$}nYx=(rbjYvZ}g`ngcl%Q*2A@IRZTFKMpLiv zVm4!mR6ruGqT91mR@@64a$9L{ZW0ZQO?qjbip23$vCiY^3JY$IjE2yoranoCWjOyw)NIIg#O=tMPjp^H#Db(4S1B>%5N&eX>k$U(Y5 zc#>*!WE65myMNsOzENm%3^!mR38aWj0K`~AMSC^=Nb1DO6^a3L8y4$T>kxMS#g!r% z@`l0nNG=?HdhzVK#fnl>Ox0U+=DxaK!+TE-E)sK6JSDRcfY#wm2;R;GKVW5Id^ewt z)Pg;Nxmu`^YE`nl07`H|!69u;38Y#iHY1gc)1U zDVWYcmq8g@0~cCufJyAYLrQh!da6GMZz1XLk+*(8tOo7&c(C!=M!D@D66-Az@ka_0A)%#M+F6N0)y^HR<-D&Ar-(v7Pt_mo{@~t;=|Jre^z?J}A zBT70H+pfnic#;z+U4Ac0n4TtC7elU935kgvQH1TK-Yhc!2xR|GII(^p_}aAKIr;u? z^h1ygltJ&dp_qJXjdoL&+hku*G%KnU;u=wl6bdX2c!nzrI7g$ueVTmIIDLrhC5A&a z*MsyFpvp>(Dgi-o#}T(ZIpB#rhZQN+Bb5)FBLp5V8ab=b*jok*R6?l<@GpkXDGsBZD%=CNq6YwYk=EBoB5?q~`yy(Xhf09luM` zoC!pf2qE5%uL~p@DkFsL{>LULdpcmy(gt)Kvcgw*bUsJyU7 zl(AtC6#zCThM}8~2H03%5d?E8YtRDbYJ3MQhkYTyM;V%Jf5hRq1sI-LwmDV@y4p(s1l_j8D)~hu^ zTw3YbIz6326l%=d2Y$bj&+cY)Nd*c$OwxS|Z6XVI;@53nC~8KSQO8r2WSb((y{{-f z9wArL%{f>3XZ>nK)A?PA@h4WtFbxbcXkahR2Ce^An!+%bK({hW#-OEKxsMSz$eHAn zB2=PG%c;=-fegvVZ*FDh&`MOM0BzW@lqBXPF4Ce?Ga2R|hCqPV@-mmJNDy$S0kmnn z$bamS8^XCK1NSwU#2L^;%3~b$e!eFLB4h1Q`l0b_UjxKWTa9YO*UG3wq^cW(#;^B% z&lcJK_M9D#RU_M{8)*e?=+>t{{){%fFLV`c&6%vmkay zNv!kquVoY24uj|vRxiuE6}%(t$qP|{)!g)Kv_Vk8Sg~`*W}jv*T~z7$#{&yJK6mCh z7QK5Z*n;M3FQZsmJ#z{c+LdBsHb|garhRN>-xr1iKxL-peFl3Bf<-eIv7feeWZ+Zj zL>2%@beT_yNk zVmIhEm{c4ye#hLOK~+-^+pdfvo>W~f?H%AvM(j_AD9(;MQ5W_4)YG~dJ(>x0OqooN z#j#i^$_GJJEV~BFAmlf#NFIL}6V&M>5EDjsXLuMx@C0e%0S1FQNbd05$P>hyVY6s6YSiPyX=W<@L6H%a6`)z{Qz(wNeCIO5T`a zg7(b84!Zq~m z5l|TCLBA226H1pjao!U#Esn!TLfxi&48`qwiza&I3?q`)OElUk5MDQH7;zP<^Zj3`S$C1yfkNTGm@X}JEX3nLJt_9 z+IYDo#EjpE%v(he64est08$p1h0f{n@nH}Y_bdQP10nPXSQTipi&wCfNwuK>O$_G# zpD?@{WcOMkonULhK{!MV(-|eD#;4#_x4;ota^!nIWAX(T3`UsC2-z=~QD4F=M~W!1#EmZ5q=_Z}#D#hOC|YaVk6f;3 zT6#I|Cu-nBi}LAzjPXjf-Jki#@UQ>;$$!=BNCf7Jg+nz_?b(SK6;#e6E-IH+1a5r> zgT&RrirDEDK4wOs+ekU`KG|$w8=^W!T+I9O?-+3Q>?_n+@Jtn+Oy$b~6#%TV^&h-1 zqy*C|9H`dM$G;fL_44hj*LjQ1=-BW3xdnJ9H?IVQq*E&L+4NO8Ilso$H|PPL?e6T) zz|N8VZS-Y;CFBx&;_bQ`u~7Gnp(*?0OEjDDi^K9QcE{g4=ez}B^cIL!u%};bopz0{ zL+`wO(J@4p2_7rqxgi9J<3lejj9@(ui=CSD#T&w;8%8Zodc%%{NW$c%B)_zX{vrEv z!NhSlz~Xb?qLLbY1V?{Chd}I~0EInGJmoTYBt)#^>)Jy)$z>z_z11cGi!$zDMf7-^ z-4(xwADZ5M)~Z21GtmQ4=Tahjj~dArjq=GI1gK#_j%{!AZl=HanmprS%p*c_d7s+Q z!S@I7-C{tRCIU2AOW~%;T2=2jppXP+vzIQ^dXf<+ePA2cgE%C-caA}f?MsS=%OH%! z=h0R#QoCXzOoxJhV=Nws^)&3g!h|3V4J3#z79)cN#ICNO-%&tYrj5aGAVy7PLaQ%d zokqI^het?*cH)}tLv*0I$;jawJqDv zb*Wbd0Rv@c}IgHnf6RPh;%FqCnQ*Yc-tLK42}Ys zI;#Mcc#}`kC}sIB?7;B9s-X9yNA%#SKw2r~))Q~^^G$3E#>o*c8LWNr zuj?O*#Oais*c%_Oceql#R_=4=v8OZNH(k~F6PBu`KCjQkXDjr|{bkxaGaTqX>Nknf zlK1r*;w-5iR+c7dFhdkiOvQAjw;tqon{H$Nbu<6ow(s_MJ`AzaMepi6E$>QJ1xWYo zCq4c5csybC=ri4Jl!`_C$p-BuK%NGi37+7{N~o$E=S%kg*7X@kOcl&S-;1jKkFmglew&R#8H zyC}shir$ar+xT9vN8Q6}%MzR$w;KK%W#imuVhWW*Z;Bn!g%RnKz9>sPrJNS_??N0n z4CGUhGuN`_J1n?jXDfVWgN=L^3b&6px|u02il6C5B+pj?=n2k4DvlDY;+L`kwHzXy zx$x`rLV^I$4{ z-obTCsF5oO6rN$ zZs)+hX~tN=%pdI7dM~b~@r`342$95J`|QGdH`z(jHo3w+3nK(~d4Ol26UDdEKORL^ z&0=P_-22QVpPC>NBEZ`?qrCwJ4kk&oIVY&Heyi+w6F*edjOV}wyj+xgsP+adop_j! zFp)@uXQ01SHS!(HYtj(UwzQ8jKXISK|Dm&ug#{tcKRRSv-b50>7V>^^XmH6|8V>YL zb%&piFvRjy_YpvP)TxyFHaz`@_u2@-d?d)%He+L;IXOXOmK=Y(nWdSS!wMHqtS2iy zatWMeH!MX7Z)SiK#o#+5S&!T`vR#JZ^4JY;R-v04IYiOdlLLm#Qh@)zUsoVy`xtcw z22dkq@u7e{FfDa)MdutZ&27neTnd6gg@JdMtny|neL~O&QUN}tFNAw0t=AcBD~@+? z(x~gY%K!iX0Z`lH48sL~?9+eVK_GW8XF1|r^y=BDevD(+gY(EPN*uGJu8C!>_&fiM zHDmcDL~5o5rQ%PmPml{>={azMRlN8NkRt2NSoz-`1QJ>fOa_QSMM#yvszTFJXoJwf7!LdP30 zL*;afGrIszZ15xo_RHtcJXvH&g;nF{HSAdf0{-~VMqdU$-nMz&~8iC!>gb`gWjtW;{IO4G;5 zs@4b>IKFT5=J>H3COsnRE^xxHK*l&x)JKyX+ol_Lh(#7bgn_X&F$zi*1or`V&sAjs{j8)tn2_XutZI$eo6#T7w&@%__l?{oTq2*Lrv_#EBG1snzVCGKX#Mqn|Cf7h%ER;=61AV5yt-0yL3nmk zoB~E56K93J;$z5xtZrj z#i6v?645BwTMAvaC8kp|po*PwYC{dtZcynCMj=BXN7Fm+lc1Q@b5R;eB4Jhbeh|LU z0$9bmfUf-K!Xf?LsC01o?eAj%F?fFi-Flz?KtqkCrP2s^hwYa^?>!xzo^x6BKWn_` zS&+oFFYX{I+E$F_P>8nn_+M_YaEIWAM5sAEWQdTqO~;6$Sq6LAcejYVl~v|ma0?5ve)k1@cXZ}rpEb4nio>dlzs2RU;EkF z<1D!I(CuSXaxM4kO}#1N5l%Iv)#|M{%3YrK05={@dmj~Dt7UiH7nA?jRXO7Y86g}! z-!tV2VDBJ^S0U~kxC8Pr_kIz(=i>u2&2k}+3uB-E`d_dop1PuT=gg?fb_G&j5Caz{ zQx!sY|B%T(rYa}K8K<^4_TUu5Etp0>!+4u|Wmr7GM7f?60wHha8rT-0||9ZS~ z#jdvM5ir4&A!f4^gE40l^WQU%^gY_DVtddy-wHkzu>vcfzID}!LXuRYomE#nV>QEb z#NfnKzRSO*@3{#G)qQq^Ghm)4xJys7wvl=uLnO!USX6}yR%EMUPb_g*8!i^Dq;_kF z*DFsHr?@;+!ti<(l=HFuXluRo8ZoGVepf;+=Y7^nBcMX(s40boIaIs}*3?Qk7_U!> zQ#WgHpjTR8gz~_^e$exF_!nN}ofKA#6Xit%$TwH62zd(ys!x2GcNlj1LtqU!Kj-M1 zcffry>1311&E47@;*T$&(zg}3T+@6YuY<-Oh!=1FnI!G>n#woe}P$s(8O-0oEjGV=B0^JflOzl_@ym0aiE)XS0$X^CdZ zybi~@@Y{fgr(TMrLTxjo%a5tblX=8Be77z)wE)xYQHZ3H?>Zu1OyN`HXdF#I2Y6Yu z001C`Fz*o2{D6i%1e{?2+5l8kQ+G+{f7`*8rlIN9gu`zJ^PpW}ZK?p~zyJenJ-`(t zDT9d!s185^AdJt#Pyj2NtqcPakha>80C62gaX<{G20}mr*mS`hmjD5TPyhg)JW>E3 z6^wugYOyC3+et|d3*n(os4rQCfc{-D<7^lJcbEV)8u(xejLBHiK|(`r$S@d_4K^s` zjsVy+YgAbIfOzV-{M+$U3K0ZVFd7Z;5pqkDjSsEYk}~*wPAbW zK+R*VCn1gZv;Um^TgJra1ky;~5SwarZtFm_Nec zR!VYv{J#IJh1}5(#oxXb(7NzJ3mbbjR?SJf2g-u(TS|L!HdcftR15%MPTuWdZ?$Arxv3}1mo@Z6l&$V38t zCHfWutg^?tA~fW7bq;B|?!j!DZhaM+XUshXivTpo#IZSo3H$u z6zmE~`1Zj`uO&J0G;2c6NPJEN=L;-+-@cO)-f|j4Ea8(jsS_Lk6DQb{ihK#1bskgNwuS$9DaYn)( zgEXA`kpkk|HmvJY3Pgo9PQAP@(g42sT4n+o3HcYj+7)X`9Hasl^S>UFbeg@jm_(0*M!?F3hSkVen{j#7T>_z;EIekmq%8)#QO^0-d644#I=vQ5? zYfN}uwQ>6%zDA8E$Dwgsi7lCLilYQFLVb>AH!3%Gedg<-!n`$a8JKzGhl~z*?T)Tf zyj7CK{U1L+vQ4dh->$7eaK9U!e09hq-k9#drYxseIVCv;V2B2JcO5X-B8izz8&*p125 zXt${U%t=GV>{O88$9acPq~WN%6eC`fhwI5mTeQLIVbd9OXKyQfT>G+RPch998BU|V zxCvE-<lOt<43>}dq+#C!9XUv&X7-GPaJ&mm{$ak}(Bb(@n1vgb7vUnEEG zL5{HQ0KJvg)P59wWe;p)aq*#dV9x^FSSj201p(|f#q(6E~}!lct&<7 zlGonGS1&(6)Xj}B_3(;`Nz0n7V`M_3*^T) zWHTjwhRivy7tB8QbJ|lrjGqT!JoEV0zlR&1EC2x45p$)A4y|3 zDPx_5IPP~c(yI)rgc-(Xb;}?M=(Gy`Y>97O78G%M1s$}&8wMFzw;iQlL=~ymV1o@d zG!uBG@a!M6<-oyPeC0l4Ib}tZJTL&_AzM0#UM?PPtoBvG9Vlp6aC>;Oe42BwKl!+% z-YB0!wEb%wj&smaczoRi?-vClBCS3YA3s}$18eLDFglWK`?4}%2 zrSpIhBFc#KiZRAZSPEtAUnqjd9BmQ*r?MpV_yc^w4LYu$B)-4X{oA67Z@EZ1FQZ!A zeS$Ym595+R#;(zr>5Uh_OJ$wMfGiC^g4aAC(u)yxdjSSYe)2w7F+jxnKMt;4Ec#eJ z2vIF82O(MfC`splaUXviYr5*rc=>kPT84ufzil{%Uus10m!IT#^G+?~)4(&1^aqnb z|G14H@`&%Ezk0N^ld@rcRBbBH zdL#Ja=o(@8E7BxgT;3{FsI|;X{ABl(;x&4;)p6ar>@m307p$KU7`#LhFQk--@<=&HtAXk-r~@6hZCIO+ZuS)5Xe z{ERW3;n*lh`cj+3xG^PJzZ%yVsTb7KCF^@=alU27I_xQsX%7nr-{IBzr5XW8E?tYX zH3WwaiZ-iE=~XEfL}0!ovH_b=H(;Va>>AM5!L4x2O2&B}ZL`=AK0EcuoS*uwz@v*0 zYw`i+P6f{$!zvc6mQvG$R`4Z!6*1e_6HobDa;$)AS9wm^1tvL2ZCby_+hK+{J^$?r z7lI3IV`O0pFa7kmuLqI#;ToFK#+YkLBnT#cV{wCUmc8q?GUzf*f}g9$Z-Jsw%=;}M|7Q4u!e{q7qguGU75oXGZptEj~?0OI`KXtY+P7gYPsSi ziFxWHoUjE#lYFBdO9hIr=(EjGcrby7A~_U3>b6CdxodD%!O@HYLhQ7dh4>Q=o0uRy&?qG_x;r zt1xr<4{NI#J8t6D4nXx_jH+kXTy3LX3ltofANq*O^{Rimik;Y8&MK6VU_03})EB0> z?KjoCe^oWIHtE##2z1Hef4?4Nz~SF=+EEf@+d0U|0DPp(hpze(})J@s+9k~V5&*aUa{Q!%n zP*Fa_7hRm3ncEi=Fcqd*IEfarNBfUw=B_g6sQzGgd#9AfR=P3L=4Lk)NmUwOQ~22P z(^?9t&@&R@(g+@zA<>m7q4Ypj8D%C_FIGE~;qb`ljWVJ7hWQs$iq>+Wtpx;^YD}Zx z!rP>|r>!yF;wfLfb=wk$ofAI5ifvvd z?E^%;gb(jdh7|LW={&l@kwr&&0Rq?XR@@Rs!`H&e> z5bqnfLbXvP6bZ=b2s%L0wwxZen7fu_5omG4@2YgXNX0N6)|(-31>Vz-q{hhaBvD}^ z3Uq6Z~hBa~#IoD`sC7^3^q+IT?R~Dr( z@ib6T+P!nHpWf;)$PTgYS!JvGHYY|RyB{il&TE(q7e z(p^QVY%9!%Uz+B5n`vvwzxUb8Eu#OtOAd;sh4C&V7^>I&B*?4G&ACKfjP>a z(rhS%XKK*If)@JS$!Ipy31@Bn$_hK-LMMdqxQ(*;fSPQFWT>LGAok$X+7;nC7AL8! zV7>^qhf1BE`kz?}OBz+!tp;~14n(aQ*#f4)Cw7i1BuCF%mBiR?`b5lhymoC#LF5PD zTGYc@HvA=*7+Uj2rqG;4NyGDZP2?k(;5o|h9|7Y?qPJb_f<`0%jrW$Ks9?p!XGC{W zNcEHY|9g{h*t@SDiz@~*rX(-9XJ0#ci;eB2hOh*+hDW>==l|Qa0&knRb1w-+z4HQ) z7l&nwDyZje##_IVC4bg<2kzzj-fRAk%3s{hDtA zEAT(9sXymPt~-~BeIrYIq*uDCW>p%h;*Tt+m)>hPv`?5lWcx<4lXq;tyv?MXu@6=R z0v7#pQPlMZd5#Fet9T3WY?w_ja_Gv9H;t2fekQ5zZt&eOTovj>?43;MwO5uaK(xj6 z6gw~HqHN=WLdiXN@cJBc#sE{RbX{Z;mZgli16AxX(DngU2pxjdxt{edM|U#O1<4Dn z-F*-aCLB`J7(1E}zi8W)02a8M${bPGX<+!GV*L|KtgkY^U}>crD!@HLX*mQi8~&pd zWZuX;7#YcWxUZ#81~#NSA|%7J=Ths>vE2{}PV-^gV?jT3SB$$r+yzEz+$db?%JU2$ zOofu3a~ITq=sG>l7eNhaD4}$rd6l)^8Iib z3!OE-S*2P+ZOz&7LKiAj|BVM)mnxR`LrJ&|8i^uZTh<vLe?{f`B|L)J@(;W74wUyZ=it^I0cSdl}LJJj|smLny{HJ zDhb(59V8HDX2KuxEpJC|X)h?~muo%6lc|kt`47RvdlycyeY2L)g`b#uR7r<)QjuME zzmj9v9fyQj$nuBDj)vU(V^5p%IC#Mkia;Bo1f0}nc=9x)ci|3zIZiv-_OQLS_%h}& zX=z6?lZ~|#L^o+U&&B9XgpEhvZCS?BvDG!C@GHe(cB+_o+W&)9YXX`I>Kc>;xGxzg zyBC=N+8H8EcO-9_2yg+wzO*kQxjiaHXF~x3qUNeASUiE6XY%oi}bgV|$ z61{yu#Oy!}>b7;y4GZtqrlM)h1Rl$+wB7gx4YIyKs>$C;AaoAsI-OzU)b;5ZueYIS zZi!#+-rqtsG6NxxQRc4P!5 zL;W1`R?}I~X?R=&6HU%ENbwgKp#F~q_|X;}pkRt4u=pg8(2BU=UaMr`pY|REDFzWg zgQG*>rt_xro+&l*HZ`d2A9|G^lou?|9IM^DbJ`q89F*y!b(oI9M8@eU=!&^-ztx|g zgm8}@s$|W;3Z)oPiXKa7BslDc_=_8qwiLA9N3>Hpa-%ll*(MQent=5bfez}Idaib5 zu`gKr=d8Qk^1U7BfMeIlv{hh*5KO&Kt{^)lOSEHwQvk_&8u9>V7>w-XagS!V3`Q$1 zRFDQ+2&ipXLKyELkH{VKxI~s&MykB1E`U5Wx7%rW6$b37^>h9L?`3Xag|8a{NiY-W zaN7?>#oCeMy`k>*p|T6LP}Y?kIkSR!wyiTN&)!H+`m8Np8k(vf7x>Nq(#-dLb`?6* zay!Z?w3z+2FDhDe4rJ!QvAr}Qo@|H)2bLt-_sM+y@jv9T4z#3Y)QKnE?OTDPgrt@2 zch=z2m+pN0Iq*1qc4gjuli2|0QR?e67kQ9(<}cul3x>%AdZtXVLv&Tfnb8%q8=`~z zernU=1Nwl3#;a;!zk!r#UURYS#ZRvtSX_q8@Pw#kq=P#UbtIAXru2Ixh@>KB?ryRX zCs{6m!oM3zu~=7I%^dZ4D0!({J>=~7%y zYt0V6&rlS*X+vDE`&%CYCWA(9R=wcQY2;lQXJ#(6F>Qx2!^dNE8D!p%UW`Pt-U6b_`ZRo~=6QzA^HZ>B& zTEKby=>?KOJz)KnEt9CP(U7Xq0bsbgELIGtLY)5zy0)(>{r}fyI1R;C?s=|?_!vkJ zEV=&>4HArdm9VQ!VmjV^K!UH=vN+)P?p60ljJ~27pE}O=YdS>_?ph8NR`*-gK>TdP zNxj?!8SGtlV0AmS^OS1Xj%t@3j%ViD*Qg?#9#}Z%`eg%c{n>z%$};(kf)h^^z(ol8 zwpP_AD>y0Ut#bIxNnw2!1hKQf&Fm__FIpr#z|f=TB-QkyoO&8CPaDW)!_S;1-c!pK zhqt?vZPpY9c~e&aK=yiC&0c~1@Wgi?d%k`m@FLCL{kejK^R>eNjM1Z%@(~zRMH4v5T+u5eLSku+=f2GckejG)k$)51 zkLtBy59Q0#9@qo(Gp{S^dd{j;?9bTH_3^b_@nc_c4p^|j*rR;e2I=R@y&Wj_CaK)3XP?!Tent`6)5ih&4;Kj{MN1 zvOtE8cQZ~AnrIny(Mk9APvLrL5i6S92D-yk;@3?u^qF0ySgM;~R?3RlqTQV&-H_E$ zJZr3A3njJJNc1C*)UzqQQCuCDJwg9d<%b2>%vtehq(88HsZ0o87dN)u+3a{iotuY_ z3aOO=ZOC+`M$x|uw96IQS_%`TAJ+ZTPBciNhwKC7s@K&vt!S6pKi-Jgx1s2R@SZKShOkQ6enZcz0Itb*^=c4S^#Y%=~|!!D&m4_s9f3$rb44rLI;( zp9g8N$^r+(;5JS)FuM_l7otk*dB)Ablq8Y zW4~e#gw!eXM6lCnqNQ!W>yIDJh?8@fu>xNgz*Ib>ECHV_af@n zflz>5cbj?{wTN@wXGe1jXvS>LO39<9G*u#y!XD`2#7K|{?#f5Xd|o^;(=qo4L)4iC%e^Krh;57d zEiaH>+8w+1;nZBk#q4eRZNzfg1DPhR0}I&>^fgj7g%Z2Ux1cMif(L6xkU#-2joibV zF0yI7h8eIeJz#?XpS#&6r9S@0gNc-Cx-l!5izx3Q=ke<~`5&aKK>eIBn!bclad)T; zyf>b7%zSr_^w4NTp5s5)!h$h@G3S=8NkLPm?F@w3iDaw>0NgttI|Mb6q$_V2y zVE*AHk(DIYJDy9jDS@Lc>rp>agK-rXpqR<_)HQY)(FRnh{B^D}Z<{U1^^k(_UXr>pkldH*TEC*IS#NxeI zUN#v0-=$uxe+(uQ8~P4nnZ`u5or&OQA+V>2wRNs|`_>J*U>pupYwz3T9m>YU?T9oV*5{O#{x_Kunx!+TX}^jh~-g zCBfEn4v|DKe5o&sD!EHQd9o? zd84A5E@)N{GU|khN;wwj747M61rAr{-gv-Evp5Lp|S;^R~cA`ZCy^?X| z>C8&n`_sEqbpfi0ABoAj?4=Ci`Z9r4Ys2vL4aIQ8kYG=F?SC>;AEz9-a-z6~YTKz3 zXegJOR#A40FA2&bg+I`hN*N$Hkh^-N{vCYcPQMW$ikV#}-OIK^v9E$?DZkhq^R(>o z8T(lJYnLQ36L2?$+bx+l7SE7D`onc16|7}E7+zMZ3x_k=P%x*Cy&wC=w8#5Aucurv zKhJ3@r{2HD`!oE60|^oauxtk29myuY`7cm^jz)AMsrbLDk~7}lYiQ*C9Hf(^Wrz^l z9hMCM`Tdpfx^g?YYQw>nLBx7v=Idz(TWkHpdYI|$Hni)XUtguc1M@Z-IaUz1^~qgt zdJWVDqi+?~EOjaXmYk*Ko9_iXVv-!<=d#_Oui<_DN!)0eb*ywjHz0qT&f}d#g4I7R z#K~T@J_Cv8g1DRncMFi%CF#>ikV%J;6h4U zf4WCH_>XD9H(E++9H&F;rd?FNxKbpBaNUwQqx*?#RV9rI>Ew{MYW|@Y*@o{yY*bL>3u}tQq z7|abKIOX%8{1QY;_#kV+Y|B|syMFfNfQPU|*A%!HmyTa)r}M0Xc^`9GzmtLLp={|oE&ivCkLnYVpL@R6x-q!-GW>2;1Jvc!QI_mX9(^PAV?rMfdqGVcemgqXz(BjvctXidG7Ds z_ubvk&L4BCd#a|pztvr*x=x?&7QpQa*q;yC=B;UU5cIrw_d)><;CYG7ub-0&Nh51N zbejEkU+a{>=xVytIv>m0%p+(b21)Hn{(0ijitET@Nrb~fQiX@qDwc54E-lB2L&opp z5GCe92cS{$QryiS4{E1bpn-#9gj5=n>%h|#+I4y3hJ0SYNP%fQcnc>lHg{6^ zt7w8n{v~IQ`3X_z3t62;_8|4L)gJRf$-SYr;9!JD!gKn~)peD*RpYVo%243|?5c0a zvx)fz`dW%R_a6myJ1DRlGCAUC^vFd{?c>mKVd94SWp*ctTE00*0k}uZ4sSu^A45zA z{j;J}aUHdj+=|0r|MEI$ov`?l=wxKWBK&^p<9lPu+pM)fYJ2UEzYsm)r7OB6170nC znd>9Ua$c%shyur*>X%I7XTZ->-79ti+{H_aRM=+hSWE$^@8IHPciVCR;HCbnpu?9B<#~xM)QxRA} z74?oWRHQvt2{RqF<|yNb(1zsoY)qQw4>wxD0kN;ZtqGn}KM%qSJGgC2-01jxS7P@+ z9Omp^+oQJ&D}EDXZ}XwZVmp&0w%vvro#Cqj|jv*XSN+bbb9XuIGB(tlx>hvpP)6B-v(vLJOnJgk|h3 ztk)BVu=(~N6~`zC(4fe0v(EgWC|k=X;rLw}!Cic)x>-zcIPJ}co<$z$f>(ZkdY6;} zMf;05fUxjV=`q9E&kOKx5PP~gv!Q&tVR-Vfg(dgLYn4+KB zPw@_v4Uh?nVi?BOL)3tYtXIAu%uMQ z`yUo~ri5uEi-jhQb1gUtR*z$BWouOG4<9zSC!go#XdvYt!`V z_VYuOgEKL$$upFw7&rCtCx5nn$lflPi37MMl|QlE1!q=e84Q`F#8Oax3?o1Kdg;t! zw%jGB&3^^@18&ujjqwhnL|7ST!#e#$wB!l9))FsSq*{HiK7<#Tf0Nsn_aag<#I*z#T7Nb?uvoGoIk7`mSYj>!t6&1nL&|*}1HC{$2H-TLG`AHa zr#h`X@G|a?Fj*t2zka}d-9t;z3qEDpP)9K^fo8!bYGj_$p6#FNAVe1lcI81If7BKGtAuD&IB*ph!N7Tx|6^A%R1T3#GX^i5 zMZgyW;HIVvD+GG0CB()Zfc;z+(_g=PWnVbJ9iz%BhFAkO#v8@!1%7TC*Wc*Pu@86IV) zT~FXS7XaXVR5Jk}85t=Y(l!DB_DM*%(VTpfI9CmDf;0=Pg1$j6D0IZwiBQ(4b0zb2 znj0GZuJ#{#U}%PXIHs8jbUEhVpAcUKS9J2N$oBmvXa)*&W4!96`|v z_^+!^-LoY{B&h0Oo@){(6EU;qUM&RpHC*L0tbu}72q5*>AH@PHTVSBe1j-8l2yCz7 zD=>Ya6dc_Yu?zHyEFpTc)?d;r1ZJ8*$vKb;c##AysDS_$e+hpC)L@{(R8Yoek%vt1 zU)R4y5$KNB73;xtXNPQZKtVeM2>VAyS>nGk2u!qN1vY<6|1E_iKFZdD;u?O&Ae$}i z6TnQpI&>O_RZsx|O8&o#{HxY<(|GaAi)jb=0)@fJ+!;4-!2SNO&Wk`djdm?d1LemOAJu)6Wi7MF zOjYEk+ocF*=sf+!YHsimrG_dnA0XjT0)V2kK~ZQW>mV?!|Fe=N&*cHg(3bkbehn`J zLlaO~5HJ37h0?e{f%qT13i$i&UND&P^{ytz>#QeKnSg2D# z32GgabG5^t_heZ64PftuPJRNOcW5x*lpF?6A8vGVeKO%~w;#|67ist5LeL^?(r52; zck4SSF&nEIhsP+$hi7K+zv5ZYG^NuV@=eErbUfR|G}SjrMbZDjl`o@+{nUGLk(HSv zj4a}c3fpREsv*Q{23;v?*a58zs)(2OsJ6HUlPHHKG>P`QNuZ^}vVKahKulcZli$l3 z32=dUE(FH;e**B_Z2`bTdQ`~P!hv|>X_y1X9@vYrVNmw;SAQ!9&X*zFU1lby zIzLhKERH9Okwks>OaLB>=)z;MV?~l;gZ^RVw4&UDXf;WByk_{OVu^+9Ui^$(2egog zvhnAxao^b(0irSIo3+?%Mf2g<#lH#!Cc$BbmJ26c`>pOjR~c8~@dI#y1OS0a{Huzw z0JQVNh`WrOJ=YN!l-tSHI+Kido*vwUZHeBW)kxS64m^xDcl2A8RqYqRlP>)dv5pwQOj`gnMFVJZ7cS=LD1

COY4JxdBGXhv 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

%eYVTccCGN^#}0WZTTrKls~vS{<37_&H8*hdw%y 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%0DU&XRb_~GL2{yI#B{UWJTdNe_TPp3exW=Py_qe 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

SAna(g@RiuaC%EYqyfFQlZv$cWjzAI> z%#|)!TgwXNF+;NP%Y(xIX&N;Ue(%TNaU)ivQ!#R(%=K1XIMfTIhP5XfN1f+UABVVo z2XtPpxNgJ1oPCDGZJ2T3;ghs-p$ZT-0H5H~s9#BUD}K)I;GB+{V^L}?KfOo#=wvIa zyn*z(t29W~gqLYaZ-5agU_XRAk9RQbhlrV^hWn=#(o3c`=BGPbEYi9%9M-Y}$-;Da z0$}pZS5C+LDHJPAtIAA2!b#z3u2c;gn`x52b915HQ5RcDR{k{LM5{Xw~+sGLcQUR9JjuUzcd zibKtlf@W@BPK;=LfSW$YN6jXJuwtb z<8vQT>PsGSjrALRswT~kgXM-_pe9lz>lLp0@gUA$qXn^V~>B{uF#g+ z9mnIRN9>|f^?vPMCTUY{dCs_K%+Z}TuP(kS@P;iDC8FwPEb+WD`}`?~m1VWVaVqjExOzHK#+&{Ejd}Mxj+Be;Faw- z@HWqr<+Mh$r;)7+A(Y>J#TI-^;Td(xOxNGINq8Zaz(#%Y~xLDqg) zTVd4T=%V`EIGo!Ns3{Zh#6ZGU;Wl%V=qkXN9F2iSWRdyp{laH3Q?ofXVFT9%Jay{HUgYeMmlWj&uQ*J7cwHw4g9De$HS#D#L%{ut^XJ% zY5@FLreH$+I$7Pvmc*1W=e8cfcgDPmmLE2dxP}x+Rys#|?SPjhlOY9e$TqSf(=>)b zPgNxliwL<_8#!W5z|E~>e_j9B+lAFJz!hETY*a5(_)8CI#_$|4&4$EjmWiBQWqg^d zbZx?4@+*WM8D({+#twbSdq?OoiWfT-(zEfi9>Y@(p>x~P=dd`Nh;dp#jlCLeIg1$( z?V-ato43@Fv9zRN4%w%zj%H!TDqMLK91m(`K9>9mf7v!!%auWe&(T^7cIMO>`43$7 z^h&WT+ZAs48rcc3!-(Beej+dHDNc$Y^5mhm%x$!fgU_x~w5Ix$@Tt<4V~XDxFn2n+ z(%Omlz*cX*eWtBJ$toVi)Lb}#S4TXDYMcBh^^tJE^7B^h9vA_CTJ5#`mNp%Qi)v9D0I$BLLjP%wv=LX2=-QkitkXY*bHd z%6Dq)Q=I_OSx2SLu`N_U!sxi(fYEb4e;%Hty~5Y^;DXC)_|7HZF@&r1%+S<(Lno~N zW?_-*9j`ux%6%WKZd25sYli_i-yGm2mWjCy{|kyKvG;0Edjnfb}l5bX_QC zeYI;VMnMH$5-s#aYu$B)zf;Ntp5|CQd3e#alDf3btW?Bi3%alj(M2!M#dW+Tvx=5g zQTvYU^^nlX2(_a|I>tg)hz96Ntd(*%`ABW5!yY4J=W+Q_iAKT44ieq5Lyo!)xA@AZ z6(}|^VL_$KPchdy_a1`=X}11Q!vy*FIy8IDSp3vJmWV}OP8Ao{JuC+uehFk3m6jTx zfU}6)4e1p^YQAyXip#Ldq-%Ot{R1 zAo~_gTWSJ%k123_0lrJn;hiGl*t09VaZIP8XARhi?eG2#=60o}>`>O?V0Hvz)YQU= zfk$52f`FX6^ofo*q6ykuho8qtkYh2Ij}NsPobEJyw68F8cYdvT+<>0uUz5#E5i zsT_h>d6754=PwwhwUTmv$1O>kO(|!QIr|PU)4+A*$702lhWtM9Y1xr$3ulRDc?u_y zCR3PQU?em9HpG&08D7|aQ)W&TN-6QVS`ko&?g~J;^SVU!x*%=_EjzTI+Z=s(`W|Zh zfN^Oyb5LOz$_BY#9K1)Ld)RWt8V@$qsn(W=OkJ&{>>Tr_alC1N@ANIQw-Rfqug zVk66r^qFpr^M!1%)6U1CN^OA45pH`V-P6dafui0nJpsZvd`OI>@nPR`@6XiIRXpO{ zibSyGYd4>|EI-}fn9Hbr-oAJ#QcXo@+~EBkMP|}76PO)E#vCCoR2gh9Uv>sfP?E~9 z2?|wzIy9lA8-Ly)H^Tz|4c`~yk;jAvzXbtOb*lg*b8}8c;o-eStsT^RI+jOTdihu=q8!b~MG+czb9-x_{5Blr!#Q1z)g-+^$IJ*Xjp2 zBmj>*O4<&FfJ6&Pe!U?(}XjtH;7*KBv6a{I}Io*OVAqD`ZP6GbcSkXN% z9qK17;Yw=-ovZUFj80{rYXS%!p3oy_MHA#il<=f5uhv@cv|Oa%q0~d#Q28h}YIuMn zAq7Rf2nbW`ZE1=6Hy}3_@1En^t+FhX*}U6Bcgs#a*rf3g`fD1AEfw``JVl62v8E65Bhk(tS%Ry@%}G<`hx zgpf@fu?=w7^d5%1e8&2;E1dMN@_EgiOs!=f8yCAM$RVnQq*lM`ezkiB>~wdFbWvwT zHFDUlLwxN^_FPkLzJ^J)5D9maksF#iZjW~$c@^v?5GntzRsK3?)cBxCb2@&xm_3i2 z+XmxP7kngNKeaZ4Xu8-1+$`z1o2bC43^8^2HXxQ!~b;#j3ahn|?< z(LQ*7x*TdoAMV~uG(9Wbe#bb^oUgh!l&G@%q0;jea3@SZ!7`^G@t?O4K@{0Kq5>oAAvx063~M zf=#a_iS!QeaP8@#Xlm)M{>`76L*CL}wo>-{4IMl{I5rZtWe*~R>Sl>ZdheR zsCoO7mPI-aQl@oQJH0MPR$9b@zzpXOCUo%*Qn{;s{pkz#{94L%v|g zlf|y}oD8&-D}TufnI~?PzsCUAXR^bLr?UI~WE`K=V;++`t$J7{7k_N!2qaEzOW*5? z63rcn$3!ZHBL^2_fRAN_$;8pj{>-;#m@|3rDiz&YGYd zsJ@=1D>6A;t|b&bGre)IIG1{F+jPc9u+x-1+cFw>mat0dC38hcMCMbWt?FwywzuWP)lO*-5>4me z_z?a=L(w+eVW@$85~Z2YXRRY-&xRVEnS@FZ?XJKqAe+`v*9|v;#`kvitG)QWu(Lb~ zBru~eKlX<27vy^Wi8i!O#nR{+{9w>VVI*k4RTT$kqrU5x8m*eD6l^h8LX&G6q1)%^ zhQ_6(rl17G5sY~WUr+5MV*PSqHS8W&3mm28aEFFyYeuI>07*%aJ!&)ZlaZKaj(TXm z`$Al)2#n=`3UDTYKVDTwD~$F9vWgRFpoFC`8O_<35kU;qt(?agGnh=jB%;EEfB4tW z&uqsDf8XyNzn&Eibb;&bZus8F^qbAXtgMZ7=t1W5x=^(`Nf9L)_h+@lMTgDO;;eU3-&<(c*iD8 zu?g$b{t0mwJgMrHLfNGa)Wi8eV}+Akj(Z+VdAkMkr*|HE;qn{x%Gd{ebQ0QHizUn^ z?L)fK=)(M@<9UCzX8P{V4|D|+GuA6*mhN-38ZY}%zcaMX8e#wbKLAWXv%mNdCtm^_ zjtO{02(J~3B>RwXZngx5&@bB*nXp}RlT5A++PG4%t|qGIrU4ifa5CU#xC7Z`nt`d% zR&_SRs>?oq;_c{3rGy3xhX zzLDrWQ)#p85A?S5rQp|9(xXrr-HscHzGiTytq*&OlQM^=X!6(MX$^qjLMxQHrUbjP zmQEwhTWzRt7GSOG2693dDm8gS82F5{_?Ym)5MZ+vkyw-Mq-tfcv3t0jGc>ESnjtjB z{+_ryKlPhe0IfO=)4QernV@ia-DRNqmP^BXmu*VC>xwIixYOuKIWy+`sL|8Voq=L> zn-d_ui?W)5mH@)vZ*B#|2||<)I1ToO6_D&VJwrqTDgGn5h!$!}oQb`hy-Btj{EW;DRfOM^F^;4(vDvLF)_AHxF3;R22lA+>W6 zX=equNiZa1!Z4OE!(8E4rBoILvK`V62V~@*a#_#Jt+*q|OO4wz9xuSepD`)i4*>a* z?eOa+jff@b2)H_F*LLUuww0RhA%rh+0>Imwy2xhdBCRgQV#N{av~!r%36THY#sXSm zAA~FF>mZ2nX!U$?$V6D?^XwbxpHCL}Y|>QLiLXLsFekjHNQ6TMYcO5HMYf>K+pyVu z<~p<5MXFcu$anGcc$gmjn9Kg5aPF`uG&5V$fKZIct883OahU1Bt9r)MW@TF|`H7!s z!T&`f|LCV^08@p6>ApsAFdKdDNN94TG?`-{tSiNIvC%_AfHaKesSaSG> zfz}^@Je9sKO91vJlo_OJ%#V5YDX?G6`^7FrZ|`f^>dDYXy5Q6i-g9=~!~T=!g)*bo zXB@iBQ`Qxb4#%%i0lQ^5=fX^`Gk|~GIO%s5mM)@O25Om`i15mBcmbWQ@WYtKh!``& z?u(HFQJbEKi8s8GQ2Pgjx?3;LiV#e8UIQZWO*)=)R`X`>=bxzfnZrh|+e0sFIp(X{ zC~~%6@q2ItfbV0(k+x{G7brx;q}*NX>^y}%^aRImu_cqY`Q076RJ(HvI~>oEZrcW; znt$|J=Y~OHWW1U?9^=3~!;odiAm$R%CT-|&Yxv8OJ)aOC#&C|N1|jq?l7$b*Z8=(_?%#DnlWKy27`rmFi7Zv z?;ZBlyoJAFRXf@_BlC<#z5IW<-`#XPCC@3CyeU4frz5#(VuL15q!WH7``*yW?AeT& z|Hry`^;0J(=hpe|Qtqc(s$_$QQ=R)5X1~aikAP9Xnt}n@GA)l{uvEh>8Ti18`z4v+ zhTxIUCRPJUbm0EAMr!*ELN1yu1A0Di8E^MH&CFyHaOr77uhBVF?n$ck&fcroUtzx2 zE`n#^8Vrrp6z7*LQRgG@u#TjT~r z`v>k1=m2Ldszc1?Fn=4&1L z)sfu0KELKKh(0qtQ^M{X?lnzpZ>11u66y}KW{N)k_~iK4KWbxjZ%90#_aNYV`nxGT zY(5D!)0ry-?cRz0fG3(GF8A1$I8})Lu6<>;68OBkveS5^y+pr+d`ki8kw*=l zJJ#Jmo+)Q7pro2wY-!+-hV|h%5=}e+_lw@9oZ(Ge9-!Dft1jt17QcV!GF=;wQm~j2oAYR2_+ zW_42IwiDnmJ0zmiZ1x>61d`q%s{k+0JtZX=v4dYG9$7@VBHVarR7*ryXohpuylk$r z*+Yx-S*F{j1@75whc|MZGRYc1Qn&DUXJ<%W>4ax(&Qe*Pz`MV@)XWW7MUy90^-_i7@i+g zHFsA(q!JS;?(h6}_Y@_VNCd4h=GGRiR;d?mIu%GyFr0RIJ-AZv~XC!v}4 zYQ?MkM?;(>qC98j-i$^yKfvX-*RM1&T#2`hZfePPun9Qh-VCa!@Fw+tZ)nAUL^HzR zyH=Z}a=S)+c^b{9mS@ECmhDq%?_jT8w;#2sJ&Hj&?xyI=S>*c)WU6^1Y(F!eEZ$p)cZER}4Yi8gszhipk+(d>zROg0`8|hdiI3xkpm?C4Z4CzpUEO5r>9^`mFLF!A z=9ex_T>NJ&hzY`Re{U3_0{KP#ZKu+3<=@f2xAJ;0wNlx=&O~7K-Uf)gF@p!>rlt5w z>N!F1<7@Q~@n*DM7?y&UF~}Bmz}LMdR50rDBRoY0XAS6-E_FS|2B%0Igm+{NQ)I<{ zq%pY>DjKtEY>>MJT$W9BUHIrd+Wml1Y&@fCM`Kl@!@A1GTBxp9O@=@DZ zyp8lf>}WI7_cUM#juUkHd-Z5G78aXY>6KSra!=ESfe0VjKWUp?u{Ypu5iSXG_9Z>? zau2itlAFtEO02hsxnpBs1ZlOoi8gC>Dg`mxMx%S1x)Tg1>67v~C^VZPH%ptrP2U#a zgc<&rWXODu>NKZ`Uw9hBi6LJE3(KpRs!hl%h=W|UjjhQDU6WFzS>~RomB870)nyN!7j9;7WljA8W=bp9F6g86_w~;j?6Z^7G~jtG3dHJ(_!9NR><(%xuocnWNM827Q_I1Sh32cma(VwEY<+!E)uvz6*hzHvb#m@c>Do z@NN}WZBISOhOtFn^FC(WXbCSSpZ2Dp9#CW%xbOsonebC-;P4XQ!lVvt{2VsD?svaBGzf8H) zc|K5cZ2`|&p! z%>fs|U=SPR*%=WjTf&bfh-{O&sm7UHv!&6@sh* z5TOapte#ta8(Tr4VZZZ*Pj|IZyNB8x$mQYG&J7^PhCE!XH0u6(hOXHYcfmBDW2{zB zbQU|CffWZefc`$NJ;ptjjVx$(`I&wfix{eWZq&d;Kg)G%Q6(p?Y6OFQu z1is8}dm1eU>~UHnhsd(Fm<%RAo{t_jnCIfl{4#NX>J;&Vkl0+A+_u=6`2%gQNnZSQ zh*C)ql|NqqL&s?(kH#`uzfMinv=8`AcLD+uc++sCmE>cRL`Jvkf`)VK5zdO{6dF?o z44HSNcfc0VH|#COXLTF!j2+gcWwNvc+hkli7i^EWkUbvIIaDqsFFu95Rr^z= zd%S|fDaOpcUxE)xcJ90g(+m;{*8Ke{v-V$ug^w?d=gbA3F>@D?HBG!cV+gl`*Ytfu zLJDdVG%z;v5=2rQ1dF)CTUY%iPA`JlDa*snmFli>#u zX&WZ1Wqjuy#*t_8R~uunis`YJfQ})u0gK7 z`2NEtC{~AYk5???Yv|%~H!ocx#UWu$e&8kPm?oYv#-w-hQKCU1%wY`*^KM4c3?+KM zC8NE>g2XHbp)M>0s6KzW(L|&ALnz!lg?{mf^8LdyHP(?@yemgsHNc{STakf@*mLLr z01pQ~+BM>6?2Zqri{GXD&DIM0nX-)-H&tE3x9lcs`%JRIc#Z(@8h13)preqa4TN!X z?4wPx#c*p7HoE$$qy)&iDIIyK>X7AKp4(m6;K5OwD`+qAfUWsQ-l30robnh9g{Tc& zJvqw*kq9RbROO+MI_L)9K}&QVBo;k7^L@xY#40(_<-1G9(P>;f=1AZl1asYVxt2V; zUTJ6J4hQYT3Y9;tDdI0bBEN4cABhdH;FqBB|NjSYuy$WS(M`j;FJ{p|EU!`GTk1}$ zt`{)14WjPd;^RM_BJBbv#Gb-E08z?m%tuL&u)oMkNEsR*lGjJx3E(!XDq(6>g9H-# z7nquP!Q>mO4Gv!^Hh3WtOD0i=sW5ON>3~`1{LCg+HsVzj-{cfaI!g)|aC8D`HART|C}=j4aKpXP-S-;(kHgA1O5P@L091y`KULow>O#AcmiKX`qN> z)qKX^b6&GZZqUnp^3ImR#c3(BuqQIl2M4Jm{0=2#Va`iTIh9rw4=1AUm2K?kFz0qx z7*N!QUKXel!USW)x5NmnM(*xpFdxBGTXGM`q~jCB8-PNacN#B4by)0S39D`|aras`6pUk1Jy_-qxY45JqMd@P7KGds!u@>2n zoY)M7G?@N8L`(kvf6xV7Ev z2V;~G{iwSAd~ioR!h+s8rbkUXZ$)bnO`*l;A1fwPm5#fy`B<6_-C>vMC>U6htO!}q zHpM+|*}0zHlYxdqry03mbrHz`P~ZB8d-fA5B-J-6jP|KT;|k9A9#VRve`=2_(3kon zgRg^2?aATlfIqNkk}9T|WGG+=ldL2u;tP24o9|A*Xf@y9LYdUx95cyCY!>Ez@L^hd zb(zrgG4+TK)SEfLtwVpCXX&YrRiI`f}v9&R}^ zR8SOy0OAk9v$%>p^a{laYR8)6!gF|<)4#sI@TmbLKCrRpBSX% z{q+sn{IThq*#;&h!_Pi5Ri}=WW{#|nDn5~C`#DZPd+d1@q_bSdj|?LS1&2C;U2iLH zX&-|}g{)Fy$&wq|f%Lh=@PFA-k9i~fPv-R`o>{uG)TaLf)uqT9qq2WS~JSgl) zqP+;?%>3fgvrq6C-rzpC3VT5Y;{i{DRW?>+pw;SC@o*>(6mq!BUt?M!mFxw#GX!@v zD!T5+!$gcgblG+~zg{PA<=L!*OEfNTKyEqGuw;qlXHW z0of1#8$&~r>bTX8h5vj@`zDbWW`;v{MB}u@*;&sm*9YtV88~`(XJuvvn)3URc)*JM zj1N7+!?HCXbqIGBThAlN5#Jg8$^tiU@!HnlMdjf@`E~cgf2ucUSL$*C+e9Itl?xv= zEaqVs{s0V{uu4$TCXPH(fO<;BajpYMj+ z8K1pn+2`&GyXsjZg9~QYX-3P!w#h3Jg$u5LDk3xUdwJ|~v3{AKP3!4(KuoejaqAnq z^c$->kXCv$Su4-XwQQ@Jcz0uOwN)lxVx|KVXM0r_$Ax`#vLyb;`l;hVm{NVz@J+sW zc3;qBuZzZNZvPsf{h<$tKn-2ao!A`A%GUBc0 zvCCCb*AKT31m5_7==g!ySv-2=|7oh|m^Tf_O^ts|mYbHGR?Gs|D#r>GA@n)aEzZpL zVqBW@DVm>q)<(X;9Yn=du=FeFCl(5$N_wxuNh(O}G+yiVzkgi%Q-GC3rNr1lAR~{a z``-#vED?dnUFam9f*$@pPID%M&Y*US`y~%6F5Q2eZOi0%;3?=Z>@p`eZP&kubzC zz|DGv~PnL}%LIM5rV zm^h%RV~>YORzkw8W=fmzJR}6c_Lz$S0J;@SI1I{T>#9Em-}sFIKX%NNM<%O_w>4Vv4ul$)p>*24>41aR}j0u=)769i!#{5LcHO2vZhsTMU{RnWG*Ku9< zqH4){uK{$)d=P+15WCEk0=(ddAp+8(7ww%3pO=<*TK(nMh2p3lt{l*Tl-q{h;cC)m z5dJy*T?TJmFdN|)#{#R;mWW4a9(^44+aqZv(_)m+TsT?A*TueJdy7!OBAm%pnc6A<}nt@t3R?w>?Z*|ZkyL7-=Jz@sqP zR0=bq8}G&V{6k-7OMF#wTdB&W0~A!$WOwAxJlIkC0gb;;Il@D8{#jc2ypoyaV+rzw z`x!QajJnDS2|!i<*aMB=cW=N9=WL>aM4YgNZ3OFh`a!7V42HW+5IVf6rkb*2lhMEu z$yI&g#BuwJZ!oQ)4kR)M=m~#=q&EosrvkkTNJIY*r$)z#72Wd95fSk6op0@={mJ*Q zmujkOn%co}1a((fBG&Q%5`r{Z@l+!F;78>&K7ti_Tbkxi+Ky0e%=%6{gr&n`{hzo# z;I@KcPZ_}pP`IZ(w_#0$uDU)Yu+jH~FiV#JU10c;mvxPunhY(wRBCvzR09d~F-As< zD%h*FGl|5Oi;s>z89RLhtqCO>>@NMZw>SySx`NQo*f7eW6*8?$HpDX2f%KeuO6pn( zJLTh2S9zr6IZB~?+)J|JroQ~+HBL_jkL;LAbP z!)ZB@HDJaZF7pazJdciJk2_MkG9&KJ+5>)F^4%aC`$Ap>ZA8>*0<{5YEv^@Vtj-Dq zxGQ8Hd!kRHH;yCBV_@BwSMYGT0Yf6N25IWW_6m-*gUC3Ye^U zk+_@P`Y9wg?UapXGuiBdoRC7bDjWfDOr+!>G+>7XkMQL7hk-RCxw8VkbZtYF{e%6t zN4jBMAH7-D_@!%PV>I4Z#=u`FKSB@y0oIdfat0TY;1l%g`i6i2!<%p|$eZ231UrBL z09@E^ge%vnkN^NHjU*;u)Qp8`syC+q1ek^ZA0bTC{3kD%qtc2(x&b9x%#Oyer zv{evocb0$v00Bfb76WjD;Q(0**f#^I_hiw`N|quQ0fgxGR&<>ec_OWz)eutvDDJHn zGpG!x6j!yDDkP>HCblW1KBBGXkOk}DG!hxv2CZGgvH&Xr^Qw^jXE>k%Wb2ZckTx^U zB1$c}PN4gcz(2qX;~pfnBcc3v;#kzE7|LBmw)2~vZqf>g*=hgeh78pHQX!q$d-f7M z7q9PUqkNjjF!s{w^RkEbx~o2p_I2{gUDm2}jD<$xPdaP5B?<#!7Uv;gNEMz0ooEbo+;C&{4yvxNYMSfAR z<3g~_F1tqa6htU^1Q~%m)zAiptYKvLA1u7XJk+psyV*Q|3ki650h*Ql^|)}jBPHGl zia!79AB_VI!8=tLUIoib!&?9XR1S%|8|?<%P8D_`Ivna1!yJe0ceyn4fMcOw16A6B zfS5~^UAia$$@Xj_vmJ^U4f*DUqFg-Vlh`_nW<%#V&8RRDfqNTY3hmukDGCRUhBxN9 z`!n@=c&^Xmb)0;x|FssBck-`B)-*^@Xba5~p?klYr#!5mxM(Rt zQW`s+FD!VrvPZ=q>m(l+`k96P(}7n6QL2kLl!u>F%Vf;B1!lh9Rm|p84g)fbI#h#b zp6|*KT@NTUdDj<~$t=q)XExaO%CnOeQh@Arb{zi&bZV`x>JCLQPp|B$O^|r$c`pp^ z{Zbo<-f}U0BFVsg9bU(ASwBXjl+8wrG*4me9iQVq#h%QA{Hn&W1hXDHJ#-?&xkU!8 zXY2r44$8`&r3N*ZpBOJ3(<3_O-8(-3gZ+dX*{i>`4cDWCvsQMK=krf&n)zdo941oY zLju#Zb4*v=$U$6k|9vo7U?Ph{i>guTp4<8^H}?ah6i=1l+S&%V%fZZ^BmOd#y z(K@;+TlngLTXDg_P7{6`=~;?j(d0qq9}C??%@VA(-Kx1Mtsq8wlbo2v*WGWQw)!** zbQi?ZZ0vn`R}Q|yB}ZE@;K~Y=zxn?h2>Z^L*rOg=H#w<~&9_R*rO^P>)w!QSCv&ph zstxA$LO9&Zh{IX^gr^ITn%sUZ3=-*%@y|>yxNn2zIM>FZ-Tj}{w;an_(~|kvWs31| zdWTUbGzOlHQBctIp%uJ1c%EIxSG@w4HMD}PXFpu=u+Er-H={Em+CC#Lj}@H(R_D z{h8T523j(e^vNP(-P?zNYbnc){PYjfUY#nU{bd9?KLlBL3><7+GQQ_e7M;H@dr;gf zkTs0U=U>=GT1kyNak4V<2!|~}YJq5gSc?)SV%mlJ6bwBaJ&&Z=YzP;Wf-?54hiCcX zVNTZAMlcF$+>U)I5Hilq;ZdfWmX7jC%vtw^aYD3W}p8qw2Q|Tjz`i()bd0FR3pW01dg@%X1Oxe8v&2So9fL|m8p(09k9SO4*$_Io3?^ZMNn(BPe% zZLt}T=5$O7(a4=O^n0IFTuGaf+-8PS?v0E-cZRLJxP{A10G0Bm5Phg0OART z<9YNXfSTMFCN)80+lKX47Z5RQYh-{X7@Qlfsq3A!l50co@Ba?)_n$-1sPH z!KS)T$zwyI?qW9;+I-#>rs;Icph9rm-Te%p2Ic4z0&DZe=YGEuwnoVo`qC@TNU;i^I&DxEHkEzVgn?`j|@0 z^HJK)>(x^RC3`oV0Hed-+j&h4MqMZtNSn~Tbygm28B>b_Nl{Rb&9I2(WlU6;dk1>P zXC3(qKcJ(>Y%b(kJl$gHJQ4KqN8&*FwiGHCM$G6c&c{lAtWxoN<9uZ`z(YTYh(Pg|MDsqO5wx%&;ERbfp}VMRli+ zFEeZxqwkUw|~?7e3uUCqgE3@f*0+XMlzhE!TX&zTmYB>#SpIm3i=p26w0b2w7;9YohEI z%Mr0)=VmG<=&!&e6xTbSyqzXwgNIHIsLF>I*I@y5MS(;6m+@4fP$Pe89@lNh`Do$sxppXZyB{ zC&L^9fta}22QQ8dujB?Y@?1C^gyNfE zQ_T>iMpVQA00007+%3?G4&o3?SO5S39U*a^vl*ZifZ*K#ZYn~XLcA5am-}rBH${xKtb6X`&lUv;k<6i z=pSTLWoWjLBPtjR?)M*Bt^?rA03E1%LO?X82LW`3X3a6zeA8&c#N+!xkvR3d@pYfd;>?NqwkMi&C0Sbj!mo&nMx}R;ysBQS?5Pwh_fhbNqVr zS@C5(XDqXA8OH>t{vC^{0OBOb0-T-U>kTMJw z8BRksi92?2RVChQ@y&u|+|>j`^k9Hb64s>H5Zh7lfj|c0gEN?6TFRXnr8Ce`X6)`#bRovfSrQP+bM`n5-ohEXq&&omP%jD(N$UiqV-paPWfj>nJYufDOi@W{+ zqmEm)TDp4WeQ>`jhTr73cG{lnoSMj$Y}N;fH$Db}n!`cw5?5`w*`Rp%MwEEo2*{+W z1tnEj!v`zPV&C*L2mQ1UnxE`iDf$ z&BOSsnkZCU$|Tfi@WO`ZaCwvmBzp6K)2cWiMe+(BXT-tiRI`+asmBH{Dx4vN;h`t< zC8u82v~4{KH_Q~jrqYHyDqdm;NcMS>@KO%tyk&Kx2T{ykub;_`rcBIFffMyy=$u?S zY!=Ja7*wj35Q5a1{V;MFhXLn;Mv zHfAQv$lvxMl@N2Q^;*}pg=5ghZwm| z(N|x!gzhQS#~sPiJ)vNk9AOH_tfs>9v(eSzeR&!cE`V`^<;2*~Bc3#Lj$(I!gbCF|q&ikm3XlkMq=2O7 z=z!KfOnu#IB-o8X16LhvO2asbsIc-tXDHX|5MaZQxL%CP>2xu*hPBfDX!)dQoF>@3 zsm-Lx;806pQ_^zA_Vk&vNUV8?chyI@XkO3&002^Zd8z;ZeyBhH^*jGwc1JCI%I~}I zwRY=2bhq()h=Wu2*VzG~B+4;P)MFi)7(C*GWRJw~54`f7p>sAVWVXy@{x{XyGoR?V z@KqP6H%85Coq{|lP^1ky9Sj+MHZkI?|BHHoag4gQ_&AhwWCTK-%}QyUrsG49Fp(}a z;9P8(=sS^A;?_#N7QdHDgaDiN+@#ZNbpANd&nWgR)$nfv`W7-=Y?7p9J#!U2SGRpS z!`yKqM^`#BaMiX64^pjAm!AsH#)@7c5BC=GnpM$#vl zE(Ohs;A|&%ztM`TR+wTlehF4H2MYoihD&3y&vH{5&6po+gmy{#Tvl78vLX9dav?`Rj+4WG;j*Pl}DDcE|jGs?ZIU+D6+QO?2MM?+3lu%?K7`TBA0>p zCM*6rOq$_J7T`ZZsxhM*rIDwV`doV^wvmw6dvO9hg?yjxx8sh1fs_(ybw+5B<*YCp z;XN#VG@MEDcWG-sV3c+W>V;6Vg)f1ZTR@NE-mGau1?VV!6fNK^1XBr(|IX{l^_tt# zFFE$NdyXeUi=kJuVrB~Hxxu!)zXAB;M$;2YWTSsg?^l=^9HpmI#awd5-97c@8KAX! z;`g9`V;Ax*q^HQ+h`1Mj&?*cSte>s_)6=*_I+v+au=`28H+5W<&){axet0~U3M>%l z0=_KZgd`{MoBYnB{08&>^uNST=>jGLPaXbd4c%YA{V#hJx0<9o{6rdvCeK_p(ZYNY zec?)%OO+mv(>9u5A}$*>q-UT9Bu9~4*cndgWW2yUTy1rIbBGr|kVSf%kqosT!0vj~ zi`;bz7J(?u3enOvD?O%|f|z9^N4qhNIf_P$IL9}&_Qi=A2?kRh zI_MQ@dWIL1akeh`<(B~O$C*z7O!4d5Ldy)fxn*ng7<%*af$T72x)bCpV>CrdqtobX z8zv{nOk1ER2tM@0he?f`?n2+;X-J{auXW8Y4m{vUM5okEgMWeyl*eak$!tg1Pf&kx zNM@^m}cfZBsM<0@hqxD%2Fi|gvN2VWh7*F>z zBKe-scW5JVjor9O|Bvv++s)DDJmDELkR$ldvz2jW(Am6npHT*w&`A~KWr=NdJ|$>u z);qTzu=6UJ=qKiyI~PS`&$$Ap`({k_mqS@A?lIq|Ta$0GY}%YLy7&?i6!O=9sdhw9 zk+s~3H(C*eZoU(~l4B#Be*bD$w5*0B5JMSKE8g>ysu~(s+}jcS$vk#^MTyN9o9Dz2 zEE~^M{pvCPzeQ^yI!IJ~m5QG8A9E-huCXl40cw;O4@zSCjadrUh`7xX#Kwu*zje@F z=npn_@=GOFV?fjziu8kLv)y^nY2Ald`pJVU#T<8m4d_ znBBe|93g;jC+`PKzoFY~eme1=dw~BRQDvMGFLQt|GK|Ynn3A1>!v;H~!=RJSCOI4b zg8NO7KlG+~erqc~D@ZR@9QcBD+fF6qz_~FK8~O^d2F(p?^xLnJ(9b-PjbvPp_4=DO zQZ*)wwW>gH%i}IMI68bkrzwL}K@S}UR~V?8OTspX^sZS-fOz+5kknO4)Te1`k}|&z zur*O!xEfqvjFY32)8)}yi{Ek6KmOADgS)o@>=14}+LZQ5Q;U&4LK30^X6Ch zx39p`J~IA%AkzV~tm8~#lZQ3~W1aFJ3!RNx5l6K_Bq{zo_vnPO`@B=cmKF2j6?fK6 z$l${Z8UA`AK?icP6DX&V0Th*d)05z^b zwXIfj5u3O%d$CjkN#$C%BF`8qw-({TUhfo+SjCSIK0Mw2%jHtbX0*DDqsF}?*ztmy z5v~B-IF#?K>c1EPfx_RcpaDfkzwm-VQU)nN;x_wX5_8}-QliU4z4b3GL|kd@Rrrux zYRGq*Oc(vOkCUBVWPS@!toWBau8Mjj8Xt-78R;%tw=;Gy1CUby;;a&+)%teq06p!JqSlg zgQ9xjS3Q*sO9fl?o&k6uSt2+=QmLu=u8<&;XzxQ6N_OF{z=i?aya#l34|=@{t?IS8 z-w)ow>Wd~iu76;?O}gV*6og?lk6@ay$%L&a#7mqGR(qjr{5ArVmV82j1a9MZ$%3x~ zifE|CagMytGY{Lh4408QSreo;(Dx!sfP`dm$Y=2;BW63MXd*>*p52yh>Phq?K?!N; z=Slj%ir%QTmr?jv()-##AMo}UW3*Bqx)jFM=$`z!u3s&G50JOwNCXPd_qC3&B5j|Zr20y zHTKu}V*=Zes$VH!hK0WGWoU!_{w*NRf#6HY=#`efnBUn1Q9nwq?w7z?Xh)9gp}Jr7$d9P zT&J8b>eld4CjLcHa0KeA3Sn6+sTw%1gkdesRVitHBR|Yd-T2`l9rZN51<8HFvG#N{ zA2k?PG@=6TYG5CwJ*sOZF^e69hSQ*3c*aoqKvg*V-LxBK07dRDZ^V)@$pWIc4x?nh zXyLi(l2poui(Suhf=q;jHO5u7>SU4fd4k!h{bH2IfMoZLv0h(6M*vz9`2iC#Z*C>b z>)#J*PbbuQF^aX~3zhXjS`^}luK3vIcuHOZwg^7q4>g{ylWR5HHthl-UFcIM{ky&v zI-R5=u~7GTsoBscpL5SW?4sBET=-fJ{+D?G1FW;fY4rz)y`UNm$G@(Ba>gj2(uefO zuVxW9Xc*R4U1#4F$e=CzGzJj4SSSo#{+HP4`G>5Z?sLe%U*_YY zQjX7!p z0n}k--M2jg%U}>&#|-O|Riw*Jo*O6Q%um3nN`jds>pB$a*&?3?J|%Q=_saJ`uFWxUwE8kWv2P`rDRnu}*1 z&JzMrSr%iki>c@}yGwb!$FimA3QS+${mLqV*AJ@yiZudbx_+ydI6prns2N`fuVk7` zQTz*H6ETY#E<@p^k=Bf(;8AOk87=|3G<`7~T38H8t9&0QEOF>P(Igd;o}BVC!Yf`$ zeucWQ01Cm+Ld$6!6X@z9#)p=q@hS@?Jzs`g&Xw8aTn`?c-%fmSK!M#$ZvF?Fz;ROy z3x4SPj=%Y4*1x_hsJxnJ)|}$bT_chSy}D*y3`*gYNsqHTtQVJXw%!F4H~<0B4B2Fy zyBSu4)RiK@44SPGvA($-@%hI#6I9&8IHDG#dqNqLB$}|{I(YsRM)0pnrh`O{hV)#G zRF5iXEiNHBws7kw-so+5%&E{ZzeUl@1^dE&UAU(Jwy*%#T%b-f|76iYp=Tg_xumV-0_S%$C5g$Hu6$$IM@$AOIn9euk5u8y#ZM5@VH>MXYzKQRVHcq(J1Mdl8wO)xS}C z*bkg<4vchM!=@i0bIZz@96+w{W9_i*pR!A3G}RUGHN127N76eoS}-Q9UfER144?7X z-Rsk8l_~9O!QwcFq@Z$Ia^#UZZTEM3pALBuk`gk|d&;cpP9r?_ryg|ap zXDsOuF(Za;Uwr6kRDhe zK7Xv3!H{=V{$Cuz!WM4JgrA%^UxDfs7#iFCwZ?NMi|&dz8bvK73rDQMaQHz~5B{OY zJw;-ji6xiHcOzBrbVm1=y=XL#C)ACUJn-A;{qtoU0 zt14nc8eG|aJH_cjJTqezQAc;59n845p@Z&4KfqIB1yVq%MAJtVK!J@XK~-3s?*B&fC~N5$yrZGqr4MH4_U{vA!Zq zxf2s>wvI4HR#}Jx_Gf5|mEZV2)_kP(d?~3Fri)pLV{+auXnXr)QkE_^ir2qa! z!H1yua#fVg%kLD20kkFcm0cH@NBqESdeSm8KJQxj6(SR=?mEl2C7iLDOy2=SvdrIG<+XKgS?!Z zA;GgTgta@s<&kdI^j0Rkm&&~SEfoAZIiklTXjEV?sS|0Pc22i|d==avUF|RNDEo2B zQZaJQT6*4Z4VV)QbH~Mapqv@I+*tU&pW^`5%vo;-)!yA`y~K`|$E%dXAW@X3WJq)a zpO)@8)}POHs42o<2R>m`Sfk(&1u_tFfT=k|Y>%}4!)?4g-0_EQkQ8Jvn`W4wBjgyu z=bu0Qj~zIAV7aowPJU4TAabWROGMFzZJZW=Mjiw%@!C4>_#a8ARYk?6O5rnoq%~%V zaZM2QQ1wPNthR`0D%A%Fp6_RCj-Qw~rEP}rfwWx}(3ahG!TmzD%cZSiZ#t;%1|wN>9UGlvxjJR!wC?;J3*KNc!0nMdF}lm_U?T2dq{@l+ zBIRIxx(LsPzhg}e0|}ZxG(x2Olwz-{s>KTGsW%Eh->AB)8Jz!|*K%{@76#&Ol~;fcp1w5|h=c(@rvT5IKwvpw&;BZmLod z)AOLSHW$L13c!l!$K8B|Xd1-}(c||Y2BqpIhg>m13<}&+Q^oGPVaExL@LCp1v+z-a zH)2}JC$gA0cTm^M4O5`nIjYNaAugt6=bV#UgN(OH@q8|8@P)qsv$PpUU3cJ)SDNtCQ%w8OVg~P;{#=E*q}` zI)Ph*-k4ZJIg_+A12nxPj!MRw@EJmRP5z?A(oeDnu`~`dD!(o8Dfl2rOdH87=50r$ zp{;d{-=iNK^L96R2DqMD2RbT@bT(MW!01TSHWjdJ%>$8)oX&dRW^zIzBo*4hW*Af= zCp+-ubpGW7RlfEK@k84P?3pN$-ewsH45g3hvEY-H=z9?(Z`ckidL`=-F7+Bq3hqOt zhy#nb608gpiqG1eF&)sVE8))=UybM{U2*A-L5y&9)3n3&Qf0RKm#IKfYH6o>tgkD~ zDs>BE=1OR4Vdg>6OzTPS#pat~l3y|1nV{A3En^C~oh)YZgWQwUu?ECvRZm9VlrD}d zOH=PELALSN_0UI)!ZB|vM|6;qhMxQ^KdLe6mTk&|V=Vt|Bad}Hl=$1esZ|H&SzeKVFw#cCI(+OzyH@&V@=-GBip)ep`ospe8FUm!q_M%uQ$Hm>}`>b>` z+1xM*=-38&D)3GCv|L1qtBFZcDYwi>VT(fhuQh@QM{c>|DjC#hzQnT8(0W*CkR?7T zUB5Oj;&2V7o5!Lv8#QSIcbcQn*4QQ!X;P{F8pzxnAU{eZE#p)Cx(Bi(=oap?jH#CU zTI9mQjRp13jeRZ^^OD-YC)AW%Zo*g6En`P1hEaig+L^HoG$?Pehse zb+j0NL~JbDLU6h#$MN>j?$97HXa`avL(kvQVM zG3YSFr|T7L^t9hr)HVk z8rnK&YZ~s=Y;z%ks;<&Br3 zViHoY?-6r<{1!xnH-Y^JWEW5rgMR=;K)Sy*s?*!uzWr7rzHGUuLww}I+S)Y}yJo{# z@1EO{A5im`HbLR7Z+sHQ?c4g63I7190@YGc0xjp-3q_A>_f*sPG!>B^z6mApH)~@$9DKfnx+#DGL z)c_;K=B+#wn&(E;n7|6Ht6u_w+&b`7hB;5vRvcxod8+azFi{mR;N76SH|WL0eN2t* z3cQ2o#(GH;OK!vaJ7>NgTXB1;OYNd4kt=9Y08DHI?0p!9m=?a_pS&5tR1L4l$wV5Ze0t3;>Ais7K))yW8zjR)4Fshq7WG1}PDRB^{{kWEW8Q}d3HWN4iJq+Y zYg=?C2tx2l_YR$WFT8`wMAgg8Y>cHy4U0ot&qS%PTg$@5qQ_cT|I<2JOpwQzIQVI2 zJaRIlksxZ}P1Sc_l8?ZH&u{gXE~j1rl9T@2+Yr&V$r_drkwP~|IDAsm7(kL65PiQ< zpI;u$^i$D@-mv&6+oV?=@Xt>F#NESQ+oMT15Ug3`p)$Yo(+!4!fE6vPaCC9^A;Kod6kXX&(I_v-4|W*;Jrg+gY8UN!zn{xTNvHPh)`3tfDIG|{p@(l>v=s56XZ~sP z%zreASdW9tfl7CV4f9Nt(?Q%14=L8ivChdgN~T61ZwjGf8qj{Miaw;tRP%<6t3V50 za*0V{yMl=cj>+ER@TR z2Jo8dpD99xu}J1<&>MXt*DIUWRrPx7VW0Y_8sV~GZa7qKD9;~b1p&XJ55G>VOI2zM z>ETdQzU~#hy`?)#>d3h4lKOGDWDqnQo_g+{aQi9M4-17~8eb02RsQZwV?c^eA>(c` z8^*&*fV<9v_0Sh%p8wwfgaCa(aVtA6bjXbE_v0a^MCUQ)fm}vmSOWcx!J;lr#fk@R zG#vO|FH2tYGM=kWU$iW^bR&^KUDKsGwMu?ChVf@%^bKgVm8PPwD1W9MwVL(N))O=! zn|t^U+gY6Gy^7fLN`Wcq{!=>JepA|6RNeUxY-SLfWSqrFro!RF>^a{6fjt5-C7(@D zjUkgB-5&$xde1Yt5cF&Ah+arY^aQfEmYmp zTqH#EDf$a?>bAqUe=`mavys8!gf+R7gqbSrrjVFd(cE;ckhG@tu$|NK{L09@7c<0v z4xPAG&cN5!_Y}^oa}>z~Y_#p{wW`4I0aV4}rO*)#Qp?Ir-m3W|K!|JuTp2R8wef|gNAs=H6|Z^z2-|tC-!DPX>9I0;GPgdBv;h~UmbKBALw*#gZb*3lW9f6ljQbEk#<7`CerfYt*{Z^ z)+InNr;BqIp}!6GxW#x98x|;H-iD9{?i+dXF5#?57uj-8{R0W0>mKNV(eYhp^QBR)79}{ zzw81wdd%bad(CW*>9Q+L6B@KUjtIK<_WPi_R}4?un7`PAg*Qt`R7yN#Pa!-|^A#73B)8#DLZ@==jh*_dgC6aJ+@xGNp@i2i6KLSI|L8y$-ic=oG)n}^cmRP8% zgd;z@W$|zP1%|q;AzKW0)=GEVJTLhtmUcrP=kMCHmHc0hpY66I2%kMC_j>x~0B^pq zfvT^cDHorlvUUY~g$hgR=PT^aXMI;?|6Bu7OdQe1lq~y;6Y=kRjtDn1debT?O1!p3 zBZ?*S|AY?*(;=YzcG*Lit;kIuHdE(QrBgp#)vGt!J$%8UQI#AXxe7QoMp(JLSrlYo z-8ix{d|@{2;6+D!#NpRnM>w32^*_N;cuhIRVdR8+9K|`ye@4pMRv>ve)tk;r(-c4k zmuSR2THIS8ScW=OXyDj^#tTdK8G) zUi7e0l(N6~H_v)&{>^h#{m4E~ERL69gWVN3!wMl1s15>l2Rd$ym~{%&)jqyy%q zJD}eIxDrr$(1>p!p;W|Ki!Lv9k7eHU4m8^+2gaM;5sX&&&r3VuFtKDgBJjcuB-NU% zn>nMMtaYXJG#>uIZ@Dc*cSIaVLFXv})>{7ML-re&AHtLUMKST{+`fp7CXWkH&KsmG zQ;i z-$G44Jg{|iv`Hoh`V*GC`v~3RIjjp=_?5$eN{vn>qa}xmTh^rD>De}{0-!6LxdtJ&ir55@Q^wLa>FN}s4iQ}KC5YP zaAj56@VSXy4*fl{&U25rtv?Ncp$JPGM`e9x1-BY5VM(H|Q<;ZWdkD4dg6~>W1>ao2o!saCH3+JX@pv=5K~)K34j&uJcti`GGZ0hI!Od=6jrhL?=-+OVeJF^LT!SyZ@{WJ^9lk@&9}QoD2pm3yZhO?|E6! zkvomE&cy+p!!$R;kdf&t1~lg2p?h(C?H=A$mBOfWQ{h?;x+4wh(?V@iVA*Soeo&c0 zKevrH6Ul8Nw%(58Kx!(RlBqQTp1ZN!+w*BKCFqJoyb;mL*cx#Yk}9@4D6W&!)m8G< zq0KpAhB?f)#;dRv2%EBM97i7r6ZAdbF!XQvzeTHA^Arya?94C5NnD z^J;cZ^C{7(R2ir5vrtUF2{&t;6TLuVNL*i(6t(k#K{0LSsa9?80u4>RH#S}?Jgr#C>>9BA<4Tjb3$-W3^cOzq-(qA z6vuac%!aLux}fq(`bd5KQ-VX0Ma$a)GKHHcTtEj80=pD#7i(8%l2S>OzGFoHZ`%{m z6bPL55yul3f+4Q;UF)0qO_UFu81<=PjXON1n(>FSefVM!V^BO2iOkGT)pTh4XJk;? z^Ni{6!=T-g{92HZ43p-Yr{!{D7Tn0R=SIZ(q*s4KIHZc}s^zGz{LUgAQbm$v{9k1p zMoOzR8I|M;lOhXk!FtiK`!E`;MIhbnoRh*t5disMlh7APQM{aumjvNVtBQM)5<$WW zACCjtzH$2PAf#65Q?ooZ$w+FiN+@%FV$nb*mB(>nW^v95wBW{90DRL>X|_YiZ{&$h zpM=+VsmfP;;{MjEoS-=vqt4K=*bTHTq>xgwPo9!fc5=;}gs3Kx@211D%Zb>ea8E%$ z5@}8PvL*cqp<3JOvDiVin$Z_e3Ad=7YyXLG!<5k04i=*_M~ShY%o@&DTV*ISxWn#- zlJMPgGDj{?TkUe5PjrN3zsl%nBdo6O3b}F1YEoZf(Bql=@DtG%5;eI&y>0F>x`r*BTp` zUEszw##4`PF?VuOzy)tgI7p!`2hu)fJa`e?$5eypY9JU&x17G-F1G{R&#cu#MU!Vr z5E^F%p(r7T{XtEC7Vv7~!X^f)+ZO>D3JF`H^HthP&8L5Dvshc0`3B)uEIh(%DN2iu z1fX_}*j;rXys@?uj^~CdL^W9#ypz`vU-sXlK8v_5D5jdn9of$^fX<3--ROlhD#*y< zjq|Q#P^W%B&ZBA)E`BH7o+tJirxN5l!QZ`6PCfB5rSC1?3O&CV2LFGfwDjU1{Fs@# z0UD*ov$9$rJ`yv}gPE*itsjzkJ18AEe$8ylbi*elYZtkD_wp!1C~QYx&pNR z6&PX;+c;0XyjMgxogP6|oMA2u95g9v)zgAI`nXMkvmOD#taUQono(#1Oy>k7uPbXkyXs? z`vnFg=n48G@?H}MmzPKv%3=1)-4OI~V6wgt5G9dbzYPk_RvHnYvTW(0PUDot zDgCUYL*Iz{*>vrp(WtPFCM-7NG;DP;H;*ZM3V_UD(TbtK&}=QMPUZ zEwL2N#m*bUQyOi$ER=I^y?A|s>3OQ=M4eYia0uYv3iRCaC|84scNX~i%-Gurg~-3h zq=`7U`@t>4;E@!d4kU>-2(|}D@L2hCmpAPjn^RGQ1dW@u-Z9-kMgL}VDIyw+yt`k5 z%tZSl4M7<{(?P2G>jE3NXiyA>uRf}{T~(WwB`Ce_=6u(%tV8(M!!bNS@?2P#`HzRt zwFEK}g$DZY*<)0}>{Gdmf$BdK`ZxMqgpDRNS6uOCas9f+fAl#TXHti3Y6t=_>TW`2 zKXM<^&Ok8^Llg~D1;V*5I$j~CW78rVJDff$h>~5c^@w5{$;ASKR)gzCUGr0?ExV-E zchJVO1cup0ONoezik}}TYU09XcA857Z_d}3h{^{{xFc{D>u_zje-^!0Ul>${L5b_H zeJOGQF29bqXiR3udTs@`ib%lE(Z98qK43PywPF?6B-|y*E6@yINX@ z3Mlm)@_m!L_S5eY=@7dyDJGmCn3O8{&u|AjB72oHHFIVC%iGK%Q1%Y@d>Jk@!H$3y z?pAd!L0wKKHx13UhcfPg+00xrLSOV0r&xyYEfs0LjK{*9?Ekc6Rv87=0G~+5ki>n0 zGVC-;6n$xCgZSTizK{ONfj6Ek*$5PlOWH_PiKx{Hl-z{(K#I6yAVa9&x%?Ftv^wC= z426c>&HM(G%o5Nps1=s)Zs}+m7L&~)E@g5mYn8G2#$cgu@g`BzLrx9C4-{4R;*I~Ac zMD>rXQkj6Wi>_Ni@y4bb)JMdqJoKtnaE{Ka{|*n%>2ij=F!xHyEADf&O>gfE6itiL zQm=@C>NTPom!IthoM1iqw|%%Qd&T$FTLcnke#f)C(EiPAT&O`UIq#S3b7kEs7rt=YIC$kspr6@s)p)Vz01 zc=LIM<2S7lm;VMIV!M5?#2oJCE`8{E!o|Rw?C7VDx4Q9z3Ws;8aoPp?xE9;HF@)mE zG6<^MLmK+0T(hLu-c#bH$Y6d4nY@HXhJK*8`hPis@GBexgrx*dsL^d`u@TU3ArYbZ z-Q8WM)Gp=^N?2K??>5P5iwFs!x^%(%ECqJ!id`Fz6l%nTti}NDNh)PY{16XP+lAz4 z@c)nDhh-EnGNTgyY_mT=o<~Sg)a_bL7MN;hC#b3*o+Rg0A?Sr5e(i+h@ZbpqQLax- zRaHpw<0^-06G#oJN+4*i7>TwRFDDO6`&tE6_FImWWE#1Bn670lSvqHCF}O2cojs)z z?jp}q_NROS%T2u_wb>)Tvz;E}Dqc+WIZ#0hEH9MY609#= z40;0|fF(i13)d~lp(qbU6X5Ll=nvx}hIn^yZE#uV! zVzpNp??kzIhBO&-@P^D!o$)0liG1Si9i>lwq_IP?qh3o@^;+0)9A*`1D*+{WnfZ|> zD7}(ez&%Y9x%E2W#q|IfOH=;9u$G`X?%>@fUq@R$P%X=z?oh@PfZI0t91`Jgv3K>m z0Hc{l=G&R|Mgn?)GS&-1n8YnwUJu0oRjGm3^(MUfS*tR9c%2H#G zY6-T5z>nzk&btVo$jY9%xcSz&AXfBM-@1Mg2Sp=k01Rla8!Xqxblb3V_ma}I#Q$(V z-^;<<$+EkXeK?IIXVV|vYs(m+Z#XcrWuaz;+X4DfVb=TI9Uia6q+WCwW zcUoP)THo01$#fhqomvv1`Ula!-=00K!9$>rKn_-p^fkvB#k_I*UkA)bB98!9I>gBT zRJgWU{9lh*Ah16~+M z@(^$2G+q=Kk-piKFl%ut$N^x~z8j@VJ}KP#T|lcwIbdq=78dhoWHZU$(Wn>QO|R{R zM8MCQApGZN`c78~Fhppf&uf79W5^n_$#J3BIk$CN--HQl=c*^)dKPQuDQqoHZ{%TD z$kARlwO49nmHLJtxjWgxzV?gPtahtx)Dd)A0FlM5cc7>-9G*Au#uddEb`~0XnVzW1 zRASZw#`>S0xZZ+v3kJu+0L&YwMK=BGbpoTNrex(Qrwto5rR7FAH*i^m2FshOrl!Cl zE7nWBI7-0;>=gg-0I%oSH_ePfW5Ox)+(*Kk*kq>?OmCh+_QTouEl#3e8_XlyLn!#L z=1}$4*@ObwI*gPd#lW}}jAl3SVDlUDn5NQuvmi70m$SuLW#4uIwv`bXT8pT zgn*D|)>$!_H6aRbtwsGXdncc&eF154Jd@M{2!2aReOkdtO^`RJqtCsDuh0ABxG+Fp zF0;|F)P1gZ;l4m?jcvTapmFl#2xXi`uIc%ZV5u7`bE5v%3QtGc(D2G0^H7HP1z-+d z8ne(>Z=imYR~x}hX?BQ4>`U8W=3b3wD(atuke6Re!B|oz3WGYpc|oK(#DlPTsid+% z30s{?VXVbKz{QKXCSstE#CQYJRUOQ#zOFa^r<2ARQ3t2qH0ft+*0iYVhnKZY($JkO zA|$5XdfH#ktW~avn$cUHq$f|x7!qM+VC?n%JOEF=#SWjQiBfMU;=V(hwyIyFRE#_4 zl7jqI)|1 zb?k3za&B-&O(ofDq5%t|o3JovAIvM>4?+Sq$TWr8^JN>;KBj1+=3zq$x*_H7+hhAe zT@(-Ghyr1b|B}KyD&U3mAMJ_O`~1cRJY_`87EHOS;!m}=-l5{dzt|r^c0(~Yq}rx& zL&Ac~3u;vx-EcL#vm&a})Q;&j6cOC&O)*9l@9)MO>w@%(ya8gzLpec#R!x-9?ukf2@s#!B-+CIg4V2nCMJ*?z(O^ZGAOYN+C zMr-AEdl11v@EJ6b>NSy`zmUG?94-YGXU#56C;(&2@J*k$W#W;o8r`5eS~`!&@FS1# zFv~-{4#(x6i?#o3yHCBwQESLC=9(OF8vV=quS-{gAMtylDFKr15tHv5q$Q>)QR*EG zT}nG`EchE~t+&{1daVDs;t z{$6#VvuFY8f+CeO@tJ-X8o)P?QHbN5={`_&wA9hM?l)v7P`ddd1S@;73($SdIRE? zZHoVQUI21-u447oiX0cgQPs%P~+vUfm+5) z9*ZP}HVL+yH0~r-y^o;mKKAlIZP9M~Xo03QrVDRk<07`0M>WTZU>))JCH^>!DR;t5SHtZ;JTW`MHt52Src6?_p(4T1fef2lUvRnj}1zot77fY zL66zfig)MpToc+a?%j&lQy^n7ES(~ejG*BQlVGi^r*;v!y_!oiE`c?kb_&4L6Cd@J zT&Rh}^IknhygCgP!&)zFy-SvA_ zpDc7t=N_xPcH3&0E%7rom=o7bndE%!uTF!>d&S6}dwN09+&1lCFJv~s;FW9dmhIkc zuwm8YNwS+?*mUhveZO-qvl_7ZLwYppKBl;^GzmN7^Vyoogx`R^7L!X4~dHj^+2M!xQ)W?Nal2}0(8 z1{uoQswGN|tuzPV$|S}u0WPx}858XkZrlN#mXh-r@;p_VFjE6}&ze_%!fd$B0lDIy z)k@ptt&#`eYCcCO74hRz=r!RN#TTD^j(TdfZ&fX*R3E6#oEVUBHEtIh_yqRmcg?=y zdxu8Fi!8y4Yf-gA{XBY+FGFZKv zEf0^@;5rq0!vpitP}Uw0xl)v&xxAcaY+tzdLGthlY}a&yR#5(v0zQK zMchxrTqZ@B!h93u!lie>yKlNn&{m|XZBfhX*-}DLA86@y)XG{CBHQx>&3*j<9H-_z z?6*I2v;I!E4K>-QLqwEs2bp2VLUv`roi|)lSUnMTf>Ehp>J2RoC2vnJH74;p&t2F8 zNmvVUq1E56ZN0~u4(qbJ366~68fGJ0s{HnCAC;(2>6pzYN>OvSIxA99rYuVaaKucZyFJMU96!KwshxONqj-XvK(rG-P}{N|Ru91cOE_I3>uIk;JB<{SDf%+Hd9s z?SfBdU*;T%*@qUMJ=Kg=JFbGYLIQlI6}ndDD$FeY00sK4dR<8?1eYv|A?(LaUYM#Q z_iKAw1;&dRfBNcWeclb|XY{K$%CU7qaaS4hm>vz=@9Jt>W4@lO+T4#;0j9sNNeiBC za`eZ>GY8rqi9(CNGD_4y=L$-{32a2pBT;;P*J{|@@4ZEtUK982R0gi+dSP%Kygxvr zW|!niI1@q&O`k7Snb^J6>jg|1b?$E~XX)d1m+N#yf8M&o)73Ce3E+B(dab zb(}4Zw9#6gOP7U8xjUo!$7>qVm~w>W?>Ls6lBdIx3iJEWLd)kr;~kGP-!yOm1&5OKa5ie{LhWr_~N?kDW?RBHfhCLT8gWz)Gm;F*9wr>_RW=Hf;d zUGF>Pa3hI@(~<%_aGzSkI}{%@aP+Vvbm8au#B-V}dddbK5#LX0Vfnsssm@|d1*CiH zoB&?}3rpdb`!SNHFQKCI#g?-lGy$O)`6zaTc7Hv2+;)KpW;!8W4f&x zXw{qchoK%2kXV+b;HHH)Ku*U%7}=u&O%jV5nMPzbC+m;Jx~s8 z#t^WD>I|eA^V00a>Kss2CbN5#dgivC$(D&cec6EX76mZ!UP}P3CWs~D{#a!;HnD@f zM^W)U!2hh185zC+6c0%t{S{hzQ+|g9{i8x-`y3%iehx*XUWPJo0TJmu@LTc;lou{{ z_{&Gla4lywdrpxSrtGutB|Y0IJKheAEsy3`2y5yC*u%!+z@Pyk8p9X*S3{JNBK1V_$@TgY~ zc!^7t8y}jBJ~V?=W}(8pI&-9b60^uYu5D&nT9{=3khsyS$4-l!nev{<>R_vk7pccd za6WA?r-&NO2d~5>7pf%rR68i6KCI%IY>Z$iL8m~RLRO_RP*c24M57!%k7-Jd;^EWl zO~a`KoU-&gY=j`X8GJY|UM9DLhx1qt7l9|C|1RmmS->CMT233JPeioa`PmTpf6wLQ4)Rt zPClDz#FnvgHavyahr#cko(qo}+&JW8S66eI>UDS~U|aX&|GjA7`mQq>#&#U{a&Q}% zyw>iKMN!s#yoZn)MC+!kS>b1uaGFm@++w%b^3}BI8|Ns##@fHErDhL*RYq8wv!`h( zWf4m{5wDrI*(alv>i77ASgZ#n3P3m3F!Wb-)cP%Uw^kMfwE= zX?n3v8_bcwswP_1lC`{rZd}LcA{A>j8S06oz^(m+DZ$HR@VPZPew4^$;ASE*9bpp! zH~<(KKqDZH%8(kO-(Y~R*Txzf& zK>3~1(|@E$lOa5wjk|5@?ZGy6n?vD&H6B-0px?CtP&{8uqC+(J#8o5+l6WHty5YRO z80c0)NBn4&Pp3G4J-vc*d)+LABs78Yi#6$5e)xx_a|I-N-g8M@$0lqvn;SS2`_MO8O57nTfgFAfYU*^jWi0 zY^cqp-G9ciG;SgGvsVU~LQ)CXW6;u;#b{943PLda-)nd(F>-cup@Ngyn);z_y%Zgr zVy8>4#Ap-BEyWBI*JtK%SYu5R2|Kf5yTL76c)1~xJ+rQJl%au%Y61M2*XEqd+;mB+ zPn~{Qd`&=2A;mfMTV`h9<0Q5w1%);RNUf)bmm^oUi=kzIw_|OCqEU9BzDD4Gdf%dzP%J3lNR-v|QYYO*B?@EG z6W#x1aOh1omiA-9XDB~z(sO04Dv|)Hm(r&iNvK+TS_t2-MdbtRvz~~U4kBQm4;t%# z&_NulH(Q;YFRQ05y1*=0o5eyrnYPBD$MIRD@M&+kFn0*!4AdL63~;Hic{YG)#_U-N zz53d-{@#Fg*YzsW0rlWaIgIpoGLIfK6WATpPCWnIhrb{(`_F*)kO06icW++XIv>7y zf_7XjN!q92yd$Bu4IdV0!a4B;9-)b=2*w_5i&~LZ>Q@_erIXWbbqi<7Yr%vU-OfjW zR%{1L*E4>rR$!RB|I^ywjj%3yhNp@JZ+NBkQ-oD;>=|TDH9liht8u*K5%zRAD)*1M zCo$JZE$|K}2WuP3mL8++53}ebs);Q*NTO_ zhLU!2Fa%cbJnVM_c?3qbL05Aka7;7-3cxG0N(>ijg@r#3!6DKvy>Y45zF2{pM zVTE88%53@`?bx>#KKr{tigLUrb+!X^0lSbt-cDDkb0Yc!BFb*k!1AClTjT@Q5}*ee z4@Rdt7nKKy8oG61?fPU-<$w)%8?jJMTnPVv&TJGY52RIt_98Jr+XGY|Dq|=Q(`Pw0Okx>r(<3(UPMu`i44(UV6-_k%dFEz6Vxpy;sNu(*lhc!L3FnBv0H`0xg+b`IH4brOlozzJ=o zcw;|s2YPQspK*7B0C>zEu&_S)0>s4mNE`a-i=v-jt9t|;&?ZdIfKW(sV*t4l#3Q6c zfmV&(YAAr-%dHmwGKlnYo|cr%EuAW?S;#IF$?ynF`0x%)CF=?M^A`|nP4}~6l-x(0Tl}56=tEk=b>;t6+%lLks;Y^CqZ~GmfO)n+p2K>63 zfbDV}zCM_e`r8(LVCXvM(R~ec0!RoN1R_%MaI2cpxg*-Wj?}@+5#P@7-NxtjgFZ_z zZ$L9kHnuLsGOO3`ch}||4Yb<5`!t(dLN&Z`RYj1da$*JYe!?W_L3Km6kZC?@oqjMNy z%*M!)(^!RoskwJdc(Lj0f9$}h)G)5J_n*GCgoXg!{U4EEZG5ZM@4I}YCVy_OyQ2#p zGTT$*G(KKIoEEv5{uTf9V2c|=XEUS6&RJV|i=O&@zFQE`MUm-Nztk7Bh?>>)JPPUvx)6CUEVZN|%hEOH z3DVg3Xic6kn2*o@!~7jpbqpE7_s(&JAL3V8aa>v&R_jiSUh{~+fxc;VUjb=Pl07IZ zT8?O|^+RgkPE*Cjey83?fGH$`!PqkA67IKN)K4w1KE-b3d@=vH1naV#eeBG&&;tW>75Z=v z&Q~vQ_!ONlw+x_GQDMV=UKZv51OU?*QS(uGsk^)8M@QA@ymjbu0SxS_t>JlQ^#{ zMa>^I>t2o9^M;e~H}xi3h`M8tu%%mUPRF{EcJ81cecXhtG(6i2zp7usxLMFbSqc>zUCEsLCmzifzT(Uto68Ptjr2!AzULf96caD8D?uLjwjy;>qj|tbFC5vG z<7AgZ_q<0WR4-tut_Y(*=~M06sNV}MwEn9RS1pfb(l2I}+wPJ9OanZj1O(!~>Y?iV zD8CeGRvz4{P?k))G-NjPZZ{mFNyu;yJ)*XS*yuLf+HGn5I$RsX7Cj&5#BawJV)T0z ziUn;1JwoWmwI>E}G$h?;wGW6L@5qC7FQ06RGzOkcrj&9Z=oj8DOv(6VBK!$IteD@~ zB(0yr%9zC3!fl^Uv$i3-DH%9H($W-vAUR|*u-^XOi)UZbW_4pi*KWoJX$OU~Ww%G! z0_}6ACr?w@Bv__Z$MUyC2vZv5Kib@DdtgLjLJ{CEiJYg|8S4}rxLbWDldav0MzcyEPYm(Ht9b{q*dezT( zoHTUGbg{S=XE)Czg?LzXIdm?!74q+6o!L8><%m`e#|WdWL_OT-NMRPX*@PPH@Sv%xm2@!(-o zNpvPQ3DR7#RgG^`762D$_u@S24Zvug#G*uN*GLXbdm6WqF80b2aShg5l})k-<{Z2f zQd)fzhMGd^?r{M3XH}MIh5{u6+eOKACmTp`?L)!_IAI-;KI)Q>U2(FAJoCKjn z9D53|yVFW}4)4gJssSauhDE^HXfq{WFt9dQLH$JGl;vcBO)E~VIDUv3ng4*$qTWf; zA4GtqIWu>}ibqbjiLFq$K%L;H&vTcwQ3WPCwc4K53B*CRUyW=ZLsNNwmAv zH;x?Sp~jJSL>@)NRlI zjH9hAwpJq+|HYTz#Z^n39bqDS ztM2G7F=(ydp1t12MHkCk0F|g~38P@dMui#lVVEko>Z5rtfCV$kkpNakY z!MNv61J%=Q)n_A->f+knkmJDifc_FCGnw=W9e-hkQnx!?-r#2`2fI^- z?5!WKl$5Gf>Cc^oj6Y~b9fyjkGn5@-Dj<(W@i1B6yy+a_;QnDQS6~+39hd{TI($T4 zeJlY)SmwX35^2ZGy0%YdFE_1e>@CFdZ-$3^R?xsL$HStejtI9@u?D?|#cQe!@_>Zp zS^3eHQxBvk*<4ntk!!d80@ZtyaGVP~Cy);6*z@|5DZha+7P^ILd=h#O=MfC`*Zb}r zdjVt#*;KGEU?*Sqpl14mVA6m;vlbqH=y_bwyYj zNLi=m0P@^1c3#Fhl>OT_*P~-!uzyyDqFt^w3lcuqXlV_pNJOi|$DzM=|*kui!%#_&tUXjj1RP`856 znwhz;wFis1JWMOQanHoS`Y2CA#R60|VuyBsCfD>$h`>V0GV^>>>(h&OJDZg6_AEKf z*h|U%@Qre~Go*F|eBhjYy~JS`dM$~(I9 zd;oaMEecdLRv*h5q&&M@WM|e$Tq~I-FanzzLucgn5T@QOz`j1mIN?_rvJhCdR-UlH zBVN;%(lm1ORDxDHI{C5{s+b(OG1r>bPKmgm#9m`4d0@7oXhd@i)*npm{H6t}NBfEz zJ-;WI-Nl1?6iHWzC=~OMx30&-LxwSHR8!m68;IT{pG0>`hEe|zpMRj#eiV+oc#JxS zjrqLzTqe%~3S8!%-&6=&mjJecPYOti^~WNIAVHUraW7ShP!Iq4#GH|M=+>1=$1uU! zq8Ci|q?g+6y4Amz&lFqQqC`75oW6N1E9}HfSF=Gy!S{t$u<=Hhm#-IJ-BRsMRk+BE z8`yIXZCXpr2QZcnXozcfjL4O^)tSi}BT+0%L`BtloNv2Q?NSJ$FBF_`9TrpS2&K%d zs`a3~xEDfagFLlml>w;1t5cyaCGDt|^WcaM2uYqZ*A$0XLcMO*A!N*|-$Xv<`M4Gp zAb(>pPDF!JMOEdY*N-%JejRku-p}dHDU412iICjlz~{VR(}ISRKPLc92I2Db_sR99 zz6IC&EnUe>9|FB8>BW0s?6(&^9=u`9Ba=l0gfF1;C&!)`DojJ)X4M7ZKGeG5VX$esHQ%h)75!iCb3w5sX#&3 z^(coma^7n=x7zq^WdKnkN6*y-$4sxv?=Wz|P`n{{C_BIXnv(0pE>mE4B~#r6BC$G^ zx?uVx>-yDFjjiNn^u|f!W=w;yW_pFMpoSaVTA2^S;T5aH zxg$JeH`5C9_#JZUKuFvZQ10#p7%&(S5Ndx=!^-&S@xlxUs9xt`C@kOEa@j0PO`jm@MFqmz5aofS~>};K>z7AUGa`(#IM0_6NyT&Ndn`Sox{XBgbO|9?Z{VNEK zoM*^mtzi8$C8^GhEsuGE=m*#?25`LEQ@tasg_rs1Be@!D{5VQ>Y+-QB*Fm2i2RU+!HUHao+r3y11aha&p*HkfD(> z&etT%oKea(AEcQsByCPHAY+jnFV4>}^dW9jcY|TDIu?z` zPTYMBQCSpN%l~n0(28@vhtqou{$&D8DdZY?AX9_;W&Z$a_Nny#=lT3JUI^DCHhnsH zkY$u(#GpoTA?l5do7xhio_6T&LK(GpcW>QVW2dGr?L zlKX*TmpDv+gVg6B6eYtPU%=2z0J&vfUlXyAre3w4@f>p!TQq%m{p-fs%ZD@eDIye9 z@p$|)g~b5ayenEwMiFHUG1TXv&`tb2-j80Pz{ArkIOVn1ux0Oxgf;$+@oV{*pw#Eu z4)czA>a3AZGnHR~q2s)beJ&DFAA5@lJxAIl)QH~3M9$Nqb1%b5iwcO2;M*x(a@z3) zPS@ZN*%?e{3ggRFs7xn4w#!J%9yl(vs|YI{Y2q`Z`?{_uzHHr54-}HG#|!$hO)M)dNoQb9bc+pr2?TfVkfxQkiGG&1FQlcGDK8HVoi$i|r*EeeBp?Ug zzsFbyh{)J#-+*T>O3=jRV&c%hZB8l@QN}auxj;l6zmP8i4pe36g7-_WTtTm409(nD z$b$vu@t9iZd?p&Ct7cd1P}02h>kHxW#>?*scZtH%^BH^dvddTTC!(2L7%*SY+bnMg zjd72-VY;^C8ZNOa|z(uW%>a$761TnvkGaV$7gD4=X=d=Gd_OTQn&k1t|4&3JyLP>yL^;vVs7 z!!uAF4}5QuUyETdea-CcQm4MYk8b%u|JkH{`zuHu$$AKrY{&P~wP? zZ``BkbU!cVlnaWmjvzu|uDR$)RFllYU;$0MG%W-r-+UuD`gMMSfx-3F<`+ zkOy)N092w1#1zkYW6LRv6H(fy<)LZQjGk`U?20&- zjubLYkG~5oO&BhG?7qT$`kzjY?mv8?HtT;Re9X3b$f&$N?_bkvA7J$_9=ylr*N$^O zo%1SAXG9&tHCs`_`<52OR>LahFP&tBtFW_LQx}}*0~KSS!0I_5tg?H>NzAkOUvRON zcp|Mqy~=@PbUmDe56r;8Ar833kSZU}ZJ45WWozGZXKg_ox1`Kk^+QkMh$!$^K3)10 z%-q-(PXZeHK#1KmI*m7%J(h^ui$!Ovbg4GIAfb6OlAeiUXm0Md-P^$s0~e!A>mPlJ z^K9hQtcDoqC9)7Ukm?oaTM9X~h+Mvw+QZ9Me*^GF-EwEtmQq1@lXp6${N|R~&ZkqW zG;PMUYIV%3Z9Y1-saF>=Ye1kPp33J#t8|U(!5h|ySIsOCv`;$UIMXxC?xymnAJ~^S znBGvqN&QKfCFL;KapwznNqiWkCl%+jb&u5NxwEs0qskh3Q!R~$D5ompAyRo=>uS06 z7KlC-2a!p<4Sb4HNb6Atqw~z|G$$E=b-9Dekk~UMN4kJ_-8o(E)9>rjq2%zsv0XsI zS37k9J6J!#5b%ggeXz@a3{lUezXEnR-zM&5V*_JEzkUbe}?}}yZx&vk;q+ck2(#$ z9~6XlGS9#;LQ#BsHrb`Nd|ioYw}N{evC}m%yc_R2z`^Sd-Cvas>>=T-Le`FhzGt%- zJZM7RT2{;9OL0VZ4#+d(NUv`mI45mv4>WM|Jw+pQ;7MyBfuiGOuYuV(%^sKCqrT7{ zl5%lR$E1WkY~VE7XW~9MVL=&YA&_I9*k=rU+`rwps@>3H@}57&rTE?1_$CfIY}2rWMFgf;#LEO z5aB~grq@&r6zY@({GdjaJA2R&@eAInB0#={BeN$A;U^#gPGH zCdT_zGIm7{Vm*cz9_*CC10kv)DxMMz}D(_iif8aa`+rR$j zYg0SMb`F1%LNYi7Q!Q)xHaO|5K)3&j(f=()+M_goQi(-s!PwB=W{@SC80&;JlX^hM zDqsL79^PT^sIb-Rs_~%&ZbHXdC7NOW;(@_4@3Rp|)>%)D`+V&B?qoxD`9^FNy3u|B zL-U1wTrt}oa${tbb1&wI7cakZNXnq9lh`diO79|&wSU&y$KUoWS5@zUoWVZR!s74L zThNyS`c5T0U7H1|i-+$*TX&WUgUO`eTztKPHmz`x)=a)-)|47Yn5kG~4kC*Gd+KMm zM)^=46z<;`m|cVS70|*mx;tQA)!y6@fS6}o9hQiCmBBumr<_1snvuz;;C*%wKt&sL zT8d(Qbh1S7s{T;j-*ru}*ac$bqCi&%|Kc^HjeW9;yc79m4Zo0{{UZW zyo%>7bq{tKS`4_+u#pCuJJS;?%d~XV-o1uId(H0yvfU&{ciE#iN=01tNL4rdmVeh_>6g`%62#KuQwpzjpKEm@c_U5_XQ!lU#t1grl~yR3I{pddIJ|S^t{teOb8F$QAUKZ%e9zspM5Tv4TB8OBJho7AQmx#>o(`f;}j4s5eWsd$`jr3{s@Xaq$PKrPOnqk}O9PNW711>n0jx_tX%mgyb7Lc8CfNogj^;zf!B&-ESi=W zJ+wzQLH-cDRG?QrT_O*mcTsz(?+>Usqkts8HBzk5!YnN{ckMCk2-^>4xwc&sN7dpx z4GyiB$kmQ}BPzDHwx-ABjbcnmKb*~ru>eV&7~+x4pxs^#BHUOt?)mK1Wzb>YPp}Fg z+6PEv3J!xcA;vvY&7wQ_`cyC} zu!soaby@M6(X03El5|U|I-H6yA=;6Wn2;IacE1Zo%hL)QiQC43oZXX+YHbCzbE4kW zs|Oo|a>#ekbcMOyx$k^~v`mFpk<`Uv_1(%)yGa>}bb?$arw)^qnVRP#&TGI@&$3hR zqfR%CQ%Dm5c>?_%;33R+klQE?fOkX@mcT_WS9A5OpR2%~ov!k9DU^!*r&`;be?9Uf z7DG^R=Zaa$OBc>T4Al@?Q@s@oYnQcgR&VEmMai)YtY;KYL!TMen3Jcgv|vf(h!HQjr0p{ad5;c)*_C!d?FZGI#BY=_~knHBR0Y>)ZK!<2Zx3te{) zv!r}=X+)-z2ZdFA)V=!dWnf&^XT(C7&W|Vew2^LFiy5dRc*;v#F)wiFpX$UQ1dela zlcjedWfNBd61rG(=zWH8Ao}I@e9=t$9H=3=DNy9*S{HIwl7f|7#NBp7N3t(Cdf^Sz zXf54(z%Ci^sxIP?=3ix_+lpi^rAqgO6%K?R9T=BAR{8e?_-3A3w}DWWNysBoL!ZCR zQ3w#7Tri67fqx8jR$WP$*1bV(XOUwMB82+r*yg{**jQn4Dj!=IcUTBMZt-B-%Y7^z zD-xV`4K`lN`2Wqm8s1zu3*Le!ew)1Qm)goip}T zqG~iWgnDlc#Q9LLtLKY&o?Qq;8)g~MyLd>9xny{Tz(4uK`o65}JJ=_$`7jN*_wT>D zQF%wasDH-4{AJQix@h*4?n@OoPih|T{*^Ng|Em^yu|E~Y) zs3*;!>+5;Lk~1-LnxpWLiI`H0V>vtRk4@S*p4qBC1^21Z2@@W+6YvRnp@3$n#GE6m z``U~%S&KI)G_2#0C-JPZck^vk!&PJt(Qv%!(?$s+zeejI&TjZ7TXMWKblg-s#b%5EMZ>5kOdK5Fi~-~hcs(M36>(}pH(snFEQRXfMi z8oo#ABlt&dyD9^Tu5SIi^S5aRO~m33%9b7Ycki%pOgxUK`Gd(V&$PK_IReyzy%+{2 z5C#pDGPd3s{IRP2a7wZ1BMI!)3I*~%f!(!yaD-P&y5*uRybsr_BVO6^QNL-bS^F6_ zVaz(gM2@z_@ORr6h-$PRhNC z;ldv+jNst<+~4P9rYtXsF<{w12Gze>gz@q&t_8U-Tv><#rQu=e7Squn5$eeKx z`_QusqkhfJA|X_9LU*;ln`(5SXX+XX-dKWXq;<&OZqUoSv(^{kD!3!AY%k599amM? zEosAkLZyPET|Sto^?KB(XlFmtdUaRAb9GgrC-ywynPNl!G|Nx9UkG)ejuqPgpEnD) zo)K!q@e^9$gM#H7m3@$@MkX9QCcb8xlf!)&hJiM2HOoW3!VWleR$^Oxn|L{I;SgR| zxy7wq=9H(9wD^sa0tcK(n(f;Gm4)Qky`?m{iDm`96@l}CsVnLyr88QiMsQB9VeO5~ zD9}BSXH@uuqMkFJ8!{lQg|4mN&f6Wj4w%*3+n-Q9ho_=ja7XQ3&%Q2%SFfB}?KK~L zqDY5Ns2zbUR~n;zv)EjzmWHcE`uo};3`l8|55eaa`=G;Ew`rp8`YYHp5GJYOl@rpR zJ9Zsp&?~u$)!vX!E-HIGRO%LqZDBE}50|X;ZqMeWA0KkC4jcw%W!7#!JxUvO&Z29R zcF1)^ef+zGX?Wgb-ziIfs_jE8C*qLk6ER#7u302yk@#1e@`=&3lpyBEY_tN3xVpx7 zLcexDezVVeb=T}SF@fgfY7m_2Uws?`!`C=JW-b@4#K2hVI3tke%)2T$jvGdbq?sfa zn8D4^bGoe>cAm`ltI=N7od6Bo!7*TgA~kUcNU|l3h_a402`Ma_!imSbwUo@#6a0mz zYS$yuD!mF7$~hlBFjWl!S4vC^xCc|sjfu~4xnla$m)P-Yo+||Pkm20=v;-c}K+pGeIy`O)h$g))U3MW76;F#;}PCs;pY%s^l4i zbP)>p$&1RXjs|uqo&-Cn>x2N^*$iK~k=2Wcc5gEmumQ zM^%@7?Fo`hkw$t0u5fSRlcc`gL4{SlIZpBcIL#>VH`%*0K$O%g#Yfh>#cLf@S|ez| z)WY#ZHM`!3>!$nkQ$a6~k*=Jff+;?E<%vduR~hG| z5^EM`K*$iZa|lJ7C!_=@>Q(>I33Jc2oe3-~#tQJ&I;UOD%p|5Fk6r4_3UD)O$y>=-gKbd4_a{OBLL3WvkoD7amAxZ08((}UQYP1iA z*ZRIamvt(8Er(0a?Ybu`c6s!o5y`8-zf&7Jidoa_6uRYqCTOhXIg8W>SB z1-+=pQ7W>7v2hd=a+h`Wmw!7OkZ-zbtOY2b{DLb$yriEel+d1O`$-VIb&-aMQ(dx6 zi`=`mw0}%xpTqbl*HK%II8lt6B!YMTzlhm+N75*lrD6=7r7G8Is#Z5|^2!>ph*lplL z*NXk?$Bn5TMT^${?r;4jJ&fsLV16J9be2Z*JU&nm+klBSk7y;KfDT!;Vyxe12(T$* z<~7WKmER+)ga|&;fX91}e)Lk&=9{)BO`7WqXf(395~GdAPsGj z#Jbs1R1WV$__sxPknY6~h7F2EINCvG+Mx3xDoR)HUkI5R5Uig%wIBku!Bq8}>FmfLGUO+rBOkbsI(^-IYjN`#WV`zHTXw-!NJLH6L?YYO18=#cg|f<%u%jy zJ!sovt_ont5p^Rh{JAzg!COwxT!t8naXy*rgp$Q->Xy%FdBH0G(5k!3p_>ZbODA)M zX}615GLSH65U(8G+^i{T`J*g>gv-3sOEwijv})b|87rr`^@c5u%DFfjdy@XM(Mw)S z;Qp1xxyM*hr6I~Jx=$d+>$An^Fv1yoLIz%}v?1^I4``@>;JwbTQS zBlQToK`!D&!-(l%01r(GQY00m*lHkuOItQvSrjhNc?^Lq)!tK;fV-!Y3ZAW*HOn99n%$(nHsgfzf|A}QOt$xkw=EAv&U*HPVmOaL z>@O^DC7o+h7ez-U$>YCNpNctgDgy67tuf0r!phAHI8^n$WnxsvG?8}F6Ho2)0~%A;$b&BNYqcn;99#t!0` zZ!CE%Dejqt&YGQ4i;1h8NOL-;teP~nE|zcUBXebkvJJbgWvBR& z7mX77zYP$ceah9|m@L;EP0dMuVuMFO>2Yk=mZ>13ypL2`__X|_ZQ3;1pDiO1| z47#>4MdDTiwQUDtcZ)dr52}3L8>a4KO@Z)P5D!NAQ_UC@1(=o2Ss2N!hcEEE`e*?4 z{Dq7Oi;GHlm~s&O4rhPU0WZ$qIK9YFSSoPL{bn4#-fx^X1ELvJL8PQt z*3iegLqMRe<(K9y8EG(nXSRQ?y`7L(2v6l?>Rp9*zSSC$qRod1PaRD%9E}Rx1CyKU z<}yC|dkGpSZrN^#P-)1*BU9T}KlQArvV2v-A3bxF;JCy49sV}!3P{xy?$*kRQ|XWT z5{YP0>|xVa4{OyQx`<)EUak834mI^M(Meb&VXwhzKujG<-i^NMxpU6lOuR`_IQE_T zz;7W?p%Ok)(ch+6^S>V7DoDEgt+a+hwZd+)vsII*w+mQh48I)_=p0wySS%7vVPjA?1o*Km zANwA}F@xRbptAH!x{C3~Siv z^iR+2i5KHj9CuKz=Msx|UiSDj*ocL9*6Eh^WYjXtf3~@@Th-7G$kC=6&vR){zw2gs8SAbt2cFN(iEO1#~ufE7@w>Blk2zo z?Np*6@0_1?tbofsP`WAwy=G^1EMcheQT=|v`q<4y!jM`!`>=|Q*~2xFzZ-h>jFhw=;eb4E8ZtQ_@u2QAWUFAS>ixQ2g} zj+=`%5RHa{epNrdV!WWDEkns;2^0wjg|hoVV+e+7(IsKP>5_qVC~20s0_&j|x(K6~ z7mAKlwBkZzGCG|)Z^l5N25A#^%;|w3&SlwjX5xKs?7G;OUQoREi+CWJl8t&;xi5P| z>K5ciQ39Q`dP2wIf3Q^ujA}}|xS-Q6GV_}Sn-zSe>gDZM1G1XiCPVj`>M%RHtGd0-c}hn0!ccr<*wX{YP8gJ_Rqb6Gmr0 z5I;k*L_mahCr{eT5iD6;J$hLG+I-9iGhLxc|IO~cZHWKw&mm^W z{39mkQr3-t;qO=QgiRoY%h+eC)z6XRT?2*|K?tLcs3A?r??5G%NrgaAc%$)d$d*K* z4QI0o4{BWkJL0T&WF8J6@CfCvLJKaE9^xe7OjYMBtya7)`LLLQT`!R@wwtem(>rLW zKvl0loy++FzgW*74x031by#ySdv40I9tFa#__t%=sG{sykb@401NAO9!{lo%)nDsH zag_)}S|Db5rr?{V<08$+2SX=t^We>3Hfc^e0%ul_T=yCbebGP5Eg?IWAc#5EsBgU6 zgB6B#QhkRMa8uW_QJ7nR#Np$f8nTNp#W!vEB(E$!fl2}jZNh=0sh;H!2eAKa+)~&+ zfAT;1!5^ijH-#kclGm+IUWhlOwU&Q9v9i^596)NciV-$!kMhB@Dfc-`#nLbEmA|35 zumdN}-rW#L%VqUr%4j9H{d~W5B=;376rB_t9;1Vzoc<*&T^e__I6W5T=H#QBbfM=@ z{Cn68{Z4j;rHqh}++msxgd5e5qm+MUni*tVToZe}KF8pL%s z;%6U|&oJ?u#(oSce7aF$;NU}GeA7HWmUn+kS;HudzZza;DgYbPfUWZPE0PM>%1Juy zlMOr#Q2-4}ufLm^SfjD^H`QmZYnd35<_#fA?vpYVNK`<%bAu)csk}nF<(Dnb{3fG1 zmymb-(G2rB2WiuixuG%7LT=jTccwUSUm=?JATI?(Pe%3<(VT)W)ZVS`wRH%fOVFrG z_KR@BXnC~P;*vO;a&N;w3|n-Fo&JoW5JdyyEv#`q%?>)nthrQOwwd-S|2DWo+bJ== zL_q^4o_smxbz|?tc7V8um&vHCi$=(9y9ya;7h*Qz0Yam;76T1t2XgQOH9h+rofZyg z-(m-WqX56~EoaV{m5!-Jdq0yms{FVIymB6VVSTV7U>`j960Ns`Rm9UxpOGq~5rk2u z)l&pMt}a%_M;+kh22bJNQNp1=XjBo2WIga(VQ%P9e#%MI^v@U#sq_4M=y`@KL720o z1%d3m7A563@0}1S>}%1eC$Xp8w>FRxa|(> zPczM4$)9t`eD{>##$WOse54Ly>PR1BQ80uyubSqVl*p}wZCOMoO+oP=#AA%uN#v`P zD^Z<#_|zd=O1*kN<9>6WLPiGh<9}Wxp=r>h+XaE?IRekR)6?=vBC~POwQwwe;bl=uJQMySi3pr#@`!&?R`ixaZ^;*tcmU{npawj z0F_$XUY z{E_jZc{o?5$9xk0MWg1p{0n-^W#4D_TKzW}SP&rXQWdB>MA%Cp9sK%wn@l)$|C_MU?QiL%odu z5ijv&*#@*bjR!JPw;VHusRti(egK0yA$DFAc-(SXLY3?Xq%0mh z5(F0=w=8D{{vqm-j=0+jh>R)-c1+!>)wfFP&D9ZRzVPMM`EfB@dHBHe z4bgdp z(lOKuzo99Ao>10LIO9L1Q1({-~Mehih^=wbWiPX)X^aQDx z)?AOCp0Hd?FU@Hv_0m;;E-f~yfl37;>@MH_x6*0kAqGLo_do7@BQMDo6na$B9&5(> zT>AKn`h#@qnziwpkllj2=*rwwquhJ^KfHaZg?Zb7jKm`{tv}yy0i@(hvs)+KUviz4JI`1uV-_o$3jZ6*oysvF&kua3wEkmL*zf{ELi zALTOwgbFDx3Y)p3Qvv(uk9*tr?i)_u{PXTyH1No~l8U+9V z;^P^gR!WePAM}(!n3D4#C^QiO?*W1D=Nk)w??;~RUwvc@lL6R7u_O+B!(gO)QMx66 z_qYLjhY5(|%uSW=NQ9_>L!a0e!T)Ic(?CoRy`U7{m~z3hh`65Z>?eN4fE7l$H;-nb zOFx?-twyJ`@$`!*_EXG(&!>Wvr{H^NnFBSZxBm^@F?u_f1@XMTzP23ICHYNt6^M2F zjVMB96bF1t!(3HlTC^~1z)GBd!O1~#*y0BA5=L8@o*4A_9PMk$wIJ41@m@ z>4?Gb=dR9hOM+CF2AuDx1$D3ksA8tW!e_aYJ(B1DcZ;B$&~wkT|3QFt z@U&9L3W6nE^C{}P|BZyiD*nQEK0&mq-m<+X{NE7B7DLScfImvb+`|}#mk`0z=og-y zgsh^K{$6*V#1a{C2Su((H^cFh)ALAcUnaG0xc*h&=k1b!4yXiJI#A>A$jWNwWU#f9 zUa2(*{q_@Plw~-gM#SH@LK`529KqFPt^Q} z5XJ-OX%k$n5+2wB9RNTV1k3>e0P4y=GeGUY|1E$I9FGS8Ae{Lf5Cwya!w2Ah;#v7( z_wj5Bbb2T%Rk!VyF$+MW5 z`Ss>AD!d5{Ru^As6&Mqoct(^6b0jXB6d}VWLe5dK{ptn^KmpqnFw$Q zX4K1+k`Zf)wBa{^A|dKP05Kp8AeeLmBnS?GcbNDt3Nan+qkZY5iiAw2g%zGm_zPYgimW=9M#g zc3e-CGJ+h~ADJ0`WTU|2R9rkoLT+q9@H1NeD}pO2&`Z53vZsTqN<)3fwmPwbURaUj zy9dOj>SGY(8wvaFq48|8c#b*y7h2E!99D1qF`aVpR8{slsq`~$n3?FsiVz<4pyGIE zKqMTRs&%Z@9(n8)(B=ZfQuK1tDf7={tlA1$jyZ_%7oy9Yiwrol7GXNz_sVH+$nro4 z7`bg#?6IM+mXIR0bsOb>WOmKaejkzg)Ce;OwqKoEtSwleV#Mz1m*!i9hnKlUl* zO;i?871y_12?wHIx4%A!nH|*+<3hFXj-_iE2m9qg?;rHR4K??B&ix+5o=EAS;&A}F zR*12wslDcxp_k%ZY^eo$+m}_|&4BFozw`yi;~vlZ5aam{ufexzsXe~5{^rg_^RS0G z(fRp>-hNmRB9j~gxmujecL;@q5Cv*_JFv9`SqWgUQ?vB>e&?|~lEMd_>Gpnw^ytFF znok=Vrd;uNwhB+vXsmo>`E?Quh$dVMI(JyGB_K`P2d@LP%`icz1*+LEvFFqFDMIK{ zGGlGmg5?3ei)|~ zs?_;E6oxTCYU1l|PocGF3i#=Q|8%|a4XnNocZ2R;2ywOJ35$dh0s$ufk2y#`k__VT zvkm~HrvI8*diT&z(fY1s-_JLoS~^}A*6AqKCH-&ek7LYjJ_ z%PfDQ8E2lhDa+-N;~y?$LvG(*iZD`Umz0iy3QvY9_<*U)K*@$Bf~zHohK){ZaNXP8^E1s7m8y^kZGGu zPBBtJ3WGY{uz$Ttb-t9jqT){N!2XAfq4VY5$atc!Rk3VA7)~3iEFKruA4q_gAMslx zqA|2pw9^J}&Nyo7c!1C{(m`%y_WFB(nklfh$K+%Ww;T?0cMu5t`ixg-qPU60hSu8D zX~MrVDIW0R#{;eu8Ro*`q{$6Ow7E&?P5{&^b1D&2NW_0U_+d%I3pGuM86q>|PZ!!i zMKS+{652MN(Ew@Uaj){H$bxWv;15IopK@UX2mB;5VmjGGYE?MY7_`_obext|Id7eXK=&;G*b#HvR zO%-E-Fqiu;=`+y%@=T}#C9ycqysVPI&f~ANAf$Af0O0PW5&}70{|3w>1g!T*IsuIo zkogA_YA3Sa_=Z^aIOIH71Zni2517qyu~O{r8qp5LD8s5Ro{s)=d>D>Gjpzt9dT2Y= zpz!)B?3kD${sD>TxZ!nvTWk3b?3_S51ewpa8nsP&wW=k<8LMOTPT=PijJB9)Z?1#f zT>sB0iH#=MQp0%W{>(atW&;qc$j@&WXov{P&p>r^Dirdk!2B6B5}nqUcxw&YDh$XA zrv8#|#B_g{sNNz#b}Z6BrAMk@jQ?S4fvLsA?(GM(*8>n{rdQ6U9g{hnN$Iw8hP@oB zw(aCws_jkE>bxUhIGBMPEWj#BTE0<7%DOnNP>Z>7eZ{laeWwa|RCD-ATTo3d<80&` z1JHVau;Ai`LXlv&g08#%s(1ot@7s;G3=cAg<{uMxpbxcMd%t+{Im$Ts@q7aa|H|Y9 z9q6LT<=f~cx5fno0C9N)4PAm#>%E7|4Ps?SdE_)U!|(=}U!vZ5M_BpoN?PO6uIa(! zwBp_g$Walhk_dako7$jXsPMXU@reh(5xeldlsEqyf?HaWv%rnNo|cXBJEHfbRqsb5AmNF<3Y7GRG{h!GG|60WBKSAB*>e>AR8=5tKtM%|= zq^^$VFVDK32enB^>?cmBdU=Qw1@V)`3C$;n;Lz#nvC?T?E$({q@&O--o}X|xrYA~2 zWfEY{yYK~Bq*!Lg2e+P#Qb@mmn6+MBlTHhILX2I_Jo1jogtfHGqmuD5UOvaj@gyp{ z+Qi7)DUUXcV$6Xe?P{~MRa#k|UzyAA<<~wM+FuI)$CIzOWCr4NA_)ySecBRsXUnkR zSE<&s9f(oeVf%>DZkhEIfPn)&EKb`CyA0K0A~K3lPF&}f`?)@_=o@l^f%Uwv>Q{f} zKWW_<6FJ|MKf0b-s4oO=IGYK;PXq?y*ThAxi1mUn2ZVJu=7J5Ne&h@hk0dz*T`${?nd3$;YH0R@6!_!KL<(p~)c6@lRiv)0=19!{W2K zXWt)|-xsh>B$;nDoID0HiIbHK{~mt#lDSpESD|vEwFgR8)G6M&K`2C*xU=(YZ1AEK z0r|%0_;Hd>WXru@a&SED; z+O|@vnl;c`!6^*|pZz_P3yjKUuH_RCFBHYUU65MLFi6*jy`N_w^Y7)Q>8tqZY8rC7 zJNj{5Jz}XbIk?y+Vt2wvRKB_97e5lN7U9uYGu$c`)JYwF)Xm;jR3l>s^Eh$w1xTW- zxhUtIQR)PamWdyk2m%ycgz)&7go|%>J^j zj$qf@4Igq4HuB|BRZ*ZFO3bX}U1#F{_^x|W_; zu0hz60P8UCs&K}~glnu>)BGmRikN?BjQr;}J_Jg1crcPAN2~_rIwG0L$as^B|Klr+ zDIL{4Y-aE-AJBi69@>-vI3%XTfm$A5O7}~vb@r%8NFfk#_J0!b^C*Kk$SwX)An<+! z0u=&sbIdsr0o!(*`92YwTq`U=Mivou0d=dmVXO+MqISSo`)IgGdE0gQZ^<5J!FYR* zK*fo%3v0`2$PI-D6~~cXF#D6^rHn>MrlaZMSJ4)?cWRTKX)BIkRbvPI?WMHTml9WV zQ;80^f)Pedi%4@TRmykLmgpvFMV=@>9R>Dk!vvz~Xg03L`-ebaR2#lNtrtcOP!E6T z7UeUOBfHVH^VV^9<=_+B(xKBhBfANHyQ0w^WtlFX=|Q%xE)+U#H|^`I;!J~7tFUdK;HlPD;_N4MPc zZQ6dDqi#F|w9hku6R|Gyn_{3>aGT`u{QdH=^S2K|sX6 z$&n@mfZ}4Qr`8gOe6Y#mKlBG$$b3`Dh6;+x7%tLN6o*rJQmULst^iLJ3nHA7qe;xM z!CMcb@6RFu*h)yLH#yFt7{uB=NC<#-(Gl`IQNz5~-bWXigX=?`#BR$FjkB`iF!>U!-<6NL|6#-kZ&O)(HDLX+GDaf8GC>=6 zG{gY{X}qKm(kv)QSvb_r%aAJTGFwB~5z<493pP1mTo!>5d+A~z$Z=#Yje@@14?#%QmA00u%4e1h_jAE7 zY2;h!sd zp!fu7*je$CyPe>8JztK!P&K?8dFZaShKG^q$iJ9m7xBq|adzMAEBwz{2#W0jrlgkFC}Mu$mu>l;aM@ zhuve@d8kxwxSDjb1{K=d1`qqXrj}WI$PUma+{Qld>6dr$z!Oh}KuIZe?ade$GuFyq zk*6UJgmsGF2Biwp0<%Me_rOh8-=fJ+Jh%ehJZ#&4Er>6UCmYZ&W?%X{dD&x+@Cwt! zmC$i|JG|<>F@Gu>GlQDJeD^5Rsp>o!+IsFD&yoW4H5Txott{~%--yutS-Z_Gpd_#Q zBtW(QHk#T5OiFy2$=PdLCSevp4pH!+zRot>dj3Eg@LW zDnk1)25{d`Cl4I~fd5h;O`isU*C6oZ$khgGIl8G}WrpJWU)0d-!bD;6Aw2-ILu|fm z_b=)2BQO4IG@ok=g;PL4hJUCR)^Qm8a^AQ<6k(>%t5KQLEc%GjqA>^0-iZ~Je7XpY zS)yN^{|41rxv&Y891VJBGGp#^28o}_)gD-%xMCa z4djmBFgbf>dwOw<)7RFt5Xo+XgWV5zX$S$}?}64AK!f`5pMkz0Y`K?UZJ}rw2&f3& zSPwYe0cJ30$6;ac8~_BL;WR_8t#5I@a<>G$r(g!DX#P)V1dW%JvMP$fRYZ<&KgyI? zXx@0f)!-#>Pg-*`i&qXUy$`G8RU7Wo$+dOIjOz)O&Tz!2H~^Go7x3ZEvX3Gff2tN} z*+;~$>ivMVrY3ea(>)km?2e0=j=LzfEyDM{uT30lv>vb8;YtBf`ab?*v5wf?BjA8X z$y$1S(N8!zW5E6Q$H##DjAsm2p!+uiO?ATlF#6H94kJBR#4-I#5aj0R!L0LX0#3}A zHM4js$9DnC;=?_ng*@urKV(tn@A(%^wN!Br*%7Ai+2=3@2BtZ_AcrJw!f%Hg7?{}* zkVwwYrbi>o_Xt-^oWG_oX&*tUt7w{XlJC!3ERshNvM?6e=9dwF+10-Ep85K_-*P^b zsT5B|Gi;rtwMlMTZ2!cXsctpBR!%}mKWqW*Y&-eTm`W%6wNo{nfmlT@5H4Di^3|+d z`8@u>gfe%TI*{sc{vCc3Z?HaOnZlb<^+TUH7xbusYmxp>V~eOrz4jQ+X};v|ADSm> zch#yrbWD!Iwyl_bac?=S)QAd8#U_<$3;-%|ixYiJ%6JAn`F_bk+lQh`eV&7IybRS& zX}0iTJ7}8FHcG7Cn4Sx}@s5O84@Kp1XmtRug#avsaloXiot!S(+%_S3oBQJDfWpsp zKN3`fu>ItR!;p}cErE?24Q~}I43bUj?rm*tP>AsPc; z<}e|6x<;s#p=~?mkMmvO^1$Z@(+JlmL(G>rC^oc=gUJLUv?S;pd>O^a<4fl6f?Fs0 zM2zveZ?4|bmcE?LWM9EyHCRWMKtPATjp=_P4M4HsG$YWZ9!-yFbhR(nt^!|@A79w* zXxqy>`rl^5a7_a3l?lFH zsN;3^6+t5IW@xDNM*^MA2>Wqkqr?^^rQXM8sEcd$g^3$2D4Vcsa4x$B7eAuWKKrzV zfaKtLt|aXq(w9z=Kbo2j!2EI2~!y7{-^B(Z% zKSRTtO42*KsjuLy;u8oM_qYCo1AiFD7p#CkGl9)uJ$tppJ<;T1J;th7+Zy$|LDB4% ztlN{T68=3o1-v7^h*b7=M7+t~M!tZaW;zd5()*b=haBakv%G#@5R%MFNGQB=S#>y= z`rA;oHBc8{F6p9tAGS;GA!Vvmi{p8YP3wbqUo-ecbWCW-+N!9|SDwtsQm-4d^#ds9 z5cTOV)JxWLyPV8Mimf&KLCHVYTlZ-Qx9oIC*gZW|S5dQT~XuR)E2GTf&v2=5-I7;4lf47=fwo`@U= zxf;QuLo~cGDk#G%>E?^t1b>7xyrbVNS!5>z3*B73j?%|VF@^@Pst(S+7m6r=fc5|T zWCIDoCmZ0fsVa07QPUqojBg+j*S3E|F&C1~z6& zJaIH0Sz*04)~)3U8%?1|Ss zgN7g#7^zf_PZ>CzG20EG{QkT(>ynVO^H!JGs2-Mg4v)%XbR>>2n^yun9_5&qjw{+} zc7(TsOJ6gYS~(m&%U6$G&UIXI*0fc<3e(jpi^dkVi#<^4U2(*@aH?VT-(38DYhr!! z@a_?ksiX{FN{=RaUPZ8>)VVp9A7pM#9K;wfj&*s3T=J{92!m;f!_8EI6D z>`S`YXj7ObAsM?s@MXzKt0m<8cEJPqB8ov^OriFGg$}?pyiq9x^#+mQd#;r~RGI*O zy!&$*&In>l+$eM~53F5e7)qirOAEq|UeU{bw4X@T2x zRboB{yYK`@NA3K`Y z2kKCf8`Hx<#!*&mH03AS==Y%3yCQ(p+(vk5f)I&J*F&t$gf(hmPe(XlhCz2WGt@2(X_%;CAU(LA+dSO96RHy8AYi&-Mlb4khSo8YQbEJ5no04gEofY zO-FJg$S4#!*+Xlde-8;i4}A6C3h8QhqtU6c04NmK072mVZPdWNBc@Y_&0&^!LpM7y zORNd--0s_-{{=Z>c)N96ud$xBu*hU`HW7X*h6O^8EP`{2jkV@r!+WomOBZjK&cbm% z^_f#pV0048xZ$J9vKuf&fncFJ5B7ut58~~;KT0Lg7*~;-R^)dNZ}nV<$pzn4Vel5a z=S`ep<45yKAMA>Yt+ze7%5L~s_20UpPYTsJ4H&pFI^(sw1Fj`&3 zXiP4jHg1a(=iE@P59*=_GRt3r#@&+;Z{~UbbI_ocIl?koo`Cc%T!y@R?lJ^A$k3_k zvyg38mR5*W)Ezo$A}NoU^idoiq&K7MYqT(RchqCF!~t9t(UWoB?|7Z{9y>E&(GjN?I|r7<`w@Q_49+ zFIYGl=P|<-ma;Egj!X?LUodYYlh@B}PM>NnM{Igdw=m-ox4m&Psmb~UpbA|d_$geS zV?Qkq!yk81-%h~W;6zMI;FYq9@Mju@0(3l|$qNQ&jrh9)&BmspGWpHPw(ok}7h6w# zaW}Y+&XG0qPvVF7Q1>sIj0O$k>1e{tq{2BjU4wS_E?A9Da;v8UOezVv0cre*!1MRVtV;0Q|`v4Z`hF5n^B3=x;B3BnP zsnW1+H779!NM$jR7d41PtG687q2QkS32BoMsnVGyS%9g59=F;u_|4DrLQDp{$Jbao z=r|+opEuE>y3Rj2b~pbx7Szbamdv|iCE8Hl`r1Y-=LS5|>V*nYI(l{6cwyfso1gCZ zd=K>ZQ{xY`%IWyT&Up*n%JftfVI)3M{p+R74}UmcHJfW{m&?Cv30@lA@*=KAO!}mc zs3CVY{RUenr;lqHZ9~7;65%m8uPxYY4)Hhf)$wm#%03qjIvb7pMbXj8$@bu<#Qyif zw&`p`-zWg!#~EizmtF~6bVl*Sg-^69XBXFs2cwtjJa`qCnwjJ%B0S{e2^KS!LRWiL zgHr5tNswrkb<*y-Ny&9l2PIGKK!fkjWRh$__^QrrOkv0LtD5KswKm9S(W|crX&XvD zJ_%$cm4?_L=DC5aGAsy;oRv<)F+&5L{UX{T*ET^+J`2TI*ftozY>z@V4!A1;01!5+ zD6^NH+a2TSXI6)h-M(M*rf9a@J zqJ+cm&P&)pH;X@x6SCobdCL*ch4;Qj-Xy@x#T(h>HE)d_^6hJJkS!}lK%s~O2!iV$ zUWax>o9qFv1A=2xMx6FI;^De4tY<&<&)m)g5e1KFBU?UN1J_|Cfxo=#CfGj@Bqcs} zb<>Q|s`=G5p5k84^c6xoVAfVUe;@0~UwK}hFVic>uUhI5*$i+K8W`Y{r(h@vbeIpl zMEn#ftQ}C_dKBx8X9M;V#!xFoM&IbjEbTJC*;fM;fb4E3zk$A?)(-lUP;#&!H2b`T%uQ7$XXO3^>u_W_{7EijmsY~KL-j< z$3|YRQ+$y!3Up3(KAMc%u%ANRJHpbKilx%6i;{%V4P>8BJ}|V2V+gjUbj$N#OX>}R(EdLTl{6S{q)phZdfq^dutz4+ zi{ERyubtgPT@xKv8X=TDot`_IpOy48w$ntF9-DTzprx6u zK0-M;V@;D_%v5P_p?*_#-G0jQaE@)PA|@b;xQWARKCB7<2wT_r5MDUfflO}D1;p$2 z3k>*w10QThl~lhM6^gKeAiV!M?tgi+fHyGskO~JM(Lc>k#!Mg#&h4W4($S3T;PChk zTFjU)H=X9u>DhHAi!y|G#(of{c)Q9>F-?D`p|8_bgq^HO(Z6`$wqx!mPaRcrYf*|j zw#8ed35CULn(>3ff#4nuH>Nn~d4!0?QvO>s&Xap1w0*3yrm&Z|JM~XArge7=_3q@e zn~Xd~#_Kf{=asy5$Q-)%2pxU`+zu%JJzf{`2~J68!ml*t6RqFadmy3a&6e~ES(2Ng zD=o#cV7%p3Z1ol}lntSO@OUUr!Le!=A3`so2NTUR*zJDoMj}Xkh2$uni3t!?cTcET zx|R&K4`CI}8*z?T?D>_leIRM{FE`}BA6U}EMzHI_2!hB2V+KxJp@UryIRAM_y7hoR zKtryAfrFn3c5PgR!sBJW0G{Aj#dq@G6D_hLnz%edaoOT{2oc>LQjmJj*3~ClaWwdV zemJV}8YX!lN?^J|pAjlE_6JSXP#avHfOygQA!yPxWYe}00m?==x3N>MN>9 zY?jaXm1>I^bw=cea)R2M8Z|GZoLklOQ^xz5pdg|97a!*-c2e9~UI_LwAE5q$E^+`i zYO6(!-3bC8-LBlb8m8qsh^M2^bXyGwO8zetF;*wvcBUXjH~Y^?Pp!J!q50{u*#gPr z!Ia_spoaMvUNkX;SUM>Xg_ZI{Fs@U#)d8}Iv5>S~iNbPo6tQ29Dz;?nzb;zXN~lB4tL_Otv&t#MWuH7|Z`*Mvr9izMeeJIv zJ@Aaw0#IlQaK;)`X~-)IUwKWlq>B+lX^3wrg>j7IPIoL#?09*MSq$`(LKqn!Z(C6z z)obhZ!KZ#VaislO!2SSGOf@6tD4jx1W8vKqw;#& zqy!hC8=SIRAmYv|DC6enFz)m-!adDuS1GhdEcszpF-*+9;kBUmoH8+enj>5p)Gy{% z&*U4PH}2mT{R2wPxJ+z_7g^#WLQ`q?v#fICm-7TbITnn2Fd>Y~6Lz3Ggd?i$G@5>V z|G=>561z}5PeR`Npxx{MQPMN&j6**f8TCa$Om1e&^*cyb#i}WVf?fn#`*L%0YTfr| zodWjLSa%?w;ssSmb-MG5H`8dnxC_ZC97<@w1K&3k@}eZ1y)88E2HEXH^*V(gI(9HK z(@NY>VMapu`0yf*cVF4l0+zpme}R|YM6mvavSaakXR`0x&rG#u0x0^ESp$EmO`Rwo z(eTA6rCMa}?9?ECZhKBy@7ZBOb9f445yo43b?Tt=;`}Zv+O@d;432XuigmRD{?Be4 zvjgg^38c;Q5ItX8$X=($CQN*EVYQmg6AyRVG0n440yXkGjbJBgAdswC+dRp9{h2rH zzUEe`pcnVvn|}FL+ukd%2=vG#B2wXMIC!Jv=jWV(TX0Och#RNR)w}*pjP}2_H+)MC1NIFdL-&Iye0PW zc3G`)qW>s3hLN*A=j7a6G90@8DbY1I{N$gjh=#XZ@hbls zy0@wp9{`2Iogj#Be{t-eu0F6!@gV$XS?C{@)vV;~5f1no+SPpAsNHIA`Sxm&W#?xq zDl=foM?5U-)`HL#-D1{;OeQ1mbtoo`Vwj#yegp&;f(b*zWN7n! zk)1UFyp=y}rx>*OXIK9o{t0$F@V@N@6biS2AlCoh|9>(bfDohhef1)?*+Jr(`PK{Hx%(8@#e5q$?i>l|ydn{pZ;cY;MOmJOLL40gRg{GBljVfac>R$AaRGeL? z%XvVe0Qbu#^vjItu6Qp2Ue;jAu=+TbD)y%VBDP9B3H5F-T{b`QOoORt^lkj1n`kcg zA82=GQ5DUEs_WczV|$MB|6|904^@h1{zU4ehe-n9y$^vP-u~MAKYeI`B*SSrou&vG zY)JvD$WCv3{y0KvO+Syc^Yqf{EpW= zZo~Bk-o#}Ti+9zp5%t+Ded^B=Z5I?WUI~~hWhZRxYQ&nmnuR-u-4F zt;`I;kdJaAr7piNaEV?SAVsNI=syZ$)*ce&=;i!b3xgR)?pmG?zf?X!+X1z#kmbdj)mZB= zy7sO63xjw7(bmsj^1441`<=gb(Lixv;Dom`BX?pB-~`PbcDq{XOXTU^efE@XX2N5( z(Y=`*Y&ykWr|sA3B1H==A9-Uf!9%DjFqwVSu5n%LVdbnJU08(r7$OT9!nwX|bj5mn zOq9LT{2Q73S1`T*J<~o?oQ)aXT1U<;=QDNtz+BbqO~!N{>2k!l!LF?PBLqKmvJ>)^ zC!ts_dK@YhWM!XXoB#L3J|ksAs@UprTPncARU;I-31lTw1&!L3*A%YyhSVp%tefxY zoFt!M4|`quTw)wm&>!0AHN7?G>!8i1J7;i~Da2kEZ$S<@ zS5U{C_dI^q+p()seKm~Ii$q(TDE8`2sM8=Z;j8-oS@_^xOTqLxxsOt<=(0^DRv)PbO5F(EU1{&Dux`| z(k~1yzw!YjJ{_|x&VZEJrQvTp@l&bS4;ja`qywo$Y^`*oXRgh*GFwy0TpN=h>)q%8 z3eG#3pFB0FMg;hQE%Oj@i7XBq>30W(gz}BLScrgq97zyi>1&pj5lkjx%*WcLbO&ty zw4>*&r(kuMFUKL%NRy;`KN=z_tijLKQJM%n4>s_4q1o}>n<8dfOP=W}^qam{7f|@7 zTK~R%9Ofq73HL3!gpP#voS8K4V;wjcXk~F#2r!Sl!bR8@bEO_2D;d$_T_!%p@nKFl zpQ6063CFGX<}ooXN*;;qi_^JM6Qb&Z%A4~ncb!AIBIL{ILQUUAK^Sv<3-jK|ye{xJ zI>*AAW||niPlrD#WCq|Q?GY{<*TTYP7V}*|Wd&ZEVfuw+?Cu5Nn>HrID#J6_jTemq z$siOzFn>Y+zHq7gDC3*$5|9aLP4%$pC?uk_o?PGcOwdGS9F^`x4xsYMEd}^b_Vqx< zEG03a`PCB`vuELf6^Ph~`1TpqvCo=HjcT1@*?p(hm_N^kOI~%J$nwwM0jTCW&=Ktq z)y|Rie?jC^j(!0W%Gpl1SW=`XBMuqa=6sn zs}!*vw5F^xy}s2=vhq8syv28%Oy|gHw!JFzgG)--k?(LAj{T^E3iM4A+(-&1-&H$X zanhuf^M@8DqXCxj-m>eo1zL_sibZNVX&QslSu7e57*g3c0#!3o5!W_;?Mi%3-gksa zDoA*Ael0x|(~HS}2T>D+I-5X^C(jMR@j`6FJlmMRJi#J^3${}_VliLo0#3LH0s zK#->Y+eiRqz!;dTKm>`-`@)2Qd$LTpQIj0@@~ew2HI!M4tox@2&jR`CaqeZPI3s>8bn)upOfObyCe~R-S?WB zpC%5S#?poGXgtFR zL8j^Gq|$LT(-?s6`<@F%ffr*^{qiCr2hPqpMpwCu0zrQH z=Nv*il7@ii0)X^jDVQ8P80x=07sFMg1hC}SvOG%`A=IJiX0kTl*Nby_iY!Ww?K?Iu zb~Q*_V}zGXHc6YO${rAE1$Qnfy-6d|4quQFO!FOD_r?fgt`UWoJ6U~6p?iF;x0-d$ z?{Om7{pxetb-j%+R!2(rOj-JM#zi3)6h%M}e%YsAAcaUA*6=_?_k-dMpGvii6kof& zs$`^VJRV3#!iel;;F#O&cl7b${M2u&Xk24UNtWVcxa4oSg13|F>h*57v77RGGAE=) z`T`4*7+k=Dn#{pF3a^8@Z6=Kx_7a;pFhAPd||R2Y~+={lqo2_p4*}d{eeZ= zxrFB|!DOk66i+bm)dj6osY3h5U3d}GmXV@OMbhnD4hw8o%w-?HNe^yBQR@#t-wWrz zasJ=VP?eZn9Sykp(*}Yp`5R(zEfv;L<$T^s9lQv_4Ggle!giRCA$qKk&6IvtBg>%e zINAq8PRt(wrhr{ef|)WW$g`lz??HLk{)qEI1hX!NQ0ZN4Wn^q+29+voSC9gNe0HVo zn&(nTRSnuuUP@4Ai5K}YJJpNKQ$|Lmtc?pH^?5?apbta0?g_tV(G|ok+UmHXJUn63 z;djK{`L;8LNXvQ|g2#=n6SHS0f^&cN@JI9u6P@e(uC9AyqDav9V@mkpC%axU?vxX_ zwp2O;2Hn?9H;Gl?GGL*8mo#wCpr+5tCB5_LTB+D&{$0$dau<)gckg~Rvtti|-B(ecD4Re(Xss40YQ|sYcZ_fKHuafo^y|(BHhq$$s@=s7PV4T} zoV%D~F6kx6#sc?>sijK`$fBQ&jIAK)abYx3;?(eLf4t*KHZ1v6p+A|Kk{_DLoRy)E zW22D@rBj$4o9Plejg%m*mE*Np);%754z*?`nx^#IWkL$DF;gXaSNQyqIZ4Uk$um2( zMu6+bgauPvi)*{QTaexlcIG;01g8m5MwL4h!6 z{4gOcx-0tJk913@(>zHE8tyE95!uPx&;^y5ft{|`vO;q`-u*H}FlkTqDv7a#zetbI z%$$*CA@2qq7CJ}NTwB6O!sboF2R*f0Rq^b!C0*Soxdf09sU&Q^YRT4nQN=8f4iZKG zIAl%wX7h~}nOsF-430F*whoMmhBqLaGN&v~`0ZhyFUd@BS5sX#DY>0l*0G$z}C= zA{aU$a$(yUx3km5{uDaFoeIQ%M{m-`Nus1H>|S8pDys_BH)Tu5V^~;jS1^bHu}+&3 z%7}Ri2Q=zY32V*nWqTv7vhoIPL^y=0E)vLuR97PIjW&!nU3q96!4fEwwNFW*+`Tf} ze<4pvNGQ7X_BZ^2cS{f0MD+86F~QaIb>Ary$toCfWQ`ej>e zbpnkDL7-xG+_L7S$9UQQ^d|@E@1OCG*2HtQY-3Efrs8l6R6Ab^>ejX z*#NLO{=1R=E1D7i4uaeVOYrZ^6N2Lc#H$g> z#{8dkPGjfkke0JX!p!W|{jHVe9&@$W~o z(kA+CN7=-Qij)kjfk_md6j+HkfrhWwo@E|JnB;ktP1}hVw70~N#g@E}{D6*;W*E6K zy$Y52F-Aja>!hGLNAg!Q`{%hCRwuv-iF9kO>3h~VN)lGwahxnTc^Y2%-tXB4_Rh7V zv6nScPcCC66L3lmcE2`$wJsRx)d#=AbrdpRPDs6M%I^PIX8C|JdaX{fa-r^Yw?Z4Z z?ZUCoM8ytiF2`c$8#16eU4`#id(bSM+(`CYq*P;HnZURZPAlri@6`)KMq92S{vH_} zmS!fXs1MS>_bc?lpshv%=vxT6I^#Y$44rA#vzG~61*bRXYg2X6w|CrJK~3EX$&)87@IBvTC?0KUi>nv34~{wJOww&3#HmZmxHc=gJ6dtFrQ`iI1zF zox8#j5Ryn`$`>1Lh)rEpPfSoW5MSSTm*eZi1mjB>o47`VKDnP#%(%!%ziAnvNXG*3 z4?z9chk%PmhvM&317k9n7~rOcdL&#TzA)@A20sygk&n_k!eOjz(g6}1e1twQj2xMP zyucr)Ke9{pq$3<20Zz(yv<)_An0$;!{$Mm1=q;t|`vHe6mkH#9<#kojIrdECLV4%3 zzr+8mRR1H`RKr}jF$lv5x#7dNAeTp}=_WI{x(>2~;@1ThkBAFO_i)0fz<>z4&^F8O ziAAVo>2&errJo-{PrF7ZzUGg|@jI_<${9XZI&!-#R&nxoE z33d58Lviizz4J z12&NGdiH>2W$LLIeIiW4^y)jaRr~3mRfQNBcj#@<@+vei#%xT`a8CK=%LhK4=`I9A zd<*Z|Bi3M;CEQ<4`qc%Gt04=&gcUEI&;wY7(O5^G*CK@iUW9uu!Ock0at~ru4VoVrtJ_M zd~(s1DrQ9lFKeU?Z*y_YHe!$&Bl>mO{>M^4WQVh+b9|IUl?ntmF} zg!U{H@dH62{Nt(q-9+;zT6mJdeSaZM)uyQl`IL~jW6~{`0P)yx(K;C~1S9mo_dbF~ z&(32auuPDHAFbA91DO^f^Dx}~1Tc`X3aD9MMQKYU*-sfLr@W_vBTk} z%tc~DP08R?#D$25oq;=s}Y7K9M3Kg@{)eV2lUkd<3$eeXlA{FO>;lF=Q1IVWh)KK@i0V{At8k{ zg-<8L3q05*6_)}@FB6=2TEd(h1M*o5A<5%uQM7`{!TA4oJHkX7Qo+U!C={CpLDBy$ z0B|-5+L88O2`ES}!)bZAv|f$+z6OPoiH{E@2}7*vR72mDak@0bk3r-k^E{q8p6wGKNr{lt$oMuU8CxgG&mtEqwZJzGW!Op z+Z+51?8)hF`la{!JlH|%6so)|x3TBz94Vxr%9xI`O813K4=`ZYWaXStuSs?PR`^EP zC+Gei`kmFv&9$C#Cx*{P5#9BNVb@}Gec2RvI%V~_d^p#%f`O^fZLw2?L4}#n(KIcs zH2pLOXI)L(fb3s7#P}n>Pu>t9+c)XWo{=L1bn-tEJ*M-X<3{ZY!5)2mUbeO$k7l&| zvhxDWbwgJ^IIrB{g|b$ZhqZt9H6H%AUe%aG${ag(iunR30Xhzo}{P5v&h%n1#o zV(;4h;`U4!C-1mvLHUwMavwJ!Byg1cAXxjDYi(pWJbv;ho8SFRug2qNU5H=v@-KC-?bhr_NN20eFZ$eGWRR5yVgu^>gSK%q8rODZFD?c!qru zwq5pLs)S76SIx~E>87*{$mVzGKsr#1!eR^Hhnl!Qbu(i%bg%9Vh|_W|1ZmHD8x(#Z z>g6e0D7c>Fw(@~(w{k~hN~Sb!V7I?VrWJdKocm)BZ8Y}5@&w5Nk&$Feu$1hUbZj$=j7BISFC%QrY?Ck@7QB1Rjt?P6&y1N@(`%>5PQ-q_mP~Q{|wKfP<*E#@Bxp*NQZb6Jp zyfG1>ca02CVCysU5ddWjM~&EX4OUrj`=+C`U`8IoryNEsm+_x=R#(R70H}mnDyyT~ z!($Q#@EoK+wCYC`4DdOL6E%+ zQx%+P?$I0SRULYXO<=vsL+zU4`jzoJjp zlU9E~<)Y_LitfL2-Cv0*;Uf@~{okN~s~6zv%bPHG37`%P%QK#wVWn8sl%$z@nKg*i ze`aSz#LK4nKso~Lxhe1CoGGY#G7`;ckh^A6F+H}o&|u_iw1?K_?k9}YEH9vAaI*?) zHnV)X+sHVviX`uHdby!C`+cv)V+x)hbTdOEdw7`H=jISSSw$G1f+_l_r;ebUxip)N z=+9(pdM5NqqN%)$p*n;NDxPqJ^R(PbI*hl zGGB@vD2;&m=wqg0%AY#`L`jMa5opECX*$d2_mQfJReWn+a0z*IzJK_6cx(a}UMD2A zGl}`^5~##|F8X>UtXB%buGE&*r?=jmefPzzzVqXzy54%r&CWqIh*{F;;)A+4y;?a!5~8Wh+ROoM}0w&k}dGkgj8ns z129U!-9&5qYRs|3vMc<2f^Csv*CEnAcLT+J0O=UOR4Kst-b0wo*RmD(m7Y543j8=& z@p8=ekXp@6)35SL+oi?#m{JI4kPAh>+jv%XSTuvXcyYYVw(vNAMf{0RhWlDzH0RQ0VZGojroDNzN}hkDJbIO1a||(u-H*5J zX#1K+t8!GPGeFbP87)A3n?yX;!^fjxuw-DBNXdXNcQ&1;mXleI z7}9u^rj*W|8tZ63m~w!!M#-3+!w3!PrV0v!QTqQ?kaiH%)!(}OpSmj$ zTs4-5HuZV>%#RWjxO9m0SYqU@b{_EsZ>lLq2~|oG#fSrcpK0p5WsaAncJ}xiWDc4z z`rV~0M*LGv<#&~^O!8z#zYh;EHbjz#8G|qYzR^)}RY=4utaa!wKaJ`%*>bA848G@G z2-=4AIZV9+JqUJ4X9`Z{LFg3M%3ip1?&gJg<*r|papXZBz6l>YIi$P%im7B2h&4bu?_|=66E4q}BO zzjkuKDv6VeD1Hpxf6Q5m_yCO#MckyUk~-G6Pm{h(y?PG2njmnH#9ig!g!WED*J>xv zWWtXP<)e;0n&Md6(<1yDl-)rzW&EfpF%C2qoQ0QF>Ue5O-cs{`n`oLjIy6eWYxQ?@ z4wRyHgogV_T^$P@#WdB-q6r(fY?T&fCjkF*DXlN7P*s_^($mu>TTIQ*FGy#q)Tz%U zi)fM-v&aF+$#wuA4YAFsbv)B>6Ic@lSOyB}fd4BzWlRphf6BEYIUs1Pe~1{&Za;g# zOMsStPP-#a$_~4zlVLbLZibD(h&s0#=&(yz4PUM=+1^!Td+eqkRxqvfXuxL3Pz?)C zB%2LCEJ&SlWodSMcL(ur><9rOFRccW{$kx6JYt4(3~m84Q~hhQAugP`zR6 z1BAyjmGm|6-fw2%!q2`ogW5TZ%_RKNIRkal9TG$9r)4)V9{ELD;HWQ*GjzqbD#iPF z5(7y*)=i-X#z4aRbM5&gH7q%jz#RK<>+q3zGd!OA4ZM1daQN^APVk4Pl&2)u3iJ)= zf!{T}FLpEAl!8f+Upzq?;f@GP9M&}{vDuxhKLW$;SPF__sy)_JA`E5aQsbAV#wwCkxJ{>QE=P(2xe#EfV*v? z{nxez1h;6)tTbswZkW-4Ot|U_``hAT?aUb^_y@21C12^Z@qGibTFs_ZyqY*8Gp_Fk z?~%&zf#u-Gt6H#4;d~!R5Y&;`9<+qc4fo8)jAcs1NjUNt9(^V{xuJK9)n2WKHUv+L z7_IYADLF6oc6P)k%q!hjLWTPcdhjD{PTla~Bx_sPB-hiKswsl0!!wwM1i>q5Gc0nVlg zBdqhud};-Kjq1J@?>jAP!?>=U?XI6fxX{S;T_zTtR|dpr#E{V5+^~V$*ShUAmNkL& zy1am0=oJB;T(+o62at$DEn2>ePpcI8OMSc)d%cC^{VGooNC?9nNGqmVKG2b-@%w}Or zbnb|3D)VGuf0(UG4F9}bfk3fZW;~pcpbg&>(2@W z33{7ZZ*9EhqI3_V)QC2>h9*pzh&CVK#7E6^uF^$D*U$ua*l+4}pG0g7tuupIawfIK z4VW;#x9NDo$NH5(As4I@)~Bm~d&R~<&>l{z3j|GmXQr`jEA{iN9ec02vdlqFcE`->l8e`>L?&ZZTwSUiR*TR2Yn=y%}!Oh$c(fh`t z0fizmAZV@s?au&l45wX!kB~qN49pZ)g(C0)ITO3FDWY*Zt~O@*ikLs#lYIM&xu!I}58 z5p#jL@pkcDBj-0!9tgUk*HnrR9e-&HBo$Gxls-A3=JR#Wn3E!=nq$5nIH0;jVaDGr z!6+3xN59n5QUf6x^l=g{mZzjfhXLNF=Jp?U4}gFPCxc4~C9thLXhVo#CRF ziRQk2608DgWKU=kx={J*=!;0_ay61UaNP&%Lbt8ix2X6<9}Wg02f;GSIfln>eAxP~ z$}vIF#>ABHc8n4HT@EML%hjXMQ=c_0hO$r-Ke`{?VViJzrn4Y?E=0~(H zTG#cy8^QMm1d+ut8;X-6;=RV^GN@XKIDF?9!Pv)`G>or~kfM=qK0R?~+mq6yS8uGF zYd7};k=Vx{SYRE{-}5BDHhg%>Fv<})|By3yTVsLEP$MHflKMeIEc3HiSCudi05D^3 z#*w)h@4Y=q^0&19jy2(pAf(dAiVVY9{^>PP1VR75w!Shf?p}F&ac^O9D^Of2u$1EN zZpGaS6qn+%P~2UMySuwXad&TVcYl{YJx|Yd{_nThT=Pq2CUYm5Op;Cf@AVDdD&!jg z6oK}*c_ew&@x&{W63Si53Q0D8Vy%X8l0Xn+ZsZ|jI|}818%w$%f+>Kla|EVN<2=F4 z9p$r{{6>qU)*0SobI7$w!t&~+LIMLUshgun3^&rYnFsdI;z?KX6YPwO7G~qa@9YO` zs@5V``WLJvWF|A)-D0~l=Mn&zI(_`N+)vU66hV- z5wC|Ik=WHbalfHn9WJq9%6Xqk3VZAxL0h~KU22{F$z0%Sh5L8yPp-xkG8%;e7i!!`afC?p*I zCpdzZ)83&VK0}%CbYBXh&4%7MXAa#S$k+=$E#zk|9Z&Zp>9Ox@?vKaaxl zanUEQtBKi}1~X60)JoRfHpd71nZP)_v$jI%n8L?qY$1oi9WKje7D{_uoE*gu^=|4l zj6$b4yJF3z?Teb-XYw;7MH)5hHOJk<#A{E=>VdxPKc6vc09v_s1*Go?vM~j|)9e&* z)X8SgP`r6+YkTRej}m%NTAQDU~zey*<$dEV;@`ZQ{RE5*Bxt%s!J>m2zNG zHk5FH?~|d+YobP(-PMwT*HxhYE}n@+0wPr6T!-JTh8b1Syp1HfJATUexyxB{{mpzAx8BqI$f!j9MoE(RGSOUL z_*~XykXxaj)n+(&PhbP4KUO}!{2JK2a*HP^wAhdx$7n|=_C6`^A zkJTHMbG1Pj04RovFH|Y3=&Yi&NDb@`L{RjK>E=XMGx^}baEt$qdi&L9cEGs)Ee8%> ziW3jlEZUK_;FqL&`ctxto?n`npO;b`mrVrbS@T9v6zGZV+LQt)`kFlJ_HAS;&n6J> z5=MFw2{I?urmqU0{I++Bj7DR5QU^?Fpt9FJZi;g3Kw|d76!tS&63ijwVr(6nm&v;ZhI{-wT|vUTqh~%qvHmUlNNEsZg%Y^;)d=>Eg+bJY zy#kIDKek)3ue8)RG`3KIdX01ASj7_6+xDLa9os#h8fOIFOP_tr6rPi8IOS{qmtc|1JVQmaQ`|ZH>icG(Ifup8)6{U);JjSp zuVxSm(LfYq`tqWW)Br@jnV3M6c>{(g`K@9ysw|Wzpv~%8L4b%Mio1aOiTGz&^ON26 z=!-E23gQCO7F+>PpWV>~cwSKRGuFw#-W}V!21yoNsZ}5duO+*>XWyRablllNEf{sM zM@c=R&=XP>qM?8;*~=>IXBy5>0Be%SP~c%N>xE9HzzG*VZ?&Kbe&@hAsVmyc_M;a2CA$oGeyzMBxK}=O0*|2 z3vHRqS^LR3yOt}8Fi6$y*ZzUoz|k)8+r0c)?X;kT>w-A8cQ$^c;?2uf_}W;D#MQ$a zs}jLBcaAYYq7-Dmq=e6?kuPva^yst`WVUE`oy*diGJRc}DtT%I)&){Ez$~J?Uod9A za%$mk&e4{0wvvwE;PW|q2rG7an;fV^$7{uj!PD}~s*4L^3mx7ulb{Ju)nl%WzsHg6 z5z7~GQNPBTn=q^4#TO+PmcS~_jl&b2(;9&ZwQGiQWGwFJ0kVhHIu$^pJygMpmqDu# zEYVzY8)dt$Ub=bBy}pX{ss0vlOI6k8{8(qtffa&~#FV+?zfbvkRQE$xO<4#TO;Fcl zl+ez|cgbek&`FgwI5f>%Kc31roayv>z5GiZ=JR54)JLqQp@GEQo-nQjLWM~>9U}S0 zz#bG43yhZjnQwe@0ztd5wUybe8}!J#ON!g53z!`e6#Jr;w(p7yC*@CzM>qnI z`6K4xnYUA0n@;~UCcsuMswb^cL~)5Y8B9#}44X&krZGw;XgJj4osiRLOpS|39xH^C z+%+`Kz|2j|)2~ZMD^(X29zle69bm$Njgi8PVQ@1Rl3LtB#Ty(jjz<^_WU@qWX+T3~ zP66r?4t5nvJ$7r|$E18=+Z+7glNkyM6Ec(4oPa}L-ALKlRF-=p zut?%QU3h^~9m)LZyC)QTZ1#675?HZS)H_3Xm=`q+Jn=2WD7z$di?2X%lK`t+uK7rF z$dgz*gJ@*?vG3jkRD5N%GZtj}x<6KI@NBxcoO0>I{lB0=qAlAcJ;>Eu774<8k1LN05zIQZ3E&+Z>mV$t~Eqagf@HUR?= z*OLf!Vg1-Ng)k-5m#6FZd?TIlir2=+SLdTcRYLi}fi7uH-CNtpiNXNrZ1F@F*n-&r zb@mt~y`RL|D#=D>ypU>eOua`wL==dBzP1iXFcdB-mmV-7qxW>`8cip0Ck66cVf$zD zZiC_V{=xk7?l6MYFjK?<`m+#Kbe~w1<)D5dRuu04oSwU$U!(QHqaG*cV54{kE`vOj zNucFi(6;1^$Ih&GW$<|qhxIVcKxn1OxwAQOBqUI*dEA#s?~#ejZ@Ss9Iu3=;B|Ryx zUxm^L+BB4PS&W>fThk<$Kq*BzsVH`!Y=aJ6*Utc(Oa5EkUUx=U>jI4CoG>@TPKM{~ ztZ}U1S#8^m5{*3+94OFtt)a_hnsl8_GX10B8=374ugXrf5P;sWC~D#;k_ZMLiV1XAHG7c8v642{qxB^=q1%cLOr>Rs*~D`@9)v5 z8xp}pXdc3+$`oJ6O^|(*{nhhz?;LW<7DGa1YgUM?TYfsMe(A|YD-LWPtGw1mh&3EEPmrCIDz5DWst%5w41VVGo!1^jo{eq)k*5zBmQPw;Hn-lzv zaXU#Mbs+b*m?SZ^{dEIGSj>$rcQ;kXUtGtWKtVqrkwi+aL+$UkDvV61GMybGidcCe z-%CK&=WT_f)zF1e=&xBS`b_<s_pLkG`8()NK}F8otF_98=8U42mrJ*j2Z_?hKb! zKpmBi9n!+x64LytDu*5&jpmK1G;__CBBFzO*Zh|I9Xq-?H|7l*-jhmaqH2ZmJAnxC z9`xPuVVIfK=m=vJRUK~y(I`TI+)2Ay{u^KHchyLDy7EFy3I@DyMGa&QY6r*pygH^n z@6+7%SeM#rJc+_`e5k#iU90`|ofKAvSOW+3C<8W5YLmDiFlppP+>mFUJEl78B|{q_ zH<2VX`d2zkMwl0|B<%YR0_#SSQd!(&bd}`{;2KX;s8qym)#YlSizia7#1M|(A>y*8 zce`m873*;@w4T%IWQ$JNmAGtJ?pjl>S8h9ueGcmNr~$7mW}-Q4E8Wc)BXp)ez6M#j5hGQ{lV(z}XCym0? z@h#e469d|0d%@9g93$xa9cnSf|F}7zE+_Rz=&78&j$P{(o3%{Hz&AsndvQpk8+gTk zpBHusC?lN@_$0c{QYsAks!-4UW=>G%JD=l0MGL=2mQssV8V-%gh|@$xi6lbDmN4_2 zOn|B6W=xmgP)%C%)62;j82AuwnSnf^xX$-XOE-dD8q~saUZsfSi z<0$a$_3&4I{UflqSg#th%o!UMW>i0%T6V`5p)+`;m#}=UbD-?IzXL?4wmn-7UiCQe zVAT^sA*!B?MT>wj0IDbKB}5+)Gx;GSOV6J{^xr5F>PWTVQhSegXDUe3ceb+`F8zx3 z8UeNI+lwF5R<9Are?1{M`F}%1(e}ZcbC(!~j@xj>z%x)e2_1BrkI`}0$k|MmZ5d&o zY26aGf3l#~+f>l(cy(R*(jB$j0)u1p62l-NhVRr@^|mu@Kic}&gweR_9Cdh#agWbi zTYEf=p|bSkw}Bzf-GfURBlav^!!iK_o3cY5LB3Hl0yQ+Iw{!>2{PLmsU;OActWIIe zi%w{nDv({vsRnCx?LC~2jE~+LD2iklUkL1Qd9ZwaXZI(QD9j z7>7aABf9b`e3HA_ee>U&t+$61K?y4#&RYf2rdhz+Ff21fbL?#w5IPX_d`XNPWXgP{8;I7^(pH03vb169Y%S% zaC-d+d9(3IJy&^Nh-V-?06KYGxE$EV{YM+n@CyluK-F(m$=>Uk_P5I8ZH`hVjin#PRwFWS+O|j z$htGN&xog@Kyj0MhN&X0Vs68EQesTJGSgbcBrSRCam=ePJ=36nHp$SMR(?+zwDPxB zRTyt-Z8=evdaP00p&M|FAztODe=OE^v?=>hY zRTbFk$jExScaO|tvWij32<=OxTw2qM0z^U+NCGgy%#vnv8(Ciev=DT<5)6^fVO#jn zz#$QEz3WZ)nQN`g&ktiQQ$Du5NBPG$e%58GL!uL5 z=-aqCYDkHm=&JsAOE`w&*P`ccO)}r$i;OOOY1manS}89vik7qTl|^I_YZ}EAs~sym zMds~|>~9m_NhQ|Ty#OUrju8T=K_ zIfGHllFFdInTBXCOZzhe*&=wGJF#>^U5pvyPVneKo&R1i4X~QK1 zM&jKGg_hH0GhIZY`zAZ&@Y3zB8v;Sry2GjFHTyABp#7+HxmiM|2VHNM8tG1lYgD7? zW=g3K-7FZ3DJ;Omt#zNbIUWy_vzoB{1@IyxhO3Mc1Bgx}yTY^Ffk7X9mc;WGF2Bk+ z=`VVH_P9YC2hKv_2;eytQK`zoS1q-p(A-%>ajtFY0fMU;Yn(6SroX+9z{sR=Z-e;5 ze>nuAn*D6)1Qj36e_Vnu9gINt7sG$f&{{)WB59Cy_0mV_P`w8vjs_)|2BKZpZ|1cD zs?6^Zt}f=kTA*Y{Zl1lVD)80A8KbB91nzUZ>RPH-^bE`^!1HY7fQ9=}tt#no%g5Yv z3mBBgf3(epjj1BaP@ii9^szT&l}s(hR=eAWn&fJb)&LrT(<}IqX0&KG>Mb_?6w%o* zKgduVLzVAg!Y5s)AFruLqb%m3D*Q|4EVeAPeDf)l1V=_y!VFz~b3up3B`0{2I4rYW z!WGEuqFfSE=nkkfVlT9ir@<%ef=xm|sEF&WZyW3=sM9QEMX2;@A91`12tY?ZCBo-8 zX(_Ve)ESX@BDBW^Oe{ZOLCcepwwl#XZ)5P6FFU-%TfQsp+gQz_S_v5dR*ZsIyXPQ73OCJ=82oTze!s`_@7?-AJ_^sfDt7A^wIBQws?!ry$WNZ zS}4vSbd-4=`3R*_BPpF;@05AlYxj|)<{&5zifiRp5FbA;N9m8=UE?=Zz!n-NF$~lp zw(g~Bt2dz8*)i5Woz|J7`sQ-|)*!C8h-+U15S&dBVb0HnRVqQgO#|(PW5qT^Q_894 zmeH@brZd9BUO7F4g>wYuo6trf(-&kcD~EEK8o(7txf42H1cm2aB9&8rzl%4nR?tV1 z%a3da9j2wJQ^|e&b`_l2YB3g(SB9gPENQ+sje_{4Mu7AfuR7^#2>UBws~rzte78#u#+xNzdWLK>hy@FYanS%xw&IXecb)-_{n7I~%7lZh{T z`YllFx_5AOER#pQwlNETLHy8rU3L8P2Z-9lP(ZkJZ}4<#8+({a_%3+bcf&Buo5_f0 zI+H<0k0G)*A@>(HDJtI2OoAqkQz*ELXLnl5=wWG`*oO5itg`5lc#l3!{=QD;&?-(u}c=F){B=E=Q zqgn+jmF>#QmNo8DPvd0qA?QEi6DelCKe@*A;al*@aDAgvuj&8cP3{_4>UfEio8yO! z_A*@rHE&}gY#S7t%N_cM*2Emy>oh+uA3 z%EKZVT9F~{W++|$U8ozv5%{>~B{vtb&9keQ_u12l^-BSVBAc>uzxZ%Dvd;XMa106;5bh@B)?ZtPC3xwp5|+MlEFeL)Qm{Te$3QN<6X>2~tQM4`+7 zn|rCoF9aST(ecjw$6J)q=+{jnM}q2kwjEn+)9W{4I4s+n%Ef>)gtB4h%(_-h1MYu=^6QDr4!D{G8hR zJ*^yCdH$s!lgjWNv|=XjFc=~9kIw(DGXP1d1?PLy2PwXNMHgSHy~B9fBA_&1kL2ZZ z{b(eBAqLbM$3TV)P~QZi&@XdOq8r zb=CY62&kM@OUg}4b{9V7-@!W}*-X<)qs&*MM2iv&qbeWJVTTi)Bf18-GK+ua8F0IFBr{)MXy{6{YI0D*g+x8;^C5KH4W&wNp757910PF6zdu5&}%EP9r- zh0KS_$i4J%XMl}NV9j3L) z*Cfdt918wG{1Le@wWIK0kmJ6(aM3q$G;UWybFSsWAEcJh*r zsM*bum1OH|17z~Xfe}vsKV!vbbvxdq+OJ(sG75H85w`7(JFwmvPR7Z$y)0&>r5Z2Y z+lQRWvF`bGcP2#Q>a8erF^6ax9xc|=IXI0qZ7k}Jlv0m3xjA9-CEsBpAq;}av0#s# ze%fI*UW4?-0)j;dB^vAWG=dQO@^O9LZf{vSl!Jj->aPHa;p zHG;YWN*-=$$-$TjQNRQ5R5a5LD(Ou$t1SUjh);V63$8E=_=w5X(|V!jnSt<;L>9^099F zUlBjRzW-N5e=s8RUy%Me7p$gk$KTb-U2IqbT|$-YjBbpBy}t$>D=LS>L0wRThe$Cm zSW`BsA?H98eDQ-~3b{XY0@-w-nAeYX#tPlP*-WB}`F3#2dCm5|e>}x!^L+R`0w{-4 zfCP)p`>&DyCH^A{pAHyN>5sMkYrzIZpl%m)9be_4bX2hPOXcc^+3UBfQ0rkqqz{6! z5-}?m?w8IdGokp^=YhItMgl!^ui+JdE9T{jsaA1XNuNw_WGuMraX0r}-MwP-E+@I< z!>w1wgWoQ9k8R4sA|K>*Dr`3dp9$^fsFlqVwh9!HpnYcef~9pSd4)McLT-8b_VT)z;jDju_ZV;>$_RIslU`B8`4;0N{1+ z;4sY5cLPV>p*(c9G<>iu=k_3vWux1-yFT)yv$(&rZY^$-ePb8D8XKY zRPuss?FAZeW%qf6FARS2BwsBMu}$;sc?LGnP584RbQ0q{!rw#nq2HbNvf}GNY>50D zB|-_nHpmYEil$=ipjzE@Lr56lH%fZr5Ko19liDQgT_8|71|vHB?d*SNRbF*FZqbMK z(uSK-3}eHuTtAQ03EmS9@A*~cI*U5_^IDZ)Lgmm#cK2;~CImVBH-hM(I@#*25iUXkrz#2e)dtJB zN`U0!e5i~%hGpOP@S$H(%b)HpkzSBvfk7WIF=8S4$Vd0&)AH&MYWr~XV zeV6awdJ!~h3!+cjJ#9rT=rIsNC@93;)W}vSJP=4IG!O_wIlvqc;GY2=`5?+>x^&8R z{#C9FL6s~wQ?3fk|KA8rrN;UnT9fUJ`WHh|88la}3IgPo?Tr2hag;m%1%m;Pl&}6* zApii4|J3{c!~Vmnfoior7+y#~HXvHY(9MjMgN~hzj*)>uUGV?JB7Y(T>aPD6i~rEy zsresrs;hy3&chM1Fz8-_qk{xlfdE9!S;3}u=3${~`f3WC!GVCphruC$UwNu~|C2&g z7X(t*5d<`n5eTGOm!#Se2&h{B&pZEl>pyP`1p3dK2x>Vy|4&A|abJM>*#7`j(Zav7 zf>QEI`a(*Aav~z(A&xEt1pf`=h!#f6O3M8UtBEQpOUlcMg#Te>W@qH&WM*Ud?^)QQ zh4I4jvI>GKl0q_~|GSd%|6K}8v@l#$PFP+i_Qrs6`8- zB>vHp5mnNc6OjeX(0#?inL*`QwkS=xd~(D)uk4_pM*{#Vb9Ti!S;Fm)`MK z>i@3lSlqWgyM=}?xDK}NbfgYmNFW~FkbDIS8sjfx44U)Ug!I_d-1JMdB=+Q zOUsFFVTkorYPji#4E+gy;>WlAy&wPf7eD>;m;L0&FZb#F76HI;{Ws&!>8Q^^pA8@3K_m_9 z^F+uiyinASz?VY8L{tUkZ!fDzX*Bkn7s2Cj9k!VEs4BF zKS0-w>SStDGnVt)pr+x8SpO0AqvY*jYt>-T$|tzikHBG}H+cJ7Rxo-sMDGbD?<_3Y zC!utyaw?1d%3+WnZ)JUd!WA-`UXE4s=^AN!Ff}A#6_N^e>1Tb(OTp~+2x)<5nv!L(5@6W$9rZxAC3}Z548B!T`_&r z4PgX4TM<>NCq4FU=p9L-$5JgBJ``Zdc76$Y!28_C%==9aStU7WiR3O=NxzjahenDxSf+&gZ{#?2gPBx%%Hj!M1X{dac2q4Y*t zLx@chRu&wh8aGNh53ngH>mMo-0LR!3AJ3+fsGa@4zgax`t%Kye#@Sv}k12dkZ4jbX z&Dsx?vrNvcq*bFz$y07?ajv;s+Xf&h0}sB|9`#@zn!7m=Fd4pfSFx$yTH@WmTjQkC z@OEMksI_?0CJ0kbk&P~R2n1BoL^X?HbO%9-A7-t0q}AKk~zPZ-=2*6-CL9% zZs~eXj3ZKNx)d;&0nvb9S%iG9 zCSWBlJ4oKPLhf^VSrLM$G1JuyoYnsgiyGZuKx-nN>Z=P1su za!nzqNpdUV0AdF&~%HRfWy!0T8c$Z4c26~k)I-Qch$>{953Rve@Lh2S;y$ojv6m2fn zNTprJ!f7wvcKk80s1!(o9;a>CG0acqvmxc|w1?H}Dtk4rm2aTma&%<$7h2G? z+M_((J6yA8o@W77SXF1SB&5xfAw##R5wv<2xC38jS$1;UZ>ZV}maaHdyc~EuwV^rX zrzZSJqWkb5*E~f%zF66Z?tHA%KrSADv7KlTXUgS}JA|G(j12XH6}>v`xoyxGC@ZP^ z;Gwc3HSD?7v``NQsXh!>L)pL;kd=44_!%y?r+*6AH3Y{PF&>COJj5ITCcv3%yc6xg zQ17lf#ALCI~R`v7^axq+2`_N01TljCEdWv^3##kmTBki z7}ih2O~7KK^0n96Zw7vrcoPSCuW1Naskat<2B=4^`JCP(G^1q-El!$G8r9ujkv)g~ z+fWh=%^;2s5aY_|b`Pe=0&QR3;eJsl&ffdQLP6{FtNFS%TK7BWsmDg&Bs7CuGj0(J zC)SU1XOFaX;TlXrLpx!C)c$PKxxZf0-rc1Y{LF}c7slbWMpZiDmtOEi=73eG^F&Ng zx(P0vo0&;HJUcMmGtd{1W38q!c7wEd6rq+Dt7g|Tf_5^$TBu^>mpS5Rv4h4l@C!5) zd^JJ#j^&12BkLykGo?EBTo$JKvE=O`eSG zP4ri&BQzUNIkhg7UtscY+GM3Hh8v6tI*e(k~RlZ!ahOX93I9UvTcHrjX43G>3JKWTORL|6v{f~8-aOg%ha zT8;x2lQrXjPFY^;*c1~L+;7SumQm9#q@r`&otxx)R?AB(122Q=^kJ-eBz=dzuOg4= zn%pJOuPK)SXzBX9CJLTop&Jd3sF|C)A{a30?3OO)ge3fE8a7~ESUd=Oa5J?CujJ`~ zGTMH-WzUyrbjHl*R7_WN5+U*aY$ABW(R<*A9!IHINQ@mJCk$+o>1<@VPs zkfLVA1uxx-T-K5`tc@ZaO;L50qi$YtrxMh}nzphijS|>>M#^ALHWAD9G~%_*VNTc0 z;r7jUSrZVPq7i9$jQG!Th)~zjQLVL|810sKa$>54PXU-SB8`;tWyb>(&_eW!z!2!*7-N;{cG!Lx~hc8{rxS#ZFR1dCB4-Hj|s< zJU@QhOjfpafs=$f?B@kFaPNtI%@VZLbf^ zunIAO++Fou`R=Tpza$Jtox2YQ(d$F{EIGUkp&+W~qh#t4xeb2kOw%?3&wLS2TS%oQG!e(zGxW@=__@BFJ88WQZm$(`XhVWo;Yvt9C=*?>LFIX0y zGzGDb!edOkK6+$$=#NX}gMTkMxt9VPm|RR};sUo$nRisdWHou#HTcyEZ^V=P-*T>W zg9?ex;DBH47#P&PT(qvSJ7><++21M%&LzWu!%Q;GW+EXb-v3pPmK zEeQfXpn84B=Tf&n);#Cf+tPA#LN@ZkExaJhkh~eq z6#LzeG-OlE|Mx*{0Txk{ZXtoPB9TXDGi0AyVZ-2&ueC2LL{Gmo8MgjST=>fvw9JZ3khS*j2~Vd2oDUL49Yw z39`Z4S3vBL7j#TbZzi68a!33*`v?0M1&r4HF4A#jm2E3Z4OOAdn0#kRxZqXceS8_6 zZJWj?q?Ap@v6y|GEEB9Vq_B)|}@OcHA zsut%}kN+rgTYr`h)TiLtr?gC@%5ZwwoG|l6+*7m3!KP%QwK)sAYoI|j{9{K)&NGsr zB4F;CL@GSS>JQ=8NGA^=_OpZF_>i=wS=qk!_b@+OFStfZ1M-VRty&qixAPZ>D2;x1 zna)XI89i(7BeOE$8BO=eO{E4dy>f56Qi;gY(<$n>Jc(zS{A41vbm|PG5C!in8oIH| z8h&?a`^n!mftzMX9a0Kk%}=J;#p$)9pN&uy9(BhLLHIOzv(Z0Y47lV)nleauY!!MY zq_vvLrcQ<3C?FE`=of$CMVIw;cM=Ig_biwe$XZehL>cVxRiYR%^xO-Akv{s%eeUN8 zaOLlLFRLGIKMmM49bb2380(J-?c+2Q`&irom~h*%+-GqosGiFs+$y?+ssr<$S|VS# zvzKu)P@+ZVoD!j6NGF9EdxQ&MXmY*$88 ztj%wc{tzu^NM^I{L#)sFBlFP+xAUvCW1VK0e*3i|TYIJ18fjGxamcvb*Esv^cnGNT zxL6qr)OT4qvo|3S22dB}`}@_5bLW>m#gi}Rn1TTEsWeRUoxq30QqSa?Y}RQm;32}f z%M|7@Ht)*$q}* zT7BLD(ii?tF5bG4h&75A5zf%T+45JpcobVsFO~ATr4pGfHv>HBuhp{7L?9QI@e0j& zy&9RFp=G6O8eex1x=`NG-L_gu{4e620toidU*Pog@BB+f&zIlpV(dJQHXz4`j(93Zlf5{i7`Le|i{t!q&w-!qsj{KX6mkAz-5152Nno_dd<6#mHZ2BQGO0UHP1Q1CWUQQiUl+q(LgPjk&ApLP^~ zcvWg0XIaW_$+1PM82sqPjcg6UUm(JxYXvVj6mmZ1fF3bsH?GJjWg(k_F zgNQXBS+o5V^1U=nS=7^Cr)loBDe#X||m-E12wgfJ3wXX}uP#DdwbFrze? z6}tn|ll65DebCgl_csy$=@7G#JZ%;es-t;&v!tDKZ;`bDh8Y|E-4hxseG?{BNhzzL ztK3ZY+$WjA`g0m=5qTm!KagiLFv^z6$#H{6z_;?<VphLrY_9wzHMi=4e?S=EQX+6&H!9YbshfKCQD)DeQ>dzr^BU#OJQYA8kMU0eY;j|o1qptzP)8d4qn@( zzzOW7T@Dr8t?b=1Iu%`(HIePayLT_%TPx02wJI(6T_y5^BqOW`9V^foW&H=Hs_AjL@8B6bzblk_iR{)Dl=Y^={NeU6SAfnZQ#qL@1Cnvudb%e&KD(#>~ zXo|6PC9q2ol#V{1KO*w%{e1OKoFVbYl5@B)6w1^Hg?WTUH^qk9OLp=0ruBWb5=v{?N?AG7CI-= zG(b+EQ|Q^^&sikM?ZIt&c2M5-CIB#(>)|Hx9K~%Kyu0i#z;_A1+_;=XJqQSHa>E5|;mL;q2h&`X5@9RfNiEgFa9SV)8(g`fAZ^w*~KDNO1x2A3IbJT|(_eym~PPw4<^R7DRStBBzQNjAHMztO#;tziEN}hN* z{g`d$(ch;NBuBu|Z{@Lb4w=P+(F}zkKst&VB!<@6%*eNTX)-Y3LtryB5T|c3?C|p) zl>W!tDc*Eru%9|d4j7!#Sn&nT1Yw;7bkKjkFw3#h=toA@WuV+&#E^k;1z_DWI-yXv zf$KG(xcQYWcsrIRDg6kXwoJ}M(0}0vlo&D+lsT_2ElOtzC|E-&-aer96+=xXwiR3j zS9|$^U_Q^1Zcq=zkxV^&N!S5yn5t4g!~G&VYLiUtRr&6clb;hV8Fdw9~P7t<6#7Ynk5A z5NUdka&{o&N$gTt&7iT0PahQqEJXt95=Nc3k0blrMdbo?v&X%IBpZ%xaD}CyB;yO{ zTC6T+O_Q!50*TRFk7Ku!*GQ7_z*4{rX4M6&ovjbWu>3U3OSY$=(oSIhJ!&o4yWpmH zj52O}UXQvTJ?V5|Ao)&&Z*-iEN7?KiF4Cc!zbYy3=ojDzjTrg(TkpNdQjC)L2jxBZ z=A@!HVaLsB$kZ$U1 zwXXTh(%+O~m^qAw{`zxKBe#?~KugtHfD59l(fMUq=|6wekF{&`Nl$gQg`g%J_tZlr zq!yEccWACwhg5al4Ax*Hkw}LIH#Xz!KyAUl)`UJ6!o{p zqy^(O7>X&+R(%x8arb!O!>91^$=2I3`eCrD8Ut`Di`YVYh}0M13+>n7#dk`Dasn1L zaz|Y~U1DIb=)35sTfMrYP~I_?`aR`UE$X4L(48Yj?*I>T`A=l#S5J3M|At>J-s({w z-z|ye&*R}j)ET?<9gMaM4&f%uvW_RI45S2J4du6^H z`QW%cR^V-tt8OBfmH7hZ5%)h^JI!%O_OSS7GGWo}`L)*-Dg`4*H@yc*swX$le-O() z?%!KeE8*C_*IZ4`5P(WN-m68V=U^NEjxH~VqkQw|?8BbFg`kg6#Y_{|FQEt;!;KY_ zjdd$;5d2a3p-L0JNwC=u1^D{eb=~lScJr_W$jZ3{!qTd2BV9LaJlkGf9O8(YKp71@97AT!O zLvLJH$zzR4>zt=@qo+{}MZXgdHopd9t5-nglXu?JcxK|0fv4AWCrY;|%3OkP(2V0} z9VZf(%6}pfbHaHX<&<`O-b=@cWlPT_Y*3f-`y@X4f@CSFbx{P-GS<+WpMpY++4IDz zL4(%7^~e%>OWMg73r1ulHENt+Vws{5-Lr`Guh!=a5+VrzH3V&oR@5b)$me^>KzQYj z-j?}7bvoquVT(uS?E^kuVL5MAg6$CGiBBPiLq0bG!u7XL3S@@m$X!FC-RzK!{}CkX z1%*SP>24cY*sfiC5>0j1-z-TbUlC)j+W>CX_i!cmvND_=6E?C}Mj3J>ZYaFu#fW~( zz1hhdh9?5<#^;(Vl`TV$83>=l2A+9e5$8|p--2S6lYiBrx1+Mty0+Ma0o1tpetvZ; z66TLE;}tmmPy?OMBtD4GrZg&)2@12ZolA{ulZcutaB~?53y@}TK+zp{d^2Nj;LG@z#PU?FjedI5h%}Y`q}k+NN6bLtK+?XruMB1$jBzQ`N#x1;Ka2r}AXWPlu-DktbSr}hxX zf!7^9pdxQk&93e5Hm_2Jpy@r(FX?Zg$7B9|3fp;Eh9|(p*6R65ab;f}8+*u-ToliI z!F!u7G*R9qC|#in$9ys}@5px-hT9fXz{S+ciY*w`p0-52O0hJ7P}!znEN}vRFw1AF ziL#vF^@p0meIUvJXR^#g$rhzy_smvTr{TT-<}WpI6dIV_Qvmjf>cHu1eIF172{Ibr zUt)WOT?*4CkjYa9xHgMI$VkG^tF;r%BQBqE>^bL{{xZk=p(e8KL;D!-o?k04J9HDA zv?b)bdl^Ku{ErR5)UgjG=jGIy2A8-l#Q0VvZgM0JduAy?>9 zNn)xE?$~RXSHv5&J#PnZqANFSN(_c`Mvf0-?063Wy-3r;;-0puapRs`7f{i73{-|# zek7Ep!*@=l%8`E>6{CxYN$H_hjp6)3-k&?1jDYgpwPfGko+AO}HxDp8ry60px?Q1w zK&pg6A#pD9@WwxkXOvm-2dKz*)QZXJ3|8kUcM*nPOjEsxq&F?a>)3`&R)&tjDKD*w z3eopDJIv=3yi8ED!0ft))%~}-Z?G$Y|E?hrnlhJ_F7}C$-j6nbLIo&6uK8{q8F5GI zNy*lZz3dsKw!lB^_nOcm-E&Ony_~<|NgzP^k--9TDkroR)Z&;ZL2Y3$A8Yvufnz-Yf&yvCK%!-imFZAoqEl%iH z3L!#QVFKxMlW53;_GleZYFt+bn8^gzvn?%MzSi7NdIWyNh^>O#@?GKUs8R2!D=uAl zELJs2Muq+nNQ%#9sco?xL(5v(-2`XZ3r45o02l+^d@ZF~V}Ea+V_`$1p%wP>y0Xbu$1|AP%&?|}C`!iZEAgh+{h z{;?W(7r;ap(HQrdDdT8MSE~-!PJi5puE){xlcxCdgrwiH{k@c6`p#|EaQ2pqrmgyZ zkQV@y*XVlzfR*O&OMg)siaVf+M;823bVy2=_q;BU5zi)`$r2mLKqTC|{aTHnWt|EH zV{Q^^w_pCOYmPLzq@tSjvm2>E%P+3*L;aG`oL>OqI?-Fv%Tb0ODWNGnpVd>PSE< zXl`{J)(=1p5Z@bzYBA&3mXshjQT)3qnD;uOY`VJ0u17ou6mkxtmae-zLa7e9!VbmX zC|}M8ZS^-gBRpr6B+3*wy4#4Zo3$baF!$bt&Kpz93pffGX;d9Fv0FvaXEuhbUZ8Ya z?WP3J@bBbv$yuYk>#F+9&?dBGcF{e;x{JXt56PP18t9udq(g-MNfp}hJZaE%wyA(& z@{fkmrw$$H9yPuIqWKrABq>GU<4MJxxq0l&2NFOjasg^uCPTG+UBvKu2cJLmU2%a< zxGx;VVpJ%=?g<1mlwDn+U-OcNI4LNnq7@txH(6|p1uK%EERX`j8Zx(|c`&^q3ZW>L z$=SE>s1^m_&5wIMrxGL)WLi0Ok5$Gd`b(o#p~E{m`Xb?7cx)(77RRTAdqq>)vi926 zit3z!uLSE*EjxkAAtKKca4x_(odsZpjhO(Q{er=({DK15IOtuME*RzV0l3ZSZ~vwn zcwzsq>4q10k#jqx5O^wltxE&WBt++JsP~LzXQauUGdq-1r6f;2HP(fZY3ezS5q!lU9=V7@?|bzvuu%-$;*y-udnzPwK1jhz+ce;?N8tXqXd#UYYER9dIid*UonS4GN7BgcNz6KE%#7u7(c5#wY5>Mn(aJm+{43l~$ac*!iQp_yXjn_?DM8@7i^Vui!Jc9@w%A?IY1( z_=OkoA!%HnWPB~wqyZ=?OA3LYeyBYpsDzsD!U}M8QFor`gEK7KsAfWQFMdmINq--0w&ge9V1tIBXprv5sZ=9wK>U;D(j?enK_As}U zV@1X1%RE*br3t@}H%DWMvnsyM$^ia2k3yvz?Rl@L@|%b_yBW)!SgFQ&I{tYIrqDygxA{RsPod)vOa_r$eHSg_+*1sPntXR z1L!=aaUWAW9b15m&Hw@0j^ZcU7axsth4(NQZjEEnVa390q8hB$EkD(8a^v^FwZ7}U z*p8=oZzX0_WA|e>9MB}0Gd#!ugzLCwedJ#r)&~he9aWoRSU%iNErw$%&!2RviD6`7 zVcLs()zHKuEAa?{asOi65t8LGl(aVr5mRlOni@R#rNG&vRiqO3yZ_i08~4EAF&VS! z5~|Tn2}hxa_Ut&|bsNFtRrlChJ=?1cngww<7Ibo%KujhA%i!+bk~>zjq>__EE@|E6 zAOWc?QDWD-NV|F%4&smv+!lKeYQFm0p9(LAH!07a>L$s4KXe*5%OmJe5%(q+x)xJ_ zq0h4co!s`Jj%P`^He+s^dxklzs8k&4M=$FN0#SyR9ZIc)=j)eMFZm2BPU9jBN7ePM z2NmX}`;dPxOm+b;YJt4Vk?-P*Vx2pGFBd689*K{t4?EfzdATIN<9hj{IIc{YUClr? z`DW*(_N(88EUWT5CKd-al<+#AA@;Sv<{rNb#^f_jl{J#gQXFPU1HXlF64gcrCd-V6 z{UwyoBDx}cDY&Yh3P1csUb^inwe@PaNsk^fUq+poQX{~3f8|s>ZdS)s`qhy5Ab`d~ zI<)Z>%07VZf^iDnJ2fCzC}r6Bsm1&D1QepesHPRLb(yI{q7@zxtOf!_mPi0~MKzs( z?}6(!G82j69)jdlT2+RwY9EgU(>g+~pnVS9UXB89Y^*d_hYTXwd}W6H>}vWGD3Ob? z2_CddQql!>E1jM>OX`h5VQ*?-HhWxO8qflfd&Fm5Ku$&t##q|r@C2V=lhM1jfBlY3 ziM{X5>rixHSB9>MaTdnONwto_7v6u7==?!BMPd{aD83cJ0x_%b&0Wl>?sc~KCIRp! z)_p=ZZuXBVJyuj&Y)Xn z%7no6Ys;a@Anw(t5L;zA5Rpqm88m?y_m+fV*9@$Cb&}pWf#S__u({pC+9~gu4=aQ3 zPslP>Do)KL_Sg<9nNM}iND?pkdR2zu5hN&j4aT&9b9A|3i~oyyGJD)o2m1+9 zfCKz9eSfPS)&PB|7+ZN5ul@uVvtGw38h+1Gz9bd#54>fAI8GA5>Q0x$pFsWgL$+`E*8`GK|$x=Ko3Szx7)=Xu64{wu$x}e;p=rI>-XXZdHYZ~X6 zGv@O@;=?jRI3$BgXL^9Q*OzmrFnA|}e%<3pbjs#2k_!A#4DrrU_P|wwT>y?Hw^We% zs(^nd2IFM&1op%hIbE2~j$c@6$aFw)p~5!UnVD#hf;-xj1j~PKv1#^rt;p*i9_q^I+3p?RtlnDliP&q`K900%f>dQ*IG~yipLEvaNFa&k!;xFLR|^Fr zhH<=!0mx;|l!zl*j$*X6SBd{NjxQYbT4h(OKM%NGZ^9JhoV`9QF$;NVw z?ypKQQs3!qd0G`BIRF~waa1zi@H|b-zK5FPd&*A17H_@g#yJ!d5*8Gdv%Bc^m5-_< zrm>@oE2HWom5US1!@jg7){R7>`*0qX^Jmbc0a7h=K}gm9G8TO}vEb+>+ySnxGS-Rm zL5pXLu!SrIH?Dth^OHQ|F^+tk!RGejLk|E&8sO;ocCiyHq4?P88#uVDJgEtZgLe@RB-W8sqjbp=jx z!#6&T6KTw>*pNNw!)F+U5G^&FAe!D&#?sUV=#nmYnD$?x#fEMn>`uAGijQ5dn0>$( zD$8ToM3s2t!aL*ebb#3Ep)en9&j-B>@y|m$Da~kP1pI@0Yfzkuu}~ z5gYZrNrCGeq2p;QbF&kOHa1nQ{2l}xkFvVG)x#X4fenCG5T$zV&$@XZ+1P#X3!S^* zXZC*q9>hP2-)&zG4YT3HXhm;+FO1kKIPovoV0&iyzBGh0s%_VvJmLKf~uB5UuCg6x#w2!>0 zn6Ejc?|yVa`o)Phk2s9n9J&dZLO2A|n1w{0EIL}Bodx7`Ncue?4LrfzHb-|(2yz|+ zeKW)5ElYpg>QRWS22`hX2)=KLnNkKwCG)Zc?(B6Ii#O*TO`$#L?_jiC`mn*kcXqq8 zQ#ijqQBrnLDZeJLgt*msBRdUaXGdQ-+VePQ%HzS4*qSa89*il9Ei;YW25sgui?E1% zo3Xc(=TGcwFD|4TZCs);i9*EXW`eBDZh3AvfmJDoo00Y68h?Nw(LWKG^846_QiESF ze04U#9r(dZ_2DKbXnNPEn645j9OziJ|$G+fX#s3R%*;;iRu`h{dN^} z&I(zX^j1R?$!?QRo}X9#$cSpi(t|d`jh4MydBVhTWc=;@zZUsn-^L&r@xH6GkcqtHBsAj)UVsZEwaT8|Zcn&~e zqLY!VG5dDE#wHi;Q(YcBZS7`^?LmH2PNRf7Db;_ z@L1SVH1kX*JUD^2U|jP>?<`5omG@vb=<-W5dX5hW{5}X72}s%kj58d9;@`<1=#^&) zJ0)wO#^y06DP}SxCcQ$YUXChkfe&0@S`Ht_&*{FG+U!mKbWoWXqrX33Q`)5cut9Mo zT6K#9if?Yk-0#Kl37knxqZI~5{Pj#7qw{}i3o-*wzQ7*Klc!g#*s_Ko2^usVnLa7g zs`fR-MC#?G?cS4e&lD*w&2t0I<<{4y=e|H8I0SDPv4;2V0F&gX;W~%Gjbol*T5*ED zTD}YimM*`2G#45e(ZqY4O5F+BttPSL-?N`{4xY7x`n%a~0Nnd}NNX0qWw2Vd;e zTmPh0VCZQsegvPf9gaHIakEK(Sl@XwdiZ7(=C!#iBRuHipG+fMmA|xRb(wsNLT3n4 zU^Yxc;Pc*{PT4Zn^t=8NSNOCycGGzw7|cKAu?F|_8j6-f{d-9cw4vV>hk=O@+6%CQ>M%LAf4$-+Zfj#9# zp;MIjz0KSs;AMDwLwu)+uZrrq%AmZ%kOs=x?p{dooWsPfVQDML=N7IdGM7e+f<|y+ zMutC{ana>1iXK|vr0u%j$8PgXbLh7K zs`4cL1XKuNQ5RI{i>3O)qC}Pi-R`UNxO zCY6ocH$3`y26Ak#nC!H@NW_?>LEAT`7q2t7h%S=$~b->TTKcQ+v$J z)Y%F2R=68WGR(>2X8WS&-e9K+=nc4T{+Rp(=lXuI=IvwSlh{YT>+zWSCJKg9hl{Dx zfR>Qbg0_b1yW|BrtcyH2dM~IsK|EAb_^`T%Jkj9UOQajj)TMPiA9lr&LV@3$7~{h-4ThRAmdWWBvBE zbfN5jB**6ODVE}j4^*F{k(aRU=8cG*I`auu;N%Pz13J&{hpw_>01E7}F@<*}lIdH5;o1;2>zcvhB01?i1-V^v(`l^Z zHqxt`cH>fjizK47{bymDPD*8Pb-dE_nfB_F+aq7Cpi?H5Zx*?Hg?|U23gg8cfrWbn*;VXdR?emi zWLvnUrl^DhK0V}Vpy7H$hWk{dT)>~gIDNFY;XJwFn*gTrx`ay5BfE(woqnhv3;Lb& z9zAQL5p{V;tsA@Ukn5y@nR)(k_OM*L6URuJ?#WaBI2M0u2eGB$4ldd57#STD&Fbh# z{XYlQK8TFRj5hbEw?#pjho!?BG!b+`b~x=o)WQ+_FC2ZZUc7@1d( zpLvzYbTht5OVAsW=ZxE#T`+Vf5GwA^Fe!I>W|r6zD0DT@huUf&X7pp8ZAA)xaemK& ze|;~|&5EjHF+uoV*o60W=n5&#;y_`~(VFbcC~W};9WJwj`c zKB0mH^KVc3d(BX+E~yK;j9LJnAUIKaB4D|}$oxN}HX&>wp#cgcw|mrfhC6~^1}A<| z|Bd0=wV(=mr*u2(-@n~03V&!v5Pr=AEEY5`G=EV^#gLDyfq?f6SdT<`4%)OC2PTW^%4UZvt+o{N*;V;D9U5b^R!)}gXuRCrp|F2^pI zSIhR&2*ELb9clyw3zM5}f&i(t3k1ta^n0aA~c;Nx;PykpZlO=TTPJ zlMZ^nk#t+LolXA@cxAQNGH41i=!hiny?kIdBNPpiRv#43$@UtZfBDTJzet1)*Ih3d za`f>_JGUr2p0h4lS{WQ-DfyHEmdhOnvEpc^dP#@}%>2LO>f0*6x z<=TTf4Ez2TdJ2~Q=IPQ-bX)0rCQSE(+Ojv?3Vn9sq>s(gc_Z{WoqROhjfwh!-U9!O zj*vy(r}UkMga*}(bf8*+GcDf&^*7z_W9tpUkvVj9w(?0<-%&U7HwUQ;-6}Mo>EKxz zX_ESiE9;?d8ijT^lz+H@F6yKFTh$%;#_SFGR)g`(`>2BwVHp~M#*FvxJ3^i_cp@Nk z=XxNytjzJLJ&q!%8FOh~akKF(tQ$$wBMSKoec%*uiXHY|UKMQdoc#`_o5R{1#P+Uo zYtvj#xs|p0AboK*We)D!C56m{YW57v+Nw#B|3e*-!-KCG2vZ&yby$I%Hym>NCru|%Af%%U*dw7hEbMC^G2qSGtedl{o>#t7v);u6z zlrRm#5LsEHwr{fFhq3^O*7>)9e zYLXq*)0HQZD;cf6E3h-J>E^|kZiGGZ)dsO*X@I6XY_zn+ZQb9 zYc7@jk8z`waN*j_0%xQWja4q=J$4-V*RHHV4L?-Rp$Cq{{_?1+rp8X!5~e!5LkTHN z9iic#s!ejmB73-`809MsXb!VO>&7eD8-sP|?tZb)O|gJFUw4L9-J`SEe$BRM3xrPp z9|?Zm!u^Q~mkGEQ*5#W6wqbSlrLAWvjRu+0Ao*UgUc6gA{S~meu=XTReY=E%bjwAZ-9S4c-(k!`9=tn z^|gY(Wl51@(aY)_l6cNp{F2zaN-N>wn<=;q~$5&C^R^$VEg*NVZ^6oVeZe&`iQueCgS z@%lCd9$R)%2=e5gdzYBtj7rQKk5>!HI@RRswhQBXBJ$&==YdL9PS3@j{Y-Cf>l1)9 zDo?H7Kn#2wQs|0jz(fLl)f{wvMH^V|0c-1SEN7oPCYoY8HJxM=rDXw@g0lDu7ra^> z->9$dDd|NrE`|R56e6lb+ekxd5op1o$T#-qIg$d;%* zadZJ}L_!tk5K4zkELM!S<4g;@!=JK;L>hkzoX1O4EqM-p$Im(-q^2ApaN zEtdLw7RH?3u1U^3#Eo~SuZ`*wkA&)wJg^nBa7`Br(TDOWJ|Tm&QQ{zwnu0^ogmnvk zA4_63OijCGQaBSYi)jK#paCv^VkV*2f97vGvSxSz871@8(2_M}MR-`vt}nJNzS_=s ztJaMG&{v8{PsGaD1(e@*35H1sMQ^KA@7MVC&G*(0E_@T0ntfvu1;4YxDea;ipZM5U zUd#@QDCagI;#ZQxd2r}CVT2oi3QDw*tPW$E3s)17v+ zwD9O|Zl^%B|M@My2M};!)7Fo*jOHr-V5bbiPP9B!3o@;w5YjDp6Z@m(7k_%PP2;|M zytvp^1GG{gN`_kc=lew=8o&3$0v#Ay^dZf)P~h%fb}P|9Mj229xTl0f2OnX^E=9FM z{F6R@{yI{qiS3@ofcQxh7~D}m@-qe0%$uDz$5m`jGijo9yX0r3P2G1U5W#`hz(&K0 zbj!LIJ6>S4Z=bTZg5dM8pAP}>Wf5P*_Cl;cHI$@*HyC2y_a?bAx zKYhfux|iP)#SLJ21{9f-tgisy1VecCeg0rIHsK@KBKRrUmVhPQhPB8NTWV**-HfC;ibOPd{6;DXjT7Trnj6QO}wv1ma^rG8F6`kHZ zHXmP1QT)$}S`t|NM;nzoMid2wmbvtS`8IEJ{W0egC7T(w`Av-ZM?+zxv`=G%fwtpC z@C{7pqx_BI?pV{jp*(eSQ8zJBK3-Um@rI}C9~HG;z@jP&5$z)k3Gpjg-L{osVNWVj zA-msP+inznk+L;2h4(5A34x?uKD`!=JL)fMXk+{t34W19u96;E#(}cv4_*JLn^s(i z=udPSfM8%#wY!ID$lmJ!Mf@`prk1NXuC{v}GP%!~)|z3y z&iVb?ZgyL&lJHx4!svDjyIKFZaewOY&!z&V2dFXKPEuKAT0mBos93tWV09!CcM0Cqfm+1GPuC*YkL(pDJw(1x{)>pnGI|nig&aqJX(@Hwr_#3Z<9Jyo7&l3;KH0OlND=8Z zKHNZKnnXDUD)POT=}+vr_!hJw$Btw49Vm-~;M!-24up+YVgTB$+qO8OH<>_sWPXOs zCG2ZK#F)(A$F#dlVizM`=kwhF-;6=DU3AqpuV9_umgg>!6@mQcJ%3FPo>mIHw<=2VcKPh}1XV;%9om+~ z$UG=FlLWBSc8)m4-KOP&8h$#97wphMA|syfiHASRak5v=$YrscQwI(Q_zQDc$&BBr z^mqxxQ%-4rJ!P`Hon-rzS7a36j-xc~csQ0Ysfi$ilZ+_bd+e`g+bYD=+3898Mie?J z(TZ4=5#vbk`Mj8BoW>C_nOQ%~g$u*o#HnWuyn%_>>5I3FUwS?rAaCHX_fae)r;CW7 zp$HIvWoo)~Jo4*UeOD%e3&39O9jkq{OpcXSiudH+vdV?#VRTk1MBH`4TTk9v*G=w1 z^D0Q=P!lbP5$Ff)=cCHzdQ0&|Y1R3!+pbTB5S=3zQd|2WTawrB8-^0%og~mi9;ada zSjdgoCle)d66S0sn0Ohy#tI{+^gx5|f%@-vs2UI(vyLuH*I?BykvE+%csZK89%d4M z9>m_+EO~n`44>3h`ZH`d$!Bu5=H_hOtM0-kmn?-2{3aWcFflDZgKUg$}kA`4vWt(9(0RttfwOwNKgW`LdEd?|?mK z6%vlBj^z4AH4B3nlARy%ZFDQ1I)+pqWZ}@=Ez(>5KH0Op)=f&s6G&vS58&Y9{DBD- zB6h=To-89Ew{y|n+z0sfLu-_88Y^{$V+V?%cdhsSP_3;BFf^;fdyEFcLMGkMmbaE#-sY+SRT+E=Jyf4TYMJEeO= zE+JoyEdNvte0_w}FJ6@2dA-D)xUai40TMKXH|rLm`H&Agl;d zLcfkvus!}uda4!flmwMoUT*wPw)}}r8DbxI@=5aXNrLWJ8 z4QIH699AF_LA1((Gq2=#jFeF8Cp%Y~s&1XE!}QM=9rLW?z)p`}x#MrUjoKn~=ib(= zTk|H$&s^5rH4?#BTm6ON<%@$^43SShRM{Q94-+O8I+V)$)76~o&oC9POV6yjV3j}Q z#?!G!AUEOd!Zl@enC{`q-R65}G>K~t@}Pr;-+$&~Bdf=W-{)}4Q7dy{dcos1R#Q*z ztg_e#wla77&Hn~IXnW?PnsYtnyAMXy|2Y#BoN}bwgzO8_B-gCiid4qufM^NE!K8um zvRqY;n&#nklY&!{gU7X&4iM#l$r;87;8DuQ^$xS?iw`OOGigq}RP>gYXvbO>a8 zkzFpn%_3vElXn2EzyU(6FDRgcxy-h9f}VHj@{6i&1_DcIJSl?>1Y_8nE>FXY@B*TIWeGcr=fUIXy-&_UB_?qq45Q z!~ES`0osd2dbIdVLkfG*ic?{Cg9+%QuwaCOMSHy7NJCK4Y!hMRXJ37RDw}`8K$>!! z^J;k08FCoail}oFF*M;{-5oT+ep`5DNF-1-`cmx5V2UFC?OO1obaBqoa1EOSD*eIl z^1%!#6?Z&wJzv=HK0&b-k@}d~w--U7xQ1o6TLS0%Yx0(Yse$NYD^5Pl;U<;~@eE<@ zPLXAyy2*!Gd_53-=B+apPAZy+8aS6Vd?pFw*;iYE;W+ECr+k!cX&Zxu%sMZ^%dM^I-CFnWK8a^)6bj}>)guu~U+sXI8gD}j+Z0dy^n z2u;RW2*JuxOi@^y2R6faFSDgH9Fn#;esdm{4qAUa4A!&@uUCI$@XP3OJhb9AI%Odv zT!kxErJvQZ#C*=Bh@$xe?}b(+!iGMsyS7kGc~=(Ni^HCRzt0oCuEMq@dL6U~SRkp( zi;vkXxlU(6ZX+ZEhgY8L$MNX4&K?VI6v}7IQBwfsY zbe!OWa})IH9_`XS&Tpz4=Js@?M1WE0aVx^Bhj zR~oDnh=q%-#w+j($Kdx=ILi|Bfwc?+&^k=w4`Bh{XrEByLXm_V+IjaJ0)6D}%%EcU zjtiZZ#o4vWSJwJ~=hqOCsf*vhD;p<*CM)DM;%fg=X1{s~H9FRCB9+@7&Se0%$28v2 zZf7v(%*C-ZAtC&_2~;}VxIV==(ZaV7@uERD(oja{3#b`wqoUU4JqbAb)+j(nXDM=l zG{XB}F9mpJ2h2PM;E&86>`_w8ke0|K9p+6F(_I|#8*3-KrF!xdXVZ9VBZyTRvc5X3 zV5uGxJ*u2Cw*fU%;RD|oc#7^=Z{1j&%pq1}D@2^?SUtV)K`1SO%OS&|FIh&CR%mv} zuAn3D$pjjYDuH(LVHpAHT5T`d=YToV^K7qshMiQ6LR)SVMRp9v>>v|n8hIg`=FaaBI!F;WARj1coB9Gpa_;*> zoGSImU&-D~{0#>7-LBpUI)k21P-Wrk1TGZdK>cx5fw#E`sohd6Oj7+V)M}M?M#Xqg zuV2X3V#Zogob{9mWF`mDhA6dlM}m~mij~oZt@x*RDqUg|3*m#Tk&<_6b_Wik~+>hesFm$vzN~= zX`&w>hDjbqECyOV^PO+8(gkbXCTB^<*Ihps=>*n5BLcmM8DpX6)edfM{DSd`eRbC6 zKp)bK*_8SwwO_CCm@cSn9Z+M1D@T8dSPtixDC_f*khN*-#GKQsA#O(qD^Q@hvf)}- z0HSC{+0QW{6QXAsQyS*uWtpme)~Iu7V^tL7On=878RF$ZovkZ~-|Q+TUttMjq9B|k zO>TWoOo8|iZlMy)23Mb!E*+1JL@?DgxVFXY82fWy+zaUs8+Cpkz}?==^p52srdl`t zAfIrpvn5oynzPNGO7M=VNVzj);gU~q6&7WNzH(A|B9 zO#<%G6_c_>_?_ARcJ@pkH?~nx&;>y4)W+D3;~Uibr)ghXp|-p?XV48Ge3rC9QSoQ? zOJ0Bt++j?rW;dL((lYV8&vrVSBKEow%t@+4%#tNPXQ8~TTE#iM#VM-zLzwqpKzFym zF5J9nlv7gJWq&u3&|I&rNZ(>}P+*V{6HCVPrA^OkZg0i%Az`WUJoOXWNzj%NPer3U zQ1aY`O12<#lJmr(aW8{YTX&C(bfIH!Rn4*vnE4PiWF!}%Dp2KdQ=&ilgS370bpEM4 zfI_)}Fa`gy>kYpq*Y%;*L>=wkH8EvepQ4{lm&gb5j(zl+K3T-J1oqA1Jc03^eOG9* zfcmS#1?C8QzH+yUXwg!Ns)-N|TN=FkwlJ;>A4Rq(-^dDHc1_FpW~~5cB4AlN!<9u- z`!=^Uq;t{CVmlwsH|rHd!TFk->pa(G9n0v~ky{Es*L|XctXJk+EjOM|4mLhSsbVwb zD>I!<3`#md9M0+wS+j13Xa;N?Jg3>|>u}%I;?{#m27SUovU--mxsB&8bQ$Z1dH>={ zpW{`L-uK$s$M0H~_Tk31-U`d|`@wba6p7a-EoNQ7mMhLuQGf`~T=v%`_+Ox4PeuG* z)zXP#QKi%OZKVkw#0hy7Ib~6w%55UfZA@fp2ZCMA0u#>LtJVQ;a{*hJ*IPP1t&op? znc~-}8c3GhoZ5sF2=$R_kY-#gT$u3Ho*9&~^K9xleWwhA+~>bH%Q^13+9JDQa_i7vC6S-VOs?D!9+&VYv(AhVZWlLc?HsOTlB{uzj5 zm%)FB>|3&&UF6aX%gFU}?6r)M)51DIJ;E^;Ikd5%y=O9JbcTsX63j z6Wtxl5I3F>c2}P0Q8Mk4i4RyL^EN{32@n$YT!|_3{I|Q98nV+HjMW zBWET?GRWff^A0-;4h6>i_KU(QLtj3VOVH+|w=69>GyOSt&g@+7FQ87D;YoTaa<}N; zO=SD3hs5wsyS6)0C+nBt*!)mszT}ejHudWF?_T|yP9&R*8brhle8)Z}1F}BgJSvk@ zrjJ-xe(Zc(6J(GzL^8CbpsM37_B&a%jdWWE?M3*}q;zQ`Sw!;^W9+83f7+6x9?5J) zOVN~(tNQzqD7~(eWB))0R0PA_*{aHU`;#-3slUvjNV#&+SCDOm(fShM;UG_{Wpzln zxjdQlzny6K)kE0SCt%Om*Izd~U!K4C*ng~q-}%v=9};pFS8p$)YvfkCsyz3WYxI_U zqvF8Tf))Q02&SSnoon7|h*w3!ynE5ss25Y|83Ra#*A^T_B!9AkU0Uj{d9xZ#XX+G^ zZ1_`t4_V)-P6Fkg3L3GHZjfGR6wgIcfYiJ0Ak}HeK{I{vOzm16i_PTA&=|{{3~83) z6IcoT^+LFrJIbYjr)-Agq#Sh=3IG16KPlW9mE4-A4(|xgtJ$ED%w|#pnyz#wR=*sxSsoyMAd;6ugzrTF-P#i{uynzrQo&0KHByt0+ zsZ@v3mCsMGq9jQ~d9RLy8YKDyeuvBKkN2a7j1c$!-38R68BG(7DUU|?)?C0oTHM|s zT0HC7V@{ZDJBeVr36h-cm(W&rcUY45hld-FTUPXD{h z@BoL8!H`PUjxe7b7un7=YGTkJIP$IvtyRO7r8zOZncwmV?`{dfJXx~3Sq>XSGl_XV zk$sJ07ihchfmlhAY|)8xYxU@XXs*eBjZ#@L&NenP|`9=hZ+$6Di1C zghq?@XrKk(8m6&@46pn+qbP;(uotQe4N~( zydc=w;Zbvskn6NY$5WX9DZE9%a7tNWp$ZF}>`y&%?J&pu^Tq^9u3F94iQ-@XavWTpT-b&zGFzh7|G2HwI{*s+^vt05~dPA2x?0;|9nW zMJt=hDNh9sJ#bl1=Z))WX&&!BCFr%xM9oSnWHn)W)n{w{uhDP-6yFA8-;wsCru3R9 zk~N2)@^-@QKp*HiNyF^nb1J8tZd5(3qK(o_Zh0L^ZLjwD4~apJQXRS6ft@k6av})U z#00zC6p3Y(aQ)6tjic zv74arXyZb3Tm9>7>$XV+Np)5Y4l*kmA++Cw!C?8e8es-0@mYoe781h<3UvVO?!sur zR}Eafu`oua>9{;J855D>@2)uEfol;S&p_f?ff~M{)%j=u`<_VBZa`iop|&OVWqj_0 zgN$yl&_cU>o}jPO*tQ}lJU5|yy;nbtqgtyP@8WlQfi5@D2?6Bw$ihto_z*VmxRcjaTyI^+w_QTs%3A_6-_ugot?EwSfTl|w38higNg`8hpH@P)Hb{eiuh5()EZT_&MQcKHYjA~n%w-AG#}Kc;GQI(}GbI-eNqha( zNaL5b6E1vojHh%}=yD6*Oz%$H$_F`+F;N{#q~6W0sl573XI7u?H~sAHBP{h5n+4LR zjbegh73SREbH#x!8_JG; zv|_&*uV|WaLj9poM#uNT@v*D`MF_*??Ecc+TTpQoSDyR+o=-YU$)}V1+Fein>q&*`3(XEmTd3+?<(cgE_x^SBr zeQe%ugrPB-$ZP1XVq$6eA>t&EQ%trU&OO+JhNkk}T4Yg7L7pY2VrP)??WlLld2M*NtP3Rp>KO zzbdJLdhkfOtK+{VJfanIkPLwhlm|*3Fu4ie)$oNd#$UL=e8jYshm3(vpG%bkuk#7GxeMe~->Yx3JH z8|U8F2=c#xFU9NGqCeu{A31sx^|IABq3V zbVSIlSURU!Y62kwI%DdijfaY zWWyx=E2+^oF&S<3_fFvAx`V7Q618`3nfk~*fwBq$Atpu`7$QQ3_3P+du5h=;gUiK# zT2yp}GM-ZaN`K^Lj_02gg9Ynu1Bqg45QyP3>=E0UUPq;pk4~67RJtH5W&hgwiI;M1BhjDbSPE<6^giWxSki%i z@OF}N+;DS$Ku&mKF!90HfnMhjk(D9;1mTNxw;x0emn9M3w^u-G5&6_IS{D+%BcC9< z1s1W`J4H&1Qy*huCub|A*hz2>w1{9mLJl|!nH>iV!Cv{k>iTBK0k@||Lc}<3c4%o$ z4&o?>4L$nG;gO?O55cTfu3*FxoInla9nZ`7#%3{0lg?+t->Nj9P=;q7O1}~t!NzaEc6mF83V7_k`1InGlRH5CP>uw+|0}Ew)Z)xuzsIYgeq@?1Tu<$*wM-u9(goFeFj=bSeCdw+#gZEn>HoxC=+M4>Zn0FOS zvNUuB%>f{M{z;-2%jZX3j9!sM&hLoW)dNAdMNAT`rL#>nVn|(tnoJi1@)b{ltnPG0 z=|i;OaCYsVfAdo5;r=iYk@H-Sf_XtSvnK#1?h+_SZcU^+1oLGvYqfU^ z*6961Q)rjV0z3vQ(f_J7lV#eNK%hqW%UwP zTW*Q|6WAgvZmVE{x0|a%TJKudq4q1P8-W`Zp~s^D2?NdVgIsvdU`?dsN>wid=xK%{ zUlC52D_CBiXmLo&1mmlHLW^-o-95P-667quA2Mwj&K=J0Yh<%HTw|sudp2+4?r#LsrM=L z6S=o@>}sfiwmceznxeD_$YwimvDtebvbpBD`U2ov5{$7**9TpK-NmXVpLJFEc&8KVVUwl{^VAPRS&E8=+jBg?FS@>{%f z7?{oj5j;KG;%3-UHGXCSXpNIk-lf@#BDtXk?vG7py)urFa8{JMgKbJw_m*KeQ>#cs zb9oBZHxN7FQ7`kegVKFlunq+t;OPE&ZAS>VYDz?p)Ukd?Blzt|?NUHwY-2NM< z6%H$}lBmVB8~kq}9elV}kmtb}5;tFr>j|u#d`a$N!9Wr?zO>$bjI`BI!kEV(H91&P zbu?9*m-RmKp(WCH=i}cVhR){dro8L~?Z>1p)JY7x`2J?+OIy8)gn1wbQYpp1I_lJ0 zc|nf&G7?M4IDJJQ0*MBSvH{-WM?i9^4c-sv)qxjm25Ei_g+XKZBj5O0wv}uV#UvbrJcYZ zK(dNj(G}w9+cyE78WTYVW3h?7ZAvM>PKlASOB%8;qYF`@cP-~q^RVG^7}c=~mjJzI z6t#-f4{t#@H(5AKSFEH45U@vk$ikyxmObUfG9hW9kd0J*V+k#i(4u;Esj$d>r;G{vC3g2x{Wna7li{_zTA)4V^Iq7#GxZy#Q%XQOLnz{lcv!M4wg6lwC{6h`l>zqi(-y)C)$-*|30-&9ieQIl&h6g%;3P=?NOp zSAaoMF7z@SI*DUrQxc*Vxu)=q22YD}^|v7Xsg?_>p1R@k&`&f8$}|@}on$K)Bjp>; zpWz54vX3XJIR>!RsvRnlh+o`{a@s+>F;4Y`x}w6hC{|-j(q4TloDdkTzwKs7%Pi4@ zR;POjw`3m>F#wjQ)xaW?6qS;m2$QLoooV-}#ao|(?ajalp+5px0}A5+Yvau7B@n2Z zS=SsvDI?$e<@|XW{XXGbr<@tx= zPx1y!Ar&iO*{ZAE=}>A=Jw_dE4KLqSfI3HxVoUJw^G`+@?F#d&&5p{)>E?Lc$4wwR z?J2st&9cP+yJ&Y4i27e0K}VxYx1)MaMo+hM8IFGllr^_>E1hpW{7N6m(ljC=I-jg$ zCd`BuowjT0kW-rBj7yh8{vqS2L7^o9{d0&+#z<60ME=sz!#kq5(#73Me9+Uvo*f{#hTdXgJmF_g`NCYFZJA`;gvvfpC>Zp;3g!%hWwbW6yp(L23b09|azpQMb9 zv);&yKv&wpl#8(hKrq4;|m78f7lj3Cpr1a=K`CxVaj>>`c2wGMHJ$W2j+FQ^v=*O{% zY*cpAzV?*%KFWR*+hGZDrh+usvF^(gR;RLtya92gz7v}hn(^MninF|L9(ynHzA1xW zXc(4!sPHVESu>VE!604tMd*#U{GO(cXGf)%Ygr&>nCTCb^)OFZBwf!&A-*~d?AEjBz1pU?n|7Xeot6IU4!0zD%N^p%TmEJK+b$w>En1;Gd?b)FCzw%bC{LHa zUrIMH(cxPR@F(L(HFtX6# zyRy0rr1{rPWawjX)M6X0+- zKF+)(PRipX9@>+`eykb+Wj~!&=K48{COD|TjXMZ5L=C0nwRLx-R#*mpoMn@yt zSq*r}=b^fM&BS}R5*13R`1w>!1<)MLSo}w}QR*ALLvYF}DuOUdQoMxty#QIev)R26 z&{Cv50k*HNY<5f@PRNPaS9UG=t;8G;dFHyp!!{Umtr{SWLGV{1z>_iG}khsmB>} z=gyb|S>GUqLNpn*l4Ys>G!YQw6v~k1F6w5G+@i+)am(I zZwjuf-O6?kaofBudJedn2In5otvj{#3h#eI(z*a#*Ri;Hh`o#qEKkd+HxK(M*)2zY zK`~rZW5mQvXxW_`Exwcv!cWIv%{#r@5!Pj6xuCjEA1IE3qIc96>|wNEUocSn=q9?> z7T1)oQ@#s}Pk_UiCgqQ;I z;`t?|7`zzjCaBWX&P5j5YF{H>Po==s2_Z*HO8?HxQJkfo)@)KTspTxZ|@{h^3kZC-?#cwRQK4cG^F!2#{|mUVC@9j@((oraj*`G&!g>I<8ENw@tIhY3eFR z&eB1ryo&myl)n}~;W3Qs{f6~9tN07aOm#V`;Ap!})Xj`|8QD{ecN} zwSCVqyARh29j3?!sVctNFHXWD!UXl|Oe}Oh9T5AkL3V=R#qdf)5dW=aIrOxU*E5A5_LNFq$NDHnN{;J^mRfDm?ASW4uV*rezt4Z4RoNWh=k zY(Lir5J8oDD*T)5?J$S&x)?b>MBmt5V@P68SHpKvWrho-pl1kqUz+bRpI5u$ z3xa(6>A<)$NX)8_oAR&DfX$dQzl-z={*B$*4N`jYMe+{16PPu^yV3WS4;*j&xK*c5 zg2&%pTX|Q={_wN~Bd9!F^IsWWA6An=1ta(ACcXR`_-;PJHn1|=*r`5?gI4+5O~ddQ zK9Z>vW#-BAQc<+kA`gv+5chcWS81KsA$N9Nb;a7X9P|rc@(w%N%py&|JqKGf_ooz_ z;Qe~`lCV7XS1gC#<916JJIZQvW9&JwmN$4Kd>1?MDJB~PlyuV2=gC>tL}R`fD6kZ; zjQoJ`#v9$lUTOe&ufYO$QpV?R2Jv!O0&&?KV}7I-#Ne*p6-}57@ypu{niuqq8Q08l zC9Y0@r4qmLJI!f)g_ImKUYjPJ9=}yNdW+s4!lhpu3e#%eEfv}eZpDj%&mw)11y=F& zo!2I0NLM+hyR`MFYR>5aAsnp!5g8GjbQuN9AJ6^8Y>KdsI&t`gPqbyGLHog7RYc}5 zU`qS~M0V^4scK|WLD};RFWLu&6?0aJ@4%iwMl}&_2~g8K#M>jkV1UT@f@hn#$@1Si z^^$E;t#4F>qQCbzv3Rzwh4Au9BV_E`?^X4xE?DyA@7%;%Wp}VR4JzZ7LHnNxi!kZz z_LzjNDJhl$R`Q=3bEw&+OoZ=eYn-K(ru0l$<&aJ{$uilc23ian%*x-40MT)b%_xJT zWZ*G#yyF5)08QzDRg?)aV+;zzwR{lhBDw?&vcFpxSz(z;5H?3fPM-FQR3Ho|lyicp z;q}0QR=@{sITdX7!slX(pOFT?Nq@iBx({Hy?t)uif4?o|N>rFp;U6VE%OiE%e*`CL zW*#?9<%Atm1XQfX^X0Mj*t4__@*5ag3S$^sTChEMM5)cQmE`Y`r?LqHk?$9 zru5-?;{DE{Rl3wdc1fMOJ5*+V>wLaf20|S}nC|o5ldah>Ns=k0&RSsmr&T)cX`obp zlvOa3A(lDzoo080K&*gJb?DTcVfaa5uVkJ92}C(j&jA1ff;g6HUVs7o_>hQMOPu!Q zqbDN36XEqR>_Q}(Dm^9?e>QM{S<>&Qt6x2j!D5JWmwtpseC0VN_~qqt>VKepro)V) zs7|A>>`gG%rk%-UROIYUSS9gqY7FH_%^X1*AkF1+kCQI(8KBx`=+osJmEWUUf zaG=dAC~KZYmF3gH?ZXR6chVlJyh)X{^8Cn&CI0j6U&A~~#UJAzHYUKs{;|Fc%2P(v zzs54<`*!*;xl4dt5jzRSvHA(Dz#{Dggq8&UEqDb0B%sm|q8e%7b4ku&60|yYQ9~fJ zS}xAf022WKVvrl=0uAtgccOrOFf`5t#qyUH zF}Nti_2uvY#YqGsNAhiOxuoSDuImVBExf*GgWSN=bj~J=@M;!Te#<%?uRe&4?O727 zQb-SB*A3DtPQxy!`Gu|ID*c@>cAU2*KwN+b@fiXr`KJrr!B}bQ=TY|G(*rH?c&#u- z#zQoBNY6FpjP!r77}7TceQ)iU?tHgtBRr4PX9B@sxQwv6iMIPTqADGlU6NlA)A>7M z-q}s7&Da9M{=!SA+dv(~Cx)d??9y9WS83Ba9m3kk=95dN89&XHeW{$l?uDCe_QIW*EUsdNVCrl=JU<};LNVBXIt z1lfxpKXL-t_CMF;-~jb@IdOu2*YiO=+9{_w6FYk7q~`K~;HZIRyIf}PsJ=j$G%5%{ z7C;?m!ybMPF+Wi*d?-c3T0~~3g-^rOZ9Rhp%^bpWP7g7NeY0P|SBuLO__8QnaUMt0PMBt3Gs>M&aL5PI>$e!yqb5okoRdTC` zs|@$P6U563JuO&u3-n&^idX|n2TefNJuQn=`WFeY2LOcsi(fQ}+<`xcfRnjDErI(6 zV2V=N{~t^MNar)&Idw?`%>Qhi1pg0w0ks1EJ&*1~M8Iha1GqGR-sa0@9WMw9kIg+i zhHn=cNkC5n<1w1_7t)JVgyDGLqcMWAzfRawoJKton0o{Y|G7{^ZxZ#Rsm9v_UA2Y? zu)tFV60V%qNhPgb1J1D3kcd=XTbX0GX7gi<(bqIM0bA z7F+gj3o<9FAOrM}Pv8qYfnV+m6gNB}GcXn}AnRXh4&&V{o)S zG__d32-1Pytb}l+ex=igBwd@urGie1YoHod+`g32sup|@Wb>;7@tQN2k;woo9L*dl z-K`eBvkx=c2~dHjMjE?i(vogK9HcUW9Em+1{i}mmn`X6>U|~IEzq7jzj;VKm;{}(qJqGI z&e#A}9F_;K5{;9F9?jzfw)0m28b*f<<9y{zY9q8h3P4`~MgIUH^)ocK8bC+ z(a9_cK%w=1M8rKeY;dQeycQwp3bOOM=@{lsx#sUH9}m@QGhrldjtAw?F@S~ov+0in z3>`9Q%>vpH4csc-z+lo91(5zZj`X&wzm^VcuQP*;XLrs}nY2glLgU;tE2Z}&>Lyir zXtY01SA`f($v*Uy<4iUWa{ZTi+5rHQ|7D)Qzsv&?u!ni@|3{2}B=Py0&FcT3`Tz3; z#yJW>xY0@4bK-H`-Z=_cTMSR{;@=PYkvLasoRp^ee`F6MT9NXR84K$uCytUlT;?7I zy`+#a0Z9AT3$rUkcGY=I(S!~j6Z|A(%u zp#LucCmpv3AU-a;eHX=bZUklW|G*1v+Fi?uKs$zt*XaMxg){YyCDg)WKOvF%;|Kqr z6Ew3H8zBle)7u_`ZWZWPcn|a8j}}FMrRqTEOxXtIU!Xm2&|Se=R@!I*bLpV0H%7@GazxbTf(LowCE@>x>Zov4(g?C&C@#T9~*i z0;bn41=>Asl=NCaXiC9H^Dolyv$=@P)FGh)IJ9X2|H8i|>Dr#7GnpM3__m5jH*uQxV9V0DA=CIU$->vK)05tTCO4iGx!Gf`3h zICGPo6|XobDe)(}jq@RPuf4u5YIvA&O&Uu4C&RLv7t~6adgy$k5@*}zuTRhIQ@Tm% zUjt-t7(n`-Ffv8che&4-4Q>|4uoRNl?`Qvw5Xt?I55~vtuhq(|9g2$qa}6ya)aze# z`{F@|R#+2MbL-Nh==>0UzgRch4ZYn^DFNT(k|sIa9R<;uxG&ec2}9N0*aAE46X4i9 z>p=0myT%J)?J&W_lrTF$gx*6Pp$y7Y2cQUl83$r}1JwW^2U$^mIo~wC{(KW&o5gdd zCo{BYxY+KlDmxPll1{7sFh{USc9V)Bj+8uemsq3}mWI-N(WS|+wmS1#nrP>f^zy#C z@`d%>Pa#?dWjdTv3d=7(kk+0Kg^PrB%mk~O>um^>Hkb=Q1-{^hnXMtM6_yewL{9#D z_mU8bhLhy+zDiv_?j&7~M?sl&MX&2CI!F>74}It7Tz65xg(_MIRTVq=uNjb#N#Yi@ zvO)vQVlkKwC~qH}VxY08XTy^0iRq?xMc&4pa)|kjmn`Lahx-p4iqcg=ZBa^jBCS7Q zOVge=Fkfy(YxkN;nq<|7W&%d17(kTRHNUC=GO%Sju|9zEK(cOcy?+%4EdWsVzntLs zS8)LS_WvmU@0)I_xPTe{Kg&D5ZiC>T31jMWFYbR{n&W422{83Rbe@L?TGclW`krES zjdt^Q^UF%eXM9Rj$0*%{TXdSwm0lkC?L+1d6}a`wBSLmX+*vOS5MOh}1-+awyPf9- z2&40_cUHCQ9vokBF7rE}WXae+`^ijscx;&SJa#AKvc$=PPO4GK<*{#qZBPK+rVIA> zS?u;RB?tv@%%ReQ#DYN}G*Mc=iu_r1+i%j-CY3-&$n|~yw8v64no5IYC6?(FL4uIr zi{7xkWz%P^|8mOx3p8x-K3f`P#Dx-yr|TcbN#QXfTyMj3@RT-z)-Zpi2@j19YAw)I z?_VUC762IkFEDpN+@Szadz#|^zyW~LA9Dsu7rs}O`Hu&!zdGdxW*tle3cml(Mbf{k zJ0g$jK@|70D>oUvSX2NQAYxzYfwE8RtUrw=$Kh(gJ@SPO)Bg%#5`XByIjb&($L!wk zbi^i78Q>Yt2u9pGuIRs9ceu|OJ)i7C>s=ztQ`<{95!_=b+cp^?Ka12*x-6Y#2zSZ%m#QY3tID zpdpi0lJdT#XC0h&#R_~8kLNH2&Ed7dy|yp1aD@-SNF^Ct#*c!P4ZIr%tlJr&BV!Sy z@bAUz=W|r0^WW-uL~oag)*?n7+ZJZ6sG)YSKphH|M&=-CB0BzQ&xIH{K(xT~QOXi*H78S@dSH|9G3QI;(LaQ?r@5DI|( zi%ih}I16qdRlUg8|1S&xbOX}?IXFahiSPrU#T4P(0;(tA)(I-Me~<7D_~zU;JYO+T z2F#cV>9Ht15GkN^zKBjOoS-A!44rCSLC(YCe6r%$n}^kaC#jokGz zd~!1SL#H{vzY(j1OhSm`ca}z$zd%auEv|wMh2nSZ|oN|81aQqJ}np>^@D0W zIiCP|_{sY>Aar?Q>_>1Ff%<3@fUQrO9Ps?p_uDH0H)5L2J@iC=#a#0D}H6aJLH-p#TOa*Rsmd zA4QkoA(hN^8&ybFX=;?)?An@1}31!2b%8G+QAIhd{uN>oPiP#2Z$GhE9aM{FXNIM*KAY4sK+>^z_k} z?hWf;()=ZZ6`<;FK@EBMI|{tgdFtWV@W&BK^hr66zPu8)x3e)os!L_BI5kd?qy`IS zV+L)QJ6xZXU1?PBK>BZEkr#h7;oOn4Aj^$|KoBHBaCfW@CmK|EdTF#p!i;I19?>x^ z(Gi)0SQ-9)Wz2StQW2^6Y_W4zmkt{FL9^@^>xJ(4SuoQ2{b_Pn0<$yxF0)=X1(}_# znGK$ic;}4|#W3W~v)*ntVhDfSY$11hKnW~0ZR>~c5NO!*12DS==Qc&a?`>z~Bu%r} ze821OEP!u$>7~*rPqw#OHd7=^w5F9AlMG7=d(OLn?m-Q9(jU$mP)2}{Q~2x}D{44A z;*Mvd{MU2#qzoH~czdj9ASFKFx#@d-_rU0ZEe%S~nzKH30<+gi?hECe)|D=*f}`?{ zzud30Fb#cOIKO6Wd{>>yQ<8Ks5qi#bd9M|l;89(~*y=axBkEABjQw?~ueEyv{!O9N z8a2NXvH@kgN1A%PE$t12eMnQpo|O=^N16dg&C4fpHR~908$y~AT``19JCLzS5!xqH z3>?>HuywQ`;rK1Zr{-2cy_KG1s_ zf~#-N7d0Z$q(e(BZSKREXS_p?pfvS*nKFhC@rNQ!#$CSw+fplR6JEzzB7}Illw(YW zZWT^Mq~@(L-=ao1TfNuuEB&mdutaDph3{bFkD3SaN8jv(5^Hk6a@^$)fvH2feT{yT zkt99R)~xGbYnD0)_`COFrH}F|iZ}%V#QM|O5NISt0aK|eB#*VJm$*dUlkVX@t;a=HR_q!&po zj^H?wkmz({x#;1q6z!}PjEdR+5o%w-HURd>88sstZiIj9nt+T$o%J;(GT5aJt;pUQ z2DszG7)b=E`h)$`&aIH#y|o4y-Cc#b0st2RZ6*-#C-J;HuFo8LvgjsOq#I7$_PpDh z#K7f)FqnLWDA+v@4i?xmZ1u1^s4zk!iull}Xy!I7v4tHtSdA^HAz!fYt>H@y!=D-O z02d5*%)UpvgUCvl3Iv-6=i}f)jugjU2?|1mnlnQXoK`A(LcmB7FR3|Ky~K%WE$jR` zw7J>wVEpAG3ypK|4vVI=rNJ6WHoD@+2e}u;rwKLqSVtL0S+*lvwdXWkFEzy73C;qk zP&KM9p1SOFEyk%!M*EUJAH|A22A-7Ol=jreE@VP;3TA$?cNhq#%YcK{V85$$KGKc% zsVWG7MJc(wp|jC2$uRdAhiL>=Vk*%pibO$A-5-ZI!j@9?&PX0R{O3}GQbA@q{H8Ln z5e+Hx3>Sf}B8BZwtMs^Z&Xbp@Zv*bS1@1qdpZ^6JQSCvhD{ zd=oW%VZEELW>+ez#+7Xr(`t9!&t+|j_Z2Z5>4(XJ;7^0kM)Oz^?^#=4Zp#m)X>Rv0 znz_2^S(_f>;8f7qxG?Rf+iL5eVv&SzAtJW0N&O6&&MQ(kErC% zFakITU$#5)j*(12nO*N3Wq{mm3euv@+D7cz$QRdh92JSo;HA}(VBdao6;3{?t-u~H zE>a=zMF13ee*ID9AmcsKbH?y5_6b`x>M_L470{djuwB`N=r#ymRfVeOW- z%=GPK$BMu^U#W03{C;(<)&k2Vl{RJ8x?jA>cg?6WI|OQHAb=^0!Y1aWmCWjV$#D(< z98XN$s(u*#J`U2R2@5pq+lHXhM|z@%2gclq-scBqASAYD^r`n3V>J2$()=$}#{Xgr zD7$meOFhJ`;<(=!1puLUskP5(sebzV8BOoY;HW)tA>JW}&5S%?_TT-&6@kZpT5Nis z4TJ}IduI>zFE_Z8c%s?Yv;uZ?`hC=Vm3dI#_-?}OaZtd%WBt9|7E77_qfTRT8RC%p z0D7NCHJpadzvP#b#O)zbg~dMj}Uf=v&QMUj>~kj-&yIU_}`<r~m#o|Gp(v`ou`)aPwBY4Kr_j{pcYNv?nm{%AD&QN3h(e6VTC&nbhHv)DTAUgFni>2 z7c@Ql42~PAi1TN>1mI~bkz&0h3-a~?#6^abQ(SgQWNiAWe$0!-86*P;Q^~$c!WRf| zktc)c*1Lrq%^@`4EcEf4GUl2?BRhuV0H1cU`8d(Xz9Z!`PNq&2@GgCoeGiAZL|-fu zZdH~iPx%^YoOWT4N(1Cy zUY#k$7fV9UtMa|wnzyMPzKoDbbT?F*<!Nwp&;Mek|2PZLW0D#cL zw+co$M7T6WCa)dk&oL*MWe+AE=6@($%-@?ecW0~ZNHoX0M56k4z;iTR-O)rcR$^$E zf7=f_aBB%^&L2Fa7f@8wlmU?MtA~;XL69~UBuExO5dS*N=xD+#j6|)JF!&O4VajtI zhZ{%21l_PS*i4;#kUug+&-h7=dH*4EzqBSzMu`6ESm1lJ;Wq!+TmO)uRE8TZ)1cP+ z!gXg!*R!BqVT*bYspDt-Zi3ae7u+6uw}M*i20(G=J67u>F}W4gNPR%K>}#WF*ikCo z5cuUV(2=CE^ZW)?<6{;(hAo8bim+_Jn+zn)`d#gpxB^F8$=dnKMoI3@1`YmP*tc&O zFuLh_BkfC0Tn|Wm5N)ZFADi{-*sq2*o)+fo2_+wI=icP`T-T4<7;vF7V$yA$k?q6R zr0(4d5=#$SblbiX2KY9b%-J_}*fwNd3*^LX7b?N-t8p}c-voA06J$khbz-A3Md+q< z%Nr=>d5x5kuqYVCuznsyf#zA3reWtbl3a0zBSVgk0^A+P+YzYJF08+rbif^Rq|^% zHdAe|XzFN(^y*D37)#OAIMz@VGJV>&un~fr-pf{crppT}7)H-fH= zLw&xALk~ep9ManB&-}a&bBzWWZ$i%3oCKlj3%|^a!m(@w$b~GjW7^d6MO|ck++*LI zQkMFzQMiy5U|Vk?8-YmW66uwJGz22-zw=^49Y^(C0+baPX?}m=H>BD!q0HrK_Aiu| z)1I`HppfhFUKGc5hMYP0+gTaTiGj#_7=%yM+OyCbu;xX1g{+o$9xA$UcAl2cS34J) zhdZMKtccL}oE9Ypp|%SQ*mI|on*e2+;YS2a|8pB;rM1}jZ4Bf;hOc93r>=ukw8JMf z8EIj&tt;anJQ=fNcD$A!_!r7kN+)}+x;D^zeL0i<{vMXewz5~!xlJF}yehMqn-M(T zI{zHZ9Ah^@{5|UP&SEt%E+{thDF0Yuk7Nc)?!9MfC5Tjof}kvs`j(>Vs_X7*Jr^Q zV-4F=^<;W!X~!%iwyEe7&3cci!L*%^t?FXCe`F* zVf4;Xpg=?aUJmW?cQ(+ovPd(y`C%iB0-L>HPer<*lW!a#a6yGDeK+Dd-Lnc3=BPZ) z6zIBmm>m}?(%g1^TO+&Az>;8Y)c0pp|M3raU@<4Oi^qjdaovk!3G*|(Zfp6|Eq$Py z*w2G>RYVAdGbEYQVoU#ue5CUg_&UR@#4o9tBMYbI4Jq?kV1RKpU&`@{@U&MCfKYuA zp4T#rMe9gH`rB3BcS2*hDNQ-M3f_TV5)_T`qN#K@E>>={WUxB>F;l*A*p3Wn3^^NB zxx5qvhdI}q09}#e=vzvPGSE|2=2U-+$1XlZ#9^niz`7M)5T*!GVj?VT0HKQ}n`d$Q;sw=qi%K8rG1*uEgF=bPDUSanH1tUjBQ z4V4f8JIh>nwX0o6J%n)C!-K!~p_*iTU`v^#{Wwf7*75KN+3Wk59u?IEnfP!S40^}I zH#~2NAMLnyAV3=_S}t_HyuZ@B!s)uFYDH-6KO%j;z`gfNsPc~7meQ{!R(LSP2LozB zh|YuspT?oNlEn(ya%ZKbhx8_{8pwz@mSF+%w0XTa^QI2-YtkwHH>YDd1XZCrR1xPDQB1_IhVdY=7|O0S68qd_PD*b{eCs9lq>4lDXT3wn$pQ4O9#F8 zRTbWr!~@`9q%LT-YEYg@bxY~>AQ3+*qRy-JI4`hJk7P-e46CJdK@NIzli?)ikU?Kv zub57EXh#$?UDJMt_H`TLhbJD7%7>FmbiD2vEId9KEwN+U*`dRfD_1)MW}=9d4}w|N7x&0Jro#kN@^U07M@YO*QDjy{ADM33Bk|<%fL->gr?8Q z3p{Z6RKbg4U~$FTLm%MjP+altpQpb{U6y~p-mDC>vNh!-P-!F;N+zCKV{Tv?h%;;g z99ub+w8)u~nq;bq@_QrH#v&`LUiay!by_2OE}6|ngm?@^5=Zb$%g+-mtJ_8hQTs%U-`;JlhhQuqT#(7StHMET zg2cAJBWbr=4#p9#0_JDxUG#d;*m};KaC&yHLN$sVM2jn7h%a9IS_+F*u8t$=;_GbQ zwi+6e2t)QqK~2*VFWhHR)=c{&!(Z0*`ifcOrzvDX_mkJhWbIW<;uWzl5s2HQV}BNM znKO&aCVkK%t*1$rDwAEisN9MVL`p-yO_QgAaIxp;YnZ$&nUjLfVrJG% z%_>I6TULfnwYg8U?t~S+v|kHa;Z~X0Z*c7ZbMoAPf<3JM3lq;Rn2)Pf_Qso%ZzRE* zBGmJv+Kw19=~AI~PotA4J0C~RS0D^I6VC*6cq*0)E0N{WW-k7jzhJ2sF9R>#efRtY6b6p`nKIVn8M7?!QIX8-K>ybl`j=syI0_qQh)z>)ycVCi2tIK*|`7!RPDk-}m^ZI%_+ zupgjnE1+}i!l?CYv9q`Iwhy~{dxZ)|!-fF7Gl*V}dos;EmIe6fzAO&u!}cEqWVUvJ zOb4^9`L+W@q<}=QCW7X~=5IcbEeVq6R^(_{Yy=@tS14Bl9^M2}WlkH}KUCpd4P6ao zl6N(_o2Y8)HKH0Gk`QXtvY*|O2FtkHgD=v+ZWoT+#33{DfM_(vDCad`=o!CkRQwbm zZBKb@ixlX8Mk9}1S%--i0_GHVT{W7$l$=}rBV4kMhZ|l7-Ev`PmN1=~#6X@qrJ6xU z9#aaM8ev@dO4nk^Ce#gQdeuC+;*N=+_mhq5toY}zpK zjp;qS)}n|uNBLn)4!^w$44$Dm&vwg10F6+XAMSpA90((1f=(8FiJOL!w>p}Bc84p| zm;E{MbuSNcuqt{Hr3X@JYq+u$oxRIZ2P%z#bEL<=eah#BPBRJkgz^dpF1mgRhyMed zxaD%OyG_J75UoEwVFu55$QO$O-9Ilrk`iJm=H2mTrcLn!#P2ba)dHkNf|<1A6c<85 z4H-P9apw;cpPr|C)GKd@P1`@=wMN!RRSb%~CTskt5baTs2qa8qYAhON;ysE4W|9J^ z(raJxh8|K&wHa?lVZc?5tI(A_EtH(q`w?6vYYoM>BLF3)QT8sy&J@Tr($2eA`*K5=vkdT0Z*f5xcK`s`Pxxa_>+z8vCBsXr6m8ti=|Fc_r@72X80eaoj@fMhIm-iJ8#HiTJHu*}Ma~bRy+8kOATA4PDrYU4U69ZF1{BthwND3RGIg}F?uhgWfFkjWs_(5K~s@Rn`mq6!90(-QNdRA z;I4agh$gk$Bjf4J5mZ?acwBLbPx0p3=V&mkq90KY0XuZ4mArRQRnNp?+8c1 zHv|G#%u*h}NxU-%S*`yx@KmjivM`WWFX*nJlPIl$OvK>o3b!NcAn0`t%Eek$iOYY8MS;AS)SioUoTa1a{?|02&j`uboT$0t>8YYp9eAfcn z=OdfE01NyZXFBM2K>+wg5)I}oHu9g_v!?1()vN~Uu9)Ub2!fyQ#YRvrs&@TUGfgxjlhAgGbDG0QFAnWNcR*lKn6Xlqe7*4=mB%|03My_}8<{{L*p1$g zL(G#)KGv9yc`*+rLi34cB`3=P5G{O_OuY3Mq-BcVDVVf7u=ICDrl`byNV>Lu|E~4^ ziAtxk0?i!wJW|Wt?AY2u_TX^fd}5ebFl72$I~W${XnlK#oorT+Q`Nc^&{S43Pr=aAKsd z07SUF_psaTx?akKK`4ngp!OdWolenmWaT_oNw)ER8*tH#$jD|XK%OKbultF8_NKJ? z9-tNiExLR_mZE;J+Ok#IKd`>{pKrk9Q*ufTGJ$kOWo5FGefYr_aZ6x*U!-nDiEq$; z2y&+;2>)bmM<|60*)-*4g{-0tEG>h?d&0f7DwgA6|T=`Aqp z{fd~%)tQUM-VXQd^s`4B)=kmmv3r!Or{TT7_W&)FFHjAKue)D$sBv>6g=MCP5W5M% z@s9AdxCsj>wcInu?XmZb#NeQQOoEWnuQwh^V`9P1dc5W(lNuExQYdZ8 zg?%h+K%a`aU3mc>?>C4`o!g}A3;xB)ge1q{M1QrLN%b;but+T4_WF#dTpU^;JD8=) zzx()wlHQD}`i($MUxO6qU0&QF4uMU=D>&E$sBlp|3{0GkwS6PZfEWp<3gfr&N2%@= zEV1p--6cU5iv2*BTvl8X)<_|Q$cZPOf;~H7Wae`$WFGyr?9`66ax)lL3b$v1u#}+K zR86Ng;r&_4?YHokU9Oyeutugp@sC0f%@--)@nEtCwdzcjiQxPSL#8KG+BW*z6AW|N zBIp>24yTJVP7g<>_TCpxfOLO1Pd*$b@$eB_1OM%+T1oW{hvn{1_YW%~1p7pf6@qba zV*_2roZW!Wk_k4^+UH)^#i?;@sgztCl5DyDFW)bmF*_s86;UNG-r*U>ULf}b@yo!|TUrbpat45SL3K(byBckz)=n}Xl@@ip z73+snMFB|w2r}i)`ZEZSeMoZT?C=*edM%bR>_#A@2rpXX{UqUSO^$SF)L?uggMKM9 z+jBq8FIA1-D(@Q#uo5X<4f16ZN?U=Ds$nfx6_NxnM%8&6f9-;B3{C^~xH8m906IDp zt0>k73s@Gc{c2Uwc`c2z4i{0=4`g(+lt^(4!H&K=E?s-WG3lwr65HQ6&3`l!1?iqQ z4+oD)4Lv=FQn738$m4^Re%i0g@AR`a9%M51#Eso5{8L9z z+EXj^99hNIxR3ceP0&x#iS!o6I%&htORunKAzB29oKGLHSJZUdrwwDLJ49w)$zk)cnT&=E*JGD0{(w_CmV59jfCRNqNAvC2M_DWd^(A4j(YzZ*# zn4za%H4FFO#|vtj?vREi>u~cs>ODKxgggvf@zDOX9;Rs`AI$fbFkY-n;6L5BRxq5y zVA6mXC!Ot^R?3^Ku7UAjrg(gqgtfmx+0q~I@&6CX;EpA;0Ob(BF5>@Qt^Y49b1PT7 z(6|admWA`1Sg1qNH1~72RetE9MOdCR#&WYqryAQkYJwgza|w~DXU|uuuc{dIP6G4+ z&)ku?D69QC95LmJBgtiZyy~cn*b8)^lb5eLPxyKk8&v`0qJSGV%P+mDURPJk0XPF^ z7g|Hu=)6bU&c1i1=di9jfdm_%Qq?I*1aaYL!tBiF<-Zw%66$F!AUlZSX2 zs7wO~vVCFgu4teH8Ky*2rZ) z#7K2|Nw`DE!;O$@Pg6LvO_AMZucVAYF#KYHP}LE=SIs}d$>^($*7m$*>S!dnEmtHWW+i{bbi1mby-IjFig*cml zKr`JJ=c9mINe?;&oFFgFp;vm#+@PaMg%YTIH~)eEn*}>;5wmW(p~0iM5w2I?p1UCF zr3x8G*t;x2!cec3MGwa4RAUMjWohK`hWg$zJ2GlBFEc@DrpE8xHx_c>GJP`%xzMvd zM5GmGm9?$E;)A9pLhtqaaAioQqX!y@VU^@V$z+s|!UkTk3M_&ExnUX#=Hczd73(Va z(^tYi;G2Hd4rYs%R;b9wtocpScwd>i&2xdnip$MO$C~U}2|BjDA($HEu{pQJ#IjI_ zV>Q;Ei%RRWQ8PZ6YeYz=?5L!dr+lqcnH`48RoK)2(>ziBNAOhyNX1RXoDb~|=z5cE z=N9*k7M`;3`v_bODr}719@2<)jtrw&vPU#LddNohmKm7*wabb#kFC z#?g1|E~&g%Ydf^-@LR1P?tdSFU&yZ4__8-q%F6n?BozX*t%o9onp>-NwXCg z2>kLH5)JqT8CLVU8&B+MEc~6P#?@0o>nDd?CyGF4Mvm^)aTpKeFP|50|22^wjoe&S zNZd=s(V!pG@OjF`nnl2j^1a}c$4ED*?jw2Pp8>|=;GafgO5L2%)t0kQj+2xjR~{eQ zs6?wR!N7bdep!8(%(UKDIreXYSwI&@aYoJPnGu^f*<7A^a;G>kHvUtMDFN|nSthfn zKTJ$oo9GZkx>U0Is~hnmf^MjU+Z=hcXutmtbXtEcGO(w%qrOd})gS=XhJ*$^yWPO` z?24s=g87E-TuW5rw9aMv!806B77FC}0~a_zRkN&=TuSzN3|(k_E`WCz0Lh^(iK}WR z2QE+nuSYg^;2O$SP>ZUf))`MVVix#E{kMS32T|{%t@)y^Mn}47Kp@xxc#WRCGC8yr z?MOv8KfkyhQ0}x9|3*%sOs=#einz4a%X1nshb>HmR+G)*tS0US%}{&&lVuk3g7(n={ZR9Y&^Cp+~#38igz@TOkhiW7J8N#U>` z5OJjTOO#mJyld5IpaS++#t=ypx7Oc0TyqSscDGs6{^+HWsU*7mhk<(W>U`v3N<~4t z7^)I9zFX4L*Hu_gg4*pa&qYNW?rdwQEn5JRr$tnUH*jVK6;XHq=`6WL3X6g&? zk6y)*PX_IjWqs|?!!Jd~^^Y`%DX%9UtT-&KJU2=fXv}6*Fk4&$SgkQ0>=;v3Q#ue} z;H+wmN*Hq){8N!*wjvv|7mx76uc31KfX*n_oT*NgyNLtjr$M|? zL=r$lqHEjqi<3G7v_32p?2$UiV5R53?pHY*j{_%MY})lT-+68-f5l1RTa@fmL3^yoo|r_`V^vZZ5YSSIDDGli7o@C+uto zo`WAiV7Lq{kMbmbTVLA;tef9&xCLPrYQW>+CMWjIahj(s6PPc3ipOTu)Krx_~k(h$9Ls~cic0g zurWy!Io@am$DgBHH0mKn-oF4kXlC74y(7RFM>6SVnY><78OOfG%F3yi67dXfy;;Zz zSxCnOM(scEO_bYCR&sC@zvGzI;3f?)Eg$>(PO8q;9@u$R4Xqj(9DfK}Z&8BkM+h*~ zV!PPw{*oB?1yKtAAw$3gY>n+6>E?)Dp5fj9$165|@-Q!zh1hdwqDg(Fg{+>1?}u;1 zt7UzPzqwM@XfEQcR(+=5*>M*i<1vV{0re!S8*+--Op6$k^9J)RB0|Ca%A4A#Z@|oS zxVQa>5gIpEvGdllzR;G+strbijx8GDOjjj&;!o9b6#ZOQkj-L#k&q2R{*U_IxmK0< z4`!xHPqX7w;C_zi(HVo*gsZk6y#z(ak>4U$Tg_}Nffxrg+E;VCyd*Clf&5G@cML5& zUnGc_|K%#6k1!XeUfd^0!1m(d>zKsOc-2?1`|5FDqybz`F-NpB|3EZ(0R}6;qGrOD z5UNIbR4Mh6q;zo|GsBBl2HqHu(6rcvlI9{Od` z<18R{8Y<%jfFWdrObNzKD@NmXsDd70AP>`H597wx zFd^w zYPW^XtpOKC;?|~7%Sl<3?1EUmF#*p{4qUHf$R@TCLLo_LyDM(0c_nXJ7KycjYiMMK zy?3W(FprMsbZ?y%(B~ksCvaxqo*Lmb*EFBOs?-#k%_enD`6H%>c(G|U_b51KhUsZy zhf49s2OWgJ_gj2BUkAOJOswu+yV+-isd(tupykAq+I2^JOyV%Ca=bi;$SwjJtx;ah z27MTvW>DXP)kjB-gKq3JFuXS7H%WNvQ4fv6J{=)*6o#dzr9*q3F}ZK z9TF+|EGTB+xgIE=O`dS5ZfW7pmLp<_#sRomGtV7_1S_zh=gvo{C%~lodkab-{kq<1 zcX@wvgMp_%ubH#g$(Pm9+S3^S<#B3_ntvZZPB=Y`t17Q@-|J93b_ez<=x;+&BnPCP zK{Nf8@sjzsD`a_{m^Uh02Ge|!3c58wrk=qD)=eG7B<}q%|I^+Vxd{n)<`=%Y=3_>v zQ1lwLBr0z$^aGWew}UC*TZXAD4ZE=r`A@Nn3eR7A=KZDt6E71BQSb=EUU8VYtEgA) zYJ7#h`?$8!)H2$emW-o?tK%5%p4}Leg}E}HJhT(8+gEW$PzG#rUQEC`pIwTFEt3F} zohuTd^5i~2x-6G|411uyu-QIvdUn|6DF{2F`dK46S{q@GHSLzYX zb>(H=i35z~Pq6{Yu%VP*Xzf0T#+Doy#dc$6WTJ>vgfkt9AV3e#cQU;QA|liEot!6W z`={5qa5lMSsJ@-2uz4y@|utt8Pi~3Q&3>ClsPjtmFm^_jUL|1$^Dmd*~ z^a@8J_Poy9orls9xxC;xIp(!kp`yNM<=~iWk2ppsrG5g~kSO@vCxvS3?y^4DKsY;;JTiw zyJ!yD_H(;PNeJ}MaWPyqvMUJ!;9CydFF>EnglP=ixI9<&5Hv!y9O?xttF5Q&iyA|A zhff?h{7WRHbIk=K_SVQDMGRpF-oP3MRZoJa+opA)2I^yuYmGSIfwY1K7%R~Ww<9hZ zcReS-5&OR=n+~aq-g%01Q;e?wV(y=@MyN5(FX|f0$1c^V z45XMhBUMSu^kOTr{Y;Wt2?l+u8ca~UjhT*9I*0iutdj>RC&@@QxbLzXv{rb&i8Ds0 z3&^}Rrm_sZr_uwD6iTo?dk;*fA|oMj0!?}U5X7@$qO3^B~{5ceU!g1 z=6~=)d0aD|r=$MHR2@{?=A546!O-LqbS@wZbGD(qWd9|HGySYx!T0a8xxZdz{A0yJ zmKbdGEi5KcH5mK4!gDI2&*tuLD!GYFFlvub*|DZAr-S{FoF+@kldVQR)_GC4jV5=T0zeJvYCB|=buc#0$0bq4Fo0765o5$Upp>$ z(_L;P0h5ZeGtu33)t@EdhztujOk}IE4Z;%k<4uCc8-PPeY`K?Otb+^Lo?@RQMHgrA zOPQ5=yN?ifxJSD4X$b{RoUK-X-Gbpxvi!J9Lmpf| zssVxnuQ6^TC!Q<%2Cw?0_>uI2kZG*=|lW`>-gYSs?0^45|n3Z)88b zvB6H;pipnm*|J3s&-Kz$h5Y5BK)1dHRX!Xq}<0;q$Cl+0!SmOX)M z(2Unz8E))g3`OTdIN>7n$;3Gl9XC2xZmzEP<0k+K#P?#IXm`W1lSsB35oM!DUhe?h z)-$z^x3|?EM#^(Iz0I#91!jjKPzX%b#?kO7q>CVAN_6fq99(=vO^Ny+#Q}BGE(kos;MTeza#qK;Zx&Qa>k6=&M;u8k z8xrf89;~t9pkA5yFlP?aAv>N7Mn?0Nj`9|4xb7l%!7>^WJ>r3VCXSlBUxRuhiw zlBTkS0lKmarTqjZy}`5C+K(_YXrYtW%Twfl3e#%r1AV`2Ue%27o?W#Ujn?}7W7s00 zeWTgUksu-&M`p<4i0rMfI-D2pVTq5S2N;31-RaQ@8R6Kl1|^;@)vPsaR&9rJ-T$1I z8o5?Rg5#J7F!ZQ)@S|YY!((yaNw9#?%k6+8N|{cZQj_5TChv{_#&D&6r~%^we*Bp3 zzlO;vo{PcqF#)icqT{%mX@~DuAZX_g#P+{qPy63oB&_}Ha4f*%D`3yA(eH`EZ!Sf@ zE>&yT0(Nmo?(kP6*KZt8Y&$YVZZ^BLP2hRNCD0cgzl09He@_^|LZZej=^2^J%s~3p z1O)h1jkeM&^UZU!Wkks+^V_-`p^AaG`E2i@e9o+WLocn6& zC^gox&gw=#q;vVQSRJ1%ta1;w3z`~>WoT!W?as^JeAS^zEU9Nji(qkwpj9rpp6k6; zrnDBamfZ*gvN$i=P!dZ=&KdF%<^>7pH(M;-cWr90c{7%WCx2El9ChCSowUgVL`Z+hpk^Xq`A+Aqk;~*^+O@Dj4M);|^L+I=1If%_r=VWD9Q_b|IcMG;7-{i@ zUnDUZhE;0Em_q@>WP<2U{KHr^urPkyD${TVm$fqQ>my?(^_8@J{gbNSQ?D4uW)+IA z?!2dN@c5|x3f7E$YN<_|r4)J#v}%fvinW2Th%mqcbpvHs2gi9z9VMByd3jyS@&Z-H zOoTL&QvJ8j!(0AiKZhhQ4rq-MD{nFiz#ZUE)HppyML4>dHa~@iUJ9;&S{V6`vY0#* zVKF_XR0Byru0k2$QQeuzW*?maF7Cew89lkV45)%+s(-Z zMyqr{XwgjC;U$p@H=G@EwtUSROl&xm2xzODU-FJ|nQ5FbFArCcB9x&TmWM+};*g>- zp{(*FmVJZbo)im-Sb-3rKakr0OzyvqWkmalGj~xdeERCgRA38e#NJ=y0f5oRggSB& z9i`?VDgRHV)WZGF6%YS8^e6$&J@AqqY z+rP^5ETSIp65=^Iy(vhA0&UdK&WAH4U+8>gsWLb9p=uU&oMw)&VFol!jXoTYO z=I&n3c@Ad-jq|LxSN{YFDU88XS)#yyay)hPR9?5p?FreW`P339a5x(W zlrKq6W3y(_J~ zhFqa+yOQ}K&1A@66N>Jv&1Sn!$k2!|?Sz{&Koo$=1=KDoBYJvr=~b+=D@%};_cXHB_nayvDxlRzc*xlacHR5q82~6#*b;*0w|GHd*&oRL z|9rr2*oC(bu#6`5LoMnv0WswJ&)@-|^eK^ez1e+e_y3bv^l3{#yT+C7gu!q5cE%#P zrC)=A&K;Y}p~QkN*nzxvB02|Uq8>9LIi(RWpN}r`r!MfQ*?)b3us&@i5w+AV0@*ts z(~`Ups0bDtzpBYP)ic-E7n)DN9s-3Jj>;e9>VjnTwv4eCj5NA)Xq{chQ8cL%jRh@? z8<1>nf8L+~&`|%$9Yum_?0m|~-m?WW!RvS~)dAXOw(j5`Y>Dlyeg+t(un)}MPR!Lg zaIEJRxeOr@dL%N*WQ!#_E=s$~R0N4_@4g2*tD>%~ZGRK0=h0?6q}IT6wnDU1b;*3d zLRt*NO8y9DC-&Z2PVt5rONTJ1Xm4wIV^u@>9$1ldAXD5;JPA3xv^RTuOsYK zzA*rSkh`QKf4RTM^v;TMSSV%o7qd!(28b2MjF=I|Ra-j2OwYO3Pms8*hQH$(FpBS& z=3tn9XL?(uI#g zA8;joC6lxNm9@~s~qF&bMVLMHB5$xNvXDYtGT&;P#pH7z%qWR?tWU~E%GJZGqZ)e}# zZ(@(wi%(l)t|!bovKZUx>Tw#x6ULlP45sdbH!?-!M@c`_>A&3#fUHm1)?q75nDB|; zzfxcSYPn?b-{n1h+6p}BXh5;)N__nYGe%t;H&Uo9X`_#@;e4 zuBB-d9o#LrySo$IJp>J!1b26bL4pJi?l1&`ySux)d(hw#{0_(Y~w&?-}g`9kpg-$4j9v!|~%R)MJeR;Gq1km$v$b)$V{$2^@mw{``>Ng6k z?*T;>;g6X7b~rksHDkXWujYu{J@n>+CdS`SLs7(C zrC#e*eDReAg?SCO=a&)iaQ>*{N)W`O$v4w5DxFG{4vd3($Oc7gbv<*Cwgi(?%_ef3 zlcx$$L0Yghd{35ADGC_FU76bSfJJGMTo*8@dO`MUDn@a=&lF*hz9>z&!Pt@bwwZtn-93J9_i0oPiRF_d$DufR&4lfym?`y#@4Y zHiDHWvZ%=dR-CM8B$?qXGww;cA!4!Nl~Jjt;BeAyLh6 zf$fekz0TM8W6MgS!cv}5XKSCcsUBh7unQT}N-WKv`Hi>77{e?&zHmnnVC=%< zYdIJKG-p1$1uCZ-gI)&T)jnPvcC40pEU*Hn(vyQ=irQF|=u5)dFS&Rcy3+ZdzCj87 z9*6&N@3{jwu6s&YO4w5_V!mx=L`gaPz)`VDmy^99gJWy-!xrzne2#xHjom?Cz;ScS z#93_M&8*eJt!6CMmsV96nUkpXkkd>2-UyYGZm=Up*^O`Q;j7u$ zckl8Vk@6u*8-!3%^|^+HGhup;eT^BW4mY{YD~w1%%7?REX*zI_V`jL7W?yfQTU>FL zsmwoO7(Ng7(({FM2HlHLBzmc%H?kN;xg(5E3OGEEj1BuD-j}^^WalV78S$%@WZsJl z;qwwImNkA`)vbQ|GVso4>&2>hjDt}gGo+e6UdHNr3EfSxVU+ZW5dmXoJAK~Wd}=0e zHq;gc$MhNX)0cf?n$GD~OFsk7n`PZ^W4&-pY*VnDLe#aq)QKt>|TjqX()auvHh`)6_w> z;?RQI`}R1Q*~?zu z?4aWDZdGH`plO(XLFe-yj8r(Z{>7DIn+|J0*Q@!Kv@zHKo2PUEm39b$rLDlgx*dDa z;Rmt{ItSwjcPE0Y*xN%aQW#Hx7}QB4XdYgnLS`uicN?x7wqiWkMVZhKlKqV$N}0!E zPPa}K8Sv{Y#ni2<&!scoMS6AvEQ~xqnS*Uh2jtzlW#Nu(2ZWrsb0riKupR}J8oqhG z|E=NQ^?}{AN+p~$)KQNfl{Wv7NEVn5NQ?#rk(LX6ADuoFNv!F5uibE*)`M-NkJmlK zgE1IjtwQIdN0X%pSzlHuKq)HFR}rsS!vEW(FV^vMFemD`oic1vnctLt zvMLi3U!2&@iGt)Y(qBSu{U6%{}(~D7Z`E(Io_V z=~wT6D~P6IG0YY5G@lzQ=8<&z6>-o{v%-SdR3X(;8^XvP!7Ui|w%E0}!;HQmOM21W z9CaQ?M%1C*J*2sw{0TtSqq_ywQVH1Y-O#$z(Kr0++1}oF(R#yx@1}X zmiQnO>aJuR-vv3nT<^qqn8YoY2| zAld5Gk(tCor7V2$ts;Ok6@(KsOAB%!-b55ctXUznheIx*D|3~$t^RO`p{m=2VU+Vq zT$(sEJ(2jTEf&0r2AkO1Zi$&VYw=F8;8kiZuT*o=pvrUqqiW`x0$*ctlBO?*ltA0@ zGrv4DN&Fsw!G##MJD;R|c!DTYE>E+v-Io{JUq)S=8$@>#=66{JzjA(I1cp*8ac*OL zaCPrA^;`RJUueTk2o85Bn7U>?YOtwI!r7G&NAz=4m>k2fDc9(jjH7E3%x(twfVRu@ z2-`|K@NCBNGGTiH*FGBcMGYLDfShdj#Jd*>^M5paWE6ipi#s+rV8NF{ed>(OywZ(_ zl|1{cyhv>dUE2jZ$&{G<%AroDX(9<`Tq3fY_194`&vpn?si)VWyXyC?7$>=Nv#}W( zv*e8F2Qe!`5088U!px$9h?L_ML(49sbxD#I7`#Su`{MU?J&WG)S6#^7dT0?{X&e(lVv9*_NCV?GdKx-w8a)-|D_BT-U=vVrbXsCH3?lht1)Y z{uW9-MBc~675~*)vBU~nDb!=$37RiCOqfW92q{-@T4W!O;}M$6EP~*0L{dioRX7c) z?O4jPy}H01Qos`rl`)Di(0jp;otGyomlgHEWo2`dT`$5Wi-9baDnR29Q z_5G+_?4Zv-_FbnrbKz8TC&(u=Y`yhum5cXy{GSAA<4~v1Vej`1%$J9-S77mlElSSU z^@kxN7>E%=WO|5fR%*=0$WtR_-_tuBlBpLyY8Lpujf$+HLUX<9e$zh?*X~VaS9P?c zR+jLd*N4DuiJI`qE#@#n4!{;nCw_%#SU{b4O7m+c-G}_4YV-c0{vw=Ez>e)RLeuYk ztuZm~v#t`4YI`E5WVVH9Dr?S*siPQ1R95HhUP>zS^B98V9o9%;L2j%^S%Y=7lOUgK zsHgtr+46|491&BXF1nTQQT-)~(Z*+t5B3{Bb-sKmiA4FRFb4Xz^97qb{%(>|x<0PQ zMmj6l`GhJ%zG9vl0el{J7*41@gmBiN+=8Kt5iq7^In(j;HVX7R_U(f+5XY@}$s*RQ z-<>HT!@UM@XPlR}L2d!dyhDiS4qz;@_1Q9uh`nwud|dua4qf*|fF!n_`jhM2=nah3 zU*M?{N?Lu~8a(hJ0Ie%|akf4dHwRYV1u zX;olj+&)I%{I%68gXe3kM#C2Oq-_;2L?M*KpL5t#ug3 z$!p3^Z~Y=WJHH*Fe&JR5IOrkS7-!Ty%3uIJz2jz&LKUKIZo)XlBa=j?{A=D+$-zWQ z>!DxidSW9I8@cCg*#n3yl+_&`^4+;rKQ7xWL~C#9e4sPwCqRCK5)X8q9CYu#zG8#@ zm;6wKLlW5Jq{6DfmbIYEzyJ$AY=TV=A0FRwOMRwx78>iID9I)9na)Tpt_N<@8XyAOuBw?TWK_$p`R;? zYdmU3>+8PA4Z~l_{lO;&Spgwi{)xOG*dOdeKTe~)PB#Gv22?a5+oZk)uL&FjM%^J< zEaTwoRg?gEe>I*g?!11;*Een8H>RPbLd1egsuhbjvD~dSig5NWNq&xL-J$zKR#Uc1 zg0KlnO|JRTmZu5ZFFlb)+h}FsXYb@};WZfn9q2|KLpZ$z@2;bFwyHlt$@d;rx+1ad zzTwH5uN%UbB2LF~dv=DG2=?al>d%t9!yeG>xaU#rN!}2MU`k3kLh4BChHA)odwyj^ z#+&#PedSp>E(+$Qv%XXa8|FdVizT%Y;U;Ylf0zndkWJ8Dg70S9kro>`3W4W49F*As zut^SX4N{}4N`=tt12x;^OXeI(F;fwI{WQzmKV|8zr;9T8u??VDG?M zqQrj_S>C~Xx~+5Iw-8&%_Wd6C)CqF{uF{E(1L2zAWMwYMPFN7=@GQKGrdJ(VS0SrC zJ!8N}Y?A{aSO1B1BiK(cX`pnfCBLc>Ng>b_UsB9>vF79J{x>>>gp|-sYu{y$EXo+P zE!k11-xxT_V|5%OBr&=x!F&BcwC(Q@a6aIy5X1@z*<}`UU)z)$RlC@1i>*OX0W{gI z1j$^2Z%L4{nxfeFsF_GsS0_ai^<+B{_n{sP4@BRMd!O_BzY`eSZwK0Y!a~q&=~k#_ zW_qi7iPbQ9XiJl`D@5Vu1el3KIp|Mh*3SMApj$G!kjN|p(V#wn1fJn?BV)DcMwdD8 z2HfO@a;IlST}sCdm)y4@kFFhMPPo+S*l-KUe#^c)PlcS?s+1wA?tL6=J@pusAgb=n zceo1dbu0U(SMUKHD#x>qpyYR2zGp(C&>IVu<+*PtG)tcfc&yWG>lhIjd2SYhTs}MD zYR=3OTSS9MZohn|LNnuZ5tu)VaK-^gEZRZO56i_~zKb%JP)fMKdPJ)pKHwxh}kO0z+i?Oxt+dDyiOUzo4O( zuTncglcZ9bs&i&P3_w^XFrLi{24|yt+H4vadt@Jq*kePL#^9=J`um}E2*zs|4ETR; zltwCI&A)zo-7XSVPi&@O4T(iffZ%$_k+@s47Z5SyvC(STMl+iiJhu^k;*H3#m^{%R zA#yH%uj5gJKO&(a0dJZsy%6s}MA85f%K}2a{8J;5?B}5YXs$j`SN>pA1K`140!td2 zXbpzJW>00E%k-KJ=-M{ejacu=7;lh&dmkf`nLoJjnt4beC3lFrJdO6ZE6R5L432Kz zO9afR%RJs&NWTNn50T#znxvuBA$HVlalFlCT5oY>9`zeA6sw#}uqE`U$$PTTd9gbL zkO8pdx*1{&Qhwdqg+h$7NXcR)zhU+_d|yn5%|Fer-L`zKwMYi~YWVL1U^Y#LWg7Py zZS6UeNdw8bqHZ-FxqT6L>Ro}s6Rdi(oxNrjZ4rV24s{j5gjL9ukh_z$eG#14OeUuF}sU|Ycq;a96UB6sQv%T&jh(z7iw+APX8yhwJ75#e`qh@7?`?^N&d9%&6 z!q8i(+(XsDRbfqb+eNybgsKl>kf<{jleL2I?LO=r@N)Kp%koZ?s$5rBA=cz(Z<>gt zbq(SbMYn3z;Ui4_L9#bMD6&5m`g2?tzEh=%k3`0!>80q&)-5kkjKWp?$ZL1O{?!B+ z3R(sC6!6Ci1uhZr?ZN~duMdY5OawnQetLQ@{t(c&f}97e4T^jg){Ra}Ok&YPDI$3* zf(0@vuMZ6%FTvBm1s@k$KwsM8I&@Gsx*e9#&R|@Y6+%7aE?p#L5?^9d5(~wQqCyd5 zDcxGX&SQqY!~vtvLK~p??kUHV8&Q*68=-#EDj>#euiG)nU%lCjqfLxDDBXSy7iiRG%O14^f;$R*YN1 z73vwt9!`gO8x29)`An;ZPy-2_FYl%Gkm!>Oq~{&Z_SSq`7u=4zW&x+uB`x!^6EjoD zJ`zLlY;l9%4OD-x7(R~UxpClSLu&CN0&(-~Oqp|?=zt)P6$0}Wqz$W}LQ>Ph{xN%p zWNT0tm*+}%y5=H2u1$B@mWfDa$f&t{ai)L@nZ3a%XW zoj*P3B-%`}o<=T-HHu~vtB(ipq(;9P^z!S9FmtWjo&&`TK3`WIdtSE7v{l2WQR+km z!bO{g_D?s^84>DtFf zjhdQw+fP$QG(D+!BNAU8SiyoS-E{y3(Kx`bsTxCp_p$bh?H;*0EX*6Gp<#eOsAGz9 z&VJo;PC>x${Ze8Hze}CoEz_v^Qj^uHgYLWHnanewl2H_Vh$R_-*Gg2B zpwM~CFv-3a@a864z2yxl-sK7+t$+$o)h!96kpv@iJH2Nhmr~I-JrH$2_EAVih7Wx+ z(+LWYt5UM3YjMO$AK>)k7Z1u1h9JIWkX2l9Kh815PMv%9mW;T>`;bxKLUe8;S2SvB z+7nln7docgKp`p2Xg@aEnizuuCS%k0>WX_-JB7;Lu5n7^Hg05XW^6yyGZSSMkT`;e zc3sy8C{n?6iu?0{o*E-)oL{b2>O5+QKh;q_ObMr>d8$&6<-Yf@H?_feEQJjEwOosJ-aOYE`cU~gnv0Kn=CEg9to&)wR_5KIOCvUMtTK{zrg0$ zNks!D5`rE6rRo2%t%m*H zT{95dDo&xMgJ5&3TeeAWE1$KgeUVYA#U+pJf8uaM`+@foV>G@{cb2;k+3mA=Ozfp* znow)!o>q%smr*2AeLO7BU}#D7j|x}5cKtRY0Lyt3Msv`d_W&j$P4zJ7o%h8(FiV!r zx!xx2?qQNiI?p~}dxb!>Z>&~^O%>-IrXJ4FybZ4;wK1aau(yonCo~+YaGD<*CPHrC z)v6*Cw8i$d_0i`i$dQq(@1v#?d3WtWWZMszeWx^M3qjgZcpq=Qi*qAD;o7&U`wS!& zAB)@e`oFAev6P!!cz1ta>pL9f}@WLsuNBX8>i!+&{^q~ z_hkZ#$Lk!&QZasHNhrI1*hIch&k~gh_WPv+Ztla!)MDepom;;SW-MNH2P9Fs^sE-x zWgOtQ-{`D7eGnL-Qbr&lM03-p%DFE3-E`(k^GS;Caqly6)dyS~p8eu`2G)V>q#-iZ zx_m{g0@#m~)}|6%x#D_q#!kDl34@5W%v_B9b|jq(PTaqG&V&=+t-$;ozZ4eG)|@MM zLvBhM^7JQ~^_>{>E2co1=R#5zVgl_0p~U`-d(w%(mo7m1qov&Ok()_7iM|eMVANme z*#7_;P^~5YV2D+N&9flX=IUpMV|kH$*CiQd+8nnYu@&~O1Q z-J4&A526~ZTnDkoC%xVNAkh*al+j;OSm3*e03BqnCI3SMQ3G1W#pFg*Y2fv-t(F$+ znqhoYbedRF8&=1J^#z4YA$hC_BZMe$GieoH9m#Dxw6E+p7vt3FbC~i|Co+84M>`50 z^^^(tFJw)2b^bDmyUIyYJlSJ1&*y;zzB^2)OPm_67n|`MWcT~!)6q#X=$2|HgyQ<# zutWZOS}Qz3jXte8?H)F~8FsQ@cDH~~L4U{W7~t<0VC@IQ+y3mqgjL%YczSr{@r^nO z-Ba0jUcK9%_GR?rgeBnX(@b?DLu-D?w*-Xt-)xk1OurvR@!E7>{gCVV>9@OpOEo!$ z1M?ePY4oK4;dQ*!rERT0ShjuCqfH1o34=Ug`5iqA^~TbVwIvkND>ERP^&dZ}CJE?J z5ALw>xGg;6MiHi*$_FpKHMZ;c;kp~+QtFSPJ-y(h=Ury>E@OOt18Y2y-xt;|s)wI= zVw0RYJS}bs2~qU=0v^iC&+FSyfLj%81%Ej_ZdvE+1qK#CsPBJmLI%Ev=D&At!08+q zm&dF(fTh9Ll@0usim_!GEsEObJss-FUkhQ7o-y$g4?Ic5(o@%tZ@a^q#W))HZrn#a zJdUb|c@&~2)OwONwBB+`h6QIe?~%=9Cv99riGq2rSf{AFBfjMURFH^rr8}OAV2H1w zpSiQ(pVdvnner$ur56pYWb?`xj_PeZ{<^GQp)S}oL5dV=VxVv`bo1uO%^j_Ra49#; zohm<9xTANy9C$98e5^6)={Nn86!Da>)bD4DN$6;?m++^9dKUcg$&R08>4X#o`~oSl zCK2*k6eX1L<__8*Sql}K+dJzTp(JZGCt02KZl^C_jQq$ihwG4=g>$kXK+f|AFOF4U79!7 zOGIfPwa2p%fTZq#Q2StU z!JkRQf$1nvaj1v`K&}X*v*{f=RUe}WsGJiuOBzoK#jyAuPSjOwK2UZ@2Th&=&tw3DLazMUwuXs&v>E8 zPK}s2%WLUcjyjv%*y4w4bF?rKd&|Qb&Af)8J5~@oT}`uaZjf%N)`j!k?Vu%$9K6v4 za4)-4`W#{zpp6Q^W2}8-_ zRn2b%*{w~#EPoGwiwhi!av){V?oSdT1U~uR$-|fVbS;9b+x#zLUr1 zA~Oa(Jy7+m=TqPAqFmMEZc(mHFW*^=Trz`8;S=0BXWQdHeq(1(x z3x$F8c&uO4xa`qZ+$j0-;gduFqD~A%44N6l{P~`(l|wmTjNoa*^(BY6UJ!-t6QJt& z*9eiXX7UPdj)9FBD-gV&sp7Xz?(GKKTNmDx=$wX*l}L2(veIGd(%U$W!jxd1l^-WE zdyaX%bTk6S?>;-_)Px8jnMOU7-+j3BlnX0yGa5=Ko;08l|0ajj$rYQ<)ge3PpOfLH zVtMSnn?0VNFk8drH`3Z2b-aab_{EVkOfQ5wn~|OVGHGPUld48fu`F}NQ*67Y4M$Q} zbb2GvO}gx*f6^{sY;V!@!_)Ia@)oMEid|0qK_ek<`4Cb~H6nUYh$ua+I2Cq0<|O8Q zAQaM%;=PT>==Cf+#9&(TPIK}r;aai8nI*ClbwX=N74j3b;9gEdITBR@V5ShEisnK7 zmNmm|R6U>>^kHsQtyPB>_9}mny4=D`)6;Jp9Y*{8Q*O-1?yYJ+#pYvrA}QZmDh#>z zpDg)uWs%EJ6ym#{)RdE8pT_7lA$Srk&>an z7TLC9s*%`5IK3_gYs_DHIv~WCFrh4De&hG%gDE`N8^9|O>gV7ID)H*BVUv-dpo^mb(65w3AZ2?4VdrzZ6nw7 zq4#nMlglD5spNjyJ{_|rmvNZp1*uEu5*3Ft!}|5^yWO1E<)WCb@9`T?9rF5Yt&dvp zA+8#qZD>!CTDimy&XM?Zq9sRmBxH(qzTr<_G5#Z z2Zs4M5{`SR2y&K>r1pxc$%4Pe{LGy5* z1tA`0R$d=|{VX;%6MD(pj`bBlvrBpwE+T19K~}e3nxl=tU6wO5{XKbccz&|ZWnHKJ zL-CwcV0d#ZDyu@r20^Vp4%EOBM0gr^5UAcNPy6celo0uqX8@+fW7LQwGevFQy8y4}4>H|qc+*)tbCRXxLVGq3{9GDy3^2@US7SLvE#zYIM zVGR-=xyUN0jM~%iSJ5(m9u}6`zV|)s$hm;~B}!Z!xE^F^c}NmVj3UrCUnTftvP7NH z)xX-v;N}=ZGcCSSa7RQa6RUlEF@!%=GPVq7l9}8T)d`%#FaGX(a3(*Q^p?)3B(1f5 zZk6-qD}*R-CsdsHhMxu?NJUpY*qk$hHo_17Dp=b3`SYM0!Stgl5;xRBpW?g^La>ZP z-q3zS&_PV%-aUe}zKp|@aa1rKFTSE?!Pr)W68l9uQ0mRF+LxjX6}Ms~w@DFoLiA&P zLr?ZKDa$kalIJ0o3?;`-JA-qD<)yTi3D8GAyU$rHRA$+a^%>@#zwZxZgLX5ckYFmO z78|kGi%u}p7Qdu?_nA~zTVn!W=UUx0;ypN?FlQMzUT6zB|2vbk_o0T9T|+*eyYJa{ zU(0~K+}e)etpruXu2%GsD$OjzSWfs2AW{cQ_KY*DU$A;Z2R*t$lG%8mDad%vOMLf3 zLiGAKM!XnpUcb7`h&4@Uoa3K6C&=+u{`Z0up90g+K1XYze0lp3p?B5BMcNWVBtRU!YpOD(1HbqK;#=0FtIk5q@AUDG?Dv_jaKc*f6Z z((%sA&oTK_Og~~cO2T)NkveWdZIHx5ijWHMs9+*KcHU=dC9FUT3;Kf1jsz`uFaQG& zf5#Jr*Sgur!~sE8WL+N75x75fA-|rO>w$>>!yIpdzOWv?6eau+cSc2=c9I$5{Qo!_gCHG9EEWi@_@{!LL;RU06DS4gd%R^Jm*@nv1ML{sM@&&JK(%>ELQZq+mHtws$;2 zH>vlGM-n?P6=9!2iuNlG4hKo!xTIL_ASwIDi?bdDTG+3xX2E^N;s(F`<)~X_tQJl&w%Gn0v;r ze6vh2bZ&<+J>=vT$V-Z~l#dN7XEDTD*kOTYg-!CoH%_Do#m9WcHHl+OS{h4VO3AFg9`M_Q!}t~V(-JUS zV7^(nt(N%8cN%k_q#z+LF4*e*0hjwWq9k(hQ%7sF0RybzJH1wa<3;ERfQNDH|ZM9U!#L-$qLoJky5oceC06YaIMTw0@KeVM>d4?|Mz)*^uaY49u;Pc;5`P zv%x3gSt<4j53BhS^&(CBf756RbE@q)dY^Q~5?j>k*KNQu{w*8NcK`O>B@bzl=Y z>=Cu!q==-U9iKQ#)TuquoV&?<{#z@73Gm>_v z9$A-!`D>ATT?D~b`x@GigeCnVE_kqeiQI!|)LAo)Z1xuT4C5mmoR?lX|9pJE0Jkfq z*W#vx$JSsPS9Lz^jW2PcK*Re>$CU$N zKzkk$RI-R2zobm;2SxSfxaT|nDn}IEYuVMDl%2_Y;M*Fb2NgnM# z@m5!zao7x_K~}7~AdfCfJH}BCbskz*rS!*zTszvrYa1QU5&{O+g9abQA8Quplu%_E zZ>}5RJzU2`CC;UNo7a3yv`ToU562dWglxQaIWSk>M`-B{i`2-~rYZj37L`Ev`G{PK zqr$GazUvR|(dZ|so+jkT9bS}6ewfo^xVY?*x6;lFL`PmY)b;U8QDm+1&w0+~nOkAI z49Ks?9(&|&R!D*2Wk~Ce#J|b9eBoCcf#Ynjg(^&0uMC2Ew}}Yxt!5B>)_d%FvA$xD zFLan>57=HPPd}$0D;afNRLMYM=RoL+Kh}z%`d6q0+4{kn4&dzPi(|;<4>k;=o!85i z<^i3CtFv&S8ZG`vO8IimGnz-vcW4Tv&cGop0u_X{G&E-_9dB@Uh-e!_Nd(P17?qQk z_cAC(`z_px#Ybp}yFl2MjmgYHC`IuW%(TqR%VctXi0#rSnXz`c7ha|NYqYpgrlD;q zddpfM#6fR11AARe*=_ssej}B+bpj+bbK{k)i*T@lT0nU`fbF5aAu%lH^kCZNa4GfT zqVF8e8O6^bG(9t7q7$U|n;unu7q>X5+fBQIN&uuUaMMu0iQ5C=GlVptEI87rg1cns zpY_8|_-ybwVjHg~As|x1iHrR4GbSq>-a^w{`uN0P9#1%=&QNTb@3^OsT&WiMz$HiY#0Q3{kq-w)Cpw8YB& z^i9F#SDQ(LZA+4}!eSzN>@B!Q(*a$-gy}>t8h# z*7~0Ry!h4H2sR`TXcMW#9bgy`Z$klr0TlqA%rPXm%ZS)za5TrF(dO!1@ga(!t2K_; z!CN7oT2+65^)E7U6x>0={;KIzbN6-JAh708mDBnZyf2g~4}z;RjxJ{*^>goW;UzLB zzpmvPpu0P!EnHbI``y^@J=K)vWv%(ucjE>F@G+@~=i_JiLzA)Om>V1PNpJO`H#-2y zsAtW;p&7{VDYX)o!2%J#$Y%*yqPO5E?}4MDM?mPyf4Y|c2C?9+pNqpXJ`ps4#Xz#r zBRM~n)#)kI_6H}+ZOHbF+fhXKJF&j%)DtrPW~sum$w;aJz~<au zX3T&$t8cB7yW6rW^fv)vl~dS&*-fa zM|^VGjA>-uVh2P`p-L$DT~PXCXkDmEMaJ)WF#cKwq4HEnskSw1S!OCA&d3MYH@0m7 zF(XSh1CGp>wUlI6M`74+vK*!QVYw#D)j;um}&{bf~A{if(RrU4urw_D=ppY zJVw-hpaU!tIB0E=LLs9H2GDJ~`vvE81-VQRdIjNOEdi!o!p&y&VN zyBXr(nxzGJjK=@CX&Vi_)dz{y0b#ho%zy)G4&ZM$=hJy6YNX;Wix20O2ii?alH7oeKPxh9JZ|5T$vC&} z7S%UeY2w?(4E?@FI`ot&0eIz$@+Y)K`HppSa5)f^rk9@8Jt?Rg@!v1R2k}g(H9fhB zC+;nK>#emNR2i09Xr>UxZ42r|SxAlD#YPlFxb2!v(Lcj_B8pIhZ_K`DW&JjBSkZ=! zPvrT=4~|a$Wg8dX7v!9V06B*NgHpi{y(=l{pxyCVU5bz}sWczE_t9q>_}PZ`tT&X-m*NqnKeH{>U+_O86b>`M z2@N&RD!_Ve9;FP;M+%3BPszO9(Th53qe?YY)a5)w<)cd>0zKH1K{<;WN>Xf+`reVZ zD2;i1gFe()V@!(2PUg1}B6Pr7p?|@-_M)^enl<;e5>}w5`Q*LWxGWV8lLkP542S21 zt@xPMsw6VDhhITNuh2J(%eCvKp6MG zg~0!7@dVCFTh^2}^0hR0D_gcVRy$L#FoLz%12WSrV;8^^%IM?A1d%QXP5`JG2$S+J zJ^(b)uX+Dr1J24Viyp}Px?c?zTo^_lz!S}wv#meK$y^lF3xsL@5AvVhi|iE@0B05c zLSy2l3^Bs09eK@(&OHYYphX zn)nZ0Z~^}t2S;qq8x9iyP#X~D=|9;2n-bJ*i*?*z$s$-KW_v`Vsh7X{|9^{krOpyy zX2J%h4omt6KjPIA{}<};R`yom`mg%?qk$s^mV9t)z7B*H{fqt@3xE{0FP0g%UR3i3 z(*huvD=jcnHg<%@fD?okNJaeo#kurdNPfTOON@jY#k1wbp3IqGOJDPI)%0cvmAXAyvTOB00Yx-t{_@NZAwyhgTyg#tJA6GbAfL|_sFiTtzYTF)JUhLly{8tmVPT)axjzPJBIdC zW)0=}4H4;~;0Z>!*YBnt;bK-#F$2;aztF}k{w=KgLLzP(4C0z0?NRqc*-1#Isu~N1X?ehNPp&hK=z(8hn_wm- z7(`7#w5bS(Dl>Y^1Mo+cHay;pr_Y9?#)^KG@>4@*PPIy81Jwdy^ZsG>zs7_%4HSOu zg`iDSN`k=uu%_etR?DIu&5H~jXQb$Hpmrc^?_V_Ne>w91L_;(!_Yf0*n*2~B>M

    ;6x&D5hCTI*y=q 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Ν(Ss;STilHYkTN47-*m_;;d;}`M%N@a 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 - fun setAsDemoMode() { + fun setAsDemoMode() + + fun cancelDemoMode() + + fun isDemoMode(): Boolean +} + +class DefaultDemoModeObserver : DemoModeObserver { + + override val isDemoMode by lazy { MutableStateFlow(false) } + override fun setAsDemoMode() { isDemoMode.value = true } - fun cancelDemoMode() { + override fun cancelDemoMode() { isDemoMode.value = false } - fun isDemoMode() = isDemoMode.value + override fun isDemoMode() = isDemoMode.value } diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/DemoModeDataSource.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/DemoModeDataSource.kt index 64eccf09..869a610f 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/DemoModeDataSource.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/DemoModeDataSource.kt @@ -25,12 +25,15 @@ import de.gematik.ti.erp.app.demomode.datasource.data.DemoPrescriptionInfo.DemoS import de.gematik.ti.erp.app.demomode.datasource.data.DemoPrescriptionInfo.DemoSyncedPrescription.syncedTask import de.gematik.ti.erp.app.demomode.datasource.data.DemoProfileInfo.demoProfile01 import de.gematik.ti.erp.app.demomode.datasource.data.DemoProfileInfo.demoProfile02 +import de.gematik.ti.erp.app.demomode.model.DemoModeProfile import de.gematik.ti.erp.app.demomode.model.DemoModeProfileLinkedCommunication import de.gematik.ti.erp.app.idp.api.models.PairingData import de.gematik.ti.erp.app.idp.api.models.PairingResponseEntry import de.gematik.ti.erp.app.orders.repository.CachedPharmacy import de.gematik.ti.erp.app.pharmacy.model.OverviewPharmacyData +import de.gematik.ti.erp.app.prescription.model.ScannedTaskData import de.gematik.ti.erp.app.prescription.model.SyncedTaskData +import de.gematik.ti.erp.app.protocol.model.AuditEventData import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.datetime.Clock import kotlin.time.Duration.Companion.days @@ -42,99 +45,109 @@ class DemoModeDataSource { /** * Data sources for the [profiles] created in the demo-mode */ - val profiles = MutableStateFlow(mutableListOf(demoProfile01, demoProfile02)) + val profiles: MutableStateFlow> = + MutableStateFlow(mutableListOf(demoProfile01, demoProfile02)) /** * Data sources for the [syncedTasks] created in the demo-mode */ - val syncedTasks = MutableStateFlow( - mutableListOf( - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 1), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Completed, index = 2), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.InProgress, index = 3), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Canceled, index = 4), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 5), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 6), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 7), - syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 8), + val syncedTasks: MutableStateFlow> = + MutableStateFlow( + mutableListOf( + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 1), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Completed, index = 2), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.InProgress, index = 3), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Canceled, index = 4), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 5), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 6), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 7), + syncedTask(demoProfile01.id, status = SyncedTaskData.TaskStatus.Ready, index = 8), - syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Ready, index = 9), - syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Completed, index = 10), - syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Completed, index = 11), - syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.InProgress, index = 12), + syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Ready, index = 9), + syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Completed, index = 10), + syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.Completed, index = 11), + syncedTask(demoProfile02.id, status = SyncedTaskData.TaskStatus.InProgress, index = 12) + ) ) - ) /** * Data sources for the [scannedTasks] created in the demo-mode */ - val scannedTasks = MutableStateFlow(mutableListOf(demoScannedTask01, demoScannedTask02)) + val scannedTasks: MutableStateFlow> = + MutableStateFlow(mutableListOf(demoScannedTask01, demoScannedTask02)) /** * Data sources for the [favoritePharmacies] created in the demo-mode */ - val favoritePharmacies = MutableStateFlow(mutableListOf(demoFavouritePharmacy)) + val favoritePharmacies: MutableStateFlow> = + MutableStateFlow(mutableListOf(demoFavouritePharmacy)) /** * Data sources for the [oftenUsedPharmacies] created in the demo-mode */ - val oftenUsedPharmacies = MutableStateFlow(mutableListOf()) + val oftenUsedPharmacies: MutableStateFlow> = + MutableStateFlow(mutableListOf()) /** * Data sources for the [auditEvents] created in the demo-mode */ - val auditEvents = MutableStateFlow( - mutableListOf( - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadPrescription(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadPrescription(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadPrescription(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadPrescription(), - DemoAuditEventInfo.downloadDispense(), - DemoAuditEventInfo.downloadPrescription() + val auditEvents: MutableStateFlow> = + MutableStateFlow( + mutableListOf( + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadPrescription(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadPrescription(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadPrescription(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadPrescription(), + DemoAuditEventInfo.downloadDispense(), + DemoAuditEventInfo.downloadPrescription() + ) ) - ) /** * Data sources for the [communications] created in the demo-mode, * this is used as the source for communication between the user, pharmacy and the doctor */ - val communications = MutableStateFlow(mutableListOf()) + val communications: MutableStateFlow> = + MutableStateFlow(mutableListOf()) /** * Data source for the a [profileCommunicationLog] communication log that a particular profile has downloaded the information */ - val profileCommunicationLog = MutableStateFlow(mutableMapOf("no-profile-id" to false)) + val profileCommunicationLog: MutableStateFlow> = + MutableStateFlow(mutableMapOf("no-profile-id" to false)) /** * Data source for the [cachedPharmacies] used for communications */ - val cachedPharmacies = MutableStateFlow(mutableListOf()) + val cachedPharmacies: MutableStateFlow> = + MutableStateFlow(mutableListOf()) /** * Data source for the connected device [pairedDevices] that will be shown to the user */ - val pairedDevices = MutableStateFlow( - mutableListOf( - PairingResponseEntry( - name = "Pixel 10", - creationTime = Clock.System.now().minus(10.days).toEpochMilliseconds(), - signedPairingData = "pairing.data" - ) to - PairingData( - subjectPublicKeyInfoOfSecureElement = "subjectPublicKeyInfoOfSecureElement", - keyAliasOfSecureElement = "keyAliasOfSecureElement", - productName = "productName", - serialNumberOfHealthCard = "serialNumberOfHealthCard", - issuerOfHealthCard = "issuerOfHealthCard", - subjectPublicKeyInfoOfHealthCard = "subjectPublicKeyInfoOfHealthCard", - validityUntilOfHealthCard = Clock.System.now().plus(365.days).toEpochMilliseconds() - ) + val pairedDevices: MutableStateFlow>> = + MutableStateFlow( + mutableListOf( + PairingResponseEntry( + name = "Pixel 10", + creationTime = Clock.System.now().minus(10.days).toEpochMilliseconds(), + signedPairingData = "pairing.data" + ) to + PairingData( + subjectPublicKeyInfoOfSecureElement = "subjectPublicKeyInfoOfSecureElement", + keyAliasOfSecureElement = "keyAliasOfSecureElement", + productName = "productName", + serialNumberOfHealthCard = "serialNumberOfHealthCard", + issuerOfHealthCard = "issuerOfHealthCard", + subjectPublicKeyInfoOfHealthCard = "subjectPublicKeyInfoOfHealthCard", + validityUntilOfHealthCard = Clock.System.now().plus(365.days).toEpochMilliseconds() + ) + ) ) - ) } diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoAuditEventInfo.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoAuditEventInfo.kt index 2e781d86..793da09e 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoAuditEventInfo.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoAuditEventInfo.kt @@ -42,7 +42,7 @@ object DemoAuditEventInfo { internal fun downloadDispense(taskId: String = UUID.randomUUID().toString()) = AuditEventData.AuditEvent( auditId = UUID.randomUUID().toString(), taskId = taskId, - description = "Max Mustermann dowloaded a medication dispense list", + description = "Sie haben eine Medikamentenabgabeliste heruntergeladen", timestamp = Clock.System.now().minus(randomInt.randomDuration()) ) @@ -50,7 +50,7 @@ object DemoAuditEventInfo { AuditEventData.AuditEvent( auditId = UUID.randomUUID().toString(), taskId = taskId, - description = "Max Mustermann dowloaded a prescription $taskId", + description = "Sie haben ein Rezept heruntergeladen mit taskId $taskId", timestamp = Clock.System.now().minus(randomInt.randomDuration()) ) } diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoConstants.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoConstants.kt index 73086360..84520423 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoConstants.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoConstants.kt @@ -24,7 +24,6 @@ import kotlin.time.Duration.Companion.minutes object DemoConstants { internal val randomTimeToday = Clock.System.now().minus((1..20).random().minutes) - internal val pastDate = Clock.System.now().minus((15..100).random().days) internal val longerRandomTimeToday = Clock.System.now().minus((2..58).random().minutes) internal const val PHARMACY_TELEMATIK_ID = "3-03.2.1006210000.10.795" internal const val SYNCED_TASK_PRESET = "110.000.002.345.863" diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoPrescriptionInfo.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoPrescriptionInfo.kt index 25fb7a94..48608340 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoPrescriptionInfo.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoPrescriptionInfo.kt @@ -299,30 +299,6 @@ object DemoPrescriptionInfo { } internal object DemoSyncedPrescription { - internal val demoSyncedPrescription01 = SyncedTaskData.SyncedTask(/**/ - profileId = demoProfile01.id, - taskId = "${SYNCED_TASK_PRESET}.1", - isIncomplete = false, - pvsIdentifier = DEMO_MODE_IDENTIFIER, - accessCode = DEMO_MODE_IDENTIFIER, - lastModified = longerRandomTimeToday, - organization = ORGANIZATION, - practitioner = PRACTITIONER, - patient = PATIENT, - insuranceInformation = SyncedTaskData.InsuranceInformation( - name = null, - status = null - ), - expiresOn = EXPIRY_DATE, - acceptUntil = SHORT_EXPIRY_DATE, - authoredOn = NOW, - status = SyncedTaskData.TaskStatus.Ready, - medicationRequest = MEDICATION_REQUEST, - medicationDispenses = listOf(MEDICATION_DISPENSE), - communications = emptyList(), - failureToReport = "" - ) - internal fun syncedTask( profileIdentifier: ProfileIdentifier, status: SyncedTaskData.TaskStatus = SyncedTaskData.TaskStatus.Ready, diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoProfileInfo.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoProfileInfo.kt index 0f07270e..b802ffbd 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoProfileInfo.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/datasource/data/DemoProfileInfo.kt @@ -16,12 +16,15 @@ * */ +@file:Suppress("MagicNumber") + package de.gematik.ti.erp.app.demomode.datasource.data import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.db.entities.v1.InsuranceTypeV1 import de.gematik.ti.erp.app.demomode.datasource.data.DemoConstants.EXPIRY_DATE import de.gematik.ti.erp.app.demomode.datasource.data.DemoConstants.START_DATE +import de.gematik.ti.erp.app.demomode.model.DemoModeProfile import de.gematik.ti.erp.app.idp.model.IdpData import de.gematik.ti.erp.app.profiles.model.ProfilesData import kotlinx.datetime.Instant @@ -69,7 +72,14 @@ object DemoProfileInfo { isActive = true, color = ProfilesData.ProfileColorNames.SUN_DEW, insuranceType = InsuranceTypeV1.PKV, // Note: Private insurance account - avatar = ProfilesData.Avatar.FemaleDoctorWithPhone, + avatar = listOf( + ProfilesData.Avatar.FemaleDoctor, + ProfilesData.Avatar.FemaleDoctorWithPhone, + ProfilesData.Avatar.WomanWithHeadScarf, + ProfilesData.Avatar.WomanWithPhone, + ProfilesData.Avatar.Grandmother, + ProfilesData.Avatar.FemaleDeveloper + ).random(), lastAuthenticated = null ) @@ -80,31 +90,41 @@ object DemoProfileInfo { profileName = "Max Mustermann", isActive = false, insuranceType = InsuranceTypeV1.GKV, - avatar = ProfilesData.Avatar.OldManOfColor, + avatar = listOf( + ProfilesData.Avatar.OldManOfColor, + ProfilesData.Avatar.Grandfather, + ProfilesData.Avatar.ManWithPhone, + ProfilesData.Avatar.WheelchairUser, + ProfilesData.Avatar.MaleDoctorWithPhone + ).random(), lastAuthenticated = null ) private fun profile( profileName: String, isActive: Boolean = true, - color: ProfilesData.ProfileColorNames = ProfilesData.ProfileColorNames.BLUE_MOON, - avatar: ProfilesData.Avatar = ProfilesData.Avatar.FemaleDeveloper, + color: ProfilesData.ProfileColorNames = ProfilesData.ProfileColorNames.values().random(), + avatar: ProfilesData.Avatar = ProfilesData.Avatar.values().random(), insuranceType: InsuranceTypeV1 = InsuranceTypeV1.GKV, lastAuthenticated: Instant? = null, singleSignOnTokenScope: IdpData.SingleSignOnTokenScope? = cardToken - ) = ProfilesData.Profile( - id = UUID.randomUUID().toString(), - name = profileName, - color = color, - avatar = avatar, - insuranceIdentifier = insuranceNumberGenerator(), - insuranceType = insuranceType, - insurantName = profileName, - insuranceName = HEALTH_INSURANCE_COMPANIES.random(), - singleSignOnTokenScope = singleSignOnTokenScope, - active = isActive, - lastAuthenticated = lastAuthenticated - ) + ): DemoModeProfile { + val uuid = UUID.randomUUID() + return DemoModeProfile( + demoModeId = uuid, + id = uuid.toString(), + name = profileName, + color = color, + avatar = avatar, + insuranceIdentifier = insuranceNumberGenerator(), + insuranceType = insuranceType, + insurantName = profileName, + insuranceName = HEALTH_INSURANCE_COMPANIES.random(), + singleSignOnTokenScope = singleSignOnTokenScope, + active = isActive, + lastAuthenticated = lastAuthenticated + ) + } internal fun String.create() = profile(profileName = this) } diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/di/DemoModeModule.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/di/DemoModeModule.kt index 1ee15dbb..3fe7b09b 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/di/DemoModeModule.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/di/DemoModeModule.kt @@ -45,7 +45,6 @@ val demoModeModule = DI.Module("demoModeModule") { bindProvider { DemoDownloadCommunicationResource(instance()) } // only data source for demo mode bindSingleton { DemoModeDataSource() } - } fun DI.MainBuilder.demoModeOverrides() { diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeProfile.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeProfile.kt new file mode 100644 index 00000000..1d9e9164 --- /dev/null +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeProfile.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.demomode.model + +import de.gematik.ti.erp.app.db.entities.v1.InsuranceTypeV1 +import de.gematik.ti.erp.app.idp.model.IdpData +import de.gematik.ti.erp.app.profiles.model.ProfilesData +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import kotlinx.datetime.Instant +import java.util.UUID + +data class DemoModeProfile( + val demoModeId: UUID, + val id: ProfileIdentifier, + val color: ProfilesData.ProfileColorNames, + val avatar: ProfilesData.Avatar, + val personalizedImage: ByteArray? = null, + val name: String, + val insurantName: String? = null, + val insuranceIdentifier: String? = null, + val insuranceName: String? = null, + val insuranceType: InsuranceTypeV1, + val lastAuthenticated: Instant? = null, + val lastAuditEventSynced: Instant? = null, + val lastTaskSynced: Instant? = null, + val active: Boolean = false, + val singleSignOnTokenScope: IdpData.SingleSignOnTokenScope? +) + +fun MutableList.toProfiles() = map(DemoModeProfile::toProfile).toMutableList() + +fun DemoModeProfile.toProfile() = ProfilesData.Profile( + id = id, + color = color, + avatar = avatar, + personalizedImage = personalizedImage, + name = name, + insurantName = insurantName, + insuranceIdentifier = insuranceIdentifier, + insuranceName = insuranceName, + insuranceType = insuranceType, + lastAuthenticated = lastAuthenticated, + lastAuditEventSynced = lastAuditEventSynced, + lastTaskSynced = lastTaskSynced, + active = active, + singleSignOnTokenScope = singleSignOnTokenScope +) diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeSentCommunicationJson.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeSentCommunicationJson.kt index ec6fc505..c24b3ec5 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeSentCommunicationJson.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/model/DemoModeSentCommunicationJson.kt @@ -87,4 +87,3 @@ data class DemoModeCommunicationPayloadContent( ) } } - diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/orders/DemoCommunicationRepository.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/orders/DemoCommunicationRepository.kt index 1ce5409d..938852f7 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/orders/DemoCommunicationRepository.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/orders/DemoCommunicationRepository.kt @@ -16,6 +16,8 @@ * */ +@file:Suppress("TooManyFunctions", "MagicNumber") + package de.gematik.ti.erp.app.demomode.repository.orders import de.gematik.ti.erp.app.api.ResourcePaging @@ -108,7 +110,6 @@ class DemoCommunicationRepository( syncedTasks.find { it.taskId == taskId } }.flowOn(dispatcher) - override fun loadScannedByTaskId(taskId: String): Flow = dataSource.scannedTasks.map { scannedTask -> scannedTask.find { it.taskId == taskId } @@ -234,14 +235,15 @@ class DemoCommunicationRepository( @OptIn(ExperimentalCoroutinesApi::class) private fun loadOrdersForActiveProfile() = findActiveProfile().flatMapLatest { loadOrdersByProfileId(it.id) } - /** * Method added so that demoModeProfile02 always loads with some communication * and for other profiles we have to add it. [downloadCommunications] method takes * in profileId so this can be changed to a different profile later too */ - private fun loadOrdersByProfileId(profileId: ProfileIdentifier): - Flow> = + @OptIn(ExperimentalCoroutinesApi::class) + private fun loadOrdersByProfileId( + profileId: ProfileIdentifier + ): Flow> = // For the profile 2 we load it with some existing communications if (profileId == DemoProfileInfo.demoProfile02.id) { dataSource.profileCommunicationLog diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/pharmacy/DemoPharmacyLocalDataSource.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/pharmacy/DemoPharmacyLocalDataSource.kt index 9b434e7c..98d689bf 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/pharmacy/DemoPharmacyLocalDataSource.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/pharmacy/DemoPharmacyLocalDataSource.kt @@ -101,7 +101,8 @@ class DemoPharmacyLocalDataSource( withContext(dispatcher) { dataSource.favoritePharmacies.value = dataSource.favoritePharmacies.updateAndGet { val favoritePharmacies = it.toMutableList() - favoritePharmacies.indexOfFirst { existingPharmacy -> existingPharmacy.telematikId == pharmacy.telematikId } + favoritePharmacies + .indexOfFirst { existingPharmacy -> existingPharmacy.telematikId == pharmacy.telematikId } .takeIf { index -> index != INDEX_OUT_OF_BOUNDS }?.let { index -> favoritePharmacies[index] = favoritePharmacies[index].copy(lastUsed = Clock.System.now()) favoritePharmacies @@ -127,7 +128,6 @@ class DemoPharmacyLocalDataSource( favoritePharmacy != null }.flowOn(dispatcher) - override suspend fun markAsRedeemed(taskId: String) { withContext(dispatcher) { dataSource.scannedTasks.value = dataSource.scannedTasks.updateAndGet { diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoPrescriptionsRepository.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoPrescriptionsRepository.kt index 46b5b455..eda63295 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoPrescriptionsRepository.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoPrescriptionsRepository.kt @@ -31,6 +31,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.withContext @@ -57,13 +58,13 @@ class DemoPrescriptionsRepository( } override fun scannedTasks(profileId: ProfileIdentifier): Flow> = dataSource.scannedTasks + .map { list -> list.filter { it.profileId == profileId } } override fun syncedTasks(profileId: ProfileIdentifier): Flow> = dataSource.syncedTasks.mapNotNull { taskList -> taskList.filter { it.profileId == profileId }.sortedBy { it.lastModified } }.flowOn(dispatcher) - override suspend fun redeemPrescription( profileId: ProfileIdentifier, communication: JsonElement, @@ -88,7 +89,8 @@ class DemoPrescriptionsRepository( } dataSource.scannedTasks.value = dataSource.scannedTasks.updateAndGet { val scannedList = it.toMutableList() - scannedList.removeIf { scannedItem -> scannedItem.taskId == taskId && scannedItem.profileId == profileId } + scannedList + .removeIf { scannedItem -> scannedItem.taskId == taskId && scannedItem.profileId == profileId } scannedList } Result.success(Unit) diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoTaskRepository.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoTaskRepository.kt index 0f0d7fc1..1188026d 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoTaskRepository.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/prescriptions/DemoTaskRepository.kt @@ -16,6 +16,8 @@ * */ +@file:Suppress("MagicNumber") + package de.gematik.ti.erp.app.demomode.repository.prescriptions import de.gematik.ti.erp.app.api.ResourcePaging.ResourceResult @@ -43,6 +45,4 @@ class DemoTaskRepository( ): Result> = Result.success(ResourceResult(0, 0)) override suspend fun syncedUpTo(profileId: ProfileIdentifier): Instant? = null - } - diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/profiles/DemoProfilesRepository.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/profiles/DemoProfilesRepository.kt index 88979bb4..4f267f03 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/profiles/DemoProfilesRepository.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/profiles/DemoProfilesRepository.kt @@ -20,6 +20,9 @@ package de.gematik.ti.erp.app.demomode.repository.profiles import de.gematik.ti.erp.app.demomode.datasource.DemoModeDataSource import de.gematik.ti.erp.app.demomode.datasource.INDEX_OUT_OF_BOUNDS import de.gematik.ti.erp.app.demomode.datasource.data.DemoProfileInfo.create +import de.gematik.ti.erp.app.demomode.model.DemoModeProfile +import de.gematik.ti.erp.app.demomode.model.toProfile +import de.gematik.ti.erp.app.demomode.model.toProfiles import de.gematik.ti.erp.app.demomode.repository.profiles.DemoProfilesRepository.ImageActions.Add import de.gematik.ti.erp.app.demomode.repository.profiles.DemoProfilesRepository.ImageActions.NoAction import de.gematik.ti.erp.app.demomode.repository.profiles.DemoProfilesRepository.ImageActions.Remove @@ -28,20 +31,25 @@ import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.repository.ProfileRepository import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.flow.updateAndGet import kotlinx.coroutines.withContext import kotlinx.datetime.Instant +import java.util.UUID class DemoProfilesRepository( private val dataSource: DemoModeDataSource, private val dispatcher: CoroutineDispatcher = Dispatchers.IO ) : ProfileRepository { - override fun profiles() = dataSource.profiles + private fun demoModeProfiles(): MutableStateFlow> = dataSource.profiles + override fun profiles(): Flow> = demoModeProfiles() + .mapNotNull(MutableList::toProfiles) - override fun activeProfile() = profiles().mapNotNull { - it.find { profile -> profile.active } + override fun activeProfile() = demoModeProfiles().mapNotNull { + it.find { profile -> profile.active }?.toProfile() } override suspend fun saveProfile(profileName: String, activate: Boolean) { @@ -142,11 +150,13 @@ class DemoProfilesRepository( // Not for demo mode, will come later } - private fun MutableList.index(profileId: ProfileIdentifier) = + override suspend fun checkIsProfilePKV(profileId: ProfileIdentifier): Boolean = false + + private fun MutableList.index(profileId: ProfileIdentifier) = indexOfFirst { profile -> profile.id == profileId } .takeIf { it != INDEX_OUT_OF_BOUNDS } - private fun MutableList.replace( + private fun MutableList.replace( profileId: ProfileIdentifier, activate: Boolean? = null, name: String? = null, @@ -155,10 +165,11 @@ class DemoProfilesRepository( avatar: ProfilesData.Avatar? = null, profileImage: ByteArray? = null, imageAction: ImageActions = NoAction - ): MutableList = + ): MutableList = index(profileId)?.let { index -> val existingProfile = this[index] this[index] = this[index].copy( + demoModeId = existingProfile.demoModeId, active = activate ?: existingProfile.active, name = name ?: existingProfile.name, color = color ?: existingProfile.color, @@ -173,13 +184,13 @@ class DemoProfilesRepository( this } ?: this - private fun List.deactivateAllProfiles() = + private fun List.deactivateAllProfiles() = mapNotNull { it.copy(active = false) }.toMutableList() - private fun MutableList.updateUUIDForChangeVisibility() = this - // map { it.copy(id = UUID.randomUUID().toString()) }.toMutableList() + private fun MutableList.updateUUIDForChangeVisibility() = + map { it.copy(demoModeId = UUID.randomUUID()) }.toMutableList() enum class ImageActions { Add, Remove, NoAction diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/protocol/DemoAuditEventsRepository.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/protocol/DemoAuditEventsRepository.kt index f82476bf..4c1767a0 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/protocol/DemoAuditEventsRepository.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/repository/protocol/DemoAuditEventsRepository.kt @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + package de.gematik.ti.erp.app.demomode.repository.protocol import de.gematik.ti.erp.app.demomode.datasource.DemoModeDataSource @@ -19,5 +37,4 @@ class DemoAuditEventsRepository(private val dataSource: DemoModeDataSource) : Au ) return Result.success(mappingResult) } - -} \ No newline at end of file +} diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/ui/DemoModeTopAppBar.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/ui/DemoModeTopAppBar.kt index d30e447d..ec5dbf85 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/ui/DemoModeTopAppBar.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/ui/DemoModeTopAppBar.kt @@ -40,7 +40,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextDecoration import com.google.accompanist.systemuicontroller.rememberSystemUiController -import de.gematik.ti.erp.app.demomode.DemoModeActivity +import de.gematik.ti.erp.app.demomode.DemoModeObserver @Suppress("ComposableNaming") @Composable @@ -49,8 +49,8 @@ fun checkForDemoMode( demoModeContent: @Composable ColumnScope.() -> Unit, appContent: @Composable ColumnScope.() -> Unit ) { - val activity = LocalContext.current.getAsDemoModeActivity() - val isDemoMode = (activity)?.isDemoMode() ?: false + val demoModeObserver = LocalContext.current.getDemoModeObserver() + val isDemoMode = demoModeObserver?.isDemoMode() ?: false val systemUiController = rememberSystemUiController() Column( @@ -77,7 +77,7 @@ fun DemoModeStatusBar( ) { Row( modifier = Modifier - .fillMaxWidth() + .then(modifier) .background(backgroundColor), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically @@ -108,4 +108,4 @@ private fun Context.getActivity(): AppCompatActivity? { return null } -internal fun Context.getAsDemoModeActivity(): DemoModeActivity? = getActivity() as? DemoModeActivity +internal fun Context.getDemoModeObserver(): DemoModeObserver? = getActivity() as? DemoModeObserver diff --git a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/usecase/idp/DemoIdpUseCase.kt b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/usecase/idp/DemoIdpUseCase.kt index ed355270..470ebc83 100644 --- a/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/usecase/idp/DemoIdpUseCase.kt +++ b/app/demo-mode/src/main/kotlin/de/gematik/ti/erp/app/demomode/usecase/idp/DemoIdpUseCase.kt @@ -92,11 +92,11 @@ class DemoIdpUseCase( // no implementation for demo mode } - override suspend fun getPairedDevices(profileId: ProfileIdentifier): Result>> = - withContext(dispatcher) { - val device = dataSource.pairedDevices.map { it.toList() }.first() - Result.success(device) - } + override suspend fun getPairedDevices(profileId: ProfileIdentifier): + Result>> = withContext(dispatcher) { + val device = dataSource.pairedDevices.map { it.toList() }.first() + Result.success(device) + } override suspend fun deletePairedDevice(profileId: ProfileIdentifier, deviceAlias: String): Result = withContext(dispatcher) { diff --git a/app/features/build.gradle.kts b/app/features/build.gradle.kts index b9dfd63e..a1bf8f97 100644 --- a/app/features/build.gradle.kts +++ b/app/features/build.gradle.kts @@ -18,10 +18,6 @@ plugins { id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") } -tasks.named("preBuild") { - dependsOn(":ktlint", ":detekt") -} - licenseReport { generateCsvReport = false generateHtmlReport = false @@ -48,11 +44,20 @@ android { it.name.startsWith("kapt") }.map { it.name } } + buildTypes { + val debug by getting { + isJniDebuggable = true + } + create("minifiedDebug") { + initWith(debug) + } + } } dependencies { implementation(project(":common")) implementation(project(":app:demo-mode")) + implementation("com.google.android.material:material:1.10.0") testImplementation(project(":common")) implementation(kotlin("stdlib")) implementation(kotlin("reflect")) @@ -154,6 +159,8 @@ dependencies { } tracking { implementation(contentSquare) + implementation(contentSquareCompose) + implementation(contentSquareErrorAnalysis) } maps { implementation(location) diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/DebugSettingsData.kt similarity index 97% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/DebugSettingsData.kt index 8dff7814..81e1b563 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/DebugSettingsData.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.data +package de.gematik.ti.erp.app.data import android.os.Parcelable import androidx.compose.runtime.Immutable diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/Environment.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/Environment.kt similarity index 94% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/Environment.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/Environment.kt index f02c0fbb..3be5c794 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/data/Environment.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/data/Environment.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.data +package de.gematik.ti.erp.app.data enum class Environment { PU, TU, RU, RUDEV, TR diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/di/EndpointHelper.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/di/EndpointHelper.kt index 944a9d39..032c213a 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/di/EndpointHelper.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/di/EndpointHelper.kt @@ -21,7 +21,7 @@ package de.gematik.ti.erp.app.di import android.content.SharedPreferences import androidx.core.content.edit import de.gematik.ti.erp.app.BuildKonfig -import de.gematik.ti.erp.app.debug.data.Environment +import de.gematik.ti.erp.app.data.Environment class EndpointHelper( private val networkPrefs: SharedPreferences diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/navigation/DebugScreenNavigation.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/navigation/DebugScreenNavigation.kt new file mode 100644 index 00000000..4a63a258 --- /dev/null +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/navigation/DebugScreenNavigation.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import de.gematik.ti.erp.app.debugsettings.timeout.DebugTimeoutScreen + +object DebugScreenNavigation { + object DebugMain : Routes("DebugMain") + object DebugRedeemWithoutFD : Routes("DebugRedeemWithoutFD") + object DebugPKV : Routes("DebugPKV") + object DebugBiometric : Routes(DebugTimeoutScreen::class::java.name) +} diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugLoadingButton.kt similarity index 98% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugLoadingButton.kt index 3bc733f5..366695d5 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugLoadingButton.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size @@ -24,11 +24,11 @@ import androidx.compose.material.Button import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugPKV.kt similarity index 99% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugPKV.kt index 557327c6..4e7fbdc7 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugPKV.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.PaddingValues diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreen.kt similarity index 88% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreen.kt index b6bdb198..1e825adb 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreen.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import android.content.Intent import android.net.Uri @@ -69,6 +69,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -77,8 +78,11 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.debug.data.Environment +import de.gematik.ti.erp.app.data.Environment +import de.gematik.ti.erp.app.debugsettings.timeout.DebugTimeoutScreen import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.navigation.DebugScreenNavigation +import de.gematik.ti.erp.app.settings.ui.LabelButton import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AlertDialog @@ -111,33 +115,35 @@ fun DebugCard( modifier = modifier, shape = RoundedCornerShape(24.dp), backgroundColor = AppTheme.colors.neutral100, - elevation = 0.dp, - border = null + elevation = 10.dp ) { - Box { - Column( - Modifier.padding(PaddingDefaults.Medium), - verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Small) - ) { - Text( - title, - style = MaterialTheme.typography.h6, - modifier = Modifier.align(Alignment.CenterHorizontally) - ) - SpacerMedium() - content() - } - onReset?.run { - IconButton( - modifier = Modifier - .align(Alignment.TopEnd) - .padding(PaddingDefaults.Small), - onClick = onReset + Box( + contentAlignment = Alignment.Center, + content = { + Column( + Modifier.padding(PaddingDefaults.Medium), + verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Small) ) { - Icon(Icons.Rounded.Refresh, null) + Text( + title, + style = MaterialTheme.typography.h6, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + SpacerMedium() + content() + } + onReset?.run { + IconButton( + modifier = Modifier + .align(Alignment.TopEnd) + .padding(PaddingDefaults.Small), + onClick = onReset + ) { + Icon(Icons.Rounded.Refresh, null) + } } } - } + ) } @Composable @@ -232,6 +238,9 @@ fun DebugScreen( }, onClickPKV = { navController.navigate(DebugScreenNavigation.DebugPKV.path()) + }, + onClickBioMetricSettings = { + navController.navigate(DebugScreenNavigation.DebugBiometric.path()) } ) } @@ -254,6 +263,12 @@ fun DebugScreen( ) } } + + composable(DebugScreenNavigation.DebugBiometric.route) { + DebugTimeoutScreen.Content { + navController.popBackStack() + } + } } } } @@ -394,7 +409,8 @@ private fun RedeemButton( fun DebugScreenMain( onBack: () -> Unit, onClickDirectRedemption: () -> Unit, - onClickPKV: () -> Unit + onClickPKV: () -> Unit, + onClickBioMetricSettings: () -> Unit ) { val viewModel by rememberViewModel() val listState = rememberLazyListState() @@ -423,7 +439,6 @@ fun DebugScreenMain( LaunchedEffect(Unit) { viewModel.state() } - val scope = rememberCoroutineScope() LazyColumn( state = listState, @@ -439,23 +454,29 @@ fun DebugScreenMain( DebugCard( title = "General" ) { - Button( - onClick = onClickDirectRedemption, - modifier = Modifier.fillMaxWidth() + LabelButton( + icon = painterResource(R.drawable.ic_finger), + text = "Biometric settings" ) { - Text(text = "Direct Redemption") + onClickBioMetricSettings() } - Button( - onClick = onClickPKV, - modifier = Modifier.fillMaxWidth() + LabelButton( + icon = painterResource(R.drawable.ic_qr_code), + text = "Direct Redemption" ) { - Text(text = "PKV") + onClickDirectRedemption() } - Button( - onClick = { viewModel.refreshPrescriptions() }, - modifier = Modifier.fillMaxWidth() + LabelButton( + icon = painterResource(R.drawable.ic_pkv), + text = "PKV" + ) { + onClickPKV() + } + LabelButton( + icon = painterResource(R.drawable.ic_prescription_refresh), + text = "Trigger Prescription Refresh" ) { - Text(text = "Trigger Prescription Refresh") + viewModel.refreshPrescriptions() } } } @@ -463,7 +484,10 @@ fun DebugScreenMain( DebugCard( title = "Card Wall" ) { - Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { Text( text = "Fake NFC Capability", modifier = Modifier @@ -520,7 +544,6 @@ fun DebugScreenMain( item { FeatureToggles(viewModel = viewModel) } - item { RotatingLog(viewModel = viewModel) } @@ -534,8 +557,10 @@ private fun RotatingLog(modifier: Modifier = Modifier, viewModel: DebugSettingsV DebugCard(modifier, title = "Log") { val context = LocalContext.current val mailAddress = stringResource(R.string.settings_contact_mail_address) - Button( + LabelButton( modifier = Modifier.fillMaxWidth(), + icon = painterResource(R.drawable.ic_log_mail), + text = "Send mail", onClick = { val intent = Intent(Intent.ACTION_SENDTO) intent.data = Uri.parse("mailto:") @@ -558,9 +583,7 @@ private fun RotatingLog(modifier: Modifier = Modifier, viewModel: DebugSettingsV context.startActivity(intent) } } - ) { - Text("Send Mail") - } + ) } } @@ -639,7 +662,11 @@ private fun VirtualHealthCard(modifier: Modifier = Modifier, viewModel: DebugSet enabled = !virtualHealthCardLoading ) { if (virtualHealthCardLoading) { - CircularProgressIndicator(Modifier.size(24.dp), strokeWidth = 2.dp, color = AppTheme.colors.neutral600) + CircularProgressIndicator( + Modifier.size(24.dp), + strokeWidth = 2.dp, + color = AppTheme.colors.neutral600 + ) SpacerSmall() } Text("Set Virtual Health Card for Active Profile", textAlign = TextAlign.Center) @@ -706,7 +733,10 @@ fun EnvironmentSelector( } ) { Row( - modifier = Modifier.padding(horizontal = PaddingDefaults.Medium, vertical = PaddingDefaults.Small), + modifier = Modifier.padding( + horizontal = PaddingDefaults.Medium, + vertical = PaddingDefaults.Small + ), horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically ) { diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreenWrapper.kt similarity index 95% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreenWrapper.kt index ee454dc3..76c0e894 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugScreenWrapper.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import androidx.compose.runtime.Composable import androidx.navigation.NavController diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugSettingsViewModel.kt similarity index 99% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt rename to app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugSettingsViewModel.kt index c4e1561a..40be1a3e 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt +++ b/app/features/src/debug/kotlin/de/gematik/ti/erp/app/ui/DebugSettingsViewModel.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import android.content.Intent import android.content.pm.PackageManager @@ -34,8 +34,8 @@ import de.gematik.ti.erp.app.DispatchProvider import de.gematik.ti.erp.app.ErezeptApp import de.gematik.ti.erp.app.VisibleDebugTree import de.gematik.ti.erp.app.cardwall.usecase.CardWallUseCase -import de.gematik.ti.erp.app.debug.data.DebugSettingsData -import de.gematik.ti.erp.app.debug.data.Environment +import de.gematik.ti.erp.app.data.DebugSettingsData +import de.gematik.ti.erp.app.data.Environment import de.gematik.ti.erp.app.di.EndpointHelper import de.gematik.ti.erp.app.featuretoggle.FeatureToggleManager import de.gematik.ti.erp.app.featuretoggle.Features diff --git a/app/features/src/main/AndroidManifest.xml b/app/features/src/main/AndroidManifest.xml index 021d37c1..8cf395e1 100644 --- a/app/features/src/main/AndroidManifest.xml +++ b/app/features/src/main/AndroidManifest.xml @@ -3,6 +3,10 @@ + { - debugOverrides() - fullContainerTreeOnError = true - } - } - bindProvider { ExternalAuthenticatorListViewModel(instance(), instance()) } - bindProvider { CheckVersionUseCase(instance(), instance()) } - } - - private val checkVersionUseCase: CheckVersionUseCase by instance() - - private val auth: AuthenticationUseCase by instance() - - private val analytics: Analytics by instance() - - private val intentHandler = IntentHandler(this) - - private val _nfcTag = MutableSharedFlow() - val nfcTagFlow: Flow - get() = _nfcTag.onStart { - if (!NfcAdapter.getDefaultAdapter(this@MainActivity).isEnabled) { - throw NfcNotEnabledException() - } - } - - private val authenticationModeAndMethod: Flow - get() = auth.authenticationModeAndMethod +class MainActivity : BaseActivity() { // @VisibleForTesting(otherwise = VisibleForTesting.NONE) // Only visible for testing, otherwise shows a warning val testWrapper: TestWrapper by instance() @@ -145,6 +90,7 @@ class MainActivity : DemoModeActivity(), DIAware { // @RestrictTo(RestrictTo.Scope.TESTS) val elementsUsedInTests: SnapshotStateMap = mutableStateMapOf() + @Suppress("LongMethod") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -172,6 +118,7 @@ class MainActivity : DemoModeActivity(), DIAware { if (!BuildConfig.DEBUG) { installMessageConversionExceptionHandler() } + WindowCompat.setDecorFitsSystemWindows(window, false) setContent { @@ -179,6 +126,7 @@ class MainActivity : DemoModeActivity(), DIAware { LaunchedEffect(view) { ViewCompat.setWindowInsetsAnimationCallback(view, null) } + withDI(di) { CompositionLocalProvider( LocalActivity provides this, @@ -187,16 +135,17 @@ class MainActivity : DemoModeActivity(), DIAware { LocalAuthenticator provides rememberAuthenticator(intentHandler) ) { val authenticator = LocalAuthenticator.current - AppContent { settingsController -> + AppContent { val profilesController = rememberProfilesController() - val screenShotState by settingsController.screenshotState + val mainScreenController = rememberMainScreenController() + val screenshotsAllowed by mainScreenController.screenshotsState - if (screenShotState.screenshotsAllowed) { + if (screenshotsAllowed) { this.window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE) } else { this.window.addFlags(WindowManager.LayoutParams.FLAG_SECURE) } - val auth by produceState(null) { + val authentication by produceState(null) { launch { authenticationModeAndMethod.distinctUntilChangedBy { it::class } .collect { @@ -212,12 +161,9 @@ class MainActivity : DemoModeActivity(), DIAware { val navController = rememberNavController() val noDrawModifier = Modifier.graphicsLayer(alpha = 0f) val activeProfile by profilesController.getActiveProfileState() - val ssoTokenValid = rememberSaveable(activeProfile.ssoTokenScope) { - activeProfile.ssoTokenValid() - } Box { - if (auth !is AuthenticationModeAndMethod.Authenticated) { + if (authentication !is Authenticated) { Image( painterResource(R.drawable.erp_logo), null, @@ -227,17 +173,16 @@ class MainActivity : DemoModeActivity(), DIAware { DialogHost { Box( - if (auth is AuthenticationModeAndMethod.Authenticated) Modifier else noDrawModifier + if (authentication is Authenticated) Modifier else noDrawModifier ) { // mini card wall - if (!ssoTokenValid) { - HealthCardPrompt( - authenticator = authenticator.authenticatorHealthCard - ) - ExternalAuthPrompt( - authenticator = authenticator.authenticatorExternal - ) - } + HealthCardPrompt( + authenticator = authenticator.authenticatorHealthCard + ) + + ExternalAuthPrompt( + authenticator = authenticator.authenticatorExternal + ) SecureHardwarePrompt( authenticator = authenticator.authenticatorSecureElement @@ -256,7 +201,7 @@ class MainActivity : DemoModeActivity(), DIAware { DialogHost { AnimatedVisibility( - visible = auth is AuthenticationModeAndMethod.AuthenticationRequired, + visible = authentication is AuthenticationModeAndMethod.AuthenticationRequired, enter = fadeIn(), exit = fadeOut() ) { @@ -272,77 +217,4 @@ class MainActivity : DemoModeActivity(), DIAware { } } } - - @Requirement( - "O.Arch_10#2", - sourceSpecification = "BSI-eRp-ePA", - rationale = "If an update is required, the user is prompted to update via Google´s InAppUpdate function" - ) - private suspend fun checkAppUpdate() { - if (checkVersionUseCase.isUpdateRequired()) { - val appUpdateManager = AppUpdateManagerFactory.create(this) - val appUpdateInfoTask = appUpdateManager.appUpdateInfo - - appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> - if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) { - val task = appUpdateManager.startUpdateFlow( - appUpdateInfo, - this, - AppUpdateOptions.defaultOptions(IMMEDIATE) - ) - - task.addOnCompleteListener { - if (task.isSuccessful && task.result != Activity.RESULT_OK) { - finish() - } - } - } - } - } - } - - override fun onUserInteraction() { - super.onUserInteraction() - - auth.resetInactivityTimer() - } - - override fun onNewIntent(intent: Intent?) { - super.onNewIntent(intent) - - lifecycleScope.launch { - intent?.let { - intentHandler.propagateIntent(it) - } - } - } - - override fun onResume() { - super.onResume() - - NfcAdapter.getDefaultAdapter(applicationContext)?.let { - if (it.isEnabled) { - it.enableReaderMode( - this, - ::onTagDiscovered, - NfcAdapter.FLAG_READER_NFC_A - or NfcAdapter.FLAG_READER_NFC_B - or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, - Bundle() - ) - } - } - } - - private fun onTagDiscovered(tag: Tag) { - lifecycleScope.launch { - _nfcTag.emit(tag) - } - } - - override fun onPause() { - super.onPause() - - NfcAdapter.getDefaultAdapter(applicationContext)?.disableReaderMode(this) - } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/Analytics.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/Analytics.kt index 3c772ddf..2132e6a0 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/Analytics.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/Analytics.kt @@ -19,31 +19,36 @@ package de.gematik.ti.erp.app.analytics import android.content.Context -import android.content.SharedPreferences import android.net.Uri import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.core.content.edit import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavHostController import com.contentsquare.android.Contentsquare import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.analytics.usecase.AnalyticsUseCase import de.gematik.ti.erp.app.analytics.usecase.AnalyticsUseCaseData +import de.gematik.ti.erp.app.analytics.usecase.ChangeAnalyticsStateUseCase +import de.gematik.ti.erp.app.analytics.usecase.IsAnalyticsAllowedUseCase import de.gematik.ti.erp.app.cardwall.usecase.AuthenticationState import de.gematik.ti.erp.app.core.LocalAnalytics import de.gematik.ti.erp.app.mainscreen.ui.MainScreenBottomSheetContentState import de.gematik.ti.erp.app.pharmacy.ui.PharmacySearchSheetContentState import de.gematik.ti.erp.app.prescription.detail.ui.PrescriptionDetailBottomSheetContent import io.github.aakira.napier.Napier +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine - -private const val PrefsName = "analyticsAllowed" +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch @Requirement( "A_19095", @@ -52,12 +57,20 @@ private const val PrefsName = "analyticsAllowed" ) class Analytics( private val context: Context, - private val prefs: SharedPreferences, - analyticsUseCase: AnalyticsUseCase + private val isAnalyticsAllowedUseCase: IsAnalyticsAllowedUseCase, + private val changeAnalyticsStateUseCase: ChangeAnalyticsStateUseCase, + private val analyticsUseCase: AnalyticsUseCase, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO ) { - private val _analyticsAllowed = MutableStateFlow(false) + + private val scope = CoroutineScope(dispatcher) + + private val isAnalyticsAllowed by lazy { + isAnalyticsAllowedUseCase.invoke() + } + val analyticsAllowed: StateFlow - get() = _analyticsAllowed + get() = isAnalyticsAllowed.stateIn(scope, SharingStarted.Eagerly, false) @Requirement( "A_19093", @@ -84,11 +97,9 @@ class Analytics( Contentsquare.forgetMe() - _analyticsAllowed.value = prefs.getBoolean(PrefsName, false) - if (_analyticsAllowed.value) { - allowAnalytics() - } else { - disallowAnalytics() + scope.launch { + val isAllowed = isAnalyticsAllowed.first() + setAnalyticsPreference(isAllowed) } } @@ -125,18 +136,20 @@ class Analytics( @Requirement( "O.Purp_5#5", sourceSpecification = "BSI-eRp-ePA", - rationale = "Enable usage analytics." + rationale = "Enable/disable usage analytics." ) - fun allowAnalytics() { - _analyticsAllowed.value = true - - Contentsquare.optIn(context) - - prefs.edit { - putBoolean(PrefsName, true) + fun setAnalyticsPreference(allow: Boolean) { + when (allow) { + true -> allowAnalytics() + else -> disallowAnalytics() } - - Napier.d("Analytics allowed") + } + private fun allowAnalytics() { + scope.launch { + changeAnalyticsStateUseCase.invoke(true) + } + Contentsquare.optIn(context) + Napier.i("Analytics allowed") } @Requirement( @@ -149,16 +162,12 @@ class Analytics( sourceSpecification = "BSI-eRp-ePA", rationale = "Disable usage analytics." ) - fun disallowAnalytics() { - _analyticsAllowed.value = false - - Contentsquare.optOut(context) - - prefs.edit { - putBoolean(PrefsName, false) + private fun disallowAnalytics() { + scope.launch { + changeAnalyticsStateUseCase.invoke(false) } - - Napier.d("Analytics disallowed") + Contentsquare.optOut(context) + Napier.i("Analytics disallowed") } fun trackIdentifiedWithIDP() { @@ -188,7 +197,7 @@ class Analytics( @Suppress("ComposableNaming") @Composable -fun trackNavigationChanges( +fun trackNavigationChangesAsync( navController: NavHostController, previousNavEntry: String, onNavEntryChange: (String) -> Unit diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/mapper/ContentSquareMapper.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/mapper/ContentSquareMapper.kt new file mode 100644 index 00000000..4f56a9b9 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/mapper/ContentSquareMapper.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.analytics.mapper + +import de.gematik.ti.erp.app.navigation.NavigationRouteNames + +class ContentSquareMapper { + fun map(routeNames: NavigationRouteNames): String = + when (routeNames) { + NavigationRouteNames.DeviceCheckLoadingScreen -> "appsecurity:loading" + NavigationRouteNames.InsecureDeviceScreen -> "main_deviceSecurity" + NavigationRouteNames.IntegrityWarningScreen -> "main_integrityWarning" + NavigationRouteNames.ProfileDetailsScreen -> "" + NavigationRouteNames.ProfileColorAndImagePickerScreen -> "" + NavigationRouteNames.ProfileImageCropperScreen -> "" + NavigationRouteNames.ProfileTokenScreen -> "" + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/ChangeAnalyticsStateUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/ChangeAnalyticsStateUseCase.kt new file mode 100644 index 00000000..944f3b77 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/ChangeAnalyticsStateUseCase.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.analytics.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class ChangeAnalyticsStateUseCase( + private val repository: SettingsRepository, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + suspend operator fun invoke(state: Boolean) { + withContext(dispatcher) { + repository.changeTrackingState(state) + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/IsAnalyticsAllowedUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/IsAnalyticsAllowedUseCase.kt new file mode 100644 index 00000000..60e94a3e --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/analytics/usecase/IsAnalyticsAllowedUseCase.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.analytics.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn + +class IsAnalyticsAllowedUseCase( + private val repository: SettingsRepository, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + operator fun invoke(): Flow = repository.isAnalyticsAllowed().flowOn(dispatcher) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecurityModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecurityModule.kt new file mode 100644 index 00000000..25020e4d --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecurityModule.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity + +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptDeviceSecurityRiskUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptIntegrityRiskUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.GetDeviceSecurityUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.IntegrityUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.IsIntegrityRiskAcceptedUseCase +import org.kodein.di.DI +import org.kodein.di.bindProvider +import org.kodein.di.bindSingleton +import org.kodein.di.instance + +val appSecurityModule = DI.Module("appSecurityModule") { + bindSingleton { AppSecuritySession() } + bindProvider { IntegrityUseCase(instance()) } + bindProvider { GetDeviceSecurityUseCase(instance(), instance(), instance()) } + bindProvider { AcceptIntegrityRiskUseCase(instance(), instance()) } + bindProvider { AcceptDeviceSecurityRiskUseCase(instance(), instance()) } + bindProvider { IsIntegrityRiskAcceptedUseCase(instance(), instance()) } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecuritySession.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecuritySession.kt new file mode 100644 index 00000000..96711ac9 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/AppSecuritySession.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity + +import kotlinx.coroutines.flow.MutableStateFlow + +/** + * Holds the session variables which decides to show the integrity screen or device security screen in the app session + */ +class AppSecuritySession { + + private val isIntegrityAcceptedForSession = MutableStateFlow(false) + + private val isDeviceSecurityAcceptedForSession = MutableStateFlow(false) + + fun acceptIntegrityForSession() { + isIntegrityAcceptedForSession.value = true + } + + fun acceptDeviceSecurityForSession() { + isDeviceSecurityAcceptedForSession.value = true + } + + fun isIntegrityAcceptedForSession() = isIntegrityAcceptedForSession.value + + fun isDeviceSecurityAcceptedForSession() = isDeviceSecurityAcceptedForSession.value +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityGraph.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityGraph.kt new file mode 100644 index 00000000..509eb958 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityGraph.kt @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.navigation + +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.navigation +import de.gematik.ti.erp.app.appsecurity.navigation.AppSecurityRoutes.DeviceCheckLoadingScreen +import de.gematik.ti.erp.app.appsecurity.ui.DeviceCheckLoadingStartScreen +import de.gematik.ti.erp.app.appsecurity.ui.InsecureDeviceScreen +import de.gematik.ti.erp.app.appsecurity.ui.IntegrityWarningScreen +import de.gematik.ti.erp.app.navigation.renderComposable +import de.gematik.ti.erp.app.navigation.toNavigationString +import io.github.aakira.napier.Napier + +fun NavGraphBuilder.appSecurityGraph( + startDestination: String = DeviceCheckLoadingScreen.route, + navController: NavController, + onAppSecurityPassed: () -> Unit +) { + navigation(startDestination = startDestination, route = AppSecurityRoutes.subGraphName()) { + renderComposable( + route = DeviceCheckLoadingScreen.route, + enterTransition = { + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Up) + }, + exitTransition = { + slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Down) + } + ) { + DeviceCheckLoadingStartScreen( + navController = navController, + navBackStackEntry = it, + onSecurityCheckResult = { appSecurityResult -> + Napier.d( + tag = "AppSecurity check", + message = "Results from DeviceCheckLoadingStartScreen\n" + + "isIntegrityAttested: ${appSecurityResult.isIntegritySecure}\n" + + "isDeviceSecure: ${appSecurityResult.isDeviceSecure}\n" + ) + when { + appSecurityResult.isIntegritySecure && appSecurityResult.isDeviceSecure -> onAppSecurityPassed() + appSecurityResult.isIntegritySecure && !appSecurityResult.isDeviceSecure -> + navController.navigate(AppSecurityRoutes.InsecureDeviceScreen.path()) { + launchSingleTop = true + } + + else -> { + navController.navigate( + route = AppSecurityRoutes.IntegrityWarningScreen.path( + appSecurityResult.toNavigationString() + ) + ) { + launchSingleTop = true + } + } + } + } + ) + } + renderComposable( + route = AppSecurityRoutes.IntegrityWarningScreen.route, + arguments = AppSecurityRoutes.IntegrityWarningScreen.arguments, + enterTransition = { + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Up) + }, + exitTransition = { + slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Down) + } + ) { + Napier.d( + tag = "AppSecurity check", + message = "IntegrityWarningScreen loaded" + ) + IntegrityWarningScreen( + navController = navController, + navBackStackEntry = it, + onBack = { isDeviceSecure -> + if (isDeviceSecure) { + onAppSecurityPassed() + } else { + navController.navigate(AppSecurityRoutes.InsecureDeviceScreen.path()) { + launchSingleTop = true + } + } + } + ) + } + renderComposable( + route = AppSecurityRoutes.InsecureDeviceScreen.route, + enterTransition = { + slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.Up) + }, + exitTransition = { + slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Down) + } + ) { + Napier.d( + tag = "AppSecurity check", + message = "InsecureDeviceScreen loaded" + ) + InsecureDeviceScreen( + navController = navController, + navBackStackEntry = it, + onBack = onAppSecurityPassed + ) + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityRoutes.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityRoutes.kt new file mode 100644 index 00000000..02c20e6a --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/navigation/AppSecurityRoutes.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.navigation + +import androidx.navigation.NavType +import androidx.navigation.navArgument +import de.gematik.ti.erp.app.navigation.NavigationRouteNames +import de.gematik.ti.erp.app.navigation.NavigationRoutes +import de.gematik.ti.erp.app.navigation.Routes + +object AppSecurityRoutes : NavigationRoutes { + + override fun subGraphName() = "app_security" + + const val IntegrityWarningScreenArgument = "isDeviceRiskAccepted" + + object DeviceCheckLoadingScreen : Routes(NavigationRouteNames.DeviceCheckLoadingScreen.name) + object InsecureDeviceScreen : Routes(NavigationRouteNames.InsecureDeviceScreen.name) + + object IntegrityWarningScreen : Routes( + path = NavigationRouteNames.IntegrityWarningScreen.name, + navArgument(IntegrityWarningScreenArgument) { type = NavType.StringType } + ) { + fun path(appSecurityResult: String) = + path(IntegrityWarningScreenArgument to appSecurityResult) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/AppSecurityController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/AppSecurityController.kt new file mode 100644 index 00000000..deef855e --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/AppSecurityController.kt @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.presentation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.appsecurity.usecase.GetDeviceSecurityUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.IntegrityUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.IsIntegrityRiskAcceptedUseCase +import io.github.aakira.napier.Napier +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.first +import org.kodein.di.compose.rememberInstance + +class AppSecurityController( + private val integrityUseCase: IntegrityUseCase, + private val isIntegrityRiskAcceptedUseCase: IsIntegrityRiskAcceptedUseCase, + private val deviceSecurityUseCase: GetDeviceSecurityUseCase +) { + @Requirement( + "O.Arch_6#2", + "O.Resi_2#2", + "O.Resi_3#2", + "O.Resi_4#2", + "O.Resi_5#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check device integrity." + ) + suspend fun checkIntegrityRisk() = + combine( + integrityUseCase.runIntegrityAttestation(), + isIntegrityRiskAcceptedUseCase.invoke() + ) { isAttested, isRiskAccepted -> + Napier.d( + tag = "AppSecurity check", + message = "integrity check: isAttested $isAttested" + ) + Napier.d( + tag = "AppSecurity check", + message = "integrity check: isRiskAccepted $isRiskAccepted" + ) + return@combine when { + !isAttested && !isRiskAccepted -> false + else -> true + } + }.first() + + @Requirement( + "O.Plat_1#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for insecure Devices on first screen when the app is started." + ) + suspend fun checkDeviceSecurityRisk(): Boolean = deviceSecurityUseCase.invoke().first() +} + +@Composable +fun rememberAppSecurityController(): AppSecurityController { + val integrityUseCase: IntegrityUseCase by rememberInstance() + val isIntegrityRiskAcceptedUseCase: IsIntegrityRiskAcceptedUseCase by rememberInstance() + val deviceSecurityUseCase: GetDeviceSecurityUseCase by rememberInstance() + + return remember { + AppSecurityController( + integrityUseCase = integrityUseCase, + isIntegrityRiskAcceptedUseCase = isIntegrityRiskAcceptedUseCase, + deviceSecurityUseCase = deviceSecurityUseCase + ) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/InsecureDeviceController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/InsecureDeviceController.kt new file mode 100644 index 00000000..c5bffe24 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/InsecureDeviceController.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.presentation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptDeviceSecurityRiskUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptRiskEnum.AcceptForSession +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptRiskEnum.AcceptPermanent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.kodein.di.compose.rememberInstance + +class InsecureDeviceController( + private val acceptDeviceSecurityRiskUseCase: AcceptDeviceSecurityRiskUseCase, + private val scope: CoroutineScope +) { + fun acceptRiskForSession() { + scope.launch { + acceptDeviceSecurityRiskUseCase.invoke(acceptRiskEnum = AcceptForSession) + } + } + + fun acceptRiskPermanent() { + scope.launch { + acceptDeviceSecurityRiskUseCase.invoke(acceptRiskEnum = AcceptPermanent) + } + } +} + +@Composable +fun rememberInsecureDeviceController(): InsecureDeviceController { + val acceptDeviceSecurityRiskUseCase: AcceptDeviceSecurityRiskUseCase by rememberInstance() + val scope = rememberCoroutineScope() + + return remember { + InsecureDeviceController( + acceptDeviceSecurityRiskUseCase = acceptDeviceSecurityRiskUseCase, + scope = scope + ) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/IntegrityWarningController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/IntegrityWarningController.kt new file mode 100644 index 00000000..507b0d12 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/presentation/IntegrityWarningController.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.presentation + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptIntegrityRiskUseCase +import de.gematik.ti.erp.app.appsecurity.usecase.AcceptRiskEnum +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.kodein.di.compose.rememberInstance + +class IntegrityWarningController( + private val acceptIntegrityRiskUseCase: AcceptIntegrityRiskUseCase, + private val scope: CoroutineScope +) { + fun acceptRiskForSession() { + scope.launch { + acceptIntegrityRiskUseCase.invoke(acceptRiskEnum = AcceptRiskEnum.AcceptForSession) + } + } + + fun acceptRiskPermanent() { + scope.launch { + acceptIntegrityRiskUseCase.invoke(acceptRiskEnum = AcceptRiskEnum.AcceptPermanent) + } + } +} + +@Composable +fun rememberIntegrityWarningController(): IntegrityWarningController { + val acceptIntegrityRiskUseCase: AcceptIntegrityRiskUseCase by rememberInstance() + val scope = rememberCoroutineScope() + + return remember { + IntegrityWarningController( + acceptIntegrityRiskUseCase = acceptIntegrityRiskUseCase, + scope = scope + ) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/DeviceCheckLoadingStartScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/DeviceCheckLoadingStartScreen.kt new file mode 100644 index 00000000..670996a9 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/DeviceCheckLoadingStartScreen.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.ui + +import androidx.compose.animation.core.LinearEasing +import androidx.compose.animation.core.animateFloat +import androidx.compose.animation.core.infiniteRepeatable +import androidx.compose.animation.core.rememberInfiniteTransition +import androidx.compose.animation.core.tween +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.res.painterResource +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController +import de.gematik.ti.erp.app.appsecurity.presentation.rememberAppSecurityController +import de.gematik.ti.erp.app.appsecurity.ui.model.AppSecurityResult +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.navigation.Screen + +private const val ANIMATION_TIME = 1000 + +class DeviceCheckLoadingStartScreen( + override val navController: NavController, + override val navBackStackEntry: NavBackStackEntry, + val onSecurityCheckResult: (AppSecurityResult) -> Unit +) : Screen() { + + @Composable + override fun Content() { + val appSecurityController = rememberAppSecurityController() + + val infiniteTransition = rememberInfiniteTransition(label = "InfiniteTransition") + val angle by infiniteTransition.animateFloat( + initialValue = 0F, + targetValue = 360F, + animationSpec = infiniteRepeatable( + animation = tween(ANIMATION_TIME, easing = LinearEasing) + ), + label = "FloatAnimation" + ) + + LaunchedEffect(Unit) { + val isIntegritySecure = appSecurityController.checkIntegrityRisk() + val isDeviceSecure = appSecurityController.checkDeviceSecurityRisk() + // on obtaining results make a callback to use the results + onSecurityCheckResult( + AppSecurityResult( + isIntegritySecure = isIntegritySecure, + isDeviceSecure = isDeviceSecure + ) + ) + } + + Box(modifier = Modifier.fillMaxSize()) { + Image( + modifier = Modifier + .align(Alignment.Center) + .graphicsLayer { rotationZ = angle }, + painter = painterResource(R.drawable.erp_logo), + contentDescription = "integrity-check-loading" + ) + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/InsecureDeviceScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/InsecureDeviceScreen.kt new file mode 100644 index 00000000..5d6f35dd --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/InsecureDeviceScreen.kt @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController +import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.appsecurity.presentation.rememberInsecureDeviceController +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.navigation.Screen +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.BottomAppBar +import de.gematik.ti.erp.app.utils.compose.NavigationBarMode +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.Toggle +import java.util.Locale + +@Requirement( + "O.Plat_1#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "insecure Devices warning." +) +class InsecureDeviceScreen( + override val navController: NavController, + override val navBackStackEntry: NavBackStackEntry, + val onBack: () -> Unit +) : Screen() { + + @Composable + override fun Content() { + var checked by rememberSaveable { mutableStateOf(false) } + val scrollState = rememberScrollState() + + val insecureDeviceController = rememberInsecureDeviceController() + + AnimatedElevationScaffold( + elevated = scrollState.value > 0, + navigationMode = NavigationBarMode.Close, + bottomBar = { + BottomAppBar(backgroundColor = MaterialTheme.colors.surface) { + Spacer(modifier = Modifier.weight(1f)) + Button( + onClick = { + if (checked) { + insecureDeviceController.acceptRiskPermanent() + } else { + insecureDeviceController.acceptRiskForSession() + } + onBack() + }, + shape = RoundedCornerShape(PaddingDefaults.Small) + ) { + Text(stringResource(R.string.ok).uppercase(Locale.getDefault())) + } + SpacerMedium() + } + }, + actions = {}, + topBarTitle = stringResource(id = R.string.insecure_device_title), + onBack = onBack + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + .verticalScroll(scrollState) + .padding(PaddingDefaults.Medium) + ) { + Image( + painterResource(id = R.drawable.laptop_woman_yellow), + null, + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxSize() + ) + SpacerSmall() + Text( + stringResource(id = R.string.insecure_device_header), + style = AppTheme.typography.h6 + ) + SpacerSmall() + Text( + stringResource(id = R.string.insecure_device_info), + style = AppTheme.typography.body1 + ) + Spacer(modifier = Modifier.height(PaddingDefaults.XXLarge)) + Toggle( + checked = checked, + onCheckedChange = { checked = it }, + description = stringResource(id = R.string.insecure_device_accept) + ) + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/IntegrityWarningScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/IntegrityWarningScreen.kt new file mode 100644 index 00000000..9c046833 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/IntegrityWarningScreen.kt @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.Button +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController +import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.appsecurity.navigation.AppSecurityRoutes +import de.gematik.ti.erp.app.appsecurity.presentation.rememberIntegrityWarningController +import de.gematik.ti.erp.app.appsecurity.ui.model.AppSecurityResult +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.navigation.Screen +import de.gematik.ti.erp.app.navigation.fromNavigationString +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.BottomAppBar +import de.gematik.ti.erp.app.utils.compose.NavigationBarMode +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.Toggle +import io.github.aakira.napier.Napier +import java.util.Locale + +@Requirement( + "O.Arch_6#3", + "O.Resi_2#3", + "O.Resi_3#3", + "O.Resi_4#3", + "O.Resi_5#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Show integrity warning." +) +@Requirement( + "A_21574", + sourceSpecification = "gemSpec_IDP_Frontend", + rationale = "Show integrity warning." +) +class IntegrityWarningScreen( + override val navController: NavController, + override val navBackStackEntry: NavBackStackEntry, + val onBack: (Boolean) -> Unit +) : Screen() { + @Composable + override fun Content() { + val result = + remember { + navBackStackEntry.arguments?.getString(AppSecurityRoutes.IntegrityWarningScreenArgument) ?: "" + } + + val appSecurityResult = fromNavigationString(result) + + Napier.d { "app security result $appSecurityResult" } + var checked by rememberSaveable { mutableStateOf(false) } + val scrollState = rememberScrollState() + val integrityWarningController = rememberIntegrityWarningController() + + AnimatedElevationScaffold( + elevated = scrollState.value > 0, + navigationMode = NavigationBarMode.Close, + bottomBar = { + BottomAppBar(backgroundColor = MaterialTheme.colors.surface) { + Spacer(modifier = Modifier.weight(1f)) + Button( + onClick = { + if (checked) { + integrityWarningController.acceptRiskPermanent() + } else { + integrityWarningController.acceptRiskForSession() + } + onBack(appSecurityResult.isDeviceSecure) + }, + shape = RoundedCornerShape(PaddingDefaults.Small) + ) { + Text(stringResource(R.string.ok).uppercase(Locale.getDefault())) + } + SpacerMedium() + } + }, + actions = {}, + topBarTitle = stringResource(id = R.string.insecure_device_title_safetynet), + onBack = { + onBack(appSecurityResult.isDeviceSecure) + } + ) { innerPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .padding(innerPadding) + .verticalScroll(scrollState) + .padding(PaddingDefaults.Medium) + ) { + Image( + painterResource(id = R.drawable.laptop_woman_pink), + null, + contentScale = ContentScale.FillWidth, + modifier = Modifier.fillMaxSize() + ) + SpacerSmall() + Text( + stringResource(id = R.string.insecure_device_header_safetynet), + style = AppTheme.typography.h6 + ) + SpacerSmall() + Text( + stringResource(id = R.string.insecure_device_info_safetynet), + style = AppTheme.typography.body1 + ) + // Todo wait for new uri from security staff +// val uriHandler = LocalUriHandler.current +// SpacerMedium() +// Text( +// stringResource(R.string.insecure_device_safetynet_more_info), +// style = AppTheme.typography.body2, +// color = AppTheme.colors.neutral600 +// ) +// SpacerSmall() +// val link = stringResource(R.string.insecure_device_safetynet_link) +// TextButton( +// modifier = Modifier.align(Alignment.End), +// onClick = { uriHandler.openUri(link) } +// ) { +// Text( +// stringResource(id = R.string.insecure_device_safetynet_link_text), +// style = AppTheme.typography.body2, +// color = AppTheme.colors.primary600 +// ) +// } + Spacer(modifier = Modifier.height(PaddingDefaults.XXLarge)) + Toggle( + checked = checked, + onCheckedChange = { checked = it }, + description = stringResource(id = R.string.insecure_device_accept_safetynet) + ) + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/model/AppSecurityResult.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/model/AppSecurityResult.kt new file mode 100644 index 00000000..7f18c645 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/ui/model/AppSecurityResult.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.ui.model + +import kotlinx.serialization.Serializable + +@Serializable +data class AppSecurityResult( + val isIntegritySecure: Boolean, + val isDeviceSecure: Boolean +) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptDeviceSecurityRiskUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptDeviceSecurityRiskUseCase.kt new file mode 100644 index 00000000..f908d7f7 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptDeviceSecurityRiskUseCase.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.usecase + +import de.gematik.ti.erp.app.appsecurity.AppSecuritySession +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class AcceptDeviceSecurityRiskUseCase( + private val repository: SettingsRepository, + private val session: AppSecuritySession, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + suspend operator fun invoke(acceptRiskEnum: AcceptRiskEnum) { + withContext(dispatcher) { + when (acceptRiskEnum) { + AcceptRiskEnum.AcceptForSession -> session.acceptDeviceSecurityForSession() + AcceptRiskEnum.AcceptPermanent -> repository.acceptInsecureDevice() + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptIntegrityRiskUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptIntegrityRiskUseCase.kt new file mode 100644 index 00000000..7746ee56 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptIntegrityRiskUseCase.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.usecase + +import de.gematik.ti.erp.app.appsecurity.AppSecuritySession +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +class AcceptIntegrityRiskUseCase( + private val repository: SettingsRepository, + private val session: AppSecuritySession, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + suspend operator fun invoke(acceptRiskEnum: AcceptRiskEnum) { + withContext(dispatcher) { + when (acceptRiskEnum) { + AcceptRiskEnum.AcceptForSession -> session.acceptIntegrityForSession() + AcceptRiskEnum.AcceptPermanent -> repository.acceptIntegrityNotOk() + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptRiskEnum.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptRiskEnum.kt new file mode 100644 index 00000000..ac9af4bf --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/AcceptRiskEnum.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.usecase + +enum class AcceptRiskEnum { + AcceptForSession, AcceptPermanent +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/GetDeviceSecurityUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/GetDeviceSecurityUseCase.kt new file mode 100644 index 00000000..1bcbde95 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/GetDeviceSecurityUseCase.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.usecase + +import android.app.KeyguardManager +import android.content.Context +import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.appsecurity.AppSecuritySession +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import io.github.aakira.napier.Napier +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +class GetDeviceSecurityUseCase( + private val context: Context, + private val settingsRepository: SettingsRepository, + private val appSecuritySession: AppSecuritySession, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + @Requirement( + "O.Plat_1#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for insecure Devices." + ) + operator fun invoke(): Flow = + settingsRepository.general + .map { + val isDeviceSecure = (context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager) + .isDeviceSecure + + Napier.d( + tag = "AppSecurity check", + message = "Device security check: isDeviceSecure $isDeviceSecure" + ) + + val riskAccepted = + it.userHasAcceptedInsecureDevice || appSecuritySession.isDeviceSecurityAcceptedForSession() + + Napier.d( + tag = "AppSecurity check", + message = "Device security check: riskAccepted $riskAccepted" + ) + + val result = when { + !isDeviceSecure && !riskAccepted -> false + else -> true + } + Napier.d( + tag = "AppSecurity check", + message = "Device security check: result $result" + ) + result + }.flowOn(dispatcher) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IntegrityUseCase.kt similarity index 70% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IntegrityUseCase.kt index c09aaec9..2fc86395 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IntegrityUseCase.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.attestation.usecase +package de.gematik.ti.erp.app.appsecurity.usecase import android.content.Context import android.util.Base64 @@ -24,9 +24,9 @@ import com.google.android.play.core.integrity.IntegrityManagerFactory import com.google.android.play.core.integrity.IntegrityTokenRequest import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.Requirement - import de.gematik.ti.erp.app.secureRandomInstance import de.gematik.ti.erp.app.vau.toLowerCaseHex +import io.github.aakira.napier.Napier import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.flow @@ -41,7 +41,12 @@ import java.security.spec.X509EncodedKeySpec import javax.crypto.SecretKey import javax.crypto.spec.SecretKeySpec -private const val RequiredSaltLength = 32 +private const val REQUIRED_SALT_LENGTH = 32 +private const val DEVICE_INTEGRITY = "deviceIntegrity" +private const val MEETS_DEVICE_INTEGRITY = "MEETS_DEVICE_INTEGRITY" +private const val SHA_256 = "SHA-256" +private const val AES = "AES" +private const val EC = "EC" class IntegrityUseCase( private val context: Context @@ -54,8 +59,8 @@ class IntegrityUseCase( "O.Resi_5#1", sourceSpecification = "BSI-eRp-ePA", rationale = "In the release process, the app is signed and the signed app bundle is uploaded to the store. " + - "An altered application can only run on a jailbroken device. We are using Googles Integrity API " + - "to detect jailbreaked devices. If a user is using a jailbroken device, may it be known or unknown, " + + "An altered application can only run on a jail-broken device. We are using Googles Integrity API " + + "to detect jail-broken devices. If a user is using a jail-broken device, may it be known or unknown, " + "we display a security alert so a user can make an informed decision to use or " + "not use the application.." ) @@ -63,8 +68,7 @@ class IntegrityUseCase( val salt = provideSalt() val ourNonce = generateNonce(salt, nonceData()) - val integrityManager = - IntegrityManagerFactory.create(context) + val integrityManager = IntegrityManagerFactory.create(context) val tokenResponse = integrityManager.requestIntegrityToken( IntegrityTokenRequest.builder() @@ -81,45 +85,39 @@ class IntegrityUseCase( sourceSpecification = "BSI-eRp-ePA", rationale = "Signature via ecdh ephemeral-static (one time usage)" ) - val decryptionKeyBytes: ByteArray = - Base64.decode(BuildKonfig.INTEGRITY_API_KEY, Base64.DEFAULT) + val decryptionKeyBytes: ByteArray = Base64.decode(BuildKonfig.INTEGRITY_API_KEY, Base64.DEFAULT) - val decryptionKey: SecretKey = SecretKeySpec( - decryptionKeyBytes, - "AES" - ) + val decryptionKey: SecretKey = SecretKeySpec(decryptionKeyBytes, AES) - val encodedVerificationKey: ByteArray = - Base64.decode(BuildKonfig.INTEGRITY_VERIFICATION_KEY, Base64.DEFAULT) + val encodedVerificationKey: ByteArray = Base64.decode(BuildKonfig.INTEGRITY_VERIFICATION_KEY, Base64.DEFAULT) - val verificationKey: PublicKey = KeyFactory.getInstance("EC") + val verificationKey: PublicKey = KeyFactory.getInstance(EC) .generatePublic(X509EncodedKeySpec(encodedVerificationKey)) - val jwe: JsonWebEncryption = - JsonWebStructure.fromCompactSerialization(token) as JsonWebEncryption + val jwe: JsonWebEncryption = JsonWebStructure.fromCompactSerialization(token) as JsonWebEncryption jwe.key = decryptionKey val compactJws = jwe.payload val jws = JsonWebStructure.fromCompactSerialization(compactJws) + jws.key = verificationKey - val requestDetails = JSONObject(jws.payload).getJSONObject("deviceIntegrity") + val requestDetails = JSONObject(jws.payload).getJSONObject(DEVICE_INTEGRITY) - emit(requestDetails.toString().contains("MEETS_DEVICE_INTEGRITY")) + emit(requestDetails.toString().contains(MEETS_DEVICE_INTEGRITY)) }.catch { + Napier.e { "integrity check not done" } emit(true) } private fun nonceData() = ("GmtkEPrescriptionApp: " + System.currentTimeMillis()).toByteArray() - private fun provideSalt() = ByteArray(RequiredSaltLength).apply { + private fun provideSalt() = ByteArray(REQUIRED_SALT_LENGTH).apply { secureRandomInstance().nextBytes(this) } - private fun generateNonce(salt: ByteArray, word: ByteArray): String { - val combined = word + salt - return MessageDigest.getInstance("SHA-256").digest(combined).toLowerCaseHex().decodeToString() - } + private fun generateNonce(salt: ByteArray, word: ByteArray): String = + MessageDigest.getInstance(SHA_256).digest((word + salt)).toLowerCaseHex().decodeToString() } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IsIntegrityRiskAcceptedUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IsIntegrityRiskAcceptedUseCase.kt new file mode 100644 index 00000000..3c217393 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/appsecurity/usecase/IsIntegrityRiskAcceptedUseCase.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.appsecurity.usecase + +import de.gematik.ti.erp.app.appsecurity.AppSecuritySession +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map + +class IsIntegrityRiskAcceptedUseCase( + private val repository: SettingsRepository, + private val session: AppSecuritySession, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + operator fun invoke(): Flow = + repository.general.map { + it.userHasAcceptedIntegrityNotOk || session.isIntegrityAcceptedForSession() + }.flowOn(dispatcher) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/base/BaseActivity.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/base/BaseActivity.kt new file mode 100644 index 00000000..1433f219 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/base/BaseActivity.kt @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +@file:Suppress("LongMethod", "MagicNumber") + +package de.gematik.ti.erp.app.base + +import android.app.Activity +import android.app.Dialog +import android.content.Intent +import android.nfc.NfcAdapter +import android.nfc.Tag +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.view.Gravity +import android.widget.FrameLayout +import androidx.activity.setViewTreeOnBackPressedDispatcherOwner +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.view.ContextThemeWrapper +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.ComposeView +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.view.setMargins +import androidx.core.view.updateLayoutParams +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.setViewTreeLifecycleOwner +import androidx.lifecycle.setViewTreeViewModelStoreOwner +import androidx.savedstate.setViewTreeSavedStateRegistryOwner +import com.google.android.material.snackbar.Snackbar +import com.google.android.play.core.appupdate.AppUpdateManagerFactory +import com.google.android.play.core.appupdate.AppUpdateOptions +import com.google.android.play.core.install.model.AppUpdateType +import com.google.android.play.core.install.model.UpdateAvailability +import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.NfcNotEnabledException +import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.analytics.Analytics +import de.gematik.ti.erp.app.apicheck.usecase.CheckVersionUseCase +import de.gematik.ti.erp.app.cardwall.ui.ExternalAuthenticatorListViewModel +import de.gematik.ti.erp.app.core.IntentHandler +import de.gematik.ti.erp.app.debugOverrides +import de.gematik.ti.erp.app.demomode.DefaultDemoModeObserver +import de.gematik.ti.erp.app.demomode.DemoModeObserver +import de.gematik.ti.erp.app.demomode.di.demoModeModule +import de.gematik.ti.erp.app.demomode.di.demoModeOverrides +import de.gematik.ti.erp.app.features.BuildConfig +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.timeouts.usecase.GetPauseMetricUseCase +import de.gematik.ti.erp.app.userauthentication.observer.AuthenticationModeAndMethod +import de.gematik.ti.erp.app.userauthentication.observer.InactivityTimeoutObserver +import de.gematik.ti.erp.app.utils.extensions.DialogScaffold +import de.gematik.ti.erp.app.utils.extensions.SnackbarScaffold +import io.github.aakira.napier.Napier +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.onStart +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import org.kodein.di.Copy +import org.kodein.di.DIAware +import org.kodein.di.android.closestDI +import org.kodein.di.android.retainedSubDI +import org.kodein.di.bindProvider +import org.kodein.di.instance + +open class BaseActivity : + SnackbarScaffold, + DialogScaffold, + DIAware, + AppCompatActivity(), + DemoModeObserver by DefaultDemoModeObserver() { + + override val di by retainedSubDI(closestDI(), copy = Copy.All) { + // should be only done from feature module + import(demoModeModule) + if (isDemoMode()) demoModeOverrides() + when { + BuildConfig.DEBUG && BuildKonfig.INTERNAL -> { + debugOverrides() + fullContainerTreeOnError = true + } + } + bindProvider { ExternalAuthenticatorListViewModel(instance(), instance()) } + bindProvider { CheckVersionUseCase(instance(), instance()) } + } + + private val checkVersionUseCase: CheckVersionUseCase by instance() + + private val pauseTimeoutUseCase: GetPauseMetricUseCase by instance() + + private val inactivityTimeoutObserver: InactivityTimeoutObserver by instance() + + val analytics: Analytics by instance() + + val intentHandler = IntentHandler(this@BaseActivity) + + // This is needed to be declared here so that the dialog can be cancelled on-pause + private var dialog: Dialog? = null + + private val _nfcTag = MutableSharedFlow() + + private var pauseTimerHandler: Handler = Handler(Looper.getMainLooper()) + + /** + * A [Runnable] that makes the app require an authentication + */ + @Requirement( + "O.Auth_7", + "O.Plat_12", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The LifeCycleState of the app is monitored. If the app stopped, the authentication " + + "process starts after a delay of 30 seconds. We opted for this delay for usability reasons, " + + "as selecting the profile picture and external authentication requires pausing the app." + ) + private val pauseTimerRunnable = Runnable { + inactivityTimeoutObserver.forceRequireAuthentication() + } + + override fun onPause() { + super.onPause() + // cancel the dialog when pausing since it might show up security concerns + dialog?.cancel() + + // this sets the app to require authentication after the pause-timeout + val pauseTimeout = pauseTimeoutUseCase.invoke() + Napier.i { "Started pause timer for ${pauseTimeout.inWholeMilliseconds}" } + pauseTimerHandler.postDelayed(pauseTimerRunnable, pauseTimeout.inWholeMilliseconds) + + NfcAdapter.getDefaultAdapter(applicationContext)?.disableReaderMode(this) + } + + override fun onUserInteraction() { + super.onUserInteraction() + inactivityTimeoutObserver.resetInactivityTimer() + } + + override fun onNewIntent(intent: Intent?) { + super.onNewIntent(intent) + lifecycleScope.launch { + intent?.let { + intentHandler.propagateIntent(it) + } + } + } + + override fun onResume() { + super.onResume() + Napier.i { "Stopped pause timer" } + pauseTimerHandler.removeCallbacks(pauseTimerRunnable) + + NfcAdapter.getDefaultAdapter(applicationContext)?.let { + if (it.isEnabled) { + it.enableReaderMode( + this, + ::onTagDiscovered, + NfcAdapter.FLAG_READER_NFC_A + or NfcAdapter.FLAG_READER_NFC_B + or NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK, + Bundle() + ) + } + } + } + + override fun show(content: @Composable (Dialog) -> Unit) { + dialog = Dialog(this, R.style.ThemeOverlay_MaterialAlertDialog_Rounded) + dialog?.window?.decorView?.let { + it.setViewTreeLifecycleOwner(this) + it.setViewTreeSavedStateRegistryOwner(this) + it.setViewTreeOnBackPressedDispatcherOwner(this) + it.setViewTreeViewModelStoreOwner(this) + } + val composableView = ComposeView(this) + composableView.let { + it.setViewTreeViewModelStoreOwner(this) + it.setViewTreeLifecycleOwner(this) + it.setViewTreeSavedStateRegistryOwner(this) + it.setViewTreeOnBackPressedDispatcherOwner(this) + dialog?.let { dialogNotNull -> + it.setContent { + AppTheme { + content(dialogNotNull) + } + } + } + } + dialog?.setContentView(composableView) + dialog?.setCancelable(true) + dialog?.show() + } + + override fun show(text: String, icon: Int, backgroundTint: Int) { + val snackbar = Snackbar.make(findViewById(android.R.id.content), text, Snackbar.LENGTH_SHORT) + val theme = ContextThemeWrapper( + applicationContext, + R.style.ThemeOverlay_MaterialAlertDialog_Rounded + ).theme + snackbar.setBackgroundTint(resources.getColor(backgroundTint, theme)) + snackbar.view.updateLayoutParams { + width = CoordinatorLayout.LayoutParams.MATCH_PARENT + height = CoordinatorLayout.LayoutParams.WRAP_CONTENT + gravity = Gravity.BOTTOM + setMargins(24) + } + snackbar.show() + } + + private fun onTagDiscovered(tag: Tag) { + lifecycleScope.launch { + _nfcTag.emit(tag) + } + } + + val authenticationModeAndMethod: StateFlow + get() = inactivityTimeoutObserver.authenticationModeAndMethod + .stateIn(lifecycleScope, SharingStarted.Eagerly, AuthenticationModeAndMethod.None) + + @Requirement( + "O.Arch_10#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "If an update is required, the user is prompted to update via Google´s InAppUpdate function" + ) + suspend fun checkAppUpdate() { + if (checkVersionUseCase.isUpdateRequired()) { + val appUpdateManager = AppUpdateManagerFactory.create(this) + val appUpdateInfoTask = appUpdateManager.appUpdateInfo + + appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> + if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) { + val task = appUpdateManager.startUpdateFlow( + appUpdateInfo, + this, + AppUpdateOptions.defaultOptions(AppUpdateType.IMMEDIATE) + ) + + task.addOnCompleteListener { + if (task.isSuccessful && task.result != Activity.RESULT_OK) { + finish() + } + } + } + } + } + } + + val nfcTagFlow: Flow + get() = _nfcTag.onStart { + if (!NfcAdapter.getDefaultAdapter(this@BaseActivity).isEnabled) { + throw NfcNotEnabledException() + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt index 3487406d..ee60af26 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt @@ -18,14 +18,14 @@ package de.gematik.ti.erp.app.cardunlock.model -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes object UnlockEgkNavigation { - object Intro : Route("healthCardPassword_introduction") - object CardAccessNumber : Route("healthCardPassword_can") - object PersonalUnblockingKey : Route("healthCardPassword_puk") - object OldSecret : Route("healthCardPassword_oldPin") - object NewSecret : Route("healthCardPassword_pin") - object UnlockEgk : Route("healthCardPassword_readCard") - object TroubleShooting : Route("troubleShooting") + object Intro : Routes("healthCardPassword_introduction") + object CardAccessNumber : Routes("healthCardPassword_can") + object PersonalUnblockingKey : Routes("healthCardPassword_puk") + object OldSecret : Routes("healthCardPassword_oldPin") + object NewSecret : Routes("healthCardPassword_pin") + object UnlockEgk : Routes("healthCardPassword_readCard") + object TroubleShooting : Routes("troubleShooting") } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt index b6421f0a..b37fac11 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt @@ -45,7 +45,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.card.model.command.UnlockMethod import de.gematik.ti.erp.app.cardunlock.model.UnlockEgkNavigation import de.gematik.ti.erp.app.cardwall.ui.CardAccessNumber @@ -97,7 +97,7 @@ fun UnlockEgKScreen( val unlockNavController = rememberNavController() var previousNavEntry by remember { mutableStateOf("healthCardPassword_introduction") } - trackNavigationChanges(unlockNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(unlockNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) var cardAccessNumber by rememberSaveable { mutableStateOf("") } var personalUnblockingKey by rememberSaveable { mutableStateOf("") } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt index e300652f..17d05ee2 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt @@ -80,7 +80,7 @@ import androidx.navigation.navOptions import de.gematik.ti.erp.app.MainActivity import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.card.model.command.UnlockMethod import de.gematik.ti.erp.app.cardunlock.ui.UnlockEgKScreen import de.gematik.ti.erp.app.cardwall.domain.biometric.deviceStrongBiometricStatus @@ -159,7 +159,7 @@ fun CardWallScreen( } var previousNavEntry by remember { mutableStateOf("cardwall_introduction") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) var cardAccessNumber by rememberSaveable { mutableStateOf("") } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/CardWallNavigation.kt similarity index 54% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/CardWallNavigation.kt index 055a765a..b85f5823 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/cardwall/ui/model/CardWallNavigation.kt @@ -18,17 +18,17 @@ package de.gematik.ti.erp.app.cardwall.ui.model -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes object CardWallNavigation { - object Troubleshooting : Route("troubleShooting") - object ExternalAuthenticator : Route("cardWall_extAuth") - object Intro : Route("cardWall_introduction") - object CardAccessNumber : Route("cardWall_CAN") - object PersonalIdentificationNumber : Route("cardWall_PIN") - object AuthenticationSelection : Route("cardWall_saveLogin") - object AlternativeOption : Route("cardWall_saveLoginSecurityInfo") - object Authentication : Route("cardWall_readCard") - object OrderHealthCard : Route("contactInsuranceCompany") - object UnlockEgk : Route("healthCardPassword_introduction") + object Troubleshooting : Routes("troubleShooting") + object ExternalAuthenticator : Routes("cardWall_extAuth") + object Intro : Routes("cardWall_introduction") + object CardAccessNumber : Routes("cardWall_CAN") + object PersonalIdentificationNumber : Routes("cardWall_PIN") + object AuthenticationSelection : Routes("cardWall_saveLogin") + object AlternativeOption : Routes("cardWall_saveLoginSecurityInfo") + object Authentication : Routes("cardWall_readCard") + object OrderHealthCard : Routes("contactInsuranceCompany") + object UnlockEgk : Routes("healthCardPassword_introduction") } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/core/AppContent.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/core/AppContent.kt index 1f665687..bd6599b1 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/core/AppContent.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/core/AppContent.kt @@ -63,7 +63,6 @@ import de.gematik.ti.erp.app.demomode.startAppWithNormalMode import de.gematik.ti.erp.app.demomode.ui.DemoModeStatusBar import de.gematik.ti.erp.app.demomode.ui.checkForDemoMode import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.settings.ui.rememberSettingsController import de.gematik.ti.erp.app.theme.AppTheme import kotlinx.coroutines.Job @@ -85,7 +84,7 @@ val LocalAnalytics = @Composable fun AppContent( - content: @Composable (settingsController: SettingsController) -> Unit + content: @Composable () -> Unit ) { val settingsController = rememberSettingsController() val zoomState by settingsController.zoomState @@ -111,7 +110,7 @@ fun AppContent( }, appContent = { Box(modifier = Modifier.zoomable(enabled = zoomState.zoomEnabled)) { - content(settingsController) + content() } } ) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/DebugTimeoutScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/DebugTimeoutScreen.kt new file mode 100644 index 00000000..23c60611 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/DebugTimeoutScreen.kt @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +@file:Suppress("MagicNumber", "LongMethod") + +package de.gematik.ti.erp.app.debugsettings.timeout + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.material.Card +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import de.gematik.ti.erp.app.MainActivity +import de.gematik.ti.erp.app.core.LocalActivity +import de.gematik.ti.erp.app.debugsettings.timeout.intent.restartApp +import de.gematik.ti.erp.app.debugsettings.timeout.ui.MetricChangeDialog +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError.NoError +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsScreenViewModel +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.PrimaryButton +import de.gematik.ti.erp.app.utils.compose.SpacerLarge +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerXXLarge +import de.gematik.ti.erp.app.utils.compose.SpacerXXLargeMedium +import de.gematik.ti.erp.app.utils.extensions.LocalDialog +import de.gematik.ti.erp.app.utils.extensions.LocalSnackbar +import org.kodein.di.compose.rememberInstance + +object DebugTimeoutScreen { + @Composable + fun Content( + onBack: () -> Unit + ) { + val viewmodel by rememberInstance() + val dialog = LocalDialog.current + val snackbar = LocalSnackbar.current + val activity = LocalActivity.current + + val scrollState = rememberScrollState() + val elevated by remember { derivedStateOf { scrollState.value > 0 } } + + val inactivityMetric by viewmodel.inactivityMetricDuration.collectAsStateWithLifecycle() + val pauseMetric by viewmodel.pauseMetricDuration.collectAsStateWithLifecycle() + val error by viewmodel.error.collectAsStateWithLifecycle(NoError) + + AnimatedElevationScaffold( + topBarTitle = "Biometric settings", + actions = {}, + elevated = elevated, + onBack = onBack + ) { paddingValues -> + Column( + modifier = Modifier + .fillMaxWidth() + .padding(paddingValues) + .padding(horizontal = PaddingDefaults.Medium) + ) { + SpacerMedium() + Row( + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + Text( + modifier = Modifier.weight(0.4f), + text = "Inactivity timer:", + style = MaterialTheme.typography.body1 + ) + Card( + modifier = Modifier.weight(0.6f), + border = BorderStroke(0.5.dp, AppTheme.colors.primary600) + ) { + TextButton( + onClick = { + dialog.show { dialog -> + MetricChangeDialog( + label = "Inactivity Timer", + currentValue = inactivityMetric, + onDismissRequest = { + dialog.dismiss() + }, + onValueChanged = { value, duration -> + viewmodel.setInactivityMetric(value, duration) + dialog.dismiss() + snackbar.show("Inactivity timer reset. Restart required") + } + ) + } + } + ) { + Text( + "$inactivityMetric", + style = MaterialTheme.typography.body1 + ) + } + } + } + SpacerMedium() + Text( + text = "The inactivity timer is called when the app is running but nothing is clicked", + style = MaterialTheme.typography.subtitle2 + ) + SpacerLarge() + Row( + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth() + ) { + Text( + modifier = Modifier.weight(0.4f), + text = "Pause Timer:", + style = MaterialTheme.typography.body1 + ) + Card( + modifier = Modifier.weight(0.6f), + border = BorderStroke(0.5.dp, AppTheme.colors.primary600) + ) { + TextButton( + onClick = { + dialog.show { dialog -> + MetricChangeDialog( + label = "Pause Timer", + currentValue = pauseMetric, + onDismissRequest = { + dialog.dismiss() + }, + onValueChanged = { value, duration -> + viewmodel.setPauseMetric(value, duration) + dialog.dismiss() + snackbar.show("Pause timer reset. Restart required") + } + ) + } + } + ) { + Text( + "$pauseMetric", + style = MaterialTheme.typography.body1 + ) + } + } + } + SpacerMedium() + Text( + text = "The pause timer is called when the app is minimized", + style = MaterialTheme.typography.subtitle2 + ) + SpacerXXLargeMedium() + TextButton( + modifier = Modifier.padding(horizontal = PaddingDefaults.XXLargeMedium), + border = BorderStroke(1.dp, AppTheme.colors.neutral300), + onClick = { + viewmodel.resetToDefaultMetrics() + snackbar.show("All timers reset. Restart required") + } + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + Image( + painter = painterResource(R.drawable.ic_reset), + contentDescription = null + ) + Text( + text = "Reset to Default", + style = MaterialTheme.typography.h6 + ) + } + } + SpacerXXLarge() + PrimaryButton( + modifier = Modifier + .padding(horizontal = PaddingDefaults.XXLargeMedium) + .fillMaxWidth(), + content = { + Text( + modifier = Modifier, + text = "Restart App", + style = MaterialTheme.typography.h6 + ) + }, + onClick = { + restartApp(activity) + } + ) + } + } + + // show errors for timeout + when (error) { + TimeoutsError.InactivityError -> snackbar.show( + text = "Error setting inactivity timer", + backgroundTint = R.color.red_500 + ) + + TimeoutsError.PauseError -> snackbar.show( + text = "Error setting pause timer", + backgroundTint = R.color.red_500 + ) + + TimeoutsError.Error -> snackbar.show( + text = "Error setting inactivity and pause timers", + backgroundTint = R.color.red_500 + + ) + + NoError -> { + // show nothing + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/intent/AppRestartIntent.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/intent/AppRestartIntent.kt new file mode 100644 index 00000000..a09ea33d --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/intent/AppRestartIntent.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.debugsettings.timeout.intent + +import android.content.Intent +import androidx.activity.ComponentActivity + +inline fun restartApp(activity: ComponentActivity) { + activity.finish() + activity.startActivity( + Intent(activity, T::class.java).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + } + ) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/ui/MetricChangeDialog.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/ui/MetricChangeDialog.kt new file mode 100644 index 00000000..3d0bcc00 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/debugsettings/timeout/ui/MetricChangeDialog.kt @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +@file:Suppress("MagicNumber") + +package de.gematik.ti.erp.app.debugsettings.timeout.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material.Divider +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TextFieldValue +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum.HOURS +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum.MINUTES +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum.SECONDS +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import kotlinx.coroutines.android.awaitFrame +import kotlin.time.Duration + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun MetricChangeDialog( + label: String, + currentValue: Duration, + onDismissRequest: () -> Unit, + onValueChanged: (String, DurationEnum) -> Unit +) { + val focusRequester = remember { FocusRequester() } + val keyboard = LocalSoftwareKeyboardController.current + + val (value, duration) = "$currentValue".extractTimeValues() + var textFieldValue by remember { mutableStateOf(TextFieldValue(value)) } + var expanded by remember { mutableStateOf(false) } + var selectedDurationEnum by remember { mutableStateOf(DurationEnum.valueOf(duration.name)) } + val items = listOf(SECONDS, MINUTES, HOURS) + + LaunchedEffect(focusRequester) { + focusRequester.requestFocus() + awaitFrame() + keyboard?.show() + } + + Surface { + Column( + modifier = Modifier + .padding(horizontal = PaddingDefaults.Medium) + .padding(vertical = PaddingDefaults.Large) + ) { + Row( + horizontalArrangement = Arrangement.Start, + verticalAlignment = Alignment.CenterVertically + ) { + OutlinedTextField( + modifier = Modifier.weight(0.4f) + .focusRequester(focusRequester), + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done, + keyboardType = KeyboardType.Number + ), + keyboardActions = KeyboardActions( + onDone = { + onValueChanged(textFieldValue.text, selectedDurationEnum) + } + ), + label = { + Text( + text = label, + style = MaterialTheme.typography.body2 + ) + }, + value = textFieldValue, + onValueChange = { + textFieldValue = it + } + ) + Spacer(modifier = Modifier.weight(0.1f)) + Text( + modifier = Modifier.weight(0.25f), + text = "$selectedDurationEnum", + style = MaterialTheme.typography.body1 + ) + Box( + modifier = Modifier.weight(0.25f) + ) { + IconButton( + onClick = { + expanded = !expanded + } + ) { + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = "$selectedDurationEnum" + ) + } + DropdownMenu( + expanded = expanded, + onDismissRequest = { + expanded = !expanded + } + ) { + items.forEachIndexed { index, durationEnum -> + DropdownMenuItem( + onClick = { + keyboard?.show() + selectedDurationEnum = durationEnum + expanded = false + }, + content = { Text(text = durationEnum.name) } + ) + if (index + 1 < items.size) { + Divider() + } + } + } + } + } + SpacerMedium() + Row { + TextButton( + modifier = Modifier.weight(0.5f), + onClick = onDismissRequest + ) { + Text( + text = "Cancel", + style = MaterialTheme.typography.body1 + ) + } + TextButton( + modifier = Modifier.weight(0.5f), + onClick = { + onValueChanged(textFieldValue.text, selectedDurationEnum) + } + + ) { + Text( + text = "OK", + style = MaterialTheme.typography.body1 + ) + } + } + } + } +} + +private fun String.extractTimeValues(): Pair { + val regex = Regex("(\\d+)([hms])") + val matchResults = regex.findAll(this) + var value = "" + var unit = SECONDS + for (result in matchResults) { + value = result.groupValues[1] // Extract the numeric value + unit = DurationEnum.extractedUnit(result.groupValues[2]) // Extract the unit (h, m, or s) + } + return value to unit +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/di/FeatureModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/di/FeatureModule.kt index 5e5c9140..483d1fed 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/di/FeatureModule.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/di/FeatureModule.kt @@ -18,8 +18,9 @@ package de.gematik.ti.erp.app.di -import de.gematik.ti.erp.app.attestation.usecase.integrityModule +import de.gematik.ti.erp.app.appsecurity.appSecurityModule import de.gematik.ti.erp.app.authentication.di.authenticationModule +import de.gematik.ti.erp.app.timeouts.di.timeoutsSharedPrefsModule import de.gematik.ti.erp.app.cardunlock.cardUnlockModule import de.gematik.ti.erp.app.cardwall.cardWallModule import de.gematik.ti.erp.app.idp.idpModule @@ -43,10 +44,13 @@ import de.gematik.ti.erp.app.settings.settingsModule import de.gematik.ti.erp.app.vau.vauModule import org.kodein.di.DI +/** + * Use this only in the android-app module + */ val featureModule = DI.Module("featureModule", allowSilentOverride = true) { importAll( cardWallModule, - integrityModule, + appSecurityModule, networkModule, realmModule, idpModule, @@ -70,6 +74,7 @@ val featureModule = DI.Module("featureModule", allowSilentOverride = true) { pharmacyRepositoryModule, messageRepositoryModule, taskRepositoryModule, + timeoutsSharedPrefsModule, allowOverride = true ) } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/idp/IdpModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/idp/IdpModule.kt index e8c04bed..2c2e919d 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/idp/IdpModule.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/idp/IdpModule.kt @@ -56,7 +56,7 @@ val idpModule = DI.Module("idpModule") { val idpUseCaseModule = DI.Module("idpUseCaseModule", allowSilentOverride = true) { bindProvider { IdpAlternateAuthenticationUseCase(instance(), instance(), instance()) } - bindProvider { + bindSingleton { DefaultIdpUseCase( repository = instance(), pairingRepository = instance(), diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenContentNavHost.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenContentNavHost.kt index 56431e70..1254215a 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenContentNavHost.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenContentNavHost.kt @@ -32,14 +32,12 @@ import de.gematik.ti.erp.app.orders.ui.OrderScreen import de.gematik.ti.erp.app.prescription.ui.PrescriptionsScreen import de.gematik.ti.erp.app.prescription.ui.rememberPrescriptionsController import de.gematik.ti.erp.app.profiles.presentation.rememberProfilesController -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.settings.ui.SettingsScreen @Composable internal fun MainScreenContentNavHost( modifier: Modifier, mainScreenController: MainScreenController, - settingsController: SettingsController, mainNavController: NavController, bottomNavController: NavHostController, onElevateTopBar: (Boolean) -> Unit, @@ -91,8 +89,7 @@ internal fun MainScreenContentNavHost( MainNavigationScreens.Settings.arguments ) { SettingsScreen( - mainNavController = mainNavController, - settingsController = settingsController + mainNavController = mainNavController ) } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigation.kt index 9cdf8f9a..998db531 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigation.kt @@ -18,15 +18,12 @@ package de.gematik.ti.erp.app.mainscreen.navigation -import android.os.Build -import androidx.annotation.RequiresApi import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue -import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost @@ -34,18 +31,18 @@ import androidx.navigation.compose.composable import androidx.navigation.navOptions import de.gematik.ti.erp.app.LegalNoticeWithScaffold import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.analytics.trackPopUps +import de.gematik.ti.erp.app.appsecurity.navigation.AppSecurityRoutes +import de.gematik.ti.erp.app.appsecurity.navigation.appSecurityGraph import de.gematik.ti.erp.app.card.model.command.UnlockMethod import de.gematik.ti.erp.app.cardunlock.ui.UnlockEgKScreen import de.gematik.ti.erp.app.cardwall.ui.CardWallScreen import de.gematik.ti.erp.app.core.LocalAnalytics -import de.gematik.ti.erp.app.debug.ui.DebugScreenWrapper -import de.gematik.ti.erp.app.features.BuildConfig import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.license.ui.LicenseScreen import de.gematik.ti.erp.app.mainscreen.presentation.MainScreenController -import de.gematik.ti.erp.app.mainscreen.ui.InsecureDeviceScreen +import de.gematik.ti.erp.app.mainscreen.presentation.rememberMainScreenController import de.gematik.ti.erp.app.mainscreen.ui.MainScreenScaffoldContainer import de.gematik.ti.erp.app.onboarding.ui.OnboardingNavigationScreens import de.gematik.ti.erp.app.onboarding.ui.OnboardingScreen @@ -68,16 +65,14 @@ import de.gematik.ti.erp.app.redeem.ui.RedeemNavigation import de.gematik.ti.erp.app.settings.ui.AllowAnalyticsScreen import de.gematik.ti.erp.app.settings.ui.PharmacyLicenseScreen import de.gematik.ti.erp.app.settings.ui.SecureAppWithPassword -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.settings.ui.SettingsScreen -import de.gematik.ti.erp.app.settings.ui.rememberSettingsController +import de.gematik.ti.erp.app.ui.DebugScreenWrapper import de.gematik.ti.erp.app.utils.compose.NavigationAnimation import de.gematik.ti.erp.app.utils.compose.navigationModeState import de.gematik.ti.erp.app.webview.URI_DATA_TERMS import de.gematik.ti.erp.app.webview.URI_TERMS_OF_USE import de.gematik.ti.erp.app.webview.WebViewScreen -@RequiresApi(Build.VERSION_CODES.O) @Requirement( "A_19178", sourceSpecification = "gemSpec_eRp_FdV", @@ -451,30 +446,42 @@ import de.gematik.ti.erp.app.webview.WebViewScreen fun MainScreenNavigation( navController: NavHostController ) { - val settingsController = rememberSettingsController() - val startDestination = checkFirstAppStart(settingsController) - LaunchedEffect(startDestination) { - // `gemSpec_eRp_FdV A_20203` default settings are not allow screenshots - // (on debug builds should be allowed for testing) - if (BuildConfig.DEBUG && startDestination == "onboarding") { - settingsController.onAllowScreenshots() - } - } + /** + * Main screen navigation start check + */ + val mainScreenController = rememberMainScreenController() + + val onboardingSucceeded = mainScreenController.onboardingSucceeded + + val startDestinationScreen = shouldOnboardingBeDone(onboardingSucceeded) + val analytics = LocalAnalytics.current val analyticsState by analytics.screenState + val mlKitAccepted by mainScreenController.mlKitAcceptedState trackPopUps(analytics, analyticsState) var previousNavEntry by remember { mutableStateOf("main") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val navigationMode by navController.navigationModeState(OnboardingNavigationScreens.Onboarding.route) NavHost( navController, - startDestination = startDestination + startDestination = AppSecurityRoutes.subGraphName() ) { + appSecurityGraph(navController = navController) { + navController.navigate(startDestinationScreen) { + popUpTo(AppSecurityRoutes.DeviceCheckLoadingScreen.path()) { + inclusive = true + } + } + } composable(MainNavigationScreens.Onboarding.route) { - OnboardingScreen( - mainNavController = navController, - settingsController = settingsController - ) + OnboardingScreen { + navController.navigate(MainNavigationScreens.Prescriptions.path()) { + launchSingleTop = true + popUpTo(MainNavigationScreens.Onboarding.path()) { + inclusive = true + } + } + } } composable(MainNavigationScreens.DataProtection.route) { NavigationAnimation(mode = navigationMode) { @@ -496,8 +503,7 @@ fun MainScreenNavigation( MainNavigationScreens.Settings.arguments ) { SettingsScreen( - mainNavController = navController, - settingsController = settingsController + mainNavController = navController ) } composable(MainNavigationScreens.Camera.route) { @@ -511,8 +517,13 @@ fun MainScreenNavigation( ) MainScreenScaffoldContainer( mainNavController = navController, - onDeviceIsInsecure = { - navController.navigate(MainNavigationScreens.IntegrityNotOkScreen.path()) + mainScreenController = mainScreenController, + onClickAddPrescription = { + if (mlKitAccepted) { + navController.navigate(MainNavigationScreens.MlKitIntroScreen.path()) + } else { + navController.navigate(MainNavigationScreens.Camera.path()) + } } ) } @@ -536,26 +547,16 @@ fun MainScreenNavigation( } ) } - composable(MainNavigationScreens.InsecureDeviceScreen.route) { - @Requirement( - "O.Plat_1#4", - sourceSpecification = "BSI-eRp-ePA", - rationale = "insecure Devices warning." - ) - InsecureDeviceScreen( - stringResource(id = R.string.insecure_device_title), - painterResource(id = R.drawable.laptop_woman_yellow), - stringResource(id = R.string.insecure_device_header), - stringResource(id = R.string.insecure_device_info), - stringResource(id = R.string.insecure_device_accept) - ) { - navController.navigate(MainNavigationScreens.Prescriptions.route) - } - } composable(MainNavigationScreens.MlKitIntroScreen.route) { MlKitIntroScreen( - navController, - settingsController + onAcceptMLKit = { + mainScreenController.acceptMLKit() + navController.navigate(MainNavigationScreens.Camera.path()) + }, + onClickReadMore = { + navController.navigate(MainNavigationScreens.MlKitInformationScreen.path()) + }, + onBack = { navController.popBackStack() } ) } composable(MainNavigationScreens.MlKitInformationScreen.route) { @@ -563,18 +564,6 @@ fun MainScreenNavigation( navController ) } - composable(MainNavigationScreens.IntegrityNotOkScreen.route) { - InsecureDeviceScreen( - stringResource(id = R.string.insecure_device_title_safetynet), - painterResource(id = R.drawable.laptop_woman_pink), - stringResource(id = R.string.insecure_device_header_safetynet), - stringResource(id = R.string.insecure_device_info_safetynet), - stringResource(id = R.string.insecure_device_accept_safetynet), - pinUseCase = false - ) { - navController.navigate(MainNavigationScreens.Prescriptions.route) - } - } composable( MainNavigationScreens.Redeem.route ) { @@ -688,11 +677,7 @@ fun MainScreenNavigation( AllowAnalyticsScreen( onBack = { navController.popBackStack() }, onAllowAnalytics = { - if (it) { - settingsController.onTrackingAllowed() - } else { - settingsController.onTrackingDisallowed() - } + mainScreenController.allowAnalytics(it) } ) } @@ -700,8 +685,12 @@ fun MainScreenNavigation( composable(MainNavigationScreens.Password.route) { NavigationAnimation(mode = navigationMode) { SecureAppWithPassword( - navController, - settingsController + onSelectPasswordAsAuthenticationMode = { password -> + mainScreenController.selectPasswordAsAuthenticationMode(password) + }, + onBack = { + navController.popBackStack() + } ) } } @@ -789,11 +778,10 @@ fun MainScreenNavigation( } @Composable -private fun checkFirstAppStart(settingsController: SettingsController) = - if (settingsController.showOnboarding) { - MainNavigationScreens.Onboarding.route - } else { - MainNavigationScreens.Prescriptions.route +private fun shouldOnboardingBeDone(onboardingSucceeded: Boolean): String = + when (onboardingSucceeded) { + true -> MainNavigationScreens.Prescriptions.route + false -> MainNavigationScreens.Onboarding.route } @Composable diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigationScreens.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigationScreens.kt index 55b54ecb..25540d76 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigationScreens.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/navigation/MainScreenNavigationScreens.kt @@ -21,8 +21,8 @@ package de.gematik.ti.erp.app.mainscreen.navigation import android.os.Parcelable import androidx.navigation.NavType import androidx.navigation.navArgument -import de.gematik.ti.erp.app.Route import de.gematik.ti.erp.app.card.model.command.UnlockMethod +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.prescription.detail.ui.model.PopUpName import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import kotlinx.parcelize.Parcelize @@ -33,22 +33,22 @@ import kotlinx.serialization.Serializable data class TaskIds(val ids: List) : Parcelable, List by ids object MainNavigationScreens { - object Onboarding : Route("onboarding") - object Settings : Route("settings") - object Camera : Route("main_scanner") - object Prescriptions : Route("main") - object Archive : Route("main_prescriptionArchive") + object Onboarding : Routes("onboarding") + object Settings : Routes("settings") + object Camera : Routes("main_scanner") + object Prescriptions : Routes("main") + object Archive : Routes("main_prescriptionArchive") object PrescriptionDetail : - Route( + Routes( "prescriptionDetail", navArgument("taskId") { type = NavType.StringType } ) { fun path(taskId: String) = path("taskId" to taskId) } - object Orders : Route("orders") + object Orders : Routes("orders") - object Messages : Route( + object Messages : Routes( "orders_detail", navArgument("orderId") { type = NavType.StringType } ) { @@ -56,43 +56,43 @@ object MainNavigationScreens { Messages.path("orderId" to orderId) } - object Pharmacies : Route("pharmacySearch") + object Pharmacies : Routes("pharmacySearch") - object Redeem : Route("redeem_methodSelection") + object Redeem : Routes("redeem_methodSelection") - object ProfileImageCropper : Route( + object ProfileImageCropper : Routes( "profile_editPicture_imageCropper", navArgument("profileId") { type = NavType.StringType } ) { fun path(profileId: String) = path("profileId" to profileId) } - object CardWall : Route( + object CardWall : Routes( "cardWall_introduction", navArgument("profileId") { type = NavType.StringType } ) { fun path(profileId: ProfileIdentifier) = path("profileId" to profileId) } - object InsecureDeviceScreen : Route("main_deviceSecurity") - object MlKitIntroScreen : Route("mlKit") - object MlKitInformationScreen : Route("mlKit_information") - object DataProtection : Route("settings_dataProtection") - object IntegrityNotOkScreen : Route("main_integrityWarning") + object MlKitIntroScreen : Routes("mlKit") + object MlKitInformationScreen : Routes("mlKit_information") + object DataProtection : Routes("settings_dataProtection") + object EditProfile : - Route("profile", navArgument("profileId") { type = NavType.StringType }) { + Routes("profile", navArgument("profileId") { type = NavType.StringType }) { fun path(profileId: String) = path("profileId" to profileId) } - object Terms : Route("settings_termsOfUse") - object Imprint : Route("settings_legalNotice") - object OpenSourceLicences : Route("settings_openSourceLicence") - object AdditionalLicences : Route("settings_additionalLicence") - object AllowAnalytics : Route("settings_productImprovements_complyTracking") - object Password : Route("settings_authenticationMethods_setAppPassword") - object Debug : Route("debug") - object OrderHealthCard : Route("contactInsuranceCompany") - - object UnlockEgk : Route( + + object Terms : Routes("settings_termsOfUse") + object Imprint : Routes("settings_legalNotice") + object OpenSourceLicences : Routes("settings_openSourceLicence") + object AdditionalLicences : Routes("settings_additionalLicence") + object AllowAnalytics : Routes("settings_productImprovements_complyTracking") + object Password : Routes("settings_authenticationMethods_setAppPassword") + object Debug : Routes("debug") + object OrderHealthCard : Routes("contactInsuranceCompany") + + object UnlockEgk : Routes( "healthCardPassword_introduction", navArgument("unlockMethod") { type = NavType.StringType } ) { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/presentation/MainScreenController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/presentation/MainScreenController.kt index b50b6d6f..35b2018a 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/presentation/MainScreenController.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/presentation/MainScreenController.kt @@ -22,23 +22,43 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue -import de.gematik.ti.erp.app.attestation.usecase.IntegrityUseCase +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.orders.usecase.OrderUseCase import de.gematik.ti.erp.app.prescription.ui.PrescriptionServiceState -import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase +import de.gematik.ti.erp.app.settings.usecase.AcceptMLKitUseCase +import de.gematik.ti.erp.app.settings.usecase.AllowAnalyticsUseCase +import de.gematik.ti.erp.app.settings.usecase.GetCanStartToolTipsUseCase +import de.gematik.ti.erp.app.settings.usecase.GetMLKitAcceptedUseCase +import de.gematik.ti.erp.app.settings.usecase.GetOnboardingSucceededUseCase +import de.gematik.ti.erp.app.settings.usecase.GetScreenShotsAllowedUseCase +import de.gematik.ti.erp.app.settings.usecase.GetShowWelcomeDrawerUseCase +import de.gematik.ti.erp.app.settings.usecase.SavePasswordUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveToolTippsShownUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveWelcomeDrawerShownUseCase +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch import org.kodein.di.compose.rememberInstance +@Suppress("LongParameterList") class MainScreenController( - private val integrityUseCase: IntegrityUseCase, private val messageUseCase: OrderUseCase, - private val settingsUseCase: SettingsUseCase + private val saveToolTipsShownUseCase: SaveToolTippsShownUseCase, + private val saveWelcomeDrawerShownUseCase: SaveWelcomeDrawerShownUseCase, + private val acceptMLKitUseCase: AcceptMLKitUseCase, + private val allowAnalyticsUseCase: AllowAnalyticsUseCase, + private val savePasswordUseCase: SavePasswordUseCase, + private val scope: CoroutineScope, + getScreenShotsAllowedUseCase: GetScreenShotsAllowedUseCase, + getOnboardingSucceededUseCase: GetOnboardingSucceededUseCase, + getCanStartToolTipsUseCase: GetCanStartToolTipsUseCase, + getShowWelcomeDrawerUseCase: GetShowWelcomeDrawerUseCase, + getMLKitAcceptedUseCase: GetMLKitAcceptedUseCase ) { enum class OrderedEvent { @@ -57,15 +77,39 @@ class MainScreenController( orderedEvent = null } - fun hasUnreadPrescriptionAvailable(profileIdentifier: ProfileIdentifier) = - messageUseCase.unreadPrescriptionAvailable(profileIdentifier) + private val screenshotsAllowed = + getScreenShotsAllowedUseCase.invoke() + + val screenshotsState + @Composable + get() = screenshotsAllowed.collectAsStateWithLifecycle(false) + + val onboardingSucceeded = getOnboardingSucceededUseCase.invoke() + + private val canStartToolTips = getCanStartToolTipsUseCase.invoke() + + val canStartToolTipsState + @Composable + get() = canStartToolTips.collectAsStateWithLifecycle(false) + + fun toolTippsShown() = scope.launch { + saveToolTipsShownUseCase() + } + + private val showWelcomeDrawer = + getShowWelcomeDrawerUseCase.invoke() + + val showWelcomeDrawerState + @Composable + get() = showWelcomeDrawer.collectAsStateWithLifecycle(false) + + fun welcomeDrawerShown() = scope.launch { + saveWelcomeDrawerShownUseCase() + } fun unreadOrders(profile: ProfilesUseCaseData.Profile) = messageUseCase.unreadOrders(profile) - fun unreadPrescriptionsInAllOrders(profileIdentifier: ProfileIdentifier) = - messageUseCase.unreadPrescriptionsInAllOrders(profileIdentifier) - suspend fun onRefresh(event: PrescriptionServiceState) { _onRefreshEvent.emit(event) } @@ -74,22 +118,60 @@ class MainScreenController( orderedEvent = if (hasError) OrderedEvent.Error else OrderedEvent.Success } - fun checkDeviceIntegrity() = integrityUseCase.runIntegrityAttestation().map { - !it && !settingsUseCase.general.first().userHasAcceptedInsecureDevice + private val mlKitAccepted = + getMLKitAcceptedUseCase.invoke() + + val mlKitAcceptedState + @Composable + get() = mlKitAccepted.collectAsStateWithLifecycle(false) + + fun acceptMLKit() = scope.launch { + acceptMLKitUseCase() + } + + @Requirement( + "O.Purp_5#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Enable usage analytics." + ) + fun allowAnalytics(allow: Boolean) = scope.launch { + allowAnalyticsUseCase(allow) + } + + fun selectPasswordAsAuthenticationMode(password: String) = scope.launch { + savePasswordUseCase.invoke(password) } } @Composable fun rememberMainScreenController(): MainScreenController { - val integrityUseCase by rememberInstance() val messageUseCase by rememberInstance() - val settingsUseCase by rememberInstance() + val getScreenShotsAllowedUseCase by rememberInstance() + val shouldShowOnboardingUseCase by rememberInstance() + val acceptMLKitUseCase by rememberInstance() + val getMLKitAcceptedUseCase by rememberInstance() + val allowAnalyticsUseCase by rememberInstance() + val savePasswordUseCase by rememberInstance() + val getShowToolTipsUseCase by rememberInstance() + val saveToolTipsShownUseCase by rememberInstance() + val getShowWelcomeDrawerUseCase by rememberInstance() + val saveWelcomeDrawerShownUseCase by rememberInstance() + val scope = rememberCoroutineScope() return remember { MainScreenController( - integrityUseCase = integrityUseCase, messageUseCase = messageUseCase, - settingsUseCase = settingsUseCase + getScreenShotsAllowedUseCase = getScreenShotsAllowedUseCase, + getOnboardingSucceededUseCase = shouldShowOnboardingUseCase, + acceptMLKitUseCase = acceptMLKitUseCase, + getMLKitAcceptedUseCase = getMLKitAcceptedUseCase, + allowAnalyticsUseCase = allowAnalyticsUseCase, + savePasswordUseCase = savePasswordUseCase, + getCanStartToolTipsUseCase = getShowToolTipsUseCase, + saveToolTipsShownUseCase = saveToolTipsShownUseCase, + getShowWelcomeDrawerUseCase = getShowWelcomeDrawerUseCase, + saveWelcomeDrawerShownUseCase = saveWelcomeDrawerShownUseCase, + scope = scope ) } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt deleted file mode 100644 index 36d4b6f9..00000000 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Copyright (c) 2024 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -package de.gematik.ti.erp.app.mainscreen.ui - -import androidx.compose.foundation.Image -import androidx.compose.foundation.LocalIndication -import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.selection.toggleable -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Button -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Switch -import androidx.compose.material.Text -import androidx.compose.material.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.unit.dp -import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.settings.ui.rememberSettingsController -import de.gematik.ti.erp.app.theme.AppTheme -import de.gematik.ti.erp.app.theme.PaddingDefaults -import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold -import de.gematik.ti.erp.app.utils.compose.BottomAppBar -import de.gematik.ti.erp.app.utils.compose.NavigationBarMode -import de.gematik.ti.erp.app.utils.compose.SpacerMedium -import de.gematik.ti.erp.app.utils.compose.SpacerSmall -import kotlinx.coroutines.launch -import java.util.Locale -@Requirement( - "O.Arch_6#3", - "O.Resi_2#3", - "O.Resi_3#3", - "O.Resi_4#3", - "O.Resi_5#3", - sourceSpecification = "BSI-eRp-ePA", - rationale = "Show integrity warning." -) -@Requirement( - "A_21574", - sourceSpecification = "gemSpec_IDP_Frontend", - rationale = "Show integrity warning." -) -@Composable -fun InsecureDeviceScreen( - headline: String, - icon: Painter, - headlineBody: String, - infoText: String, - toggleDescription: String, - pinUseCase: Boolean = true, - onBack: () -> Unit -) { - var checked by rememberSaveable { mutableStateOf(false) } - val scrollState = rememberScrollState() - val scope = rememberCoroutineScope() - - val settingsController = rememberSettingsController() - - AnimatedElevationScaffold( - elevated = scrollState.value > 0, - navigationMode = NavigationBarMode.Close, - bottomBar = { - BottomAppBar(backgroundColor = MaterialTheme.colors.surface) { - Spacer(modifier = Modifier.weight(1f)) - Button( - onClick = { - if (checked) { - scope.launch { - settingsController.onAcceptInsecureDevice() - } - } - onBack() - }, - shape = RoundedCornerShape(PaddingDefaults.Small), - enabled = if (pinUseCase) true else checked - ) { - if (checked && pinUseCase) { - Text(stringResource(R.string.understand).uppercase(Locale.getDefault())) - } else { - Text(stringResource(R.string.ok).uppercase(Locale.getDefault())) - } - } - SpacerMedium() - } - }, - actions = {}, - topBarTitle = headline, - onBack = onBack - ) { innerPadding -> - Column( - modifier = Modifier - .fillMaxSize() - .padding(innerPadding) - .verticalScroll(scrollState) - .padding(PaddingDefaults.Medium) - ) { - Image( - icon, - null, - contentScale = ContentScale.FillWidth, - modifier = Modifier.fillMaxSize() - ) - SpacerSmall() - Text( - headlineBody, - style = AppTheme.typography.h6 - ) - SpacerSmall() - Text( - infoText, - style = AppTheme.typography.body1 - ) - if (!pinUseCase) { - val uriHandler = LocalUriHandler.current - SpacerMedium() - Text( - stringResource(R.string.insecure_device_safetynet_more_info), - style = AppTheme.typography.body2, - color = AppTheme.colors.neutral600 - ) - SpacerSmall() - val link = stringResource(R.string.insecure_device_safetynet_link) - TextButton( - modifier = Modifier.align(Alignment.End), - onClick = { uriHandler.openUri(link) } - ) { - Text( - stringResource(id = R.string.insecure_device_safetynet_link_text), - style = AppTheme.typography.body2, - color = AppTheme.colors.primary600 - ) - } - } - Spacer(modifier = Modifier.height(PaddingDefaults.XXLarge)) - Toggle( - checked = checked, - onCheckedChange = { checked = it }, - description = toggleDescription - ) - } - } -} - -@Composable -private fun Toggle( - modifier: Modifier = Modifier, - checked: Boolean, - onCheckedChange: (Boolean) -> Unit, - description: String -) { - Row( - modifier = modifier - .clip(RoundedCornerShape(16.dp)) - .toggleable( - value = checked, - onValueChange = onCheckedChange, - role = Role.Switch, - interactionSource = remember { MutableInteractionSource() }, - indication = LocalIndication.current - ) - .background(color = AppTheme.colors.neutral100, shape = RoundedCornerShape(16.dp)) - .fillMaxWidth() - .padding(PaddingDefaults.Medium) - .semantics(true) {}, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - description, - style = AppTheme.typography.subtitle1, - modifier = Modifier.weight(1f) - ) - SpacerSmall() - Switch( - checked = checked, - onCheckedChange = null - ) - } -} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt index a0849658..6d2083af 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt @@ -47,13 +47,13 @@ import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens import de.gematik.ti.erp.app.mainscreen.navigation.MainScreenBottomPopUpNames +import de.gematik.ti.erp.app.mainscreen.presentation.MainScreenController import de.gematik.ti.erp.app.profiles.model.ProfilesData import de.gematik.ti.erp.app.profiles.presentation.ProfilesController import de.gematik.ti.erp.app.profiles.ui.AvatarPicker import de.gematik.ti.erp.app.profiles.ui.ColorPicker import de.gematik.ti.erp.app.profiles.ui.ProfileImage import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.settings.ui.rememberSettingsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.PrimaryButton @@ -89,12 +89,12 @@ sealed class MainScreenBottomSheetContentState { @Composable fun MainScreenBottomSheetContentState( mainNavController: NavController, + mainScreenController: MainScreenController, profilesController: ProfilesController, infoContentState: MainScreenBottomSheetContentState?, profileToRename: ProfilesUseCaseData.Profile, onCancel: () -> Unit ) { - val settingsController = rememberSettingsController() val profile by profilesController.getActiveProfileState() val title = when (infoContentState) { @@ -177,17 +177,13 @@ fun MainScreenBottomSheetContentState( is MainScreenBottomSheetContentState.Welcome -> ConnectBottomSheetContent( onClickConnect = { - scope.launch { - settingsController.welcomeDrawerShown() - } + mainScreenController.welcomeDrawerShown() mainNavController.navigate( MainNavigationScreens.CardWall.path(profile.id) ) }, onCancel = { - scope.launch { - settingsController.welcomeDrawerShown() - } + mainScreenController.welcomeDrawerShown() onCancel() } ) @@ -207,7 +203,7 @@ private fun EditProfileAvatar( onSelectProfileColor: (ProfilesData.ProfileColorNames) -> Unit ) { ProfileColorAndImagePickerContent( - profile, + profile = profile, clearPersonalizedImage = clearPersonalizedImage, onPickPersonalizedImage = onPickPersonalizedImage, onSelectAvatar = onSelectAvatar, @@ -227,7 +223,10 @@ private fun ProfileColorAndImagePickerContent( Column(modifier = Modifier.fillMaxSize()) { SpacerMedium() ProfileImage(editableProfile) { - editableProfile = editableProfile.copy(image = null) + editableProfile = editableProfile.copy( + avatar = ProfilesData.Avatar.PersonalizedImage, + image = null + ) clearPersonalizedImage() } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffold.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffold.kt index 31d798f7..114fdf49 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffold.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffold.kt @@ -40,19 +40,20 @@ import de.gematik.ti.erp.app.mainscreen.navigation.MainScreenContentNavHost import de.gematik.ti.erp.app.mainscreen.presentation.MainScreenController import de.gematik.ti.erp.app.profiles.presentation.ProfilesController import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.settings.ui.SettingsController @Composable internal fun MainScreenScaffold( + modifier: Modifier = Modifier, mainScreenController: MainScreenController, - settingsController: SettingsController, profilesController: ProfilesController, mainNavController: NavController, bottomNavController: NavHostController, + showToolTipps: Boolean, tooltipBounds: MutableState>, onClickAddProfile: () -> Unit, onClickChangeProfileName: (ProfilesUseCaseData.Profile) -> Unit, onClickAvatar: () -> Unit, + onClickAddPrescription: () -> Unit, scaffoldState: ScaffoldState ) { val currentBottomNavigationRoute by bottomNavController.currentBackStackEntryFlow.collectAsStateWithLifecycle(null) @@ -66,19 +67,19 @@ internal fun MainScreenScaffold( var topBarElevated by remember { mutableStateOf(true) } Scaffold( - modifier = Modifier.testTag(TestTag.Main.MainScreen), + modifier = Modifier.testTag(TestTag.Main.MainScreen).then(modifier), topBar = { if (currentBottomNavigationRoute?.destination?.route != MainNavigationScreens.Settings.route) { MultiProfileTopAppBar( mainScreenController = mainScreenController, - settingsController = settingsController, profilesController = profilesController, - navController = mainNavController, isInPrescriptionScreen = isInPrescriptionScreen, + showToolTipps = showToolTipps, tooltipBounds = tooltipBounds, elevated = topBarElevated, onClickAddProfile = onClickAddProfile, - onClickChangeProfileName = onClickChangeProfileName + onClickChangeProfileName = onClickChangeProfileName, + onClickAddPrescription = onClickAddPrescription ) } }, @@ -106,7 +107,6 @@ internal fun MainScreenScaffold( MainScreenContentNavHost( modifier = Modifier.padding(innerPadding), mainScreenController = mainScreenController, - settingsController = settingsController, mainNavController = mainNavController, bottomNavController = bottomNavController, onClickAvatar = onClickAvatar, diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffoldContainer.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffoldContainer.kt index 2bfe8954..a0d1885b 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffoldContainer.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MainScreenScaffoldContainer.kt @@ -18,6 +18,8 @@ package de.gematik.ti.erp.app.mainscreen.ui +import android.accessibilityservice.AccessibilityServiceInfo +import android.content.Context import android.net.Uri import androidx.activity.compose.BackHandler import androidx.compose.foundation.layout.imePadding @@ -44,83 +46,73 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController -import androidx.navigation.navOptions -import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.analytics.trackMainScreenBottomPopUps -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.analytics.trackScreenUsingNavEntry import de.gematik.ti.erp.app.core.LocalAnalytics -import de.gematik.ti.erp.app.features.BuildConfig import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens import de.gematik.ti.erp.app.mainscreen.presentation.MainScreenController -import de.gematik.ti.erp.app.mainscreen.presentation.rememberMainScreenController import de.gematik.ti.erp.app.profiles.presentation.ProfilesController.Companion.DEFAULT_EMPTY_PROFILE import de.gematik.ti.erp.app.profiles.presentation.rememberProfilesController -import de.gematik.ti.erp.app.settings.ui.rememberSettingsController -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext @OptIn(ExperimentalMaterialApi::class) @Suppress("LongMethod") @Composable internal fun MainScreenScaffoldContainer( mainNavController: NavController, - onDeviceIsInsecure: () -> Unit + mainScreenController: MainScreenController, + onClickAddPrescription: () -> Unit ) { - val mainScreenController = rememberMainScreenController() - val settingsController = rememberSettingsController() - val profilesController = rememberProfilesController() - val context = LocalContext.current + + val showToolTips by mainScreenController.canStartToolTipsState + var startToolTips by remember { mutableStateOf(false) } + + val profilesController = rememberProfilesController() val bottomNavController = rememberNavController() + val scaffoldState = rememberScaffoldState() + + val showWelcomeDrawer by mainScreenController.showWelcomeDrawerState + + var mainScreenBottomSheetContentState: MainScreenBottomSheetContentState? by remember { mutableStateOf(null) } + + val sheetState = rememberModalBottomSheetState( + initialValue = ModalBottomSheetValue.Hidden, + skipHalfExpanded = true + ) + val currentBottomNavigationRoute by bottomNavController.currentBackStackEntryFlow.collectAsStateWithLifecycle(null) + var previousNavEntry by remember { mutableStateOf("main") } - trackNavigationChanges(bottomNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + + trackNavigationChangesAsync(bottomNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + val isInPrescriptionScreen by remember { derivedStateOf { currentBottomNavigationRoute?.destination?.route == MainNavigationScreens.Prescriptions.route } } - @Requirement( - "O.Plat_1#2", - sourceSpecification = "BSI-eRp-ePA", - rationale = "Check for insecure Devices on MainScreen." - ) - CheckInsecureDevice(onDeviceIsInsecure) - @Requirement( - "O.Arch_6#2", - "O.Resi_2#2", - "O.Resi_3#2", - "O.Resi_4#2", - "O.Resi_5#2", - sourceSpecification = "BSI-eRp-ePA", - rationale = "Check device integrity." - ) - CheckDeviceIntegrity(mainScreenController, mainNavController) - val scaffoldState = rememberScaffoldState() - val scope = rememberCoroutineScope() + MainScreenSnackbar( mainScreenController = mainScreenController, scaffoldState = scaffoldState ) + OrderSuccessHandler(mainScreenController) - var mainScreenBottomSheetContentState: MainScreenBottomSheetContentState? by remember { mutableStateOf(null) } - val sheetState = rememberModalBottomSheetState( - initialValue = ModalBottomSheetValue.Hidden, - skipHalfExpanded = true - ) + if (sheetState.currentValue != ModalBottomSheetValue.Hidden) { DisposableEffect(Unit) { onDispose { - scope.launch { - settingsController.welcomeDrawerShown() + mainScreenController.welcomeDrawerShown() + if (showToolTips) { + startToolTips = true } } } } + LaunchedEffect(mainScreenBottomSheetContentState) { if (mainScreenBottomSheetContentState != null) { sheetState.show() @@ -140,22 +132,20 @@ internal fun MainScreenScaffoldContainer( trackScreenUsingNavEntry(route, analytics, analyticsState.screenNamesList) } } - LaunchedEffect(Unit) { - if (settingsController.showWelcomeDrawer.first()) { - mainScreenBottomSheetContentState = MainScreenBottomSheetContentState.Welcome() - } - } - LaunchedEffect(sheetState.isVisible) { - if (sheetState.targetValue == ModalBottomSheetValue.Hidden) { - if (mainScreenBottomSheetContentState == MainScreenBottomSheetContentState.Welcome()) { - settingsController.welcomeDrawerShown() - } - mainScreenBottomSheetContentState = null - } + + if (showWelcomeDrawer) { + mainScreenBottomSheetContentState = MainScreenBottomSheetContentState.Welcome() + mainScreenController.welcomeDrawerShown() } + LaunchedEffect(Unit) { - if (settingsController.talkbackEnabled(context)) { - settingsController.mainScreenTooltipsShown() + val accessibilityManager = + context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager + + if (accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN) + .isNotEmpty() + ) { + mainScreenController.toolTippsShown() } } var profileToRename by remember { @@ -164,7 +154,16 @@ internal fun MainScreenScaffoldContainer( val toolTipBounds = remember { mutableStateOf>(emptyMap()) } - ToolTips(settingsController, isInPrescriptionScreen, toolTipBounds) + if (startToolTips) { + ToolTips( + isInPrescriptionScreen, + toolTipBounds + ) { + startToolTips = false + mainScreenController.toolTippsShown() + } + } + val coroutineScope = rememberCoroutineScope() BackHandler(enabled = sheetState.isVisible) { coroutineScope.launch { @@ -180,6 +179,7 @@ internal fun MainScreenScaffoldContainer( sheetContent = { MainScreenBottomSheetContentState( mainNavController = mainNavController, + mainScreenController = mainScreenController, profilesController = profilesController, infoContentState = mainScreenBottomSheetContentState, profileToRename = profileToRename, @@ -195,10 +195,10 @@ internal fun MainScreenScaffoldContainer( ExternalAuthenticationDialog() MainScreenScaffold( mainScreenController = mainScreenController, - settingsController = settingsController, profilesController = profilesController, mainNavController = mainNavController, bottomNavController = bottomNavController, + showToolTipps = startToolTips, tooltipBounds = toolTipBounds, onClickAddProfile = { mainScreenBottomSheetContentState = @@ -211,52 +211,8 @@ internal fun MainScreenScaffoldContainer( onClickAvatar = { mainScreenBottomSheetContentState = MainScreenBottomSheetContentState.EditProfilePicture() }, + onClickAddPrescription = onClickAddPrescription, scaffoldState = scaffoldState ) } } - -@Composable -private fun CheckInsecureDevice(onDeviceIsInsecure: () -> Unit) { - val settingsController = rememberSettingsController() - LaunchedEffect(Unit) { - if (BuildConfig.DEBUG) { - return@LaunchedEffect - } - @Requirement( - "O.Plat_1#3", - sourceSpecification = "BSI-eRp-ePA", - rationale = "Navigate to insecure Devices warning." - ) - ( - withContext(Dispatchers.Main) { - if (settingsController.showInsecureDevicePrompt.first()) { - onDeviceIsInsecure() - } - } - ) - } -} - -@Composable -private fun CheckDeviceIntegrity( - mainScreenController: MainScreenController, - mainNavController: NavController -) { - LaunchedEffect(Unit) { - if (BuildConfig.DEBUG) { - return@LaunchedEffect - } - if (mainScreenController.checkDeviceIntegrity().first()) { - withContext(Dispatchers.Main) { - mainNavController.navigate(MainNavigationScreens.IntegrityNotOkScreen.route) - navOptions { - launchSingleTop = true - popUpTo(MainNavigationScreens.IntegrityNotOkScreen.path()) { - inclusive = true - } - } - } - } - } -} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MultiProfileTopAppBar.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MultiProfileTopAppBar.kt index adc1a90c..2dd2d672 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MultiProfileTopAppBar.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/MultiProfileTopAppBar.kt @@ -35,9 +35,7 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -50,35 +48,30 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens import de.gematik.ti.erp.app.mainscreen.presentation.MainScreenController import de.gematik.ti.erp.app.profiles.presentation.ProfilesController import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData.Profile -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.TopAppBarWithContent import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.launch /** * The top appbar of the actual main screen. */ @Composable internal fun MultiProfileTopAppBar( - navController: NavController, mainScreenController: MainScreenController, - settingsController: SettingsController, profilesController: ProfilesController, isInPrescriptionScreen: Boolean, elevated: Boolean, onClickAddProfile: () -> Unit, onClickChangeProfileName: (profile: Profile) -> Unit, + onClickAddPrescription: () -> Unit, + showToolTipps: Boolean, tooltipBounds: MutableState> ) { val profiles by profilesController.getProfilesState() @@ -86,14 +79,6 @@ internal fun MultiProfileTopAppBar( val accScan = stringResource(R.string.main_scan_acc) val elevation = remember(elevated) { if (elevated) AppBarDefaults.TopAppBarElevation else 0.dp } - val toolTipBoundsRequired by produceState(initialValue = false) { - settingsController.showMainScreenToolTips().collect { - value = it - } - } - - val scope = rememberCoroutineScope() - TopAppBarWithContent( title = { MainScreenTopBarTitle(isInPrescriptionScreen) @@ -104,20 +89,12 @@ internal fun MultiProfileTopAppBar( if (isInPrescriptionScreen) { // data matrix code scanner IconButton( - onClick = { - scope.launch { - if (settingsController.mlKitNotAccepted().first()) { - navController.navigate(MainNavigationScreens.MlKitIntroScreen.path()) - } else { - navController.navigate(MainNavigationScreens.Camera.path()) - } - } - }, + onClick = onClickAddPrescription, modifier = Modifier .testTag("erx_btn_scn_prescription") .semantics { contentDescription = accScan } .onGloballyPositioned { coordinates -> - if (toolTipBoundsRequired) { + if (showToolTipps) { tooltipBounds.value += Pair(0, coordinates.boundsInRoot()) } } @@ -137,7 +114,7 @@ internal fun MultiProfileTopAppBar( profiles = profiles, activeProfile = activeProfile, tooltipBounds = tooltipBounds, - toolTipBoundsRequired = toolTipBoundsRequired, + toolTipBoundsRequired = showToolTipps, onClickChangeProfileName = onClickChangeProfileName, onClickAddProfile = onClickAddProfile, onClickChangeActiveProfile = { profile -> diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt index 56814fd2..d7026889 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt @@ -38,9 +38,7 @@ import androidx.compose.runtime.Immutable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.geometry.Rect @@ -54,11 +52,9 @@ import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.min import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.Dialog -import kotlinx.coroutines.launch enum class ArrowPosition { Top, @@ -73,20 +69,13 @@ data class ToolTipState( @Composable fun ToolTips( - settingsController: SettingsController, isInPrescriptionScreen: Boolean, - toolTipBounds: MutableState> + toolTipBounds: MutableState>, + onToolTipsShown: () -> Unit ) { - val coroutineScope = rememberCoroutineScope() - var tooltipNr by remember { mutableStateOf(0) } - val showMainScreenTooltips by produceState(initialValue = false) { - settingsController.showMainScreenToolTips().collect { - value = it - } - } - if (isInPrescriptionScreen && showMainScreenTooltips) { + if (isInPrescriptionScreen) { when (tooltipNr) { 0 -> ToolTip( onDismissRequest = { @@ -111,11 +100,7 @@ fun ToolTips( ) 2 -> ToolTip( - onDismissRequest = { - coroutineScope.launch { - settingsController.mainScreenTooltipsShown() - } - }, + onDismissRequest = onToolTipsShown, tooltipState = ToolTipState( arrowPosition = ArrowPosition.Top, elementBound = toolTipBounds.value[2] ?: Rect.Zero @@ -153,7 +138,7 @@ fun ToolTipWithArrowTop( val offset = with(LocalDensity.current) { DpOffset( x = tooltipState.elementBound.bottomCenter.x.toDp() - 12.dp, - y = tooltipState.elementBound.bottomCenter.y.toDp() + 4.dp + y = tooltipState.elementBound.bottomCenter.y.toDp() - 36.dp ) } @@ -199,7 +184,7 @@ fun ToolTipWithArrowRight( val offset = with(LocalDensity.current) { DpOffset( x = tooltipState.elementBound.centerLeft.x.toDp() - 231.dp, - y = tooltipState.elementBound.centerLeft.y.toDp() - 12.dp + y = tooltipState.elementBound.centerLeft.y.toDp() - 50.dp ) } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavGraphBuilderExtension.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavGraphBuilderExtension.kt new file mode 100644 index 00000000..43704911 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavGraphBuilderExtension.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import androidx.compose.animation.AnimatedContentScope +import androidx.compose.animation.AnimatedContentTransitionScope +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.navigation.NamedNavArgument +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavDeepLink +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import de.gematik.ti.erp.app.navigation.Screen.Companion.track + +fun NavGraphBuilder.renderComposable( + route: String, + arguments: List = emptyList(), + deepLinks: List = emptyList(), + enterTransition: ( + @JvmSuppressWildcards + AnimatedContentTransitionScope.() -> EnterTransition? + )? = null, + exitTransition: ( + @JvmSuppressWildcards + AnimatedContentTransitionScope.() -> ExitTransition? + )? = null, + popEnterTransition: ( + @JvmSuppressWildcards + AnimatedContentTransitionScope.() -> EnterTransition? + )? = enterTransition, + popExitTransition: ( + @JvmSuppressWildcards + AnimatedContentTransitionScope.() -> ExitTransition? + )? = exitTransition, + screen: AnimatedContentScope.(NavBackStackEntry) -> Screen +) { + composable( + route = route, + arguments = arguments, + deepLinks = deepLinks, + enterTransition = enterTransition, + exitTransition = exitTransition, + popEnterTransition = popEnterTransition, + popExitTransition = popExitTransition, + content = { + screen(this, it).track(route).Content() + } + ) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationAnimationUtils.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationAnimationUtils.kt new file mode 100644 index 00000000..fd3ae4de --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationAnimationUtils.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import androidx.compose.animation.EnterTransition +import androidx.compose.animation.ExitTransition +import androidx.compose.animation.core.tween +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.slideInHorizontally +import androidx.compose.animation.slideInVertically +import androidx.compose.animation.slideOutHorizontally +import androidx.compose.animation.slideOutVertically + +val enterTransition: EnterTransition by lazy { + slideInVertically( + initialOffsetY = { -300 }, + animationSpec = tween(300) + ) + fadeIn(animationSpec = tween(300)) +} + +val exitTransition: ExitTransition by lazy { + slideOutVertically( + targetOffsetY = { -300 }, + animationSpec = tween(300) + ) + fadeOut(animationSpec = tween(300)) +} + +val popEnterTransition: EnterTransition by lazy { + slideInHorizontally( + initialOffsetX = { -300 }, + animationSpec = tween(300) + ) + fadeIn(animationSpec = tween(300)) +} + +val popExitTransition: ExitTransition by lazy { + slideOutHorizontally( + targetOffsetX = { 300 }, + animationSpec = tween(300) + ) + fadeOut(animationSpec = tween(300)) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRouteNames.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRouteNames.kt new file mode 100644 index 00000000..141d2191 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRouteNames.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +enum class NavigationRouteNames { + // App-security + DeviceCheckLoadingScreen, + InsecureDeviceScreen, + IntegrityWarningScreen, + + // Edit-profile + ProfileDetailsScreen, + ProfileColorAndImagePickerScreen, + ProfileImageCropperScreen, + ProfileTokenScreen, +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRoutes.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRoutes.kt new file mode 100644 index 00000000..99a2cb9a --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationRoutes.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +interface NavigationRoutes { + + fun subGraphName(): String +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationType.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationType.kt new file mode 100644 index 00000000..330edfd6 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/NavigationType.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import kotlinx.serialization.Serializable +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import kotlin.contracts.ExperimentalContracts +import kotlin.contracts.contract + +/** + * This NavigationType allows us to parse complex objects from one screen to another + */ +@OptIn(ExperimentalContracts::class) +inline fun T.toNavigationString(): String { + contract { + returns() implies (this@toNavigationString is Serializable) + } + return Json.encodeToString(this) +} + +inline fun fromNavigationString(value: String): T { + return Json.decodeFromString(value) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Routes.kt similarity index 72% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/Navigation.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Routes.kt index 34de90fb..41bd37a4 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Routes.kt @@ -16,48 +16,21 @@ * */ -package de.gematik.ti.erp.app +package de.gematik.ti.erp.app.navigation import android.net.Uri -import android.os.Bundle import android.os.Parcelable import androidx.compose.runtime.Immutable import androidx.navigation.NamedNavArgument import androidx.navigation.NavType -import de.gematik.ti.erp.app.mainscreen.navigation.TaskIds -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json abstract class UriNavType(override val isNullableAllowed: Boolean) : NavType(isNullableAllowed) { abstract fun serializeValue(value: T): String } -object AppNavTypes { - val TaskIdsType = object : UriNavType(false) { - override fun put(bundle: Bundle, key: String, value: TaskIds) { - bundle.putParcelable(key, value) - } - - override fun get(bundle: Bundle, key: String): TaskIds { - return bundle.getParcelable(key)!! - } - - override fun parseValue(value: String): TaskIds { - return Json.decodeFromString(value) - } - - override fun serializeValue(value: TaskIds): String { - return Json.encodeToString(value) - } - - override val name: String - get() = "taskIds" - } -} - @Immutable -open class Route(private val path: String, vararg arguments: NamedNavArgument) { +open class Routes(private val path: String, vararg arguments: NamedNavArgument) { val route = arguments.fold(Uri.Builder().path(path)) { uri, param -> uri.appendQueryParameter(param.name, "{${param.name}}") }.build().toString() diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Screen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Screen.kt new file mode 100644 index 00000000..1cd2fdb8 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/navigation/Screen.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import androidx.compose.runtime.Composable +import androidx.navigation.NavBackStackEntry +import androidx.navigation.NavController +import com.contentsquare.android.compose.analytics.TriggeredOnResume +import de.gematik.ti.erp.app.analytics.mapper.ContentSquareMapper +import io.github.aakira.napier.Napier + +abstract class Screen { + + abstract val navController: NavController + + abstract val navBackStackEntry: NavBackStackEntry + + val trackerMapper: ContentSquareMapper = ContentSquareMapper() + + @Composable + abstract fun Content() + + @Composable + fun trackScreen(screenName: String?) { + TriggeredOnResume { + // TODO: Track everytime by checking if it exists + Napier.d { "TODO: Tracking logger $screenName" } + // Contentsquare.send(screenName) + } + } + + companion object { + @Composable + fun Screen.track(route: String): Screen { + val routeEnum = when { + route.contains("?") -> route.split(("?"))[0] + else -> route + } + val trackedScreenName = trackerMapper.map(NavigationRouteNames.valueOf(routeEnum)) + trackScreen(trackedScreenName) + return this + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt index 06200df2..4dd1d55c 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt @@ -22,9 +22,7 @@ package de.gematik.ti.erp.app.onboarding.ui import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedContent -import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.foundation.Image -import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.background import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement @@ -38,7 +36,6 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.selection.toggleable import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Icon import androidx.compose.material.Switch @@ -52,7 +49,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment @@ -63,7 +59,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -74,16 +69,14 @@ import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.Route import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.features.BuildConfig import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.onboarding.model.OnboardingSecureAppMethod import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.ui.AllowAnalyticsScreen import de.gematik.ti.erp.app.settings.ui.AllowBiometryScreen -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.NavigationAnimation @@ -98,18 +91,16 @@ import de.gematik.ti.erp.app.utils.compose.visualTestTag import de.gematik.ti.erp.app.webview.URI_DATA_TERMS import de.gematik.ti.erp.app.webview.URI_TERMS_OF_USE import de.gematik.ti.erp.app.webview.WebViewScreen -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay -import kotlinx.coroutines.launch import kotlin.math.max import kotlin.math.min object OnboardingNavigationScreens { - object Onboarding : Route("onboarding") - object Analytics : Route("onboarding_analytics") - object TermsOfUse : Route("onboarding_termsOfUse") - object DataProtection : Route("onboarding_dataProtection") - object Biometry : Route("onboarding_biometry") + object Onboarding : Routes("onboarding") + object Analytics : Routes("onboarding_analytics") + object TermsOfUse : Routes("onboarding_termsOfUse") + object DataProtection : Routes("onboarding_dataProtection") + object Biometry : Routes("onboarding_biometry") } private enum class OnboardingPages(val index: Int) { @@ -130,13 +121,22 @@ private enum class OnboardingPages(val index: Int) { @Composable fun OnboardingScreen( - mainNavController: NavController, - settingsController: SettingsController + onOnboardingSucceeded: () -> Unit ) { val navController = rememberNavController() - val coroutineScope = rememberCoroutineScope() + val onboardingController = rememberOnboardingController() - var allowAnalytics by rememberSaveable { mutableStateOf(false) } + val isAnalyticsAllowed by onboardingController.isAnalyticsAllowedState + + LaunchedEffect(Unit) { + // `gemSpec_eRp_FdV A_20203` default settings are not allow screenshots + // (on debug builds should be allowed for testing) + if (BuildConfig.DEBUG) { + onboardingController.allowScreenshots(true) + } + } + + var allowAnalytics by rememberSaveable { mutableStateOf(isAnalyticsAllowed) } var secureMethod by rememberSaveable { mutableStateOf(OnboardingSecureAppMethod.None) } val navigationMode by navController.navigationModeState(OnboardingNavigationScreens.Onboarding.route) @@ -154,34 +154,27 @@ fun OnboardingScreen( secureMethod = it }, allowTracking = allowAnalytics, - onAllowTracking = { + onAllowAnalytics = { + onboardingController.changeAnalyticsState(it) allowAnalytics = it }, onSaveNewUser = { allowTracking, defaultProfileName, secureMethod -> - coroutineScope.launch(Dispatchers.Main) { - settingsController.onboardingSucceeded( - authenticationMode = when (secureMethod) { - is OnboardingSecureAppMethod.DeviceSecurity -> - SettingsData.AuthenticationMode.DeviceSecurity - - is OnboardingSecureAppMethod.Password -> - SettingsData.AuthenticationMode.Password( - password = requireNotNull(secureMethod.checkedPassword) - ) - - else -> error("Illegal state. Authentication must be set") - }, - defaultProfileName = defaultProfileName, - allowTracking = allowTracking - ) - - mainNavController.navigate(MainNavigationScreens.Prescriptions.path()) { - launchSingleTop = true - popUpTo(MainNavigationScreens.Onboarding.path()) { - inclusive = true - } - } - } + onboardingController.onboardingSucceeded( + authenticationMode = when (secureMethod) { + is OnboardingSecureAppMethod.DeviceSecurity -> + SettingsData.AuthenticationMode.DeviceSecurity + + is OnboardingSecureAppMethod.Password -> + SettingsData.AuthenticationMode.Password( + password = requireNotNull(secureMethod.checkedPassword) + ) + + else -> error("Illegal state. Authentication must be set") + }, + profileName = defaultProfileName, + allowAnalytics = allowTracking + ) + onOnboardingSucceeded() } ) } @@ -246,7 +239,7 @@ private fun OnboardingScreenWithScaffold( secureMethod: OnboardingSecureAppMethod, onSecureMethodChange: (OnboardingSecureAppMethod) -> Unit, allowTracking: Boolean, - onAllowTracking: (Boolean) -> Unit, + onAllowAnalytics: (Boolean) -> Unit, onSaveNewUser: ( allowTracking: Boolean, defaultProfileName: String, @@ -275,7 +268,7 @@ private fun OnboardingScreenWithScaffold( secureMethod, onSaveNewUser, allowTracking, - onAllowTracking, + onAllowAnalytics, onSecureMethodChange ) { page = it @@ -293,7 +286,6 @@ private fun OnboardingScreenWithScaffold( } } -@OptIn(ExperimentalAnimationApi::class) @Composable private fun OnboardingPages( page: OnboardingPages, @@ -342,7 +334,9 @@ private fun OnboardingPages( secureMethod = secureMethod, onSecureMethodChange = onSecureMethodChange, onOpenBiometricScreen = { - navController.navigate(OnboardingNavigationScreens.Biometry.path()) + navController.navigate(OnboardingNavigationScreens.Biometry.path()) { + launchSingleTop = true + } }, onNextPage = { onNextPage(OnboardingPages.Analytics) } ) @@ -677,7 +671,8 @@ private fun AnalyticsToggle( "A_19980#2", "A_19981#2", sourceSpecification = "gemSpec_eRp_FdV", - rationale = "The user is informed and required to accept this information via the data protection statement. Related data and services are listed in sections 5." // ktlint-disable max-line-length + rationale = "The user is informed and required to accept this information via the data protection statement." + + " Related data and services are listed in sections 5." ) @Composable private fun DataTermsToggle( @@ -703,21 +698,15 @@ private fun LargeToggle( .clip(RoundedCornerShape(PaddingDefaults.Medium)) .background(AppTheme.colors.neutral100, shape = RoundedCornerShape(16.dp)) .fillMaxWidth() - .toggleable( - value = checked, - onValueChange = onCheckedChange, - enabled = true, - role = Role.Switch, - interactionSource = remember { MutableInteractionSource() }, - indication = LocalIndication.current - ) .padding(PaddingDefaults.Medium), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(PaddingDefaults.Small) ) { Switch( checked = checked, - onCheckedChange = null + onCheckedChange = onCheckedChange, + enabled = true, + interactionSource = remember { MutableInteractionSource() } ) SpacerSmall() Text( diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingController.kt new file mode 100644 index 00000000..cbf2756b --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/onboarding/ui/OnboardingController.kt @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.onboarding.ui + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import de.gematik.ti.erp.app.analytics.Analytics +import de.gematik.ti.erp.app.analytics.usecase.ChangeAnalyticsStateUseCase +import de.gematik.ti.erp.app.analytics.usecase.IsAnalyticsAllowedUseCase +import de.gematik.ti.erp.app.settings.model.SettingsData +import de.gematik.ti.erp.app.settings.usecase.AllowScreenshotsUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveOnboardingSuccededUseCase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import org.kodein.di.compose.rememberInstance + +class OnboardingController( + private val saveOnboardingSuccededUseCase: SaveOnboardingSuccededUseCase, + private val allowScreenshotsUseCase: AllowScreenshotsUseCase, + private val isAnalyticsAllowedUseCase: IsAnalyticsAllowedUseCase, + private val changeAnalyticsStateUseCase: ChangeAnalyticsStateUseCase, + private val analytics: Analytics, + private val scope: CoroutineScope +) { + + private val isAnalyticsAllowed by lazy { + isAnalyticsAllowedUseCase.invoke() + } + + val isAnalyticsAllowedState + @Composable + get() = isAnalyticsAllowed.collectAsStateWithLifecycle(false) + + fun onboardingSucceeded( + authenticationMode: SettingsData.AuthenticationMode, + profileName: String, + allowAnalytics: Boolean + ) = scope.launch { + analytics.setAnalyticsPreference(allowAnalytics) + saveOnboardingSuccededUseCase( + authenticationMode = authenticationMode, + profileName = profileName + ) + } + + fun allowScreenshots(allow: Boolean) { + scope.launch { + allowScreenshotsUseCase(allow) + } + } + + fun changeAnalyticsState(state: Boolean) { + scope.launch { + changeAnalyticsStateUseCase.invoke(state) + } + } +} + +@Composable +fun rememberOnboardingController(): OnboardingController { + val saveOnboardingSuccededUseCase by rememberInstance() + val allowScreenshotsUseCase by rememberInstance() + val isAnalyticsAllowedUseCase by rememberInstance() + val changeAnalyticsStateUseCase by rememberInstance() + val scope = rememberCoroutineScope() + val analytics by rememberInstance() + + return remember { + OnboardingController( + saveOnboardingSuccededUseCase = saveOnboardingSuccededUseCase, + allowScreenshotsUseCase = allowScreenshotsUseCase, + isAnalyticsAllowedUseCase = isAnalyticsAllowedUseCase, + changeAnalyticsStateUseCase = changeAnalyticsStateUseCase, + analytics = analytics, + scope = scope + ) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt index 4605bbe4..d4f231f3 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt @@ -81,7 +81,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.orderhealthcard.usecase.model.HealthCardOrderUseCaseData import de.gematik.ti.erp.app.settings.ui.openMailClient @@ -104,7 +104,7 @@ fun HealthCardContactOrderScreen( val navController = rememberNavController() var previousNavEntry by remember { mutableStateOf("contactInsuranceCompany") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val title = stringResource(R.string.health_insurance_search_page_title) val navigationMode by navController.navigationModeState(HealthCardOrderNavigationScreens.HealthCardOrder.route) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt index 204e9e5f..e06a352e 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt @@ -22,7 +22,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.remember import androidx.lifecycle.compose.collectAsStateWithLifecycle -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.orderhealthcard.usecase.HealthCardOrderUseCase import de.gematik.ti.erp.app.orderhealthcard.usecase.model.HealthCardOrderUseCaseData import kotlinx.coroutines.flow.MutableStateFlow @@ -30,9 +30,9 @@ import kotlinx.coroutines.flow.combine import org.kodein.di.compose.rememberInstance object HealthCardOrderNavigationScreens { - object HealthCardOrder : Route("contactInsuranceCompany") - object SelectOrderOption : Route("contactInsuranceCompany_selectReason") - object HealthCardOrderContact : Route("contactInsuranceCompany_selectMethod") + object HealthCardOrder : Routes("contactInsuranceCompany") + object SelectOrderOption : Routes("contactInsuranceCompany_selectReason") + object HealthCardOrderContact : Routes("contactInsuranceCompany_selectMethod") } class HealthCardOrderState( diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt index f2433e1d..5d5536d2 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt @@ -30,7 +30,7 @@ import androidx.compose.runtime.setValue import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.mainscreen.presentation.rememberMainScreenController import de.gematik.ti.erp.app.pharmacy.presentation.PharmacyOrderController import de.gematik.ti.erp.app.pharmacy.presentation.PharmacySearchController @@ -126,7 +126,7 @@ fun PharmacyNavigation( } var previousNavEntry by remember { mutableStateOf("pharmacySearch") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val handleSearchResultFn = { searchResult: PharmacySearchController.SearchQueryResult -> when (searchResult) { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt index db5d99f7..aa3bd2d7 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt @@ -47,14 +47,12 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role -import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.pharmacy.presentation.PharmacyOrderController import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.deliveryUrlNotEmpty import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.isDeliveryWithoutContactUrls import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.isOnlineServiceWithoutContactUrls -import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.isPickupWithoutContactUrls import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.onlineUrlNotEmpty import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderExtensions.pickupUrlNotEmpty import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData @@ -65,6 +63,8 @@ import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.shortToast private const val MAX_OPTIONS = 3 +private const val DISABLED_ALPHA = 0.3f +private const val ENABLED_ALPHA = 1f @Composable internal fun OrderSelection( @@ -74,43 +74,25 @@ internal fun OrderSelection( ) { val directRedeemEnabled by pharmacyOrderController.isDirectRedeemEnabledState - val hasNoPickupContact = pharmacy.contacts.pickUpUrl.isEmpty() - val hasNoDeliveryContact = pharmacy.contacts.pickUpUrl.isEmpty() - val hasNoOnlineServiceContact = pharmacy.contacts.pickUpUrl.isEmpty() - val hasNoContacts = listOf(hasNoPickupContact, hasNoDeliveryContact, hasNoOnlineServiceContact) + val directRedeemUrlsNotPresent = pharmacy.directRedeemUrlsNotPresent - val hasNoContactUrls = hasNoContacts.all { it } + val (pickUpContactAvailable, deliveryContactAvailable, onlineContactAvailable) = + pharmacy.checkRedemptionAndContactAvailabilityForPharmacy(directRedeemEnabled) - // service availability checks - val pickUpServiceAvailable = directRedeemEnabled && pharmacy.pickupUrlNotEmpty() - val deliveryServiceAvailable = directRedeemEnabled && pharmacy.deliveryUrlNotEmpty() - val onlineServiceAvailable = directRedeemEnabled && pharmacy.onlineUrlNotEmpty() + val (pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible) = + pharmacy.checkServiceVisibility( + directRedeemUrlsNotPresent = directRedeemUrlsNotPresent, + deliveryServiceAvailable = deliveryContactAvailable, + onlineServiceAvailable = onlineContactAvailable + ) - // visibility checks - val pickUpServiceVisible = pickUpServiceAvailable || - pharmacy.pickupUrlNotEmpty() || - pharmacy.isPickupWithoutContactUrls(hasNoContactUrls) - - val deliveryServiceVisible = deliveryServiceAvailable || - pharmacy.deliveryUrlNotEmpty() || - pharmacy.isDeliveryWithoutContactUrls(hasNoContactUrls) - - val onlineServiceVisible = onlineServiceAvailable || - pharmacy.onlineUrlNotEmpty() || - pharmacy.isOnlineServiceWithoutContactUrls(hasNoContactUrls) - - // enabled checks - val pickupServiceEnabled = pharmacy.pickupUrlNotEmpty() || - pickUpServiceAvailable || - !directRedeemEnabled && pharmacy.isPickupService - - val deliveryServiceEnabled = pharmacy.deliveryUrlNotEmpty() || - deliveryServiceAvailable || - !directRedeemEnabled && pharmacy.isDeliveryService - - val onlineServiceEnabled = pharmacy.onlineUrlNotEmpty() || - onlineServiceAvailable || - !directRedeemEnabled && pharmacy.isOnlineService + val (pickupServiceEnabled, deliveryServiceEnabled, onlineServiceEnabled) = + pharmacy.checkServiceAvailability( + directRedeemEnabled = directRedeemEnabled, + pickUpContactAvailable = pickUpContactAvailable, + deliveryContactAvailable = deliveryContactAvailable, + onlineContactAvailable = onlineContactAvailable + ) val numberOfServices = remember(pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible) { listOf(pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible).count { it } @@ -170,7 +152,6 @@ internal fun OrderSelection( } } -@Suppress("MagicNumber") @Composable private fun OrderButton( modifier: Modifier, @@ -180,7 +161,7 @@ private fun OrderButton( image: Painter, onClick: () -> Unit ) { - val shape = RoundedCornerShape(16.dp) + val shape = RoundedCornerShape(PaddingDefaults.Medium) val serviceDisabledText = stringResource(R.string.connect_for_pharmacy_service) var showToast by remember { mutableStateOf(false) } @@ -205,8 +186,8 @@ private fun OrderButton( .padding(PaddingDefaults.Medium) .alpha( when { - isServiceEnabled -> 1f - else -> 0.3f + isServiceEnabled -> ENABLED_ALPHA + else -> DISABLED_ALPHA } ) ) { @@ -228,3 +209,54 @@ private fun OrderButton( shortToast(serviceDisabledText) } } + +private fun Pharmacy.checkRedemptionAndContactAvailabilityForPharmacy( + directRedeemEnabled: Boolean +): Triple { + val pickUpServiceAvailable = directRedeemEnabled && pickupUrlNotEmpty() + + val deliveryServiceAvailable = directRedeemEnabled && deliveryUrlNotEmpty() + + val onlineServiceAvailable = directRedeemEnabled && onlineUrlNotEmpty() + + return Triple(pickUpServiceAvailable, deliveryServiceAvailable, onlineServiceAvailable) +} + +private fun Pharmacy.checkServiceVisibility( + directRedeemUrlsNotPresent: Boolean, + deliveryServiceAvailable: Boolean, + onlineServiceAvailable: Boolean +): Triple { + val pickUpServiceVisible = pickupUrlNotEmpty() || directRedeemUrlsNotPresent + + val deliveryServiceVisible = deliveryServiceAvailable || + deliveryUrlNotEmpty() || + isDeliveryWithoutContactUrls(directRedeemUrlsNotPresent) + + val onlineServiceVisible = onlineServiceAvailable || + onlineUrlNotEmpty() || + isOnlineServiceWithoutContactUrls(directRedeemUrlsNotPresent) + + return Triple(pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible) +} + +private fun Pharmacy.checkServiceAvailability( + directRedeemEnabled: Boolean, + pickUpContactAvailable: Boolean, + deliveryContactAvailable: Boolean, + onlineContactAvailable: Boolean +): Triple { + val pickupServiceEnabled = pickupUrlNotEmpty() || + pickUpContactAvailable || + !directRedeemEnabled && isPickupService + + val deliveryServiceEnabled = deliveryUrlNotEmpty() || + deliveryContactAvailable || + !directRedeemEnabled && isDeliveryService + + val onlineServiceEnabled = onlineUrlNotEmpty() || + onlineContactAvailable || + !directRedeemEnabled && isOnlineService + + return Triple(pickupServiceEnabled, deliveryServiceEnabled, onlineServiceEnabled) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt index a2bf3c27..39a578a8 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt @@ -18,16 +18,16 @@ package de.gematik.ti.erp.app.pharmacy.ui.model -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.prescription.detail.ui.model.PopUpName object PharmacyNavigationScreens { - object StartSearch : Route("pharmacySearch") - object List : Route("pharmacySearch_detail") - object Maps : Route("pharmacySearch_map") - object OrderOverview : Route("redeem_viaTI") // TODO change when redeem_viaAVS is available - object EditShippingContact : Route("redeem_editContactInformation") - object PrescriptionSelection : Route("redeem_prescriptionChooseSubset") + object StartSearch : Routes("pharmacySearch") + object List : Routes("pharmacySearch_detail") + object Maps : Routes("pharmacySearch_map") + object OrderOverview : Routes("redeem_viaTI") // TODO change when redeem_viaAVS is available + object EditShippingContact : Routes("redeem_editContactInformation") + object PrescriptionSelection : Routes("redeem_prescriptionChooseSubset") } object PharmacySearchPopUpNames { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt index 1a0cbdb9..3d128e54 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt @@ -43,7 +43,7 @@ val prescriptionModule = DI.Module("prescriptionModule") { bindSingleton { PrescriptionLocalDataSource(instance()) } bindSingleton { PrescriptionRemoteDataSource(instance()) } bindSingleton { PrescriptionUseCase(instance(), instance(), instance()) } - bindSingleton { RefreshPrescriptionUseCase(instance(), instance(), instance()) } + bindSingleton { RefreshPrescriptionUseCase(instance(), instance(), instance(), instance(), instance()) } bindProvider { GetActivePrescriptionsUseCase(instance()) } bindProvider { GetArchivedPrescriptionsUseCase(instance()) } bindProvider { UpdateScannedTaskNameUseCase(instance()) } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt index e00829f4..b3aaeabb 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt @@ -63,7 +63,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.analytics.trackPrescriptionDetailPopUps import de.gematik.ti.erp.app.analytics.trackScreenUsingNavEntry import de.gematik.ti.erp.app.core.LocalAnalytics @@ -103,7 +103,7 @@ fun PrescriptionDetailsScreen( val navController = rememberNavController() var previousNavEntry by remember { mutableStateOf("prescriptionDetail") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) NavHost( navController = navController, diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt index cfb1637e..aee68dec 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt @@ -33,7 +33,7 @@ import de.gematik.ti.erp.app.prescription.ui.TwoDCodeValidator import de.gematik.ti.erp.app.prescription.usecase.PrescriptionUseCase import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.userauthentication.ui.AuthenticationModeAndMethod +import de.gematik.ti.erp.app.userauthentication.observer.AuthenticationModeAndMethod import de.gematik.ti.erp.app.utils.compose.shortToast import io.github.aakira.napier.Napier import kotlinx.coroutines.flow.Flow diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt index 904a48f4..44754589 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt @@ -33,7 +33,6 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionData import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.Label import de.gematik.ti.erp.app.utils.compose.NavigationBarMode @@ -45,8 +44,7 @@ fun TechnicalInformation( prescriptionDetailsController: PrescriptionDetailsController, onBack: () -> Unit ) { - val prescription by prescriptionDetailsController.prescriptionState - val syncedPrescription = prescription as? PrescriptionData.Synced + val prescriptionState by prescriptionDetailsController.prescriptionState val listState = rememberLazyListState() AnimatedElevationScaffold( @@ -66,7 +64,7 @@ fun TechnicalInformation( item { SpacerMedium() } - syncedPrescription?.accessCode?.let { + prescriptionState?.accessCode?.let { item { Label( modifier = Modifier.testTag(TestTag.Prescriptions.Details.TechnicalInformation.AccessCode), @@ -79,7 +77,7 @@ fun TechnicalInformation( item { Label( modifier = Modifier.testTag(TestTag.Prescriptions.Details.TechnicalInformation.TaskId), - text = syncedPrescription?.taskId, + text = taskId, label = stringResource(R.string.task_id) ) SpacerMedium() diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt index 6e52f7b3..3301fae4 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt @@ -19,18 +19,18 @@ package de.gematik.ti.erp.app.prescription.detail.ui.model import androidx.compose.runtime.Immutable -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes object PrescriptionDetailsNavigationScreens { - object Overview : Route("prescriptionDetail") - object MedicationOverview : Route("prescriptionDetail_medicationOverview") - object Medication : Route("prescriptionDetail_medication") - object Patient : Route("prescriptionDetail_patient") - object Prescriber : Route("prescriptionDetail_practitioner") - object Organization : Route("prescriptionDetail_organization") - object Accident : Route("prescriptionDetail_accidentInfo") - object TechnicalInformation : Route("prescriptionDetail_technicalInfo") - object Ingredient : Route("prescriptionDetail_medication_ingredients") + object Overview : Routes("prescriptionDetail") + object MedicationOverview : Routes("prescriptionDetail_medicationOverview") + object Medication : Routes("prescriptionDetail_medication") + object Patient : Routes("prescriptionDetail_patient") + object Prescriber : Routes("prescriptionDetail_practitioner") + object Organization : Routes("prescriptionDetail_organization") + object Accident : Routes("prescriptionDetail_accidentInfo") + object TechnicalInformation : Routes("prescriptionDetail_technicalInfo") + object Ingredient : Routes("prescriptionDetail_medication_ingredients") } object PrescriptionDetailsPopUpNames { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt index 412144d1..c7c5dc04 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt @@ -81,7 +81,7 @@ fun SmallMainScreenAvatar( modifier = Modifier.size(16.dp), emptyIcon = Icons.Rounded.AddAPhoto, profile = profile, - figure = profile.avatar + avatar = profile.avatar ) } } @@ -157,7 +157,7 @@ fun MainScreenAvatar( modifier = Modifier.size(24.dp), emptyIcon = Icons.Rounded.AddAPhoto, profile = profile, - figure = profile.avatar + avatar = profile.avatar ) } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt index 8fc09478..03f71107 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt @@ -32,18 +32,14 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.features.R -import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens -import de.gematik.ti.erp.app.settings.ui.SettingsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold @@ -52,7 +48,6 @@ import de.gematik.ti.erp.app.utils.compose.PrimaryButton import de.gematik.ti.erp.app.utils.compose.SecondaryButton import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall -import kotlinx.coroutines.launch @Requirement( "A_20194", @@ -61,11 +56,11 @@ import kotlinx.coroutines.launch ) @Composable fun MlKitIntroScreen( - navController: NavController, - settingsController: SettingsController + onClickReadMore: () -> Unit, + onAcceptMLKit: () -> Unit, + onBack: () -> Unit ) { val listState = rememberLazyListState() - val scope = rememberCoroutineScope() AnimatedElevationScaffold( modifier = Modifier @@ -73,22 +68,13 @@ fun MlKitIntroScreen( topBarTitle = "", bottomBar = { MlKitBottomBar( - onAccept = { - scope.launch { - settingsController.acceptMlKit() - } - navController.navigate(MainNavigationScreens.Camera.path()) - }, - onClickReadMore = { - navController.navigate(MainNavigationScreens.MlKitInformationScreen.path()) - } + onAccept = onAcceptMLKit, + onClickReadMore = onClickReadMore ) }, listState = listState, navigationMode = NavigationBarMode.Close, - onBack = { - navController.popBackStack() - } + onBack = onBack ) { LazyColumn( modifier = Modifier diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt index 71705f42..b9790417 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt @@ -33,6 +33,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn +/** + * The prescription [repository] obtains the active + * scanned and synced prescriptions and sorts them + * by the authored or scanned date in a descending order and then + * by name. + * + */ class GetActivePrescriptionsUseCase( private val repository: PrescriptionRepository, private val dispatcher: CoroutineDispatcher = Dispatchers.IO @@ -54,7 +61,11 @@ class GetActivePrescriptionsUseCase( .groupByHospitalsOrDoctors() .flatMapToPrescriptions() - (scannedPrescriptions + syncedPrescriptions) - .sortedByDescending { it.redeemedOn ?: it.startedOn } + (scannedPrescriptions + syncedPrescriptions).sortActives() }.flowOn(dispatcher) + + companion object { + private fun List.sortActives() = + sortedWith(compareByDescending { it.startedOn }.thenBy { it.name }) + } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt index beb8002e..3206362f 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt @@ -31,6 +31,13 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn +/** + * The prescription [repository] obtains the non-active + * scanned and synced prescriptions and sorts them + * by the redeemed date or expired date in a descending order and then + * by name. + * + */ class GetArchivedPrescriptionsUseCase( private val repository: PrescriptionRepository, private val dispatcher: CoroutineDispatcher = Dispatchers.IO @@ -50,8 +57,11 @@ class GetArchivedPrescriptionsUseCase( .filterNonActiveTasks() .map(SyncedTask::toPrescription) - (syncedPrescriptions + scannedPrescriptions) - .sortedBy { it.taskId } - .sortedByDescending { it.redeemedOn ?: it.startedOn } + (syncedPrescriptions + scannedPrescriptions).sortArchives() }.flowOn(dispatcher) + + companion object { + private fun List.sortArchives() = + sortedWith(compareByDescending { it.redeemedOn ?: it.expiresOn }.thenBy { it.name }) + } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt index a863b092..0a923498 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt @@ -19,9 +19,11 @@ package de.gematik.ti.erp.app.prescription.usecase import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.invoice.repository.InvoiceRepository import de.gematik.ti.erp.app.orders.repository.CommunicationRepository import de.gematik.ti.erp.app.prescription.repository.TaskRepository import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import de.gematik.ti.erp.app.profiles.repository.ProfileRepository import io.github.aakira.napier.Napier import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope @@ -37,6 +39,8 @@ import kotlinx.coroutines.withContext class RefreshPrescriptionUseCase( private val repository: TaskRepository, private val communicationRepository: CommunicationRepository, + private val invoiceRepository: InvoiceRepository, + private val profilesRepository: ProfileRepository, dispatchers: DispatchProvider ) { private class Request( @@ -64,6 +68,9 @@ class RefreshPrescriptionUseCase( val result = runCatching { val nrOfNewPrescriptions = repository.downloadTasks(profileId).getOrThrow() communicationRepository.downloadCommunications(profileId).getOrThrow() + if (profilesRepository.checkIsProfilePKV(profileId)) { + invoiceRepository.downloadInvoices(profileId) + } nrOfNewPrescriptions } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt index c443b79a..3864f0b4 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt @@ -25,9 +25,11 @@ import kotlinx.datetime.Instant @Immutable sealed interface Prescription { + val name: String? val taskId: String val redeemedOn: Instant? val startedOn: Instant? + val expiresOn: Instant? /** * Represents a single [Task] synchronized with the backend. @@ -35,13 +37,13 @@ sealed interface Prescription { @Immutable data class SyncedPrescription( override val taskId: String, + override val name: String?, override val redeemedOn: Instant?, + override val expiresOn: Instant?, val state: SyncedTaskData.SyncedTask.TaskState, - val name: String?, val isIncomplete: Boolean, val organization: String, val authoredOn: Instant, - val expiresOn: Instant?, val acceptUntil: Instant?, val isDirectAssignment: Boolean, val prescriptionChipInformation: PrescriptionChipInformation @@ -62,13 +64,14 @@ sealed interface Prescription { @Immutable data class ScannedPrescription( override val taskId: String, + override val name: String?, override val redeemedOn: Instant?, val scannedOn: Instant, - val name: String?, val index: Int, val communications: List ) : Prescription { override val startedOn = scannedOn + override val expiresOn = null } fun redeemedOrExpiredOn(): Instant = diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/Avatar.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/Avatar.kt index 4ee544a3..0dff0b2f 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/Avatar.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/Avatar.kt @@ -77,7 +77,7 @@ fun Avatar( profile = profile, emptyIcon = emptyIcon, modifier = iconModifier, - figure = profile.avatar + avatar = profile.avatar ) } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt index f0350207..1097d7dd 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt @@ -32,9 +32,9 @@ import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument -import de.gematik.ti.erp.app.Route -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.pkv.ui.InvoiceDetailsScreen import de.gematik.ti.erp.app.pkv.ui.InvoiceInformationScreen import de.gematik.ti.erp.app.pkv.ui.InvoiceLocalCorrectionScreen @@ -50,16 +50,16 @@ import de.gematik.ti.erp.app.utils.compose.NavigationMode import kotlinx.coroutines.launch object ProfileDestinations { - object Profile : Route("profile") - object Token : Route("profile_token") - object AuditEvents : Route("profile_auditEvents") - object PairedDevices : Route("profile_registeredDevices") - object ProfileImagePicker : Route("profile_editPicture") - object ProfileImageCropper : Route("profile_editPicture_imageCropper") - object Invoices : Route("chargeItem_list") + object Profile : Routes("profile") + object Token : Routes("profile_token") + object AuditEvents : Routes("profile_auditEvents") + object PairedDevices : Routes("profile_registeredDevices") + object ProfileImagePicker : Routes("profile_editPicture") + object ProfileImageCropper : Routes("profile_editPicture_imageCropper") + object Invoices : Routes("chargeItem_list") object InvoiceInformation : - Route( + Routes( "chargeItem_details", navArgument("taskId") { type = NavType.StringType } ) { @@ -67,7 +67,7 @@ object ProfileDestinations { } object InvoiceDetails : - Route( + Routes( "chargeItem_details_expanded", navArgument("taskId") { type = NavType.StringType } ) { @@ -75,7 +75,7 @@ object ProfileDestinations { } object InvoiceLocalCorrection : - Route( + Routes( "chargeItem_correct_locally", navArgument("taskId") { type = NavType.StringType } ) { @@ -83,7 +83,7 @@ object ProfileDestinations { } object ShareInformation : - Route( + Routes( "chargeItem_share", navArgument("taskId") { type = NavType.StringType } ) { @@ -102,7 +102,7 @@ fun EditProfileNavGraph( mainNavController: NavController ) { var previousNavEntry by remember { mutableStateOf("profile") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val scope = rememberCoroutineScope() val invoicesController = rememberInvoicesController(profileId = selectedProfile.id) val auditEventsController = rememberAuditEventsController() diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt index cf2d758f..80f2ea8f 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt @@ -119,6 +119,7 @@ import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.CommonAlertDialog import de.gematik.ti.erp.app.utils.compose.DynamicText +import de.gematik.ti.erp.app.utils.compose.ErrorText import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.SpacerLarge import de.gematik.ti.erp.app.utils.compose.SpacerSmall @@ -287,7 +288,10 @@ fun EditProfileScreenContent( ProfileNameDialog( profilesController = profilesController, wantRemoveLastProfile = true, - onEdit = { showAddDefaultProfileDialog = false; onRemoveProfile(it) }, + onEdit = { + showAddDefaultProfileDialog = false + onRemoveProfile(it) + }, onDismissRequest = { showAddDefaultProfileDialog = false } ) } @@ -534,7 +538,7 @@ fun ProfileNameSection( append(" ") appendInlineContent("edit", "edit") } - val c = mapOf( + val inlineContent = mapOf( "edit" to InlineTextContent( Placeholder( width = 0.em, @@ -548,7 +552,7 @@ fun ProfileNameSection( DynamicText( txt, style = AppTheme.typography.h5, - inlineContent = c, + inlineContent = inlineContent, modifier = Modifier .clickable { textFieldEnabled = true @@ -587,10 +591,8 @@ fun ProfileNameSection( stringResource(R.string.edit_profile_duplicated_profile_name) } - Text( + ErrorText( text = errorText, - color = AppTheme.colors.red600, - style = AppTheme.typography.caption1, modifier = Modifier.padding(start = PaddingDefaults.Medium) ) } @@ -679,7 +681,7 @@ fun ProfileAvatarSection( emptyIcon = Icons.Rounded.AddAPhoto, modifier = Modifier.size(24.dp), profile = profile, - figure = profile.avatar + avatar = profile.avatar ) } } @@ -702,11 +704,11 @@ fun ChooseAvatar( profile: ProfilesUseCaseData.Profile, emptyIcon: ImageVector, showPersonalizedImage: Boolean = true, - figure: ProfilesData.Avatar + avatar: ProfilesData.Avatar ) { - val imageResource = extractImageResource(useSmallImages, figure) + val imageResource = extractImageResource(useSmallImages, avatar) - when (figure) { + when (avatar) { ProfilesData.Avatar.PersonalizedImage -> { if (showPersonalizedImage) { if (profile.image != null) { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt index 7c1bedb2..f1a00ab1 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt @@ -95,18 +95,21 @@ fun ProfileColorAndImagePicker( actions = {} ) } - ) { + ) { paddingValues -> LazyColumn( state = listState, modifier = Modifier - .padding(it) + .padding(paddingValues) .fillMaxSize(), contentPadding = PaddingValues(PaddingDefaults.Medium) ) { item { SpacerMedium() ProfileImage(editableProfile) { - editableProfile = editableProfile.copy(image = null) + editableProfile = editableProfile.copy( + avatar = ProfilesData.Avatar.PersonalizedImage, + image = null + ) clearPersonalizedImage() } } @@ -148,7 +151,7 @@ fun ProfileColorAndImagePicker( @Composable fun AvatarPicker( profile: ProfilesUseCaseData.Profile, - currentAvatar: ProfilesData.Avatar, + currentAvatar: ProfilesData.Avatar?, onPickPersonalizedImage: () -> Unit, onSelectAvatar: (ProfilesData.Avatar) -> Unit ) { @@ -220,7 +223,7 @@ fun AvatarSelector( emptyIcon = Icons.Rounded.AddAPhoto, modifier = Modifier.size(24.dp), profile = profile, - figure = figure + avatar = figure ) } } @@ -276,7 +279,10 @@ fun ColorPicker( } @Composable -fun ProfileImage(selectedProfile: ProfilesUseCaseData.Profile, onClickDeleteAvatar: () -> Unit) { +fun ProfileImage( + selectedProfile: ProfilesUseCaseData.Profile, + onClickDeleteAvatar: () -> Unit +) { val colors = profileColor(profileColorNames = selectedProfile.color) Column( @@ -300,7 +306,7 @@ fun ProfileImage(selectedProfile: ProfilesUseCaseData.Profile, onClickDeleteAvat modifier = Modifier.size(36.dp), profile = selectedProfile, emptyIcon = Icons.Rounded.PersonOutline, - figure = selectedProfile.avatar, + avatar = selectedProfile.avatar, showPersonalizedImage = selectedProfile.image != null ) } @@ -316,7 +322,11 @@ fun ProfileImage(selectedProfile: ProfilesUseCaseData.Profile, onClickDeleteAvat .background(AppTheme.colors.neutral050) .border(1.dp, color = AppTheme.colors.neutral000, shape = RoundedCornerShape(16.dp)) ) { - IconButton(onClick = onClickDeleteAvatar) { + IconButton( + onClick = { + onClickDeleteAvatar() + } + ) { Icon( imageVector = Icons.Rounded.Close, tint = AppTheme.colors.neutral600, diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt deleted file mode 100644 index 27cf28fd..00000000 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2024 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -package de.gematik.ti.erp.app.profiles.ui - -import androidx.compose.runtime.Stable -import de.gematik.ti.erp.app.idp.model.IdpData -import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData.Profile - -@Deprecated("Not to be used, left here for reference in case of errors found") -class ProfileHandler { - - enum class ProfileConnectionState { - LoggedIn, - LoggedOutWithoutTokenBiometrics, - LoggedOutWithoutToken, - LoggedOut, - NeverConnected - } - - private fun Profile.neverConnected() = ssoTokenScope == null && lastAuthenticated == null - - private fun Profile.ssoTokenSetAndConnected() = - ssoTokenScope?.token != null && ssoTokenScope?.token?.isValid() == true - - private fun Profile.ssoTokenSetAndDisconnected() = - ssoTokenScope != null && ssoTokenScope?.token?.isValid() == false || - lastAuthenticated != null - - private fun Profile.ssoTokenNotSet() = - when (ssoTokenScope) { - is IdpData.ExternalAuthenticationToken, - is IdpData.AlternateAuthenticationToken, - is IdpData.AlternateAuthenticationWithoutToken, - is IdpData.DefaultToken -> ssoTokenScope?.token == null - - null -> true - } - - private fun Profile.ssoTokenWithoutScope() = - when (ssoTokenScope) { - is IdpData.AlternateAuthenticationWithoutToken -> true - else -> false - } - - @Stable - fun connectionState(profile: Profile): ProfileConnectionState? = - when { - profile.neverConnected() -> - ProfileConnectionState.NeverConnected - - profile.ssoTokenWithoutScope() -> - ProfileConnectionState.LoggedOutWithoutTokenBiometrics - - profile.ssoTokenNotSet() -> - ProfileConnectionState.LoggedOutWithoutToken - - profile.ssoTokenSetAndConnected() -> - ProfileConnectionState.LoggedIn - - profile.ssoTokenSetAndDisconnected() -> - ProfileConnectionState.LoggedOut - - else -> null - } -} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/Navigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/Navigation.kt index ffd90c21..05869e22 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/Navigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/Navigation.kt @@ -26,7 +26,7 @@ import androidx.compose.runtime.setValue import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.pharmacy.ui.PharmacyNavigation import de.gematik.ti.erp.app.pharmacy.ui.PrescriptionSelection import de.gematik.ti.erp.app.pharmacy.presentation.rememberPharmacyOrderController @@ -45,7 +45,7 @@ fun RedeemNavigation( val navigationMode by navController.navigationModeState(RedeemNavigation.MethodSelection.route) var previousNavEntry by remember { mutableStateOf("redeem_methodSelection") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) NavHost( navController, diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt index 1c26c9f3..88d8711e 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt @@ -18,12 +18,12 @@ package de.gematik.ti.erp.app.redeem.ui.model -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.navigation.Routes class RedeemNavigation { - object MethodSelection : Route("redeem_methodSelection") - object PrescriptionSelection : Route("redeem_prescriptionChooseSubset") - object LocalRedeem : Route("redeem_matrixCode") - object OnlineRedeem : Route("redeem_prescriptionAllOrSelection") - object PharmacySearch : Route("pharmacySearch") + object MethodSelection : Routes("redeem_methodSelection") + object PrescriptionSelection : Routes("redeem_prescriptionChooseSubset") + object LocalRedeem : Routes("redeem_matrixCode") + object OnlineRedeem : Routes("redeem_prescriptionAllOrSelection") + object PharmacySearch : Routes("pharmacySearch") } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/SettingsModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/SettingsModule.kt index 3dc15551..14b9cc17 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/SettingsModule.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/SettingsModule.kt @@ -18,8 +18,22 @@ package de.gematik.ti.erp.app.settings +import de.gematik.ti.erp.app.analytics.usecase.ChangeAnalyticsStateUseCase +import de.gematik.ti.erp.app.analytics.usecase.IsAnalyticsAllowedUseCase import de.gematik.ti.erp.app.settings.repository.CardWallRepository import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import de.gematik.ti.erp.app.settings.usecase.AcceptMLKitUseCase +import de.gematik.ti.erp.app.settings.usecase.AllowAnalyticsUseCase +import de.gematik.ti.erp.app.settings.usecase.AllowScreenshotsUseCase +import de.gematik.ti.erp.app.settings.usecase.GetCanStartToolTipsUseCase +import de.gematik.ti.erp.app.settings.usecase.GetMLKitAcceptedUseCase +import de.gematik.ti.erp.app.settings.usecase.GetOnboardingSucceededUseCase +import de.gematik.ti.erp.app.settings.usecase.GetScreenShotsAllowedUseCase +import de.gematik.ti.erp.app.settings.usecase.GetShowWelcomeDrawerUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveOnboardingSuccededUseCase +import de.gematik.ti.erp.app.settings.usecase.SavePasswordUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveToolTippsShownUseCase +import de.gematik.ti.erp.app.settings.usecase.SaveWelcomeDrawerShownUseCase import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase import org.kodein.di.DI import org.kodein.di.bindProvider @@ -31,4 +45,19 @@ val settingsModule = DI.Module("settingsModule") { bindProvider { CardWallRepository(prefs = instance(ApplicationPreferencesTag)) } bindProvider { SettingsRepository(instance(), instance()) } bindProvider { SettingsUseCase(instance(), instance()) } + bindProvider { IsAnalyticsAllowedUseCase(instance()) } + bindProvider { ChangeAnalyticsStateUseCase(instance()) } + bindProvider { GetScreenShotsAllowedUseCase(instance()) } + bindProvider { AllowScreenshotsUseCase(instance()) } + bindProvider { GetOnboardingSucceededUseCase(instance()) } + bindProvider { SaveOnboardingSuccededUseCase(instance()) } + bindProvider { AcceptMLKitUseCase(instance()) } + bindProvider { AllowAnalyticsUseCase(instance()) } + bindProvider { GetMLKitAcceptedUseCase(instance()) } + bindProvider { GetCanStartToolTipsUseCase(instance()) } + bindProvider { SaveToolTippsShownUseCase(instance()) } + bindProvider { SavePasswordUseCase(instance()) } + bindProvider { GetShowWelcomeDrawerUseCase(instance()) } + bindProvider { SaveWelcomeDrawerShownUseCase(instance()) } + // bindProvider { GetDeviceSecurityUseCase(instance(), instance()) } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt index a258f70c..ae48b676 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt @@ -40,7 +40,7 @@ fun AccessibilitySettingsScreen(onBack: () -> Unit) { val zoomState by settingsController.zoomState val scope = rememberCoroutineScope() val listState = rememberLazyListState() - val screenShotState by settingsController.screenshotState + val screenShotState by settingsController.screenShotsState AnimatedElevationScaffold( topBarTitle = stringResource(R.string.settings_accessibility_headline), @@ -67,16 +67,9 @@ fun AccessibilitySettingsScreen(onBack: () -> Unit) { } item { AllowScreenShotsSection( - screenShotsAllowed = screenShotState.screenshotsAllowed + screenShotsAllowed = screenShotState ) { allow -> - when (allow) { - true -> scope.launch { - settingsController.onAllowScreenshots() - } - false -> scope.launch { - settingsController.onDisAllowScreenshots() - } - } + settingsController.onAllowScreenshots(allow) } } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt index 77d9e5b1..a9b0bb07 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.settings.ui +import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding @@ -28,19 +29,17 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.semantics +import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.onboarding.model.OnboardingSecureAppMethod import de.gematik.ti.erp.app.onboarding.ui.OnboardingBottomBar import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults -import de.gematik.ti.erp.app.userauthentication.ui.BiometricPrompt +import de.gematik.ti.erp.app.userauthentication.observer.BiometricPromptBuilder import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.NavigationBarMode @@ -50,9 +49,28 @@ fun AllowBiometryScreen( onNext: () -> Unit, onSecureMethodChange: (OnboardingSecureAppMethod) -> Unit ) { - var showBiometricPrompt by remember { mutableStateOf(false) } val lazyListState = rememberLazyListState() + val activity = LocalActivity.current + + val biometricPromptBuilder = remember { BiometricPromptBuilder(activity as AppCompatActivity) } + + val infoBuilder = biometricPromptBuilder.buildPromptInfo( + title = stringResource(R.string.auth_prompt_headline), + negativeButton = stringResource(R.string.auth_prompt_cancel) + ) + + val prompt = remember(biometricPromptBuilder) { + biometricPromptBuilder.buildBiometricPrompt( + onSuccess = { + onSecureMethodChange(OnboardingSecureAppMethod.DeviceSecurity) + onNext() + }, + onFailure = { onBack() }, + onError = { onBack() } + ) + } + AnimatedElevationScaffold( modifier = Modifier.navigationBarsPadding(), navigationMode = NavigationBarMode.Close, @@ -60,7 +78,7 @@ fun AllowBiometryScreen( OnboardingBottomBar( buttonText = stringResource(R.string.settings_device_security_allow), onButtonClick = { - showBiometricPrompt = true + prompt.authenticate(infoBuilder) }, buttonEnabled = true, info = null, @@ -71,26 +89,6 @@ fun AllowBiometryScreen( listState = lazyListState, onBack = onBack ) { - if (showBiometricPrompt) { - BiometricPrompt( - title = stringResource(R.string.auth_prompt_headline), - description = "", - negativeButton = stringResource(R.string.auth_prompt_cancel), - onAuthenticated = { - onSecureMethodChange(OnboardingSecureAppMethod.DeviceSecurity) - onNext() - }, - onCancel = { - onBack() - }, - onAuthenticationError = { - onBack() - }, - onAuthenticationSoftError = { - } - ) - } - LazyColumn( state = lazyListState, modifier = Modifier diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt index 3d28aff9..b8c149f1 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt @@ -52,7 +52,7 @@ import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults -import de.gematik.ti.erp.app.userauthentication.ui.BiometricPrompt +import de.gematik.ti.erp.app.userauthentication.ui.BiometricPromptWrapper import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.CommonAlertDialog import de.gematik.ti.erp.app.utils.compose.NavigationBarMode @@ -70,7 +70,7 @@ fun DeviceSecuritySettingsScreen( var showBiometricPrompt by rememberSaveable { mutableStateOf(false) } if (showBiometricPrompt) { - BiometricPrompt( + BiometricPromptWrapper( title = stringResource(R.string.auth_prompt_headline), description = "", negativeButton = stringResource(R.string.auth_prompt_cancel), diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt index 9ff4019c..027aaa7a 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt @@ -54,7 +54,6 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi @@ -76,7 +75,6 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import com.nulabinc.zxcvbn.Zxcvbn import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.features.R @@ -88,24 +86,22 @@ import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.annotatedStringResource -import kotlinx.coroutines.launch import java.util.Locale private const val MinimalPasswordScore = 2 @Composable -fun SecureAppWithPassword(navController: NavController, settingsController: SettingsController) { +fun SecureAppWithPassword(onSelectPasswordAsAuthenticationMode: (String) -> Unit, onBack: () -> Unit) { var password by remember { mutableStateOf("") } var repeatedPassword by remember { mutableStateOf("") } var passwordScore by remember { mutableStateOf(0) } val focusRequester = FocusRequester.Default - val coroutineScope = rememberCoroutineScope() val scrollState = rememberScrollState() AnimatedElevationScaffold( topBarTitle = stringResource(R.string.settings_password_headline), navigationMode = NavigationBarMode.Back, - onBack = { navController.popBackStack() }, + onBack = onBack, elevated = scrollState.value > 0, actions = {}, bottomBar = { @@ -113,10 +109,8 @@ fun SecureAppWithPassword(navController: NavController, settingsController: Sett Spacer(modifier = Modifier.weight(1f)) Button( onClick = { - coroutineScope.launch { - settingsController.onSelectPasswordAsAuthenticationMode(password) - navController.popBackStack() - } + onSelectPasswordAsAuthenticationMode(password) + onBack() }, enabled = checkPassword( password = password, @@ -180,10 +174,8 @@ fun SecureAppWithPassword(navController: NavController, settingsController: Sett score = passwordScore ) ) { - coroutineScope.launch { - settingsController.onSelectPasswordAsAuthenticationMode(password) - navController.popBackStack() - } + onSelectPasswordAsAuthenticationMode(password) + onBack() } } ) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt index 3440e5ef..59b4077d 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt @@ -33,6 +33,9 @@ import androidx.compose.material.icons.outlined.OpenInBrowser import androidx.compose.material.icons.rounded.Timeline import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource @@ -49,15 +52,24 @@ import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.handleIntent import de.gematik.ti.erp.app.utils.compose.provideWebIntent +import de.gematik.ti.erp.app.utils.compose.shortToast @Composable fun ProductImprovementSettingsScreen( settingsController: SettingsController, - onAllowAnalytics: (Boolean) -> Unit, + onAllowAnalytics: () -> Unit, onBack: () -> Unit ) { + val toastText = stringResource(R.string.settings_tracking_disallow_info) + + val context = LocalContext.current + val analyticsState by settingsController.analyticsState + var isAnalyticsAllowed by remember( + analyticsState.analyticsAllowed + ) { mutableStateOf(analyticsState.analyticsAllowed) } + val listState = rememberLazyListState() AnimatedElevationScaffold( @@ -73,9 +85,17 @@ fun ProductImprovementSettingsScreen( item { SpacerMedium() AnalyticsSection( - analyticsState.analyticsAllowed - ) { allow -> - onAllowAnalytics(allow) + isAnalyticsAllowed + ) { state -> + isAnalyticsAllowed = !isAnalyticsAllowed + + if (!state) { + settingsController.changeAnalyticsState(false) + settingsController.onTrackingDisallowed() + context.shortToast(toastText) + } else { + onAllowAnalytics() + } } } item { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsController.kt index cd391ee6..cc45eeab 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsController.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsController.kt @@ -18,34 +18,48 @@ package de.gematik.ti.erp.app.settings.ui -import android.accessibilityservice.AccessibilityServiceInfo -import android.content.Context import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.lifecycle.compose.collectAsStateWithLifecycle import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.analytics.Analytics +import de.gematik.ti.erp.app.analytics.usecase.ChangeAnalyticsStateUseCase +import de.gematik.ti.erp.app.analytics.usecase.IsAnalyticsAllowedUseCase import de.gematik.ti.erp.app.settings.model.SettingsData +import de.gematik.ti.erp.app.settings.usecase.AllowScreenshotsUseCase +import de.gematik.ti.erp.app.settings.usecase.GetScreenShotsAllowedUseCase import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.first +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.map -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.launch import org.kodein.di.compose.rememberInstance -@Suppress("TooManyFunctions") class SettingsController( private val settingsUseCase: SettingsUseCase, + private val isAnalyticsAllowedUseCase: IsAnalyticsAllowedUseCase, + private val changeAnalyticsStateUseCase: ChangeAnalyticsStateUseCase, + getScreenShotsAllowedUseCase: GetScreenShotsAllowedUseCase, + private val allowScreenshotsUseCase: AllowScreenshotsUseCase, + private val scope: CoroutineScope, private val analytics: Analytics ) { - private val analyticsFlow = analytics.analyticsAllowed.map { SettingStatesData.AnalyticsState(it) } + private val analyticsFlow by lazy { + isAnalyticsAllowedUseCase().map { SettingStatesData.AnalyticsState(it) } + } val analyticsState @Composable get() = analyticsFlow.collectAsStateWithLifecycle(SettingStatesData.defaultAnalyticsState) + fun changeAnalyticsState(boolean: Boolean) { + scope.launch { + changeAnalyticsStateUseCase.invoke(boolean) + } + } + private val authenticationModeFlow = settingsUseCase.authenticationMode.map { SettingStatesData.AuthenticationModeState( it @@ -62,13 +76,12 @@ class SettingsController( @Composable get() = zoomFlow.collectAsStateWithLifecycle(SettingStatesData.defaultZoomState) - private val screenShotFlow = settingsUseCase.general.map { - SettingStatesData.ScreenshotState(it.screenShotsAllowed) - } + private val screenShotsAllowed = + getScreenShotsAllowedUseCase.invoke() - val screenshotState + val screenShotsState @Composable - get() = screenShotFlow.collectAsStateWithLifecycle(SettingStatesData.defaultScreenshotState) + get() = screenShotsAllowed.collectAsStateWithLifecycle(false) suspend fun onSelectDeviceSecurityAuthenticationMode() { settingsUseCase.saveAuthenticationMode( @@ -76,16 +89,8 @@ class SettingsController( ) } - suspend fun onSelectPasswordAsAuthenticationMode(password: String) { - settingsUseCase.saveAuthenticationMode(SettingsData.AuthenticationMode.Password(password = password)) - } - - suspend fun onAllowScreenshots() { - settingsUseCase.saveAllowScreenshots(true) - } - - suspend fun onDisAllowScreenshots() { - settingsUseCase.saveAllowScreenshots(false) + fun onAllowScreenshots(allow: Boolean) = scope.launch { + allowScreenshotsUseCase.invoke(allow) } suspend fun onEnableZoom() { @@ -96,50 +101,21 @@ class SettingsController( settingsUseCase.saveZoomPreference(false) } - @Requirement( - "O.Purp_5#3", - sourceSpecification = "BSI-eRp-ePA", - rationale = "Enable usage analytics." - ) - fun onTrackingAllowed() { - analytics.allowAnalytics() - } - @Requirement( "O.Purp_5#4", sourceSpecification = "BSI-eRp-ePA", rationale = "Disable usage analytics." ) fun onTrackingDisallowed() { - analytics.disallowAnalytics() - } - - suspend fun onboardingSucceeded( - authenticationMode: SettingsData.AuthenticationMode, - defaultProfileName: String, - allowTracking: Boolean - ) { - settingsUseCase.onboardingSucceeded( - authenticationMode = authenticationMode, - defaultProfileName = defaultProfileName - ) - if (allowTracking) { - onTrackingAllowed() - } else { - onTrackingDisallowed() - } + analytics.setAnalyticsPreference(false) } - var showOnboarding = runBlocking { settingsUseCase.showOnboarding.first() } - var showWelcomeDrawer = runBlocking { settingsUseCase.showWelcomeDrawer } - private var insecureDevicePromptShown = false val showInsecureDevicePrompt = settingsUseCase .showInsecureDevicePrompt .map { - if (showOnboarding) { - false - } else if (!insecureDevicePromptShown) { + // onb ... + if (!insecureDevicePromptShown) { insecureDevicePromptShown = true it } else { @@ -150,43 +126,27 @@ class SettingsController( suspend fun onAcceptInsecureDevice() { settingsUseCase.acceptInsecureDevice() } - - suspend fun acceptMlKit() { - settingsUseCase.acceptMlKit() - } - - suspend fun welcomeDrawerShown() { - settingsUseCase.welcomeDrawerShown() - } - - suspend fun mainScreenTooltipsShown() { - settingsUseCase.mainScreenTooltipsShown() - } - - fun showMainScreenToolTips(): Flow = settingsUseCase.general - .map { !it.mainScreenTooltipsShown && it.welcomeDrawerShown } - - fun mlKitNotAccepted() = - settingsUseCase.general.map { !it.mlKitAccepted } - - fun talkbackEnabled(context: Context): Boolean { - val accessibilityManager = - context.getSystemService(Context.ACCESSIBILITY_SERVICE) as android.view.accessibility.AccessibilityManager - - return accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_SPOKEN) - .isNotEmpty() - } } @Composable fun rememberSettingsController(): SettingsController { val settingsUseCase by rememberInstance() + val isAnalyticsAllowedUseCase by rememberInstance() + val changeAnalyticsStateUseCase by rememberInstance() + val getScreenShotsAllowedUseCase by rememberInstance() + val allowScreenshotsUseCase by rememberInstance() val analytics by rememberInstance() + val scope = rememberCoroutineScope() return remember { SettingsController( - settingsUseCase, - analytics + settingsUseCase = settingsUseCase, + isAnalyticsAllowedUseCase = isAnalyticsAllowedUseCase, + changeAnalyticsStateUseCase = changeAnalyticsStateUseCase, + getScreenShotsAllowedUseCase = getScreenShotsAllowedUseCase, + allowScreenshotsUseCase = allowScreenshotsUseCase, + analytics = analytics, + scope = scope ) } } @@ -213,14 +173,4 @@ object SettingStatesData { ) val defaultZoomState = ZoomState(zoomEnabled = false) - - @Immutable - data class ScreenshotState( - val screenshotsAllowed: Boolean - ) - - // `gemSpec_eRp_FdV A_20203` default settings are not allow screenshots - val defaultScreenshotState = ScreenshotState( - screenshotsAllowed = false - ) } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt index c6b5d753..32738629 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt @@ -21,32 +21,29 @@ package de.gematik.ti.erp.app.settings.ui import AccessibilitySettingsScreen import androidx.compose.runtime.Composable import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.navigation.NavController import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import de.gematik.ti.erp.app.MainActivity import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.Route import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.demomode.DemoModeIntent import de.gematik.ti.erp.app.demomode.startAppWithDemoMode -import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.demomode.startAppWithNormalMode import de.gematik.ti.erp.app.info.BuildConfigInformation import de.gematik.ti.erp.app.mainscreen.navigation.MainNavigationScreens +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.utils.compose.NavigationAnimation import de.gematik.ti.erp.app.utils.compose.NavigationMode -import de.gematik.ti.erp.app.utils.compose.shortToast import kotlinx.coroutines.launch object SettingsNavigationScreens { - object Settings : Route("settings") - object AccessibilitySettings : Route("settings_accessibility") - object ProductImprovementSettings : Route("settings_productImprovements") - object DeviceSecuritySettings : Route("settings_authenticationMethods") + object Settings : Routes("settings") + object AccessibilitySettings : Routes("settings_accessibility") + object ProductImprovementSettings : Routes("settings_productImprovements") + object DeviceSecuritySettings : Routes("settings_authenticationMethods") } @Suppress("LongMethod") @@ -70,6 +67,9 @@ fun SettingsNavGraph( mainNavController = mainNavController, navController = settingsNavController, buildConfig = buildConfig, + onClickDemoModeEnd = { + DemoModeIntent.startAppWithNormalMode(activity) + }, onClickDemoMode = { DemoModeIntent.startAppWithDemoMode(activity) } @@ -82,9 +82,6 @@ fun SettingsNavGraph( ) } composable(SettingsNavigationScreens.ProductImprovementSettings.route) { - val context = LocalContext.current - val disAllowAnalyticsToast = stringResource(R.string.settings_tracking_disallow_info) - ProductImprovementSettingsScreen( settingsController = settingsController, onAllowAnalytics = { @@ -100,12 +97,7 @@ fun SettingsNavGraph( rationale = "The agreement to the use of the analytics framework could be revoked. " + "But other agreements cannot be revoked, since the app could not operate properly." ) - if (!it) { - settingsController.onTrackingDisallowed() - context.shortToast(disAllowAnalyticsToast) - } else { - mainNavController.navigate(MainNavigationScreens.AllowAnalytics.path()) - } + mainNavController.navigate(MainNavigationScreens.AllowAnalytics.path()) }, onBack = { settingsNavController.popBackStack() } ) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt index 94c327da..9f4bc9e1 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt @@ -88,8 +88,11 @@ import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.card.model.command.UnlockMethod +import de.gematik.ti.erp.app.core.LocalActivity +import de.gematik.ti.erp.app.utils.compose.OutlinedDebugButton +import de.gematik.ti.erp.app.demomode.DemoModeObserver import de.gematik.ti.erp.app.features.BuildConfig import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.info.BuildConfigInformation @@ -102,7 +105,6 @@ import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData.Profile. import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AlertDialog -import de.gematik.ti.erp.app.utils.compose.OutlinedDebugButton import de.gematik.ti.erp.app.utils.compose.SpacerLarge import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall @@ -117,13 +119,13 @@ import java.util.Locale @Composable fun SettingsScreen( - mainNavController: NavController, - settingsController: SettingsController + mainNavController: NavController ) { val buildConfig by rememberInstance() val settingsNavController = rememberNavController() + val settingsController = rememberSettingsController() var previousNavEntry by remember { mutableStateOf("settings") } - trackNavigationChanges(settingsNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(settingsNavController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val navigationMode by settingsNavController.navigationModeState(SettingsNavigationScreens.Settings.route) SettingsNavGraph( @@ -140,9 +142,13 @@ fun SettingsScreenWithScaffold( mainNavController: NavController, navController: NavController, buildConfig: BuildConfigInformation, + onClickDemoModeEnd: () -> Unit, onClickDemoMode: () -> Unit ) { val context = LocalContext.current + val demoModeObserver = LocalActivity.current as? DemoModeObserver + val isDemomode = demoModeObserver?.isDemoMode() ?: false + val profilesController = rememberProfilesController() val profilesState by profilesController.getProfilesState() @@ -174,23 +180,26 @@ fun SettingsScreenWithScaffold( ProfileSection(profilesState, mainNavController) SettingsDivider() } - item { - HealthCardSection( - onClickUnlockEgk = { unlockMethod -> - mainNavController.navigate( - MainNavigationScreens.UnlockEgk.path( - unlockMethod = unlockMethod + if (!isDemomode) { + item { + HealthCardSection( + onClickUnlockEgk = { unlockMethod -> + mainNavController.navigate( + MainNavigationScreens.UnlockEgk.path( + unlockMethod = unlockMethod + ) ) - ) - }, - onClickOrderHealthCard = { - mainNavController.navigate(MainNavigationScreens.OrderHealthCard.path()) - } - ) - SettingsDivider() + }, + onClickOrderHealthCard = { + mainNavController.navigate(MainNavigationScreens.OrderHealthCard.path()) + } + ) + SettingsDivider() + } } item { GlobalSettingsSection( + isDemomode = isDemomode, onClickAccessibilitySettings = { navController.navigate(SettingsNavigationScreens.AccessibilitySettings.path()) }, @@ -200,6 +209,7 @@ fun SettingsScreenWithScaffold( onClickDeviceSecuritySettings = { navController.navigate(SettingsNavigationScreens.DeviceSecuritySettings.path()) }, + onClickDemoModeEnd = onClickDemoModeEnd, onClickDemoMode = onClickDemoMode ) SettingsDivider() @@ -229,9 +239,11 @@ fun SettingsScreenWithScaffold( @Composable fun GlobalSettingsSection( + isDemomode: Boolean, onClickAccessibilitySettings: () -> Unit, onClickProductImprovementSettings: () -> Unit, onClickDeviceSecuritySettings: () -> Unit, + onClickDemoModeEnd: () -> Unit, onClickDemoMode: () -> Unit ) { @@ -246,11 +258,20 @@ fun GlobalSettingsSection( top = PaddingDefaults.Medium ) ) - LabelButton( - icon = painterResource(R.drawable.magic_wand_filled), - stringResource(R.string.demo_mode_settings_title) - ) { - onClickDemoMode() + if (isDemomode) { + LabelButton( + icon = painterResource(R.drawable.magic_wand_filled), + stringResource(R.string.demo_mode_settings_end_title) + ) { + onClickDemoModeEnd() + } + } else { + LabelButton( + icon = painterResource(R.drawable.magic_wand_filled), + stringResource(R.string.demo_mode_settings_title) + ) { + onClickDemoMode() + } } LabelButton( Icons.Outlined.AccessibilityNew, @@ -594,7 +615,7 @@ private fun LabelButton( } @Composable -private fun LabelButton( +fun LabelButton( icon: Painter, text: String, modifier: Modifier = Modifier, diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt index add03031..20b66a66 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt @@ -20,7 +20,6 @@ package de.gematik.ti.erp.app.settings.usecase import android.app.KeyguardManager import android.content.Context -import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.profiles.usecase.sanitizedProfileName import de.gematik.ti.erp.app.settings.GeneralSettings @@ -32,13 +31,8 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.datetime.Clock import kotlinx.datetime.Instant -import kotlinx.datetime.LocalDate -import kotlinx.datetime.TimeZone -import kotlinx.datetime.atStartOfDayIn - -val DATA_PROTECTION_LAST_UPDATED: Instant = - LocalDate.parse(BuildKonfig.DATA_PROTECTION_LAST_UPDATED).atStartOfDayIn(TimeZone.UTC) +// TODO: Break into smaller usecases class SettingsUseCase( private val context: Context, private val settingsRepository: SettingsRepository @@ -64,7 +58,6 @@ class SettingsUseCase( } // end::ShowInsecureDevicePrompt[] - val showOnboarding = settingsRepository.general.map { it.onboardingShownIn == null } // TODO Move to Mainscreen val showWelcomeDrawer = settingsRepository.general.map { !it.welcomeDrawerShown } suspend fun welcomeDrawerShown() { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/datasource/local/TimeoutsLocalDataSource.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/datasource/local/TimeoutsLocalDataSource.kt new file mode 100644 index 00000000..c81fa9ea --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/datasource/local/TimeoutsLocalDataSource.kt @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ +@file:Suppress("MagicNumber") + +package de.gematik.ti.erp.app.timeouts.datasource.local + +import android.content.SharedPreferences +import androidx.core.content.edit +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.INACTIVITY_TIMER_ENUM +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.INACTIVITY_TIMER_VALUE +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.PAUSE_TIMER_ENUM +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.PAUSE_TIMER_VALUE +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultInactivityMetric +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultInactivityValue +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultPauseValue +import kotlin.time.Duration +import kotlin.time.DurationUnit +import kotlin.time.ExperimentalTime +import kotlin.time.toDuration + +object TimeoutConstant { + const val INACTIVITY_TIMER_VALUE = "INACTIVITY_TIMER" + const val INACTIVITY_TIMER_ENUM = "INACTIVITY_TIMER_ENUM" + const val PAUSE_TIMER_VALUE = "PAUSE_TIMER" + const val PAUSE_TIMER_ENUM = "PAUSE_TIMER_ENUM" + const val defaultInactivityValue = 10 + const val defaultPauseValue = 30 + val defaultInactivityMetric = DurationUnit.MINUTES + val defaultPauseMetric = DurationUnit.SECONDS +} + +class TimeoutsLocalDataSource( + private val sharedPreferences: SharedPreferences +) { + fun setDefaultTimeouts() { + sharedPreferences.edit { + putInt(INACTIVITY_TIMER_VALUE, defaultInactivityValue) + apply() + } + sharedPreferences.edit { + putInt(PAUSE_TIMER_VALUE, defaultPauseValue) + apply() + } + sharedPreferences.edit { + putString(INACTIVITY_TIMER_ENUM, defaultInactivityMetric.name) + apply() + } + sharedPreferences.edit { + putString(INACTIVITY_TIMER_ENUM, defaultInactivityMetric.name) + apply() + } + } + + fun setInactivityTimer(duration: Duration) { + val (value, enum) = "$duration".durationEnumPair() + sharedPreferences.edit { + putInt(INACTIVITY_TIMER_VALUE, value.toInt()) + apply() + } + sharedPreferences.edit { + putString(INACTIVITY_TIMER_ENUM, enum.name) + apply() + } + } + + fun setPauseTimer(duration: Duration) { + val (value, enum) = "$duration".durationEnumPair() + sharedPreferences.edit().apply { + putInt(PAUSE_TIMER_VALUE, value.toInt()) + apply() + } + sharedPreferences.edit().apply { + putString(PAUSE_TIMER_ENUM, enum.name) + apply() + } + } + + fun getInactivityTimeout(): Duration? { + val enum = sharedPreferences.getString(INACTIVITY_TIMER_ENUM, null) + val value = sharedPreferences.getInt(INACTIVITY_TIMER_VALUE, 0) + return (value to enum).toDuration() + } + + fun getPauseTimeout(): Duration? { + val enum = sharedPreferences.getString(PAUSE_TIMER_ENUM, null) + val value = sharedPreferences.getInt(PAUSE_TIMER_VALUE, 0) + return (value to enum).toDuration() + } + + companion object { + private fun String.durationEnumPair(): Pair { + val regex = Regex("(\\d+)([hms])") + val matchResults = regex.findAll(this) + var value = "" + var unit = DurationEnum.SECONDS + for (result in matchResults) { + value = result.groupValues[1] // Extract the numeric value + unit = DurationEnum.extractedUnit(result.groupValues[2]) // Extract the unit (h, m, or s) + } + return value to unit + } + + @OptIn(ExperimentalTime::class) + fun Pair.toDuration(): Duration? { + this.first?.let { nonNullValue -> + this.second?.let { nonNullEnum -> + val durationUnit = DurationUnit.valueOf(nonNullEnum) + return Duration.convert( + nonNullValue.toDouble(), + durationUnit, + durationUnit + ).toDuration(durationUnit) + } + } + return null + } + + /** + * Allowed enums on the debug screen + */ + enum class DurationEnum { + UNSPECIFIED, + SECONDS, + MINUTES, + HOURS; + + companion object { + fun extractedUnit(input: String) = + when (input) { + "h" -> HOURS + "m" -> MINUTES + "s" -> SECONDS + else -> UNSPECIFIED + } + } + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/di/TimeoutsSharedPrefsModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/di/TimeoutsSharedPrefsModule.kt new file mode 100644 index 00000000..c24b3595 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/di/TimeoutsSharedPrefsModule.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.di + +import android.content.Context +import android.content.SharedPreferences +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsScreenViewModel +import de.gematik.ti.erp.app.timeouts.presentation.DefaultTimeoutsScreenViewModel +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository +import de.gematik.ti.erp.app.timeouts.repository.DefaultTimeoutRepository +import de.gematik.ti.erp.app.timeouts.usecase.GetInactivityMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.GetPauseMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.SetInactivityMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.SetPauseMetricUseCase +import org.kodein.di.DI +import org.kodein.di.bindProvider +import org.kodein.di.bindSingleton +import org.kodein.di.instance + +private const val ENCRYPTED_PREFS_FILE_NAME = "Encrypted_shared_prefs" +private const val ENCRYPTED_PREFS_MASTER_KEY_ALIAS = "ENCRYPTED_PREFS_MASTER_KEY_ALIAS" + +private const val ENCRYPTED_SHARED_PREFS_TAG = "EncryptedSharedPrefsTag" + +val timeoutsSharedPrefsModule = DI.Module("sharedPrefsModule") { + bindSingleton { + val context = instance() + val masterKey = MasterKey.Builder(context, ENCRYPTED_PREFS_MASTER_KEY_ALIAS) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + masterKey + } + bindSingleton(ENCRYPTED_SHARED_PREFS_TAG) { + val context = instance() + val masterKey = instance() + + EncryptedSharedPreferences.create( + context, + ENCRYPTED_PREFS_FILE_NAME, + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + } + bindProvider { + val sharedPreferences = instance(ENCRYPTED_SHARED_PREFS_TAG) + TimeoutsLocalDataSource(sharedPreferences) + } + bindProvider { + DefaultTimeoutRepository(instance()).also { + // set the initial timeouts for the app + if (!it.areTimeoutsExisting()) { + it.setDefaultTimeouts() + } + } + } + bindProvider { GetInactivityMetricUseCase(instance()) } + bindProvider { GetPauseMetricUseCase(instance()) } + bindProvider { SetInactivityMetricUseCase(instance()) } + bindProvider { SetPauseMetricUseCase(instance()) } + bindProvider { + DefaultTimeoutsScreenViewModel(instance(), instance(), instance(), instance()) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/presentation/TimeoutsScreenViewModel.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/presentation/TimeoutsScreenViewModel.kt new file mode 100644 index 00000000..78e1a62f --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/presentation/TimeoutsScreenViewModel.kt @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.presentation + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultInactivityValue +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultPauseValue +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError.Error +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError.InactivityError +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError.NoError +import de.gematik.ti.erp.app.timeouts.presentation.TimeoutsError.PauseError +import de.gematik.ti.erp.app.timeouts.usecase.GetInactivityMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.GetPauseMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.SetInactivityMetricUseCase +import de.gematik.ti.erp.app.timeouts.usecase.SetPauseMetricUseCase +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlin.time.Duration + +abstract class TimeoutsScreenViewModel : ViewModel() { + + abstract val inactivityMetricDuration: StateFlow + abstract val pauseMetricDuration: StateFlow + + abstract val error: MutableSharedFlow + abstract suspend fun load() + + abstract fun emitNoError() + + open fun setInactivityMetric( + value: String, + unit: DurationEnum + ) { + viewModelScope.launch { load() } + emitNoError() + } + + open fun setPauseMetric( + value: String, + unit: DurationEnum + ) { + viewModelScope.launch { load() } + emitNoError() + } + + open fun resetToDefaultMetrics() { + viewModelScope.launch { load() } + emitNoError() + } +} + +enum class TimeoutsError { + InactivityError, PauseError, Error, NoError +} + +class DefaultTimeoutsScreenViewModel( + private val getInactivityMetricUseCase: GetInactivityMetricUseCase, + private val getPauseMetricUseCase: GetPauseMetricUseCase, + private val setInactivityMetricUseCase: SetInactivityMetricUseCase, + private val setPauseMetricUseCase: SetPauseMetricUseCase +) : TimeoutsScreenViewModel() { + + private val inactivityMetric = MutableStateFlow(Duration.ZERO) + + private val pauseMetric = MutableStateFlow(Duration.ZERO) + + init { + viewModelScope.launch { load() } + } + + override suspend fun load() { + inactivityMetric.value = getInactivityMetricUseCase() + pauseMetric.value = getPauseMetricUseCase() + } + + override val inactivityMetricDuration: StateFlow = inactivityMetric + override val pauseMetricDuration: StateFlow = pauseMetric + + override val error = MutableSharedFlow() + + override fun setInactivityMetric( + value: String, + unit: DurationEnum + ) { + runCatching { + setInactivityMetricUseCase.invoke(value = value, unit = unit) + }.fold( + onSuccess = { + // call super only in success + super.setInactivityMetric(value, unit) + }, + onFailure = { + error.tryEmit(InactivityError) + } + ) + } + + override fun setPauseMetric( + value: String, + unit: DurationEnum + ) { + runCatching { + setPauseMetricUseCase.invoke(value = value, unit = unit) + }.fold( + onSuccess = { + // call super only in success + super.setPauseMetric(value, unit) + }, + onFailure = { + error.tryEmit(PauseError) + } + ) + } + + override fun resetToDefaultMetrics() { + runCatching { + setInactivityMetricUseCase( + value = defaultInactivityValue.toString(), + unit = DurationEnum.MINUTES + ) + setPauseMetricUseCase( + value = defaultPauseValue.toString(), + unit = DurationEnum.SECONDS + ) + }.fold( + onSuccess = { + // call super only in success + super.resetToDefaultMetrics() + }, + onFailure = { + error.tryEmit(Error) + } + ) + } + + override fun emitNoError() { + error.tryEmit(NoError) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/repository/DefaultTimeoutRepository.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/repository/DefaultTimeoutRepository.kt new file mode 100644 index 00000000..d0e97903 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/repository/DefaultTimeoutRepository.kt @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.repository + +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultInactivityMetric +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultInactivityValue +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultPauseMetric +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutConstant.defaultPauseValue +import kotlin.time.Duration +import kotlin.time.toDuration + +class DefaultTimeoutRepository( + private val localDataSource: TimeoutsLocalDataSource +) : TimeoutRepository { + override fun setDefaultTimeouts() { + localDataSource.setDefaultTimeouts() + } + + override fun areTimeoutsExisting(): Boolean = + (localDataSource.getPauseTimeout() != null && localDataSource.getInactivityTimeout() != null) + + override fun changeInactivityTimeout(duration: Duration) { + localDataSource.setInactivityTimer(duration) + } + + override fun changePauseTimeout(duration: Duration) { + localDataSource.setPauseTimer(duration) + } + + override fun getInactivityTimeout(): Duration = + localDataSource.getInactivityTimeout() ?: defaultInactivityValue.toDuration(defaultInactivityMetric) + + override fun getPauseTimeout(): Duration = + localDataSource.getPauseTimeout() ?: defaultPauseValue.toDuration(defaultPauseMetric) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetInactivityMetricUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetInactivityMetricUseCase.kt new file mode 100644 index 00000000..0e6c5773 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetInactivityMetricUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.usecase + +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository + +class GetInactivityMetricUseCase( + private val repository: TimeoutRepository +) { + operator fun invoke() = repository.getInactivityTimeout() +} diff --git a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetPauseMetricUseCase.kt similarity index 73% rename from app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetPauseMetricUseCase.kt index 2bb62a48..d66ed2e3 100644 --- a/app/features/src/debug/kotlin/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/GetPauseMetricUseCase.kt @@ -16,12 +16,12 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.timeouts.usecase -import de.gematik.ti.erp.app.Route +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository -object DebugScreenNavigation { - object DebugMain : Route("DebugMain") - object DebugRedeemWithoutFD : Route("DebugRedeemWithoutFD") - object DebugPKV : Route("DebugPKV") +class GetPauseMetricUseCase( + private val repository: TimeoutRepository +) { + operator fun invoke() = repository.getPauseTimeout() } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetInactivityMetricUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetInactivityMetricUseCase.kt new file mode 100644 index 00000000..31c60b61 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetInactivityMetricUseCase.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.usecase + +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.toDuration +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository + +class SetInactivityMetricUseCase( + private val repository: TimeoutRepository +) { + operator fun invoke( + value: String, + unit: DurationEnum + ): Result = (value.toIntOrNull() to unit.name) + .toDuration()?.let { + repository.changeInactivityTimeout(duration = it) + Result.success(Unit) + } ?: run { + Result.failure(IllegalStateException("value cannot be set, unreal values")) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetPauseMetricUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetPauseMetricUseCase.kt new file mode 100644 index 00000000..b3b0d764 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/timeouts/usecase/SetPauseMetricUseCase.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.usecase + +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.DurationEnum +import de.gematik.ti.erp.app.timeouts.datasource.local.TimeoutsLocalDataSource.Companion.toDuration +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository + +class SetPauseMetricUseCase( + private val repository: TimeoutRepository +) { + operator fun invoke( + value: String, + unit: DurationEnum + ): Result = (value.toIntOrNull() to unit.name).toDuration()?.let { + repository.changePauseTimeout(duration = it) + Result.success(Unit) + } ?: run { + Result.failure(IllegalStateException("value cannot be set, unreal values")) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/troubleshooting/TroubleshootingContent.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/troubleshooting/TroubleshootingContent.kt index c4412049..c92ddd9f 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/troubleshooting/TroubleshootingContent.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/troubleshooting/TroubleshootingContent.kt @@ -56,10 +56,10 @@ import androidx.compose.ui.unit.dp import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController -import de.gematik.ti.erp.app.Route -import de.gematik.ti.erp.app.analytics.trackNavigationChanges +import de.gematik.ti.erp.app.analytics.trackNavigationChangesAsync import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.info.BuildConfigInformation +import de.gematik.ti.erp.app.navigation.Routes import de.gematik.ti.erp.app.settings.ui.buildFeedbackBodyWithDeviceInfo import de.gematik.ti.erp.app.settings.ui.openMailClient import de.gematik.ti.erp.app.theme.AppTheme @@ -79,10 +79,10 @@ import de.gematik.ti.erp.app.utils.compose.annotatedStringResource import org.kodein.di.compose.rememberInstance object TroubleShootingNavigation { - object TroubleshootingPageA : Route("troubleShooting") - object TroubleshootingPageB : Route("troubleShooting_readCardHelp1") - object TroubleshootingPageC : Route("troubleShooting_readCardHelp2") - object TroubleshootingNoSuccessPage : Route("troubleShooting_readCardHelp3") + object TroubleshootingPageA : Routes("troubleShooting") + object TroubleshootingPageB : Routes("troubleShooting_readCardHelp1") + object TroubleshootingPageC : Routes("troubleShooting_readCardHelp2") + object TroubleshootingNoSuccessPage : Routes("troubleShooting_readCardHelp3") } @Composable @@ -93,7 +93,7 @@ fun TroubleShootingScreen( val navController = rememberNavController() val buildConfig by rememberInstance() var previousNavEntry by remember { mutableStateOf("troubleShooting") } - trackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) + trackNavigationChangesAsync(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) NavHost( navController, startDestination = TroubleShootingNavigation.TroubleshootingPageA.path() diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/BiometricPromptBuilder.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/BiometricPromptBuilder.kt new file mode 100644 index 00000000..7791170a --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/BiometricPromptBuilder.kt @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.userauthentication.observer + +import androidx.appcompat.app.AppCompatActivity +import androidx.biometric.BiometricManager +import androidx.biometric.BiometricPrompt +import androidx.core.content.ContextCompat +import de.gematik.ti.erp.app.Requirement +import io.github.aakira.napier.Napier + +@Requirement( + "A_21584", + sourceSpecification = "gemSpec_IDP_Frontend", + rationale = "Only biometric means provided by the operating system are used." +) +open class BiometricPromptBuilder(val activity: AppCompatActivity) { + private val executor = ContextCompat.getMainExecutor(activity) + private val biometricManager = BiometricManager.from(activity) + private val authenticators = fetchAuthenticators(biometricManager) + + private fun authenticationCallback( + onSuccess: () -> Unit, + onFailure: () -> Unit, + onError: () -> Unit + ): BiometricPrompt.AuthenticationCallback = object : BiometricPrompt.AuthenticationCallback() { + override fun onAuthenticationFailed() { + super.onAuthenticationFailed() + Napier.i( + tag = "BiometricPrompt", + message = "authentication failed" + ) + onFailure() + } + + override fun onAuthenticationError(errorCode: Int, errString: CharSequence) { + super.onAuthenticationError(errorCode, errString) + Napier.i( + tag = "BiometricPrompt", + message = "authentication error $errString" + ) + onError() + } + + override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) { + super.onAuthenticationSucceeded(result) + Napier.i( + tag = "BiometricPrompt", + message = "authentication success $result" + ) + onSuccess() + } + } + + fun buildPromptInfo( + title: String, + description: String = "", + negativeButton: String + ): BiometricPrompt.PromptInfo = BiometricPrompt.PromptInfo.Builder() + .setTitle(title) + .setDescription(description) + .apply { + if ((authenticators and BiometricManager.Authenticators.DEVICE_CREDENTIAL) == 0) { + setNegativeButtonText(negativeButton) + } + }.setAllowedAuthenticators(authenticators) + .build() + + fun buildBiometricPrompt( + onSuccess: () -> Unit, + onFailure: () -> Unit, + onError: () -> Unit + ): BiometricPrompt = BiometricPrompt(activity, executor, authenticationCallback(onSuccess, onFailure, onError)) + + @Requirement( + "A_21582", + sourceSpecification = "gemSpec_IDP_Frontend", + rationale = "Selection of the best available authentication option on the device." + ) + @Suppress("ReturnCount") + private fun fetchAuthenticators(biometricManager: BiometricManager): Int { + if (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == + BiometricManager.BIOMETRIC_SUCCESS || + biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) == + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED + ) { + return BiometricManager.Authenticators.BIOMETRIC_STRONG + } + + if (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == + BiometricManager.BIOMETRIC_SUCCESS || + biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_WEAK) == + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED + ) { + return BiometricManager.Authenticators.BIOMETRIC_WEAK + } + if (biometricManager.canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == + BiometricManager.BIOMETRIC_SUCCESS || + biometricManager.canAuthenticate(BiometricManager.Authenticators.DEVICE_CREDENTIAL) == + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED + ) { + return BiometricManager.Authenticators.DEVICE_CREDENTIAL + } + + return if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.R) { + BiometricManager.Authenticators.DEVICE_CREDENTIAL or BiometricManager.Authenticators.BIOMETRIC_WEAK + } else { + BiometricManager.Authenticators.DEVICE_CREDENTIAL + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/InactivityTimeoutObserver.kt similarity index 72% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/InactivityTimeoutObserver.kt index caf285f9..2d66d744 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/InactivityTimeoutObserver.kt @@ -16,16 +16,16 @@ * */ -package de.gematik.ti.erp.app.userauthentication.ui +package de.gematik.ti.erp.app.userauthentication.observer import androidx.compose.runtime.Stable import androidx.lifecycle.Lifecycle.Event import androidx.lifecycle.Lifecycle.Event.ON_CREATE import androidx.lifecycle.Lifecycle.Event.ON_START -import androidx.lifecycle.Lifecycle.Event.ON_STOP import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner import de.gematik.ti.erp.app.Requirement +import de.gematik.ti.erp.app.timeouts.repository.TimeoutRepository import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.model.SettingsData.AuthenticationMode.Password import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase @@ -33,10 +33,9 @@ import io.github.aakira.napier.Napier import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.trySendBlocking import kotlinx.coroutines.delay import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.channelFlow @@ -47,22 +46,19 @@ import kotlinx.coroutines.flow.filter import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.receiveAsFlow import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.launch import java.time.Duration @Stable sealed class AuthenticationModeAndMethod { - object None : AuthenticationModeAndMethod() - object Authenticated : AuthenticationModeAndMethod() + data object None : AuthenticationModeAndMethod() + data object Authenticated : AuthenticationModeAndMethod() data class AuthenticationRequired(val method: SettingsData.AuthenticationMode, val nrOfFailedAuthentications: Int) : AuthenticationModeAndMethod() } -private val InactivityTimeout = Duration.ofMinutes(10) -private val PauseTimeout = Duration.ofSeconds(30) -private const val ResetTimeout = -1L +private const val RESET_TIMEOUT = -1L // tag::AuthenticationUseCase[] @Requirement( @@ -70,9 +66,10 @@ private const val ResetTimeout = -1L sourceSpecification = "BSI-eRp-ePA", rationale = "A Timer is used to measure the time a user is inactive. Every user interaction resets the timer." ) -class AuthenticationUseCase( +class InactivityTimeoutObserver( private val settingsUseCase: SettingsUseCase, - dispatcher: CoroutineDispatcher = Dispatchers.IO + private val timeoutRepo: TimeoutRepository, + dispatcher: CoroutineDispatcher = Dispatchers.Default ) : LifecycleEventObserver { private enum class Lifecycle { Created, Started, Running, Paused @@ -82,7 +79,9 @@ class AuthenticationUseCase( private val authRequired = MutableStateFlow(false) private val lifecycle = MutableStateFlow(Lifecycle.Created) - private val timerChannel = Channel(Channel.CONFLATED) + + // Replay is required so that it keeps a buffer if the app goes in the background + private val inactivityTimerChannel = MutableSharedFlow(replay = 1) private var unspecifiedAuthentication = false @@ -97,14 +96,14 @@ class AuthenticationUseCase( when (lifecycle) { Lifecycle.Created -> { - this@AuthenticationUseCase.authRequired.value = when (authenticationMode) { + this@InactivityTimeoutObserver.authRequired.value = when (authenticationMode) { SettingsData.AuthenticationMode.Unspecified -> false else -> true } - this@AuthenticationUseCase.lifecycle.value = Lifecycle.Running + this@InactivityTimeoutObserver.lifecycle.value = Lifecycle.Running } Lifecycle.Started -> { - this@AuthenticationUseCase.lifecycle.value = Lifecycle.Running + this@InactivityTimeoutObserver.lifecycle.value = Lifecycle.Running } Lifecycle.Running -> { when (authenticationMode) { @@ -129,38 +128,33 @@ class AuthenticationUseCase( val authenticationModeAndMethod: Flow = channelFlow { launch { - var currentTimeout: Long = ResetTimeout - timerChannel - .receiveAsFlow() + var currentTimeout: Long = RESET_TIMEOUT + inactivityTimerChannel .filter { timeout -> currentTimeout <= 0 || timeout <= currentTimeout } .collectLatest { timeout -> currentTimeout = timeout if (timeout > 0) { - Napier.d { "Restarted inactivity timer for ${Duration.ofMillis(timeout)}" } + Napier.i { "Restarted inactivity timer for ${Duration.ofMillis(timeout)}" } delay(timeout) requireAuthentication() - currentTimeout = ResetTimeout + currentTimeout = RESET_TIMEOUT } else { - timerChannel.send(InactivityTimeout.toMillis()) + inactivityTimerChannel.tryEmit(timeoutRepo.getInactivityTimeout().inWholeMilliseconds) } } } - Napier.d { "Started authentication flow" } - authenticationFlow() .collect { if (it == AuthenticationModeAndMethod.Authenticated) { - timerChannel.send(InactivityTimeout.toMillis()) + inactivityTimerChannel.tryEmit(timeoutRepo.getInactivityTimeout().inWholeMilliseconds) } - - Napier.d { "Current authentication mode $it" } - send(it) } }.flowOn(dispatcher) + // need replay for buffer .shareIn(scope = scope, started = SharingStarted.Lazily, replay = 1) // end::AuthenticationUseCase[] @@ -170,7 +164,7 @@ class AuthenticationUseCase( }.first() fun resetInactivityTimer() { - timerChannel.trySendBlocking(InactivityTimeout.toMillis()) + inactivityTimerChannel.tryEmit(timeoutRepo.getInactivityTimeout().inWholeMilliseconds) } fun authenticated() { @@ -179,16 +173,17 @@ class AuthenticationUseCase( private fun requireAuthentication() { if (!unspecifiedAuthentication) { + Napier.i { "Authentication required" } authRequired.value = true - Napier.d { "Authentication required" } } } - private fun requireAuthentication(inMillis: Long) { - val result = timerChannel.trySendBlocking(inMillis) - if (result.isFailure) { - requireAuthentication() - } + /** + * This [forceRequireAuthentication] is called when the pause timeout has run + */ + fun forceRequireAuthentication() { + Napier.i { "Authentication required" } + authRequired.value = true } suspend fun incrementNumberOfAuthenticationFailures() = @@ -197,29 +192,19 @@ class AuthenticationUseCase( suspend fun resetNumberOfAuthenticationFailures() = settingsUseCase.resetNumberOfAuthenticationFailures() - @Requirement( - "O.Auth_7", - "O.Plat_12", - sourceSpecification = "BSI-eRp-ePA", - rationale = "The LifeCicleState of the app is monitored. If the app stopped, the authentication " + - "process starts after a delay of 30 seconds. We opted for this delay for usability reasons, " + - "as selecting the profile picture and external authentication requires pausing the app." - ) override fun onStateChanged(source: LifecycleOwner, event: Event) { - Napier.d { "Authentication lifecycle event state: $event" } + Napier.i { "Application lifecycle event state: $event" } when (event) { ON_CREATE -> lifecycle.value = Lifecycle.Created ON_START -> { if (lifecycle.value != Lifecycle.Created) { lifecycle.value = Lifecycle.Started } - timerChannel.trySendBlocking(ResetTimeout) + inactivityTimerChannel.tryEmit(RESET_TIMEOUT) } - ON_STOP -> { - lifecycle.value = Lifecycle.Paused - requireAuthentication(PauseTimeout.toMillis()) + else -> { + // Pause timeout is being handled in the [BaseActivity] } - else -> {} } } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/ProcessLifecycleObserver.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/ProcessLifecycleObserver.kt new file mode 100644 index 00000000..c5a71b98 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/observer/ProcessLifecycleObserver.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.userauthentication.observer + +import androidx.lifecycle.ProcessLifecycleOwner + +/** + * [ProcessLifecycleObserver] is a singleton class that oversees the processes that are observing the app lifecycle + */ +class ProcessLifecycleObserver( + private val processLifecycleOwner: ProcessLifecycleOwner.Companion, + private val inactivityTimeoutObserver: InactivityTimeoutObserver +) { + fun observeForInactivity() { + processLifecycleOwner.get().lifecycle.apply { + addObserver(inactivityTimeoutObserver) + } + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPromptWrapper.kt similarity index 90% rename from app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt rename to app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPromptWrapper.kt index 6a81e642..a695687a 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/BiometricPromptWrapper.kt @@ -15,9 +15,11 @@ * limitations under the Licence. * */ +@file:Suppress("ReturnCount") package de.gematik.ti.erp.app.userauthentication.ui +import androidx.appcompat.app.AppCompatActivity import androidx.biometric.BiometricManager import androidx.biometric.BiometricPrompt import androidx.compose.runtime.Composable @@ -25,7 +27,6 @@ import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.remember import androidx.compose.ui.platform.LocalContext import androidx.core.content.ContextCompat -import androidx.fragment.app.FragmentActivity import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.utils.compose.shortToast @@ -38,7 +39,7 @@ import de.gematik.ti.erp.app.utils.compose.shortToast rationale = "Only biometric means provided by the operating system are used." ) @Composable -fun BiometricPrompt( +fun BiometricPromptWrapper( title: String, description: String, negativeButton: String, @@ -47,10 +48,10 @@ fun BiometricPrompt( onAuthenticationError: () -> Unit, onAuthenticationSoftError: () -> Unit ) { - val activity = LocalActivity.current as FragmentActivity + val activity = LocalActivity.current as? AppCompatActivity val context = LocalContext.current - val executor = remember { ContextCompat.getMainExecutor(activity) } + val executor = remember { ContextCompat.getMainExecutor(context) } val biometricManager = remember { BiometricManager.from(context) } val callback = remember { @@ -98,19 +99,16 @@ fun BiometricPrompt( if ((secureOption and BiometricManager.Authenticators.DEVICE_CREDENTIAL) == 0) { setNegativeButtonText(negativeButton) } - }.setAllowedAuthenticators( - secureOption - ) + }.setAllowedAuthenticators(secureOption) .build() } - val biometricPrompt = remember { BiometricPrompt(activity, executor, callback) } + val biometricPrompt = activity?.let { BiometricPrompt(it, executor, callback) } DisposableEffect(biometricPrompt) { - biometricPrompt.authenticate(promptInfo) - + biometricPrompt?.authenticate(promptInfo) onDispose { - biometricPrompt.cancelAuthentication() + biometricPrompt?.cancelAuthentication() } } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt index 296298fc..9c1e88f4 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt @@ -20,49 +20,54 @@ package de.gematik.ti.erp.app.userauthentication.ui import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember -import androidx.lifecycle.compose.collectAsStateWithLifecycle import de.gematik.ti.erp.app.settings.model.SettingsData +import de.gematik.ti.erp.app.userauthentication.observer.AuthenticationModeAndMethod +import de.gematik.ti.erp.app.userauthentication.observer.InactivityTimeoutObserver +import de.gematik.ti.erp.app.userauthentication.ui.AuthenticationStateData.AuthenticationState import kotlinx.coroutines.flow.map import org.kodein.di.compose.rememberInstance class AuthenticationController( - private val authUseCase: AuthenticationUseCase + private val inactivityTimeoutObserver: InactivityTimeoutObserver ) { private val authenticationFlow = - authUseCase.authenticationModeAndMethod.map { - when (it) { - AuthenticationModeAndMethod.None, - AuthenticationModeAndMethod.Authenticated -> AuthenticationStateData.AuthenticationState( - SettingsData.AuthenticationMode.Unspecified, - 0 - ) - is AuthenticationModeAndMethod.AuthenticationRequired -> AuthenticationStateData.AuthenticationState( - it.method, - it.nrOfFailedAuthentications - ) + inactivityTimeoutObserver.authenticationModeAndMethod + .map { + when (it) { + AuthenticationModeAndMethod.None, + AuthenticationModeAndMethod.Authenticated -> AuthenticationState( + SettingsData.AuthenticationMode.Unspecified, + 0 + ) + + is AuthenticationModeAndMethod.AuthenticationRequired -> AuthenticationState( + it.method, + it.nrOfFailedAuthentications + ) + } } - } val authenticationState @Composable - get() = authenticationFlow.collectAsStateWithLifecycle(AuthenticationStateData.defaultAuthenticationState) + get() = authenticationFlow.collectAsState(AuthenticationStateData.defaultAuthenticationState) suspend fun isPasswordValid(password: String): Boolean = - authUseCase.isPasswordValid(password) + inactivityTimeoutObserver.isPasswordValid(password) suspend fun onAuthenticated() { - authUseCase.resetNumberOfAuthenticationFailures() - authUseCase.authenticated() + inactivityTimeoutObserver.resetNumberOfAuthenticationFailures() + inactivityTimeoutObserver.authenticated() } - suspend fun onFailedAuthentication() = authUseCase.incrementNumberOfAuthenticationFailures() + suspend fun onFailedAuthentication() = inactivityTimeoutObserver.incrementNumberOfAuthenticationFailures() } @Composable fun rememberAuthenticationController(): AuthenticationController { - val authenticationUseCase by rememberInstance() - return remember { AuthenticationController(authenticationUseCase) } + val inactivityTimeoutObserver by rememberInstance() + return remember { AuthenticationController(inactivityTimeoutObserver) } } object AuthenticationStateData { diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt index 5f1872ee..c0231bf1 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.userauthentication.ui +import androidx.appcompat.app.AppCompatActivity import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Column @@ -64,13 +65,19 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.features.BuildConfig import de.gematik.ti.erp.app.features.R import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.ui.PasswordTextField import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.theme.PaddingDefaults.Medium +import de.gematik.ti.erp.app.userauthentication.observer.BiometricPromptBuilder import de.gematik.ti.erp.app.utils.compose.AlertDialog import de.gematik.ti.erp.app.utils.compose.ClickableTaggedText import de.gematik.ti.erp.app.utils.compose.HintCard @@ -87,23 +94,60 @@ import de.gematik.ti.erp.app.utils.compose.annotatedPluralsResource import de.gematik.ti.erp.app.utils.compose.annotatedStringResource import kotlinx.coroutines.launch import java.util.Locale + @Suppress("LongMethod") @Composable fun UserAuthenticationScreen() { - val authentication = rememberAuthenticationController() + val activity = LocalActivity.current + + val biometricPromptBuilder = remember { BiometricPromptBuilder(activity as AppCompatActivity) } + + // clear underlying text input focus + val focusManager = LocalFocusManager.current val scope = rememberCoroutineScope() + + val authentication = rememberAuthenticationController() + val authenticationState by authentication.authenticationState + val navBarInsetsPadding = WindowInsets.systemBars.asPaddingValues() + var showAuthPrompt by remember { mutableStateOf(false) } var showError by remember { mutableStateOf(false) } var initiallyHandledAuthPrompt by rememberSaveable { mutableStateOf(false) } - val authenticationState by authentication.authenticationState - val navBarInsetsPadding = WindowInsets.systemBars.asPaddingValues() - val paddingModifier = if (navBarInsetsPadding.calculateBottomPadding() <= PaddingDefaults.Medium) { - Modifier.statusBarsPadding() - } else { - Modifier.systemBarsPadding() + + val infoBuilder = biometricPromptBuilder.buildPromptInfo( + title = stringResource(R.string.auth_prompt_headline), + negativeButton = stringResource(R.string.auth_prompt_cancel) + ) + + val prompt = remember(biometricPromptBuilder) { + biometricPromptBuilder.buildBiometricPrompt( + onSuccess = { + scope.launch { authentication.onAuthenticated() } + showAuthPrompt = false + }, + onFailure = { + showAuthPrompt = false + }, + onError = { + scope.launch { authentication.onFailedAuthentication() } + showAuthPrompt = false + showError = true + } + ) } - // clear underlying text input focus - val focusManager = LocalFocusManager.current + + LaunchedEffect(showAuthPrompt) { + activity.lifecycleScope.launch { + activity.lifecycle.repeatOnLifecycle(Lifecycle.State.RESUMED) { + if (authenticationState.authenticationMethod !is SettingsData.AuthenticationMode.Password && + showAuthPrompt + ) { + prompt.authenticate(infoBuilder) + } + } + } + } + LaunchedEffect(Unit) { focusManager.clearFocus(true) if (!initiallyHandledAuthPrompt && authenticationState.nrOfAuthFailures == 0) { @@ -118,12 +162,17 @@ fun UserAuthenticationScreen() { .padding(it) .fillMaxSize() .verticalScroll(rememberScrollState()) - .then(paddingModifier) + .then( + when { + navBarInsetsPadding.calculateBottomPadding() <= Medium -> Modifier.statusBarsPadding() + else -> Modifier.systemBarsPadding() + } + ) ) { Row( modifier = Modifier - .padding(top = PaddingDefaults.Medium) - .padding(horizontal = PaddingDefaults.Medium) + .padding(top = Medium) + .padding(horizontal = Medium) .align(Alignment.Start), verticalAlignment = Alignment.CenterVertically ) { @@ -160,53 +209,29 @@ fun UserAuthenticationScreen() { null, modifier = Modifier .fillMaxWidth() - .padding(horizontal = PaddingDefaults.Medium), + .padding(horizontal = Medium), contentScale = ContentScale.FillWidth ) } } } - if (showAuthPrompt) { - when (authenticationState.authenticationMethod) { - is SettingsData.AuthenticationMode.Password -> - PasswordPrompt( - authentication, - onAuthenticated = { - showAuthPrompt = false - scope.launch { authentication.onAuthenticated() } - }, - onCancel = { - showAuthPrompt = false - }, - onAuthenticationError = { - scope.launch { authentication.onFailedAuthentication() } - showAuthPrompt = false - showError = true - } - ) - else -> - BiometricPrompt( - title = stringResource(R.string.auth_prompt_headline), - description = "", - negativeButton = stringResource(R.string.auth_prompt_cancel), - onAuthenticated = { - showAuthPrompt = false - scope.launch { authentication.onAuthenticated() } - }, - onCancel = { - showAuthPrompt = false - }, - onAuthenticationError = { - scope.launch { authentication.onFailedAuthentication() } - showAuthPrompt = false - showError = true - }, - onAuthenticationSoftError = { - scope.launch { authentication.onFailedAuthentication() } - } - ) - } + if (showAuthPrompt && authenticationState.authenticationMethod is SettingsData.AuthenticationMode.Password) { + PasswordPrompt( + authentication, + onAuthenticated = { + showAuthPrompt = false + scope.launch { authentication.onAuthenticated() } + }, + onCancel = { + showAuthPrompt = false + }, + onAuthenticationError = { + scope.launch { authentication.onFailedAuthentication() } + showAuthPrompt = false + showError = true + } + ) } } @@ -217,7 +242,7 @@ private fun AuthenticationScreenErrorContent( Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = PaddingDefaults.Medium), + .padding(horizontal = Medium), horizontalAlignment = Alignment.CenterHorizontally ) { Spacer(modifier = Modifier.height(80.dp)) @@ -263,9 +288,9 @@ private fun AuthenticationScreenErrorBottomContent(state: AuthenticationStateDat .background(color = AppTheme.colors.neutral100) .padding( bottom = PaddingDefaults.Large, - start = PaddingDefaults.Medium, - end = PaddingDefaults.Medium, - top = PaddingDefaults.Medium + start = Medium, + end = Medium, + top = Medium ) .fillMaxWidth() ) { @@ -301,12 +326,12 @@ private fun AuthenticationScreenContent( Column( modifier = Modifier .fillMaxWidth() - .padding(horizontal = PaddingDefaults.Medium), + .padding(horizontal = Medium), horizontalAlignment = Alignment.CenterHorizontally ) { if (state.nrOfAuthFailures > 0) { HintCard( - modifier = Modifier.padding(vertical = PaddingDefaults.Medium), + modifier = Modifier.padding(vertical = Medium), properties = HintCardDefaults.flatProperties( backgroundColor = AppTheme.colors.red100 ), diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ClickableText.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ClickableText.kt index e4899d16..0ba09bd4 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ClickableText.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ClickableText.kt @@ -52,8 +52,13 @@ fun ClickableText( val resources = LocalContext.current.resources val textData = remember(clickText, text, resources) { - val regex = Regex(clickText.text) - val splits = text.splitToSequence(regex).toMutableList() + val spacingDelimiter = " " + val regex = Regex(clickText.text.lowercase()) + val splits = text + .split(spacingDelimiter) + .joinToString(spacingDelimiter) + .splitToSequence(regex) + .toMutableList() // add the delimiter also to the list splits.add(1, clickText.text) mutableListOf().apply { @@ -61,7 +66,7 @@ fun ClickableText( if (part == clickText.text) { add( TextData( - text = clickText.text, + text = " ${clickText.text} ", tag = "$clickText-link-text-tag", onClick = { clickText.onClick() } ) diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ComposeTags.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ComposeTags.kt new file mode 100644 index 00000000..f8606c52 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ComposeTags.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +/** + * Tag used for the component [ErrorText] + */ +const val ErrorTextTag = "error-text" diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/EditableHeaderText.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/EditableHeaderText.kt index 1b7b1555..9d20d743 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/EditableHeaderText.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/EditableHeaderText.kt @@ -18,7 +18,9 @@ package de.gematik.ti.erp.app.utils.compose +import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.wrapContentWidth @@ -45,8 +47,10 @@ import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalSoftwareKeyboardController +import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import de.gematik.ti.erp.app.features.R @@ -62,13 +66,13 @@ fun EditableHeaderTextField( onSaveText: (String) -> Unit ) { var isEditing by remember { mutableStateOf(false) } - - var name by remember { - mutableStateOf(text) - } + var name by remember { mutableStateOf(text) } if (isEditing) { - EditableTextField(text, textMinLength) { + EditableTextField( + text = text, + textMinLength = textMinLength + ) { onSaveText(it) isEditing = false name = it @@ -112,60 +116,54 @@ private fun EditIconButton( @OptIn(ExperimentalComposeUiApi::class) @Composable -private fun EditableTextField( +fun EditableTextField( + modifier: Modifier = Modifier, text: String, textMinLength: Int, - onSaveText: (String) -> Unit + onDoneClicked: (String) -> Unit ) { - var name by remember { - mutableStateOf(text) - } + var name by remember { mutableStateOf(TextFieldValue(text)) } val focusManager = LocalFocusManager.current val focusRequester = remember { FocusRequester() } val keyboardController = LocalSoftwareKeyboardController.current var isError by remember { mutableStateOf(false) } - val keyboardOption = KeyboardOptions.Default.copy( - imeAction = ImeAction.Done - ) - - val keyboardActionsDone = KeyboardActions( - onDone = { - if (!isError) { - focusManager.clearFocus() - keyboardController?.hide() - onSaveText(name.trim()) - } - } - ) - LaunchedEffect(Unit) { focusRequester.requestFocus() } - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceEvenly, - verticalAlignment = Alignment.CenterVertically + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally ) { TextField( - modifier = Modifier.wrapContentWidth().focusRequester(focusRequester), + modifier = Modifier.focusRequester(focusRequester), colors = basicTextFieldColors, textStyle = AppTheme.typography.h5.copy(textAlign = TextAlign.Center), - keyboardOptions = keyboardOption, + keyboardOptions = KeyboardOptions.Default.copy(imeAction = ImeAction.Done), isError = isError, - label = { - if (isError) { - Text(stringResource(R.string.empty_scanned_prescription_name)) - } - }, value = name, - keyboardActions = keyboardActionsDone, onValueChange = { - name = it.trimStart() - isError = name.length < textMinLength - } + name = it + isError = name.text.length < textMinLength + }, + keyboardActions = KeyboardActions( + onDone = { + if (!isError) { + focusManager.clearFocus() + keyboardController?.hide() + onDoneClicked(name.text.trim()) + } + } + ) ) + AnimatedVisibility(isError) { + SpacerTiny() + ErrorText( + modifier = Modifier.testTag(ErrorTextTag), + text = stringResource(R.string.empty_scanned_prescription_name) + ) + } } } diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ErrorText.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ErrorText.kt new file mode 100644 index 00000000..c669e5ae --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/ErrorText.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import de.gematik.ti.erp.app.theme.AppTheme + +@Composable +fun ErrorText( + modifier: Modifier = Modifier, + text: String +) { + Text( + modifier = modifier, + text = text, + color = AppTheme.colors.red600, + style = AppTheme.typography.caption1 + ) +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/Toggle.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/Toggle.kt new file mode 100644 index 00000000..ee4a8eb1 --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/compose/Toggle.kt @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.selection.toggleable +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Switch +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults + +@Composable +fun Toggle( + modifier: Modifier = Modifier, + checked: Boolean, + onCheckedChange: (Boolean) -> Unit, + description: String +) { + Row( + modifier = modifier + .clip(RoundedCornerShape(16.dp)) + .toggleable( + value = checked, + onValueChange = onCheckedChange, + role = Role.Switch, + interactionSource = remember { MutableInteractionSource() }, + indication = LocalIndication.current + ) + .background(color = AppTheme.colors.neutral100, shape = RoundedCornerShape(16.dp)) + .fillMaxWidth() + .padding(PaddingDefaults.Medium) + .semantics(true) {}, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + description, + style = AppTheme.typography.subtitle1, + modifier = Modifier.weight(1f) + ) + SpacerSmall() + Switch( + checked = checked, + onCheckedChange = null + ) + } +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/DialogScaffold.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/DialogScaffold.kt new file mode 100644 index 00000000..0ede4fae --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/DialogScaffold.kt @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.extensions + +import android.app.Dialog +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +interface DialogScaffold { + fun show(content: @Composable (Dialog) -> Unit) +} + +val LocalDialog: DialogScaffoldCompositionLocal = DialogScaffoldCompositionLocal + +object DialogScaffoldCompositionLocal { + val current: DialogScaffold + @Composable + get() = LocalContext.current as DialogScaffold +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/SnackbarScaffold.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/SnackbarScaffold.kt new file mode 100644 index 00000000..d992be7f --- /dev/null +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/utils/extensions/SnackbarScaffold.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.extensions + +import androidx.annotation.ColorRes +import androidx.annotation.DrawableRes +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import de.gematik.ti.erp.app.features.R + +interface SnackbarScaffold { + fun show( + text: String, + @DrawableRes icon: Int = R.drawable.ic_logo_outlined, + @ColorRes backgroundTint: Int = R.color.primary_600 + ) +} + +val LocalSnackbar: SnackbarScaffoldCompositionLocal = SnackbarScaffoldCompositionLocal + +object SnackbarScaffoldCompositionLocal { + val current: SnackbarScaffold + @Composable + get() = LocalContext.current as SnackbarScaffold +} diff --git a/app/features/src/main/kotlin/de/gematik/ti/erp/app/vau/VauModule.kt b/app/features/src/main/kotlin/de/gematik/ti/erp/app/vau/VauModule.kt index 464e8d32..e4e54c83 100644 --- a/app/features/src/main/kotlin/de/gematik/ti/erp/app/vau/VauModule.kt +++ b/app/features/src/main/kotlin/de/gematik/ti/erp/app/vau/VauModule.kt @@ -61,11 +61,12 @@ val vauModule = DI.Module("vauModule") { } bindSingleton { { Clock.System.now() } } bindSingleton { - { untrustedOCSPList: UntrustedOCSPList, - untrustedCertList: UntrustedCertList, - trustAnchor: X509CertificateHolder, - ocspResponseMaxAge: Duration, - timestamp: Instant -> + { + untrustedOCSPList: UntrustedOCSPList, + untrustedCertList: UntrustedCertList, + trustAnchor: X509CertificateHolder, + ocspResponseMaxAge: Duration, + timestamp: Instant -> TrustedTruststore.create( untrustedOCSPList = untrustedOCSPList, untrustedCertList = untrustedCertList, diff --git a/app/features/src/main/res/drawable/ic_finger.xml b/app/features/src/main/res/drawable/ic_finger.xml new file mode 100644 index 00000000..e7bac20f --- /dev/null +++ b/app/features/src/main/res/drawable/ic_finger.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/features/src/main/res/drawable/ic_log_mail.xml b/app/features/src/main/res/drawable/ic_log_mail.xml new file mode 100644 index 00000000..fa1711ff --- /dev/null +++ b/app/features/src/main/res/drawable/ic_log_mail.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/features/src/main/res/drawable/ic_pkv.xml b/app/features/src/main/res/drawable/ic_pkv.xml new file mode 100644 index 00000000..fc1aee03 --- /dev/null +++ b/app/features/src/main/res/drawable/ic_pkv.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/features/src/main/res/drawable/ic_prescription_refresh.xml b/app/features/src/main/res/drawable/ic_prescription_refresh.xml new file mode 100644 index 00000000..efb56b84 --- /dev/null +++ b/app/features/src/main/res/drawable/ic_prescription_refresh.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/features/src/main/res/drawable/ic_qr_code.xml b/app/features/src/main/res/drawable/ic_qr_code.xml new file mode 100644 index 00000000..6d5ebdfb --- /dev/null +++ b/app/features/src/main/res/drawable/ic_qr_code.xml @@ -0,0 +1,10 @@ + + + \ No newline at end of file diff --git a/app/features/src/main/res/drawable/ic_reset.xml b/app/features/src/main/res/drawable/ic_reset.xml new file mode 100644 index 00000000..edbd1145 --- /dev/null +++ b/app/features/src/main/res/drawable/ic_reset.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/features/src/main/res/raw/health_insurance_contacts.json b/app/features/src/main/res/raw/health_insurance_contacts.json index 755c8fbf..d4dd5942 100644 --- a/app/features/src/main/res/raw/health_insurance_contacts.json +++ b/app/features/src/main/res/raw/health_insurance_contacts.json @@ -22,7 +22,7 @@ "bodyPinMail": null }, { - "name": "AOK Bremen", + "name": "AOK Bremen/Bremerhaven", "healthCardAndPinPhone": "+4942117610", "healthCardAndPinMail": "info@hb.aok.de", "healthCardAndPinUrl": "https://www.aok.de/pk/bremen/inhalt/elektronische-gesundheitskarte-3/", @@ -32,17 +32,6 @@ "subjectPinMail": "#PIN# Bestellung einer PIN zur Gesundheitskarte", "bodyPinMail": "Sehr geehrte Damen und Herren,\nich möchte die E-Rezept-App der gematik nutzen.\n\nIch benötige zu der Gesundheitskarte die PIN. Bitte senden Sie mir Informationen zu, wie ich die PIN erhalten kann.\n\nMit freundlichen Grüßen\nIhr Versicherter/ Ihre Versicherte" }, - { - "name": "AOK Bremerhaven", - "healthCardAndPinPhone": "+49471160", - "healthCardAndPinMail": "info@hb.aok.de", - "healthCardAndPinUrl": "https://www.aok.de/pk/bremen/inhalt/elektronische-gesundheitskarte-3/", - "pinUrl": null, - "subjectCardAndPinMail": "#eGKPIN# Bestellung einer NFC-fähigen Gesundheitskarte und PIN", - "bodyCardAndPinMail": "Sehr geehrte Damen und Herren,\nich möchte die E-Rezept-App der gematik nutzen.\n\nBitte senden Sie mir hierfür eine NFC-fähige Gesundheitskarte zu. Ich benötige zu der Gesundheitskarte auch die PIN. Bitte senden Sie mir Informationen zu, wie ich die PIN erhalten kann.\n\nMit freundlichen Grüßen\nIhr Versicherter/ Ihre Versicherte", - "subjectPinMail": "#PIN# Bestellung einer PIN zur Gesundheitskarte", - "bodyPinMail": "Sehr geehrte Damen und Herren,\nich möchte die E-Rezept-App der gematik nutzen.\n\nIch benötige zu der Gesundheitskarte die PIN. Bitte senden Sie mir Informationen zu, wie ich die PIN erhalten kann.\n\nMit freundlichen Grüßen\nIhr Versicherter/ Ihre Versicherte" - }, { "name": "AOK - Die Gesundheitskasse Hessen", "healthCardAndPinPhone": null, @@ -59,7 +48,7 @@ "healthCardAndPinPhone": "+498000265637", "healthCardAndPinMail": null, "healthCardAndPinUrl": null, - "pinUrl": null, + "pinUrl": "https://www.aok.de/pk/versichertenservice/pin-zur-elektronischen-gesundheitskarte/", "subjectCardAndPinMail": null, "bodyCardAndPinMail": null, "subjectPinMail": null, @@ -78,10 +67,10 @@ }, { "name": "AOK Nordwest - Die Gesundheitskasse", - "healthCardAndPinPhone": "+498002655060", + "healthCardAndPinPhone": null, "healthCardAndPinMail": null, - "healthCardAndPinUrl": null, - "pinUrl": null, + "healthCardAndPinUrl": "https://www.aok.de/pk/versichertenservice/pin-zur-elektronischen-gesundheitskarte/", + "pinUrl": "https://www.aok.de/pk/versichertenservice/pin-zur-elektronischen-gesundheitskarte/", "subjectCardAndPinMail": null, "bodyCardAndPinMail": null, "subjectPinMail": null, @@ -114,7 +103,7 @@ "healthCardAndPinPhone": null, "healthCardAndPinMail": null, "healthCardAndPinUrl": "https://www.aok.de/pk/rps/inhalt/die-haeufigsten-fragen-und-antworten-zum-e-rezept-4/", - "pinUrl": null, + "pinUrl": "https://www.aok.de/pk/versichertenservice/pin-zur-elektronischen-gesundheitskarte/", "subjectCardAndPinMail": null, "bodyCardAndPinMail": null, "subjectPinMail": null, @@ -146,8 +135,8 @@ "name": "BAHN-BKK", "healthCardAndPinPhone": null, "healthCardAndPinMail": null, - "healthCardAndPinUrl": "https://www.bahn-bkk.de/egk-erezept", - "pinUrl": "https://www.bahn-bkk.de/egk-erezept", + "healthCardAndPinUrl": "https://www.bahn-bkk.de/versicherung/pin-fuer-egk/7473", + "pinUrl": "https://www.bahn-bkk.de/versicherung/pin-fuer-egk/7473", "subjectCardAndPinMail": null, "bodyCardAndPinMail": null, "subjectPinMail": null, @@ -616,7 +605,7 @@ "bodyPinMail": null }, { - "name": "BKK Verkehrsbau Union (VBU)", + "name": "mkk – meine krankenkasse", "healthCardAndPinPhone": null, "healthCardAndPinMail": "info@bkk-vbu.de", "healthCardAndPinUrl": null, diff --git a/app/features/src/main/res/values/strings.xml b/app/features/src/main/res/values/strings.xml index bef468be..156850aa 100644 --- a/app/features/src/main/res/values/strings.xml +++ b/app/features/src/main/res/values/strings.xml @@ -220,7 +220,7 @@ Ich nehme das erhöhte Risiko zur Kenntnis und möchte dennoch fortfahren. Weshalb sind Geräte mit Root-Zugriff ein potentielles Sicherheitsrisiko? Mehr erfahren - https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html Name des Profils Bitte geben Sie einen Namen für das neue Profil ein. Profilname @@ -916,4 +916,5 @@ Demo-Modus aktiviert Hier Beenden Demo-Modus aktivieren + Demo-Modus Beenden diff --git a/app/features/src/main/res/values/themes.xml b/app/features/src/main/res/values/themes.xml index af55e469..4de55388 100644 --- a/app/features/src/main/res/values/themes.xml +++ b/app/features/src/main/res/values/themes.xml @@ -9,4 +9,13 @@ @color/neutral false + + + + diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/DebugSettingsData.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/DebugSettingsData.kt new file mode 100644 index 00000000..81e1b563 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/DebugSettingsData.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.data + +import android.os.Parcelable +import androidx.compose.runtime.Immutable +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import kotlinx.parcelize.Parcelize + +@Immutable +@Parcelize +data class DebugSettingsData( + val eRezeptServiceURL: String, + val eRezeptActive: Boolean, + val idpUrl: String, + val idpActive: Boolean, + val pharmacyServiceUrl: String, + val pharmacyServiceActive: Boolean, + val bearerToken: String, + val bearerTokenIsSet: Boolean, + val fakeNFCCapabilities: Boolean, + val cardAccessNumberIsSet: Boolean, + val multiProfile: Boolean, + val activeProfileId: ProfileIdentifier, + val virtualHealthCardCert: String, + val virtualHealthCardPrivateKey: String +) : Parcelable diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/Environment.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/Environment.kt new file mode 100644 index 00000000..3be5c794 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/data/Environment.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.data + +enum class Environment { + PU, TU, RU, RUDEV, TR +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/di/EndpointHelper.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/di/EndpointHelper.kt new file mode 100644 index 00000000..032c213a --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/di/EndpointHelper.kt @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.di + +import android.content.SharedPreferences +import androidx.core.content.edit +import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.data.Environment + +class EndpointHelper( + private val networkPrefs: SharedPreferences +) { + + enum class EndpointUri(val original: String, val preferenceKey: String) { + BASE_SERVICE_URI( + BuildKonfig.BASE_SERVICE_URI, + "BASE_SERVICE_URI_OVERRIDE" + ), + IDP_SERVICE_URI( + BuildKonfig.IDP_SERVICE_URI, + "IDP_SERVICE_URI_OVERRIDE" + ), + PHARMACY_SERVICE_URI( + BuildKonfig.PHARMACY_SERVICE_URI, + "PHARMACY_BASE_URI_OVERRIDE" + ) + } + + val eRezeptServiceUri + get() = getUriForEndpoint(EndpointUri.BASE_SERVICE_URI) + + val idpServiceUri + get() = getUriForEndpoint(EndpointUri.IDP_SERVICE_URI) + + val pharmacySearchBaseUri + get() = getUriForEndpoint(EndpointUri.PHARMACY_SERVICE_URI) + + private fun getUriForEndpoint(uri: EndpointUri): String { + var url = uri.original + if (isUriOverridden(uri)) { + url = networkPrefs.getString( + uri.preferenceKey, + uri.original + )!! + } + if (url.last() != '/') { + url += '/' + } + return url + } + + private fun overrideSwitchKey(uri: EndpointUri): String { + return uri.preferenceKey + "_ACTIVE" + } + + fun isUriOverridden(uri: EndpointUri): Boolean { + return networkPrefs.getBoolean(overrideSwitchKey(uri), false) + } + + fun setUriOverride(uri: EndpointUri, debugUri: String, active: Boolean) { + networkPrefs.edit(commit = true) { + putBoolean(overrideSwitchKey(uri), active) + putString(uri.preferenceKey, debugUri) + } + } + + fun getCurrentEnvironment(): Environment { + return when { + eRezeptServiceUri == BuildKonfig.BASE_SERVICE_URI_PU && + idpServiceUri == BuildKonfig.IDP_SERVICE_URI_PU && + pharmacySearchBaseUri == BuildKonfig.PHARMACY_SERVICE_URI_PU -> { + Environment.PU + } + eRezeptServiceUri == BuildKonfig.BASE_SERVICE_URI_RU && + idpServiceUri == BuildKonfig.IDP_SERVICE_URI_RU && + pharmacySearchBaseUri == BuildKonfig.PHARMACY_SERVICE_URI_RU -> { + Environment.RU + } + eRezeptServiceUri == BuildKonfig.BASE_SERVICE_URI_RU_DEV && + idpServiceUri == BuildKonfig.IDP_SERVICE_URI_RU_DEV && + pharmacySearchBaseUri == BuildKonfig.PHARMACY_SERVICE_URI_RU -> { + Environment.RUDEV + } + eRezeptServiceUri == BuildKonfig.BASE_SERVICE_URI_TU && + idpServiceUri == BuildKonfig.IDP_SERVICE_URI_TU && + pharmacySearchBaseUri == BuildKonfig.PHARMACY_SERVICE_URI_RU -> { + Environment.TU + } + eRezeptServiceUri == BuildKonfig.BASE_SERVICE_URI_TR && + idpServiceUri == BuildKonfig.IDP_SERVICE_URI_TR && + pharmacySearchBaseUri == BuildKonfig.PHARMACY_SERVICE_URI_RU -> { + Environment.TR + } + else -> { + return Environment.PU + } + } + } + + fun getErpApiKey(): String { + return if (BuildKonfig.INTERNAL) { + when (getCurrentEnvironment()) { + Environment.PU -> BuildKonfig.ERP_API_KEY_GOOGLE_PU + Environment.TU -> BuildKonfig.ERP_API_KEY_GOOGLE_TU + Environment.RUDEV, Environment.RU -> BuildKonfig.ERP_API_KEY_GOOGLE_RU + Environment.TR -> BuildKonfig.ERP_API_KEY_GOOGLE_TR + } + } else { + BuildKonfig.ERP_API_KEY + } + } + + fun getIdpScope(): String { + return if (BuildKonfig.INTERNAL) { + when (getCurrentEnvironment()) { + Environment.RUDEV -> BuildKonfig.IDP_SCOPE_DEVRU + else -> BuildKonfig.IDP_DEFAULT_SCOPE + } + } else { + BuildKonfig.IDP_DEFAULT_SCOPE + } + } + + fun getPharmacyApiKey(): String { + return if (BuildKonfig.INTERNAL) { + when (getCurrentEnvironment()) { + Environment.PU -> BuildKonfig.PHARMACY_API_KEY_PU + else -> BuildKonfig.PHARMACY_API_KEY_RU + } + } else { + BuildKonfig.PHARMACY_API_KEY + } + } + + fun getTrustAnchor(): String { + return if (BuildKonfig.INTERNAL) { + when (getCurrentEnvironment()) { + Environment.PU -> BuildKonfig.APP_TRUST_ANCHOR_BASE64_PU + else -> BuildKonfig.APP_TRUST_ANCHOR_BASE64_TU + } + } else { + BuildKonfig.APP_TRUST_ANCHOR_BASE64 + } + } +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/navigation/DebugScreenNavigation.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/navigation/DebugScreenNavigation.kt new file mode 100644 index 00000000..4a63a258 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/navigation/DebugScreenNavigation.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.navigation + +import de.gematik.ti.erp.app.debugsettings.timeout.DebugTimeoutScreen + +object DebugScreenNavigation { + object DebugMain : Routes("DebugMain") + object DebugRedeemWithoutFD : Routes("DebugRedeemWithoutFD") + object DebugPKV : Routes("DebugPKV") + object DebugBiometric : Routes(DebugTimeoutScreen::class::java.name) +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugLoadingButton.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugLoadingButton.kt new file mode 100644 index 00000000..c231c621 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugLoadingButton.kt @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.ui + +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.size +import androidx.compose.material.Button +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.setValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.utils.compose.AlertDialog +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import kotlinx.coroutines.launch + +@Composable +fun DebugLoadingButton( + modifier: Modifier = Modifier, + enabled: Boolean = true, + text: String, + onClick: suspend () -> Unit +) { + var loading by remember { mutableStateOf(false) } + var errorMessage by remember { mutableStateOf(null) } + errorMessage?.let { error -> + AlertDialog( + onDismissRequest = { + errorMessage = null + }, + buttons = { + Button(onClick = { errorMessage = null }) { + Text("OK") + } + }, + text = { + Text(error) + } + ) + } + val scope = rememberCoroutineScope() + + Button( + modifier = modifier.fillMaxWidth(), + onClick = { + loading = true + scope.launch { + try { + onClick() + } catch (e: Exception) { + errorMessage = e.message + (e.cause?.message?.let { " - cause: $it" } ?: "") + } finally { + loading = false + } + } + }, + enabled = enabled && !loading + ) { + if (loading) { + CircularProgressIndicator(Modifier.size(24.dp), strokeWidth = 2.dp, color = AppTheme.colors.neutral600) + SpacerSmall() + } + Text(text, textAlign = TextAlign.Center) + } +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugPKV.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugPKV.kt new file mode 100644 index 00000000..4e7fbdc7 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugPKV.kt @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.ui + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.Button +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextAlign +import de.gematik.ti.erp.app.profiles.presentation.rememberProfilesController +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.NavigationBarMode +import kotlinx.coroutines.launch +import org.kodein.di.compose.rememberViewModel + +@Composable +fun DebugScreenPKV(onBack: () -> Unit) { + val viewModel by rememberViewModel() + val listState = rememberLazyListState() + + AnimatedElevationScaffold( + navigationMode = NavigationBarMode.Back, + listState = listState, + topBarTitle = "Debug PKV", + onBack = onBack + ) { innerPadding -> + var invoiceBundle by remember { mutableStateOf("") } + val scope = rememberCoroutineScope() + + LazyColumn( + state = listState, + modifier = Modifier + .padding(innerPadding) + .navigationBarsPadding() + .imePadding(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium), + contentPadding = PaddingValues(PaddingDefaults.Medium) + ) { + item { + DebugCard(title = "Login state") { + val profilesController = rememberProfilesController() + val activeProfile by profilesController.getActiveProfileState() + Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + Button( + onClick = { + scope.launch { + profilesController.switchToPrivateInsurance(activeProfile.id) + } + }, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "Set User with ${activeProfile.name} as PKV", textAlign = TextAlign.Center) + } + } + } + } + item { + DebugCard( + title = "Invoice Bundle" + ) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = invoiceBundle, + label = { Text("Bundle") }, + onValueChange = { + invoiceBundle = it + }, + maxLines = 1 + ) + DebugLoadingButton( + onClick = { viewModel.saveInvoice(invoiceBundle) }, + text = "Save Invoice" + ) + } + } + } + } +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreen.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreen.kt new file mode 100644 index 00000000..14f265aa --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreen.kt @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.ui + +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.foundation.selection.selectableGroup +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Button +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Card +import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.material.ModalBottomSheetLayout +import androidx.compose.material.ModalBottomSheetValue +import androidx.compose.material.OutlinedTextField +import androidx.compose.material.RadioButton +import androidx.compose.material.Switch +import androidx.compose.material.Text +import androidx.compose.material.TextField +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material.rememberModalBottomSheetState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import de.gematik.ti.erp.app.TestTag +import de.gematik.ti.erp.app.debugsettings.timeout.DebugTimeoutScreen +import de.gematik.ti.erp.app.data.Environment +import de.gematik.ti.erp.app.navigation.DebugScreenNavigation +import de.gematik.ti.erp.app.features.R +import de.gematik.ti.erp.app.settings.ui.LabelButton +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.AlertDialog +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.NavigationAnimation +import de.gematik.ti.erp.app.utils.compose.NavigationBarMode +import de.gematik.ti.erp.app.utils.compose.OutlinedDebugButton +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.navigationModeState +import kotlinx.coroutines.launch +import org.bouncycastle.util.encoders.Base64 +import org.kodein.di.bindProvider +import org.kodein.di.compose.rememberViewModel +import org.kodein.di.compose.subDI +import org.kodein.di.instance +import java.io.ByteArrayOutputStream +import java.time.LocalDateTime +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + +@Composable +fun DebugCard( + modifier: Modifier = Modifier, + title: String, + onReset: (() -> Unit)? = null, + content: @Composable ColumnScope.() -> Unit +) = + Card( + modifier = modifier, + shape = RoundedCornerShape(24.dp), + backgroundColor = AppTheme.colors.neutral100, + elevation = 10.dp + ) { + Box( + contentAlignment = Alignment.Center, + content = { + Column( + Modifier.padding(PaddingDefaults.Medium), + verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Small) + ) { + Text( + title, + style = MaterialTheme.typography.h6, + modifier = Modifier.align(Alignment.CenterHorizontally) + ) + SpacerMedium() + content() + } + onReset?.run { + IconButton( + modifier = Modifier + .align(Alignment.TopEnd) + .padding(PaddingDefaults.Small), + onClick = onReset + ) { + Icon(Icons.Rounded.Refresh, null) + } + } + } + ) + } + +@Composable +fun EditablePathComponentSetButton( + modifier: Modifier = Modifier, + label: String, + text: String, + active: Boolean, + onValueChange: (String, Boolean) -> Unit, + onClick: () -> Unit +) { + val color = if (active) Color.Green else Color.Red + val buttonText = if (active) "SAVED" else "SET" + EditablePathComponentWithControl( + modifier = modifier, + label = label, + textFieldValue = text, + onValueChange = onValueChange, + content = { + Button( + onClick = onClick, + colors = ButtonDefaults.buttonColors(backgroundColor = color), + enabled = !active + + ) { + Text(text = buttonText) + } + } + ) +} + +@Composable +fun EditablePathComponentWithControl( + modifier: Modifier, + label: String, + textFieldValue: String, + onValueChange: (String, Boolean) -> Unit, + content: @Composable ((Boolean) -> Unit) -> Unit +) { + Row(verticalAlignment = Alignment.CenterVertically, modifier = modifier.fillMaxWidth()) { + TextField( + value = textFieldValue, + onValueChange = { onValueChange(it, false) }, + label = { Text(label) }, + maxLines = 3, + modifier = Modifier + .weight(1f) + .padding(end = PaddingDefaults.Medium) + ) + + content { onValueChange(textFieldValue, it) } + } +} + +@Composable +fun DebugScreen( + settingsNavController: NavController +) { + val navController = rememberNavController() + val navMode by navController.navigationModeState(DebugScreenNavigation.DebugMain.path()) + + subDI(diBuilder = { + bindProvider { + DebugSettingsViewModel( + visibleDebugTree = instance(), + endpointHelper = instance(), + cardWallUseCase = instance(), + prescriptionUseCase = instance(), + invoiceRepository = instance(), + vauRepository = instance(), + idpRepository = instance(), + idpUseCase = instance(), + profilesUseCase = instance(), + featureToggleManager = instance(), + pharmacyDirectRedeemUseCase = instance(), + dispatchers = instance() + ) + } + }) { + NavHost( + navController, + startDestination = DebugScreenNavigation.DebugMain.path() + ) { + composable(DebugScreenNavigation.DebugMain.route) { + NavigationAnimation(mode = navMode) { + DebugScreenMain( + onBack = { + settingsNavController.popBackStack() + }, + onClickDirectRedemption = { + navController.navigate(DebugScreenNavigation.DebugRedeemWithoutFD.path()) + }, + onClickPKV = { + navController.navigate(DebugScreenNavigation.DebugPKV.path()) + }, + onClickBioMetricSettings = { + navController.navigate(DebugScreenNavigation.DebugBiometric.path()) + } + ) + } + } + composable(DebugScreenNavigation.DebugRedeemWithoutFD.route) { + NavigationAnimation(mode = navMode) { + DebugScreenDirectRedeem( + onBack = { + navController.popBackStack() + } + ) + } + } + composable(DebugScreenNavigation.DebugPKV.route) { + NavigationAnimation(mode = navMode) { + DebugScreenPKV( + onBack = { + navController.popBackStack() + } + ) + } + } + + composable(DebugScreenNavigation.DebugBiometric.route) { + DebugTimeoutScreen.Content { + navController.popBackStack() + } + } + } + } +} + +@Composable +fun DebugScreenDirectRedeem(onBack: () -> Unit) { + val viewModel by rememberViewModel() + val listState = rememberLazyListState() + + AnimatedElevationScaffold( + navigationMode = NavigationBarMode.Back, + listState = listState, + topBarTitle = "Debug Redeem", + onBack = onBack + ) { innerPadding -> + var shipmentUrl by remember { mutableStateOf("") } + var deliveryUrl by remember { mutableStateOf("") } + var onPremiseUrl by remember { mutableStateOf("") } + var message by remember { mutableStateOf("") } + var certificates by remember { mutableStateOf("") } + + LazyColumn( + state = listState, + modifier = Modifier + .padding(innerPadding) + .navigationBarsPadding() + .imePadding(), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium), + contentPadding = PaddingValues(PaddingDefaults.Medium) + ) { + item { + DebugCard( + title = "Endpoints" + ) { + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = shipmentUrl, + label = { Text("Shipment URL") }, + onValueChange = { + shipmentUrl = it + } + ) + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = deliveryUrl, + label = { Text("Delivery URL") }, + onValueChange = { + deliveryUrl = it + } + ) + OutlinedTextField( + modifier = Modifier.fillMaxWidth(), + value = onPremiseUrl, + label = { Text("OnPremise URL") }, + onValueChange = { + onPremiseUrl = it + } + ) + } + } + item { + RedeemButton( + viewModel = viewModel, + url = shipmentUrl, + message = message, + certificates = certificates, + text = "Send as Shipment" + ) + RedeemButton( + viewModel = viewModel, + url = deliveryUrl, + message = message, + certificates = certificates, + text = "Send as Delivery" + ) + RedeemButton( + viewModel = viewModel, + url = onPremiseUrl, + message = message, + certificates = certificates, + text = "Send as OnPremise" + ) + } + item { + DebugCard( + title = "Message" + ) { + OutlinedTextField( + modifier = Modifier + .heightIn(max = 400.dp) + .fillMaxWidth(), + value = message, + label = { Text("Any Message") }, + onValueChange = { + message = it + } + ) + } + } + item { + DebugCard( + title = "Certificates" + ) { + OutlinedTextField( + modifier = Modifier + .heightIn(max = 400.dp) + .fillMaxWidth(), + value = certificates, + label = { Text("Certificate as PEM") }, + onValueChange = { + certificates = it + } + ) + } + } + } + } +} + +@Composable +private fun RedeemButton( + viewModel: DebugSettingsViewModel, + url: String, + message: String, + certificates: String, + text: String +) = + DebugLoadingButton( + onClick = { viewModel.redeemDirect(url = url, message = message, certificatesPEM = certificates) }, + enabled = url.isNotEmpty() && certificates.isNotEmpty(), + text = text + ) + +@Suppress("LongMethod") +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun DebugScreenMain( + onBack: () -> Unit, + onClickDirectRedemption: () -> Unit, + onClickPKV: () -> Unit, + onClickBioMetricSettings: () -> Unit +) { + val viewModel by rememberViewModel() + val listState = rememberLazyListState() + val modal = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden) + val scope = rememberCoroutineScope() + + ModalBottomSheetLayout( + sheetContent = { + EnvironmentSelector( + currentSelectedEnvironment = viewModel.getCurrentEnvironment(), + onSelectEnvironment = { viewModel.selectEnvironment(it) } + ) { + scope.launch { viewModel.saveAndRestartApp() } + } + }, + sheetState = modal + ) { + AnimatedElevationScaffold( + modifier = Modifier.testTag(TestTag.DebugMenu.DebugMenuScreen), + navigationMode = NavigationBarMode.Close, + listState = listState, + topBarTitle = "Debug Settings", + onBack = onBack + ) { innerPadding -> + + LaunchedEffect(Unit) { + viewModel.state() + } + + LazyColumn( + state = listState, + modifier = Modifier + .padding(innerPadding) + .navigationBarsPadding() + .testTag(TestTag.DebugMenu.DebugMenuContent), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium), + contentPadding = PaddingValues(PaddingDefaults.Medium) + ) { + item { + DebugCard( + title = "General" + ) { + LabelButton( + icon = painterResource(R.drawable.ic_finger), + text = "Biometric settings" + ) { + onClickBioMetricSettings() + } + LabelButton( + icon = painterResource(R.drawable.ic_qr_code), + text = "Direct Redemption" + ) { + onClickDirectRedemption() + } + LabelButton( + icon = painterResource(R.drawable.ic_pkv), + text = "PKV" + ) { + onClickPKV() + } + LabelButton( + icon = painterResource(R.drawable.ic_prescription_refresh), + text = "Trigger Prescription Refresh" + ) { + viewModel.refreshPrescriptions() + } + } + } + item { + DebugCard( + title = "Card Wall" + ) { + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = "Fake NFC Capability", + modifier = Modifier + .weight(1f) + ) + Switch( + modifier = Modifier.testTag(TestTag.DebugMenu.FakeNFCCapabilities), + checked = viewModel.debugSettingsData.fakeNFCCapabilities, + onCheckedChange = { viewModel.allowNfc(it) } + ) + } + } + } + item { + DebugCard( + title = "Authentication" + ) { + EditablePathComponentSetButton( + label = "Bearer Token", + text = viewModel.debugSettingsData.bearerToken, + active = viewModel.debugSettingsData.bearerTokenIsSet, + onValueChange = { text, _ -> + viewModel.updateState( + viewModel.debugSettingsData.copy( + bearerToken = text, + bearerTokenIsSet = false + ) + ) + }, + onClick = { + viewModel.changeBearerToken(viewModel.debugSettingsData.activeProfileId) + } + ) + Button( + onClick = { scope.launch { viewModel.breakSSOToken() } }, + modifier = Modifier.fillMaxWidth() + ) { + Text(text = "Break SSO Token") + } + } + } + item { + DebugCard(title = "Environment") { + OutlinedDebugButton( + modifier = Modifier.fillMaxWidth(), + text = "Select Environment", + onClick = { scope.launch { modal.show() } } + ) + } + } + item { + VirtualHealthCard(viewModel = viewModel) + } + item { + FeatureToggles(viewModel = viewModel) + } + item { + RotatingLog(viewModel = viewModel) + } + } + } + } +} + +@Composable +private fun RotatingLog(modifier: Modifier = Modifier, viewModel: DebugSettingsViewModel) { + DebugCard(modifier, title = "Log") { + val context = LocalContext.current + val mailAddress = stringResource(R.string.settings_contact_mail_address) + LabelButton( + modifier = Modifier.fillMaxWidth(), + icon = painterResource(R.drawable.ic_log_mail), + text = "Send mail", + onClick = { + val intent = Intent(Intent.ACTION_SENDTO) + intent.data = Uri.parse("mailto:") + intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(mailAddress)) + intent.putExtra(Intent.EXTRA_SUBJECT, "#Log-#Android-${LocalDateTime.now()}") + + val bout = ByteArrayOutputStream() + ZipOutputStream(bout).use { + val e = ZipEntry("log.txt") + it.putNextEntry(e) + + val data = viewModel.rotatingLog.value.joinToString("\n").toByteArray() + it.write(data, 0, data.size) + it.closeEntry() + } + + intent.putExtra(Intent.EXTRA_TEXT, Base64.toBase64String(bout.toByteArray())) + + if (intent.resolveActivity(context.packageManager) != null) { + context.startActivity(intent) + } + } + ) + } +} + +@Composable +private fun VirtualHealthCard(modifier: Modifier = Modifier, viewModel: DebugSettingsViewModel) { + var virtualHealthCardLoading by remember { mutableStateOf(false) } + var virtualHealthCardError by remember { mutableStateOf(null) } + virtualHealthCardError?.let { error -> + AlertDialog( + onDismissRequest = { + virtualHealthCardError = null + }, + buttons = { + Button(onClick = { virtualHealthCardError = null }) { + Text("OK") + } + }, + text = { + Text(error) + } + ) + } + + DebugCard(modifier, title = "Virtual Health Card", onReset = viewModel::onResetVirtualHealthCard) { + val scope = rememberCoroutineScope() + + OutlinedTextField( + modifier = Modifier + .testTag(TestTag.DebugMenu.CertificateField) + .heightIn(max = 144.dp) + .fillMaxWidth(), + value = viewModel.debugSettingsData.virtualHealthCardCert, + onValueChange = { + viewModel.onSetVirtualHealthCardCertificate(it) + }, + label = { Text("Certificate in Base64") } + ) + + val subjectInfo = + remember(viewModel.debugSettingsData.virtualHealthCardCert) { + viewModel.getVirtualHealthCardCertificateSubjectInfo() + } + Text(subjectInfo, style = AppTheme.typography.caption1l) + + OutlinedTextField( + modifier = Modifier + .testTag(TestTag.DebugMenu.PrivateKeyField) + .heightIn(max = 144.dp) + .fillMaxWidth(), + value = viewModel.debugSettingsData.virtualHealthCardPrivateKey, + onValueChange = { + viewModel.onSetVirtualHealthCardPrivateKey(it) + }, + label = { Text("Private Key in Base64") } + ) + + Button( + modifier = Modifier + .fillMaxWidth() + .testTag(TestTag.DebugMenu.SetVirtualHealthCardButton), + onClick = { + virtualHealthCardLoading = true + scope.launch { + try { + viewModel.onTriggerVirtualHealthCard( + certificateBase64 = viewModel.debugSettingsData.virtualHealthCardCert, + privateKeyBase64 = viewModel.debugSettingsData.virtualHealthCardPrivateKey + ) + } catch (e: Exception) { + virtualHealthCardError = e.message + } finally { + virtualHealthCardLoading = false + } + } + }, + enabled = !virtualHealthCardLoading + ) { + if (virtualHealthCardLoading) { + CircularProgressIndicator( + Modifier.size(24.dp), + strokeWidth = 2.dp, + color = AppTheme.colors.neutral600 + ) + SpacerSmall() + } + Text("Set Virtual Health Card for Active Profile", textAlign = TextAlign.Center) + } + } +} + +@Composable +private fun FeatureToggles(modifier: Modifier = Modifier, viewModel: DebugSettingsViewModel) { + val featuresState by produceState(initialValue = mutableMapOf()) { + viewModel.featuresState().collect { + value = it + } + } + DebugCard(modifier, title = "Feature Toggles") { + for (feature in viewModel.features()) { + Row( + modifier = Modifier + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = feature.featureName, + modifier = Modifier + .weight(1f), + style = MaterialTheme.typography.body1 + ) + Switch( + checked = featuresState[feature.featureName] ?: false, + onCheckedChange = { viewModel.toggleFeature(feature) } + ) + } + } + } +} + +@Composable +fun EnvironmentSelector( + currentSelectedEnvironment: Environment, + onSelectEnvironment: (environment: Environment) -> Unit, + onSaveEnvironment: () -> Unit +) { + var selectedEnvironment by remember { mutableStateOf(currentSelectedEnvironment) } + + Column( + modifier = Modifier + .navigationBarsPadding() + .fillMaxWidth() + .selectableGroup() + ) { + Text( + text = stringResource(R.string.debug_select_environment), + style = AppTheme.typography.h6, + modifier = Modifier.padding(PaddingDefaults.Medium) + ) + + Environment.values().forEach { + Row( + modifier = Modifier + .fillMaxWidth() + .clickable { + selectedEnvironment = it + onSelectEnvironment(it) + } + ) { + Row( + modifier = Modifier.padding( + horizontal = PaddingDefaults.Medium, + vertical = PaddingDefaults.Small + ), + horizontalArrangement = Arrangement.spacedBy(16.dp), + verticalAlignment = Alignment.CenterVertically + ) { + RadioButton( + modifier = Modifier.size(32.dp), + selected = selectedEnvironment == it, + onClick = { + selectedEnvironment = it + onSelectEnvironment(it) + } + ) + Text(it.name) + } + } + } + Row(modifier = Modifier.padding(PaddingDefaults.Medium)) { + Button(modifier = Modifier.fillMaxWidth(), onClick = { onSaveEnvironment() }) { + Text(text = stringResource(R.string.debug_save_environment)) + } + Spacer(modifier = Modifier.navigationBarsPadding()) + } + } +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt new file mode 100644 index 00000000..76c0e894 --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.ui + +import androidx.compose.runtime.Composable +import androidx.navigation.NavController + +@Composable +fun DebugScreenWrapper(navigation: NavController) = + DebugScreen(settingsNavController = navigation) diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugSettingsViewModel.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugSettingsViewModel.kt new file mode 100644 index 00000000..40be1a3e --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/ui/DebugSettingsViewModel.kt @@ -0,0 +1,370 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.ui + +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import androidx.annotation.RequiresApi +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import de.gematik.ti.erp.app.BCProvider +import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.ErezeptApp +import de.gematik.ti.erp.app.VisibleDebugTree +import de.gematik.ti.erp.app.cardwall.usecase.CardWallUseCase +import de.gematik.ti.erp.app.data.DebugSettingsData +import de.gematik.ti.erp.app.data.Environment +import de.gematik.ti.erp.app.di.EndpointHelper +import de.gematik.ti.erp.app.featuretoggle.FeatureToggleManager +import de.gematik.ti.erp.app.featuretoggle.Features +import de.gematik.ti.erp.app.idp.model.IdpData +import de.gematik.ti.erp.app.idp.repository.IdpRepository +import de.gematik.ti.erp.app.idp.usecase.IdpUseCase +import de.gematik.ti.erp.app.invoice.repository.InvoiceRepository +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyDirectRedeemUseCase +import de.gematik.ti.erp.app.prescription.usecase.PrescriptionUseCase +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import de.gematik.ti.erp.app.profiles.usecase.ProfilesUseCase +import de.gematik.ti.erp.app.vau.repository.VauRepository +import io.github.aakira.napier.Napier +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json +import org.bouncycastle.cert.X509CertificateHolder +import org.bouncycastle.jce.ECNamedCurveTable +import org.bouncycastle.util.encoders.Base64 +import org.bouncycastle.util.io.pem.PemReader +import org.jose4j.base64url.Base64Url +import org.jose4j.jws.EcdsaUsingShaAlgorithm +import java.math.BigInteger +import java.security.KeyFactory +import java.security.Signature +import java.time.Instant +import java.time.temporal.ChronoUnit +import java.util.* + +private val HealthCardCert = BuildKonfig.DEFAULT_VIRTUAL_HEALTH_CARD_CERTIFICATE +private val HealthCardCertPrivateKey = BuildKonfig.DEFAULT_VIRTUAL_HEALTH_CARD_PRIVATE_KEY + +@Suppress("LongParameterList") +class DebugSettingsViewModel( + visibleDebugTree: VisibleDebugTree, + private val endpointHelper: EndpointHelper, + private val cardWallUseCase: CardWallUseCase, + private val prescriptionUseCase: PrescriptionUseCase, + private val vauRepository: VauRepository, + private val idpRepository: IdpRepository, + private val invoiceRepository: InvoiceRepository, + private val idpUseCase: IdpUseCase, + private val profilesUseCase: ProfilesUseCase, + private val featureToggleManager: FeatureToggleManager, + private val pharmacyDirectRedeemUseCase: PharmacyDirectRedeemUseCase, + private val dispatchers: DispatchProvider +) : ViewModel() { + + var debugSettingsData by mutableStateOf(createDebugSettingsData()) + + val rotatingLog = visibleDebugTree.rotatingLog + + private fun createDebugSettingsData() = DebugSettingsData( + eRezeptServiceURL = endpointHelper.eRezeptServiceUri, + eRezeptActive = endpointHelper.isUriOverridden(EndpointHelper.EndpointUri.BASE_SERVICE_URI), + idpUrl = endpointHelper.idpServiceUri, + idpActive = endpointHelper.isUriOverridden(EndpointHelper.EndpointUri.IDP_SERVICE_URI), + pharmacyServiceUrl = endpointHelper.pharmacySearchBaseUri, + pharmacyServiceActive = endpointHelper.isUriOverridden(EndpointHelper.EndpointUri.PHARMACY_SERVICE_URI), + bearerToken = "", + bearerTokenIsSet = true, + fakeNFCCapabilities = cardWallUseCase.deviceHasNFCAndAndroidMOrHigher, + cardAccessNumberIsSet = false, + multiProfile = false, + activeProfileId = "", + virtualHealthCardCert = HealthCardCert, + virtualHealthCardPrivateKey = HealthCardCertPrivateKey + ) + + suspend fun state() { + val it = profilesUseCase.activeProfileId().first() + updateState( + debugSettingsData.copy( + cardAccessNumberIsSet = ( + cardWallUseCase.authenticationData(it) + .first().singleSignOnTokenScope as? IdpData.TokenWithHealthCardScope + )?.cardAccessNumber?.isNotEmpty() + ?: false, + activeProfileId = it, + bearerToken = idpRepository.decryptedAccessToken(it).first() ?: "" + ) + ) + } + + fun updateState(debugSettingsData: DebugSettingsData) { + this.debugSettingsData = debugSettingsData + } + + fun selectEnvironment(environment: Environment) { + updateState(getDebugSettingsdataForEnvironment(environment)) + } + + private fun getDebugSettingsdataForEnvironment(environment: Environment): DebugSettingsData { + return when (environment) { + Environment.PU -> debugSettingsData.copy( + eRezeptServiceURL = BuildKonfig.BASE_SERVICE_URI_PU, + eRezeptActive = true, + idpUrl = BuildKonfig.IDP_SERVICE_URI_PU, + idpActive = true, + pharmacyServiceUrl = BuildKonfig.PHARMACY_SERVICE_URI_PU, + pharmacyServiceActive = true + ) + + Environment.TU -> debugSettingsData.copy( + eRezeptServiceURL = BuildKonfig.BASE_SERVICE_URI_TU, + eRezeptActive = true, + idpUrl = BuildKonfig.IDP_SERVICE_URI_TU, + idpActive = true, + pharmacyServiceUrl = BuildKonfig.PHARMACY_SERVICE_URI_RU, + pharmacyServiceActive = true + ) + + Environment.RU -> debugSettingsData.copy( + eRezeptServiceURL = BuildKonfig.BASE_SERVICE_URI_RU, + eRezeptActive = true, + idpUrl = BuildKonfig.IDP_SERVICE_URI_RU, + idpActive = true, + pharmacyServiceUrl = BuildKonfig.PHARMACY_SERVICE_URI_RU, + pharmacyServiceActive = true + ) + + Environment.RUDEV -> debugSettingsData.copy( + eRezeptServiceURL = BuildKonfig.BASE_SERVICE_URI_RU_DEV, + eRezeptActive = true, + idpUrl = BuildKonfig.IDP_SERVICE_URI_RU_DEV, + idpActive = true, + pharmacyServiceUrl = BuildKonfig.PHARMACY_SERVICE_URI_RU, + pharmacyServiceActive = true + ) + + Environment.TR -> debugSettingsData.copy( + eRezeptServiceURL = BuildKonfig.BASE_SERVICE_URI_TR, + eRezeptActive = true, + idpUrl = BuildKonfig.IDP_SERVICE_URI_TR, + idpActive = true, + pharmacyServiceUrl = BuildKonfig.PHARMACY_SERVICE_URI_RU, + pharmacyServiceActive = true + ) + } + } + + fun changeBearerToken(activeProfileId: ProfileIdentifier) { + idpRepository.saveDecryptedAccessToken(activeProfileId, debugSettingsData.bearerToken) + updateState(debugSettingsData.copy(bearerTokenIsSet = true)) + } + + @RequiresApi(Build.VERSION_CODES.O) + suspend fun breakSSOToken() { + withContext(dispatchers.io) { + val activeProfileId = profilesUseCase.activeProfileId().first() + idpRepository.authenticationData(activeProfileId).first().singleSignOnTokenScope?.let { + val newToken = when (it) { + is IdpData.AlternateAuthenticationToken -> + IdpData.AlternateAuthenticationToken( + token = it.token?.breakToken(), + cardAccessNumber = it.cardAccessNumber, + aliasOfSecureElementEntry = it.aliasOfSecureElementEntry, + healthCardCertificate = it.healthCardCertificate.encoded + ) + + is IdpData.DefaultToken -> + IdpData.DefaultToken( + token = it.token?.breakToken(), + cardAccessNumber = it.cardAccessNumber, + healthCardCertificate = it.healthCardCertificate.encoded + ) + + is IdpData.ExternalAuthenticationToken -> + IdpData.ExternalAuthenticationToken( + token = it.token?.breakToken(), + authenticatorName = it.authenticatorName, + authenticatorId = it.authenticatorId + ) + + else -> it + } + idpRepository.saveSingleSignOnToken( + activeProfileId, + newToken + ) + Napier.d("SSO token is now: $newToken", tag = "Debug Settings") + } + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun IdpData.SingleSignOnToken.breakToken(): IdpData.SingleSignOnToken { + val (_, rest) = this.token.split('.', limit = 2) + val someHoursBeforeNow = Instant.now().minus(48, ChronoUnit.HOURS).epochSecond + val headerWithExpiresOn = Base64Url.encodeUtf8ByteRepresentation("""{"exp":$someHoursBeforeNow}""") + return IdpData.SingleSignOnToken("$headerWithExpiresOn.$rest") + } + + suspend fun saveAndRestartApp() { + endpointHelper.setUriOverride( + EndpointHelper.EndpointUri.BASE_SERVICE_URI, + debugSettingsData.eRezeptServiceURL, + debugSettingsData.eRezeptActive + ) + endpointHelper.setUriOverride( + EndpointHelper.EndpointUri.IDP_SERVICE_URI, + debugSettingsData.idpUrl, + debugSettingsData.idpActive + ) + endpointHelper.setUriOverride( + EndpointHelper.EndpointUri.PHARMACY_SERVICE_URI, + debugSettingsData.pharmacyServiceUrl, + debugSettingsData.pharmacyServiceActive + ) + profilesUseCase.profiles.flowOn(Dispatchers.IO).first().forEach { + idpRepository.invalidate(it.id) + } + vauRepository.invalidate() + restart() + } + + fun getCurrentEnvironment() = endpointHelper.getCurrentEnvironment() + + fun allowNfc(value: Boolean) { + cardWallUseCase.deviceHasNFCAndAndroidMOrHigher = value + updateState(debugSettingsData.copy(fakeNFCCapabilities = value)) + } + + fun refreshPrescriptions() { + viewModelScope.launch { + prescriptionUseCase.downloadTasks(profilesUseCase.activeProfileId().first()) + } + } + + fun features() = featureToggleManager.features + + fun featuresState() = + featureToggleManager.featuresState() + + fun toggleFeature(feature: Features) { + viewModelScope.launch { + val key = booleanPreferencesKey(feature.featureName) + featureToggleManager.toggleFeature(key) + } + } + + private fun restart() { + val context = ErezeptApp.applicationModule.androidContext() + val packageManager: PackageManager = context.packageManager + val intent = packageManager.getLaunchIntentForPackage(context.packageName) + val componentName = intent!!.component + val mainIntent = Intent.makeRestartActivityTask(componentName) + context.startActivity(mainIntent) + Runtime.getRuntime().exit(0) + } + + fun onResetVirtualHealthCard() { + updateState( + debugSettingsData.copy( + virtualHealthCardCert = HealthCardCert, + virtualHealthCardPrivateKey = HealthCardCertPrivateKey + ) + ) + } + + fun onSetVirtualHealthCardCertificate(cert: String) { + updateState(debugSettingsData.copy(virtualHealthCardCert = cert)) + } + + fun onSetVirtualHealthCardPrivateKey(privateKey: String) { + updateState(debugSettingsData.copy(virtualHealthCardPrivateKey = privateKey)) + } + + fun getVirtualHealthCardCertificateSubjectInfo(): String = + try { + X509CertificateHolder(Base64.decode(debugSettingsData.virtualHealthCardCert)).subject.toString() + } catch (e: Exception) { + e.message ?: "Error" + } + + suspend fun onTriggerVirtualHealthCard( + certificateBase64: String, + privateKeyBase64: String + ) = withContext(dispatchers.io) { + idpUseCase.authenticationFlowWithHealthCard( + profileId = profilesUseCase.activeProfileId().first(), + cardAccessNumber = "123123", + healthCardCertificate = { Base64.decode(certificateBase64) }, + sign = { + val curveSpec = ECNamedCurveTable.getParameterSpec("brainpoolP256r1") + val keySpec = + org.bouncycastle.jce.spec.ECPrivateKeySpec(BigInteger(Base64.decode(privateKeyBase64)), curveSpec) + val privateKey = KeyFactory.getInstance("EC", BCProvider).generatePrivate(keySpec) + val signed = Signature.getInstance("NoneWithECDSA").apply { + initSign(privateKey) + update(it) + }.sign() + EcdsaUsingShaAlgorithm.convertDerToConcatenated(signed, 64) + } + ) + } + + suspend fun redeemDirect( + url: String, + message: String, + certificatesPEM: String + ) { + val pemReader = PemReader(certificatesPEM.reader()) + + val certificates = mutableListOf() + do { + val obj = pemReader.readPemObject() + if (obj != null) { + certificates += X509CertificateHolder(obj.content) + } + } while (obj != null) + + pharmacyDirectRedeemUseCase.redeemPrescriptionDirectly( + url = url, + message = message, + telematikId = "", + recipientCertificates = certificates, + transactionId = UUID.randomUUID().toString() + ).getOrThrow() + } + + fun saveInvoice(invoiceBundle: String) { + viewModelScope.launch { + val profileId = profilesUseCase.activeProfileId().first() + val bundle = Json.parseToJsonElement(invoiceBundle) + invoiceRepository.saveInvoice(profileId, bundle) + } + } +} diff --git a/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/utils/compose/DebugCommon.kt b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/utils/compose/DebugCommon.kt new file mode 100644 index 00000000..f358586a --- /dev/null +++ b/app/features/src/minifiedDebug/kotlin/de.gematik.ti.erp.app/utils/compose/DebugCommon.kt @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ButtonDefaults +import androidx.compose.material.Icon +import androidx.compose.material.OutlinedButton +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.BugReport +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.key +import androidx.compose.runtime.remember +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.layout.boundsInRoot +import androidx.compose.ui.layout.layout +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Constraints +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.round +import de.gematik.ti.erp.app.MainActivity +import de.gematik.ti.erp.app.TestTag +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import java.util.UUID + +@Composable +fun OutlinedDebugButton( + text: String, + onClick: () -> Unit, + modifier: Modifier = Modifier +) { + OutlinedButton( + onClick = onClick, + border = ButtonDefaults.outlinedBorder.copy(brush = SolidColor(AppTheme.DebugColor)), + colors = ButtonDefaults.textButtonColors(contentColor = AppTheme.DebugColor), + contentPadding = PaddingValues(horizontal = PaddingDefaults.Small, vertical = PaddingDefaults.Tiny), + modifier = modifier.testTag(TestTag.Onboarding.SkipOnboardingButton) + ) { + Icon(Icons.Outlined.BugReport, null) + SpacerSmall() + Text(text) + SpacerTiny() + } +} + +@OptIn(ExperimentalComposeUiApi::class) +fun Modifier.visualTestTag(tag: String) = + composed(fullyQualifiedName = "de.gematik.ti.erp.app.utils.compose.visualTestTag", key1 = tag) { + val activity = LocalContext.current as MainActivity + val uuid = remember { UUID.randomUUID().toString() } + + DisposableEffect(tag) { + onDispose { + activity.elementsUsedInTests -= uuid + } + } + + Modifier + .testTag(tag) + .onGloballyPositioned { + activity.elementsUsedInTests += uuid to MainActivity.ElementForTest(it.boundsInRoot(), tag) + } + } + +@Composable +fun DebugOverlay(elements: Map) { + Box(Modifier.fillMaxSize()) { + elements.entries.forEach { (key, elementForTest) -> + key(key) { + Box( + Modifier + .layout { measurable, constraints -> + val placeable = measurable.measure( + Constraints.fixed( + elementForTest.bounds.width.toInt(), + elementForTest.bounds.height.toInt() + ) + ) + layout(placeable.width, placeable.height) { + placeable.place(elementForTest.bounds.topLeft.round()) + } + } + .border(width = 2.dp, color = Color.Magenta, shape = RoundedCornerShape(12.dp)) + .clip(RoundedCornerShape(12.dp)) + ) { + Text( + text = elementForTest.tag, + color = Color.Magenta, + overflow = TextOverflow.Visible, + modifier = Modifier + .background(Color.White.copy(alpha = 0.5f)) + .padding(start = 4.dp, end = 2.dp) + ) + } + } + } + } +} diff --git a/app/features/src/release/kotlin/de.gematik.ti.erp.app/debug/ui/DebugScreenWrapper.kt b/app/features/src/release/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt similarity index 95% rename from app/features/src/release/kotlin/de.gematik.ti.erp.app/debug/ui/DebugScreenWrapper.kt rename to app/features/src/release/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt index 2b76a8f4..2572bc1e 100644 --- a/app/features/src/release/kotlin/de.gematik.ti.erp.app/debug/ui/DebugScreenWrapper.kt +++ b/app/features/src/release/kotlin/de.gematik.ti.erp.app/ui/DebugScreenWrapper.kt @@ -16,7 +16,7 @@ * */ -package de.gematik.ti.erp.app.debug.ui +package de.gematik.ti.erp.app.ui import androidx.compose.runtime.Composable import androidx.navigation.NavController diff --git a/app/shared-test/build.gradle.kts b/app/shared-test/build.gradle.kts index bbb2da70..3c649085 100644 --- a/app/shared-test/build.gradle.kts +++ b/app/shared-test/build.gradle.kts @@ -18,10 +18,6 @@ plugins { id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") } -tasks.named("preBuild") { - dependsOn(":ktlint", ":detekt") -} - licenseReport { generateCsvReport = false generateHtmlReport = false @@ -45,6 +41,9 @@ android { it.name.startsWith("kapt") }.map { it.name } } + buildTypes { + create("minifiedDebug") + } } dependencies { diff --git a/assemble-mock.sh b/assemble-mock.sh new file mode 100755 index 00000000..632ef2f1 --- /dev/null +++ b/assemble-mock.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Get the last tag from Git +LAST_TAG=$(git tag --sort=-version:refname | head -n 1) + +# Get the last hash from Git +LAST_HASH=$(git rev-parse HEAD) + +# example version name R1.17.2-RC1-2e984eg356g +NEW_VERSION_NAME="$LAST_TAG-$LAST_HASH" + +# Get the current branch we are on +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + +# Set the version code dynamically +# shellcheck disable=SC2003 +NEW_VERSION_CODE=$(expr "$(git rev-list --count "$CURRENT_BRANCH")") + +# Assemble the mock version +# shellcheck disable=SC2086 +./gradlew :app:android-mock:assembleDebug -PVERSION_CODE=$NEW_VERSION_CODE -PVERSION_NAME="$NEW_VERSION_NAME" diff --git a/build.gradle.kts b/build.gradle.kts index 675954b3..ecae840e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -25,7 +25,7 @@ plugins { id("io.realm.kotlin") version "1.7.1" apply false - // TODO: Update to latest version : https://github.com/JetBrains/compose-multiplatform/blob/master/VERSIONING.md + // TODO: Update to latest version : https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-compatibility-and-versioning.html#kotlin-compatibility id("org.jetbrains.kotlin.android") version "1.9.10" apply false id("org.jetbrains.compose") version "1.5.3" apply false @@ -35,8 +35,8 @@ plugins { id("io.gitlab.arturbosch.detekt") version "1.22.0" id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") - id("org.jetbrains.kotlin.jvm") version "1.9.0" apply false + id("org.jetbrains.kotlin.jvm") version "1.9.0" apply false } val ktlintMain: Configuration by configurations.creating @@ -54,21 +54,20 @@ dependencies { val sourcesKt = listOf( "app/android/src/**/de/gematik/**/*.kt", "app/features/src/**/de/gematik/**/*.kt", + "app/demo-mode/src/**/de/gematik/**/*.kt", "common/src/**/de/gematik/**/*.kt", "desktop/src/**/de/gematik/**/*.kt", "rules/src/**/de/gematik/**/*.kt", "smartcard-wrapper/src/**/de/gematik/**/*.kt", - "plugins/*/src/**/*.kt", - - "**/*.gradle.kts" + "plugins/*/src/**/*.kt" ) detekt { + autoCorrect = false source = fileTree(rootDir) { include(sourcesKt) - } - .filter { it.extension != "kts" } + }.filter { it.extension != "kts" } .map { it.parentFile } .let { files(*it.toTypedArray()) @@ -107,9 +106,9 @@ tasks.register("clean", Delete::class) { } fun isUnstable(version: String): Boolean = - version.contains("alpha", ignoreCase = true) - || version.contains("rc", ignoreCase = true) - || version.contains("beta", ignoreCase = true) + version.contains("alpha", ignoreCase = true) || + version.contains("rc", ignoreCase = true) || + version.contains("beta", ignoreCase = true) tasks.withType { outputFormatter = "txt,html" diff --git a/common/build.gradle.kts b/common/build.gradle.kts index c5ad647a..55941d2e 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -206,6 +206,14 @@ android { sourceCompatibility = Dependencies.Versions.JavaVersion.PROJECT_JAVA_VERSION targetCompatibility = Dependencies.Versions.JavaVersion.PROJECT_JAVA_VERSION } + buildTypes { + val debug by getting { + isJniDebuggable = true + } + create("minifiedDebug") { + initWith(debug) + } + } namespace = "de.gematik.ti.erp.lib" } enum class Platforms { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt index 2c3463ef..f3886795 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt @@ -55,7 +55,7 @@ import io.realm.kotlin.ext.query import io.realm.kotlin.ext.realmListOf import kotlinx.datetime.Instant -const val ACTUAL_SCHEMA_VERSION = 27L +const val ACTUAL_SCHEMA_VERSION = 28L val appSchemas = setOf( AppRealmSchema( diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt index 56f7fb8a..04397d4d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt @@ -88,6 +88,9 @@ class SettingsEntityV1 : RealmObject, Cascading { var pharmacySearch: PharmacySearchEntityV1? = PharmacySearchEntityV1() var userHasAcceptedInsecureDevice: Boolean = false + + var userHasAcceptedIntegrityNotOk: Boolean = false + var dataProtectionVersionAccepted: RealmInstant = LocalDateTime(2021, 10, 15, 0, 0).toRealmInstant() var password: PasswordEntityV1? = PasswordEntityV1() @@ -104,6 +107,8 @@ class SettingsEntityV1 : RealmObject, Cascading { // `gemSpec_eRp_FdV A_20203` default settings are not allow screenshots var screenshotsAllowed: Boolean = false + var trackingAllowed: Boolean = false + override fun objectsToFollow(): Iterator = iterator { pharmacySearch?.let { yield(it) } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt index d09b9abe..0c17ef78 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt @@ -67,6 +67,18 @@ object PharmacyUseCaseData { val isOnlineService get() = provides.any { it is OnlinePharmacyService } + val directRedeemUrlsNotPresent: Boolean + get() { + val hasNoPickupContact = contacts.pickUpUrl.isEmpty() + val hasNoDeliveryContact = contacts.deliveryUrl.isEmpty() + val hasNoOnlineServiceContact = contacts.onlineServiceUrl.isEmpty() + return listOf( + hasNoPickupContact, + hasNoDeliveryContact, + hasNoOnlineServiceContact + ).all { it } + } + @Stable fun singleLineAddress(): String = if (address.isNullOrEmpty()) { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/DefaultProfilesRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/DefaultProfilesRepository.kt index 6cc156b0..e9acf5e5 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/DefaultProfilesRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/DefaultProfilesRepository.kt @@ -32,6 +32,7 @@ import de.gematik.ti.erp.app.profiles.model.ProfilesData import io.realm.kotlin.Realm import io.realm.kotlin.ext.query import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.mapNotNull import kotlinx.coroutines.sync.Mutex @@ -280,4 +281,14 @@ class DefaultProfilesRepository constructor( } } } + + override suspend fun checkIsProfilePKV(profileId: ProfileIdentifier): Boolean = + getProfileById(profileId).first().insuranceType == InsuranceTypeV1.PKV + + private fun getProfileById(profileId: ProfileIdentifier): Flow = + profiles().mapNotNull { profiles -> + profiles.find { + it.id == profileId + } + } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfileRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfileRepository.kt index cbe25dcc..c21c65e3 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfileRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfileRepository.kt @@ -41,4 +41,5 @@ interface ProfileRepository { suspend fun savePersonalizedProfileImage(profileId: ProfileIdentifier, profileImage: ByteArray) suspend fun clearPersonalizedProfileImage(profileId: ProfileIdentifier) suspend fun switchProfileToPKV(profileId: ProfileIdentifier) + suspend fun checkIsProfilePKV(profileId: ProfileIdentifier): Boolean } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt index 1117f804..7ce37162 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt @@ -46,4 +46,6 @@ interface GeneralSettings { suspend fun saveMainScreenTooltipShown() suspend fun acceptMlKit() suspend fun saveAllowScreenshots(allow: Boolean) + suspend fun saveAllowTracking(allow: Boolean) + suspend fun acceptIntegrityNotOk() } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt index e55e408b..f5a7e2a5 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt @@ -30,8 +30,10 @@ object SettingsData { val mainScreenTooltipsShown: Boolean, val zoomEnabled: Boolean, val userHasAcceptedInsecureDevice: Boolean, + val userHasAcceptedIntegrityNotOk: Boolean, val authenticationFails: Int, val mlKitAccepted: Boolean, + val trackingAllowed: Boolean, val screenShotsAllowed: Boolean ) @@ -52,7 +54,7 @@ object SettingsData { } sealed class AuthenticationMode { - object DeviceSecurity : AuthenticationMode() + data object DeviceSecurity : AuthenticationMode() class Password : AuthenticationMode { val hash: ByteArray val salt: ByteArray @@ -90,6 +92,6 @@ object SettingsData { } } - object Unspecified : AuthenticationMode() + data object Unspecified : AuthenticationMode() } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt index bb785863..26bcd921 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt @@ -66,11 +66,21 @@ class SettingsRepository constructor( authenticationFails = it.authenticationFails, mainScreenTooltipsShown = it.mainScreenTooltipsShown, mlKitAccepted = it.mlKitAccepted, - screenShotsAllowed = it.screenshotsAllowed + screenShotsAllowed = it.screenshotsAllowed, + trackingAllowed = it.trackingAllowed, + userHasAcceptedIntegrityNotOk = it.userHasAcceptedIntegrityNotOk ) } }.flowOn(dispatchers.io) + fun isAnalyticsAllowed() = settings.mapNotNull { settings -> settings?.trackingAllowed } + + suspend fun changeTrackingState(state: Boolean) { + writeToRealm { + this.trackingAllowed = state + } + } + // TODO: Not used override val authenticationMode: Flow get() = realm.query().first().asFlow().mapNotNull { query -> @@ -85,6 +95,7 @@ class SettingsRepository constructor( ) } } + else -> SettingsData.AuthenticationMode.Unspecified } } @@ -202,12 +213,24 @@ class SettingsRepository constructor( } } + override suspend fun saveAllowTracking(allow: Boolean) { + writeToRealm { + this.trackingAllowed = allow + } + } + override suspend fun acceptInsecureDevice() { writeToRealm { this.userHasAcceptedInsecureDevice = true } } + override suspend fun acceptIntegrityNotOk() { + writeToRealm { + this.userHasAcceptedIntegrityNotOk = true + } + } + override suspend fun acceptUpdatedDataTerms(now: Instant) { writeToRealm { this.setAcceptedUpdatedDataTerms(now) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AcceptMLKitUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AcceptMLKitUseCase.kt new file mode 100644 index 00000000..ececa085 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AcceptMLKitUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class AcceptMLKitUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke() = settingsRepository.acceptMlKit() +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowAnalyticsUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowAnalyticsUseCase.kt new file mode 100644 index 00000000..c39bfc4b --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowAnalyticsUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class AllowAnalyticsUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke(allow: Boolean) = settingsRepository.saveAllowTracking(allow) +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowScreenshotsUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowScreenshotsUseCase.kt new file mode 100644 index 00000000..b7a6b578 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/AllowScreenshotsUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class AllowScreenshotsUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke(allow: Boolean) = settingsRepository.saveAllowScreenshots(allow) +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetCanStartToolTipsUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetCanStartToolTipsUseCase.kt new file mode 100644 index 00000000..daeade3f --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetCanStartToolTipsUseCase.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetCanStartToolTipsUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke(): Flow = settingsRepository.general.map { + it.welcomeDrawerShown && it.onboardingShownIn != null && !it.mainScreenTooltipsShown + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetMLKitAcceptedUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetMLKitAcceptedUseCase.kt new file mode 100644 index 00000000..05ea0e2d --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetMLKitAcceptedUseCase.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetMLKitAcceptedUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke(): Flow = settingsRepository.general.map { + it.mlKitAccepted + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetOnboardingSucceededUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetOnboardingSucceededUseCase.kt new file mode 100644 index 00000000..ab6241e4 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetOnboardingSucceededUseCase.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import io.realm.kotlin.internal.platform.runBlocking +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map + +class GetOnboardingSucceededUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke(): Boolean = runBlocking { + settingsRepository.general.map { + it.onboardingShownIn != null + }.first() + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetScreenShotsAllowedUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetScreenShotsAllowedUseCase.kt new file mode 100644 index 00000000..33eebb35 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetScreenShotsAllowedUseCase.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetScreenShotsAllowedUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke(): Flow = settingsRepository.general.map { + it.screenShotsAllowed + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetShowWelcomeDrawerUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetShowWelcomeDrawerUseCase.kt new file mode 100644 index 00000000..16cdfd5f --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/GetShowWelcomeDrawerUseCase.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +class GetShowWelcomeDrawerUseCase( + private val settingsRepository: SettingsRepository +) { + operator fun invoke(): Flow = settingsRepository.general.map { + !it.welcomeDrawerShown + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveAuthenticationModeUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveAuthenticationModeUseCase.kt new file mode 100644 index 00000000..6302bad5 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveAuthenticationModeUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class SaveAuthenticationModeUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke(allow: Boolean) = settingsRepository.saveAllowScreenshots(allow) +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveOnboardingSuccededUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveOnboardingSuccededUseCase.kt new file mode 100644 index 00000000..8dfbedd4 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveOnboardingSuccededUseCase.kt @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.model.SettingsData +import de.gematik.ti.erp.app.settings.repository.SettingsRepository +import kotlinx.datetime.Clock + +class SaveOnboardingSuccededUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke(authenticationMode: SettingsData.AuthenticationMode, profileName: String) = + settingsRepository.saveOnboardingSucceededData( + authenticationMode = authenticationMode, + profileName = profileName, + now = Clock.System.now() + ) +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SavePasswordUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SavePasswordUseCase.kt new file mode 100644 index 00000000..01ae1352 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SavePasswordUseCase.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.model.SettingsData +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class SavePasswordUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke(password: String) = settingsRepository.saveAuthenticationMode( + SettingsData.AuthenticationMode.Password(password = password) + ) +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveToolTippsShownUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveToolTippsShownUseCase.kt new file mode 100644 index 00000000..d5ddfaef --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveToolTippsShownUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class SaveToolTippsShownUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke() = settingsRepository.saveMainScreenTooltipShown() +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveWelcomeDrawerShownUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveWelcomeDrawerShownUseCase.kt new file mode 100644 index 00000000..3b07f51b --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/usecase/SaveWelcomeDrawerShownUseCase.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings.usecase + +import de.gematik.ti.erp.app.settings.repository.SettingsRepository + +class SaveWelcomeDrawerShownUseCase( + private val settingsRepository: SettingsRepository +) { + suspend operator fun invoke() = settingsRepository.saveWelcomeDrawerShown() +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/timeouts/repository/TimeoutRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/timeouts/repository/TimeoutRepository.kt new file mode 100644 index 00000000..13d4f606 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/timeouts/repository/TimeoutRepository.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.timeouts.repository + +import kotlin.time.Duration + +interface TimeoutRepository { + fun setDefaultTimeouts() + fun areTimeoutsExisting(): Boolean + fun changeInactivityTimeout(duration: Duration) + fun changePauseTimeout(duration: Duration) + fun getInactivityTimeout(): Duration + fun getPauseTimeout(): Duration +} diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt index a74d3a93..89ab681f 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt @@ -34,9 +34,9 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant +import org.junit.Before import org.junit.Rule -import kotlin.test.Test -import kotlin.test.BeforeTest +import org.junit.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -47,9 +47,9 @@ class SettingsRepositoryTest : TestDB() { lateinit var realm: Realm - lateinit var repo: SettingsRepository + private lateinit var repo: SettingsRepository - @BeforeTest + @Before fun setUp() { realm = Realm.open( RealmConfiguration.Builder( diff --git a/gradle.properties b/gradle.properties index 5a2492c6..ca6efd0f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ buildkonfig.flavor=googleTuInternal # VERSION_CODE=1 VERSION_NAME=1.0 -USER_AGENT=eRp-App-Android/1.17.0 GMTIK/eRezeptApp +USER_AGENT=eRp-App-Android/1.18.1 GMTIK/eRezeptApp # DATA_PROTECTION_LAST_UPDATED=2022-01-06 # diff --git a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Dependencies.kt b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Dependencies.kt index da65d519..8e47b0bf 100644 --- a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Dependencies.kt +++ b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Dependencies.kt @@ -51,7 +51,7 @@ object Dependencies { private const val desugar_version = "2.0.3" const val desugaring = "com.android.tools:desugar_jdk_libs:$desugar_version" const val processPhoenix = "com.jakewharton:process-phoenix:2.1.2" // TODO: Not used - const val imageCropper = "com.github.CanHub:Android-Image-Cropper:4.3.2" // TODO: remove lib for cropping + const val imageCropper = "com.github.CanHub:Android-Image-Cropper:4.3.2" } object AndroidX { @@ -64,7 +64,7 @@ object Dependencies { private const val security_crypto_version = "1.1.0-alpha06" private const val lifecycle_version = "2.6.2" // needs compile version 34 to go to a higher version - private const val compose_navigation_version = "2.6.0" // needs compile version 34 for 2.7.3 + private const val compose_navigation_version = "2.7.0-beta01" private const val compose_activity_version = "1.7.2" private const val compose_paging_version = "3.2.1" private const val camerax_version = "1.3.0-beta01" // needs compile version 34 for 1.3.0-rc02 @@ -292,9 +292,11 @@ object Dependencies { } object Tracking { - private const val content_square_version = "4.21.0" + private const val content_square_version = "4.22.0" const val contentSquare = "com.contentsquare.android:library:$content_square_version" + const val contentSquareCompose = "com.contentsquare.android:compose:$content_square_version" + const val contentSquareErrorAnalysis = "com.contentsquare.android:error-analysis:$content_square_version" } object Test { diff --git a/settings.gradle.kts b/settings.gradle.kts index 15008c2e..56ebef59 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -26,7 +26,7 @@ dependencyResolutionManagement { maven("https://maven.pkg.jetbrains.space/public/p/compose/dev") google() mavenCentral() - maven ("https://jitpack.io") + maven("https://jitpack.io") } } @@ -42,11 +42,11 @@ includeBuild("smartcard-wrapper") { } } -//includeBuild("modules/fhir-parser") { +// includeBuild("modules/fhir-parser") { // dependencySubstitution { // substitute(module("de.gematik.ti.erp.app:fhir-parser")).using(project(":")) // } -//} +// } include(":app:android") include(":app:android-mock")