From caac050ac937f1f20ff1211cff21924d4bd33960 Mon Sep 17 00:00:00 2001 From: bwnyasse <5323628+bwnyasse@users.noreply.github.com> Date: Sat, 31 Jan 2026 18:56:48 -0500 Subject: [PATCH] feat(core_localization): add error translation utility and new error messages feat(client_auth): implement error handling with localized messages feat(client_hubs): implement error handling with localized messages feat(client_billing): navigate to home after billing feat(client_coverage): navigate to home after coverage feat(client_create_order): navigate to home after create order feat(client_settings): navigate to home after settings feat(client_view_orders): show hub name in order card fix(client_auth): handle existing firebase accounts during sign-up This commit introduces a new utility function, `translateErrorKey`, to translate error message keys to localized strings. It also adds new error messages to the localization files for both English and Spanish. The commit also implements error handling with localized messages in the client authentication and hubs features. This makes it easier for users to understand what went wrong and how to fix it. Additionally, the commit updates the navigation flow for the billing, coverage, create order, and settings features to navigate to the home page after the user completes the action. Finally, the commit fixes a bug where the hub name was not being displayed in the order card. --- .../lib/core_localization.dart | 1 + .../lib/src/l10n/en.i18n.json | 54 +++ .../lib/src/l10n/es.i18n.json | 54 +++ .../lib/src/l10n/strings.g.dart | 4 +- .../lib/src/l10n/strings_en.g.dart | 238 +++++++++++++ .../lib/src/l10n/strings_es.g.dart | 174 ++++++++++ .../lib/src/utils/error_translator.dart | 139 ++++++++ .../packages/domain/lib/krow_domain.dart | 3 + .../lib/src/exceptions/app_exception.dart | 314 ++++++++++++++++++ .../auth_repository_impl.dart | 281 +++++++++++++--- .../presentation/blocs/client_auth_bloc.dart | 54 ++- .../pages/client_sign_in_page.dart | 7 +- .../pages/client_sign_up_page.dart | 7 +- .../billing/lib/src/billing_module.dart | 3 + .../src/presentation/pages/billing_page.dart | 2 +- .../src/presentation/pages/coverage_page.dart | 2 +- .../presentation/widgets/coverage_header.dart | 2 +- .../pages/permanent_order_page.dart | 2 +- .../pages/recurring_order_page.dart | 2 +- .../create_order/create_order_view.dart | 2 +- .../one_time_order/one_time_order_view.dart | 4 +- .../widgets/rapid_order/rapid_order_view.dart | 4 +- .../hub_repository_impl.dart | 30 +- .../presentation/blocs/client_hubs_bloc.dart | 58 +++- .../presentation/blocs/client_hubs_state.dart | 10 +- .../presentation/pages/client_hubs_page.dart | 9 +- .../settings_actions.dart | 2 +- .../settings_profile_header.dart | 2 +- .../presentation/widgets/view_order_card.dart | 37 ++- bugs/10.png | Bin 0 -> 116682 bytes 30 files changed, 1396 insertions(+), 105 deletions(-) create mode 100644 apps/mobile/packages/core_localization/lib/src/utils/error_translator.dart create mode 100644 apps/mobile/packages/domain/lib/src/exceptions/app_exception.dart create mode 100644 bugs/10.png diff --git a/apps/mobile/packages/core_localization/lib/core_localization.dart b/apps/mobile/packages/core_localization/lib/core_localization.dart index 8c8c71fc..0b0bc657 100644 --- a/apps/mobile/packages/core_localization/lib/core_localization.dart +++ b/apps/mobile/packages/core_localization/lib/core_localization.dart @@ -8,3 +8,4 @@ export 'src/domain/usecases/set_locale_use_case.dart'; export 'src/data/repositories_impl/locale_repository_impl.dart'; export 'src/data/datasources/locale_local_data_source.dart'; export 'src/localization_module.dart'; +export 'src/utils/error_translator.dart'; diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json index f42dd659..2aa6c54f 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json @@ -728,6 +728,60 @@ "paid": "Paid", "pending": "Pending" } + }, + "errors": { + "auth": { + "invalid_credentials": "The email or password you entered is incorrect.", + "account_exists": "An account with this email already exists. Try signing in instead.", + "session_expired": "Your session has expired. Please sign in again.", + "user_not_found": "We couldn't find your account. Please check your email and try again.", + "unauthorized_app": "This account is not authorized for this app.", + "weak_password": "Please choose a stronger password with at least 8 characters.", + "sign_up_failed": "We couldn't create your account. Please try again.", + "sign_in_failed": "We couldn't sign you in. Please try again.", + "not_authenticated": "Please sign in to continue.", + "password_mismatch": "This email is already registered. Please use the correct password or tap 'Forgot Password' to reset it.", + "google_only_account": "This email is registered via Google. Please use 'Forgot Password' to set a password, then try signing up again with the same information." + }, + "hub": { + "has_orders": "This hub has active orders and cannot be deleted.", + "not_found": "The hub you're looking for doesn't exist.", + "creation_failed": "We couldn't create the hub. Please try again." + }, + "order": { + "missing_hub": "Please select a location for your order.", + "missing_vendor": "Please select a vendor for your order.", + "creation_failed": "We couldn't create your order. Please try again.", + "shift_creation_failed": "We couldn't schedule the shift. Please try again.", + "missing_business": "Your business profile couldn't be loaded. Please sign in again." + }, + "profile": { + "staff_not_found": "Your profile couldn't be loaded. Please sign in again.", + "business_not_found": "Your business profile couldn't be loaded. Please sign in again.", + "update_failed": "We couldn't update your profile. Please try again." + }, + "shift": { + "no_open_roles": "There are no open positions available for this shift.", + "application_not_found": "Your application couldn't be found.", + "no_active_shift": "You don't have an active shift to clock out from." + }, + "generic": { + "unknown": "Something went wrong. Please try again.", + "no_connection": "No internet connection. Please check your network and try again." + } + }, + "success": { + "hub": { + "created": "Hub created successfully!", + "deleted": "Hub deleted successfully!", + "nfc_assigned": "NFC tag assigned successfully!" + }, + "order": { + "created": "Order created successfully!" + }, + "profile": { + "updated": "Profile updated successfully!" + } } } diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json index dd6c6b3c..6e7e8f1c 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json +++ b/apps/mobile/packages/core_localization/lib/src/l10n/es.i18n.json @@ -727,5 +727,59 @@ "paid": "Pagado", "pending": "Pendiente" } + }, + "errors": { + "auth": { + "invalid_credentials": "El correo electrónico o la contraseña que ingresaste es incorrecta.", + "account_exists": "Ya existe una cuenta con este correo electrónico. Intenta iniciar sesión.", + "session_expired": "Tu sesión ha expirado. Por favor, inicia sesión de nuevo.", + "user_not_found": "No pudimos encontrar tu cuenta. Por favor, verifica tu correo electrónico e intenta de nuevo.", + "unauthorized_app": "Esta cuenta no está autorizada para esta aplicación.", + "weak_password": "Por favor, elige una contraseña más segura con al menos 8 caracteres.", + "sign_up_failed": "No pudimos crear tu cuenta. Por favor, intenta de nuevo.", + "sign_in_failed": "No pudimos iniciar sesión. Por favor, intenta de nuevo.", + "not_authenticated": "Por favor, inicia sesión para continuar.", + "password_mismatch": "Este correo ya está registrado. Por favor, usa la contraseña correcta o toca 'Olvidé mi contraseña' para restablecerla.", + "google_only_account": "Este correo está registrado con Google. Por favor, usa 'Olvidé mi contraseña' para establecer una contraseña, luego intenta registrarte de nuevo con la misma información." + }, + "hub": { + "has_orders": "Este hub tiene órdenes activas y no puede ser eliminado.", + "not_found": "El hub que buscas no existe.", + "creation_failed": "No pudimos crear el hub. Por favor, intenta de nuevo." + }, + "order": { + "missing_hub": "Por favor, selecciona una ubicación para tu orden.", + "missing_vendor": "Por favor, selecciona un proveedor para tu orden.", + "creation_failed": "No pudimos crear tu orden. Por favor, intenta de nuevo.", + "shift_creation_failed": "No pudimos programar el turno. Por favor, intenta de nuevo.", + "missing_business": "No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo." + }, + "profile": { + "staff_not_found": "No se pudo cargar tu perfil. Por favor, inicia sesión de nuevo.", + "business_not_found": "No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.", + "update_failed": "No pudimos actualizar tu perfil. Por favor, intenta de nuevo." + }, + "shift": { + "no_open_roles": "No hay posiciones abiertas disponibles para este turno.", + "application_not_found": "No se pudo encontrar tu solicitud.", + "no_active_shift": "No tienes un turno activo para registrar salida." + }, + "generic": { + "unknown": "Algo salió mal. Por favor, intenta de nuevo.", + "no_connection": "Sin conexión a internet. Por favor, verifica tu red e intenta de nuevo." + } + }, + "success": { + "hub": { + "created": "¡Hub creado exitosamente!", + "deleted": "¡Hub eliminado exitosamente!", + "nfc_assigned": "¡Etiqueta NFC asignada exitosamente!" + }, + "order": { + "created": "¡Orden creada exitosamente!" + }, + "profile": { + "updated": "¡Perfil actualizado exitosamente!" + } } } diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/strings.g.dart b/apps/mobile/packages/core_localization/lib/src/l10n/strings.g.dart index 8e28b106..08583076 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/strings.g.dart +++ b/apps/mobile/packages/core_localization/lib/src/l10n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 2 -/// Strings: 1044 (522 per locale) +/// Strings: 1108 (554 per locale) /// -/// Built on 2026-01-31 at 13:17 UTC +/// Built on 2026-01-31 at 17:08 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/strings_en.g.dart b/apps/mobile/packages/core_localization/lib/src/l10n/strings_en.g.dart index 9b06837d..d56b70a7 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/strings_en.g.dart +++ b/apps/mobile/packages/core_localization/lib/src/l10n/strings_en.g.dart @@ -57,6 +57,8 @@ class Translations with BaseTranslations { late final TranslationsStaffProfileAttireEn staff_profile_attire = TranslationsStaffProfileAttireEn._(_root); late final TranslationsStaffShiftsEn staff_shifts = TranslationsStaffShiftsEn._(_root); late final TranslationsStaffTimeCardEn staff_time_card = TranslationsStaffTimeCardEn._(_root); + late final TranslationsErrorsEn errors = TranslationsErrorsEn._(_root); + late final TranslationsSuccessEn success = TranslationsSuccessEn._(_root); } // Path: common @@ -420,6 +422,33 @@ class TranslationsStaffTimeCardEn { late final TranslationsStaffTimeCardStatusEn status = TranslationsStaffTimeCardStatusEn._(_root); } +// Path: errors +class TranslationsErrorsEn { + TranslationsErrorsEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final TranslationsErrorsAuthEn auth = TranslationsErrorsAuthEn._(_root); + late final TranslationsErrorsHubEn hub = TranslationsErrorsHubEn._(_root); + late final TranslationsErrorsOrderEn order = TranslationsErrorsOrderEn._(_root); + late final TranslationsErrorsProfileEn profile = TranslationsErrorsProfileEn._(_root); + late final TranslationsErrorsShiftEn shift = TranslationsErrorsShiftEn._(_root); + late final TranslationsErrorsGenericEn generic = TranslationsErrorsGenericEn._(_root); +} + +// Path: success +class TranslationsSuccessEn { + TranslationsSuccessEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + late final TranslationsSuccessHubEn hub = TranslationsSuccessHubEn._(_root); + late final TranslationsSuccessOrderEn order = TranslationsSuccessOrderEn._(_root); + late final TranslationsSuccessProfileEn profile = TranslationsSuccessProfileEn._(_root); +} + // Path: staff_authentication.get_started_page class TranslationsStaffAuthenticationGetStartedPageEn { TranslationsStaffAuthenticationGetStartedPageEn._(this._root); @@ -1745,6 +1774,183 @@ class TranslationsStaffTimeCardStatusEn { String get pending => 'Pending'; } +// Path: errors.auth +class TranslationsErrorsAuthEn { + TranslationsErrorsAuthEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'The email or password you entered is incorrect.' + String get invalid_credentials => 'The email or password you entered is incorrect.'; + + /// en: 'An account with this email already exists. Try signing in instead.' + String get account_exists => 'An account with this email already exists. Try signing in instead.'; + + /// en: 'Your session has expired. Please sign in again.' + String get session_expired => 'Your session has expired. Please sign in again.'; + + /// en: 'We couldn't find your account. Please check your email and try again.' + String get user_not_found => 'We couldn\'t find your account. Please check your email and try again.'; + + /// en: 'This account is not authorized for this app.' + String get unauthorized_app => 'This account is not authorized for this app.'; + + /// en: 'Please choose a stronger password with at least 8 characters.' + String get weak_password => 'Please choose a stronger password with at least 8 characters.'; + + /// en: 'We couldn't create your account. Please try again.' + String get sign_up_failed => 'We couldn\'t create your account. Please try again.'; + + /// en: 'We couldn't sign you in. Please try again.' + String get sign_in_failed => 'We couldn\'t sign you in. Please try again.'; + + /// en: 'Please sign in to continue.' + String get not_authenticated => 'Please sign in to continue.'; + + /// en: 'This email is already registered. Please use the correct password or tap 'Forgot Password' to reset it.' + String get password_mismatch => 'This email is already registered. Please use the correct password or tap \'Forgot Password\' to reset it.'; + + /// en: 'This email is registered via Google. Please use 'Forgot Password' to set a password, then try signing up again with the same information.' + String get google_only_account => 'This email is registered via Google. Please use \'Forgot Password\' to set a password, then try signing up again with the same information.'; +} + +// Path: errors.hub +class TranslationsErrorsHubEn { + TranslationsErrorsHubEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'This hub has active orders and cannot be deleted.' + String get has_orders => 'This hub has active orders and cannot be deleted.'; + + /// en: 'The hub you're looking for doesn't exist.' + String get not_found => 'The hub you\'re looking for doesn\'t exist.'; + + /// en: 'We couldn't create the hub. Please try again.' + String get creation_failed => 'We couldn\'t create the hub. Please try again.'; +} + +// Path: errors.order +class TranslationsErrorsOrderEn { + TranslationsErrorsOrderEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Please select a location for your order.' + String get missing_hub => 'Please select a location for your order.'; + + /// en: 'Please select a vendor for your order.' + String get missing_vendor => 'Please select a vendor for your order.'; + + /// en: 'We couldn't create your order. Please try again.' + String get creation_failed => 'We couldn\'t create your order. Please try again.'; + + /// en: 'We couldn't schedule the shift. Please try again.' + String get shift_creation_failed => 'We couldn\'t schedule the shift. Please try again.'; + + /// en: 'Your business profile couldn't be loaded. Please sign in again.' + String get missing_business => 'Your business profile couldn\'t be loaded. Please sign in again.'; +} + +// Path: errors.profile +class TranslationsErrorsProfileEn { + TranslationsErrorsProfileEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Your profile couldn't be loaded. Please sign in again.' + String get staff_not_found => 'Your profile couldn\'t be loaded. Please sign in again.'; + + /// en: 'Your business profile couldn't be loaded. Please sign in again.' + String get business_not_found => 'Your business profile couldn\'t be loaded. Please sign in again.'; + + /// en: 'We couldn't update your profile. Please try again.' + String get update_failed => 'We couldn\'t update your profile. Please try again.'; +} + +// Path: errors.shift +class TranslationsErrorsShiftEn { + TranslationsErrorsShiftEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'There are no open positions available for this shift.' + String get no_open_roles => 'There are no open positions available for this shift.'; + + /// en: 'Your application couldn't be found.' + String get application_not_found => 'Your application couldn\'t be found.'; + + /// en: 'You don't have an active shift to clock out from.' + String get no_active_shift => 'You don\'t have an active shift to clock out from.'; +} + +// Path: errors.generic +class TranslationsErrorsGenericEn { + TranslationsErrorsGenericEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Something went wrong. Please try again.' + String get unknown => 'Something went wrong. Please try again.'; + + /// en: 'No internet connection. Please check your network and try again.' + String get no_connection => 'No internet connection. Please check your network and try again.'; +} + +// Path: success.hub +class TranslationsSuccessHubEn { + TranslationsSuccessHubEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Hub created successfully!' + String get created => 'Hub created successfully!'; + + /// en: 'Hub deleted successfully!' + String get deleted => 'Hub deleted successfully!'; + + /// en: 'NFC tag assigned successfully!' + String get nfc_assigned => 'NFC tag assigned successfully!'; +} + +// Path: success.order +class TranslationsSuccessOrderEn { + TranslationsSuccessOrderEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Order created successfully!' + String get created => 'Order created successfully!'; +} + +// Path: success.profile +class TranslationsSuccessProfileEn { + TranslationsSuccessProfileEn._(this._root); + + final Translations _root; // ignore: unused_field + + // Translations + + /// en: 'Profile updated successfully!' + String get updated => 'Profile updated successfully!'; +} + // Path: staff_authentication.profile_setup_page.steps class TranslationsStaffAuthenticationProfileSetupPageStepsEn { TranslationsStaffAuthenticationProfileSetupPageStepsEn._(this._root); @@ -3216,6 +3422,38 @@ extension on Translations { 'staff_time_card.status.disputed' => 'Disputed', 'staff_time_card.status.paid' => 'Paid', 'staff_time_card.status.pending' => 'Pending', + 'errors.auth.invalid_credentials' => 'The email or password you entered is incorrect.', + 'errors.auth.account_exists' => 'An account with this email already exists. Try signing in instead.', + 'errors.auth.session_expired' => 'Your session has expired. Please sign in again.', + 'errors.auth.user_not_found' => 'We couldn\'t find your account. Please check your email and try again.', + 'errors.auth.unauthorized_app' => 'This account is not authorized for this app.', + 'errors.auth.weak_password' => 'Please choose a stronger password with at least 8 characters.', + 'errors.auth.sign_up_failed' => 'We couldn\'t create your account. Please try again.', + 'errors.auth.sign_in_failed' => 'We couldn\'t sign you in. Please try again.', + 'errors.auth.not_authenticated' => 'Please sign in to continue.', + 'errors.auth.password_mismatch' => 'This email is already registered. Please use the correct password or tap \'Forgot Password\' to reset it.', + 'errors.auth.google_only_account' => 'This email is registered via Google. Please use \'Forgot Password\' to set a password, then try signing up again with the same information.', + 'errors.hub.has_orders' => 'This hub has active orders and cannot be deleted.', + 'errors.hub.not_found' => 'The hub you\'re looking for doesn\'t exist.', + 'errors.hub.creation_failed' => 'We couldn\'t create the hub. Please try again.', + 'errors.order.missing_hub' => 'Please select a location for your order.', + 'errors.order.missing_vendor' => 'Please select a vendor for your order.', + 'errors.order.creation_failed' => 'We couldn\'t create your order. Please try again.', + 'errors.order.shift_creation_failed' => 'We couldn\'t schedule the shift. Please try again.', + 'errors.order.missing_business' => 'Your business profile couldn\'t be loaded. Please sign in again.', + 'errors.profile.staff_not_found' => 'Your profile couldn\'t be loaded. Please sign in again.', + 'errors.profile.business_not_found' => 'Your business profile couldn\'t be loaded. Please sign in again.', + 'errors.profile.update_failed' => 'We couldn\'t update your profile. Please try again.', + 'errors.shift.no_open_roles' => 'There are no open positions available for this shift.', + 'errors.shift.application_not_found' => 'Your application couldn\'t be found.', + 'errors.shift.no_active_shift' => 'You don\'t have an active shift to clock out from.', + 'errors.generic.unknown' => 'Something went wrong. Please try again.', + 'errors.generic.no_connection' => 'No internet connection. Please check your network and try again.', + 'success.hub.created' => 'Hub created successfully!', + 'success.hub.deleted' => 'Hub deleted successfully!', + 'success.hub.nfc_assigned' => 'NFC tag assigned successfully!', + 'success.order.created' => 'Order created successfully!', + 'success.profile.updated' => 'Profile updated successfully!', _ => null, }; } diff --git a/apps/mobile/packages/core_localization/lib/src/l10n/strings_es.g.dart b/apps/mobile/packages/core_localization/lib/src/l10n/strings_es.g.dart index 7dfd4009..6c9c6b03 100644 --- a/apps/mobile/packages/core_localization/lib/src/l10n/strings_es.g.dart +++ b/apps/mobile/packages/core_localization/lib/src/l10n/strings_es.g.dart @@ -54,6 +54,8 @@ class TranslationsEs with BaseTranslations implements T @override late final _TranslationsStaffProfileAttireEs staff_profile_attire = _TranslationsStaffProfileAttireEs._(_root); @override late final _TranslationsStaffShiftsEs staff_shifts = _TranslationsStaffShiftsEs._(_root); @override late final _TranslationsStaffTimeCardEs staff_time_card = _TranslationsStaffTimeCardEs._(_root); + @override late final _TranslationsErrorsEs errors = _TranslationsErrorsEs._(_root); + @override late final _TranslationsSuccessEs success = _TranslationsSuccessEs._(_root); } // Path: common @@ -310,6 +312,33 @@ class _TranslationsStaffTimeCardEs implements TranslationsStaffTimeCardEn { @override late final _TranslationsStaffTimeCardStatusEs status = _TranslationsStaffTimeCardStatusEs._(_root); } +// Path: errors +class _TranslationsErrorsEs implements TranslationsErrorsEn { + _TranslationsErrorsEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override late final _TranslationsErrorsAuthEs auth = _TranslationsErrorsAuthEs._(_root); + @override late final _TranslationsErrorsHubEs hub = _TranslationsErrorsHubEs._(_root); + @override late final _TranslationsErrorsOrderEs order = _TranslationsErrorsOrderEs._(_root); + @override late final _TranslationsErrorsProfileEs profile = _TranslationsErrorsProfileEs._(_root); + @override late final _TranslationsErrorsShiftEs shift = _TranslationsErrorsShiftEs._(_root); + @override late final _TranslationsErrorsGenericEs generic = _TranslationsErrorsGenericEs._(_root); +} + +// Path: success +class _TranslationsSuccessEs implements TranslationsSuccessEn { + _TranslationsSuccessEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override late final _TranslationsSuccessHubEs hub = _TranslationsSuccessHubEs._(_root); + @override late final _TranslationsSuccessOrderEs order = _TranslationsSuccessOrderEs._(_root); + @override late final _TranslationsSuccessProfileEs profile = _TranslationsSuccessProfileEs._(_root); +} + // Path: staff_authentication.get_started_page class _TranslationsStaffAuthenticationGetStartedPageEs implements TranslationsStaffAuthenticationGetStartedPageEn { _TranslationsStaffAuthenticationGetStartedPageEs._(this._root); @@ -1080,6 +1109,119 @@ class _TranslationsStaffTimeCardStatusEs implements TranslationsStaffTimeCardSta @override String get pending => 'Pendiente'; } +// Path: errors.auth +class _TranslationsErrorsAuthEs implements TranslationsErrorsAuthEn { + _TranslationsErrorsAuthEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get invalid_credentials => 'El correo electrónico o la contraseña que ingresaste es incorrecta.'; + @override String get account_exists => 'Ya existe una cuenta con este correo electrónico. Intenta iniciar sesión.'; + @override String get session_expired => 'Tu sesión ha expirado. Por favor, inicia sesión de nuevo.'; + @override String get user_not_found => 'No pudimos encontrar tu cuenta. Por favor, verifica tu correo electrónico e intenta de nuevo.'; + @override String get unauthorized_app => 'Esta cuenta no está autorizada para esta aplicación.'; + @override String get weak_password => 'Por favor, elige una contraseña más segura con al menos 8 caracteres.'; + @override String get sign_up_failed => 'No pudimos crear tu cuenta. Por favor, intenta de nuevo.'; + @override String get sign_in_failed => 'No pudimos iniciar sesión. Por favor, intenta de nuevo.'; + @override String get not_authenticated => 'Por favor, inicia sesión para continuar.'; + @override String get password_mismatch => 'Este correo ya está registrado. Por favor, usa la contraseña correcta o toca \'Olvidé mi contraseña\' para restablecerla.'; + @override String get google_only_account => 'Este correo está registrado con Google. Por favor, usa \'Olvidé mi contraseña\' para establecer una contraseña, luego intenta registrarte de nuevo con la misma información.'; +} + +// Path: errors.hub +class _TranslationsErrorsHubEs implements TranslationsErrorsHubEn { + _TranslationsErrorsHubEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get has_orders => 'Este hub tiene órdenes activas y no puede ser eliminado.'; + @override String get not_found => 'El hub que buscas no existe.'; + @override String get creation_failed => 'No pudimos crear el hub. Por favor, intenta de nuevo.'; +} + +// Path: errors.order +class _TranslationsErrorsOrderEs implements TranslationsErrorsOrderEn { + _TranslationsErrorsOrderEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get missing_hub => 'Por favor, selecciona una ubicación para tu orden.'; + @override String get missing_vendor => 'Por favor, selecciona un proveedor para tu orden.'; + @override String get creation_failed => 'No pudimos crear tu orden. Por favor, intenta de nuevo.'; + @override String get shift_creation_failed => 'No pudimos programar el turno. Por favor, intenta de nuevo.'; + @override String get missing_business => 'No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.'; +} + +// Path: errors.profile +class _TranslationsErrorsProfileEs implements TranslationsErrorsProfileEn { + _TranslationsErrorsProfileEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get staff_not_found => 'No se pudo cargar tu perfil. Por favor, inicia sesión de nuevo.'; + @override String get business_not_found => 'No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.'; + @override String get update_failed => 'No pudimos actualizar tu perfil. Por favor, intenta de nuevo.'; +} + +// Path: errors.shift +class _TranslationsErrorsShiftEs implements TranslationsErrorsShiftEn { + _TranslationsErrorsShiftEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get no_open_roles => 'No hay posiciones abiertas disponibles para este turno.'; + @override String get application_not_found => 'No se pudo encontrar tu solicitud.'; + @override String get no_active_shift => 'No tienes un turno activo para registrar salida.'; +} + +// Path: errors.generic +class _TranslationsErrorsGenericEs implements TranslationsErrorsGenericEn { + _TranslationsErrorsGenericEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get unknown => 'Algo salió mal. Por favor, intenta de nuevo.'; + @override String get no_connection => 'Sin conexión a internet. Por favor, verifica tu red e intenta de nuevo.'; +} + +// Path: success.hub +class _TranslationsSuccessHubEs implements TranslationsSuccessHubEn { + _TranslationsSuccessHubEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get created => '¡Hub creado exitosamente!'; + @override String get deleted => '¡Hub eliminado exitosamente!'; + @override String get nfc_assigned => '¡Etiqueta NFC asignada exitosamente!'; +} + +// Path: success.order +class _TranslationsSuccessOrderEs implements TranslationsSuccessOrderEn { + _TranslationsSuccessOrderEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get created => '¡Orden creada exitosamente!'; +} + +// Path: success.profile +class _TranslationsSuccessProfileEs implements TranslationsSuccessProfileEn { + _TranslationsSuccessProfileEs._(this._root); + + final TranslationsEs _root; // ignore: unused_field + + // Translations + @override String get updated => '¡Perfil actualizado exitosamente!'; +} + // Path: staff_authentication.profile_setup_page.steps class _TranslationsStaffAuthenticationProfileSetupPageStepsEs implements TranslationsStaffAuthenticationProfileSetupPageStepsEn { _TranslationsStaffAuthenticationProfileSetupPageStepsEs._(this._root); @@ -2153,6 +2295,38 @@ extension on TranslationsEs { 'staff_time_card.status.disputed' => 'Disputado', 'staff_time_card.status.paid' => 'Pagado', 'staff_time_card.status.pending' => 'Pendiente', + 'errors.auth.invalid_credentials' => 'El correo electrónico o la contraseña que ingresaste es incorrecta.', + 'errors.auth.account_exists' => 'Ya existe una cuenta con este correo electrónico. Intenta iniciar sesión.', + 'errors.auth.session_expired' => 'Tu sesión ha expirado. Por favor, inicia sesión de nuevo.', + 'errors.auth.user_not_found' => 'No pudimos encontrar tu cuenta. Por favor, verifica tu correo electrónico e intenta de nuevo.', + 'errors.auth.unauthorized_app' => 'Esta cuenta no está autorizada para esta aplicación.', + 'errors.auth.weak_password' => 'Por favor, elige una contraseña más segura con al menos 8 caracteres.', + 'errors.auth.sign_up_failed' => 'No pudimos crear tu cuenta. Por favor, intenta de nuevo.', + 'errors.auth.sign_in_failed' => 'No pudimos iniciar sesión. Por favor, intenta de nuevo.', + 'errors.auth.not_authenticated' => 'Por favor, inicia sesión para continuar.', + 'errors.auth.password_mismatch' => 'Este correo ya está registrado. Por favor, usa la contraseña correcta o toca \'Olvidé mi contraseña\' para restablecerla.', + 'errors.auth.google_only_account' => 'Este correo está registrado con Google. Por favor, usa \'Olvidé mi contraseña\' para establecer una contraseña, luego intenta registrarte de nuevo con la misma información.', + 'errors.hub.has_orders' => 'Este hub tiene órdenes activas y no puede ser eliminado.', + 'errors.hub.not_found' => 'El hub que buscas no existe.', + 'errors.hub.creation_failed' => 'No pudimos crear el hub. Por favor, intenta de nuevo.', + 'errors.order.missing_hub' => 'Por favor, selecciona una ubicación para tu orden.', + 'errors.order.missing_vendor' => 'Por favor, selecciona un proveedor para tu orden.', + 'errors.order.creation_failed' => 'No pudimos crear tu orden. Por favor, intenta de nuevo.', + 'errors.order.shift_creation_failed' => 'No pudimos programar el turno. Por favor, intenta de nuevo.', + 'errors.order.missing_business' => 'No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.', + 'errors.profile.staff_not_found' => 'No se pudo cargar tu perfil. Por favor, inicia sesión de nuevo.', + 'errors.profile.business_not_found' => 'No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.', + 'errors.profile.update_failed' => 'No pudimos actualizar tu perfil. Por favor, intenta de nuevo.', + 'errors.shift.no_open_roles' => 'No hay posiciones abiertas disponibles para este turno.', + 'errors.shift.application_not_found' => 'No se pudo encontrar tu solicitud.', + 'errors.shift.no_active_shift' => 'No tienes un turno activo para registrar salida.', + 'errors.generic.unknown' => 'Algo salió mal. Por favor, intenta de nuevo.', + 'errors.generic.no_connection' => 'Sin conexión a internet. Por favor, verifica tu red e intenta de nuevo.', + 'success.hub.created' => '¡Hub creado exitosamente!', + 'success.hub.deleted' => '¡Hub eliminado exitosamente!', + 'success.hub.nfc_assigned' => '¡Etiqueta NFC asignada exitosamente!', + 'success.order.created' => '¡Orden creada exitosamente!', + 'success.profile.updated' => '¡Perfil actualizado exitosamente!', _ => null, }; } diff --git a/apps/mobile/packages/core_localization/lib/src/utils/error_translator.dart b/apps/mobile/packages/core_localization/lib/src/utils/error_translator.dart new file mode 100644 index 00000000..5e7df68d --- /dev/null +++ b/apps/mobile/packages/core_localization/lib/src/utils/error_translator.dart @@ -0,0 +1,139 @@ +import '../l10n/strings.g.dart'; + +/// Translates error message keys to localized strings. +/// +/// This utility function takes a dot-notation key like 'errors.auth.account_exists' +/// and returns the corresponding localized string from the translation system. +/// +/// If the key is not found or doesn't match the expected format, the original +/// key is returned as a fallback. +/// +/// Example: +/// ```dart +/// final message = translateErrorKey('errors.auth.account_exists'); +/// // Returns: "An account with this email already exists. Try signing in instead." +/// ``` +String translateErrorKey(String key) { + final List parts = key.split('.'); + + // Expected format: errors.{category}.{error_type} + if (parts.length != 3 || parts[0] != 'errors') { + return key; + } + + final String category = parts[1]; + final String errorType = parts[2]; + + switch (category) { + case 'auth': + return _translateAuthError(errorType); + case 'hub': + return _translateHubError(errorType); + case 'order': + return _translateOrderError(errorType); + case 'profile': + return _translateProfileError(errorType); + case 'shift': + return _translateShiftError(errorType); + case 'generic': + return _translateGenericError(errorType); + default: + return key; + } +} + +String _translateAuthError(String errorType) { + switch (errorType) { + case 'invalid_credentials': + return t.errors.auth.invalid_credentials; + case 'account_exists': + return t.errors.auth.account_exists; + case 'session_expired': + return t.errors.auth.session_expired; + case 'user_not_found': + return t.errors.auth.user_not_found; + case 'unauthorized_app': + return t.errors.auth.unauthorized_app; + case 'weak_password': + return t.errors.auth.weak_password; + case 'sign_up_failed': + return t.errors.auth.sign_up_failed; + case 'sign_in_failed': + return t.errors.auth.sign_in_failed; + case 'not_authenticated': + return t.errors.auth.not_authenticated; + case 'password_mismatch': + return t.errors.auth.password_mismatch; + case 'google_only_account': + return t.errors.auth.google_only_account; + default: + return t.errors.generic.unknown; + } +} + +String _translateHubError(String errorType) { + switch (errorType) { + case 'has_orders': + return t.errors.hub.has_orders; + case 'not_found': + return t.errors.hub.not_found; + case 'creation_failed': + return t.errors.hub.creation_failed; + default: + return t.errors.generic.unknown; + } +} + +String _translateOrderError(String errorType) { + switch (errorType) { + case 'missing_hub': + return t.errors.order.missing_hub; + case 'missing_vendor': + return t.errors.order.missing_vendor; + case 'creation_failed': + return t.errors.order.creation_failed; + case 'shift_creation_failed': + return t.errors.order.shift_creation_failed; + case 'missing_business': + return t.errors.order.missing_business; + default: + return t.errors.generic.unknown; + } +} + +String _translateProfileError(String errorType) { + switch (errorType) { + case 'staff_not_found': + return t.errors.profile.staff_not_found; + case 'business_not_found': + return t.errors.profile.business_not_found; + case 'update_failed': + return t.errors.profile.update_failed; + default: + return t.errors.generic.unknown; + } +} + +String _translateShiftError(String errorType) { + switch (errorType) { + case 'no_open_roles': + return t.errors.shift.no_open_roles; + case 'application_not_found': + return t.errors.shift.application_not_found; + case 'no_active_shift': + return t.errors.shift.no_active_shift; + default: + return t.errors.generic.unknown; + } +} + +String _translateGenericError(String errorType) { + switch (errorType) { + case 'unknown': + return t.errors.generic.unknown; + case 'no_connection': + return t.errors.generic.no_connection; + default: + return t.errors.generic.unknown; + } +} diff --git a/apps/mobile/packages/domain/lib/krow_domain.dart b/apps/mobile/packages/domain/lib/krow_domain.dart index df3a825c..fc763e64 100644 --- a/apps/mobile/packages/domain/lib/krow_domain.dart +++ b/apps/mobile/packages/domain/lib/krow_domain.dart @@ -94,3 +94,6 @@ export 'src/entities/profile/experience_skill.dart'; export 'src/adapters/profile/bank_account_adapter.dart'; export 'src/adapters/profile/tax_form_adapter.dart'; export 'src/adapters/financial/payment_adapter.dart'; + +// Exceptions +export 'src/exceptions/app_exception.dart'; diff --git a/apps/mobile/packages/domain/lib/src/exceptions/app_exception.dart b/apps/mobile/packages/domain/lib/src/exceptions/app_exception.dart new file mode 100644 index 00000000..bf9ae481 --- /dev/null +++ b/apps/mobile/packages/domain/lib/src/exceptions/app_exception.dart @@ -0,0 +1,314 @@ +/// Base sealed class for all application exceptions. +/// +/// Provides type-safe error handling with user-friendly message keys. +/// Technical details are captured for logging but never shown to users. +sealed class AppException implements Exception { + const AppException({ + required this.code, + this.technicalMessage, + }); + + /// Unique error code for logging/tracking (e.g., "AUTH_001") + final String code; + + /// Technical details for developers (never shown to users) + final String? technicalMessage; + + /// Returns the localization key for user-friendly message + String get messageKey; + + @override + String toString() => 'AppException($code): $technicalMessage'; +} + +// ============================================================ +// AUTH EXCEPTIONS +// ============================================================ + +/// Base class for authentication-related exceptions. +sealed class AuthException extends AppException { + const AuthException({required super.code, super.technicalMessage}); +} + +/// Thrown when email/password combination is incorrect. +class InvalidCredentialsException extends AuthException { + const InvalidCredentialsException({String? technicalMessage}) + : super(code: 'AUTH_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.invalid_credentials'; +} + +/// Thrown when attempting to register with an email that already exists. +class AccountExistsException extends AuthException { + const AccountExistsException({String? technicalMessage}) + : super(code: 'AUTH_002', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.account_exists'; +} + +/// Thrown when the user session has expired. +class SessionExpiredException extends AuthException { + const SessionExpiredException({String? technicalMessage}) + : super(code: 'AUTH_003', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.session_expired'; +} + +/// Thrown when user profile is not found in database after Firebase auth. +class UserNotFoundException extends AuthException { + const UserNotFoundException({String? technicalMessage}) + : super(code: 'AUTH_004', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.user_not_found'; +} + +/// Thrown when user is not authorized for the current app (wrong role). +class UnauthorizedAppException extends AuthException { + const UnauthorizedAppException({String? technicalMessage}) + : super(code: 'AUTH_005', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.unauthorized_app'; +} + +/// Thrown when password doesn't meet security requirements. +class WeakPasswordException extends AuthException { + const WeakPasswordException({String? technicalMessage}) + : super(code: 'AUTH_006', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.weak_password'; +} + +/// Thrown when sign-up process fails. +class SignUpFailedException extends AuthException { + const SignUpFailedException({String? technicalMessage}) + : super(code: 'AUTH_007', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.sign_up_failed'; +} + +/// Thrown when sign-in process fails. +class SignInFailedException extends AuthException { + const SignInFailedException({String? technicalMessage}) + : super(code: 'AUTH_008', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.sign_in_failed'; +} + +/// Thrown when email exists but password doesn't match. +class PasswordMismatchException extends AuthException { + const PasswordMismatchException({String? technicalMessage}) + : super(code: 'AUTH_009', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.password_mismatch'; +} + +/// Thrown when account exists only with Google provider (no password). +class GoogleOnlyAccountException extends AuthException { + const GoogleOnlyAccountException({String? technicalMessage}) + : super(code: 'AUTH_010', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.google_only_account'; +} + +// ============================================================ +// HUB EXCEPTIONS +// ============================================================ + +/// Base class for hub-related exceptions. +sealed class HubException extends AppException { + const HubException({required super.code, super.technicalMessage}); +} + +/// Thrown when attempting to delete a hub that has active orders. +class HubHasOrdersException extends HubException { + const HubHasOrdersException({String? technicalMessage}) + : super(code: 'HUB_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.hub.has_orders'; +} + +/// Thrown when hub is not found. +class HubNotFoundException extends HubException { + const HubNotFoundException({String? technicalMessage}) + : super(code: 'HUB_002', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.hub.not_found'; +} + +/// Thrown when hub creation fails. +class HubCreationFailedException extends HubException { + const HubCreationFailedException({String? technicalMessage}) + : super(code: 'HUB_003', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.hub.creation_failed'; +} + +// ============================================================ +// ORDER EXCEPTIONS +// ============================================================ + +/// Base class for order-related exceptions. +sealed class OrderException extends AppException { + const OrderException({required super.code, super.technicalMessage}); +} + +/// Thrown when order creation is attempted without a hub. +class OrderMissingHubException extends OrderException { + const OrderMissingHubException({String? technicalMessage}) + : super(code: 'ORDER_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.order.missing_hub'; +} + +/// Thrown when order creation is attempted without a vendor. +class OrderMissingVendorException extends OrderException { + const OrderMissingVendorException({String? technicalMessage}) + : super(code: 'ORDER_002', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.order.missing_vendor'; +} + +/// Thrown when order creation fails. +class OrderCreationFailedException extends OrderException { + const OrderCreationFailedException({String? technicalMessage}) + : super(code: 'ORDER_003', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.order.creation_failed'; +} + +/// Thrown when shift creation fails. +class ShiftCreationFailedException extends OrderException { + const ShiftCreationFailedException({String? technicalMessage}) + : super(code: 'ORDER_004', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.order.shift_creation_failed'; +} + +/// Thrown when order is missing required business context. +class OrderMissingBusinessException extends OrderException { + const OrderMissingBusinessException({String? technicalMessage}) + : super(code: 'ORDER_005', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.order.missing_business'; +} + +// ============================================================ +// PROFILE EXCEPTIONS +// ============================================================ + +/// Base class for profile-related exceptions. +sealed class ProfileException extends AppException { + const ProfileException({required super.code, super.technicalMessage}); +} + +/// Thrown when staff profile is not found. +class StaffProfileNotFoundException extends ProfileException { + const StaffProfileNotFoundException({String? technicalMessage}) + : super(code: 'PROFILE_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.profile.staff_not_found'; +} + +/// Thrown when business profile is not found. +class BusinessNotFoundException extends ProfileException { + const BusinessNotFoundException({String? technicalMessage}) + : super(code: 'PROFILE_002', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.profile.business_not_found'; +} + +/// Thrown when profile update fails. +class ProfileUpdateFailedException extends ProfileException { + const ProfileUpdateFailedException({String? technicalMessage}) + : super(code: 'PROFILE_003', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.profile.update_failed'; +} + +// ============================================================ +// SHIFT EXCEPTIONS +// ============================================================ + +/// Base class for shift-related exceptions. +sealed class ShiftException extends AppException { + const ShiftException({required super.code, super.technicalMessage}); +} + +/// Thrown when no open roles are available for a shift. +class NoOpenRolesException extends ShiftException { + const NoOpenRolesException({String? technicalMessage}) + : super(code: 'SHIFT_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.shift.no_open_roles'; +} + +/// Thrown when application for shift is not found. +class ApplicationNotFoundException extends ShiftException { + const ApplicationNotFoundException({String? technicalMessage}) + : super(code: 'SHIFT_002', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.shift.application_not_found'; +} + +/// Thrown when no active shift is found for clock out. +class NoActiveShiftException extends ShiftException { + const NoActiveShiftException({String? technicalMessage}) + : super(code: 'SHIFT_003', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.shift.no_active_shift'; +} + +// ============================================================ +// NETWORK/GENERIC EXCEPTIONS +// ============================================================ + +/// Thrown when there is no network connection. +class NetworkException extends AppException { + const NetworkException({String? technicalMessage}) + : super(code: 'NET_001', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.generic.no_connection'; +} + +/// Thrown when an unexpected error occurs. +class UnknownException extends AppException { + const UnknownException({String? technicalMessage}) + : super(code: 'UNKNOWN', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.generic.unknown'; +} + +/// Thrown when user is not authenticated. +class NotAuthenticatedException extends AppException { + const NotAuthenticatedException({String? technicalMessage}) + : super(code: 'AUTH_NOT_LOGGED', technicalMessage: technicalMessage); + + @override + String get messageKey => 'errors.auth.not_authenticated'; +} diff --git a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart index c6831eee..43674a96 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/data/repositories_impl/auth_repository_impl.dart @@ -1,7 +1,20 @@ +import 'dart:developer' as developer; + import 'package:firebase_auth/firebase_auth.dart' as firebase; import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:krow_data_connect/krow_data_connect.dart' as dc; import 'package:krow_domain/krow_domain.dart' as domain; +import 'package:krow_domain/krow_domain.dart' + show + InvalidCredentialsException, + SignInFailedException, + SignUpFailedException, + WeakPasswordException, + AccountExistsException, + UserNotFoundException, + UnauthorizedAppException, + PasswordMismatchException, + GoogleOnlyAccountException; import '../../domain/repositories/auth_repository_interface.dart'; @@ -33,7 +46,9 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { final firebase.User? firebaseUser = credential.user; if (firebaseUser == null) { - throw Exception('Sign-in failed, no Firebase user received.'); + throw const SignInFailedException( + technicalMessage: 'No Firebase user received after sign-in', + ); } return _getUserProfile( @@ -44,12 +59,20 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { } on firebase.FirebaseAuthException catch (e) { if (e.code == 'invalid-credential' || e.code == 'wrong-password') { - throw Exception('Incorrect email or password.'); + throw InvalidCredentialsException( + technicalMessage: 'Firebase error code: ${e.code}', + ); } else { - throw Exception('Authentication error: ${e.message}'); + throw SignInFailedException( + technicalMessage: 'Firebase auth error: ${e.message}', + ); } + } on domain.AppException { + rethrow; } catch (e) { - throw Exception('Failed to sign in and fetch user data: ${e.toString()}'); + throw SignInFailedException( + technicalMessage: 'Unexpected error: $e', + ); } } @@ -59,63 +82,225 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { required String email, required String password, }) async { + firebase.User? firebaseUser; + String? createdBusinessId; + try { + // Step 1: Try to create Firebase Auth user final firebase.UserCredential credential = await _firebaseAuth.createUserWithEmailAndPassword( email: email, password: password, ); + firebaseUser = credential.user; + if (firebaseUser == null) { + throw const SignUpFailedException( + technicalMessage: 'Firebase user could not be created', + ); + } + + // New user created successfully, proceed to create PostgreSQL entities + return await _createBusinessAndUser( + firebaseUser: firebaseUser, + companyName: companyName, + email: email, + onBusinessCreated: (String businessId) => createdBusinessId = businessId, + ); + + } on firebase.FirebaseAuthException catch (e) { + if (e.code == 'weak-password') { + throw WeakPasswordException( + technicalMessage: 'Firebase: ${e.message}', + ); + } else if (e.code == 'email-already-in-use') { + // Email exists in Firebase Auth - try to sign in and complete registration + return await _handleExistingFirebaseAccount( + email: email, + password: password, + companyName: companyName, + ); + } else { + throw SignUpFailedException( + technicalMessage: 'Firebase auth error: ${e.message}', + ); + } + } on domain.AppException { + // Rollback for our known exceptions + await _rollbackSignUp(firebaseUser: firebaseUser, businessId: createdBusinessId); + rethrow; + } catch (e) { + // Rollback: Clean up any partially created resources + await _rollbackSignUp(firebaseUser: firebaseUser, businessId: createdBusinessId); + throw SignUpFailedException( + technicalMessage: 'Unexpected error: $e', + ); + } + } + + /// Handles the case where email already exists in Firebase Auth. + /// + /// This can happen when: + /// 1. User signed up with Google in another app sharing the same Firebase project + /// 2. User already has a KROW account + /// + /// The flow: + /// 1. Try to sign in with provided password + /// 2. If sign-in succeeds, check if BUSINESS user exists in PostgreSQL + /// 3. If not, create Business + User (user is new to KROW) + /// 4. If yes, they already have a KROW account + Future _handleExistingFirebaseAccount({ + required String email, + required String password, + required String companyName, + }) async { + developer.log('Email exists in Firebase, attempting sign-in: $email', name: 'AuthRepository'); + + try { + // Try to sign in with the provided password + final firebase.UserCredential credential = await _firebaseAuth.signInWithEmailAndPassword( + email: email, + password: password, + ); + final firebase.User? firebaseUser = credential.user; if (firebaseUser == null) { - throw Exception('Sign-up failed, Firebase user could not be created.'); + throw const SignUpFailedException( + technicalMessage: 'Sign-in succeeded but no user returned', + ); } - // Client-specific business logic: - // 1. Create a `Business` entity. - // 2. Create a `User` entity associated with the business. - final OperationResult createBusinessResponse = await _dataConnect.createBusiness( - businessName: companyName, - userId: firebaseUser.uid, - rateGroup: dc.BusinessRateGroup.STANDARD, - status: dc.BusinessStatus.PENDING, - ).execute(); + // Sign-in succeeded! Check if user already has a BUSINESS account in PostgreSQL + final bool hasBusinessAccount = await _checkBusinessUserExists(firebaseUser.uid); - final dc.CreateBusinessBusinessInsert? businessData = createBusinessResponse.data?.business_insert; - if (businessData == null) { - await firebaseUser.delete(); // Rollback if business creation fails - throw Exception('Business creation failed after Firebase user registration.'); + if (hasBusinessAccount) { + // User already has a KROW Client account + developer.log('User already has BUSINESS account: ${firebaseUser.uid}', name: 'AuthRepository'); + throw AccountExistsException( + technicalMessage: 'User ${firebaseUser.uid} already has BUSINESS role', + ); } - final OperationResult createUserResponse = await _dataConnect.createUser( - id: firebaseUser.uid, - role: dc.UserBaseRole.USER, - ) - .email(email) - .userRole('BUSINESS') - .execute(); - - final dc.CreateUserUserInsert? newUserData = createUserResponse.data?.user_insert; - if (newUserData == null) { - await firebaseUser.delete(); // Rollback if user profile creation fails - // TO-DO: Also delete the created Business if this fails - throw Exception('User profile creation failed after Firebase user registration.'); - } - - return _getUserProfile( - firebaseUserId: firebaseUser.uid, - fallbackEmail: firebaseUser.email ?? email, + // User exists in Firebase but not in KROW PostgreSQL - create the entities + developer.log('Creating BUSINESS account for existing Firebase user: ${firebaseUser.uid}', name: 'AuthRepository'); + return await _createBusinessAndUser( + firebaseUser: firebaseUser, + companyName: companyName, + email: email, + onBusinessCreated: (_) {}, // No rollback needed for existing Firebase user ); } on firebase.FirebaseAuthException catch (e) { - if (e.code == 'weak-password') { - throw Exception('The password provided is too weak.'); - } else if (e.code == 'email-already-in-use') { - throw Exception('An account already exists for that email address.'); + // Sign-in failed - check why + developer.log('Sign-in failed with code: ${e.code}', name: 'AuthRepository'); + + if (e.code == 'wrong-password' || e.code == 'invalid-credential') { + // Password doesn't match - check what providers are available + return await _handlePasswordMismatch(email); } else { - throw Exception('Sign-up error: ${e.message}'); + throw SignUpFailedException( + technicalMessage: 'Firebase sign-in error: ${e.message}', + ); } + } on domain.AppException { + rethrow; + } + } + + /// Handles the case where the password doesn't match the existing account. + /// + /// Note: fetchSignInMethodsForEmail was deprecated by Firebase for security + /// reasons (email enumeration). We show a combined message that covers both + /// cases: wrong password OR account uses different sign-in method (Google). + Future _handlePasswordMismatch(String email) async { + // We can't distinguish between "wrong password" and "no password provider" + // due to Firebase deprecating fetchSignInMethodsForEmail. + // The PasswordMismatchException message covers both scenarios. + developer.log('Password mismatch or different provider for: $email', name: 'AuthRepository'); + throw PasswordMismatchException( + technicalMessage: 'Email $email: password mismatch or different auth provider', + ); + } + + /// Checks if a user with BUSINESS role exists in PostgreSQL. + Future _checkBusinessUserExists(String firebaseUserId) async { + try { + final QueryResult response = + await _dataConnect.getUserById(id: firebaseUserId).execute(); + final dc.GetUserByIdUser? user = response.data?.user; + return user != null && user.userRole == 'BUSINESS'; } catch (e) { - throw Exception('Failed to sign up and create user data: ${e.toString()}'); + developer.log('Error checking business user: $e', name: 'AuthRepository'); + return false; + } + } + + /// Creates Business and User entities in PostgreSQL for a Firebase user. + Future _createBusinessAndUser({ + required firebase.User firebaseUser, + required String companyName, + required String email, + required void Function(String businessId) onBusinessCreated, + }) async { + // Create Business entity in PostgreSQL + final OperationResult createBusinessResponse = + await _dataConnect.createBusiness( + businessName: companyName, + userId: firebaseUser.uid, + rateGroup: dc.BusinessRateGroup.STANDARD, + status: dc.BusinessStatus.PENDING, + ).execute(); + + final dc.CreateBusinessBusinessInsert? businessData = createBusinessResponse.data?.business_insert; + if (businessData == null) { + throw const SignUpFailedException( + technicalMessage: 'Business creation failed in PostgreSQL', + ); + } + onBusinessCreated(businessData.id); + + // Create User entity in PostgreSQL + final OperationResult createUserResponse = + await _dataConnect.createUser( + id: firebaseUser.uid, + role: dc.UserBaseRole.USER, + ) + .email(email) + .userRole('BUSINESS') + .execute(); + + final dc.CreateUserUserInsert? newUserData = createUserResponse.data?.user_insert; + if (newUserData == null) { + throw const SignUpFailedException( + technicalMessage: 'User profile creation failed in PostgreSQL', + ); + } + + return _getUserProfile( + firebaseUserId: firebaseUser.uid, + fallbackEmail: firebaseUser.email ?? email, + ); + } + + /// Rollback helper to clean up partially created resources during sign-up. + Future _rollbackSignUp({ + firebase.User? firebaseUser, + String? businessId, + }) async { + // Delete business first (if created) + if (businessId != null) { + try { + await _dataConnect.deleteBusiness(id: businessId).execute(); + } catch (_) { + // Log but don't throw - we're already in error recovery + } + } + // Delete Firebase user (if created) + if (firebaseUser != null) { + try { + await firebaseUser.delete(); + } catch (_) { + // Log but don't throw - we're already in error recovery + } } } @@ -142,17 +327,23 @@ class AuthRepositoryImpl implements AuthRepositoryInterface { final QueryResult response = await _dataConnect.getUserById(id: firebaseUserId).execute(); final dc.GetUserByIdUser? user = response.data?.user; if (user == null) { - throw Exception('Authenticated user profile not found in database.'); + throw UserNotFoundException( + technicalMessage: 'Firebase UID $firebaseUserId not found in users table', + ); } if (requireBusinessRole && user.userRole != 'BUSINESS') { await _firebaseAuth.signOut(); dc.ClientSessionStore.instance.clear(); - throw Exception('User is not authorized for this app.'); + throw UnauthorizedAppException( + technicalMessage: 'User role is ${user.userRole}, expected BUSINESS', + ); } final String? email = user.email ?? fallbackEmail; if (email == null || email.isEmpty) { - throw Exception('User email is missing in profile data.'); + throw UserNotFoundException( + technicalMessage: 'User email missing for UID $firebaseUserId', + ); } final domain.User domainUser = domain.User( diff --git a/apps/mobile/packages/features/client/authentication/lib/src/presentation/blocs/client_auth_bloc.dart b/apps/mobile/packages/features/client/authentication/lib/src/presentation/blocs/client_auth_bloc.dart index e1c39429..b264922c 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/presentation/blocs/client_auth_bloc.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/presentation/blocs/client_auth_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:developer' as developer; + import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:krow_domain/krow_domain.dart'; @@ -56,11 +58,20 @@ class ClientAuthBloc extends Bloc { SignInWithEmailArguments(email: event.email, password: event.password), ); emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user)); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc'); emit( state.copyWith( status: ClientAuthStatus.error, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientAuthBloc'); + emit( + state.copyWith( + status: ClientAuthStatus.error, + errorMessage: 'errors.generic.unknown', ), ); } @@ -81,11 +92,20 @@ class ClientAuthBloc extends Bloc { ), ); emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user)); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc'); emit( state.copyWith( status: ClientAuthStatus.error, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientAuthBloc'); + emit( + state.copyWith( + status: ClientAuthStatus.error, + errorMessage: 'errors.generic.unknown', ), ); } @@ -102,11 +122,20 @@ class ClientAuthBloc extends Bloc { SignInWithSocialArguments(provider: event.provider), ); emit(state.copyWith(status: ClientAuthStatus.authenticated, user: user)); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc'); emit( state.copyWith( status: ClientAuthStatus.error, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientAuthBloc'); + emit( + state.copyWith( + status: ClientAuthStatus.error, + errorMessage: 'errors.generic.unknown', ), ); } @@ -121,11 +150,20 @@ class ClientAuthBloc extends Bloc { try { await _signOut(); emit(state.copyWith(status: ClientAuthStatus.signedOut, user: null)); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientAuthBloc'); emit( state.copyWith( status: ClientAuthStatus.error, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientAuthBloc'); + emit( + state.copyWith( + status: ClientAuthStatus.error, + errorMessage: 'errors.generic.unknown', ), ); } diff --git a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_in_page.dart b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_in_page.dart index 6bde0059..33df7cbe 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_in_page.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_in_page.dart @@ -45,10 +45,11 @@ class ClientSignInPage extends StatelessWidget { if (state.status == ClientAuthStatus.authenticated) { Modular.to.navigateClientHome(); } else if (state.status == ClientAuthStatus.error) { + final String errorMessage = state.errorMessage != null + ? translateErrorKey(state.errorMessage!) + : t.errors.generic.unknown; ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage ?? 'Authentication Error'), - ), + SnackBar(content: Text(errorMessage)), ); } }, diff --git a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_up_page.dart b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_up_page.dart index 0df74969..2453b486 100644 --- a/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_up_page.dart +++ b/apps/mobile/packages/features/client/authentication/lib/src/presentation/pages/client_sign_up_page.dart @@ -49,10 +49,11 @@ class ClientSignUpPage extends StatelessWidget { if (state.status == ClientAuthStatus.authenticated) { Modular.to.navigateClientHome(); } else if (state.status == ClientAuthStatus.error) { + final String errorMessage = state.errorMessage != null + ? translateErrorKey(state.errorMessage!) + : t.errors.generic.unknown; ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text(state.errorMessage ?? 'Authentication Error'), - ), + SnackBar(content: Text(errorMessage)), ); } }, diff --git a/apps/mobile/packages/features/client/billing/lib/src/billing_module.dart b/apps/mobile/packages/features/client/billing/lib/src/billing_module.dart index c45991ae..2a7f9677 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/billing_module.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/billing_module.dart @@ -15,6 +15,9 @@ import 'presentation/pages/billing_page.dart'; class BillingModule extends Module { @override void binds(Injector i) { + // Mock repositories (TODO: Replace with real implementations) + i.addSingleton(FinancialRepositoryMock.new); + // Repositories i.addSingleton( () => BillingRepositoryImpl( diff --git a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/billing_page.dart b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/billing_page.dart index 2a5774a7..825917ff 100644 --- a/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/billing_page.dart +++ b/apps/mobile/packages/features/client/billing/lib/src/presentation/pages/billing_page.dart @@ -83,7 +83,7 @@ class _BillingViewState extends State { leading: Center( child: UiIconButton.secondary( icon: UiIcons.arrowLeft, - onTap: () => Modular.to.pop(), + onTap: () => Modular.to.navigate('/client-main/home/'), ), ), title: AnimatedSwitcher( diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/pages/coverage_page.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/pages/coverage_page.dart index e10f7432..52f5388f 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/pages/coverage_page.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/pages/coverage_page.dart @@ -68,7 +68,7 @@ class _CoveragePageState extends State { expandedHeight: 300.0, backgroundColor: UiColors.primary, leading: IconButton( - onPressed: () => Modular.to.pop(), + onPressed: () => Modular.to.navigate('/client-main/home/'), icon: Container( padding: const EdgeInsets.all(UiConstants.space2), decoration: BoxDecoration( diff --git a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart index 6c9513bb..f346e8fd 100644 --- a/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart +++ b/apps/mobile/packages/features/client/client_coverage/lib/src/presentation/widgets/coverage_header.dart @@ -67,7 +67,7 @@ class CoverageHeader extends StatelessWidget { Row( children: [ GestureDetector( - onTap: () => Modular.to.pop(), + onTap: () => Modular.to.navigate('/client-main/home/'), child: Container( width: UiConstants.space10, height: UiConstants.space10, diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/permanent_order_page.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/permanent_order_page.dart index fd38a142..fae4d2d1 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/permanent_order_page.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/permanent_order_page.dart @@ -18,7 +18,7 @@ class PermanentOrderPage extends StatelessWidget { backgroundColor: UiColors.bgPrimary, appBar: UiAppBar( title: labels.title, - onLeadingPressed: () => Modular.to.pop(), + onLeadingPressed: () => Modular.to.navigate('/client/create-order/'), ), body: Center( child: Padding( diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/recurring_order_page.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/recurring_order_page.dart index 64324b46..2f15cf70 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/recurring_order_page.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/pages/recurring_order_page.dart @@ -18,7 +18,7 @@ class RecurringOrderPage extends StatelessWidget { backgroundColor: UiColors.bgPrimary, appBar: UiAppBar( title: labels.title, - onLeadingPressed: () => Modular.to.pop(), + onLeadingPressed: () => Modular.to.navigate('/client/create-order/'), ), body: Center( child: Padding( diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/create_order/create_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/create_order/create_order_view.dart index eb1775fb..290165fc 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/create_order/create_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/create_order/create_order_view.dart @@ -43,7 +43,7 @@ class CreateOrderView extends StatelessWidget { backgroundColor: UiColors.bgPrimary, appBar: UiAppBar( title: t.client_create_order.title, - onLeadingPressed: () => Modular.to.pop(), + onLeadingPressed: () => Modular.to.navigate('/client-main/home/'), ), body: SafeArea( child: Padding( diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_view.dart index ed81e3f0..895c4ce1 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/one_time_order/one_time_order_view.dart @@ -50,7 +50,7 @@ class OneTimeOrderView extends StatelessWidget { OneTimeOrderHeader( title: labels.title, subtitle: labels.subtitle, - onBack: () => Modular.to.pop(), + onBack: () => Modular.to.navigate('/client/create-order/'), ), Expanded( child: Center( @@ -89,7 +89,7 @@ class OneTimeOrderView extends StatelessWidget { OneTimeOrderHeader( title: labels.title, subtitle: labels.subtitle, - onBack: () => Modular.to.pop(), + onBack: () => Modular.to.navigate('/client/create-order/'), ), Expanded( child: Stack( diff --git a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart index 093ec39d..95713729 100644 --- a/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart +++ b/apps/mobile/packages/features/client/create_order/lib/src/presentation/widgets/rapid_order/rapid_order_view.dart @@ -28,7 +28,7 @@ class RapidOrderView extends StatelessWidget { title: labels.success_title, message: labels.success_message, buttonLabel: labels.back_to_orders, - onDone: () => Modular.to.pop(), + onDone: () => Modular.to.navigate('/client-main/orders/'), ); } @@ -82,7 +82,7 @@ class _RapidOrderFormState extends State<_RapidOrderForm> { subtitle: labels.subtitle, date: dateStr, time: timeStr, - onBack: () => Modular.to.pop(), + onBack: () => Modular.to.navigate('/client/create-order/'), ), // Content diff --git a/apps/mobile/packages/features/client/hubs/lib/src/data/repositories_impl/hub_repository_impl.dart b/apps/mobile/packages/features/client/hubs/lib/src/data/repositories_impl/hub_repository_impl.dart index fdfec83d..45b8b8f8 100644 --- a/apps/mobile/packages/features/client/hubs/lib/src/data/repositories_impl/hub_repository_impl.dart +++ b/apps/mobile/packages/features/client/hubs/lib/src/data/repositories_impl/hub_repository_impl.dart @@ -5,6 +5,12 @@ import 'package:firebase_data_connect/firebase_data_connect.dart'; import 'package:http/http.dart' as http; import 'package:krow_data_connect/krow_data_connect.dart' as dc; import 'package:krow_domain/krow_domain.dart' as domain; +import 'package:krow_domain/krow_domain.dart' + show + HubHasOrdersException, + HubCreationFailedException, + BusinessNotFoundException, + NotAuthenticatedException; import '../../domain/repositories/hub_repository_interface.dart'; import '../../util/hubs_constants.dart'; @@ -67,7 +73,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { .execute(); final String? createdId = result.data?.teamHub_insert.id; if (createdId == null) { - throw Exception('Hub creation failed.'); + throw HubCreationFailedException( + technicalMessage: 'teamHub_insert returned null for hub: $name', + ); } final List hubs = await _fetchHubsForTeam( @@ -97,7 +105,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { final String? businessId = dc.ClientSessionStore.instance.session?.business?.id; if (businessId == null || businessId.isEmpty) { await _firebaseAuth.signOut(); - throw Exception('Business is missing. Please sign in again.'); + throw const BusinessNotFoundException( + technicalMessage: 'Business ID missing from session', + ); } final QueryResult< @@ -110,7 +120,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { .execute(); if (result.data.orders.isNotEmpty) { - throw Exception("Sorry this hub has orders, it can't be deleted."); + throw HubHasOrdersException( + technicalMessage: 'Hub $id has ${result.data.orders.length} orders', + ); } await _dataConnect.deleteTeamHub(id: id).execute(); @@ -151,7 +163,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { final firebase.User? user = _firebaseAuth.currentUser; if (user == null) { - throw Exception('User is not authenticated.'); + throw const NotAuthenticatedException( + technicalMessage: 'No Firebase user in currentUser', + ); } final QueryResult result = await _dataConnect.getBusinessesByUserId( @@ -159,7 +173,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { ).execute(); if (result.data.businesses.isEmpty) { await _firebaseAuth.signOut(); - throw Exception('No business found for this user. Please sign in again.'); + throw BusinessNotFoundException( + technicalMessage: 'No business found for user ${user.uid}', + ); } final dc.GetBusinessesByUserIdBusinesses business = result.data.businesses.first; @@ -206,7 +222,9 @@ class HubRepositoryImpl implements HubRepositoryInterface { final OperationResult createTeamResult = await createTeamBuilder.execute(); final String? teamId = createTeamResult.data?.team_insert.id; if (teamId == null) { - throw Exception('Team creation failed.'); + throw HubCreationFailedException( + technicalMessage: 'Team creation failed for business ${business.id}', + ); } return teamId; diff --git a/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_bloc.dart b/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_bloc.dart index 2359f296..becc3e8c 100644 --- a/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_bloc.dart +++ b/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:developer' as developer; + import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_modular/flutter_modular.dart'; import 'package:krow_domain/krow_domain.dart'; @@ -67,11 +69,20 @@ class ClientHubsBloc extends Bloc try { final List hubs = await _getHubsUseCase(); emit(state.copyWith(status: ClientHubsStatus.success, hubs: hubs)); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientHubsBloc'); emit( state.copyWith( status: ClientHubsStatus.failure, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientHubsBloc'); + emit( + state.copyWith( + status: ClientHubsStatus.failure, + errorMessage: 'errors.generic.unknown', ), ); } @@ -106,11 +117,20 @@ class ClientHubsBloc extends Bloc showAddHubDialog: false, ), ); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientHubsBloc'); emit( state.copyWith( status: ClientHubsStatus.actionFailure, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientHubsBloc'); + emit( + state.copyWith( + status: ClientHubsStatus.actionFailure, + errorMessage: 'errors.generic.unknown', ), ); } @@ -131,11 +151,20 @@ class ClientHubsBloc extends Bloc successMessage: 'Hub deleted successfully', ), ); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientHubsBloc'); emit( state.copyWith( status: ClientHubsStatus.actionFailure, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientHubsBloc'); + emit( + state.copyWith( + status: ClientHubsStatus.actionFailure, + errorMessage: 'errors.generic.unknown', ), ); } @@ -159,11 +188,20 @@ class ClientHubsBloc extends Bloc clearHubToIdentify: true, ), ); - } catch (e) { + } on AppException catch (e) { + developer.log('Error ${e.code}: ${e.technicalMessage}', name: 'ClientHubsBloc'); emit( state.copyWith( status: ClientHubsStatus.actionFailure, - errorMessage: e.toString(), + errorMessage: e.messageKey, + ), + ); + } catch (e) { + developer.log('Unexpected error: $e', name: 'ClientHubsBloc'); + emit( + state.copyWith( + status: ClientHubsStatus.actionFailure, + errorMessage: 'errors.generic.unknown', ), ); } @@ -175,8 +213,8 @@ class ClientHubsBloc extends Bloc ) { emit( state.copyWith( - errorMessage: null, - successMessage: null, + clearErrorMessage: true, + clearSuccessMessage: true, status: state.status == ClientHubsStatus.actionSuccess || state.status == ClientHubsStatus.actionFailure diff --git a/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_state.dart b/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_state.dart index efccca99..4d592df8 100644 --- a/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_state.dart +++ b/apps/mobile/packages/features/client/hubs/lib/src/presentation/blocs/client_hubs_state.dart @@ -43,12 +43,18 @@ class ClientHubsState extends Equatable { bool? showAddHubDialog, Hub? hubToIdentify, bool clearHubToIdentify = false, + bool clearErrorMessage = false, + bool clearSuccessMessage = false, }) { return ClientHubsState( status: status ?? this.status, hubs: hubs ?? this.hubs, - errorMessage: errorMessage ?? this.errorMessage, - successMessage: successMessage ?? this.successMessage, + errorMessage: clearErrorMessage + ? null + : (errorMessage ?? this.errorMessage), + successMessage: clearSuccessMessage + ? null + : (successMessage ?? this.successMessage), showAddHubDialog: showAddHubDialog ?? this.showAddHubDialog, hubToIdentify: clearHubToIdentify ? null diff --git a/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart b/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart index 76d7c8cd..85f60930 100644 --- a/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart +++ b/apps/mobile/packages/features/client/hubs/lib/src/presentation/pages/client_hubs_page.dart @@ -33,9 +33,10 @@ class ClientHubsPage extends StatelessWidget { }, listener: (BuildContext context, ClientHubsState state) { if (state.errorMessage != null && state.errorMessage!.isNotEmpty) { - ScaffoldMessenger.of( - context, - ).showSnackBar(SnackBar(content: Text(state.errorMessage!))); + final String errorMessage = translateErrorKey(state.errorMessage!); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(errorMessage)), + ); BlocProvider.of( context, ).add(const ClientHubsMessageCleared()); @@ -178,7 +179,7 @@ class ClientHubsPage extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ GestureDetector( - onTap: () => Modular.to.pop(), + onTap: () => Modular.to.navigate('/client-main/home/'), child: Container( width: 40, height: 40, diff --git a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_actions.dart b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_actions.dart index e044d1ec..e3e99090 100644 --- a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_actions.dart +++ b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_actions.dart @@ -83,7 +83,7 @@ class SettingsActions extends StatelessWidget { // Cancel button UiButton.secondary( text: t.common.cancel, - onPressed: () => Modular.to.pop(), + onPressed: () => Navigator.of(dialogContext).pop(), ), ], ), diff --git a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart index fc05ccf6..f644caf3 100644 --- a/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart +++ b/apps/mobile/packages/features/client/settings/lib/src/presentation/widgets/client_settings_page/settings_profile_header.dart @@ -30,7 +30,7 @@ class SettingsProfileHeader extends StatelessWidget { shape: const Border(bottom: BorderSide(color: UiColors.border, width: 1)), leading: IconButton( icon: const Icon(UiIcons.chevronLeft, color: UiColors.textSecondary), - onPressed: () => Modular.to.pop(), + onPressed: () => Modular.to.navigate('/client-main/home/'), ), flexibleSpace: FlexibleSpaceBar( background: Container( diff --git a/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart b/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart index 343acc25..6886cfe0 100644 --- a/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart +++ b/apps/mobile/packages/features/client/view_orders/lib/src/presentation/widgets/view_order_card.dart @@ -202,21 +202,38 @@ class _ViewOrderCardState extends State { ], ), const SizedBox(height: UiConstants.space2), - // Address + // Location (Hub name + Address) Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Icon( - UiIcons.mapPin, - size: 14, - color: UiColors.iconSecondary, + const Padding( + padding: EdgeInsets.only(top: 2), + child: Icon( + UiIcons.mapPin, + size: 14, + color: UiColors.iconSecondary, + ), ), const SizedBox(width: 4), Expanded( - child: Text( - order.locationAddress, - style: UiTypography.footnote2r.textSecondary, - maxLines: 1, - overflow: TextOverflow.ellipsis, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (order.location.isNotEmpty) + Text( + order.location, + style: UiTypography.footnote1b.textPrimary, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + if (order.locationAddress.isNotEmpty) + Text( + order.locationAddress, + style: UiTypography.footnote2r.textSecondary, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ], ), ), ], diff --git a/bugs/10.png b/bugs/10.png new file mode 100644 index 0000000000000000000000000000000000000000..c2127bb0cecf8a86b1e740e0622c7e3b6166f4e6 GIT binary patch literal 116682 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%0DCg$u-5~1%i ztmhmSj2K}4;0XTQPMyU-JgjmX4tJ`*LLwb|0i%!t$cy@0RHNmpT zrNnznAZdW672uD@^iWrCD%Vz~Lj^WL*?!DEaD1&8K$Ue385CgDkD{E&g*|eL(^I`Z z|Iw&cSNWPe8~L36a9CEO_OoL`a!z@zt2#uX@JN=&RfCKR7sNDygynE1k21u#PmqE);6~{wpDaYEv`1+bxov!JB8ewtP$>l zL5T6@g{MY=N%Naa#V%I?k4aUg-D?GPz0MFtFOsl1DmuRGUp9wc(*HsrP?-+h#z;SY z_Sh9x1#l#7Sm!|v!XHSj6vxt6L8*47{K{Q`^J2f zDi#@Y&0H}yMq285?T(+(c_v6xsl|ah_-2E{B3%nUOTSOAvGrut1ei9qr5n7lnlhOG zFS-{U1=G>WljWVrGFxi66|; zVZJLt-#@*oToL7y4(OK(m{vdnqtgZ;|D`M6``mKyfCV;w_i2oq;{Zk+8>^+IIeGDO z0gwSOm=v`bMq*81NR${*UpP;MI#x{8)l`lSKLLr{sl#(i%LH4*RA*=->80}W5V z+6}>PL<|a?VUU>zcIR$9l<^P=^+6!=0@Idx@P%#cY+M~?gXuhV%y=7Q`-f2@>?|y% zuxk=-oYrvI0GTadETPG}M%NC)isb-p#aK70}-<>?_*z zI1amN2S6045N2+c`s-IK&t-B0?f`0G0_g2061XP{=roe=A%86q>AGV67{~ba>0akc$3Gr3T2yPI?+6GMaA64HKB* zRdZjjgLm6PY3@YzuhEJ=po+ra*Rp0l`Sa$cWB2ow)ECeKRafie22@cW6hxJzw5*f* zJDd7uk^FoRO3DuFfWQ`MznGYHK-8MNgRT-psEj?19`pjrjk}&R1EFuvcSdM+eKImy zk9%P&@801@sf-MBmcyN%`WVpDV-lE%ftUp3242ED)TgrUhJ$*R7F@7_OB6VIpm09I z>3tjZW`vYpv=21(O$GvXnw*R%o7c1Z8~4|?=(Bh zjqUc^zW;q2NP-Pi|8n(E;PKL8afJgSl((bc5(jil;(<` zyR!UhIYG{EElT*Tz9#P=j7RwPEISirY9$X2Per;etJ;`FY_vr-r9@T)$NP!`ObT>6 z06q4C)}v8EZ>B7zB8-RUpoo%m?0@@T8;7`oCVuL20jOg-zt}>6kAaH*s^a0b<)ONN z|A%+mitodWA3r|&1}7C|7fzQLG5Q+rmm>+t-oElzVxFBsFfN-VJ-&S>0goYS`OZE@ zfv<-o*u3MDRvHa#pcdKd`DOgeR+lIskY;u z2juoGcEe@DIuB)fE!$;vAP}HxBzLz~Q-&660&xbHHkuKwmakLt#}9Dx1QE&tKDZC3 z;}b~y)`rhuS6BDtF0^moV~#fN#rFV_4_SSB#F64Xy}i0q@EEh5jZ*u8sonnfkZMP8Z%90;9_Be9N-ndq4+d*?|6oXja;WUISUhxW(w8 zj|5bCw!fzcPvHB|51W9;n6V&p2G3%ovWHGOUcde9#vu;UmF%S@Jls%#`~W`M+a#Y` z?S)t1_+J3o$%ni3<_!_uc*_x&KvoFogS?ut!RD!<7D0w_VJ51nU$BBR3(y_$f>d~C zb@421?D(aEnv=DomA;vagOrwU!Ei~1S(=ogbQ8A~=9~O&LV;OSGnG};mlRid z>(PTIB?yFC>>~M2639NV67#Odh{z(B@FMXdREIHRfBC)x1=vvi4=*)2il+1pO#IA;7XNw-QcD$+lgo-o52gq>D(X zu|IIsjI{OoU>FEUBVE-QfR;AQw{aCzWpDLX0RGuZf&DOZIZF7A;g&SHnOPF=2ZabG zxH4XO7H)hBtpZ5W{_6Nj2bq4WfjrXOBGu6&;X#d0Wln*{9(kp)KZ!9l)+egWa!$sE z_E0}?lh94$XDi*3LUv}_yuacZfYhJY|4^+f3sM=U#cHEl(en6|Bid@TD+9DgzQG0! zNEpEh=*!@Tm3CLm~odq=H!5l)T zE;KPrZF6NKK0bVIdxKK#Wkcq5SCD;*IGE#`qj$OHrs*q2h990N;MNL+(5MA4Su@c% zlLRy`DJ#Y#XpK*d?iB&)>Ry)>{AVRQK_R<>q=*I7-Qs6L!SlFYE7(qz=Y=Pry616o zgmeXZcYpa!@K+y`3ozmYh8eg0@_ht)9Yhzd_XA=Nd#1J%>p_}*jzYV|gn@e%#bqU{ zT-g^r9k0QvmbcwOA$*|W9PE8vg9befev0nW&bs<$9~917^PE5*fJ!^Zp{XVMbgrxg z$p6FAuDlWK0)kUO$9jSBNUAH>Y6_vJqvSQekpMa{%mhd0ysA?Fb^(s_Pv=qv*Hr6) z$=SKHW^`QO#YH!rxmAV{ew3=`E^2H6I+GZ;;^Y%n41AGeTI~+B#@8Sr5(u^D(OaBv){kvcAxvweH{&UW;SFm=d00#RFP?Yr?e6gUAOuLON` zKyF{C$)$Hd1q{8gCTpjo6O%1QfTr=}jFedAVA=cr6(HXMck>k(Mg;LXdW<2apC6#_ zJG%+{1;_|;5)uP4(-j*Tagg)@!WuMP>!!u@80zcSdmIn}@&yRK*C%v(TYP{05>53S zX=7^X9ufp}s|(4ixf-LEr*Id75``3P7(K*Xv9m()VCwiN*6uC%%&`JZC=@h2c()lZ z9|QIaQd&_OpT}zc#oDA>dJ&WyhtEZT{+++FKq*M^wFLX(riGKp!tXX*`imJ_+*(-wVF8vhhh|4uxR$&K z6l`U+Dsg#fxq9gve?QRkR#WZ9>7)*K|30cfYV>!cwAD_AcjKeF1y>wl65(r-;qz+D zFq7(P9;q{ZB@>`48%~>& zyl#{-O{0m7erLg4@b6#GgD523JPEW<_Pu3tet{gU`rTjl_j5Jt2yVUEZo)D6%NQ8N zaIRXF)ZfWdg{|U+zf`dQ;+N>?Am1oXQD2`TaZoAUq8Y|!N869oLchq&B!NIkvDJXo zs_*~|cgA}D;!P@11YdV1NwAL(!nls1q^bePYgPdD48ozQhlpUP-FZ-rojJ3=t+aKps5LDT2x z07^%PU2$EVF3e1D>YGTg=mb0SR64B1%Q9ED@u?w31yHT$brmJO!p zf`qVtRf8T?*wEU-S~Z|_4nr}0G<5?df(H%Lb@)F3?Xs&UdSgKxnlSN69F)n-AIb#D z6v!}IIvfQpn&E@mFO|I&NpL3+A7}OH^!D`WWw2!k-3tA17E>)OhjB~VLRMEwjayUg z2&`X4sRF)ZJx4h+U0xpM=9`>?0G)533=TMHjSeX+upd8DLoEtVgig(S5`b30Mu-tS zZlhCwrI5Uhqit~+9MnWr_t3__txH}&y1Hlq#we{UGwSl9rLH!WiBdEuLrKfbT;F9h z(~NWtIk_a@|WwCA^`iSQWRL53Wd1}^7JETWc8p5 zx*B$8pNJY(LPZ7Y1g8ZBr?yR2(Y*a&6F!ihxoLLV|K7b_^*b^@-UGHv?AJr1FM{ss z^3}9PXU>t2m1)-6wl2W=?UJVM9ymv6QoPL2_y38~55PU4hNe16e>OGs^NUyhr1KNP zs-za+hhsni^r0@>Ou;W4xwM%AMNdligX3#IHx2>OMqey;n5Qr|1zI0?MEpP%OZ!H_^P2l_>*AV7xqbNn%oDVk8biD9@I zvp~I)4c@D!akl}Tu7hpyPy>4x?ybLD+XIKfkLE2CgaSR^-~ZK7b{=fM;r8tK)WqQE z2dI!PMU3pIY9tUcfS7jeGTFtuW=MreD6i&JG|DOWy2pnnx7^=)rW4#K4WHNax@p~- zNkg*>sj}myf)eY0dKF^O9!<7{k23(!Cl!@p6dqYvQphTB9YxbUpudR*Xw6U(QV?x5 zr=6SwHGk8AS`C;QQ>=DC!iVwSnbkJZY{I-46i$qLTEd&{w#G=Gm)y6<=TA<|goYsiYUA zTLaCSG!-|iKDhq>maB( zzK*l;JuSa>{?y8bKBYeLcH=%gJWQwki`1(R9kJd@oLv-c$iFaKZmYy50_oDzpyrp# zKVL3)X?k9x+C}`5vyf^9liOPtZx(TWvXl#Xy*h=J%9Ue z=3{$#)Vt8x8jrE2r~%eTkIqp&^B0j8lMXB!t=;y-)-Gqa^E4jMYmRAX_J4e=kS-ot zY9xvI)_q%8(&?U}k`nXM=e>WmHo4pKQ~yp?6#q^>bb1SwHD2qA$bAu!&Jeyn?d6X{ zCE^F({e#?(p}JQ`3(MeBF)P?m7uouxn087*R5s|o`-EPww<+^(SY&SaB${c}KL*gD zppoHDM>flEg-|elRjFWfvI6}Xx)cbHbJU2UUsRrMYMxS-lVcVVdb`_M7MCbAxTz}} z{9?MMoLOoW+em2pXX?!ot#Wb^%a&sm%X1KUOx=CMQ zF*--846f##yHauX4tSYbQI-~w(Hd%KB3QR0=yEP#n3R-i?vV9@QP^CWTSqc9oW_dH z+%ze{i+t~}-s$LkD{ssi)}T4{uga^a55>@M8abS;ipniN8`Z(cc%58e@DTmoqdJmd zPZ$=#VWvJNyqnX$RkO`4kfAbYL^{D`S6o)-c_6!xr$!``T7Mm9BHoRdU!(9nFgIds(DkR^H@`Jfl? zLK3gdedH!Y_{7IY?D}AK-M(nFU~9O}t|neu4&1r6`<7n$gXm+0(JtGLZ)CvCJaz=# zPkC4vAi#*%a9U-$qRMhD^qO*9BkU`W)?X77KPT*;9@{BdC7tyRxlaMndrh=9sUB6J z+6r#uGH=s(cIiC1G3rRCHad9qYfP{~EM-3Q)2~MrT%*9im}E!Tf=QV*l?9WXqBJ@4 zX7~49NOmdTelXOSm>SL0PSE7EuK!q`XU0-Rho1KMWsq;(nXqd={?x70a8LQB7|O~ zh8_j!y+#5gN|6#ms0ksE+!g<2=G-~w%bhuA&dlW#Np^PjUVD}2`IYr7>LheBw}c+n z4YfoKX|;a<1<)58VT6*) zG5%i>e1}dNHYj?qMrhHzp2FX_dtKRVRZMgsg#O+F`>hive$^!#`ue_agG4Gtr&nU+M$orY*i_b5@LpHDP@9WD5-WCG()%;oTgEx=bhdu`9Kk{Dd!(TwW zL+~$D{($$z|L&JYxW<3H&B0c`Y?q{^1%>71FRi{VFQKp33m+kGqx<^$%)#e) zxspG5HRU{SHCUye@%&r=*kAK==jP_l#T!F((v!u*nI&JB-4Rw6kzQW$Bj43J79l$p z|AJnU`dQnhORI3UOX}*kR1k>@ic*gH60b!I^W5*nU1B1Gy{wPCet3Jl?`?NY+|NJG za7ih>0ITeOOu$Hw9F|prKTNK@`~@8JOY3u{DY!b1zT^qd2qqoDQ{wi&jX+1%WCXwD z4A)t1R0fBAQxWchX^xdcE_BX-b?Tnj9mZSqg4f>|x=T$?73mrU-!}2^Xf7`?KEkB+ z;1qLgJkw}>2>txWE@RL1v2J4B2@wxYosNy?Zdl#{PxKjUD!A?O!gJZ5PlX*`p&jmG z7&w$8=$PI)TvZZ8P(;B1A>V@}sT6k468?VW$Xk?!u==fpw6tPe<3b;W&t$Z0;1u}6 z&2!sXtVNN?mpZ+;lzT|9OV5#;j7CqA*u%kF;hHbXOTarvu6#%|z4XO)x$zQt3(COZ zDz>kgKwlJ}y@*e1yTD;1D}z5DnU7__TvY6^cpEPLZH zArj5~^XJ2*jR)EO>-d#LsaFr{{Gp(V1;)87;8Fi8F$NZ@#H*A8e0^o^8+e#0bv-{H z?q#Pz>CDArsw3wXEXWlTpzi6Pq0}te`~r4+DQB0vHmSEDW*uzF8A%Fw*zDiYi=A{q z#umAX^^J0}!0;LFlTRjV;v9C1#bK+nCNfdJVN#1-%(2rpjilsW9#omfbYlo6rrLwN znw?z1saZc+QSGuM0?!-;Q{xsD+<(#9qED-1&$-4j)+0B27{$F`Q{-diaS8$|P~}-- z%Flr#AubWm9XGg(oCm?FPQN^CPKcFcG2K1SCnCCzd&o-g;*{}`52)oOS^gW6PwsHx* zo9=EdQ(fX%lKWmFEhpzWcmRU0-o5iNAQFfc1%rGlj=OG-CW-Fzb&wE>fV(vgHQ;8b zrl$SW>5F~|ATlcYS52d}{ko=ua73FhBL6wf+uGXE+_Ed!$iVdU)Yf)oXE6i{qF(Dg z?fZvxIw3y(6&t8NMSc7zdxrn_w;Ulzj!SHLzG@%HtRFFopXk*1_bcI9MP667=39g8 zy6mf7w_#`6Pl=<=K%1ChF|%qd>(W-#>CFT$O-5`Ow1vVv-Qu8iXPSx7hEB#2VpzsfeSp0__9&T=c#UUXLx&@NeieTd982Wfx zTTicl*~fSx@j8h@fZDWPanKnt8!OsJ%OmyDw`zChtA8yybQ(s-#Dw4iPGGLXbaofN zKKEs<%)NNhJ>o{AzrpDXLCq0fn62K4u-I(>1WO0r67w?SY4|S*h9l3a&YCcFu3{Bu z8#4pBs-ApblL31+_v9MaW?{O2zjPT&kvt5>)uGaA(=m^wo(J72D}>hWU^p5q(|?cEtEvWu@j@P#StL zL*d#G?A_aszA9nAw_xsBwn5qI5lQiBmgS`|Uq5HGJS#RD1a%i&0SAR9A<^^nEZOH z#hN+g{{8z6fro!Uxt8+Tdh)W*On%m zYbSLZ|G$u66*ypoZJbx8dP`(@DL$xx7mC)%gjzY(R{$^GoCI z?4Zp?YnTjpQPANRN?aDlXC%1a2QAR_lsrT3Q}hl|kKp9x;c;;??d++vJPfU!u64D@ z*ITj9I=KmY$dc571>@#iN1v>VjQ@U3gaKxk5ZMLSM3nOZb!RmiPd#LC0h@{W%qNj- zu%A9%O_=M1iK82Dpq>zoa5lUW&x#_w&-Y~LIn`sPB!Hp1~H%UnKl7F-@b`He{MKf zZ}YHqiv%`?H_Vh%FL8BqT9UCP+pj+sz*5jWpyZ00SE$!abIWu0+1Gw9%Z}tWYf#(C zrU}{y1{gN2lT`K`>^nE!cZ!5XNIi1vg!v0FPhm3jd0(cZ%$QWg?sn#dD|6j_%xYW z;MqAjTRl3`q^1L1y+6jpoMK_|L9SPVI_B@|I7A|3^NqWRN*`?*SPvEFDJSCMj6zDb z%cgCy11X}jzuZtu;1N<-!1g(hR`T9C(978+Jd>)ftXv;%9YEeSWE3Q>Q$$5?39GBy zFRj-=?LeWYe*f&xp9^%M)BplCvPQABp67vcL@7V?q zvKw9@JLTukF6vQGgu?P*tXE)ZV0C6?-Xn&Mk8iv0y}Y}k$9;1F+Ou!8m@MlWfAWu0 zxo=o5eoE+NT%-m)COzmXkEk_%-;nCc+~o$Z^$M4< z2_%fR&;+c4oc%J&rh`Z;G^fVIFSA=u7gu+OC}%cXaq08kMaMut2;JqY1NWi?FPvEI zh2hum;=Q5@;K8N$$QBHxC8wmMO!z1qZo0%`UV@*1!Qdbu5$SZ@Uf9QM<5Yf?fT!DB zsUvF85U@UJr~-dt=p^!rUJIJ5y;J*6OZO&1G8m}jz`A%|^I@_CShWIE*Zroq4GO#t zYrM7fKSuMFm`mBUW;8EWMt)n~OeoN!2nycX?qr>nPruc59Obo`m{@~y)eK_$hZy2+>@iF|4eXMy)!z1+O+jH2l&9`7;EGYpswsGrcm)$Dc8cD>%h5x zBF#JJ55jhS)TD0bRpsP-PcgEq^PHV2k1uO&ZPm^VSrZ7JOPsDKnFPZ$hO*z}yXf1( zhG{x`?wm3x#H)df8jV$J3|Pe?T=WZ8JKl4!YhJ$mB#-kW*a-i$U>)J7gNLJ>-#+4E zY;^!--9qEw3d~(uiA6x6@Xoe~ux=8YW^?Fn?-*{qk=cr>L=5-m4zXbV{pj*W{w zsc*Xry$c54$HW+wOh_ctQda)?Hz;C#m+yvk?}S@z==jF>Ol7Eb$9LOR$OS$=zg=`R zcG9DH6{^Kp>43ug_+hTgHPn+YHV^7W8y5_n)x5yXy|X@52A#D8)U{i!a#Ut51Ojn} zA|Eswdt*vBU-<|DSR*cbG7P&5mMTM6e+sA%49YDZS|l6#K{eClJw2S9F7onTdbLMb z?ulz>a6!^QVL7-aQe7?YgMK=QrjOcvOcXgjhC&I*`Yspnq0P!YL?;x)S35fT*89w< z(rW+gd39PFk3puaje2@OWr%(?P_2&bi|!JOT2oMw*~It$89iZ>p{x@E8X?Y`qp;EH z6oT`hUqG3I)pwEEvtXjtj?G^488hCm^btaV`5aY_mz2t4zqs2r{|C>UUYD&B>DpIk z!>ylWZ~LX@^sytKwQ33%P%RYKK9$KLd`1b2;0hSpmbGp=ixg-Bk0J8W$aN+7L9-*K zc=5w3szge|Nye=7VJ3P|LnalmkAjbCgC(GPNwW9G*#wXSh>iWZwA9n1T33Q1T( ztM!2uGK{z!y6|n#Oe#&sDt{;~yIdxL?UJPALDPyK+!utRQ6$0z#r?k3iQ;?NjDhQ+ zsL01>6AEPo70hPI)le@NnaQW6b&*3!`vLAQGfE25UTr^CMo~4==7F>KdQ6T%u$+Qipeqp|LjUZCdgo!s}&pF;^*u6`bC zGcD%57c4^dCHIDZ=R(K{v11G$!CLQw4HxD6-r2eT3**V&8U6I>*JO9AVv`<2buW+# z<`XNzX7sa_K$Ij`5^DuU+A#*2yu4KHZ_*-?T2*K<)|r$9p9lqicY2d$6oVgNH5AI@ ziQ`Y?M%!cj6+AG3i>m=es?fC!ycN`YIv)^_sXA~-kqOA(ED;`c0b{E@*cf)rZsSxZ zo#$L9kKBx66esVhUdG!FcjkwyvpQJ`;u*gWWiK7rtfN%xkW|{vfzp@;0i#r+22wq* z-!m5>cg9`{frA%mreA}KR>wa(HI4nicilLsP0uN&Us<)N5|9(0;byw8_+#AJ67O& zD9EEwXbv9RN0ma8;yAkqL0Ai6U!54~$13f)#j&*!haBhr1aqiJ&U6JSKm7fQ`Lo%* zu53tHerqcgjZIQAt4Le9^`1-7qIn~XhsRy;cJS?mK_t;-*9Ri8Ud-`fy4Evwg{6EK z*DZz{U-4VP@^jbCp=u!wsHJTEjH}{fOY)!(bjENi_&-IK77H5vdJT5H5qzNo?O{bm zW92jtqd(fRejfVsJXAZ00{WnJ^aQujc;EfF*v-vBa@HeZ#&&tT5$-}TZox?QWa!b>w zSZ>8ny$m$6Ovx-*MHcLL)Ea~Clid9M`|~xZiM zBxYnxWC=yF4z^YlS#N_1>v<|lG(Ht!W-O#+0t;1BrsUx5VtG;rLX7|XXOlm_Ke)Ju z{s{3MOTB&W;>CcyduU@C$a+KOi=T?a+#b*{5c1E>F*Kj1L6glVCesoVFLccak4B@> z%h0WD1AMC$NI`Ncvb_S=$A3q6t;D~Kz_fs_H!nJPZ}IuDP^6FapEQFQ-^*jR&t~u* zXp7nsN1P?ni^x!9)#WrbO72S%Xa7tY3^cbdMe9WvI5KMFO8|$*w)Q6F1b|^ z!bQL4!!%|cjRELCS!mS-_u@;|v$Cl|Z3oPNQ18KQ&SOp9n61WnywIzwin6e5v2J=D zJdKWJszre!^l?d&tBqW?Y6S6L+=;ZRw1;}mM#`SbN29e9QucHx@UaT50D#9;r)pb3 zsvO@zBSIZ_i?7RoD2?S>iaJsUro-d0vE}5i&bmA2gqC`%`s{Z!NJRP$XR$XdzUC2e zaaaGMDM?ALLOKQ*2LrwDHYVL|IP?NuDEZ%oSxZdkGIUHb9) ztw5aaf^oXp0IGs4Tw-o)Y4rsY5KVq&gyi54s@M6_;EaL6o-DQ2R?tngDV zO9DUz$}OvJG5+=$lf86ZeC$svNQJhl!^6Omo2e22N>?}U|^z8Y*FDGQg#8wVEBp?mX-DBEr9)?;NB$xL8jW>?N4vIHIpY%qQ zv1o+&5q1YE^+RyHt-{MavPF;FEXAYLzDh~n&+Ys~TF| zjd>z?U+%^j#mM!QA+$e@h;IplLPkMF(dC@>yC1j|UB`+;5<1HR+?4vp+!ig~o$CmT zq)s(PTfJrj8FlitLI88Fp%WBR7RLJj_ybR3JddM|5>~^1Dc&>W1 zglI7U?Kd2pLbnPSbI2bSj;x^)gqrNO>!I`c2M`kz%Rc+TicfPQG>vcnN`F9B>A*a; zAx2V8y@{C0fU-d7+nAWCpkEsZV`qdLZK{he%nMT`WIo?@eRVIiwo3w3Y}jo`UY`IM ziB4BgnVsm^cN;Q!r<9ZIQ@)Y{U_B7!F7mSc)8nkzVG9yko18ns$c&89tf%gB+yJWD zDjb_>1PF@Ud=gt*gL5=*t1k2h4^R4skC!!$!=h}TXoycbwz%0VSJ)m#dI!Mn(Y`j^ zi_1`l8Vry&vi>QE&`gu_9heAPWKlpf-0ykZf4^M9?BBZ~qM`n{<|ivmE0}$NxNMzU z@f~|FvN@o;d;eT*MU7;d{2AtLmGswaZD1$-CE@Ki;UhFGEk=M!+ItxlyO`We*dIKA z{syoE=Ro$vPOc*BT(1cz+6}V&zo53y0+M~A#B>B2Kxoy1=psj}EG>Y)ccq9Ev5gj8!=lw2Qrk$qZ_C~zZw>GLI-2af=-qhF8_NQj%h z#7|)W;V9h7P}vyt^(}ld(T#u0H{tj1vq}d$Ur}M4GG3R4T%0^ICM(sicS+>BOo-iy zTIjq43g_}oPcD`X8Da+Aa_pZx87_5oaJ_n{R(4He>qqZUwo60(U1hZUdlzM--*?|) zqk$srT5sgVc>%UyN*!s!T``7FL+UV^;iUSC%G151Xk@L&rV)QkDWnLXpdu%Lw3rmb zf6avd*!EA2n`wbV!^5BTOPo_%ZTP>_LP+$SAUTTZyd>UY?eSyZamI@YyFwg`b{CF3 z3;I}YM>Yjfl1vnHVlNmWOJPGYtPGot^VPIpXNy$*@6kL&vi0v;ir$(NU`tFu96zB3 zOZTc_Xz%XRcf%Sx6I$)iSpjY;eTc2CmsW;`gwp(Sox6?R#^*yMz4bgiZa#`J@W@}l z5Mu?Fyr!btay~ktA*yJ_L|^la=`74te`*OnZgQ%x*y;1P`}3a4LHofN)-mZUiuV$6 zcWVxoP!N&5)FZ3zh0+QA%*M;>ySZf=(p00+%=QJuJx=oQluVmDMZchUXBJvLrg)U| z&sO_cfYxL*3#ae8V3NVywlTu=YLUF>9VIc6obl<$h+YOX_ITJgJH=BfGO&o^A{X>P>>n(dXXBk3U2 zbR}i<=sbP;w&qg(7n72?&lTCk!s$cwz*^AY8`Z86@WpDoSZl_(j11qky_MW913tAt z@hC+%CNA~_;@->ycUX>Pg-b1wm9g1x$;%){2>V0P9sN+0br6K}0I@B%YqCyrmjK8? zKW?Sjudl7G`7WZy{wjr7P_~wun9=NjvMtJ(82zHjn2gHQ6reEdErtH7_oe{=nl*2L))& zSv82Ug4F)kut+d*uPS;OBYo17@QoraEg5mCu0>up>agBc()MVe_{yk~C;syxL+o*e zC`Q3@o9$1K765z&xHUNLYI7}dZ($xF}T`bST37D6lieByT@U{%H?xgpO$l*`8UsS6_ z#hWCKkfZX1rdDJHMTi2b*`QZJ#tWm6@I{9Z4hD)rMZx7X_u!aQf1)#xYvsrQuh zi^E4DA=BBBPFT6P#0*vM?}iYEL{QO6Q~(jdV_Npefsd2(EHCfe5^4Al9qmC(Y;yWz zA7W;qg=!3}Xj0-+@v&s|S>7;O>1u6ha*-`UfE4Df4DwSivSK=XLanJ-L|D|2y3Vjt zl^EvASh~8{l(6Q*dICK|KT&_>dwyl{!}&7tTJ~1DjkdZ zm}D-}GY%_3QJ8t9u}4w+=rR%E|$g#A$>d**mHV58V@$t@&QmRlwN=p5co~`O7X(mCCUgO5E^{qRS zO>pzgV3(zvBV1v1^*;e0 z)Z|aVf-nNFLbOKGX`yBE_JjYRmLol8r*cWZ_*)qIN_gwsM*MMqCh|jU+#E)KT-%zd zIL#@=BOf?wO5*WNFnIiU4v^dP$W(=}!Aq{X0MWtfXMNhdK@8-Gw9E+f3+b9J2&?#R zRfiw-vJ9cB?tqDfw5;~f@{=uNW$rOffNi;2)_`un3fM{)c{+zm%{Ra@kOoCr>9rh!y&2@G3MG(k6qP0St^n5f7_cVmU+m-d}b%oLfKF`AjkgqY*<9)lb-iY>ZAqN z$lP295E&eHe60j<6Q^d%1s>XsNVCp6>!*i7?!Dk&=|5FWefb7tTnZr5kpKI4{rW1n z_m^*ClFBy-E(Sf+X)$~oQ1r5mv2$IP9fOoa+BAkQ65J;}lh&<=fOLL+_t$ReNB(R6 zV0~CwU-0et@iTZf&8{;-%{24~c__|-#;cTHQQ_@vZUl#@h3`BJdm28kU0#wT)9d!j zwZL$?;BtXp#&zA?kyo!?8Dz^x?w67$7kfdS&O5iYPr8;lR+yD=$)rdH1?v{vMHqkz zL!)K)^*q+T2utL3X2c8YK9R9>0i|T8dxc$Q2A9Z9NK>%g0pR<2RP2j)bQ29q0k2Z_ zz?Lzt9RB1_&AUSiG;762oiHMND>qfaFN>{>Qcl<~!U8VUyiRsl=8phd-fVsi;GqG; zwmsSU;OGsX-ZEVhHMMnT)fDn{V|$p!SNL_IOMtsMtKgQ^VsGFy;()r?U2*JKHlv_f z+0<9Jfs+6ZUM%bD5WSqoBc={ex70C_KYsRmYo>J-JAHH`e#K6iq;s~@~+b7HPfPyP;Q=UqA<{>n3X-u*nW-K&IhR>*8EUzudhnt@&tt2m`!4w_jv$Nk-fHFX(*IdeZ4yL z=YfrK(2W}JCRHYD#?6J5>glYY8e^RV?Q#Z^7p3`bpjx6fi$Jr_tWFcnhSO37UgJ6u zPAJzXc6{>U!FfQr=;O@vviGBT@$vET{HozVE0W=6GF|C8Yun?u~FfU|xNIb$}22pHr*!q0ydSwKu5GP9%V(~E!8X8?jCim2uSfl=V} z_FzK6cQCDk4yZIyh?(M$0*bu<*cSls_nZUi4^z??7aoB8XR2xw0pPm&%$BF^^F%cy z1ISeXkpja@O!yW}mAd9O*4p@1u>}BeP`aG28a|K;7+pZTpE!P!L&9>r9MTcG>jsdA z{#s}zY0jvSzR*{+E|0Wqg8)*-#)q`C0|j`%^HwP6mAJ`3*U1_m5PQ;tjLvzwmpYzfA9>Vw@|)oL3d9ZcZLTxY8++E4CoWt#`+mYJoerlO}!OBd(HYwouLIveS8 z0&?1~Iz&T{M-C|1g zX|9UknJp$pMy6BDQWjOWK{_X&$;;C?>4_=5e~UTl$-a@0goJL<%M7+JK>wlC@ZJ$P zR!=Vt@G3ZdE0SHBnN?fgp9$kX2TC$Hdz)9<0;<+hp=@PgPny=+ucs@Oq3E~qxwXq6 zqZLTyyOyBiAGn+(rQ9d|4+?!=26|dL(!wwE!T&PD4}@Do+tDmKfh3HO;Hy;E`_+(! zlu@p|PZ6UH2)XU)2=5@TU7+;?9>vq|42Ky7i_MGjfLf5x2GnQ;@3Y*Z%U7SxvHh*h z_untC;0@fAWfjTP>1MKvB7na?gx@?5oLWpR+I>puj8u3e4q|7VIuiP#`hwE-l#l8*CnNFjB{rzJPJ(SF>QIUzZ_DRjRd&iku=xx36{KMN&F}3e9o?djh zCjI2ECJE29=?cs6Ukg@`WygU2?mo4J1g>ZJ+e~R9xYS$hXLli}3HlZIYqegK_VlvM z>kf;|rePwF3f^|zhKxRf0po+?-;+FBFtBsZ7akbUS#4B4@%id;4ww#n_UOk_x;mEi zeFo$en~3(CVp90y$M3{9P2#qo5PV99?A0B;bm+Y7p!gzKN`9SfQv3SJr8A05=5)Xaw!! zR-BK>$_*<54XG&%9Q^E`^8(qQyqsA4s=+yRIb!(js@gbBE>~7=Uh~=1dkD7vc-A)1 z-Tk?yp~%QS{EFR;m+vntD1ZqrAtOHinm=87N)Q8bUm;LA=2(PU%ca-XzuaT;dvIS= zTKyKv6nuPSi+(Ae0ycYl8P5Oh&doAR?aJcxkC-n0&n2Dz`?}lz&(BQP%AWY;^DV&+ zN)d`uL3mE>jS;0V&H-D?Ny$U`o?)-qB0~K=9t>Gvpo?fcUl{eQrevy0!;_J=4GR5X zW8QMoJN1$G#)VnK2rtZVjxT(TBxc&SFiZDn9J!grQT!QTX%p``N&{>@sQMPKZ_Ja} zU$eOd8kesFxw4AVRmsAPrJX^O`aC~GkC#n=En`e zTYiU=d_yXve_m#BNEMemTD5vf6>v}RnH1L?0#ztjBFHmg7kJN^&HVWJ9aCq2Xvxu= zJh1btr$;O(LLiv3M`lnz6&r5<*{<{>{0^)awuDy@)fq?II)*|epo`Q;9Md@w70r1sU&9LViQfh5O~C-FVl=>R*eIah1(C37F6 z`1kCp!F#cUSyG?SK#L0=*Oc(|G`*rTWezR-SZGPh*y%qWurPK`E)${vmr z`#A-Z?3#J``EK6hGG>zVSw%%aez?5x_MRajO!F6%UHL*vR0lj(yVRvuh`!G$E4 zf?{90yK8L{`}CDY;M|K|tIZp~dRCcLbIK-0`=0u6adH zat;{EG~XJc<@@B|x4W)F=tHra-~jJ721txh~|7sZDB$47cO+_`fhUFKc`-8$E5(d7`4(<+?*jzNSoc=?)}2?P!Q zxy8N<43zh8-khwgto$zc+eN1Su69e|{9N#SQqbeM5`-l)_z__BDtys+&kEI!x_F1mhiGX9CmEVgN*L=J2wvettHxr>@D4)*}8$ETY9pKX=0{?~#PPdI5 zU29<#hxjr1h12^9n(v#xP4Yn~u=4yh7|{>B@^)tE3W$ULGd%4s$-g>4x1W8MQc}8u zGVM+VF>78k|K;0%3vYv1w(>xarnU=ZfYskMoo?Hmy8k`DPXjS*eA!P%%-ehnz^g^L`p`1r?O&dxT2#lB7|U8|FEYw;}^WUqWR?YDDb5rEu6fY6by^~aFO1{k8>>F1oQ|H zbnz&9Z#T{-Y)&jMrvNoEm$VHGT55+NKBKB>;D_rTRz4=w(Q}Yt5bk1%%qwj1v$UZK zq-XG&z`x#-p7!f=YXG}dau5=N>3~kj&UV3nJINe4c-Yzw8>1)zvAaBofo$29qz?(} zt6)q&3yS*ukKn7Ta&q8?g6i$!#FVKCZUsI~ zo+vQ~;1EqE&<$v?fYutJMhGX8zuh_Qyt_8Ci=WsyRscD*a-B`{yp*L00tPytz>OD7 zuh`}YHtAU6-QbxWUI4j8-u%qghAE!|V%5NdyiA~PGox@xS=QtyH~?AJ_m}(By3lsO zxC4`nh(Q+oT=7ttf5>$0;Z+OEB&dr}B4~uFyAQrMJq5DyXWxbFnuEn&?UnWw_#tWK z!00rpd+U}VcvyI#G`W0ve5S1wB;kB$L{b(G8M-Sjcq`Yg^rxa-tS?{#WbNOxJ>IGj zC^o4K^2uifYuZhF?FZkjNRoTxx7V;bVotqzK0-+DF9qhe8P9TYA)ROcIQ5yk6An;W z$B?BDtKAmofWE?ewl$2HaR*p+_%x`V9dpO^+W?&|Dl9x;voSV^$H@{o0l;!I=ex3a zaMORtPp@8CE@GPlxUP2W1#x&Hc<8@#k@u4!mjQdsdgvDZVAwchu0or6^^_oRHlSC= zh?;K!7jIYpba6I{|EbJBO=*C0>@X}%T)3mZ4MqyNkaleW2}vCVi6whQOk`KLrRG$z04J4;@ zCrQYDY0c{p`f&~89+HzmMio+$-G{ z1^V+940Xq11Nh#C?3#VMrk6TCBy)K5qDrhvY|=Re+Jo2R)0i%1$ zwV8eoOI}7%(>D+Qac#q@{*2t{Ci!u`zI)rv`wa7GBtC>Lo~+~WfTpOy!S25+7#N^| zeJ4VTR2Qdxwr)dIg79jA2Q_S(Wo8vNEu}ydIT{F%TpN|h$5!9-t%h!aSt?lppp0MK zV7-v3BJBXsu0W@lrS7K=$bqrf|DHY=cM_MB44-;0PbXPLwi1+!&5?U z-&wC929K?`Tm;N7=V8qjpk&ZI4*Z?!!FzOJtKT0fa`W9}ZzR7>d8sL}ODS@*m(`Dp zvWG!oF7TgS@fq`@Yo4uf(itl4-@mIXVy_2*Aw^tMt6x~M1KTt$L<0(iRe+rB)3gEn z7oJv%+0@zFVNLI+c=NtRMgV$XJJOm+YSlvXfTN|Y8yf)~2#5^+pUC7LmG`lR51Xj5 zFk~5!-Jo|H=J9lI4e&-D_+a`+;ZnYP4FE*R4!-&DTb63XWHsRdKJiNhO@rO)#7Xsw z%HapVp5x^ANiB>uU=3|fu^pJ{uX*E8OV<@7=_bztmW&3@r&KhN)e;3n-5E=XRS{iT zmF)SwVjZ2GjVpJf-B871ip*q&Y5F053la-7de7Z$1b={`36R=U=-3OjfYe5ONP#f|iWURR%TJ&& z-dgPIu>ynXBfmySZ;b#@WTx_IF$&tYgzmOCceHEk4I7AoiA33~!m_#kUGrjv8iR7+ zir>Vcwt^|TF(N3NYL~AohGuB+-Q8b`cmu3V15@VxwXcp3fLTvJLseG={?oLo7Ew}Y zR-neF1RX7NNLF7*sZ}Z8drsRwIN*m8$^U|8J0ztfCdxSw|50fd!+Z<`ul{a<(o8ud~~mBp76g)>Cw6c5t z{G3J9^{sVy>>yRMZr5RT13WOCUj^aY@6nkf|D)xB>->LP9uj>!fIAFi-cmNIq7H}> zprIG|BNc~q1{$WWkGzxLYRlyWEP<6D@XbQB%!jqkTH)cEPaX!-WVF}NtvP`0xLC3S zJg`8&oX`tWDF^L{sk#8aCY`$d{e3WpR!05;VrOKzB?xkr)^UVhSeRCy9{*+0f^bEL zm<*F?guA@s11!2W13u^tR-WVvYYI7e0&pqdg&j-w25DX6dR@u+y$TsQ$%Ckd4?x#bemc1vP&-6Ij!mxi8Q`k8 z)o3KEa2+i3X~2^GG7JH$6&J#*IuKugAZ(29J1`(5y87k$026 znyS8w5@G<`RgRdTuSZNCSRq=fiYDf=%>d({B&DwGH}@-J%2*}fpx#Hw9JL?dA@Orz zLAN2Z<$^%=zptK5=XZdQ7l9|?0d7U!9UVNj4+E-eMnO65fx%hIg1IpS5|gbe^y+E3 zg_cT7hElqM9NdK@Z4vEp4RJN0PkKo@lqkN)E)8;+5o-tb#bO_!D3TnzV1vn-2=c^`fdM^W@V zc-;NzZE1p%27boRNTxx?EV9AYKn!^}z)mA%()2Q}n%RDtUt0iHq;dJ|$bX}=CdMaQ z4zdxAjg5MQr^4#3*aKoi^FiC$_9$q}dUZi|xTHwv+v@6Swzl^6h~F=G)S)z~B8#vv z%8rsE0o`Hh)J(?}Y!B1`7j8U43mOJ&Jd3TE}@*^y` z9=W^!VbkZ@X#0{~_`sTbcF~tF@%Had5t_-PC%BX{2rCf#-T?McYp>sV6V$Cr2KZL~ z!1O{^qPdAq=>B0&T58}4kzb(mK;AyY;KyGqK@yeLP2A_ zj(Y8nOk)%91DdUTc^YYkU?zzyqsTP$4z52BBP7~+*g}7kp_f1t12_{(Ot;g(L{%t52Gs2DR7>(Ew(`L1Yc=&Xxf1!WDdNSz&-5;ILog6Y2g`nCGyRc7YsElHZ~ zpDY;6^xo@>V-F73Mr3&ZKv)~#YFkKiWIgAoe6rF*cev-3~T z(1DJQvA+I*U3ODL8zQ~#-b&ku(RP7`>MSJ?QhCkDP<`{O33VgEG{5iiPH4MJ$>hDo zF8)?UX@$mQ%I#NC>bncMEpqj8SSabG+~EA;%4Uh3`i!oww|50)y+KP{K-J%*9O)~7 zrKypcY@q|%(Yzwb1qP}02SlqO)OFCaty>prZ2`jdh0SC?K?iPmHFEGodXKKLn;TA# zOOfX9+=N*!?Cwbrwcbz%mY^is7c3<_tI|Q+X2WZVoiAWt0$q?D;j{B_$c{;#d$%yI zJuh;oJGIZ|A-(w+`QuYoIk+yd$5n;@a?KMZ#oYdVi*PUZ6Y&Q>{=^ktXx)~ zKzyARSEfP{v%d2uro%!)XKD|2F1?S&X0n^KQlKR!522KJP^hnQ@z0pb3Dm?yy0o^T zzKT(RbE)%4TLV|~P;|r-zsfx3TsTW`SO^ibmw#v5HiDd8(RwhnS6`jF+8Yr*R*o!B zE?Hl9iIh#At$V2ayWp<0w2N^i5EMLOJ$mHZqEO*Z!8`U&BDL$$eZ3vF5H!TVE6X}^ zd1J+UNjBebr7w=FuC5Mcn0XndPgD04k-J=Q|g5=k_<-=AkB2rRX z;y*gH85kIdi(HJW;rS4%aAUvElGHHr>BK#mM0^~+;ZKb*DoEs zAYGK}cIhuX8$o^-0hVn^@4E`*#?vkzkI=sBa>`g&1?RZVOYCe$^Tq|Yo(edplJLBA z(;@8icJj6z+mR#natBz1hVYNB9e65;U*}T&mUVRd7WWh zaT)rZL!lzMfNYE$O*_y{Q<}tJs92JE7UIcDUXfom1l% zmeB=S@PB9lT2$2*pPwi1riBn*!XVr}etz;cJ~=2J43!Y2`L?@zLu?5u+N$ZDnR@VI z>;rpf_KuVIxFg{xxmsGH;**5FqUf^C-0)aBQ%ZT<6=^Y8(|DK6*r`*M5eM%g?Ds7X z7$~-A{qo^1R2SQo&5e!aFoz>Yo^sIpbb5)qfK_N{7S(KgW>lO5jYcojGI)uU$b^c< z_Fp)2GSe38kp4Bx?3`WVwcNXTp(Geq|p-%GN*wA9CNtL&vX9(fYFmLPYkK<#=3M83G>r+k@dbNiiLteG1 z_g%y&%kJ(LL_JfTkx}&u+%LG1ZNoi|4&ATzQb?u!313e-(((yAw7-9{0RsIUL5O$H z#(rtN8X=W0TeQCpdhgk@_7Tli_nxvj06_2xGtGP5kW2NYHFyew91HN({2}?B5SsB= z@FSs6>Pk#Z3^-Wk+?>N?DfP)j0ipaMG(CAqDKZSx;7(|dRjWN%zstmAm^vBt=D4ot zVQQI&MJP@ml2h6|m(!J{qdSzyuOKJay1jlk_HgTBgOjIc*-qCMF(!rt3Ts3ouw0rm zjSHPT&O=vQeuKHKzZ>hs?75`YKBAYtVyHA`I0iOwu4|PJ{uI=K-;}65_~3ubCW1$O zRcH(~IuUY~QqWUA(}g0@_)UvX4=IAc%lzUkxCY4jb}OAcXIG3d@RxkA*oZ{p*5Ajaw-O@!sdI?Q>Z=qL}CcP6{h)8dt z6CgnD8~6EU?%aFN%$<9_bLQM{CVwdTC3(wwS9#X+t|fszhwUQkw%Y4QsqCL;g*}9@D{vhD+4}$kHKnyixEj&z8AKng$pKvRpedD5Zy2rEjF>PRIXGwKn zNC@e&9M;)}yFBHVFZjvP?$-;eXmvXMdLm$anUslo1d*1vou6%jr^h`;y%&rv$q56)kEkjlR1Q0@E$Q5>> zXNC#&GCe&V<$Z}_Xu-~A2fGG-_;Y^VkXiWww!Zzse_Ws>k8w%$>R_=QcTDyqgzR|F ziGjza6ZjBswlG`%n1Op@`S+b`7n&9=>mIR*YQ<+{j3yP>%`{1|Dy4|3(W^PTO$?;@ zdxr*=&G~Qk`;DoZ^*Uy4sQaJs4#bXC&$oOaUMOg3;ok7FG4X%L0OaW4hM|b3kyp;z zX6h`5fhYJXQ`|otE-NoC1_5%WLk+}s!|i-GVA}ti#a8>dHtSzE&U>Wg`i>E*Vy%5G z<>gmchB~7?af3Sa=i!m{%a$<3y7PV#Q>GzW9_Q7}s{>yyyiuN7%FtBN-`UN8N)nCE zj~#4TUfFpIH>aoXq|J<@{4cxwn)wSDch25T5@HtoLSb_oNFs3WP|OqA=G;*npVKT* zdU;ge4t>neRGdU=m|pLo`_A{3(`U`AcY`{u0+f=Vli-iFJoYq+xuda`MtJV`RSpRY z%-aWV2b(JLB;RD=!WP3_{Cik2CyXKjaEtoGHeVv#QTEdR zvH*kC)YiUS3Lam2;JP-jed%+-NKA5*m8*iCtK!0Y33J?9{$a#Q#Zh>E)PE?g@XXZ` z>At28k#RAPEI@^L7Av5 zsK5Yst9QrtM&PAyF!|2TPQYc4VrwR(!4vmIRl7W~j|>@*bfHZQNlQ=P)vc3eZNEgz zwW_AG{w;bu3)?*&`#Cm{&f_}rhyfxEeDZ!Av?S@F6>#xzc*AwpB)_!cefY!yH*s;#;@KC3%6y-5cB5u^e*ZjdSOg6F+vW?9ILo35tvy z%*36-Xs8A$Bxw~D8ut@Lbjpki5EyqvDbUGA%@{iIShsJ9I%{PH-dlqQ)1#)UqHtSG z8$Ap-o&H#CJE%*g=zZFQx}3Gsctb_CCV|_xE^5K9`L+A6st$5+ta{#&1hu!mF3JV$ z(-hG%P{EJ14^b&TXnm#~u{X~i(EDF(94Zrl6Lqv_s@hNUhsg)YH(e=YMQ7_cSeu^W%gRytdHCVk}Qv0Q+hsWyj zYWu;gi0AxqWsQ3>47O!kaRJA&rhg^Cwc}6>c`hm{3m<441Gd^3%+d#9{4v0VsfN4a zfWma8;uMRCp`fEU>s%r;o={8#24=-m;xSG{OOxG1-*^0CrM~}~2!r_1dIcGsIMZ&y z{MhXIl4`SK^OC={OKNmI0;rttcGp|R{PC8mtB7;{FTd5r#j7b>t_A4u6L$4@#;u_OBvA9`!G~*Z9&X~7&1<)BNST{Y!iO&pXV$JB{*;*R?}yiw54qt? zKxMAoHC**+{&gKR#Z3q$N6VtL#S~~X{xk?gVCD7_XcuQ^m9S{{39CLfR@cK@xf;vC zCdeyTLtBHW~4vjdbPk#F=0zg$$X0Uo+b?J0PRDjNS%uJoZAvZ)sL`vwk z4cwbRSP?e^JxEfM_fT=rg9hUoP5F>U>Gho4+`f~27<%6$gp3TMWLQ1wau00j(Vi38 z?LEZCv5*inKXSJf8wHNU27P^Abyd~b5<^CHEj*62K}lXYV12Y8i2Tmt7r^VTsVU8` zQ*jWT9>!dHnnZ@vk6nsOhA~D^X=`ao0LNc4Y&9{F%EWuAD`|lo>5sX%xY2sJs_3V8 z;9q5DZ;#t;M7eu-lwY|7lE0ffNuR6Rb#t2t3JtD%7Uwz^D4;CB8OO3C zz(7EtOZhS{6Zq~8tB2A4xNX#O#jFJjqd4cPW5C(v^z$b^jlGc(tFkgOqTtsLSi^t` ziyh-0=f^ME37IO1a@ZCEjrj@!P0a9x%`3CcL#_)s{crOV6LwAJac02fz}wM-nnHTz z=Bp+U``95*#y9y)E?X?y-AY=qWIM=!bzjwo0v;2;VBn6?GdXdmd{3ZeBBCQ^8s1LY zI<{apEKOeV0Wry!%O`?-?~u%Zo+p8hoSWu{h6(A&%&WbLhUZUk$75RuvFB*ldIyuH z(+y?@%<=I?o?^7PucMjSsYFJ=j2q9jaa3!{c)`^US3B9QTMc(X$yspq&E#~=)l@d} z6cexzA41|T>~|inG|n$Dkg^YgWJbqVBk9?{CD$C7ArpYPgz#ls!7Fa6cZg`xhU9K+WAo`MZh&fr~eoAlwb z7;NzegT$UNEWj~e_v33me9xXroO&79vh*%TE|OLp1f|}z0qcw6JozfA&rS-AeEb*S zI4_skqU?8sKG?m=k7{BRoe-2^Lr?@joB2_X0RZks744$j=Iw-bU zA${RdP*~(GxSI(lT|hFvs%n zF(dr{;$;d1h#<6lHj19h)wj2^eie>}@nquHgCIqF%W8wuF!3LHO_d($YCK!yky6`( zx!GymI_4znH-r=-&Ho?+z@M`MdS3W*De(MZn!hUbnQZ7cuI|j#* zlOHbe!!GBA9=DKxSIePaUSipe5E;=^eGST$xx0fNr@agb;0J!cx$g4{jE5jUSI;=V zSsrwn#(Fi*-QJU;SJu;d9ixeu(3zZYuV5|*&wRa=Z128RsOAH0Y8JHRn9OABycPIy z+1D8_j+N9?0-qnlXR{t#TaRuWg$$LKPifN?l!CY3WR2VKMNvoQ$l6<4+Vb_Qd7G{L zrm%c{Va7Q3ySG3k(|=j1{onf>vMPFJG2BmMh3=%Q4tu(Pj!sGnHSn@}ZK!1SzI}Ic zd%D&dDPVB2EkVsdbM_Niuh)bxU;Lo36jFFpUR|7DUCgv(wvb=eoUcO7<2iLdQr3P$ z1uuTL$_Tr85pd#;Gga@*LunL z^oInmU{;T!26H5`+H|;%&L>WThfF5#69dl$D+bRGe1S4zyGG2KfSga!c$WiA9N7;iy7f^y57G#p4e{CjKeB-be*LG=aAnpO_hwRWob zKOTKAo+>o_+!E3ThmY5^X%(o-_xJS;aj~-4+Bi5nd)zw0L_~zsW;|GW~A|%6TKFCoB)xc0GcY{&N zz(7HNDty3j!@aRdF!Zmpo*r4IPT83`%-(2)as9^6m}McJa+rv%f&pxQWHf%cW*|HE zAguBc+!z4)_(3G3o2coPsTYC9Iro0$$dW|shzPp1bAU-ZRh5@zjg3q{rASM!aWOac zA1$s$O-)So^WBg#a92j|PkaiLi`{K@t%{R3g-H8JjrZUTOmsC_5%D_ONjlmLf@z|@ zR@>E#hrFAvbrM%lR1BagrB3nk^JNaOoPzf7EA<>7qs8brvLAPl(y9!JrW7D(2KZk) z*iYtV{J1Mgt2($&uc^?_cI+JpayT=xf68>3v$db*7dL5_7jaK$gBi#x5bt4(sE7bW14Ms6zF<c4~5*VoxOIY7VF=a=D)XEN%nf3t!P zdc_Zym(0Cu_cX)FAM*=Kmbk~W!Ci?LaAx+f(e>@zbbfO~U8gMB9EZsbmjji{qr-2p zV;==jm)oGN#dShb^cAPOhkMzXjqA6fyN+DZL7>ey6|+l!; z9Ouf4;U^drdUcasAnG<*9UKna)wWi`DC9HO>i!hR%}GA@jfXRmVPK=l6{En= z9m$5~#*onKD=SnhREf#g6F!w1Hm0TPSW#+LyAlVJSB>6rQ8v}+-*kt~e(J9L{M9EB zwY}=?@j=hb>qp_@K0~>ojAc>snc!mm<9L0y%J4xMrRO6oR;b04`^;TBxn^D+PMM&o(hKk;M zvgwVp32CV;LCK=dHP#9-uMC22Li*T>SNif-DT^MF1g4GqyZ!ncHnLZlwV5j1SY20c zOmv5KovYw}cm&WVEKA=zK2TGqF87@#LnOmWw|&PG@hW8EHl&jy!h#s0KCYVKT058w znb&r%b5 zOZS9MiTlAU2$AXPIiD%B#Hw{Htqo?(UWR~qeeJ3)zLS7hIIF?j@DFU!nfH(Dm1csi z`C~x$l(qtjL$pJ=I*7cPb!_PP)FC1jPNyTf<0m$Rp*;*O9otOhoI{dfpGxPgHM&#E z`WZx6)rKTvLBD0t6vg-EylFx`vs)mF>;mqsFmrSu0)} zU~w!xhp;1~qiRMPNw5F~@9Bk6hza%b65rFu(nR}Uv+d5DRn4`OcO?X#Lu856oQju` zWbLnpe^}dY?a=sUwO8;esc9NA=~$Sr-Gqd6%h=XNh3}6_hNaE_c~)HW!dzFfhL*pN zwU`=~8caSa_1*hSuWED=Y|Ge3(3KjkLx@d@rn(6!wzbJa5)D}7r?|L`$;us{xB?M- z-&P5BLT{XjG@OX9tg7k`b?t1g{1$rEhX1TjQzxmgu$YsTlZ~Z>ouv$fFD`A*{{WSC z<{UBr>|mmen6O`{^Es?T{&UrK(^)NM5%T5RAE2$I9yS^B7G9t_+hpo!{8G*MWsLsL zXL2eEx`&hx>F51ke;*p+d=By6{l^p<+%=XO2hzT|@wXw;nr30(8k@%}bp=^(i=o0h zH^($oR__x*9xEHWAExwLuhATR_JVq+IiSWi-B-OHhDX<1M#I?qLx;VNye->bE?69n zgY9@9fw$M<9$_<-t$r~H>Fwq{87&u&$NRDf+6e+sz|J+-WA;yc4@R3kc0{T@aiiMl zZ4EWq4KWF1jrc$2La-OG3HcVZW6Gw4n!mU$kIS3k+Rm$lS%`Y#n z4(Qy3TQy%7d1IY+hRs;h7v6Ym_|8#o9owsa>4BS@k<#V?>iPSA3$2$cceiH(+<<=* zL@vGn%Dr`6Cp`D@Y4q`KP~7_AbDLF?$kMXl3|=sl!CzFE%ido3RD@ZAN2DD%GH|Z8 zqSE3N5!;W}rZhBnXz0L8%>eP*srYF{*55mwz2_nM;K;fhs)~8zb{353U6v|GUO=SP zA3Ixpa+@5S6yj$UT{1H^_E(df|C}9L9Thdy*=aSN-n^{*5g5tC zM&_@{v4`O;o87rRViGbrLg_C)?d+^Imyv%TnVRa?0y~n$Rlbp>Zh&}XU*~h_4w9aY zZ9N^cK5rc>Zjq6ISL$J?f??a=7!Qw}z>7wR9ld%T4&rlA z5v3N)uVlAQ!V6R8LPKR)unu{vH*;3-v47ssDDSc@Tgk$Mk*U)xZJ_^0pK=(D`fJ_C zL1E#y1TI-PISUXoI*2Kl>?59oDYJ6URhVab^whrFU&ST1dt#muW*X)zT7E4MFk&Zh zMBlq}`V}flPdB&OnVF$L;a_0HLFB*^jootB1AY_vV7l$Fh0KqKSwpCDVQk#I)^`N$~7$9l={f!AuPF-HVu2R#!7`JrMmdx0M$6 zb7y-y*C-l8E2yupJ+nkSJjC%ze)z8BCpx~Go*QD-^*WKX^jtyHoj?gkt|7=cE9y!>NY>rr;@)G%*D4eQ~k#H%}CgXAW?XOL{eA z(&rG7kUEVC--7Tv;u>>u#!Fj84}Q9!m)Qa&7=Yu`SDXsGIZ)!FX@{F#CMlt$ol^2? zr;Ix)%l05h4V)5?a?kWTQ`T}Xo0x%I^>pM+wq0+ZTR zk+W^ZnX2V`C`Y8bngBk4^)|z-t!2R77&vwOq~dBe{VtLh{W5<%1>vuUurK@I$dm^+ zGs-v*v@Eo97^O(krWHX^g#(X8A@vMN?CNyej2(SzKHfLK2 zCD9ZE{{&%)VCCcY#vSx;eZFND95R8}@ zvc0o&?b0u9yn1tshKxaxk9w}Tsp-gD3Pd$+f%3Neb`I8)jg3w7trr$>*R63Cv!rqvx z*yS~^_avy=i*6hj7`dB*Eh+p)1Ire>c=5E$Ee{pbZZEB^QvH~y##E|b&ff-(2U44@# zARcf$bB>;w{QL+<(eJQrUgXDB4tv%&HRLfEG8m~mh_aut_GV#!y0;+WD6b&oe6t=8 z7AP5w1K9Bn#lw?4rbQIZByU1n8A@D|LNs4}Wv_ve|Etr#}L$d?)t4R8cj% zQiFMoJOOZ>qb2@q5`3NXROZUZ)BdxR{SM6{t8`*-yr(gZJLh0hCQnE;7BWEJt={dD&_MZOFoJ-|eA@`GTw6JksKG zFDvs_^u(X{h7X{paawJZ_CuXgjzT>2G&zBon1X35d>L2Esne_g&%Ezv9=toYabz(b z3?9A#^_d3!dJ0W+f&hGwNNJ>{oPJRS^==TdnOMFD9@k|^U&tD#vDueXQDdHTCt~3KaVCssZp-&|G4U z#iL$^KyODLj3_w0&va+ks|s<|1oXsI19$b5-z}_cBf*p4dCl_TB0S7s7jPcT_g6yd z>Mj8gFVwycd_uHp< z1N}F}@+c>MaIo$P_&ZsUow0dq==lG>aYV^m+1!m;;(1N zc<6R2KPN{+fkiSbq&uHX!azsg*m{O@@!jtwd}F`8ZPyb`&m>`IWq0nh(iB^Li`e5P zRm6Y$UI5z!O+yYky7O0~#SK)oAHE>MM<|t&pzdqGLkeh3z=8l+NI-*&k+XH-{$*O*?j!3fM~T z_P1}|qbh@v7o|**NW=5Sipy`pA8u*1gUP&E0hSaG^Mv0@vennum$fjrldWP4XQ}5&;bY;NT6s(7$NZWNmIp z{!x9PAf)pkvb*L}8bGoH5U#Q^+uPe?Jk?m2VGzH3&mOxL8eO7U{35`_z##9_A7Bw{ z>OF}dzQ6Hz#hwW+@MVT4@_E|K%=CWI_Hc>!R|_zkMaBVliFqP)j^YEUGkJw zZ4_Cl?z=>-p&lz<%KHgSjG2OoX%2N1$@)8$+lgoSq4l~S-T$J<$6w+6sb97GdJK3Y zgRGI=CljBxe^kDK3%wDmhQkjJoT8)YxF0_+S9GJG$TV6R8y$^FOD*!KB)fS~U$vh9 zX6pIzzv8xqm}K;y_4_%;;J>-QDPv9%KBac=9tFMF)6&wG;;JIOa)}g!k;zGlJCyIf z6~3c;DZ|3%4@Ui-&2smj98hO~zwDt9ySVVd_CVp3Hj*&2OhjwGL;OuE(anQ^(}lcy z-BHiV=G$Cx=+;oqf_n1bhDx_}spuif7nfr_c#McNYVum3tLL~)MiR?rVBpSR?5nL- zLg!%o%=T)#C_e!hc<57>9hdXlze{?Q>H!=jwZi{dSqk(r2nsI%i9stmKDI>UgS*RI zCQUV^?@XVRXNrPogGZSS;W!UmUZ{{*d-uO*uhvcYl4?sJC1cSGxIyp&6J{-(4Lkr~?hPwLtipz7t)-OBUO##ZLKEM3;CIw)C{HbjFT~Z39 z?iOnD0e1_}lgV>R^1$=KGJihFvKojV?2ZfHo!ft2bXO7qd)? zxUCqb=h5$*&^J_?qEdi!J4S%huuNSxwSPsS_yJpISyft6Vhf^1Qaa@r+k7QjfJq!F zZesJ`Q9I#UiRkxy)2BORbDrDWWsO@yc@|aQrWdX-YbMWqegU@G8%i3Gg>M#sJ@+ft zvuik)0P6V7*IwYJE3*LiT7WBUQY;UD@xWb9F4Q`bx7-DlUZ1RTyZI4-1!NBM0mw|5 zl&HuD$S4nmM8)4!?lQK1u%-U@SOyCV3kv{`OCRpGFUnkI8Xb9f>*Fnzgk-I{x=rzO z)Hygr5$BBn=IJ7~OqsGnR@IkmWuyOq{HwwgikPdFc)AC+n2)&mT^_U5_na&Cv%dT% z&{Bym;AAyLNN)y8c}^@TC>}l)?EE~&WsuQ~0t~yQ zm+n@CLSD|VQO|z`k_KD@xD#G=(2*PeX~8rE9;eNTKnU1Okb1J~ISJ|I)wH;vzC1l! zoQ{$5G3<;st`vI?4ngT_XZf?O-ST(_05ORB?y8G4XN-RbM-syz&Y93ECYIrQ;Q%~I zW5?6&en)_V{1`lMuynSxT$9Tz8}92(qA%7gE(mb0s7FlBsZR>mF=0ZOvk^)ZO%3g8h8Spi4E^2P>r{UZ^m;S@3a2^N~<5VqkL|EFkO3HzM< zybf2;a^LYZ7|QTmTixXDeaiJ^_unm3QPG!!KT+1MnA1d!Otsy5hP}N#(lC9+ zFY-8~ZW!SYi%DP;7`LHg(5-s9F6l#QqC9m+bNlLI-Zc^3kylb)L?tOGY(wiKW^*5G zIzmu~YAviXtL76eG_U#FhzGlnk>j&dGWuK(r}eA*gg!oHQviZA6@HejKGP*Dmzbaf z&^viPSyLYySr0Q^Cob3S^6LE6#FGL-F4B1FS?*)6B}@sz^KTI%~m4 zg=kt;otYV^SHtlGohFTP{br%iHVo$K#yE&tU0I9kd>6OQR{m2MV-X!Q;|64FvKD=|(Knc38lQ2+=Jbj#- zr=_E19Qp>|bOI41NLT)_+N2UHBQAEVmKfNiY3U%q9{QjITNHu^IkH#1` zafAZbv>-?k@(VwHE#dYC{t;N=pB~XLt(eWc^B=YgE5a z(mDfmZ3lqlKjD2NfXhe#wOf6_N_=AT{ z>jw5rw@Kt0+3!I#JO)11-pC_G%)6|2oA~+>1pn(=692!dwUzb{ohFDRAweny^=@+b z0Ui~AKiS#Yv*SA|6THxK^A04JESc18dXi)gq8C+90q4~?{DY5NC&)GLzsJ{6BOrp< zY|-R>C>#8m;mcbY_z@nLlh=%Y=*G1~k1+yW}S69{l0Yo`N5xtc9SIpzUUf&E|3_h=6l)WQkr{fiwQz z{c~)%we%gyzs|8ufU|)py0Wwf(97t|jGmUp@ON+UmAVh*BAc+{_1gS^zwtfmF^Hrc zM>m$W*zoh>bDk))x3dR6c1;wuB4*`dC17}LZEu&B+1{6|S$F%F3ge_FibUGk+tuht zl7By!Ra4Rn_{~0g_EWcmvLAd8LFw(^a`}I&Z214B9>{-UX_5c(Uxn8d>j6eaMly^m zdd!Chw<2t}sHv%8^F~I0{&|u8Sn}SxC+TT5iRi4xw3hEr);#kBU}%(ve>^W^M*ttVB$_GDns*aMH2_RkVPs@vp0||+ zrtJw0ze558u%7O2Zn~8cmnHuXBomfEJSf@<2gStLh5RN{9YutNgUJK^{OIZa+w%L&;AWO)c7avyn^UO8h+Xo6lNGo0-*<0%K zEl!EMk9J*)o0@Lh+XKTR7dzJ1SK_fFW{8@01A2C5mU|K0<|3eaBldD-uWCZewv7T{ z>dgz)Rw^LHaM)NKa6p-W`QmJQ86$?1ggmeN{&A3Wh%?r6TV2pr| z!;>FHC7H&`+0XWO(=B9R=iImvD{p;`ejPLT&}(s9-5eKu?pLzR*YE#D?VKs(5QcHA>HN=t7-?fi_1pWJFACL#4Y zsA>)-Cy5-Ci!LxXTS-XJ!822@pEGvLMblC`ItHAS`JXse)YSk*2|bfhy}E)HiMr@s z7}cZxPSB~Ca|6Nt$Y~*P2V!WF5_H;5X9*?4+Ho5?V5I>~g^-lla%EWuF(J19<0FuJ zv^{_uMwgF3A`-lNa#9RP3Thqqewl{;P;|>ZMyD_z0!asB43Q23G$v6&CnuAIfwnlr z2#mxG+=ymS9UK6()sn)o4U!DB1LWHu9iiRQWH)!6@2J5>y+j!gr7ctdvI0`>p)gyk zS1;a4D%ojzVFu@$nxwToj9v6C{9ig7N#(>%J%9F(G&_&9BYK zZ|+lfyEx9GL5sM>f9<8Ye|VZ4`*k= zA^I*E2r}U^A)!a7P5#)mBtXCj-8G^HSx(eQ4eqtNx2%VZ`CyBX#-MkC&g=MifV=DH z8X$iD+P+Us`^?wM4kM!nHuu^ru%zIw(U?W&le?xsw%SCyz!hzDDa$cQBtCXgj8x_@ zDaE3twaX1npVfc_R-UDq<3b%a%7BWglVoFM2>5?GQ zB&BkBU-9E8n%i$pkGvP~;*G^v0D2<%S+ccK?b!F!CYO(L(rF zy6lW~9Ws5|fsPl0yc$EP;TGT^iTSC&`rMu)tAU#KT7RWr;oA>ahFYz5G>k({tjx3fwo8TKLowZ-)507GMDX^9w_j*s;}_`0|x&%zAoA`Fd=dePr% zzf_&|lb{6ZYrxcRhu?O0nfU9*seBSp$pA?c^m?jCbm#7}g#UmOgCiNl4t$P`Rz=*G zUAd(8s!Ii*N_Y;q#}}b%^lRqFMgYDzcdXOao@@{lK?Wf1j;DJ_1zwYlex=*$uK{ce zz(1ruTwD^8ar<}!+8Q8jy$cCK`fo`JAmIPJ1yT({V^4tS>AIY6Ka9J$0VRg``nBYi z+Qz z1PNs4%6c*q(uS=Q7)bEs-T)jHAOl>jS8suWTi3M-z|+3w{RrcN$U&tSxK2?JxJ^a} zlE#cd4}{pSfExJGGYjJE`yg9*LRfNe5aGWNFu_|0sL4Q65JM7Cb+3o=K;#On#zF>q zOTYnKrZ@%suRQ0wkj{l`JwfEeYbvnk?jL;Pvc7(M`{iXt+oim`p1HT|$&a`Dl3|sf z0WSlf@PL}3X;wJj0EhFiFiKr*Fq%`mv|NyfNW(^xV^Y|H!iYpf#$w|<6%<(Fx+8&M zSAzDLyl-~|RM~fuN6fgn*P7~AJ7f}|x=TBjwvwT4cWQ$KQ`TT^Wmq#aIdR0!lBbl; zYq2=LaUcR%I-=g4BfItJ*(&S{2Ju_K)&A%0SFZe|H9hyt9(OhF>H~GvwEL3mMxqs1 z=p*V#JoB(EuqAS5N5T%*h#e;hsasv0T2Z7*$p=Jm0Q=x)>|(9gwQ@9~1ehL1p7Rrm z3ZN~grZ&oX>%)t<-6=_;vK)(x_3;QOQ05?88?W)PvuDoL>s=}NW848h&HCnDfU1mD z_YKZ@v}5*@B*R{c8^WVjWVpa zPmZ5s^-SfM0ndqqjJUYGD9$8R6R<6LY-xe;LVv9Tn%r#DI5t{H#M(6HdtRp1Y;{9! z3s9H5f-la=RafsP8*{LfS@BSVY{Q>JzPF5wBo$chy!|G?k!IcWO#Utvo%8tj6v;5a zE&^b{Z!(;sLt5Me#|(9FQW6;gC?$hJuY=_XS1_;t8M2i}k_FtS(vJ5GY8w?iLQ$6i zCuotjq3Smmdwwe2@~KSLsVWKvP3y*=xb;sG8MFUpeZ<=4;HP#+AS#p6Il@QNODiP1 zT0qizW<-W1FJer_GSw}2rd=ZAh*x>cO)?|R7!fKV>Ehy&`INz{4T^q_O(6gNwc|XB zcHx{gUgZp0km0q>forimnLnfH>w_81hmsG8FLi3~ZpJ6_qdjWfx9SoZkPI9Z2!oG_ z2!U~T>PSpzMyN|Bc!dIH zoZfCV{rQi<4BRi`A-j`|I~_NMeeCy3DmcUsC&D*8hfGeriQZmJ-)Z&n2(a7a;aM9H zIqozazgcw@324;Mb3*bkH+8FQ+-q!Bj^d&t9B6CZj!s9T#jlReNoXwFMcXHzaQ8$% z96d-cSuljZn@lDD&JvgEY4lX#myU_S{3g|Pf^{e13%Z1hi|+pUe5}<@8Mqvn0ynt{ z`9u%(qUo6|K&ZD@`I`4f^QUu9XtD|j=tEuJkO?cH3avZz3Y2Y*FK6^3b(%(FxH-(t zErYKK{LBz*N)H%f$-L}b@k^b@$uq@4p+zk%ns7%iE%)PM0Yq-}(x<4@@S}BOVYAmb z^6xmL_gY}IN`&^k9fiktq9iPQi5B;*hc9V=UjoTQN&_;%2KOgc=r=p`P(?aa(u%KF9{CuXG>Ha%PDrq;C3_+yG?ODsOD~x$ z=IP%beS)58og~$3tKRpRe|u?Q4Lb_;&;qarol0nXsk|d3p{;G6(4fvCvaZzz`ylZs z^Gv|rX2q6*iUNH|aPkr-rYkm9KkQKV0Bt;bOhCe%=G?b0m1l%meRi4mrJ8wa*;^=yeROszZ39A?Fi7PJ=d^&dP6)ph;UqnQr6xh?Muq_NZ74(NfQ+AI-@Kr9i;r(F)JC4=VPhU44VS8I&8PC4mfuR|W=TAK5( zJEn5{trBs4gRKYGs3b7IwtEW1>MeH8t0O5i3M3@l&kuq4X{d^xEX&_>arNA;N>pM3 zt$I(UCoB`$jp&2>KI|N}Wv|gbw;MUKG)d+0^gj}T`>w#iCBG*jq&7`Z#8g?rTdKI3 z)V^MaizY2Ct(h5-%THs^=atOO&57RDix{r0?6@FI3EoHLb%ZK#r_c)7?P&}Tf==@b zGHaPJ;$0P>P4;3Ha|YCPu<2-^@Q5``oA@cXhr#6i)t_@-;*mbR!*taI0)aXh_AyT0 zcOiPa_w@>N`9-_Fsu(LbYPwIw6xU0^ri0pxkf=QmPZyy|^I4U*%;0vO`KYCsSgu>? z)LTNFSZZK$5>UU;2qy13Bv`c(2+BBt({xcK7j01My)$OcM#<@IiY_6pvoC4d{lW~U zf3-+vJnzYfwr zXM56m(f6THUEHbnOfHh4wSFccE>3K(vh5n#md~twj{`gE2vsyJ`uy^YkRhGl?Z^AX zEveXE>C6SO^CPtLMbQ3Saj|jgSs$IJn4sfT_Qr6FmrL9|dMsuuE+N6N%Ef)A`=j(@ zcHJZIXms9&J0Fmgs+`c)XG<&BBNFNP{55%ZOJ)!sqrzrhYqy#APw}JuOZDL5K_fXn z*4k4UoOdJcT8*!AfV<5*EfJRG<>h){o$19P1TO~MPrHsFK`*bJ%auGq`~Pg;Kw5h; zHi62X>kDODi-9zVYfs~PpY%lEh76>MRYWo(4yo90Ld?t==X6H~=)LVnw;)0IN}hhw zYzgX(WeElb6)jCp=$7jo1wrmCoGp9vy=`B@vy7 zpyWVK5?2(LM@_9q)A8BqL|YfB?q-bAjHah)bLcgR>f2l=`1}VqMDuRA(YR?j zLK~h!f;bFVJIZ&JWtjT}4#8Q(IgLwXB%c`elQG8iN_ig>K{V}9>d>nXi~$WB3<0e> z<>%+xC!7&O^M>%cGm;uBnwqW(u1pcfw?toNdY_K6#KG6vsCWJpwOAgpfcGUZxVUOd!~$m6MvM1>JZabIQq`Dk9IP3qjUQ-qf1;+A z^jbaBQ%vM^Jo!?VFqdt>yV12i>M&|MRi1e=5HUz^Xo7mSTiXQ*O6)P0t(OMNGe017 z*pzr*V2;16()HW=olsC63WqB53?a{MjfFM-q$>y^*Df>m*`mWZloZ>Xj8a(+wc=um zAVC@`g88bjPY`T74T^%}uklr)w7QttE?zfQ&U~00U zD$3#lIY4#%e%DezG!aBFN4 z_NPmOIMKz^CyI(q69T;PNsg&vo>#;?#^NsXKfoMFAiS-QGo3ou3o@V^gM3>63NcVk z^E%q=Af)u*EG#QAfLmNHjb}tmQAN)9!?FWV;`gFxFXtm%uiOz*!1ju|T�1@}t7 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 S{H=>2$Vw?l7K?xU_CEmJgn9A+ literal 0 HcmV?d00001