From d925f8ee84aaa521a3d32117b22d18454c2abce2 Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:19:45 +0900 Subject: [PATCH 1/6] feat(core): Add TB324ZC identity, device class and portrait TB324ZC is a distinct device from TB323FU, not a hardware-equivalent token, so it gets its own class and no fingerprint equivalence. Its firmware dump matches TB323FU, so the two share one portrait asset. Co-authored-by: Claude (claude-opus-5) Co-authored-by: Codex (gpt-5.6-sol) --- crates/ltbox-core/src/model.rs | 14 ++++++++ crates/ltbox-gui/src/model/device.rs | 51 +++++++++++++++++++++++++--- crates/ltbox-gui/src/widgets.rs | 19 +++++++++-- 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/crates/ltbox-core/src/model.rs b/crates/ltbox-core/src/model.rs index 29bd74b8..38d0c5b5 100644 --- a/crates/ltbox-core/src/model.rs +++ b/crates/ltbox-core/src/model.rs @@ -6,6 +6,12 @@ pub const TB320FC_MODEL: &str = "TB320FC"; /// Model token reported by LAVIE Tab 9QHD1 firmware. pub const LAVIE_TAB_9QHD1_MODEL: &str = "LAVIETab9QHD1"; +/// Model token reported by Lenovo Y700 Gen 5 firmware. +pub const TB323FU_MODEL: &str = "TB323FU"; + +/// Model token reported by Lenovo Y700 Infinite firmware. +pub const TB324ZC_MODEL: &str = "TB324ZC"; + /// Whether `model` follows the TB320FC hardware-specific paths. /// /// LAVIE Tab 9QHD1 reports its domestic model token despite using the same @@ -92,5 +98,13 @@ mod tests { "qti/LAVIETab9QHD1X/build", TB320FC_MODEL )); + assert!(!fingerprint_model_match( + "qti/TB323FU/TB323FU:15/build", + TB324ZC_MODEL + )); + assert!(!fingerprint_model_match( + "qti/TB324ZC/TB324ZC:16/build", + TB323FU_MODEL + )); } } diff --git a/crates/ltbox-gui/src/model/device.rs b/crates/ltbox-gui/src/model/device.rs index 6aade6e5..355fef31 100644 --- a/crates/ltbox-gui/src/model/device.rs +++ b/crates/ltbox-gui/src/model/device.rs @@ -2,7 +2,10 @@ //! and the live connection state, split out of `main.rs`. use crate::theme::Palette; -use ltbox_core::model::{LAVIE_TAB_9QHD1_MODEL, TB320FC_MODEL, is_tb320fc_model}; +use ltbox_core::model::{ + LAVIE_TAB_9QHD1_MODEL, TB320FC_MODEL, TB323FU_MODEL, TB324ZC_MODEL, fingerprint_model_match, + is_tb320fc_model, +}; /// Classifies the device model into a known SKU so wizard gates ask /// "what device class are we on?" once instead of comparing the raw @@ -25,6 +28,9 @@ pub(crate) enum DeviceClass { /// `qsahara_device_programmer.xml` Sahara manifest rather than a /// single `.melf` loader. TB323FU, + /// TB324ZC — Lenovo Y700 Infinite. Uses the efisp/GBL exploit route and + /// multi-image Sahara manifest, and is restricted to PRC firmware. + TB324ZC, /// Any other supported model. No special-case gates apply. Generic, } @@ -35,12 +41,31 @@ impl DeviceClass { Self::TB320FC } else if model.eq_ignore_ascii_case("TB322FC") { Self::TB322FC - } else if model.eq_ignore_ascii_case("TB323FU") { + } else if model.eq_ignore_ascii_case(TB323FU_MODEL) { Self::TB323FU + } else if model.eq_ignore_ascii_case(TB324ZC_MODEL) { + Self::TB324ZC } else { Self::Generic } } + + /// Whether this class uses the efisp/GBL exploit route. + pub(crate) const fn uses_efisp_gbl_route(self) -> bool { + matches!(self, Self::TB323FU | Self::TB324ZC) + } + + /// Whether this class is limited to PRC firmware and country settings. + pub(crate) const fn is_prc_only(self) -> bool { + matches!(self, Self::TB322FC | Self::TB324ZC) + } +} + +/// Whether a firmware fingerprint belongs to an efisp/GBL-route model. +pub(crate) fn fingerprint_uses_efisp_gbl_route(fingerprint: &str) -> bool { + [TB323FU_MODEL, TB324ZC_MODEL] + .iter() + .any(|model| fingerprint_model_match(fingerprint, model)) } /// Lenovo tablets that expose two USB-C ports. Only the port on the long @@ -53,7 +78,7 @@ pub(crate) const DUAL_USBC_MODELS: [&str; 5] = [ LAVIE_TAB_9QHD1_MODEL, "TB321FU", "TB322FC", - "TB323FU", + TB323FU_MODEL, ]; /// Whether `model` is one of the [`DUAL_USBC_MODELS`] (case-insensitive). @@ -84,9 +109,27 @@ mod tests { DeviceClass::TB320FC ); assert!(is_dual_usbc_model(LAVIE_TAB_9QHD1_MODEL)); - assert_eq!(DeviceClass::from_model("TB323FU"), DeviceClass::TB323FU); + assert_eq!(DeviceClass::from_model(TB323FU_MODEL), DeviceClass::TB323FU); assert!(!is_dual_usbc_model("TB330FU")); } + + #[test] + fn tb324zc_classifies_on_both_capability_axes_without_dual_usbc() { + let class = DeviceClass::from_model(TB324ZC_MODEL); + assert_eq!(class, DeviceClass::TB324ZC); + assert!(class.uses_efisp_gbl_route()); + assert!(class.is_prc_only()); + assert!(!is_dual_usbc_model(TB324ZC_MODEL)); + assert!(fingerprint_uses_efisp_gbl_route( + "qti/TB324ZC/TB324ZC:16/build:user/release-keys" + )); + } + + #[test] + fn tb324zc_remains_rollback_protected() { + assert!(is_rollback_protected_model(TB324ZC_MODEL)); + assert!(!is_rollback_protected_model("TB322FC")); + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] diff --git a/crates/ltbox-gui/src/widgets.rs b/crates/ltbox-gui/src/widgets.rs index dc083d24..9eba2731 100644 --- a/crates/ltbox-gui/src/widgets.rs +++ b/crates/ltbox-gui/src/widgets.rs @@ -4,6 +4,7 @@ use crate::*; use iced::widget::{Space, button, canvas, container, row, text}; use iced::{Element, Length, Point, Radians, Rectangle, Renderer, Theme, mouse, window}; +use ltbox_core::model::TB324ZC_MODEL; const MATERIAL_PROGRESS_PERIOD: std::time::Duration = std::time::Duration::from_millis(1_400); const MATERIAL_PROGRESS_FRAME: std::time::Duration = std::time::Duration::from_millis(33); @@ -1064,6 +1065,7 @@ pub(crate) fn device_portrait(model: &str) -> DevicePortrait { "TB321FU" => DevicePortrait::Png(TB321FU_HANDLE.clone()), "TB322FC" => DevicePortrait::Png(TB322FC_HANDLE.clone()), "TB323FU" => DevicePortrait::Png(TB323FU_HANDLE.clone()), + TB324ZC_MODEL => DevicePortrait::Png(TB323FU_HANDLE.clone()), "TB520FU" => DevicePortrait::Png(TB520FU_HANDLE.clone()), "TB710FU" => DevicePortrait::Png(TB710FU_HANDLE.clone()), _ => DevicePortrait::Svg(GENERIC_TABLET_SVG_HANDLE.clone()), @@ -1412,14 +1414,25 @@ pub(crate) fn wizard_nav_cancel_generic_with_disabled_next_tooltip<'a>( #[cfg(test)] mod tests { use super::{ - App, Density, IMAGE_GROWTH, MaterialProgressSize, WIZARD_CARD_GROW_FROM_CONTENT, - WIZARD_CARD_GROW_TO_CONTENT, WIZARD_CARD_ICON, WIZARD_CARD_ICON_MAX, WIZARD_CARD_SQUARE, - WIZARD_CARD_SQUARE_MAX, density_for_content_width, extended_fab_primary_style, + App, Density, DevicePortrait, IMAGE_GROWTH, MaterialProgressSize, + WIZARD_CARD_GROW_FROM_CONTENT, WIZARD_CARD_GROW_TO_CONTENT, WIZARD_CARD_ICON, + WIZARD_CARD_ICON_MAX, WIZARD_CARD_SQUARE, WIZARD_CARD_SQUARE_MAX, + density_for_content_width, device_portrait, extended_fab_primary_style, fab_elevation_level, fab_primary_style, fab_surface_style, material_progress_arc, material_progress_gap_angle, material_progress_metrics, wizard_nav_layout, }; use iced::widget::button; + #[test] + fn tb324zc_reuses_the_tb323fu_portrait_handle() { + match (device_portrait("TB323FU"), device_portrait("TB324ZC")) { + (DevicePortrait::Png(tb323fu), DevicePortrait::Png(tb324zc)) => { + assert!(tb323fu == tb324zc); + } + _ => panic!("both models must dispatch to the shared PNG portrait"), + } + } + #[test] fn wizard_square_contents_track_card_growth_endpoints() { // Pin both endpoints explicitly. `App::default()` restores the From ecbabc1e2eb508cc44d1096591fd728cbc6eb0ff Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:20:28 +0900 Subject: [PATCH 2/6] feat(gui): Route TB324ZC through the efisp and PRC-only paths The efisp/GBL route and the PRC-only restriction are now capability predicates rather than TB323FU and TB322FC checks. The EDL-start PRC recheck no longer rides on a missing rollback floor, which TB324ZC has. Co-authored-by: Claude (claude-opus-5) Co-authored-by: Codex (gpt-5.6-sol) --- crates/ltbox-gui/lang/en.json | 44 +++--- crates/ltbox-gui/lang/ja.json | 44 +++--- crates/ltbox-gui/lang/ko.json | 44 +++--- crates/ltbox-gui/lang/ru.json | 44 +++--- crates/ltbox-gui/lang/zh.json | 44 +++--- crates/ltbox-gui/src/loader.rs | 9 +- crates/ltbox-gui/src/main.rs | 76 +++++++--- crates/ltbox-gui/src/update/flash.rs | 49 +++++-- crates/ltbox-gui/src/update/konabess.rs | 8 +- crates/ltbox-gui/src/update/mod.rs | 4 +- crates/ltbox-gui/src/update/root.rs | 33 ++++- crates/ltbox-gui/src/update/sys.rs | 36 ++++- crates/ltbox-gui/src/view/flash.rs | 20 +-- crates/ltbox-gui/src/view/popups.rs | 16 +-- crates/ltbox-gui/src/view/root.rs | 10 +- crates/ltbox-gui/src/view/sysupdate.rs | 8 +- crates/ltbox-gui/src/workers/flash/full.rs | 156 ++++++++++++++------- crates/ltbox-gui/src/workers/konabess.rs | 24 ++-- crates/ltbox-gui/src/workers/root.rs | 26 ++-- 19 files changed, 442 insertions(+), 253 deletions(-) diff --git a/crates/ltbox-gui/lang/en.json b/crates/ltbox-gui/lang/en.json index e16817e2..098272e7 100644 --- a/crates/ltbox-gui/lang/en.json +++ b/crates/ltbox-gui/lang/en.json @@ -205,6 +205,7 @@ "err_edl_probe_work_dir_failed": "EDL probe work directory creation failed: {error}", "err_edl_session_open_failed": "EDL session open failed: {error}", "err_edl_transition_failed": "Could not reboot the device to EDL mode.", + "err_efisp_loader_manifest_required": "{model} requires a multi-image loader manifest. Pick `qsahara_device_programmer.xml` (or its encrypted `.x`) directly, or place it next to the chosen .melf file ({path}).", "err_fastboot_command_failed": "{command}: {error}", "err_fastboot_open_failed": "Bootloader device open failed: {error}", "err_fastboot_recovery_unsupported": "Bootloader mode cannot reboot to recovery directly; switch to ADB first.", @@ -227,8 +228,8 @@ "err_flash_parts_erase_failed": "Failed to erase partition {label}: {error}", "err_flash_parts_part_failed": "Failed to flash partition {label}: {error}", "err_flash_phys_write_failed": "Failed to write LUN {lun}: {error}", + "err_flash_prc_only": "Flash: {model} is PRC-only - cross-region or non-CN country settings are not allowed; aborting", "err_flash_set_bootable_lun_failed": "Failed to set bootable LUN: {error}", - "err_flash_tb322fc_prc_only": "Flash: TB322FC is PRC-only - cross-region or non-CN country settings are not allowed; aborting", "err_flash_vbmeta_key_unknown": "Flash: firmware vbmeta_system is signed with an unknown key (neither AOSP test-key nor LenovoRSA-key) - aborting before any write", "err_flash_xml_selection_failed": "Firmware XML selection failed: {error}", "err_flash_zst_decompress_failed": "Failed to decompress {path}: {error}", @@ -302,7 +303,6 @@ "err_task_failed": "Task failed.", "err_task_failed_with_error": "Task failed: {error}", "err_task_panicked": "Task panicked.", - "err_tb323fu_loader_manifest_required": "TB323FU requires a multi-image loader manifest. Pick `qsahara_device_programmer.xml` (or its encrypted `.x`) directly, or place it next to the chosen .melf file ({path}).", "err_unroot_backup_manifest_invalid": "Invalid root backup manifest {manifest}: {error}", "err_unroot_flash_failed": "Flash {label} failed: {error}", "err_unroot_image_missing": "{image} not found in selected folder", @@ -409,45 +409,45 @@ "konabess_attribution": "Based on KonaBess by libxzr — GPL-3", "konabess_confirm_changes": "Table Changes", "konabess_confirm_chip": "Chipset", - "konabess_confirm_device_shape": "Device Values", - "konabess_confirm_edited_shape": "Edited Values", + "konabess_confirm_device_shape": "Device Values", + "konabess_confirm_edited_shape": "Edited Values", "konabess_confirm_import": "Imported Settings", - "konabess_confirm_modified": "Modified from device values", + "konabess_confirm_modified": "Modified from device values", "konabess_confirm_subtitle": "Review the selected device table and loader before rebuilding and flashing.", "konabess_confirm_title": "Confirm KonaBess Operation", - "konabess_confirm_unchanged": "Unchanged device values", + "konabess_confirm_unchanged": "Unchanged device values", "konabess_error_invalid_cell": "Enter a valid u32 cell; frequency accepts exact MHz with up to six decimal places.", "konabess_error_summary": "{count} blocking error(s). Fix the red-marked cell(s) to continue.", "konabess_export_invalid": "These are not valid KonaBess settings: {error}", - "konabess_import_button": "Import", + "konabess_import_button": "Import", "konabess_import_chip_mismatch": "The imported chip ({actual}) does not match the selected DTB ({expected}).", "konabess_import_loaded": "Working table overwritten from {path}", "konabess_import_no_target": "Select a target DTB before importing settings.", "konabess_import_unknown_chip": "The selected DTB's chip could not be identified.", "konabess_remove_level": "Remove", - "konabess_revert_button": "Reset", + "konabess_revert_button": "Reset", "konabess_step_apply": "Apply", "konabess_step_confirm": "Confirm", "konabess_step_table": "GPU Table", - "konabess_table_modified": "Modified", - "konabess_table_subtitle": "Review the target DTB and device table.", + "konabess_table_modified": "Modified", + "konabess_table_subtitle": "Review the target DTB and device table.", "konabess_table_target": "Target DTB", "konabess_table_title": "Device GPU Table", - "konabess_table_value_note": "Frequency is shown in exact MHz and stored as Hz.", + "konabess_table_value_note": "Frequency is shown in exact MHz and stored as Hz.", "konabess_target_likely": "This is likely the correct one", "konabess_target_no_candidates": "No DTBs with a readable GPU table were found.", "konabess_target_no_table": "No GPU table", "konabess_target_none": "No target selected", - "konabess_target_subtitle": "Choose one DTB to load the GPU table from.", + "konabess_target_subtitle": "Choose one DTB to load the GPU table from.", "konabess_target_summary": "{count} GPU table candidate(s)", "konabess_target_title": "Select Target DTB", "konabess_target_unknown_chip_unusable": "This DTB cannot be selected because its chip could not be identified.", "konabess_warning_duplicate_frequency": "The initial target frequency matches multiple levels; the first match is used.", "konabess_warning_frequency_order": "Frequencies are not strictly descending.", "konabess_warning_other": "Review this value before flashing.", - "konabess_warning_outside_stock": "This value is outside the range observed in stock tables.", - "konabess_warning_retargeted": "The original initial-target frequency was deleted, so the target is retargeted to a remaining level.", - "konabess_warning_summary": "Found {count} advisory finding(s) in the device table.", + "konabess_warning_outside_stock": "This value is outside the range observed in stock tables.", + "konabess_warning_retargeted": "The original initial-target frequency was deleted, so the target is retargeted to a remaining level.", + "konabess_warning_summary": "Found {count} advisory finding(s) in the device table.", "live_adb_checking_device": "Checking device...", "live_adb_device_connected": "Device connected", "live_adb_kernel_version": "Kernel version: {version}", @@ -576,6 +576,7 @@ "live_flash_efisp_flash": "Flashing efisp (LUN 4)…", "live_flash_efisp_flash_failed": "efisp flash failed ({error}) — continuing to system reset", "live_flash_efisp_flashed": "efisp flashed", + "live_flash_efisp_force_auto": "Efisp/GBL target detected — rollback protection bypass forced to Auto.", "live_flash_fastboot_timeout": "adb reboot bootloader returned success, but Fastboot did not appear within {seconds}s — continuing without bootloader vars", "live_flash_files_count": ".x files: {x_count}, rawprogram XML: {xml_count}", "live_flash_firmware_folder": "Firmware folder: {path}", @@ -584,11 +585,10 @@ "live_flash_no_rawprogram_pack": "No rawprogram pack (.x / .xml) in this folder - it doesn't look like a valid firmware image folder.", "live_flash_phase3_xml_counts": "{raw} rawprogram + {patch} patch XML", "live_flash_region_convert": "Region convert: {value}", + "live_flash_region_efisp": "Region handled by efisp GBL; vendor_boot/vbmeta AVB conversion skipped.", "live_flash_rollback_bypass": "Bypass rollback protection: {value}", "live_flash_set_bootable": "Set bootable LUN to {lun} (xbl_a)", "live_flash_skip_adb": "Device in Bootloader/EDL — skipping ADB step", - "live_flash_tb323fu_force_auto": "TB323FU detected — rollback protection bypass forced to Auto.", - "live_flash_tb323fu_region_efisp": "TB323FU: region handled by efisp GBL; vendor_boot/vbmeta AVB conversion skipped.", "live_flash_vbmeta_key_unknown": "Firmware vbmeta_system signing key is unknown (neither AOSP test-key nor LenovoRSA-key) - aborting", "live_flash_vbmeta_status": "vbmeta.img: {status}", "live_flash_vendor_boot_status": "vendor_boot.img: {status}", @@ -665,10 +665,10 @@ "live_xml_decrypt_done": "Decrypted {count} .x file(s) → .xml", "live_xml_keep_excludes": "Excluding userdata/metadata", "loader_default_ext_unsupported": "The file set as the default EDL loader has an extension that isn't supported on the connected device.", + "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_tb323fu": "qsahara_device_programmer.xml", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nor qsahara_device_programmer.xml (Y700 Gen 5 only)", - "loader_model_mismatch_tooltip": "The connected device needs a different EDL loader (TB323FU: .xml/.x manifest; every other model: .melf).", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nor qsahara_device_programmer.xml (Y700 Gen 5 / Infinite only)", + "loader_model_mismatch_tooltip": "The connected device needs a different EDL loader (TB323FU/TB324ZC: .xml/.x manifest; every other model: .melf).", "log_apatch_extract_kernel": "Extracting kernel: {input} → {output}", "log_apatch_extracted_kpimg": "extracted assets/kpimg → {path} ({bytes} bytes)", "log_apatch_kallsyms_all_missing": "CONFIG_KALLSYMS_ALL=y missing — non-fatal, but some KPMs may need it", @@ -778,7 +778,7 @@ "log_reboot_target_from": "→ {target} (from {source})", "log_reboot_target_from_edl": "→ {target} (from EDL, loader={loader})", "log_release_latest_asset": "latest: {tag} — asset {name}", - "log_root_efisp_check": "TB323FU detected — verifying efisp (GBL) provisioning…", + "log_root_efisp_check": "Efisp/GBL route detected — verifying efisp provisioning…", "log_root_efisp_ok": "efisp is provisioned — continuing (AVB/vbmeta handled by GBL)", "log_root_installing_manager_apk": "Installing manager APK: {path}", "log_root_loader": "Loader: {path}", @@ -988,6 +988,7 @@ "rollback_format_raw": "Raw (hex)", "rollback_format_unix": "Unix timestamp", "rollback_manual_desc": "Set the boot and vbmeta_system rollback indexes. Values must be earlier than now.", + "rollback_manual_efisp_disabled": "Efisp/GBL targets cannot use Manual rollback; it was disabled.", "rollback_manual_error_clock": "System clock unavailable.", "rollback_manual_error_date_shape": "Use YYYY-MM-DD.", "rollback_manual_error_date_value": "Enter a real calendar date.", @@ -998,7 +999,6 @@ "rollback_manual_error_prefix": "Start with 0x.", "rollback_manual_original": "Image index: {index}", "rollback_manual_placeholder": "Rollback index", - "rollback_manual_tb323fu_disabled": "TB323FU cannot use Manual rollback; it was disabled.", "rollback_off": "Off", "rollback_on": "On", "rollback_open_tip": "View the stored rollback indices", diff --git a/crates/ltbox-gui/lang/ja.json b/crates/ltbox-gui/lang/ja.json index d98805b5..5f39b821 100644 --- a/crates/ltbox-gui/lang/ja.json +++ b/crates/ltbox-gui/lang/ja.json @@ -205,6 +205,7 @@ "err_edl_probe_work_dir_failed": "EDL プローブ作業フォルダーの作成に失敗しました: {error}", "err_edl_session_open_failed": "EDL セッションを開けませんでした: {error}", "err_edl_transition_failed": "デバイスを EDL モードで再起動できませんでした。", + "err_efisp_loader_manifest_required": "{model} にはマルチイメージローダーマニフェストが必要です。`qsahara_device_programmer.xml` (または暗号化された `.x`) を直接選択するか、選択した .melf ファイルの隣に配置してください ({path})。", "err_fastboot_command_failed": "{command}: {error}", "err_fastboot_open_failed": "ブートローダーデバイスを開けませんでした: {error}", "err_fastboot_recovery_unsupported": "ブートローダーモードではリカバリへ直接再起動できません。先に ADB に切り替えてください。", @@ -227,8 +228,8 @@ "err_flash_parts_erase_failed": "パーティション {label} の消去に失敗しました: {error}", "err_flash_parts_part_failed": "パーティション {label} のフラッシュに失敗しました: {error}", "err_flash_phys_write_failed": "LUN {lun} の書き込みに失敗しました: {error}", + "err_flash_prc_only": "フラッシュ: {model} は中国専用 — 他リージョンへの変換や CN 以外の国設定は不可、中止します", "err_flash_set_bootable_lun_failed": "起動可能 LUN の設定に失敗しました: {error}", - "err_flash_tb322fc_prc_only": "フラッシュ: TB322FC は中国専用 — 他リージョンへの変換や CN 以外の国設定は不可、中止します", "err_flash_vbmeta_key_unknown": "フラッシュ: ファームウェアの vbmeta_system が不明な鍵で署名されています(AOSP テスト鍵でも LenovoRSA 鍵でもない)— 書き込み前に中止します", "err_flash_xml_selection_failed": "ファームウェア XML の選択に失敗しました: {error}", "err_flash_zst_decompress_failed": "{path} の展開に失敗しました: {error}", @@ -302,7 +303,6 @@ "err_task_failed": "タスクに失敗しました。", "err_task_failed_with_error": "タスクに失敗しました: {error}", "err_task_panicked": "タスクがパニックで停止しました。", - "err_tb323fu_loader_manifest_required": "TB323FU にはマルチイメージローダーマニフェストが必要です。`qsahara_device_programmer.xml` (または暗号化された `.x`) を直接選択するか、選択した .melf ファイルの隣に配置してください ({path})。", "err_unroot_backup_manifest_invalid": "root バックアップマニフェスト {manifest} が無効です: {error}", "err_unroot_flash_failed": "{label} のフラッシュに失敗しました: {error}", "err_unroot_image_missing": "選択したフォルダーに {image} が見つかりません", @@ -409,45 +409,45 @@ "konabess_attribution": "libxzrによるKonaBessをベースにしています — GPL-3", "konabess_confirm_changes": "テーブルの変更", "konabess_confirm_chip": "チップセット", - "konabess_confirm_device_shape": "端末の値", - "konabess_confirm_edited_shape": "編集中の値", + "konabess_confirm_device_shape": "端末の値", + "konabess_confirm_edited_shape": "編集中の値", "konabess_confirm_import": "インポートした設定", - "konabess_confirm_modified": "端末の値から変更済み", + "konabess_confirm_modified": "端末の値から変更済み", "konabess_confirm_subtitle": "再構築と書き込みの前に、選択した端末テーブルとローダーを確認してください。", "konabess_confirm_title": "KonaBess操作の確認", - "konabess_confirm_unchanged": "端末の値のまま", + "konabess_confirm_unchanged": "端末の値のまま", "konabess_error_invalid_cell": "有効なu32セル値を入力してください。周波数は小数点以下6桁まで正確なMHz値を使用できます。", "konabess_error_summary": "続行を妨げるエラーが{count}件あります。赤色で示されたセルを修正してください。", "konabess_export_invalid": "有効なKonaBess設定値ではありません: {error}", - "konabess_import_button": "インポート", + "konabess_import_button": "インポート", "konabess_import_chip_mismatch": "インポートしたチップ({actual})は選択したDTB({expected})と一致しません。", "konabess_import_loaded": "{path}の値で作業用テーブルを上書きしました", "konabess_import_no_target": "設定をインポートする前に対象DTBを選択してください。", "konabess_import_unknown_chip": "選択したDTBのチップを特定できません。", "konabess_remove_level": "削除", - "konabess_revert_button": "リセット", + "konabess_revert_button": "リセット", "konabess_step_apply": "適用", "konabess_step_confirm": "確認", "konabess_step_table": "GPUテーブル", - "konabess_table_modified": "変更済み", - "konabess_table_subtitle": "対象DTBと端末のテーブルを確認してください。", + "konabess_table_modified": "変更済み", + "konabess_table_subtitle": "対象DTBと端末のテーブルを確認してください。", "konabess_table_target": "対象DTB", "konabess_table_title": "端末のGPUテーブル", - "konabess_table_value_note": "周波数は正確なMHzで表示し、Hzで保存します。", + "konabess_table_value_note": "周波数は正確なMHzで表示し、Hzで保存します。", "konabess_target_likely": "これが正しい可能性が高いです", "konabess_target_no_candidates": "読み取り可能なGPUテーブルを持つDTBが見つかりませんでした。", "konabess_target_no_table": "GPUテーブルなし", "konabess_target_none": "対象が選択されていません", - "konabess_target_subtitle": "GPUテーブルを読み込むDTBを1つ選択してください。", + "konabess_target_subtitle": "GPUテーブルを読み込むDTBを1つ選択してください。", "konabess_target_summary": "GPUテーブル候補 {count}件", "konabess_target_title": "対象DTBを選択", "konabess_target_unknown_chip_unusable": "チップを特定できないため、このDTBは選択できません。", "konabess_warning_duplicate_frequency": "初期対象周波数に一致するレベルが複数あるため、最初の一致を使用します。", "konabess_warning_frequency_order": "周波数が厳密な降順になっていません。", "konabess_warning_other": "書き込み前にこの値を確認してください。", - "konabess_warning_outside_stock": "純正テーブルで確認された範囲外の値です。", - "konabess_warning_retargeted": "元の初期対象周波数が削除されたため、残っているレベルへ対象を変更します。", - "konabess_warning_summary": "端末のテーブルに確認が必要な項目が{count}件あります。", + "konabess_warning_outside_stock": "純正テーブルで確認された範囲外の値です。", + "konabess_warning_retargeted": "元の初期対象周波数が削除されたため、残っているレベルへ対象を変更します。", + "konabess_warning_summary": "端末のテーブルに確認が必要な項目が{count}件あります。", "live_adb_checking_device": "デバイスを確認中...", "live_adb_device_connected": "デバイスが接続されました", "live_adb_kernel_version": "カーネルバージョン: {version}", @@ -576,6 +576,7 @@ "live_flash_efisp_flash": "efisp (LUN 4) をフラッシュ中...", "live_flash_efisp_flash_failed": "efisp のフラッシュに失敗しました ({error}) — システムリセットを続行します", "live_flash_efisp_flashed": "efisp がフラッシュされました", + "live_flash_efisp_force_auto": "efisp/GBL 対象が検出されました — ロールバック保護のバイパスを自動に強制します。", "live_flash_fastboot_timeout": "adb reboot bootloader は成功しましたが、{seconds} 秒以内に Fastboot が現れませんでした — ブートローダー変数なしで続行します", "live_flash_files_count": ".x ファイル: {x_count}個, rawprogram XML: {xml_count}個", "live_flash_firmware_folder": "ファームウェアフォルダ: {path}", @@ -584,11 +585,10 @@ "live_flash_no_rawprogram_pack": "このフォルダーに rawprogram(.x / .xml)がありません — 正しいファームウェアイメージのフォルダーではないようです。", "live_flash_phase3_xml_counts": "{raw} rawprogram + {patch} patch XML", "live_flash_region_convert": "リージョン変換: {value}", + "live_flash_region_efisp": "リージョンは efisp GBL によって処理されます。vendor_boot/vbmeta の AVB 変換をスキップします。", "live_flash_rollback_bypass": "ロールバック保護のバイパス: {value}", "live_flash_set_bootable": "起動可能なLUNを {lun} (xbl_a) に設定します", "live_flash_skip_adb": "デバイスはブートローダー/EDLモードです — ADBステップをスキップします", - "live_flash_tb323fu_force_auto": "TB323FU が検出されました — ロールバック保護のバイパスを自動に強制します。", - "live_flash_tb323fu_region_efisp": "TB323FU: リージョンは efisp GBL によって処理されます。vendor_boot/vbmeta の AVB 変換をスキップします。", "live_flash_vbmeta_key_unknown": "ファームウェア vbmeta_system の署名鍵が不明(AOSP テスト鍵/LenovoRSA 鍵ではない)— 中止します", "live_flash_vbmeta_status": "vbmeta.img: {status}", "live_flash_vendor_boot_status": "vendor_boot.img: {status}", @@ -665,10 +665,10 @@ "live_xml_decrypt_done": "{count} 個の .x ファイルを復号しました → .xml", "live_xml_keep_excludes": "userdata / metadata を除外しています", "loader_default_ext_unsupported": "既定の EDL ローダーに指定されたファイルの拡張子は、接続中の端末ではサポートされていません。", + "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_tb323fu": "qsahara_device_programmer.xml", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nまたは qsahara_device_programmer.xml (Y700 Gen 5 のみ)", - "loader_model_mismatch_tooltip": "接続中の端末には別の EDL ローダーが必要です(TB323FU: .xml/.x マニフェスト、その他のモデル: .melf)。", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nまたは qsahara_device_programmer.xml (Y700 Gen 5 / Infinite のみ)", + "loader_model_mismatch_tooltip": "接続中の端末には別の EDL ローダーが必要です(TB323FU/TB324ZC: .xml/.x マニフェスト、その他のモデル: .melf)。", "log_apatch_extract_kernel": "カーネルを抽出中: {input} → {output}", "log_apatch_extracted_kpimg": "assets/kpimg を抽出しました → {path} ({bytes} バイト)", "log_apatch_kallsyms_all_missing": "CONFIG_KALLSYMS_ALL=y がありません — 致命的ではありませんが、一部の KPM で必要になる場合があります", @@ -778,7 +778,7 @@ "log_reboot_target_from": "→ {target} ({source} から)", "log_reboot_target_from_edl": "→ {target} (EDLから, ローダー={loader})", "log_release_latest_asset": "最新: {tag} — アセット {name}", - "log_root_efisp_check": "TB323FU が検出されました — efisp (GBL) プロビジョニングを検証中...", + "log_root_efisp_check": "efisp/GBL ルートが検出されました — efisp のプロビジョニングを検証中...", "log_root_efisp_ok": "efisp がプロビジョニングされています — 続行します (AVB/vbmetaはGBLによって処理されます)", "log_root_installing_manager_apk": "マネージャー APK をインストール中: {path}", "log_root_loader": "ローダー: {path}", @@ -988,6 +988,7 @@ "rollback_format_raw": "元の値 (16進数)", "rollback_format_unix": "Unix タイムスタンプ", "rollback_manual_desc": "boot および vbmeta_system のロールバックインデックスを設定します。値は現在時刻より前である必要があります。", + "rollback_manual_efisp_disabled": "efisp/GBL 対象では手動ロールバックを使用できません。無効になりました。", "rollback_manual_error_clock": "システムクロックを利用できません。", "rollback_manual_error_date_shape": "YYYY-MM-DD 形式で入力してください。", "rollback_manual_error_date_value": "実在する日付を入力してください。", @@ -998,7 +999,6 @@ "rollback_manual_error_prefix": "0x で始めてください。", "rollback_manual_original": "イメージインデックス: {index}", "rollback_manual_placeholder": "ロールバックインデックス", - "rollback_manual_tb323fu_disabled": "TB323FU は手動ロールバックを使用できません。無効になりました。", "rollback_off": "オフ", "rollback_on": "オン", "rollback_open_tip": "保存されたロールバックインデックスを表示", diff --git a/crates/ltbox-gui/lang/ko.json b/crates/ltbox-gui/lang/ko.json index 085df348..265f4ae6 100644 --- a/crates/ltbox-gui/lang/ko.json +++ b/crates/ltbox-gui/lang/ko.json @@ -205,6 +205,7 @@ "err_edl_probe_work_dir_failed": "EDL 검사 작업 폴더 생성 실패: {error}", "err_edl_session_open_failed": "EDL 세션 열기 실패: {error}", "err_edl_transition_failed": "기기를 EDL 모드로 재부팅하지 못했습니다.", + "err_efisp_loader_manifest_required": "{model}에는 다중 이미지 로더 매니페스트가 필요합니다. `qsahara_device_programmer.xml`(또는 암호화된 `.x`)을 직접 선택하거나, 선택한 .melf 파일 옆에 두세요({path}).", "err_fastboot_command_failed": "{command}: {error}", "err_fastboot_open_failed": "부트로더 기기 열기 실패: {error}", "err_fastboot_recovery_unsupported": "부트로더 모드에서는 복구 모드로 직접 재부팅할 수 없습니다. 먼저 ADB로 전환하세요.", @@ -227,8 +228,8 @@ "err_flash_parts_erase_failed": "{label} 파티션을 지우지 못했습니다: {error}", "err_flash_parts_part_failed": "{label} 파티션 플래싱에 실패했습니다: {error}", "err_flash_phys_write_failed": "LUN {lun} 쓰기에 실패했습니다: {error}", + "err_flash_prc_only": "플래싱: {model} 모델은 중국 전용 — 타 지역 변환이나 비-CN 국가 설정 불가, 중단", "err_flash_set_bootable_lun_failed": "부팅 LUN 설정 실패: {error}", - "err_flash_tb322fc_prc_only": "플래싱: TB322FC는 중국 전용 — 타 지역 변환이나 비-CN 국가 설정 불가, 중단", "err_flash_vbmeta_key_unknown": "플래싱: 펌웨어 vbmeta_system 서명 키를 알 수 없음(AOSP 테스트 키도 LenovoRSA 키도 아님) — 쓰기 전 중단", "err_flash_xml_selection_failed": "펌웨어 XML 선택 실패: {error}", "err_flash_zst_decompress_failed": "{path} 압축 해제 실패: {error}", @@ -302,7 +303,6 @@ "err_task_failed": "작업에 실패했습니다.", "err_task_failed_with_error": "작업 실패: {error}", "err_task_panicked": "작업이 패닉으로 중단되었습니다.", - "err_tb323fu_loader_manifest_required": "TB323FU는 다중 이미지 로더 매니페스트가 필요합니다. `qsahara_device_programmer.xml`(또는 암호화된 `.x`)을 직접 선택하거나, 선택한 .melf 파일 옆에 두세요({path}).", "err_unroot_backup_manifest_invalid": "루트 백업 매니페스트 {manifest}가 올바르지 않습니다: {error}", "err_unroot_flash_failed": "{label} 플래시 실패: {error}", "err_unroot_image_missing": "선택한 폴더에서 {image}를 찾을 수 없습니다.", @@ -409,45 +409,45 @@ "konabess_attribution": "libxzr의 KonaBess를 기반으로 함 — GPL-3", "konabess_confirm_changes": "테이블 변경 사항", "konabess_confirm_chip": "칩셋", - "konabess_confirm_device_shape": "기기 값", - "konabess_confirm_edited_shape": "편집 값", + "konabess_confirm_device_shape": "기기 값", + "konabess_confirm_edited_shape": "편집 값", "konabess_confirm_import": "가져온 설정값", - "konabess_confirm_modified": "기기 값에서 변경됨", + "konabess_confirm_modified": "기기 값에서 변경됨", "konabess_confirm_subtitle": "다시 빌드하고 플래싱하기 전에 선택한 기기 테이블과 로더를 확인하세요.", "konabess_confirm_title": "KonaBess 작업 확인", - "konabess_confirm_unchanged": "기기 값 그대로", + "konabess_confirm_unchanged": "기기 값 그대로", "konabess_error_invalid_cell": "올바른 u32 셀 값을 입력하세요. 주파수는 소수점 이하 6자리까지 정확한 MHz 값을 사용할 수 있습니다.", "konabess_error_summary": "진행을 막는 오류가 {count}개 있습니다. 빨간색으로 표시된 셀을 수정하세요.", "konabess_export_invalid": "올바른 KonaBess 설정값 파일이 아닙니다: {error}", - "konabess_import_button": "가져오기", + "konabess_import_button": "가져오기", "konabess_import_chip_mismatch": "가져온 칩({actual})이 선택한 DTB({expected})와 일치하지 않습니다.", "konabess_import_loaded": "{path}에서 가져온 값으로 작업 테이블을 덮어썼습니다.", "konabess_import_no_target": "설정값을 가져오기 전에 대상 DTB를 선택하세요.", "konabess_import_unknown_chip": "선택한 DTB의 칩을 확인할 수 없습니다.", "konabess_remove_level": "삭제", - "konabess_revert_button": "초기화", + "konabess_revert_button": "초기화", "konabess_step_apply": "적용", "konabess_step_confirm": "확인", "konabess_step_table": "GPU 테이블", - "konabess_table_modified": "수정됨", - "konabess_table_subtitle": "대상 DTB와 기기 테이블을 확인하세요.", + "konabess_table_modified": "수정됨", + "konabess_table_subtitle": "대상 DTB와 기기 테이블을 확인하세요.", "konabess_table_target": "대상 DTB", "konabess_table_title": "기기 GPU 테이블", - "konabess_table_value_note": "주파수는 정확한 MHz로 표시하고 Hz로 저장합니다.", + "konabess_table_value_note": "주파수는 정확한 MHz로 표시하고 Hz로 저장합니다.", "konabess_target_likely": "이게 맞을 가능성이 높습니다", "konabess_target_no_candidates": "읽을 수 있는 GPU 테이블이 든 DTB를 찾지 못했습니다.", "konabess_target_no_table": "GPU 테이블 없음", "konabess_target_none": "선택한 대상 없음", - "konabess_target_subtitle": "GPU 테이블을 불러올 DTB를 하나 선택하세요.", + "konabess_target_subtitle": "GPU 테이블을 불러올 DTB를 하나 선택하세요.", "konabess_target_summary": "GPU 테이블 후보 {count}개", "konabess_target_title": "대상 DTB 선택", "konabess_target_unknown_chip_unusable": "칩을 확인할 수 없어 이 DTB를 선택할 수 없습니다.", "konabess_warning_duplicate_frequency": "초기 대상 주파수와 일치하는 레벨이 여러 개라 첫 번째 레벨을 사용합니다.", "konabess_warning_frequency_order": "주파수가 내림차순으로 정렬되어 있지 않습니다.", "konabess_warning_other": "플래싱하기 전에 이 값을 확인하세요.", - "konabess_warning_outside_stock": "순정 테이블에서 확인된 범위를 벗어난 값입니다.", - "konabess_warning_retargeted": "기존 초기 대상 주파수가 삭제되어 남은 레벨로 대상을 다시 지정합니다.", - "konabess_warning_summary": "기기 테이블에서 확인이 필요한 항목이 {count}개 있습니다.", + "konabess_warning_outside_stock": "순정 테이블에서 확인된 범위를 벗어난 값입니다.", + "konabess_warning_retargeted": "기존 초기 대상 주파수가 삭제되어 남은 레벨로 대상을 다시 지정합니다.", + "konabess_warning_summary": "기기 테이블에서 확인이 필요한 항목이 {count}개 있습니다.", "live_adb_checking_device": "기기 확인 중...", "live_adb_device_connected": "기기 연결됨", "live_adb_kernel_version": "커널 버전: {version}", @@ -576,6 +576,7 @@ "live_flash_efisp_flash": "efisp 플래싱 중 (LUN 4)…", "live_flash_efisp_flash_failed": "efisp 플래싱 실패 ({error}) — 시스템 재부팅은 계속 진행", "live_flash_efisp_flashed": "efisp 플래싱 완료", + "live_flash_efisp_force_auto": "efisp/GBL 대상 감지됨 — 롤백 보호 우회를 자동으로 강제 전환합니다.", "live_flash_fastboot_timeout": "adb reboot bootloader는 성공했지만 {seconds}초 안에 Fastboot가 나타나지 않음 — 부트로더 변수 없이 계속 진행", "live_flash_files_count": ".x 파일: {x_count}개, rawprogram XML: {xml_count}개", "live_flash_firmware_folder": "펌웨어 폴더: {path}", @@ -584,11 +585,10 @@ "live_flash_no_rawprogram_pack": "이 폴더에 rawprogram(.x/.xml)이 없습니다 — 올바른 펌웨어 이미지 폴더가 아닌 것 같습니다.", "live_flash_phase3_xml_counts": "rawprogram {raw}개 + patch XML {patch}개", "live_flash_region_convert": "지역 변환: {value}", + "live_flash_region_efisp": "지역은 efisp GBL로 처리 — vendor_boot/vbmeta AVB 변환 건너뜀.", "live_flash_rollback_bypass": "롤백 보호 우회: {value}", "live_flash_set_bootable": "부팅 가능 LUN을 {lun}로 설정 (xbl_a)", "live_flash_skip_adb": "기기가 부트로더/EDL 모드 — ADB 단계 건너뜀", - "live_flash_tb323fu_force_auto": "TB323FU 감지됨 — 롤백 보호 우회를 자동으로 강제 전환합니다.", - "live_flash_tb323fu_region_efisp": "TB323FU: 지역은 efisp GBL로 처리 — vendor_boot/vbmeta AVB 변환 건너뜀.", "live_flash_vbmeta_key_unknown": "펌웨어 vbmeta_system 서명 키 알 수 없음(AOSP 테스트 키/LenovoRSA 키 아님) — 중단", "live_flash_vbmeta_status": "vbmeta.img: {status}", "live_flash_vendor_boot_status": "vendor_boot.img: {status}", @@ -665,10 +665,10 @@ "live_xml_decrypt_done": ".x 파일 {count}개 복호화 완료 → .xml", "live_xml_keep_excludes": "userdata/metadata 제외", "loader_default_ext_unsupported": "기본 EDL 로더로 지정된 파일이 연결된 기기에서 지원되지 않는 확장자입니다.", + "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_tb323fu": "qsahara_device_programmer.xml", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\n또는 qsahara_device_programmer.xml (Y700 5세대 전용)", - "loader_model_mismatch_tooltip": "연결된 기기에는 다른 EDL 로더가 필요합니다 (TB323FU: .xml/.x 매니페스트, 그 외 모델: .melf).", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\n또는 qsahara_device_programmer.xml (Y700 5세대 / Infinite 전용)", + "loader_model_mismatch_tooltip": "연결된 기기에는 다른 EDL 로더가 필요합니다 (TB323FU/TB324ZC: .xml/.x 매니페스트, 그 외 모델: .melf).", "log_apatch_extract_kernel": "커널 추출 중: {input} → {output}", "log_apatch_extracted_kpimg": "assets/kpimg 추출 완료 → {path} ({bytes} 바이트)", "log_apatch_kallsyms_all_missing": "CONFIG_KALLSYMS_ALL=y 없음 — 치명적이지 않지만 일부 KPM에 필요할 수 있음", @@ -778,7 +778,7 @@ "log_reboot_target_from": "{source} → {target}", "log_reboot_target_from_edl": "EDL → {target} (로더={loader})", "log_release_latest_asset": "최신 릴리스: {tag} — 에셋 {name}", - "log_root_efisp_check": "TB323FU 감지됨 — efisp(GBL) 설치 여부 확인 중…", + "log_root_efisp_check": "efisp/GBL 경로 감지됨 — efisp 설치 여부 확인 중…", "log_root_efisp_ok": "efisp 설치 확인 — 계속 진행 (AVB/vbmeta는 GBL이 처리)", "log_root_installing_manager_apk": "매니저 APK 설치 중: {path}", "log_root_loader": "로더: {path}", @@ -988,6 +988,7 @@ "rollback_format_raw": "원본값 (16진수)", "rollback_format_unix": "유닉스 타임스탬프", "rollback_manual_desc": "boot 및 vbmeta_system 롤백 인덱스를 설정합니다. 값은 현재 시간보다 이전이어야 합니다.", + "rollback_manual_efisp_disabled": "efisp/GBL 대상은 수동 롤백을 사용할 수 없어 비활성화했습니다.", "rollback_manual_error_clock": "시스템 시계를 사용할 수 없습니다.", "rollback_manual_error_date_shape": "YYYY-MM-DD 형식으로 입력하세요.", "rollback_manual_error_date_value": "실제 존재하는 날짜를 입력하세요.", @@ -998,7 +999,6 @@ "rollback_manual_error_prefix": "0x로 시작하세요.", "rollback_manual_original": "이미지 인덱스: {index}", "rollback_manual_placeholder": "롤백 인덱스", - "rollback_manual_tb323fu_disabled": "TB323FU는 수동 롤백을 사용할 수 없어 비활성화했습니다.", "rollback_off": "끄기", "rollback_on": "켜기", "rollback_open_tip": "저장된 롤백 인덱스 보기", diff --git a/crates/ltbox-gui/lang/ru.json b/crates/ltbox-gui/lang/ru.json index d36f3ea3..94901c1c 100644 --- a/crates/ltbox-gui/lang/ru.json +++ b/crates/ltbox-gui/lang/ru.json @@ -205,6 +205,7 @@ "err_edl_probe_work_dir_failed": "Не удалось создать рабочую папку EDL-проверки: {error}", "err_edl_session_open_failed": "Не удалось открыть EDL-сессию: {error}", "err_edl_transition_failed": "Не удалось перезагрузить устройство в режим EDL.", + "err_efisp_loader_manifest_required": "{model} требует манифест загрузчика с несколькими образами. Выберите `qsahara_device_programmer.xml` (или его зашифрованный `.x`) напрямую либо поместите его рядом с выбранным .melf-файлом ({path}).", "err_fastboot_command_failed": "{command}: {error}", "err_fastboot_open_failed": "Не удалось открыть устройство в режиме загрузчика: {error}", "err_fastboot_recovery_unsupported": "Из режима загрузчика нельзя напрямую перезагрузиться в recovery; сначала переключитесь на ADB.", @@ -227,8 +228,8 @@ "err_flash_parts_erase_failed": "Не удалось стереть раздел {label}: {error}", "err_flash_parts_part_failed": "Не удалось прошить раздел {label}: {error}", "err_flash_phys_write_failed": "Не удалось записать LUN {lun}: {error}", + "err_flash_prc_only": "Прошивка: {model} только для Китая — конвертация в другой регион или не-CN страна недопустимы; прерывание", "err_flash_set_bootable_lun_failed": "Не удалось установить загрузочный LUN: {error}", - "err_flash_tb322fc_prc_only": "Прошивка: TB322FC только для Китая — конвертация в другой регион или не-CN страна недопустимы; прерывание", "err_flash_vbmeta_key_unknown": "Прошивка: vbmeta_system прошивки подписана неизвестным ключом (ни тестовым ключом AOSP, ни ключом LenovoRSA) — прерывание до записи", "err_flash_xml_selection_failed": "Не удалось выбрать XML прошивки: {error}", "err_flash_zst_decompress_failed": "Не удалось распаковать {path}: {error}", @@ -302,7 +303,6 @@ "err_task_failed": "Задача не удалась.", "err_task_failed_with_error": "Задача не удалась: {error}", "err_task_panicked": "Задача остановлена из-за panic.", - "err_tb323fu_loader_manifest_required": "TB323FU требует манифест загрузчика с несколькими образами. Выберите `qsahara_device_programmer.xml` (или его зашифрованный `.x`) напрямую либо поместите его рядом с выбранным .melf-файлом ({path}).", "err_unroot_backup_manifest_invalid": "Некорректный манифест резервной копии root {manifest}: {error}", "err_unroot_flash_failed": "Прошивка {label} не удалась: {error}", "err_unroot_image_missing": "В выбранной папке не найден {image}", @@ -409,45 +409,45 @@ "konabess_attribution": "На основе KonaBess от libxzr — GPL-3", "konabess_confirm_changes": "Изменения таблицы", "konabess_confirm_chip": "Чипсет", - "konabess_confirm_device_shape": "Значения на устройстве", - "konabess_confirm_edited_shape": "Редактируемые значения", + "konabess_confirm_device_shape": "Значения на устройстве", + "konabess_confirm_edited_shape": "Редактируемые значения", "konabess_confirm_import": "Импортированные настройки", - "konabess_confirm_modified": "Изменено относительно значений на устройстве", + "konabess_confirm_modified": "Изменено относительно значений на устройстве", "konabess_confirm_subtitle": "Перед пересборкой и прошивкой проверьте выбранную таблицу устройства и загрузчик.", "konabess_confirm_title": "Подтверждение операции KonaBess", - "konabess_confirm_unchanged": "Значения на устройстве без изменений", + "konabess_confirm_unchanged": "Значения на устройстве без изменений", "konabess_error_invalid_cell": "Введите корректное значение u32; частоту можно указать точно в МГц с шестью знаками после запятой.", "konabess_error_summary": "Блокирующих ошибок: {count}. Исправьте ячейки, отмеченные красным.", "konabess_export_invalid": "Это некорректные настройки KonaBess: {error}", - "konabess_import_button": "Импорт", + "konabess_import_button": "Импорт", "konabess_import_chip_mismatch": "Чип из файла ({actual}) не совпадает с выбранным DTB ({expected}).", "konabess_import_loaded": "Рабочая таблица заменена значениями из {path}", "konabess_import_no_target": "Перед импортом настроек выберите целевой DTB.", "konabess_import_unknown_chip": "Не удалось определить чип выбранного DTB.", "konabess_remove_level": "Удалить", - "konabess_revert_button": "Сбросить", + "konabess_revert_button": "Сбросить", "konabess_step_apply": "Применение", "konabess_step_confirm": "Подтверждение", "konabess_step_table": "Таблица GPU", - "konabess_table_modified": "Изменено", - "konabess_table_subtitle": "Проверьте целевой DTB и таблицу устройства.", + "konabess_table_modified": "Изменено", + "konabess_table_subtitle": "Проверьте целевой DTB и таблицу устройства.", "konabess_table_target": "Целевой DTB", "konabess_table_title": "Таблица GPU устройства", - "konabess_table_value_note": "Частота показана точно в МГц и хранится в Гц.", + "konabess_table_value_note": "Частота показана точно в МГц и хранится в Гц.", "konabess_target_likely": "Скорее всего, это правильный вариант", "konabess_target_no_candidates": "Не найдено DTB с читаемой таблицей GPU.", "konabess_target_no_table": "Нет таблицы GPU", "konabess_target_none": "Цель не выбрана", - "konabess_target_subtitle": "Выберите один DTB, из которого нужно загрузить таблицу GPU.", + "konabess_target_subtitle": "Выберите один DTB, из которого нужно загрузить таблицу GPU.", "konabess_target_summary": "Кандидатов с таблицей GPU: {count}", "konabess_target_title": "Выбор целевого DTB", "konabess_target_unknown_chip_unusable": "Этот DTB нельзя выбрать, потому что не удалось определить его чип.", "konabess_warning_duplicate_frequency": "Начальной целевой частоте соответствует несколько уровней; используется первое совпадение.", "konabess_warning_frequency_order": "Частоты расположены не строго по убыванию.", "konabess_warning_other": "Проверьте это значение перед прошивкой.", - "konabess_warning_outside_stock": "Значение выходит за диапазон, встречающийся в заводских таблицах.", - "konabess_warning_retargeted": "Исходная начальная целевая частота удалена, поэтому цель переназначена на оставшийся уровень.", - "konabess_warning_summary": "В таблице устройства есть замечания ({count}), требующие внимания.", + "konabess_warning_outside_stock": "Значение выходит за диапазон, встречающийся в заводских таблицах.", + "konabess_warning_retargeted": "Исходная начальная целевая частота удалена, поэтому цель переназначена на оставшийся уровень.", + "konabess_warning_summary": "В таблице устройства есть замечания ({count}), требующие внимания.", "live_adb_checking_device": "Проверка устройства...", "live_adb_device_connected": "Устройство подключено", "live_adb_kernel_version": "Версия ядра: {version}", @@ -576,6 +576,7 @@ "live_flash_efisp_flash": "Прошивка efisp (LUN 4)…", "live_flash_efisp_flash_failed": "Не удалось прошить efisp ({error}) — продолжаем сброс в систему", "live_flash_efisp_flashed": "efisp прошит", + "live_flash_efisp_force_auto": "Обнаружена цель efisp/GBL — обход защиты от отката принудительно переведён в авто.", "live_flash_fastboot_timeout": "adb reboot bootloader завершился успешно, но Fastboot не появился за {seconds} с — продолжаем без переменных загрузчика", "live_flash_files_count": ".x файлов: {x_count}, rawprogram XML: {xml_count}", "live_flash_firmware_folder": "Папка прошивки: {path}", @@ -584,11 +585,10 @@ "live_flash_no_rawprogram_pack": "В этой папке нет rawprogram (.x / .xml) — похоже, это не папка с образом прошивки.", "live_flash_phase3_xml_counts": "{raw} rawprogram + {patch} patch XML", "live_flash_region_convert": "Смена региона: {value}", + "live_flash_region_efisp": "Регион обрабатывается efisp GBL; преобразование vendor_boot/vbmeta AVB пропущено.", "live_flash_rollback_bypass": "Обход защиты от отката: {value}", "live_flash_set_bootable": "Загрузочный LUN установлен в {lun} (xbl_a)", "live_flash_skip_adb": "Устройство в Загрузчике/EDL — пропуск шага ADB", - "live_flash_tb323fu_force_auto": "Обнаружен TB323FU — обход защиты от отката принудительно переведён в авто.", - "live_flash_tb323fu_region_efisp": "TB323FU: регион обрабатывается efisp GBL; преобразование vendor_boot/vbmeta AVB пропущено.", "live_flash_vbmeta_key_unknown": "Ключ подписи vbmeta_system прошивки неизвестен (не тестовый ключ AOSP / не ключ LenovoRSA) — прерывание", "live_flash_vbmeta_status": "vbmeta.img: {status}", "live_flash_vendor_boot_status": "vendor_boot.img: {status}", @@ -665,10 +665,10 @@ "live_xml_decrypt_done": "Расшифровано {count} файлов .x → .xml", "live_xml_keep_excludes": "Исключая userdata/metadata", "loader_default_ext_unsupported": "Расширение файла, заданного загрузчиком EDL по умолчанию, не поддерживается на подключённом устройстве.", + "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_tb323fu": "qsahara_device_programmer.xml", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nили qsahara_device_programmer.xml (только Y700 5-го поколения)", - "loader_model_mismatch_tooltip": "Подключённому устройству нужен другой загрузчик EDL (TB323FU: манифест .xml/.x; остальные модели: .melf).", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nили qsahara_device_programmer.xml (только Y700 5-го поколения / Infinite)", + "loader_model_mismatch_tooltip": "Подключённому устройству нужен другой загрузчик EDL (TB323FU/TB324ZC: манифест .xml/.x; остальные модели: .melf).", "log_apatch_extract_kernel": "Извлечение ядра: {input} → {output}", "log_apatch_extracted_kpimg": "извлечён assets/kpimg → {path} ({bytes} байт)", "log_apatch_kallsyms_all_missing": "CONFIG_KALLSYMS_ALL=y отсутствует — не критично, но может требоваться некоторым KPM", @@ -778,7 +778,7 @@ "log_reboot_target_from": "{source} → {target}", "log_reboot_target_from_edl": "EDL → {target} (загрузчик={loader})", "log_release_latest_asset": "последний релиз: {tag} — ассет {name}", - "log_root_efisp_check": "Обнаружен TB323FU — проверка наличия efisp (GBL)…", + "log_root_efisp_check": "Обнаружен маршрут efisp/GBL — проверка наличия efisp…", "log_root_efisp_ok": "efisp присутствует — продолжаем (AVB/vbmeta обрабатывает GBL)", "log_root_installing_manager_apk": "Установка APK менеджера: {path}", "log_root_loader": "Загрузчик: {path}", @@ -988,6 +988,7 @@ "rollback_format_raw": "Исходное значение (hex)", "rollback_format_unix": "Метка времени Unix", "rollback_manual_desc": "Задайте индексы отката boot и vbmeta_system. Значения должны быть раньше текущего времени.", + "rollback_manual_efisp_disabled": "Цели efisp/GBL не могут использовать ручной откат; он отключен.", "rollback_manual_error_clock": "Системные часы недоступны.", "rollback_manual_error_date_shape": "Используйте формат YYYY-MM-DD.", "rollback_manual_error_date_value": "Введите существующую дату.", @@ -998,7 +999,6 @@ "rollback_manual_error_prefix": "Начните с 0x.", "rollback_manual_original": "Индекс образа: {index}", "rollback_manual_placeholder": "Индекс отката", - "rollback_manual_tb323fu_disabled": "TB323FU не может использовать ручной откат; он отключен.", "rollback_off": "Выкл", "rollback_on": "Вкл", "rollback_open_tip": "Показать сохранённые индексы отката", diff --git a/crates/ltbox-gui/lang/zh.json b/crates/ltbox-gui/lang/zh.json index be85f345..c1dcd521 100644 --- a/crates/ltbox-gui/lang/zh.json +++ b/crates/ltbox-gui/lang/zh.json @@ -205,6 +205,7 @@ "err_edl_probe_work_dir_failed": "创建 EDL 探测工作目录失败:{error}", "err_edl_session_open_failed": "打开 EDL 会话失败:{error}", "err_edl_transition_failed": "无法将设备重启到 EDL 模式。", + "err_efisp_loader_manifest_required": "{model} 需要多镜像加载器清单。请直接选择 `qsahara_device_programmer.xml`(或其加密 `.x`),或将它放在所选 .melf 文件旁边({path})。", "err_fastboot_command_failed": "{command}: {error}", "err_fastboot_open_failed": "打开引导加载程序设备失败:{error}", "err_fastboot_recovery_unsupported": "引导加载程序模式不能直接重启到恢复模式;请先切换到 ADB。", @@ -227,8 +228,8 @@ "err_flash_parts_erase_failed": "擦除分区 {label} 失败:{error}", "err_flash_parts_part_failed": "刷写分区 {label} 失败:{error}", "err_flash_phys_write_failed": "写入 LUN {lun} 失败:{error}", + "err_flash_prc_only": "刷写:{model} 仅限国行 — 不支持跨区域或非 CN 国家设置,已中止", "err_flash_set_bootable_lun_failed": "设置可启动 LUN 失败:{error}", - "err_flash_tb322fc_prc_only": "刷写:TB322FC 仅限国行 — 不支持跨区域或非 CN 国家设置,已中止", "err_flash_vbmeta_key_unknown": "刷写:固件 vbmeta_system 的签名密钥未知(既非 AOSP 测试密钥也非 LenovoRSA 密钥)— 写入前中止", "err_flash_xml_selection_failed": "固件 XML 选择失败:{error}", "err_flash_zst_decompress_failed": "解压 {path} 失败:{error}", @@ -302,7 +303,6 @@ "err_task_failed": "任务失败。", "err_task_failed_with_error": "任务失败:{error}", "err_task_panicked": "任务因 panic 停止。", - "err_tb323fu_loader_manifest_required": "TB323FU 需要多镜像加载器清单。请直接选择 `qsahara_device_programmer.xml`(或其加密 `.x`),或将它放在所选 .melf 文件旁边({path})。", "err_unroot_backup_manifest_invalid": "Root 备份清单 {manifest} 无效:{error}", "err_unroot_flash_failed": "刷写 {label} 失败:{error}", "err_unroot_image_missing": "所选文件夹中未找到 {image}", @@ -409,45 +409,45 @@ "konabess_attribution": "基于 libxzr 的 KonaBess — GPL-3", "konabess_confirm_changes": "表格更改", "konabess_confirm_chip": "芯片组", - "konabess_confirm_device_shape": "设备值", - "konabess_confirm_edited_shape": "编辑值", + "konabess_confirm_device_shape": "设备值", + "konabess_confirm_edited_shape": "编辑值", "konabess_confirm_import": "导入的设置", - "konabess_confirm_modified": "已相对设备值修改", + "konabess_confirm_modified": "已相对设备值修改", "konabess_confirm_subtitle": "重新构建和刷写前,请确认所选设备表和加载程序。", "konabess_confirm_title": "确认 KonaBess 操作", - "konabess_confirm_unchanged": "设备值未更改", + "konabess_confirm_unchanged": "设备值未更改", "konabess_error_invalid_cell": "请输入有效的 u32 单元值;频率可使用最多六位小数的精确 MHz 值。", "konabess_error_summary": "有 {count} 个阻止继续的错误。请修正红色标记的单元格。", "konabess_export_invalid": "这不是有效的 KonaBess 设置值文件:{error}", - "konabess_import_button": "导入", + "konabess_import_button": "导入", "konabess_import_chip_mismatch": "导入文件的芯片({actual})与所选 DTB({expected})不匹配。", "konabess_import_loaded": "已使用 {path} 中的值覆盖工作表", "konabess_import_no_target": "请先选择目标 DTB,再导入设置。", "konabess_import_unknown_chip": "无法识别所选 DTB 的芯片。", "konabess_remove_level": "删除", - "konabess_revert_button": "重置", + "konabess_revert_button": "重置", "konabess_step_apply": "应用", "konabess_step_confirm": "确认", "konabess_step_table": "GPU 表", - "konabess_table_modified": "已修改", - "konabess_table_subtitle": "检查目标 DTB 和设备表。", + "konabess_table_modified": "已修改", + "konabess_table_subtitle": "检查目标 DTB 和设备表。", "konabess_table_target": "目标 DTB", "konabess_table_title": "设备 GPU 表", - "konabess_table_value_note": "频率以精确的 MHz 显示,并以 Hz 存储。", + "konabess_table_value_note": "频率以精确的 MHz 显示,并以 Hz 存储。", "konabess_target_likely": "这很可能是正确的选项", "konabess_target_no_candidates": "未找到含有可读取 GPU 表的 DTB。", "konabess_target_no_table": "无 GPU 表", "konabess_target_none": "尚未选择目标", - "konabess_target_subtitle": "请选择一个用于加载 GPU 表的 DTB。", + "konabess_target_subtitle": "请选择一个用于加载 GPU 表的 DTB。", "konabess_target_summary": "{count} 个 GPU 表候选项", "konabess_target_title": "选择目标 DTB", "konabess_target_unknown_chip_unusable": "无法识别此 DTB 的芯片,因此不能选择。", "konabess_warning_duplicate_frequency": "初始目标频率匹配多个级别;将使用第一个匹配项。", "konabess_warning_frequency_order": "频率未严格按降序排列。", "konabess_warning_other": "请在刷写前检查此数值。", - "konabess_warning_outside_stock": "此数值超出原厂表中观察到的范围。", - "konabess_warning_retargeted": "原来的初始目标频率已被删除,因此目标将重新指向剩余级别。", - "konabess_warning_summary": "设备表中有 {count} 项需要注意。", + "konabess_warning_outside_stock": "此数值超出原厂表中观察到的范围。", + "konabess_warning_retargeted": "原来的初始目标频率已被删除,因此目标将重新指向剩余级别。", + "konabess_warning_summary": "设备表中有 {count} 项需要注意。", "live_adb_checking_device": "正在检查设备...", "live_adb_device_connected": "设备已连接", "live_adb_kernel_version": "内核版本: {version}", @@ -576,6 +576,7 @@ "live_flash_efisp_flash": "正在刷入 efisp(LUN 4)…", "live_flash_efisp_flash_failed": "efisp 刷入失败({error})— 仍将继续重启到系统", "live_flash_efisp_flashed": "efisp 刷入完成", + "live_flash_efisp_force_auto": "检测到 efisp/GBL 目标 — 回滚保护绕过强制为自动。", "live_flash_fastboot_timeout": "adb reboot bootloader 返回成功,但在 {seconds} 秒内未出现 Fastboot — 将在无引导加载程序变量的情况下继续", "live_flash_files_count": ".x 文件: {x_count}, rawprogram XML: {xml_count}", "live_flash_firmware_folder": "固件目录: {path}", @@ -584,11 +585,10 @@ "live_flash_no_rawprogram_pack": "此文件夹中没有 rawprogram(.x / .xml)— 看起来不是有效的固件镜像文件夹。", "live_flash_phase3_xml_counts": "{raw} 个 rawprogram + {patch} 个 patch XML", "live_flash_region_convert": "区域转换:{value}", + "live_flash_region_efisp": "区域由 efisp GBL 处理;跳过 vendor_boot/vbmeta 的 AVB 转换。", "live_flash_rollback_bypass": "绕过回滚保护:{value}", "live_flash_set_bootable": "将可启动 LUN 设置为 {lun} (xbl_a)", "live_flash_skip_adb": "设备处于引导加载程序/EDL — 跳过 ADB 步骤", - "live_flash_tb323fu_force_auto": "检测到 TB323FU — 回滚保护绕过强制为自动。", - "live_flash_tb323fu_region_efisp": "TB323FU:区域由 efisp GBL 处理;跳过 vendor_boot/vbmeta 的 AVB 转换。", "live_flash_vbmeta_key_unknown": "固件 vbmeta_system 签名密钥未知(非 AOSP 测试密钥/LenovoRSA 密钥)— 中止", "live_flash_vbmeta_status": "vbmeta.img: {status}", "live_flash_vendor_boot_status": "vendor_boot.img: {status}", @@ -665,10 +665,10 @@ "live_xml_decrypt_done": "已解密 {count} 个 .x 文件 → .xml", "live_xml_keep_excludes": "排除 userdata/metadata", "loader_default_ext_unsupported": "设置为默认 EDL 加载器的文件的扩展名在连接的设备上不受支持。", + "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_tb323fu": "qsahara_device_programmer.xml", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\n或 qsahara_device_programmer.xml(仅 Y700五代)", - "loader_model_mismatch_tooltip": "连接的设备需要不同的 EDL 加载器(TB323FU:.xml/.x 清单;其他机型:.melf)。", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\n或 qsahara_device_programmer.xml(仅 Y700五代 / Infinite)", + "loader_model_mismatch_tooltip": "连接的设备需要不同的 EDL 加载器(TB323FU/TB324ZC:.xml/.x 清单;其他机型:.melf)。", "log_apatch_extract_kernel": "正在提取内核: {input} → {output}", "log_apatch_extracted_kpimg": "已提取 assets/kpimg → {path}({bytes} 字节)", "log_apatch_kallsyms_all_missing": "缺少 CONFIG_KALLSYMS_ALL=y — 非致命,但某些 KPM 可能需要", @@ -778,7 +778,7 @@ "log_reboot_target_from": "{source} → {target}", "log_reboot_target_from_edl": "EDL → {target}(加载器={loader})", "log_release_latest_asset": "最新发行:{tag} — 资源 {name}", - "log_root_efisp_check": "检测到 TB323FU — 正在检查 efisp(GBL)写入状态…", + "log_root_efisp_check": "检测到 efisp/GBL 路径 — 正在检查 efisp 写入状态…", "log_root_efisp_ok": "efisp 已写入 — 继续(AVB/vbmeta 由 GBL 处理)", "log_root_installing_manager_apk": "安装管理器 APK 中:{path}", "log_root_loader": "加载器:{path}", @@ -988,6 +988,7 @@ "rollback_format_raw": "原始值(十六进制)", "rollback_format_unix": "Unix 时间戳", "rollback_manual_desc": "设置 boot 和 vbmeta_system 回滚索引。值必须早于当前时间。", + "rollback_manual_efisp_disabled": "efisp/GBL 目标无法使用手动回滚,已将其禁用。", "rollback_manual_error_clock": "系统时钟不可用。", "rollback_manual_error_date_shape": "请使用 YYYY-MM-DD 格式。", "rollback_manual_error_date_value": "请输入真实存在的日期。", @@ -998,7 +999,6 @@ "rollback_manual_error_prefix": "请以 0x 开头。", "rollback_manual_original": "镜像索引:{index}", "rollback_manual_placeholder": "回滚索引", - "rollback_manual_tb323fu_disabled": "TB323FU 无法使用手动回滚,已将其禁用。", "rollback_off": "关闭", "rollback_on": "开启", "rollback_open_tip": "查看已保存的回滚索引", diff --git a/crates/ltbox-gui/src/loader.rs b/crates/ltbox-gui/src/loader.rs index de16dbfe..e4750c03 100644 --- a/crates/ltbox-gui/src/loader.rs +++ b/crates/ltbox-gui/src/loader.rs @@ -159,14 +159,15 @@ pub(crate) fn is_melf_loader(path: &std::path::Path) -> bool { } /// True when `path`'s extension is the EDL loader form the given model needs: -/// TB323FU → `.xml` / `.x` (Sahara manifest); every other model → `.melf`. +/// Efisp/GBL-route models → `.xml` / `.x` (Sahara manifest); every other model +/// → `.melf`. /// Inspects only the file's own extension, not the images a manifest references. -pub(crate) fn loader_ext_fits_model(is_tb323fu: bool, path: &std::path::Path) -> bool { +pub(crate) fn loader_ext_fits_model(uses_efisp_gbl_route: bool, path: &std::path::Path) -> bool { let ext = path .extension() .and_then(|e| e.to_str()) .map(|e| e.to_ascii_lowercase()); - if is_tb323fu { + if uses_efisp_gbl_route { matches!(ext.as_deref(), Some("xml") | Some("x")) } else { ext.as_deref() == Some("melf") @@ -235,7 +236,7 @@ mod tests { #[test] fn loader_ext_fits_model_by_device() { - // TB323FU needs the .xml / .x manifest. + // Efisp/GBL-route models need the .xml / .x manifest. assert!(loader_ext_fits_model( true, Path::new("x/qsahara_device_programmer.xml") diff --git a/crates/ltbox-gui/src/main.rs b/crates/ltbox-gui/src/main.rs index 6914e2bc..8cbaba2d 100644 --- a/crates/ltbox-gui/src/main.rs +++ b/crates/ltbox-gui/src/main.rs @@ -2735,14 +2735,14 @@ impl App { /// Kick off region auto-detection on entering the Flash wizard (called /// right after `flash.reset()`): - /// * PRC-only model (TB322FC) → preselect PRC and jump to the target step. + /// * PRC-only model → preselect PRC and jump to the target step. /// * usable polled serial → probe PTSTPD (region step shows an indicator). /// * no usable serial → open the manual-serial prompt. /// /// On a fetch failure / inconclusive SaleArea the handler falls back to the /// manual PRC/ROW cards, so this never blocks the wizard. fn begin_flash_region_auto(&mut self) -> Task { - if self.is_tb322fc() { + if self.is_prc_only() { // PRC-only SKU: no lookup needed; skip straight to the target step. self.flash.device_region = Some(DeviceRegion::Prc); self.flash.step = 1; @@ -2966,14 +2966,14 @@ impl App { let path = std::path::Path::new(selected_path); if path.is_file() { self.remember_recent(pickers::PickerKind::File, selected_path); - // TB323FU model gate: if the user picked a `.melf` but the - // device is a TB323FU, upgrade to the + // Efisp/GBL-route model gate: if the user picked a `.melf`, upgrade + // it to the // `qsahara_device_programmer.xml` manifest sitting in the // same folder. If the manifest is missing the .melf // alone is wrong and would fail mid-Sahara — abort up // front. Performed during resolve so the wizard's Confirm // step shows the correct path. - if self.is_tb323fu() + if self.uses_efisp_gbl_route() && is_melf_loader(path) && let Some(parent) = path.parent() { @@ -2981,7 +2981,8 @@ impl App { return Ok(manifest.to_string_lossy().to_string()); } return Err(tr_args!( - "err_tb323fu_loader_manifest_required", + "err_efisp_loader_manifest_required", + model = self.device_model.as_str(), path = path.display() )); } @@ -3128,25 +3129,25 @@ impl App { self.device_class() == DeviceClass::TB320FC } - /// Whether the polled device is a TB323FU. Drives the multi-image - /// EDL loader path: TB323FU doesn't accept a single + /// Whether the polled device uses the efisp/GBL exploit route. These models + /// also use the multi-image EDL loader path and don't accept a single /// `xbl_s_devprg_ns.melf`; it needs the full /// `qsahara_device_programmer.xml` manifest + the per-id ELF / /// MBN payloads it references. The loader resolver upgrades a /// stray `.melf` selection to the manifest when one exists in /// the same folder; if not, it aborts up front rather than /// failing mid-Sahara. - fn is_tb323fu(&self) -> bool { - self.device_class() == DeviceClass::TB323FU + fn uses_efisp_gbl_route(&self) -> bool { + self.device_class().uses_efisp_gbl_route() } /// True when `path`'s extension is the EDL loader form the connected device - /// needs: TB323FU (Y700 Gen 5) loads the multi-image Sahara manifest + /// needs: efisp/GBL-route models load the multi-image Sahara manifest /// (`.xml` / `.x`); every other model loads a `.melf` single-blob programmer. /// Inspects only the picked file's own extension, never the `.mbn` / `.elf` /// images a manifest references internally. fn loader_fits_model(&self, path: &std::path::Path) -> bool { - loader_ext_fits_model(self.is_tb323fu(), path) + loader_ext_fits_model(self.uses_efisp_gbl_route(), path) } /// True when the Settings default EDL loader is unset, or its extension fits @@ -3160,12 +3161,12 @@ impl App { } /// Loader-picker description, resolved live against the connected - /// device. TB323FU (Y700 Gen 5) needs the `qsahara_device_programmer.xml` + /// device. Efisp/GBL-route models need the `qsahara_device_programmer.xml` /// manifest, not the `.melf`; with no recognised model the picker hints /// both. Every loader picker routes its subtitle through this. fn loader_picker_desc(&self) -> String { - if self.is_tb323fu() { - self.t("loader_desc_tb323fu").to_string() + if self.uses_efisp_gbl_route() { + self.t("loader_desc_efisp_gbl").to_string() } else if self.device_model.is_empty() { self.t("loader_desc_unknown").to_string() } else { @@ -3173,12 +3174,12 @@ impl App { } } - /// Whether the polled device is a TB322FC. PRC-only SKU — the Flash + /// Whether the polled device is a PRC-only SKU. The Flash /// wizard hides ROW + OtherRegion as disabled cards so the user /// cannot pick a region or cross-region flash target that the /// hardware doesn't ship with. - fn is_tb322fc(&self) -> bool { - self.device_class() == DeviceClass::TB322FC + fn is_prc_only(&self) -> bool { + self.device_class().is_prc_only() } /// True when the dashboard poll has placed the device in a mode @@ -4224,6 +4225,44 @@ mod tests { assert_eq!(app.country_popup_selected_code(), Some("CN")); } + #[test] + fn tb324zc_capabilities_drive_loader_and_region_entry() { + let mut app = App { + device_model: "TB324ZC".into(), + ..App::default() + }; + assert!(app.uses_efisp_gbl_route()); + assert!(app.is_prc_only()); + assert!(app.loader_fits_model(std::path::Path::new("qsahara_device_programmer.xml"))); + assert!(app.loader_fits_model(std::path::Path::new("qsahara_device_programmer.x"))); + assert!(!app.loader_fits_model(std::path::Path::new("prog.melf"))); + + let _ = app.begin_flash_region_auto(); + assert_eq!(app.flash.device_region, Some(DeviceRegion::Prc)); + assert_eq!(app.flash.step, 1); + } + + #[test] + fn tb324zc_flash_country_dispatch_rejects_non_cn_but_advanced_stays_unrestricted() { + let mut app = App { + device_model: "TB324ZC".into(), + country_popup_open: true, + wf_config: WorkflowConfig { + country_action: CountryAction::Set("CN".into()), + ..WorkflowConfig::default() + }, + ..App::default() + }; + let _ = app.update(Message::SelectCountry("KR".into())); + assert_eq!(app.wf_config.country_action.target(), Some("CN")); + assert!(app.country_popup_open); + + app.adv_needs_country = true; + let _ = app.update(Message::SelectCountry("KR".into())); + assert_eq!(app.adv_wizard.country.as_deref(), Some("KR")); + assert!(!app.country_popup_open); + } + #[test] fn flash_keep_data_preserves_confirm_country_override() { let mut app = App { @@ -4538,6 +4577,7 @@ mod tests { assert_eq!(arb_from_model(""), ""); assert_eq!(arb_from_model(" "), ""); assert_eq!(arb_from_model("TB322FC"), "arb_no"); + assert_eq!(arb_from_model("TB324ZC"), "arb_yes"); assert_eq!(arb_from_model("TB520FU"), "arb_yes"); } diff --git a/crates/ltbox-gui/src/update/flash.rs b/crates/ltbox-gui/src/update/flash.rs index 776fed0f..3b3f17a3 100644 --- a/crates/ltbox-gui/src/update/flash.rs +++ b/crates/ltbox-gui/src/update/flash.rs @@ -7,11 +7,11 @@ impl App { pub(crate) fn update_flash(&mut self, msg: FlashMsg) -> Task { match msg { FlashMsg::FlashRegion(r) => { - // TB322FC is a PRC-only SKU. The region card UI grays + // PRC-only SKUs gray // out ROW, but a stale message from a pre-poll click // could still land here. Drop it so the wizard never // accepts a region the hardware doesn't ship with. - if self.is_tb322fc() && r == DeviceRegion::Row { + if self.is_prc_only() && r == DeviceRegion::Row { return Task::none(); } self.flash.device_region = Some(r); @@ -86,10 +86,10 @@ impl App { Task::none() } FlashMsg::FlashTarget(t) => { - // TB322FC: cross-region (OtherRegion) flashes are blocked + // PRC-only SKUs block cross-region (OtherRegion) flashes // because the only valid region is PRC. Drop the message // even if a stale dispatch slips past the disabled card. - if self.is_tb322fc() && t == FlashTarget::OtherRegion { + if self.is_prc_only() && t == FlashTarget::OtherRegion { return Task::none(); } self.flash.target = Some(t); @@ -288,18 +288,18 @@ impl App { Task::none() } FlashMsg::FlashConfirmSetRegion(r) => { - // TB322FC is PRC-only; the editor grays out ROW, but drop a + // PRC-only models gray out ROW; drop a // stale dispatch defensively like the region card handler does. - if !(self.is_tb322fc() && r == DeviceRegion::Row) { + if !(self.is_prc_only() && r == DeviceRegion::Row) { self.wf_config.device_region = Some(r); } self.confirm_edit_field = None; Task::none() } FlashMsg::FlashConfirmSetTarget(t) => { - // Target ↔ region edit both map onto `modify_region`. TB322FC + // Target ↔ region edit both map onto `modify_region`. PRC-only models // can't cross regions, so block OtherRegion defensively. - if !(self.is_tb322fc() && t == FlashTarget::OtherRegion) { + if !(self.is_prc_only() && t == FlashTarget::OtherRegion) { self.wf_config.modify_region = t == FlashTarget::OtherRegion; } self.confirm_edit_field = None; @@ -324,9 +324,9 @@ impl App { } FlashMsg::FlashConfirmSetRegionEdit(on) => { // Region edit drives the same `modify_region` cross-region flag - // as the Target row, so apply the TB322FC PRC-only guard here + // as the Target row, so apply the PRC-only guard here // too — otherwise this path bypasses the disabled Target option. - if !(self.is_tb322fc() && on) { + if !(self.is_prc_only() && on) { self.wf_config.modify_region = on; } self.confirm_edit_field = None; @@ -449,4 +449,33 @@ mod tests { ); } } + + #[test] + fn tb324zc_rejects_stale_row_and_cross_region_dispatches() { + let mut app = App { + device_model: "TB324ZC".into(), + flash: FlashWizard { + device_region: Some(DeviceRegion::Prc), + target: Some(FlashTarget::SameRegion), + ..FlashWizard::default() + }, + wf_config: WorkflowConfig { + device_region: Some(DeviceRegion::Prc), + modify_region: false, + ..WorkflowConfig::default() + }, + ..App::default() + }; + + let _ = app.update_flash(FlashMsg::FlashRegion(DeviceRegion::Row)); + let _ = app.update_flash(FlashMsg::FlashTarget(FlashTarget::OtherRegion)); + let _ = app.update_flash(FlashMsg::FlashConfirmSetRegion(DeviceRegion::Row)); + let _ = app.update_flash(FlashMsg::FlashConfirmSetTarget(FlashTarget::OtherRegion)); + let _ = app.update_flash(FlashMsg::FlashConfirmSetRegionEdit(true)); + + assert_eq!(app.flash.device_region, Some(DeviceRegion::Prc)); + assert_eq!(app.flash.target, Some(FlashTarget::SameRegion)); + assert_eq!(app.wf_config.device_region, Some(DeviceRegion::Prc)); + assert!(!app.wf_config.modify_region); + } } diff --git a/crates/ltbox-gui/src/update/konabess.rs b/crates/ltbox-gui/src/update/konabess.rs index c20ce01e..017af997 100644 --- a/crates/ltbox-gui/src/update/konabess.rs +++ b/crates/ltbox-gui/src/update/konabess.rs @@ -110,7 +110,7 @@ impl App { let phases = self .begin_phased_op(View::KonaBess, OperationPhaseKind::KonaBess); let conn = self.connection; - let is_tb323fu = self.is_tb323fu(); + let uses_efisp_gbl_route = self.uses_efisp_gbl_route(); let ll = self.live_labels(); let loader = std::path::PathBuf::from(loader); return Task::perform( @@ -118,7 +118,11 @@ impl App { tokio::task::spawn_blocking(move || { ltbox_core::runtime::run_heavy(move || { konabess_inspection_worker( - conn, loader, is_tb323fu, ll, phases, + conn, + loader, + uses_efisp_gbl_route, + ll, + phases, ) }) .and_then(|result| result) diff --git a/crates/ltbox-gui/src/update/mod.rs b/crates/ltbox-gui/src/update/mod.rs index da9fe219..159820fa 100644 --- a/crates/ltbox-gui/src/update/mod.rs +++ b/crates/ltbox-gui/src/update/mod.rs @@ -159,11 +159,11 @@ impl App { Message::Flash(m) => return self.update_flash(m), // Country code popup Message::SelectCountry(code) => { - // TB322FC ships PRC-only — the Flash wizard only accepts `CN`. + // PRC-only models make the Flash wizard accept only `CN`. // The popup grays out other entries, but a stale dispatch could // still land here. Drop it — EXCEPT for the Advanced "Change // Country Code" op, which allows any country on any model. - if self.is_tb322fc() && !self.adv_needs_country && !code.eq_ignore_ascii_case("CN") + if self.is_prc_only() && !self.adv_needs_country && !code.eq_ignore_ascii_case("CN") { return Task::none(); } diff --git a/crates/ltbox-gui/src/update/root.rs b/crates/ltbox-gui/src/update/root.rs index 8eb4b730..be7c449d 100644 --- a/crates/ltbox-gui/src/update/root.rs +++ b/crates/ltbox-gui/src/update/root.rs @@ -56,9 +56,9 @@ impl App { } RootMsg::RootMode(m) => { // TODO(root): LTBox currently only swaps the boot.img Image - // for GKI, which corrupts boot on TB323FU. Keep it disabled + // for GKI, which corrupts boot on efisp/GBL-route models. Keep it disabled // until vbmeta handling is added. - if self.is_tb323fu() && m == RootMode::Gki { + if self.uses_efisp_gbl_route() && m == RootMode::Gki { return Task::none(); } self.root.mode = Some(m); @@ -371,14 +371,17 @@ impl App { return Task::none(); } // TODO(root): LTBox currently only swaps the boot.img Image - // for GKI, which corrupts boot on TB323FU. The mode card is + // for GKI, which corrupts boot on efisp/GBL-route models. The mode card is // disabled, but stale selections can survive from before the // model was identified; refuse them until vbmeta handling is // added. - if self.is_tb323fu() && self.root.is_gki() { + if self.uses_efisp_gbl_route() && self.root.is_gki() { self.root.mode = None; self.root.step = 1; // Mode step - self.error_msg = Some(tr_args!("model_unsupported", model = "TB323FU")); + self.error_msg = Some(tr_args!( + "model_unsupported", + model = self.device_model.as_str() + )); return Task::none(); } if self @@ -691,6 +694,26 @@ mod tests { assert!(app.op_steps.is_empty()); } + #[test] + fn tb324zc_blocks_gki_dispatch_and_start_with_its_own_model_name() { + let mut app = App { + device_model: "TB324ZC".into(), + ..App::default() + }; + let _ = app.update_root(RootMsg::RootMode(RootMode::Gki)); + assert_eq!(app.root.mode, None); + + app.root.mode = Some(RootMode::Gki); + let _ = app.update_root(RootMsg::RootExecStart); + assert_eq!(app.root.mode, None); + assert_eq!(app.root.step, 1); + assert!( + app.error_msg + .as_deref() + .is_some_and(|msg| msg.contains("TB324ZC")) + ); + } + #[test] fn root_route_label_separates_the_two_magisk_routes() { let label = |provider| { diff --git a/crates/ltbox-gui/src/update/sys.rs b/crates/ltbox-gui/src/update/sys.rs index 1c5b6364..47de5b4b 100644 --- a/crates/ltbox-gui/src/update/sys.rs +++ b/crates/ltbox-gui/src/update/sys.rs @@ -8,10 +8,10 @@ impl App { pub(crate) fn update_sys(&mut self, msg: SysMsg) -> Task { match msg { SysMsg::SysAction(a) => { - // TB323FU can't run Boot Recovery (vendor_boot/vbmeta LUN + // Efisp/GBL-route models can't run Boot Recovery (vendor_boot/vbmeta LUN // mismatch). The card is disabled, but drop a stale dispatch // here too so the action can never latch. - if a == SysUpdateAction::Rescue && self.is_tb323fu() { + if a == SysUpdateAction::Rescue && self.uses_efisp_gbl_route() { return Task::none(); } // Switching action resets Rescue-specific state so a stale @@ -107,10 +107,13 @@ impl App { let Some(action) = self.sysupdate.action else { return Task::none(); }; - // Final guard: never start Boot Recovery on TB323FU even if a + // Final guard: never start Boot Recovery on an efisp/GBL-route model even if a // stale Rescue selection slipped past the disabled card. - if action == SysUpdateAction::Rescue && self.is_tb323fu() { - self.error_msg = Some(tr_args!("model_unsupported", model = "TB323FU")); + if action == SysUpdateAction::Rescue && self.uses_efisp_gbl_route() { + self.error_msg = Some(tr_args!( + "model_unsupported", + model = self.device_model.as_str() + )); return Task::none(); } // Rescue captures folder + region into the blocking task. @@ -170,3 +173,26 @@ impl App { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn tb324zc_blocks_boot_recovery_dispatch_and_start_with_its_own_model_name() { + let mut app = App { + device_model: "TB324ZC".into(), + ..App::default() + }; + let _ = app.update_sys(SysMsg::SysAction(SysUpdateAction::Rescue)); + assert_eq!(app.sysupdate.action, None); + + app.sysupdate.action = Some(SysUpdateAction::Rescue); + let _ = app.update_sys(SysMsg::SysExecStart); + assert!( + app.error_msg + .as_deref() + .is_some_and(|msg| msg.contains("TB324ZC")) + ); + } +} diff --git a/crates/ltbox-gui/src/view/flash.rs b/crates/ltbox-gui/src/view/flash.rs index 4100208c..3f3abb91 100644 --- a/crates/ltbox-gui/src/view/flash.rs +++ b/crates/ltbox-gui/src/view/flash.rs @@ -73,16 +73,16 @@ impl App { let d = self.density(); let side = self.wizard_square_side(); let prc_icon = lucide_primary(icon::region_prc(), self.wizard_square_icon()); - // TB322FC is a PRC-only SKU. Render ROW as a disabled card with + // PRC-only SKUs render ROW as a disabled card with // a grayed icon so the constraint is visible — silent skip // would confuse users who expect both options. - let tb322fc = self.is_tb322fc(); - let unsupported_tb322fc = tr_args!("model_unsupported", model = "TB322FC"); - let row_card: Element<'_, Message> = if tb322fc { + let prc_only = self.is_prc_only(); + let unsupported_model = tr_args!("model_unsupported", model = self.device_model.as_str()); + let row_card: Element<'_, Message> = if prc_only { icon_option_card_sub_square_disabled_sized( lucide_disabled(icon::region_row(), self.wizard_square_icon()), self.t("region_row"), - &unsupported_tb322fc, + &unsupported_model, side, ) } else { @@ -143,11 +143,11 @@ impl App { let d = self.density(); let side = self.wizard_square_side(); let device = lucide_primary(icon::tile_device(), self.wizard_square_icon()); - // TB322FC ships only in PRC, so cross-region (OtherRegion) is + // PRC-only SKUs cannot use a cross-region (OtherRegion) target, so it is // never a valid target. Disable the card with a grayed icon to // keep the constraint visible on the picker. - let tb322fc = self.is_tb322fc(); - let unsupported_tb322fc = tr_args!("model_unsupported", model = "TB322FC"); + let prc_only = self.is_prc_only(); + let unsupported_model = tr_args!("model_unsupported", model = self.device_model.as_str()); // Region-aware target descriptions spell out the hardware market and // the ROM being installed so users don't conflate the two (the most // common point of confusion in this wizard). device_region is chosen @@ -157,11 +157,11 @@ impl App { Some(DeviceRegion::Row) => ("flashtarget_same_desc_row", "flashtarget_other_desc_row"), None => ("flashtarget_same_desc", "flashtarget_other_desc"), }; - let other_card: Element<'_, Message> = if tb322fc { + let other_card: Element<'_, Message> = if prc_only { icon_option_card_sub_square_disabled_sized( lucide_disabled(icon::tile_globe(), self.wizard_square_icon()), self.t(FlashTarget::OtherRegion.label_key()), - &unsupported_tb322fc, + &unsupported_model, side, ) } else { diff --git a/crates/ltbox-gui/src/view/popups.rs b/crates/ltbox-gui/src/view/popups.rs index 2966ec17..3f254e9b 100644 --- a/crates/ltbox-gui/src/view/popups.rs +++ b/crates/ltbox-gui/src/view/popups.rs @@ -826,16 +826,16 @@ impl App { ); list = list.push(widget::rule::horizontal(1)); } - // TB322FC PRC-only: only CN is selectable in the Flash wizard. Non-CN + // PRC-only models: only CN is selectable in the Flash wizard. Non-CN // rows render as disabled buttons so the constraint stays visible. The // Advanced "Change Country Code" op has no such restriction (any country, // any model), so the gate is lifted there. "Do not change" stays usable. - let tb322fc = self.is_tb322fc() && !self.adv_needs_country; + let prc_only = self.is_prc_only() && !self.adv_needs_country; for entry in COUNTRY_CODES { let code = entry.code.to_string(); let selected = selected_code == Some(entry.code); let label = format!("{} — {}", entry.code, entry.name); - let disabled = tb322fc && !entry.code.eq_ignore_ascii_case("CN"); + let disabled = prc_only && !entry.code.eq_ignore_ascii_case("CN"); let mut btn = button(text(label).size(13)) .padding([6, 14]) .width(Length::Fill) @@ -950,7 +950,7 @@ impl App { pub(crate) fn flash_confirm_edit_popup(&self, field: ConfirmField) -> Element<'_, Message> { // (label, selected, on_press, disabled) let cfg = &self.wf_config; - let tb322 = self.is_tb322fc(); + let prc_only = self.is_prc_only(); let opts: Vec<(String, bool, Message, bool)> = match field { ConfirmField::Region => [DeviceRegion::Prc, DeviceRegion::Row] .into_iter() @@ -959,7 +959,7 @@ impl App { self.t(r.label_key()).to_string(), cfg.device_region == Some(r), Message::Flash(FlashMsg::FlashConfirmSetRegion(r)), - tb322 && r == DeviceRegion::Row, + prc_only && r == DeviceRegion::Row, ) }) .collect(), @@ -970,7 +970,7 @@ impl App { self.t(t.label_key()).to_string(), cfg.modify_region == (t == FlashTarget::OtherRegion), Message::Flash(FlashMsg::FlashConfirmSetTarget(t)), - tb322 && t == FlashTarget::OtherRegion, + prc_only && t == FlashTarget::OtherRegion, ) }) .collect(), @@ -1002,9 +1002,9 @@ impl App { .to_string(), cfg.modify_region == on, Message::Flash(FlashMsg::FlashConfirmSetRegionEdit(on)), - // PRC-only TB322FC can't cross regions — disable "On" + // PRC-only models can't cross regions — disable "On" // to match the Target editor's OtherRegion gate. - tb322 && on, + prc_only && on, ) }) .collect(), diff --git a/crates/ltbox-gui/src/view/root.rs b/crates/ltbox-gui/src/view/root.rs index 86656844..09d50cc1 100644 --- a/crates/ltbox-gui/src/view/root.rs +++ b/crates/ltbox-gui/src/view/root.rs @@ -721,8 +721,8 @@ impl App { pub(crate) fn root_mode_step(&self) -> Element<'_, Message> { let d = self.density(); let side = self.wizard_square_side(); - let tb323fu = self.is_tb323fu(); - let unsupported_tb323fu = tr_args!("model_unsupported", model = "TB323FU"); + let uses_efisp_gbl_route = self.uses_efisp_gbl_route(); + let unsupported_model = tr_args!("model_unsupported", model = self.device_model.as_str()); let lkm_card = icon_option_card_sub_square_sized( RootMode::Lkm.icon(self.wizard_square_icon()), self.t(RootMode::Lkm.label_key()), @@ -733,13 +733,13 @@ impl App { ); let lkm_card = recommended_overlay(d, lkm_card, self.t("root_recommended_tip").to_string()); // TODO(root): LTBox currently only swaps the boot.img Image for - // GKI, which corrupts boot on TB323FU. Keep GKI disabled until + // GKI, which corrupts boot on efisp/GBL-route models. Keep GKI disabled until // vbmeta handling is added. - let gki_card: Element<'_, Message> = if tb323fu { + let gki_card: Element<'_, Message> = if uses_efisp_gbl_route { icon_option_card_sub_square_disabled_sized( RootMode::Gki.icon_disabled(self.wizard_square_icon()), self.t(RootMode::Gki.label_key()), - &unsupported_tb323fu, + &unsupported_model, side, ) } else { diff --git a/crates/ltbox-gui/src/view/sysupdate.rs b/crates/ltbox-gui/src/view/sysupdate.rs index e2a57fa8..afdd244f 100644 --- a/crates/ltbox-gui/src/view/sysupdate.rs +++ b/crates/ltbox-gui/src/view/sysupdate.rs @@ -99,10 +99,10 @@ impl App { let side = self.wizard_square_side(); let off_icon = lucide_primary(icon::tile_update_off(), self.wizard_square_icon()); let on_icon = lucide_primary(icon::tile_update_on(), self.wizard_square_icon()); - // TB323FU's vendor_boot/vbmeta sit on a different UFS LUN than the + // Efisp/GBL-route models' vendor_boot/vbmeta sit on a different UFS LUN than the // Boot Recovery worker targets, so the flow can't run on it — disable // the card (alongside the non-Qualcomm platform gate). - let rescue_disabled = self.platform_supported == Some(false) || self.is_tb323fu(); + let rescue_disabled = self.platform_supported == Some(false) || self.uses_efisp_gbl_route(); // Gray the icon when disabled, matching the other wizards' disabled // option cards (region ROW / OtherRegion). let rescue_icon = if rescue_disabled { @@ -133,8 +133,8 @@ impl App { // Disabled rescue card — no on_press, grayed out; still mirrors // the sub-row layout of the other tiles with the Qualcomm-required // hint so the label sits at the same height. - let rescue_req = if self.is_tb323fu() { - tr_args!("model_unsupported", model = "TB323FU") + let rescue_req = if self.uses_efisp_gbl_route() { + tr_args!("model_unsupported", model = self.device_model.as_str()) } else { self.t("sysupdate_rescue_req").to_string() }; diff --git a/crates/ltbox-gui/src/workers/flash/full.rs b/crates/ltbox-gui/src/workers/flash/full.rs index c3c00d77..d8e46272 100644 --- a/crates/ltbox-gui/src/workers/flash/full.rs +++ b/crates/ltbox-gui/src/workers/flash/full.rs @@ -1,5 +1,34 @@ use super::*; -use crate::{ManualRollbackIndices, PhaseReporter}; +use crate::{ + CountryAction, DeviceClass, ManualRollbackIndices, PhaseReporter, + fingerprint_uses_efisp_gbl_route, +}; + +fn prc_only_flash_violation( + model: &str, + modify_region: bool, + country_action: &CountryAction, +) -> bool { + if !DeviceClass::from_model(model).is_prc_only() { + return false; + } + let non_cn_country = country_action + .target() + .map(|code| !code.eq_ignore_ascii_case("CN")) + .unwrap_or(false); + modify_region || non_cn_country +} + +fn target_uses_efisp_gbl_route(firmware_fingerprint: Option<&str>) -> bool { + firmware_fingerprint + .map(fingerprint_uses_efisp_gbl_route) + .unwrap_or(false) +} + +fn efisp_gbl_skip_region(firmware_fingerprint: Option<&str>, device_model: &str) -> bool { + target_uses_efisp_gbl_route(firmware_fingerprint) + || DeviceClass::from_model(device_model).uses_efisp_gbl_route() +} #[allow(clippy::too_many_arguments)] pub(crate) fn flash_worker( @@ -334,21 +363,15 @@ pub(crate) fn flash_worker( // Phase 4/9 — Prepare the flash and safety plan. live!(log, "[Flash] {}", phases.marker(4)); - // TB323FU keeps region vendor_boot/vbmeta AVB conversion off (it + // Efisp/GBL-route models keep region vendor_boot/vbmeta AVB conversion off (they // provisions a GBL on efisp instead) but DOES take ARB // overlays. Region detect uses fp first, then model. - let tb323fu_skip_region = firmware_fingerprint - .as_deref() - .map(|fp| fingerprint_token_match(fp, "TB323FU")) - .unwrap_or(false) - || fingerprint_token_match(&device_model, "TB323FU"); + let skip_region_for_efisp_gbl = + efisp_gbl_skip_region(firmware_fingerprint.as_deref(), &device_model); // GBL/ARB work follows the TARGET firmware identity // (vendor_boot fp), never the connected device. - let target_is_tb323fu = firmware_fingerprint - .as_deref() - .map(|fp| fingerprint_token_match(fp, "TB323FU")) - .unwrap_or(false); + let target_efisp_gbl = target_uses_efisp_gbl_route(firmware_fingerprint.as_deref()); // EDL-start no longer forces rollback-bypass (or region) off. The device // model and committed rollback index are read by dumping vendor_boot + @@ -357,32 +380,32 @@ pub(crate) fn flash_worker( // user's selected rollback-bypass + region modes are preserved exactly as // on an ADB/bootloader start. - // TB323FU must never run a blind ON: ON bumps even + // Efisp/GBL-route models must never run a blind ON: ON bumps even // matching indices and would force the testkey/_arb // chain when no downgrade is in play. Demote to AUTO so // the EDL-dumped device index decides per partition. - if target_is_tb323fu && rb_mode != ltbox_patch::rollback::RollbackMode::Off { + if target_efisp_gbl && rb_mode != ltbox_patch::rollback::RollbackMode::Off { if rb_mode == ltbox_patch::rollback::RollbackMode::On { rb_mode = ltbox_patch::rollback::RollbackMode::Auto; ltbox_core::live!( log, "[ARB] {}", - ltbox_core::i18n::tr("live_flash_tb323fu_force_auto") + ltbox_core::i18n::tr("live_flash_efisp_force_auto") ); } else if rb_mode == ltbox_patch::rollback::RollbackMode::Manual { rb_mode = ltbox_patch::rollback::RollbackMode::Off; ltbox_core::live!( log, "[ARB] {}", - ltbox_core::i18n::tr("rollback_manual_tb323fu_disabled") + ltbox_core::i18n::tr("rollback_manual_efisp_disabled") ); } } - if tb323fu_skip_region { + if skip_region_for_efisp_gbl { ltbox_core::live!( log, "[Flash] {}", - ltbox_core::i18n::tr("live_flash_tb323fu_region_efisp") + ltbox_core::i18n::tr("live_flash_region_efisp") ); } @@ -430,7 +453,7 @@ pub(crate) fn flash_worker( // ARB dump decides `_arb` (testkey-root) vs stock — see // the post-rawprogram-staging block below. let mut efisp_efi: Option = None; - let mut tb323fu_arb_need = false; + let mut efisp_gbl_arb_need = false; // Count .x and .xml files // Count flashable `.x` (rawprogram) files. The @@ -481,7 +504,7 @@ pub(crate) fn flash_worker( // via testkeys in KEY_MAP). Classify the firmware via vbmeta_system's pubkey // (the unified key source): an `Unknown` key aborts; a fixed-key ("key2") // firmware aborts on cross-region for now (same-region key2 is handled after - // EDL opens; cross-region key2 re-sign is a separate change). TB323FU has its + // EDL opens; cross-region key2 re-sign is a separate change). Efisp/GBL models have their // own region path (efisp GBL) and is exempt here. let fw_key_class = match ltbox_patch::avb::extract_image_avb_info(&vbmeta_system) { Ok(info) => ltbox_patch::key_map::classify_pubkey(info.public_key_sha1.as_deref()), @@ -503,7 +526,7 @@ pub(crate) fn flash_worker( // (testkey device) or an abort (fixed device). let mut region_pair: Option = None; if cfg.modify_region - && !tb323fu_skip_region + && !skip_region_for_efisp_gbl && fw_key_class != ltbox_patch::key_map::KeyClass::Fixed { if has_vendor_boot && has_vbmeta { @@ -731,31 +754,25 @@ pub(crate) fn flash_worker( match read_edl_start_device(&mut session, firmware_fingerprint.as_deref(), &mut log) { Ok(probe) => { device_model = probe.model_token; + if prc_only_flash_violation(&device_model, cfg.modify_region, &cfg.country_action) { + let _ = session.reset_to_edl(&mut log); + return Err(tr_args!( + "err_flash_prc_only", + model = device_model.as_str() + )); + } match probe.rollback_floors { None => { - // TB322FC is PRC-only. The pre-EDL UI gates that block - // cross-region / non-CN country never fired (the model - // was unknown until now), so enforce the constraint - // here, before any region or country write. - let non_cn_country = cfg - .country_action - .target() - .map(|c| !c.eq_ignore_ascii_case("CN")) - .unwrap_or(false); + // TB322FC has no rollback protection. PRC-only + // restrictions were enforced explicitly above, without + // coupling them to this missing-floor sentinel. if rb_mode != ltbox_patch::rollback::RollbackMode::Manual { - if cfg.modify_region || non_cn_country { - let _ = session.reset_to_edl(&mut log); - return Err(ltbox_core::i18n::tr("err_flash_tb322fc_prc_only")); - } rb_mode = ltbox_patch::rollback::RollbackMode::Off; ltbox_core::live!( log, "[ARB] {}", ltbox_core::i18n::tr("live_arb_device_index_none") ); - } else if cfg.modify_region || non_cn_country { - let _ = session.reset_to_edl(&mut log); - return Err(ltbox_core::i18n::tr("err_flash_tb322fc_prc_only")); } } Some(floors) => { @@ -789,13 +806,13 @@ pub(crate) fn flash_worker( // AVB root-of-trust gate (device side). The firmware vbmeta was already // classified (`fw_key_class`): `Unknown` aborted before region conversion; - // `Testkey` firmware and a `Fixed` firmware on TB323FU take their existing + // `Testkey` firmware and a `Fixed` firmware on the efisp/GBL route take their existing // paths. Here a `Fixed` ("key2") firmware on any other model classifies the // device's active-slot vbmeta and either proceeds as-is (fixed device, same // region, no downgrade), re-signs to the testkey + preserves the device // bootloader (testkey device — including a cross-region convert-then-resign), // or aborts (fixed device cross-region/downgrade, or unknown device key). - if fw_key_class == ltbox_patch::key_map::KeyClass::Fixed && !target_is_tb323fu { + if fw_key_class == ltbox_patch::key_map::KeyClass::Fixed && !target_efisp_gbl { let kc_dir = ltbox_core::app_paths::work_dir_for("flash_keyclass"); let _ = std::fs::remove_dir_all(&kc_dir); std::fs::create_dir_all(&kc_dir) @@ -1071,8 +1088,8 @@ pub(crate) fn flash_worker( ) ); } - } else if rb_mode != ltbox_patch::rollback::RollbackMode::Off && target_is_tb323fu { - // TB323FU stages the testkey chain whenever the + } else if rb_mode != ltbox_patch::rollback::RollbackMode::Off && target_efisp_gbl { + // Efisp/GBL-route models stage the testkey chain whenever the // install is a downgrade, independent of region / // wipe: the matching `_arb` GBL is flashed to efisp // below in the exact same `need` cases, so the chain @@ -1094,7 +1111,7 @@ pub(crate) fn flash_worker( None, &mut log, )?; - tb323fu_arb_need = need; + efisp_gbl_arb_need = need; arb_patched = overlays; } else if rb_mode != ltbox_patch::rollback::RollbackMode::Off { let arb_work_dir = ltbox_core::app_paths::work_dir_for("flash_arb"); @@ -1309,12 +1326,12 @@ pub(crate) fn flash_worker( // gated on data wipe — flashing efisp no longer forces // a data reset, so it provisions in data-keep mode too. // Both flash below. - if target_is_tb323fu && (tb323fu_arb_need || cfg.modify_region) { - // TB323FU's AVB fingerprint carries no region token; read the region + if target_efisp_gbl && (efisp_gbl_arb_need || cfg.modify_region) { + // The AVB fingerprint carries no region token; read the region // from the firmware vendor_boot's `product_region` DTB marker instead. let is_prc = ltbox_patch::region::detect_product_region(&vendor_boot) == Some(ltbox_patch::region::RegionTarget::Prc); - let suffix = efisp_asset_suffix(is_prc, tb323fu_arb_need); + let suffix = efisp_asset_suffix(is_prc, efisp_gbl_arb_need); let expected_name = efisp_expected_asset(suffix).ok_or_else(|| { tr_args!( "err_flash_efisp_asset_unknown", @@ -1444,7 +1461,7 @@ pub(crate) fn flash_worker( // variant on a region-provisioning wipe (best-effort). // With no EFI fetched, a same-region wipe strips efisp; // every other mode leaves it untouched. - if target_is_tb323fu { + if target_efisp_gbl { let efisp_lun = ltbox_core::partition_lun::lun_for_partition("efisp").unwrap_or(4); match &efisp_efi { Some(efi) => { @@ -1463,7 +1480,7 @@ pub(crate) fn flash_worker( // with this `_arb` GBL. Abort loudly // (device stays in EDL for retry) rather // than resetting into a rollback brick. - if tb323fu_arb_need { + if efisp_gbl_arb_need { return Err(tr_args!( "err_flash_efisp_arb_failed", error = e.to_string() @@ -1481,7 +1498,7 @@ pub(crate) fn flash_worker( // A downgrade always fetches the `_arb` GBL, // so reaching here with `need` set is an // internal inconsistency — fail safe. - if tb323fu_arb_need { + if efisp_gbl_arb_need { return Err(ltbox_core::i18n::tr("err_flash_efisp_arb_missing")); } // Same-region wipe with no downgrade strips @@ -1715,6 +1732,51 @@ fn verify_efisp_asset(path: &std::path::Path, asset_name: &str) -> Result<(), St Ok(()) } +#[cfg(test)] +mod tb324zc_route_tests { + use super::{efisp_gbl_skip_region, prc_only_flash_violation, target_uses_efisp_gbl_route}; + use crate::CountryAction; + + const TB324ZC_FP: &str = "qti/TB324ZC/TB324ZC:16/build:user/release-keys"; + + #[test] + fn target_and_live_efisp_predicates_keep_their_inputs_separate() { + assert!(target_uses_efisp_gbl_route(Some(TB324ZC_FP))); + assert!(!target_uses_efisp_gbl_route(None)); + assert!(efisp_gbl_skip_region(None, "TB324ZC")); + assert!(!efisp_gbl_skip_region(None, "TB520FU")); + } + + #[test] + fn edl_start_prc_recheck_is_independent_of_rollback_floors() { + assert!(prc_only_flash_violation( + "TB324ZC", + true, + &CountryAction::Set("CN".into()) + )); + assert!(prc_only_flash_violation( + "TB324ZC", + false, + &CountryAction::Set("KR".into()) + )); + assert!(!prc_only_flash_violation( + "TB324ZC", + false, + &CountryAction::Set("CN".into()) + )); + assert!(prc_only_flash_violation( + "TB322FC", + true, + &CountryAction::Skip + )); + assert!(!prc_only_flash_violation( + "TB520FU", + true, + &CountryAction::Set("KR".into()) + )); + } +} + #[cfg(test)] mod efisp_pin_tests { use super::{ diff --git a/crates/ltbox-gui/src/workers/konabess.rs b/crates/ltbox-gui/src/workers/konabess.rs index b843bfa2..ff19788f 100644 --- a/crates/ltbox-gui/src/workers/konabess.rs +++ b/crates/ltbox-gui/src/workers/konabess.rs @@ -24,12 +24,12 @@ struct InspectionPaths { #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum ExploitGateKind { SignedVbmeta, - Tb323fuEfisp, + EfispGbl, } -const fn exploit_gate_kind(is_tb323fu: bool) -> ExploitGateKind { - if is_tb323fu { - ExploitGateKind::Tb323fuEfisp +const fn exploit_gate_kind(uses_efisp_gbl_route: bool) -> ExploitGateKind { + if uses_efisp_gbl_route { + ExploitGateKind::EfispGbl } else { ExploitGateKind::SignedVbmeta } @@ -64,7 +64,7 @@ trait KonaBessInspectionBackend { struct DeviceBackend<'a> { conn: ConnectionStatus, loader: &'a Path, - is_tb323fu: bool, + uses_efisp_gbl_route: bool, session: Option, writes_started: bool, } @@ -127,8 +127,8 @@ impl KonaBessInspectionBackend for DeviceBackend<'_> { work_dir: &Path, log: &mut Vec, ) -> Result<(), String> { - match exploit_gate_kind(self.is_tb323fu) { - ExploitGateKind::Tb323fuEfisp => { + match exploit_gate_kind(self.uses_efisp_gbl_route) { + ExploitGateKind::EfispGbl => { let efi_dir = work_dir.join("efisp_gbl"); let staged = prepare_tb323fu_efisp( self.session()?, @@ -222,7 +222,7 @@ fn execute_inspection( backend.dump_partition(&vendor_boot_partition, &vendor_boot, log)?; backend.dump_partition(&vbmeta_partition, &vbmeta, log)?; - // Gate only after both source images exist. TB323FU takes the shared efisp + // Gate only after both source images exist. Efisp/GBL-route models take the shared efisp // path; every other model resolves vbmeta through KEY_MAP and permits an // absent key as unsigned. backend.run_exploit_gate(&slot_suffix, &vendor_boot, &vbmeta, &paths.work_dir, log)?; @@ -251,7 +251,7 @@ fn execute_inspection( pub(crate) fn konabess_inspection_worker( conn: ConnectionStatus, loader: PathBuf, - is_tb323fu: bool, + uses_efisp_gbl_route: bool, ll: LiveLabels, phases: PhaseReporter, ) -> Result { @@ -271,7 +271,7 @@ pub(crate) fn konabess_inspection_worker( let mut backend = DeviceBackend { conn, loader: &loader, - is_tb323fu, + uses_efisp_gbl_route, session: None, writes_started: false, }; @@ -784,8 +784,8 @@ mod tests { } #[test] - fn tb323fu_empty_efisp_requires_provision_and_bypasses_avb_gate() { - assert_eq!(exploit_gate_kind(true), ExploitGateKind::Tb323fuEfisp); + fn efisp_gbl_route_requires_provision_and_bypasses_avb_gate() { + assert_eq!(exploit_gate_kind(true), ExploitGateKind::EfispGbl); assert_eq!(exploit_gate_kind(false), ExploitGateKind::SignedVbmeta); assert!(crate::efisp_is_empty(&[0; 32])); assert!(!crate::efisp_is_empty(&[0, 0, 1, 0])); diff --git a/crates/ltbox-gui/src/workers/root.rs b/crates/ltbox-gui/src/workers/root.rs index 98d95912..044c6846 100644 --- a/crates/ltbox-gui/src/workers/root.rs +++ b/crates/ltbox-gui/src/workers/root.rs @@ -4,9 +4,9 @@ use crate::{ ConnectionStatus, Family, LiveLabels, PhaseReporter, Provider, RootMode, VerChoice, - fingerprint_token_match, install_root_manager_apk, open_edl_session, prepare_tb323fu_efisp, - provision_tb323fu_efisp, stage_manager_apk_for_manual_install, transition_to_edl, - wait_and_install_root_manager_apk, + fingerprint_token_match, fingerprint_uses_efisp_gbl_route, install_root_manager_apk, + open_edl_session, prepare_tb323fu_efisp, provision_tb323fu_efisp, + stage_manager_apk_for_manual_install, transition_to_edl, wait_and_install_root_manager_apk, }; use ltbox_core::{i18n::tr, live, tr_args}; @@ -332,11 +332,11 @@ pub(crate) fn root_worker( let backup_dir = ltbox_core::app_paths::backup_dir_for(&format!("backup_{base_name}")); // Set inside the dump block from the dumped root image's // fingerprint; carried to Phase 5 to skip AVB + vbmeta. - let is_tb323fu; + let uses_efisp_gbl_route; // Whether the stock vbmeta ended up in the backup folder, so the // manifest can tell Unroot which partitions to restore. let vbmeta_backed_up; - // TB323FU only: when the dumped efisp is empty (stock, + // Efisp/GBL route: when the dumped efisp is empty (stock, // GBL-unprovisioned) we download the region GBL here and // flash it alongside the patched root target image at Phase 6. let mut root_efisp_efi: Option = None; @@ -396,12 +396,12 @@ pub(crate) fn root_worker( fingerprint = root_image_fingerprint )); } - is_tb323fu = fingerprint_token_match(&root_image_fingerprint, "TB323FU"); + uses_efisp_gbl_route = fingerprint_uses_efisp_gbl_route(&root_image_fingerprint); - // vbmeta is read only when the run rebuilds it: TB323FU takes + // vbmeta is read only when the run rebuilds it: efisp/GBL models take // the GBL route, and every other non-TB320FC model chains the // boot target, which leaves vbmeta byte-identical either way. - vbmeta_backed_up = rebuild_vbmeta && !is_tb323fu; + vbmeta_backed_up = rebuild_vbmeta && !uses_efisp_gbl_route; if vbmeta_backed_up { session .dump_partition( @@ -420,10 +420,10 @@ pub(crate) fn root_worker( })?; } - // TB323FU root needs provisioned efisp; once present, skip AVB + // Efisp/GBL root needs provisioned efisp; once present, skip AVB // footer and vbmeta writes. Keep the verified fingerprint so // an empty efisp can fetch the matching region GBL. - if is_tb323fu { + if uses_efisp_gbl_route { let efi_dir = ltbox_core::app_paths::work_dir_for("root_efisp"); root_efisp_efi = prepare_tb323fu_efisp( &mut session, @@ -515,7 +515,7 @@ pub(crate) fn root_worker( // keeps the two phases in lockstep automatically // if a future field gets added to the struct. let cfg = manager_cfg.clone(); - let artifacts = build_patched_artifacts(&cfg, is_tb323fu, &mut log) + let artifacts = build_patched_artifacts(&cfg, uses_efisp_gbl_route, &mut log) .map_err(|e| tr_args!("err_root_patch_failed", error = e))?; if manager_apk.is_none() { manager_apk = artifacts.manager_apk.clone(); @@ -695,10 +695,14 @@ mod tests { fn dumped_image_fingerprint_must_match_detected_model() { let tb320fc = "qti/TB320FC/TB320FC:15/build:user/release-keys"; let tb323fu = "qti/TB323FU/TB323FU:15/build:user/release-keys"; + let tb324zc = "qti/TB324ZC/TB324ZC:16/build:user/release-keys"; assert!(fingerprint_matches_detected_model(tb320fc, "TB320FC")); assert!(fingerprint_matches_detected_model(tb320fc, "LAVIETab9QHD1")); assert!(!fingerprint_matches_detected_model(tb323fu, "TB320FC")); + assert!(fingerprint_matches_detected_model(tb324zc, "TB324ZC")); + assert!(fingerprint_uses_efisp_gbl_route(tb324zc)); + assert!(!fingerprint_uses_efisp_gbl_route(tb320fc)); } #[test] From b1bc8f899a330d58d446170e3d1063c0c007fd26 Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:20:37 +0900 Subject: [PATCH 3/6] feat(flash): Store the TB324ZC country code in proinfo and persist A real dump shows TB324ZC has proinfo where the other Y700 models have oemowninfo. Field-only matching now covers proinfo, whose build strings a blind scan would rewrite. Co-authored-by: Claude (claude-opus-5) Co-authored-by: Codex (gpt-5.6-sol) --- crates/ltbox-gui/src/workers/flash/mod.rs | 60 ++++++++++++++++++----- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/crates/ltbox-gui/src/workers/flash/mod.rs b/crates/ltbox-gui/src/workers/flash/mod.rs index eb7dc3a6..eb80c768 100644 --- a/crates/ltbox-gui/src/workers/flash/mod.rs +++ b/crates/ltbox-gui/src/workers/flash/mod.rs @@ -9,6 +9,7 @@ use crate::{ fingerprint_token_match, is_rollback_protected_model, open_edl_session, read_device_rollback_index_via_edl, transition_to_edl, }; +use ltbox_core::model::{TB323FU_MODEL, TB324ZC_MODEL}; use ltbox_core::{live, tr_args}; fn require_firmware_loader( @@ -78,8 +79,14 @@ fn fixed_firmware_device_policy( /// model from an EDL-dumped vendor_boot when fastboot/ADB never ran. /// LAVIE Tab 9QHD1 is represented by TB320FC because the shared matcher treats /// its reported token as equivalent and the recovered value is internal only. -const SUPPORTED_MODELS: [&str; 6] = [ - "TB320FC", "TB321FU", "TB322FC", "TB323FU", "TB520FU", "TB710FU", +const SUPPORTED_MODELS: [&str; 7] = [ + "TB320FC", + "TB321FU", + "TB322FC", + TB323FU_MODEL, + TB324ZC_MODEL, + "TB520FU", + "TB710FU", ]; /// EDL-start device identity + rollback floor, read over the open EDL session. @@ -633,16 +640,24 @@ fn decompress_zst_file( result } -/// Country-code partitions to dump/patch/flash for a model. The TB320FC hardware -/// path and TB323FU keep the code ONLY in `oemowninfo` (LUN 0); every other model -/// keeps it in `devinfo` + `persist`. The model is matched against the +/// Country-code partitions to dump/patch/flash for a model. TB320FC and TB323FU +/// keep the code ONLY in `oemowninfo` (LUN 0); TB324ZC uses `proinfo` + `persist`; +/// every other model keeps it in `devinfo` + `persist`. The model is matched against the /// vendor_boot AVB fingerprint (works on an EDL-start flash) or the /// probe-reported model name. fn country_partitions_for( device_model: &str, firmware_fingerprint: Option<&str>, ) -> &'static [&'static str] { - let oemowninfo_sku = ["TB320FC", "TB323FU"].iter().any(|m| { + let tb324zc = firmware_fingerprint + .map(|fp| fingerprint_token_match(fp, TB324ZC_MODEL)) + .unwrap_or(false) + || fingerprint_token_match(device_model, TB324ZC_MODEL); + if tb324zc { + return &["proinfo", "persist"]; + } + + let oemowninfo_sku = ["TB320FC", TB323FU_MODEL].iter().any(|m| { firmware_fingerprint .map(|fp| fingerprint_token_match(fp, m)) .unwrap_or(false) @@ -655,9 +670,14 @@ fn country_partitions_for( } } +fn country_field_only(label: &str) -> bool { + matches!(label, "persist" | "proinfo") +} + /// Rewrite the device's country code in the model's country partitions over an -/// open EDL session: the TB320FC hardware path and TB323FU use `oemowninfo`; -/// every other model uses `devinfo` + `persist`. Best-effort per partition +/// open EDL session: TB320FC and TB323FU use `oemowninfo`; TB324ZC uses +/// `proinfo` + `persist`; every other model uses `devinfo` + `persist`. +/// Best-effort per partition /// (logs + continues on failure). Shared by `flash_worker`'s post-flash country /// phase and the standalone `change_country_worker`. #[allow(clippy::too_many_arguments)] @@ -746,7 +766,7 @@ fn run_country_change( let detected = match ltbox_patch::region::detect_country_code( &dump_path, KNOWN_CODES, - label == "persist", + country_field_only(label), ) { Ok(c) => c, Err(e) => { @@ -807,7 +827,7 @@ fn run_country_change( old_code, target_code, EU_CODES, - label == "persist", + country_field_only(label), ) { Ok(c) => changed |= c, Err(e) => { @@ -929,11 +949,17 @@ pub(crate) use simple::simple_flash_worker; #[cfg(test)] mod tests { use super::{ - FixedFirmwareDevicePolicy, ZSTD_FREE_SPACE_RESERVE_BYTES, fixed_firmware_device_policy, - require_firmware_loader, should_reboot_fastboot_to_system_after_pre_edl_abort, - stream_zstd_decoder, zstd_output_limit, + FixedFirmwareDevicePolicy, SUPPORTED_MODELS, ZSTD_FREE_SPACE_RESERVE_BYTES, + fixed_firmware_device_policy, require_firmware_loader, + should_reboot_fastboot_to_system_after_pre_edl_abort, stream_zstd_decoder, + zstd_output_limit, }; + #[test] + fn edl_fingerprint_recovery_recognizes_tb324zc() { + assert!(SUPPORTED_MODELS.contains(&"TB324ZC")); + } + #[test] fn country_partitions_select_by_model() { use super::country_partitions_for; @@ -944,6 +970,10 @@ mod tests { &["oemowninfo"][..] ); assert_eq!(country_partitions_for("TB323FU", None), &["oemowninfo"][..]); + assert_eq!( + country_partitions_for("TB324ZC", None), + &["proinfo", "persist"][..] + ); // Every other model uses devinfo + persist. assert_eq!( country_partitions_for("TB330FU", None), @@ -954,6 +984,10 @@ mod tests { country_partitions_for("", Some("Lenovo/TB323FU/TB323FU:14/build")), &["oemowninfo"][..] ); + assert_eq!( + country_partitions_for("", Some("Lenovo/TB324ZC/TB324ZC:16/build")), + &["proinfo", "persist"][..] + ); assert_eq!( country_partitions_for("", Some("qti/LAVIETab9QHD1/LAVIETab9QHD1:15/build_NEC")), &["oemowninfo"][..] From 846d9bc4d998db9ec7687a84e1a92e7e01dc58eb Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:29:30 +0900 Subject: [PATCH 4/6] feat(gui): Give TB324ZC its own dashboard portrait Co-authored-by: Claude (claude-opus-5) --- crates/ltbox-gui/assets/devices/tb324zc.png | Bin 0 -> 139312 bytes crates/ltbox-gui/src/widgets.rs | 14 ++++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 crates/ltbox-gui/assets/devices/tb324zc.png diff --git a/crates/ltbox-gui/assets/devices/tb324zc.png b/crates/ltbox-gui/assets/devices/tb324zc.png new file mode 100644 index 0000000000000000000000000000000000000000..9025159edb014b1840a385e3fe7c52764965e5e4 GIT binary patch literal 139312 zcmb5UQ*b5D7d09i6DJefndHQt*fuA&ZQJIFZ5tCiC$?>K!u$JfegFG@ANrxYx_5Q2 zy{cE&?iHyhFM*8k69Ehi3|UH2R2d8m{PDlW00;Bm2z!^%7#J7{n3SlHs>k|ekLPBI zh8opd^=IzQyHzP&Y6C!;S!D8uIJAi}luk3a?T`&kA?G@cp1-|UPb;=NtyjIR zuY=-m9E_VVIs}1sN-+LVVhJn>LXr@H3B~1=i@G~LAkUXh|L*rK@0y+!ffFC82ve>) z?9{hj*6zV=YmeooTqaPW>55|7~zdP{>!Jsq@&p~`U4<={t9OrBJsrDc^ z4KOg)8|ZrXuk!x|{>b5xE$qs4L^%Coe*bG?C-9cm)_sQP9FDRZYu~-6Hucd|RYkwD z<$c4?<$6w`uC89+*a!iJiz0y=8}^XO_J4PHaC51tsX4U24}pz?)6m`?q1WYRc(d)> z{y0BbZ@mKQ0{_ym_j}0Rxnn$=wQt`GqaQK$oB4bp?!8Xau^UMwmpG<3``;;dx(=I!Z7_P<|NVUaXZ1gf?q0sy zkF%`rR!0S{7w6}nHNKbad(L`LUtTy-UvPT&kU6_eOihorIJaLDZC|$BZ+!kgm_0-Z zM&k$v3q*ES-FEu|HTd4wW;)+h^4=Dw<2A$m29Y^+8+v=cPX6De)C##7f}j7(Pkgzt zu`#4X9KlFQy8hRux!}9j-|uk+zx&0(r>*O~?%CEOeEY7ev>s=3f&bx^=mq5SL~q-2 zyV$ zp#tVOK^OjOe-HvH-ck1-o&LSZQvdlUfbuPJ9?D9@w;^M(PTkbKD#cm&uA|4h^2>by z-qn8PCFt;E_#HIN$d-o-Ns{HD_b)X`mT(nM+X^4zVYv`up4fw2CDn(lp{>?k5xgxE~S`THH@%s$?NdquAwY0|TXT%@N`I%jzYy zi5_RUob%ZiZ1j0UOIvx5tA<4Br>gRfO=i^nHU^KxI9UKm;iYGmnLw@mZ=Q{*&n6^} zr^ey|TgUFBw@pTKeXTqbSbo)29Y+YqJQGk(O-u4KH#v0Zr*HEzn-boylrX^^RGZ66 zfb7z8Y1iJAxB)w316Za4pT3csACJwrz^KDv${&Oo53gp|3$aqY3KOZR0W(3&H&eDd zVeVR@C?O+$Xj;g2X@>Icqbx$rbwB8JH;lp9uKISa4cD6L>Y$Enx%+7WA}VEq8$uL` zChmv5ABY=u${>Ps!!w`ISixPpqK9Ua-sh%|_%n)E(oW9i65^9Tb+$dO1)hF=X6StU z<>fuUD4}P4rB!lsd7Z9e9X2-fbMZvcgAqe*1v%1OUd%)MC=KHxbf{%c_9CuwW&Ex; zQ>m3}1Aasr>ZTa*@yM{~2ec3_cjDKPQ9jUy@MR z^3FDcN8G3t-2fd!{&$=H9zu;4@y{S}U*{zNaTyF>1v_u3s*4#GOyoy;B8Y-a0or=@ z3f|xOg%&{?|@*$3PM1;4$ zNA!|MOc-RkOp}x$+V$zY%M)HFPN6I(YeZQ6L4Ja3YZ;ChG%y-AX30QOt?F4^@`2P6 zSSrZbHt--R*AqjKYN*++M!NjK0AxdnLF=>;qkeaa^ z`o*!pyJ^lAJZ8T7ISruLMn@_f``}QZGLGH;;%yMmDRMNODTLJykuER$Xc48;Zc9)w z2|QhwZlHHeW;*DrHmwd3z+j7V@)5_A)u$_}x&LW;JS_|JmZPsyYfV>0A7i7pJPX+q zf3N7{RRcsCa_F=L+KiWbweEZenePuEJ{zBa2v>WoVbe60Z%1!Fnd1lqV8C9l&H3PW zK4Yk}XlEuSetsSH5RdE)j>-X(!P?EJcguJm=Pclk!_A>y2h~JItMNLmTQ9_9p9hZ& zKBX3M*~iIExJH6k9H>=QN9vn;jOLV3FlJ-$&eS0wD|tk7UvH*q6q|nhwu|Yu>PeG6wBj912 z6pO^kit~B;^3*`K#4b@cORxc>jB-gr(|jG&q}| zO#QuI@^;+&cLGB_?J>fd8 zd)L#Wmtvz6A;Xl*yDTG{sAPa7OcJ2qdI&kEGV}B&>e%D7E>*4727xICr)h+UB=vxR zvpmS9GUo=w8E3pg2xcb?*r#<0yaztn*!|)C>+v~=CI-+cu;|4r?xsbVC5#i&5b9t_ zq)h0P^Ve#A-xQ4-*e~Bm%>NEA7VA~?5obuBwV{1XO_Bd}TWAuoT|!Mz=pywY3gJx|paF`!ThF&Xl+Fnn*8kSwrwD4(F=ZEc8=q^-Ui( zAnz`c=+^?%_$!j0Ru?Jv@G*Avw6KYu@nx@^`a0If9dXpitJ?J`RYylcW^M5@oXOIh zZ%EpqJ19kgHU+){6(PUvJ#xb4uhhB^Xt%5Nz`^kNOp4w0yHFiF4a#03A!(U_Z@c68 z@6X9u?rpBxBVtjQdl9wSju|@(D*~yex`BzVQq#5t91L4p6Eg{9oEVxEqe|O)p%$4LC1a=bvyCqkztz*WmGpmYH&`+K5n9EXLaC($BvXeSuM$wZ&;qQZRUk1QzQ?s zTBVmP<^Cx4n8eyu#d@E1+E<^-yq1zOlklJ={N&}>-X8hr?EnrR2Ir2C#NCCCT`y#n zMy=Rrp8q_KU57}DTLs)Ch{N13&FpmDX0AEBl7!7Le2My271syd+dBxK6(W)kwk`I^ z1bw3TW)H6oQLg9MGCSBd!Eb;wq*`OK>cJ<}S`TW!+Ug}ijC{HIYEkIl*!upXYodI$ z81}EmmrFNSLHFcI7FJjbHyDYrWtYEEgWsC{aVBcXMnV`ASd0Srr5S{SQ{9HyTCH%A zdojR7czO7cDk$1C6E?ITPHXUJXi(1vAn&gd=VdIn96cHA(C%7Gq3A>Sh@{X8L$JW( zdP_9bfW8hc#5EG4vVb@>hor5qOet$@wdAYOaSqiPR<1XxoFl#kPf)4h+~DzfFY|36 zs&98Ep_YgW1dH^{O~HA+zbLN@;Jk;bE@=`wj_-kDaQFB^LH(&zfMi=+w=@_Eq^rYZ z05A+Z{M1@Mwv%i$WJGQr$ZGNe3Ar!M2^)?gTmLCchr zyGV&xM->HXj4PGhrB>8OD6A}?&+ITY477&eY^cp$wMSSyZrtACMFOQfxX?+3#4O${ zv6vqz30tW`ucA&G8PlmK&e2>6sg*8IR|c0+dfJ&7i8|lo4JOy*I@^_En6+g%6UA*u z>8;Rn*rWKvv?ihwp0t*_fl5p&0yNL_rUlorpo%N@T$=3%}$W zOZUgrx4?{%2NukgvQ<4@HWE%QhQ?ADa}vXjR?b4Z2x8uBxW^1USsY)v0?8q+k({Nq zs#Xs->)z3MyZ{S|8CDty4+&_Bu!ARZ#T$=Al2912VxPr=$k5xH=bnj%>{clJ%1heE z%rAd-al-SGBPq&hO$#0smS)rc>~VaXKn&$vGZM?R!KW=2_4~aJ$<)7`L`n$Im4LsZ zO$i-tI{6|B0V6d%5s-ltl^^r$sFt8_+~&m~o=~qi8>&*WSpyUQCqM#yH{qt;QrtLQ z?1f}y8(!BSKH*g?u0pwI|xxQJvk?^jOBUZ-VqKUMkk zGIT1d>^-XI!#Z+b^Oj1bEDynh>v(N&B2!i)E0Qq{bIHo5Lwfbg>NXv(S#}4JK&Ypn z9`P3%IHG?Pb58(cjBQ71de zSUI}P$1Uni8X<+G*9aY<7q3@-xCTa`S0%@_%+AetEtC|PV!4}D+PB2;V!VA-Aaq(aizCG+-W z{iIjCfnuE331=s*Ts)~>u?YmVw=o0l_?elm*&k8}EltbWOgUHlMhd%vs%QhW2Te9) zIsB{=r!vmNO0CT3qk^95#ZLBJGc~t^ma+*Ca)u8U)O*|3&pF*s-K@9@)NIqv%=kzR z+nUI`K(YvblS}9=i*3Y78BX@likZhVmkWI>hW&(Av$VdMGSH?&`lFRS#Y$F zo3`dT&$7mw{faYp#Inh;AjM63lr^{x*)5IK=PYpdj4J->7qS&Uo?%p!iAVquLd($) z>A3jn=h2%bGZV|ESOx+txOqI2IMeY&YgNTb5UpB6V-e$YH0oZv^Q!Rq#xX27@4i28NB2r~I>w-p3`;%#=iurPEDJ20U;0Gtrx$z7hZ= zG*B@SWxTGnEv@n+WTis)O_A%ef76@rXgkV0rR_BTBHLcYCHG?;t zi^s<4B88uM?`c{*JI6t|w5U=A1U3#>fHicq=AVwSTG>t@ve?P;{<{&2clo>au<{$A$E=VbYG%Z@##i)O0 zcE`3ep>qm@_hd$CfpE*Q*)(w}SqtUka*LCZN^r5y9hio?q~dkE$d<&9?*Cm9vJv3T zk@B`E!8V?`7HXSTQ8TB!+eq_aKi3TYTzMbAcCF7q|r>Ok^NWIxVU6CYuSJphXxl^7FoPX z^U-l$o`2bw{+5{pm4}h~$y#S<2Tiwy59rPR>e+7|96FW1A=39|>O=(0M{ung*EID| zS*qo@!(qp_`b#BLt@;|uJUZ;qTbMD^izZXmcc;MJ>EFC8%65~+wZ8BYkQ91cuF+8e zLnyH*_{RDviC1Z=If~hSUk%E=3PNh)=T*tCDVL2*HAL)8emri^DGTc=Kvm;Qh7+_6 z5`BS`^BLPqfRrF>sp=P5&rtNX4~ua<5`9R!3e{wF=T18Zd>w;js*L81Aw;%SD8Qjn zmwtuwt~$;bQ9f*n%CawMCC#M66WOrf_~to{%E3ZSzl5_6)K zk9fN?GrS`uIJ-s_Cl%-MS_`n2+$M)TBL#58>pCp^q`U%k#7Wy-v^=&59LJu?qzU8+ ze|n)Nn!_|hFDI8Jz%1p${bCTbMdX#uep#wv}mYQfV)B+*1{gWB0+ zLO4C!*nK2k^F?mHIlsn${M#sAr5>X;+8b6T-Bub zSUrNeY6n>1ynH8)*0P&k@5H?j*^useg)<;Yyn=*WGBGhru!JkQJfy2~+%!-ZNh2E4f0a zTV;y+glAP_T6N;74_8z`I5a$|Ig@i5o{af?OKu0#LG;N%6nl}FKRPcEx}Skg-c&uK z@*_4TW2AEgRa&(*SC_hn{m6O3Tr<-K3)`eGe}d_A+=If+Oc0&T9Z7efGD>nfu>^G3 zd2!q8V6~2>kXfpm$9h^SCB8yUh!7G|rg0=$prLxW)?~wvwX1T4 z0>3S<07J9=1eynhT?~uVInK4{ZD9PUm4%P`essw&AiCyeTOw1g$$Cv6!s;d zBE*&(N49pvJvEdQ%eMd?L3z#9(bot=Zgpskqd0_J4fHz*DaBf5air3T$P_OusBwx} zfAUev`Y8Z3{s`3pfh}c`t!H`3E%dkbjwH1NotMH6-xSaIg-2mrh!?&{rzB9ZcR{2Xvo|~;yk^Mk?2X^Pu$Tr9 z=S}zGee}43FbR*a1x1;XvaifqAx1=?WIosUOlN`|wZ;*$$^nH9STg2B$@hMDNfYrV zIW>=yoPl`nbYy{$P2T|@srhvDuSm)A$4fCqtPau;Bjw~nT~Y9C_*TT@7CAV6i_W!Q z0F&J6J|R`kfvE+J9>Ul98l_*&xUURLe*C=evy7!){5?618RuGD{Hv$YM61yeV+88` zSj?Sf#T^++axnci!t}^mEguG$W7zAo=AyXM=0DE+cfKH0rB+bs* z85-y|-G-rJ%bSEJ^I{J14s~w#eepC9K|z|lT~f}&>^Ggfpfy#_3s~NUf1qG z)0r1fc3122Rn^ss9E-_GG*U<>*cEOILOms9Xb&{9&PV`}EMyh>UB zfEP+^Rk7N=Js;eW$fC1FWX^Kl06N%|6}vU_6Dlv?_v#rJQY$bkH!%~MVT~~UCbmie z7F*~ux}~RkZ9A<}5*EVge}G%^L}cq7+0wma!J=-{82H11Ar8=?gjVfBu4w9C&i;3? zUSX!9z{vL@C@!r5xVT_1^t=R*aqR_QdkB%?tuhIvfOq0vvL-6S+Le6EJPW%+3cmY4 zYIhW`3%>%>^KBZiVsFHHL?9i3%{XoO2`ez2T%RZgp8o*U^&mtaXU$eLivoMi%@d)kT__#>f$O% z%cftUR+^5S=$i!xRCVL-JI?mbm>ZOh69pZLRKhfTcI z8*lE{_8NTSN|`&TwIFSE+7+EwqQF{f$hMADT81&M^CLS|r7@DLT}r^C!~!^0ocw?L zc|J$jV(;s&Q5kY^ISVH>6@nj1OFt??f#EHZi&4wsrj|(*Vv-0kJ$JBjq+>X@J$=&V zn0@y!02Ro9+$pQSp0t8Vuvt=DhUAArn{T68nzDpQBoJ!S@nWJwNUw^$Rx^Roc$N(a z-m5AtB}x;T-u;-;^EC`>Lv)mzwIL7x^8z>ytMcGP==%Edv?y^asggJ{(RR7?2Y7;; zPCCVrzGk8=Hm>Ci8SIc!GbsL$qDg%f(sm64^Q4PV0(-`#BgFI+_&Q-l{B*rpmTG)i^Yw(HJvBm`WJdSru$GJ1G^4=M zsmN)0PZ)2A-T~9P)7$Pr`inm@AR}rw|Iq}q$s>0@Smx3Yo|`4rE#e*&Ny`Xkg3Fq# zN|d;-X43aU*O5!$0H|Izk9d{~m{ErLSX&7fD8ZCV4edU1>9JUv$OG;*M^5-LV|6G~ zI;=v>6&0e{b1F&VrZrv6FM!&;oMR)>sW@ISqyOU9Tux~y3K(YuACS^fNYYLc@>LvD zNj?d{;0>w_!O2XJJLayM*Fi*Ymp?JApKj_>ZO|9!uzbfd>OB-=C?IiN0|er-&ih?Q zDVMl0R(3SV(10$*&AGo<4of0_%cz`48wtk&8;6tbs32G^Aa_zFMI(k744fi5JSFis zy-nK>1mNQOl=2qJP>?by-in=ZNStxLc`JVNfDfuT?WeqOCp%nk5#Ea%WU0$~h2@&u zUa&^y>b~2z_6)6kwp6VwgrQ?)d5a^GrTq92APpO=I9hEsSb{(apHkVZsvPHN?L~%7 zQ1R)KHmDJ~z@F4XNK+3N;U$36B#P!8bZ*jYdOb_5oZwB*j*=Cpa3Xk6BTqt}N-N8Q z!wny0#-+kRpzW#&IrD?X)-g3naj6Jl{`c5eoKXx7Ep>zqmlO}5*E8GY9vWZ8Vqv{ur5vLJ3(_haZ%t-V#fCR#TrMpFmBxaR)1W2jQD7 zv{42T>%*6S^pp{RfsKmZiLo-Mc2y=rWCcjM*TfnB%w3gdG&IA4aXUKumz7|sI`6B( zA$?Njb%!vy7inQ=w-tr;%vwNrkrW!0%7@DROR9l9+U*L0K54sA7|T(QDxYe-ueFa6 zlPCRE!8EHBWYokyrb4@ah>fa4DaLf#2-{53m~6cmTY(=B)*aBzVp3)YbLX)pt)S`Y zhfRrI7m*B=ZV@?v33w_(>}2szg6>WC;v(JY_-?3Wa>M~vhFJfxtjSKOND4oa!90_I z{>UUzT73pPs(`I(vVjyOX-F-2LK&OR&=q~nVhSY1>pn`0- zRs?niY^nhgn6WnpHINyqd@eAU%P=;VDU*B?YAmsAb(~+~Mfh8wqij_$*T9R|dsJ_< zGCqAdWXFk4K{Tva1xh{*j5d`cV5*M`TKaQsC?*DIa9cLwFVuqwr=+z`4hTy%jSBYV z?sv1&1>Zr|?^Nx(hW7*_ml~4qV(brgP*%9U)mx}AHoBW21lDKcFp~3)AIcHP*2G?8 zfAFjM6R)7ldgiLOy7Zdo2u$Ia3!E=*LD5r;Gv&Uf-;iAk) zIW`HkFYzfrnsFep60%Y`p_07Unydh&1W)n~V7c7Cp}D;F6+Lp=bcAWh=W%`F&I$K; z*88<^kgG0}=`S-HdrDE8BP8v2rHJc7LcTj0k>ap6u^@5&KhZGF*TYPFd|a=E>0?$ldj_df(~# zy4=fspCuBc6Y%xJt}t>cDkqvVM|7WFTwB^8%^2k)lGopJ7nL?D2EKUt4^JL2i2qlS z#`xJ;21nj?SWdU5AIJ&6M?Py3q(Msvq71TZ8EZt>&-wi!a0E#Y8^>t##Nwb10 z3!_Dvoa2d*h75xVcC3uI|D>zu@&Fyfpl7OVaG}nd3CETYqGdfi+*RmAN0w`z>X53* zW~{fE#_0X*W)$Wa;&QwHit(k3U`T%BVQl3$=gqf}6He@L^UjH`(EF#+h?L5eM{TQU zS3O=ke3on}IxrOnLW|aC8!uc2D^MB7FvVb~snnoz<{G?x@@x9W=1vDJHjTT3Wa}qs z0ZV!m5S8j&skASdts-Q`+;gNmP?5^%2}IKD_opAh#?BUG&D*dg6xp+(pm#BxoBqJ) zmpu{Ko4yj9JXo>;4ST^r|JT9zQOa~+H2F&o{1FoN8!bV`5#D39G*R`)?6dql$J;K^OYbX+)4&tVPrr47+sxacBY}CWHw)A{#@*b0y6On&6 z_ANN9yc5q7<}<|3#_PKh3)0?YM9WR|I#Tb?g-D%*X)+c4VW!clI1|qyDI0n^LfF7l zp^sI1&8j@*xH$K&QU*_S@uEWp#h&fU0QOpI>J<*n;>G8?al)!Iv9GP-hs#VKbqjcW z9bmCx+MWh~-RoQ&Fz+9F8GiF0UhYQR2Bqr<=Y6;BAcA=;xa(_gR_wfwS>IlK?-#w! zdS4^C3jIns7&uj48<7yw=M)e@H37Pfp3x>*%FA_ zX7!cG40RB_QzosoiO4T1fCMAU+h+xtgbc!|R4R=5x#eVUAhqaX(+DD|7AnAal6thz zXuDQiDWRF81Z=4~>}0rl&2TD`Je}QoBTv(Vh-&FvKxPv3&0Pp75}mF<>*usmusVJ? zflnW6JKcx-4u^mLE;E~4uh-XLJ7gZLkx()?)Krv*EQquvNLd*u zSJ%$KwwqmKOb-SVi>H_CG+vi|?iusc%Z>$OtozM9@kj3Nq1~z4vHvi5N$~+?m_c0YwDs3nUSN1*3lzF5i%voOc=d z;=3A^zwJG^UK9Sk?92ts!Yr)84Ctf}^Ss)T$e|w5w{2htt0!^zf4_>A=t0ruV6NJ1eNqt*ZBT(bNX?YA{lP&C%kZw!ZZ)I@`#qG3nZ$M?i5x*jCYQ^y{z z4uG?r%UnpCi6EZkr5;p$8Wh8mNeCJDv|?uc?6Rr#$bw00u2{RYYEcMeV6>%ZoWrcm z0p_W7=M`>N5^M_51}Ls2uE9YUIrDW-nU;&AM@XI9|Ljz#0!6m!r4zV)#EHwwEHIjH z?Z`Py$h`>s3?b+abVfmeL@Ez-M*hi=@0cU=Cm$x(dbeCiBqS#~dbP{v5&k`r$9~imsDDSP{!Irw*{)AFqm@9LUoXm^{kqczOF%K4*34Z5?iCgZY*h z0^BZ!1(LDtcC%0n@rIwzJ+uA9G5xLx+BrH+o7uD8US!J$Nf>byg;Cd`#n$1L0d|25 zCj?&YQ8VBas9ym$Y5`%hGh_6!mL)ly*IcU0Ero)0USSr4WgQzGhYd=&CNOH-V1A$i zkcBN}WkuL~##tU-1-&M%TOyz2Y5lDrV{KZ$Ga@6oh-(!-5P99bd^|i6AX4 zZPv!V-uH#9^~PcKt6YrldM|vn#SJbOidKTna5`D#28?tAUI}!r z-u}7S!VLfeW`Lnl)g$^zy2R`)Vn&qf#cj#-1hiw@wLsTUn){4^iTw_^!~UZ{ zai&V6OINwZ)F9qYI5|28+J&Qtq@T%z)<<=!55E@d3O`hk%=j&V0rcZP)uyd$Ok*4A z@FLCsM1yHgGoRj2V*uEUuV<+Tj*|Fg*Z3$)r51*V_A^U90MP>VLQux65J&LD5-J;P zWSjbuVe;y>dHPFb@N5ZA2ko*}*!82EnEe>00DKs74S{ho74XJ!3yMVocA&Z>E8S7N z10fJ&31Cj_?UFeBrhTpYltiDNJ0yqBn>KzV1v1*BkK%_5uzFWeU~C zY?z`E{kXq+cYpHX!BSl}>3IkE;y?^Ov2bv5Hu$+<;KTASb80sq?80PI+Boyx#{2sa z_a5-h^t*qal05@A44!BXwrA}3FaF>j>}qh{#s*JnZmbT4{TYR^H(IDO-i%{DX6Yt2 zj!}B`j=@IOCJNld9V(K)$r~j-D6QSzmKma3J0cOq=o0mE!=rahR+T{I(ij`!aclau zXEkA}3Lta>Nm8A^=XY(U6dAUJ-RqqroZiW3S^W86jG~Y z!}zk}bacR@X$jy$KHb%&d_$zoz07*<^BmBiRCRkC?YaKJW_D{1YK)Bp9a(I5h~&*x zq+^j+xrweZ=xNmf5NQJ{VtSz)v!!r1=yZZ6r14oQ4_nR^q{SGzK&>rV3bi5ZH9rdA z_{e^!z=UH&##J-9DG5TMjivK5rZg-+_^BhXPxviTo3r;rm6g3;E~+9U{O+BNq)rSq z&s#``plPj#9-YP{eQ^Qt7uW`bbs}~5lVNB5Cpa7RHCjU*-fnxeJHGI_w|XZBg);8@ zz25S>pkD-|#Jx|GTs}LN9;jeMysfAXyNx~V_q?Fd>j!Kw&XN86{(4)-e=S|50y{0S z$ko+#MuyCNz5E*v{c)5Gj7)tkkj(LWBT#KzeThZJA9G!HgRtAazn<+jLJ?6 z0`A63hSo7%(JNCZ6YRrDOXRm)Hn_)y9k===8Mef|Eu(PqWu?8YXUn*qd5cU`HY%q4 zxTC+Dm9uLRgY0^$X^xbSF|FdFsC^^gtWuWN9aczar0x;f9Po zQ92>3*%T{LLK2om&`1^mfjR?)8)3ttwyQnu7z*C&lpe<~e`2=Y({9^135VWyd|Bf* zyW*Bo<&ZW=LHzCk)c!O7+IRcxnhzcKhY;cj`Gd3V{-TZwx*?dSt<1I>dq})e^XA5m z3O>w7zF)3ZsI*^!>JS*)97!5G^H-6 zqIn%bMQ;0jN4yS8?o7LQb!&k)8-I}{{+`~o5%Zw_`FI4#=W6w5x%>5~f?O5(cs;B{evfpzvMjFia&$vN!}xN_r@A^y@nGUzVhH&I$_zz) zy?^>R%qv1kRcz{yl_VL|t7HW;1(E|UVV%!1uplTep0qa9Vvmfb?MU#NrE>yf*ndHr z7BB46LieCAqrANrA6e8i2UBT&=wbv6>od+F>Y35BoE?3gXyzBJ19=m>v1}rn6k(sM zsfKA&>52do83NzkAxl4G0#1aK?GH?DgN zddfeWbhR(2AmXWp5os^b{Mcsx9Sn`M34v`157~w+6Kw18cyzMY@v9qY=WF$|{qwl! zwdec4n*G77RLnZE&Cb&92C*{{imsnP>y4$u4nOtXox*lh(Wt!PVjM5*lx^9>h#toz z?qKjO^-V9@iEg`rVwB3r%eLSveRW&e(}OAhthuaA{v1z4TElO`r24ok-1h640S8`` zTHC>^@V0|G!6ryvKW|PZ?t1)qZ;(FU_3*~sWnM4XpYKEN_NNhKpQmSbf?m8w9DjCV9r+(=E1S%TT_&N(GnLI7WuBtOjYZQrnGu1m>DZaA~;6^ zQ@K58&r@&?Ql^Ul@c9)`osHNEP7pt>`5_S@o5L6L^?6tDgw_93AI7GHz^9(s{!D%9 zDS7gc7(6&v=WzWQ-B1@Rff2UUX1e;0pb@R5H5*)Qq^^V=1#|+OB1~(zq|7;$QawAd z9*X=IX){?%eD1>_>FQFhv*B#tKLX2%(UrrGUVmN359tgs$dTVf(HN5hptQIYkT2a| zwxzZ%$R0q~+<<8>H=}NH%Cs)rNNFu*w4834Vq6^3M=CWja(uz&WF<%mNVfl@rbcsD zeV~3Oz9Y-@gAT!4+yBI~zf9nsz5Bv8Z|K+}L~jG1?}|I!XeAfMd|BObWBSjign%cU zu^^NZqLKI{VG(eUc;_Xt$UKepy4M`lkBIB$U&OJ_e$%5%**9)?#@Ou zeeG&EwZOO1>vrBoBu+E0T(8otmyPB4Diiz5hbvkx5Cso-~CUwbeylF>uM%q{y zT{fIgWQ$j4O-(fL?Y1CI@RZvR$ z5~}e+O;FJW`t}Eu!l@(XK-jFpNCRtPys^=vDG=Uh@2#=MqVznbK8ekx)qO^`(X zX-5h_9n$ei!f)hYmk9ptg%1_x6&z}YwgJO?w|Sx;d&2iU*Z#Epe!IN$ib&A&jk((P z3cI2oVNL7~AD71ytFZkDO~B&@l4Vda2375{4WY z%PtFCHm)ONAq+C=Zav%yulU#cDHo{yipy)1Xwz>+|MIiPxBWRXe!#ugf>Zzf9`Uy2 z?{=_4w>k8Sk1t*shk~)G3&O<}U6>y@h#mI6R0c z|BLI3;#AncF2C4JN@OUGR%)2eA~My)srH9#W;w))bfXQ1CwFVsxPgFqo<`Nt7;HE5 z<+eRCp0iS6Q&`*>0+*JlIXTyiUW06LIZSEtQJ?8KfZJq@()}S|Xy_+0x~^xKksTS9 z=Er7%{gJ^WyhF`0!x2r*P6||ooniz%UdG}J-@D0XBzf*tIZuv00 zo(TnacnhI5S8tjDG_s}$^a>rP@4bE>Nh{h>iuDaZ@P3!W&+Qh#D!C{FeV!+^nf zZ2tT#R-j0(FS%6LCxPX<$q#SA*Ai=fXS)D!WS-?W1GE{h?Y0BnJU?iG zueo0b8h&Rzs|4}PBqQt^xxtX>S0mGZJ^%urwKHzMo4EbXh&LMvf$wn@(*oPFH~_Je zfQJ`ga4>b8TL}G*b*VebO~xP8U@Mo*Li5OXw-7_#5aaNs)<*!CL^4$iJViVV2$ z(quhXlzbMj5!^wNXKd}8*@ma^Zln`z77GOvme=er>x6#@Q1LPrR~mtiyv~d9h3{j+*};n80Ty@16hm z#7SRngRf(NJ+A{wR{xK@j*ExYZd>xcF8-A50b_=+ESF#_x0f~6c$WRvY;XaXYi>_w zGAw-t_^|lu3s9sp=J07**VEhn9HV1Zt}bWHe++HE$L%Ey{D4``thY6U?L)@iB-6HI zc{XOo7~u;TgaGaYIA5$5n^wOkJ6yQ|i^;j(QhVAzHD>yc?04eLdk*8VL$+Nb2zPv)zQ>=>GpN+Q)G&7d5kC}Q>Rz8tWG)}^;ny>7DsmKS+(f& zgusTH1ssRp(}5DPgD`ZXxufITZZl6CaEt*ts^7=(z=RUIG7mMcCacc8N~DayiIUr1 zV@DToemKN^iF`FQh2%FM!pZC0{PTQbn!%b+5v>6lLQIl-JsrV^G173&n$~Pf9$tAd z^8*x<`=nN>OQ{RF0!ezn>LsD|Tw_(sEL?@>SP@^7e+%aCRhek@mRJZ-bV5jzlXIZR zZN#v3#l*XkmnBre^ZPX}jZA-v9S+K z-rIdT@5wmQvmprrEWFw|g>q(Kzi{xJ2hwxMQEY04<=fcfa-dw+-PTfnCVPKHUTqoh z=Zj_v?lea6G=Ix~O0?*^B4G^%Cql8rq0{;;npg0D|`}}vW{22=?yBxWA4UkK7UhS@McL? z8lBc!DF!?naR`OIpDZr(v60UAM{I-kmQwuDi*Q|v0q%G)4=JJ&*iY1wtx+lY1UOYC z;Em@SP}v~qZfS+>A|5npicFuh%8oo&lr5=cfD-oAI8B9Wj1on;(H?|bygRcBI~Ln; zemE7MA+Y+wZ-UXSq|SWg|CJvI?*407>RSSp~YBC!sP_L=`-stend z@C#VLY|}%B-vHfk^2CiUjE6@r48=`RW-~nF9K=gX&}q^jaZgrqWnbHseEovMHaT-_WjS}xdDX2Zei z%Eg=kD8g&Elx4WX>!W^z9+vSsy~&+xL6g0hJY$*GiJ_*1dVZ+ot%QvorP&a(4>d}f z2+PkBfNi|v`(65{Kh6xN+kUSD{y?6PfYZVw)Cf5)A4(KU8s%q54Uy1E%qe@I)Ee#X)T0w`}rMzW4I-x4Ira85C% z02&m|ri0mLwybI`o=K9X=j7BZisEIpmg@fx0CGT$zdTP$v?}3GI$sw9k%XnVq%;@4 z-^B#Ti?V4#+9XO_kYFcp7n0L4hSMlM5(h$@jEy_~)!d=a>JUlv7*fvmq=|D{sLIl= zf-`y;5Q&<*^Ks-RO^Z9p0;>s@Ttan>2$h2fv4tR_WNT8^jGtyX$0wgRIFKA>JJ z>-FUsq&Q3~b6ZG$@jYT*v;&2HT&~o#q`G>7G3|vQvU3)&G9hN(2}(jJA={o`!sAL)y>lrWhW(PzQHuFifn=_7BR3@Ig zTQRmYOfd`NV%pwWahLV3`sMBwet?B$5v>O}h{$*zqoqxZX&pmez$UF=lb5k}=nU@v zwd1(v>I3+}H|)b>Uw9e*{LOoC`a}eNIjEYs>h|NXgW{`AKQO331zkDBwQQ`E1Bp-3`;p3V(hDK0i_Jp z$}~C1DnIl-$>{iw?0DVZPBWB;V~;%)&9C&hxcOke|bB8`dj$X=mx)S!VpqokA^)zS5wv*|z5zaN$ z3w41SbwjF)dAmFV$_P3DO$=>qAgTKtFG^^X5eX^F_+c_})m$l=MG!R6hw_={l-n0! zD^l;bhus;cUf(myjk`)FoL}BElIP1MQ&uXwNrXs|1LLGK@qg4ww-ODoYu5r^`0Q)( z>CfMU8$WRvOieKAtGNI4D!lWdMBYNO6m~9d$AVwNnekdz7azB(C9#8p$KkPuair|U zv>FPkX%eXrqBeohwr6oap8nYHzz076F*xs{dLCGQQ_x$NfhUVuXPnw8dn$+T)!KY$ z;UX7^d%Z%Rho>>deiM!t;CKlREj*3UPy?b795rZZgw}7O_3PLit>Dznr}5<*&cpNn z(M9;Ne|IiE^M^a|kv|^b$m#&6MyEhy!pMc;HXLTLM;=^1-HpPvbnC~5NpHO-0aHf9 z3{bkN+Qy!95-DD?Ot*QBntCpa?j6eF&|~Csp#C2&~e(edyEg$%L-LKQd*Y73xPt zXAaDfu|^sw5WNK8%pvy~6V0sdDGafcRR(f+xb|7)kJzfS*K%IY6IDv}rPv-neN1V- zN$cOp6QyoJQihUMy|;vlsBBHkTEz091|)GMv(7JZESJPC^35W%MXRMJ-;8;iniA}= z(tA0Q6j}y5gXrTLGR0&lQzuNLP37>H==^)~8xyYk2Nz-AIgEGy$$Q{=0FXoLm$5NA z3GaPph8uE7|DlN+bQRIt7cjzTYOnCBfd&B?ov9cCrdxIDUZbu{SM_uPat z?y_US`g{YpL1?S@K#*TeL7}A)D8jHfF4e`-Eyrw&qgo(`?8>8s!x)4H z4KJdhMQr*_G&F#tQE1H@VUyOeK0Jxl_6UCe_fO!q&paA0`-SuHnkQd|_x}10eEHB4 zPH&#T+GrVL?=Wh+63CeQ@A07y?gbsQ33<8`tH@`@-<6eWDv_%~r>AdiRaHGM>;cER zHx)YYvVUBT{!#tWq}`xy5#uyg_B8>k$cf-Wq!xD|}(J?iqPoghj$8KEx| zz+%y3uSm{?>ZVhl!)0!5GT$XwM_fzFMC&U-*d)E%Qbl}#l$>i_r(I3* zn&nyW^fNT({-GGsNdQ;CcnRHc0j)s~XCW#wRLP2uO!ywIQYwf!vt0_Z_~L#SR5MPS zi$(9boLEM^(Q;zkF#8I3A@3%LAh`H$hgvA0ww!6;T$zo_(hcjjwfNn=lXNK{B5I;T zcjT}*aCqVOT!Wi#xfOqP)1j`0-T>>HCopPPVqKAgf`~YS{JvhF)0(NpPyBF$U z0rKwQUUosTtalQFOn%k{W_4HJ-@UXKk6PS=)piwUHdZ?D*bi~~#2GyG;_EPQ1Ke@{ zH}JH}ufn~jPveSn4`5|@5?{UltGMU%y+|!x$XLo8GsR+qa0|F>Kq*sz?fc&EHedl= zTVCroKp23*Xt*15>c@=Mjo{rTyx+ulG{UW4*}(ljcNt#rii_}*|M5b6=*>&`+}~`& zQ5?nUXc?fDKr9Sua_qaBIB{%J^~_;RZKu6{9(O)PwUWYx%t(7A=7p%$0Rq z^h05|s6BDaZkZ+Gr5#(Ie^W6^)XvlG4t8jf8OrCW=V+HCUpi&DG-Z{Io|alt0$YV$ zWLuPl5lK|X%BIU#Q#SoBjhNMEMJ$BCrS1lo+<2Z?x}7`pN>WXx!Dh-e*|lRJP$!T< z_HYy8nz*Yp@T|_EECJNhk!9wO-LF3Hw`ltv}Y>q(|3K`SQv<7`XIgPX6&WW(!nd^+y-I1+nF81cS zpd8k>rS0Fl1JC@fEAYM#{3TX4hiF`b)^A{a{UlmH0tDNakOCS{!2N4y;F<;T+`8?1V;s--Z=nnbZ z;QeTj!;zHYyBw9J7?i6^x#h2#>q&1yR0%DRs(X9KvN%BcA0cv!EWGu3(t&( z+HP)okh1l>iShC(-uJFm-1ntR@xwpA4;Np(4Ig~h4jf)Rh||M<);X&k-S!-IZUYaa z3!D-W(1rSOzn;4qc?ZfQgd)|~Wr>LeDwQV?Y@>DT1p1X}FT`8RX6aB1(&P|!=DZ0B zIwu5lNbWuX^ppG@r&5drq1jGq*bE=aK`d77zwQ!~fR;7$EtZJLxXAG6f#7HXpaB{*Xt;x%+wnLkulWcGGkY+#!6UFZx1LMT>+T50E_#Mom4NzIxHk5* zM~wqY?Rmb}$|v8k;<4C`P;JNXG(_93W4N}CPkibO?)_&M<0pRk68zY|xCrn4jREdC z*5KsWgLxHTFE{~h)EMY%=e*pb4?N&)lD3ci#Eb3lpDph2CQRm5NJ4!Nzx#+D* zz3Z}^QHr&Y;IptMi4<`FRa?O_lmST=wI`0T=>Eucpk<)Ws#;ATEi0Px=MH^lm+oZUT#>I}Xe)9R(k7$sC3RCt zH7?R*r$0kzATvo;>{+?Vc=nQms9Q0Su1OQs+g!zdC%Lfu&oL*SS=m885ZD+!IOUFL zZ8nP;>XO6Y#%xUR1yYbZb|-L#CWG`PAA)o^L824Acj!z}-jza6^D~}uB@Q0F8-I4= z*MWvG_N&+&9t-MaB#@;3JQzL%107Sh3H{+C(OxtN%c9HFfyEBqM>jLQcZ{tcf_W3n zqqKH-5Zmnrei4KL23P=yF%I7c8YHRGa4XuteSjNuC=z=RjZ-f)kHf3R0rGD_XuEPi zAba&~dyWRC`Rhe-`ZeFf?WwAbP~Yb;>AV533Bm$AGuXFa*P?AlX#Ei04bk!j){m^< zKmFn|UVi;!@TySR+xTvtqMM#;Qo4&@`@4=8E$aOnlDvnG@$> zjc|%AJpR;-a z1p_!Adzl2q#27=SDJ5~rhS%r7vIR2L*rYlFlfU*#h zLW^0?WG6iD=~v=2x7>t-M^D2yz-V+Fqw#7wXE1gxY{%+w9e@iJ<3VtEsXpEb$TT8T z?O5RlF1iR;U3&#~?cN#At-+y#$8pD(?!>7x$H6TJhYvVff}=$=ZV3)M;4lC?z|$Bb z@`$vB*nZ^_*viT2Fo(YMFk~bp+?_ZMVOu~2!nrboFal!}jA4+a?HKHY0VuTZMc1Ti zuYJVnqi_(z0XfVoABF~)uaqciJx z`+wZTi+P^tkFG|xo%;kgc2gkn0u1@;aCshirdY}x`qKz8ZlI66+B!0 zd3qJzsDrCJ&cX)d3VJ$JAfrM~@q8T$Rd}h4#}i0abB7Lt;E-oidV+Z|hl>-`E!psW zpQSalgeGL;WITA7|3)Tg0#&o6!rgbyB=K%hOm~ZlU$Mw8CxK-SGQilRf*Lssm_MGGYlNZ)k+AjT zr(TQaJnyM^(Tksr-Me>WP9QypZydZIpZ)X~@wT_T4~Gw~foLIIekXP8386=RDNUCO z;|W*@qev!4PY_GG7#@y**S`LR_^H=_|BO48ap>SNyyW|S5low4KLXK0Qd?sy1a^4h zQ?AAjy!aV-*7shQU3Zx`-gU7IP(CJ2!ZHAp$DBv84iwj<)ci-^u|QIv%R9%fel+WF6`H+DNjPK779Tq(KAlY zkSqA4p`R|Ls-^SH73?RWfj!Bmf7TRL-bnD5Sd8M9oE#luBwJa|cAq=+sa{=Xw-o(j zgioZRm{NGK5^$Os9qC8z`NDA;+1K!t9F(WvXU^Cm((PhLVANH z$H^Fissk5L&U9vpj8yaiD%x>{i6GL7SO$BaMb@De>dM-=dJjWX#$9?=efgl5ZTVYMQY-`rbnxqdYr=c`*0F9rIk*XL^SJt&EAVr_@Dq5_ zQ?E^7YL$URxcK4=aq&wp!i!(}y?Fn7KZUow<%2kM=yX@xrX*?GW!6nc+7g4~IT&pg zhK%|)I_e!z-_SOwWKgyIs6m6>0JeiM3<5R7P75J0+#Pjld#}Czhw$>BctPjHsft1? zyy(iSFT#~qAHWa)_%ra~_k98H`pYdCds1+V!xSE2p)EBNTA zmNE2eaOA?|Qxa3kyKV&z#6M2~br2*q-`A2kn@6BtL!tq$)L(CMQ%`!o^vl^(KG%za zc08+aL-cqhc00*(A(Xa5j+8O1>0-jIauS+~fgjfgq)4=Gmch!3rB9WFC_gt@PT*2} znr|XKeQpM{r_uSt?V~VJDR(Qp;DWRB6gy4y2P2 zAaPRgQ!RTg7{m$&!eu=>Y1b1<`A8~fK4)8-R6#^$0*T-jXVELtq)P@WpTb7Kpm7+E zMoB1B$viT^V>GV8`gjQM92_l(DquHI1lSgg_ZkQTyyBHVfS>z?S3>u5=XF;yf}rm2 z7ro@^c+%6Z#&7=G`|;NwxkIdmz725@$$Uz;o!S7M57OGBRt#|Q;j$M|CnVY#iE~YK z?(huoHoy%r=5;VOaOG83;y?V>|B8za?4MFYHJpuDncw%~>+txeUXK6$wf`0OA32RN zZ(!VR;$xpXiKEva#uL8#BCKp41)9z%JGjuMMo}$}gIZi9^^w|S$DS7l@*lDc0G+1EKTJL zqhQwbKH-8XuM!%ru0}0F#R6{6Tk@#9mz?{Nd|D@0S0-&CNt`?MUUQmCNl>CZ2rK&= zCA%>x&dRFGh zIWvSM&mzA;7aiD-fA^a|iMPMyFY%7w{;NO*8~{ylsyqPDL*M<|$K9+|9>kt^qBfLk z`fKxWv|SUAcv>dyLJ$xLZ-KcE9$=B`8d#8)=4!OPgSbP*Ps-9hHo30K`i*_g3ueG z`qs<8f)wZ+vwa6KJKd=K$`D`7Co{^0;wt;m!;xs&7;c)Br|yv!C9EX6yLuriM~S7* z1>G&UFb|zYv#v2K!89gA(50Mm#zdLkJCIL^Bv=y7h}VU9sL z<~5-kuBf-?Ap|S#z#MYlQkKq$Vt|6JosB!piE(UKV>#$IYsaQb*ObkT_5#-Bywok$ zmJMeKlT2*SYa@G8m*@k-lD?(F-R0RWSDNFjK6frZmtjWq3I!m_CN$+OD&?jivV(=x zB1Gwm^AWJc$BHW#T@W4}v$=nk4wP|?%mtUbq?UwuYWF9SAai$*R8RC-BHJ0Cp1Crt_k;a9CaMv zySA>5kmu5PV)ocrX>jBlYlcx{?ApDEox2yI2Vgi5mV)tb(GmALMBr8b{P}pz_1|v* z!0Fl#ed8ED|Cu|mvb>I!<#hnSRo7gC3lE%&$6Rx%>DDhiun+(GH(rU?z5Lg~7-H;J zqf#9?U~POD*IsfyzHw*-b`3}f8|iV&As}W^8&(5@oCcOS5g929jv1W6vc0|c&|)X@ zdW^~9ePW^I4pFMQ3H>)plgE&?va@P$)gz8c5!EyqFQx}1uscDTW6nNTmUq}3{+xNp zj89IL0aYZ#s|3o(g%zt!-;^9GHtEi`q^?fnyNBtZ6*1>5_ZfXT#Yk1wwMhZ1mTC{1 zGqG7r66%MnMAb9WaEu%&=)^*EJ<3W9%rG=XFB^xlx7<=R_tn1lvgxawGfZ4U+>~in zl1b6yWFYcnUK0HTR!*!TZq;$llg7`G7XFdwK_GAu?78!WUVQwiOPoX^IHuS+UDhzA zHoJ?+#NT}E%lO=LHiswhPp^MD{@L|ET4WbpHrvGPwtLPE z*mrGT4%-1|cZkKtecpKr%apZQ8~j6uE?12oiN&#rxV_V-+i zSO4>8@TQGQSFejb!|Ir_Ro-vXL zSXo}fyZ_q<@%!)mAXZjJaXq*gAa*PK!UOy9>ev4u{^5(CUR2i~bIry0$?Knw|L?6I z=-TL9w@w`qUjC1t13I}4jVFBV{^LSFr5mo&W$l6`)0c9{tNs+ZuDkyAo($%oSA0K? z)zZIcL?*{omWeKXiJ+ZxXU;;1t}OA%`vjSha>H1u$l30;f z9fZS&F%&4;=Q6ONYCuD&oLG2Yt4%czkjmC!YuJk_kw(1^r*!yv&T^lANC>(A+i@0c zX8eaZG04EiRXY}y1T4vLg%RP!@WB{=3M;5Eer8J*Na&G7#BbHyC+M|ne^|8ZaXyN% zXcyzMG|>yzA?wcRJ|I zoluQu52i61X85+_4>(#(!B`Xra#*14-S87?15uE%dS-;5df9K`O>ciKE(F%UcP8bu9CFzwK+?>d=oAsu z^Y}Sr*qx}hC&;DDx$73tBcMci^tw-hMK2>u0c}y^l8FsOuY`?L;LTaEPJuwF?HA|4 zekkoZGF&btHOW4Jpll4b5(FV+Epv$oTa2V7jofL)_GCLG+Un(bsS(lX`W)xpJi+P( z>Zmlu=A^ipa&%U`+7r6{s0JfTG%0sNd7wxFtrBe;#95YIA_;j7DR<$0pK*=-t|)0e zl|P^da-^ZgC$hS<`n@LC=y&93K!yNth3_p3XR6&TN%yJmu!MTJBsbO~FV~kTf=G*s zp8FBDBm$c_)|K_FVx{Qigu!y6M&Ft0XI*zKc(j3yaf>ldU^qH0R+JBQ&Ah|D4PAkY z0F8npS`0Pp?)9(x=@$jaT)G9|_uqLV-t=qlMMFzyXgeBSg2NITG+;OCGCK@H*1m|N zhk&1d-3RgiyzPf@FTF5tE= z1K#h$j_p2*(U2oyQ^)Y!0)7l;hXwDk-j2Y&1^KqqR_BfvKxz<17dj1i4_X?7cnpsg zpfQ*TM-HyzXJ7pe{N~$Vg$obt!#m#cVZ8kLl|uFaKG*4L+p+$b4kMU0{nX(Iudt9?g4>mql8CEb^j^qg`F*#Hnx z0yDLgB`Bt>B$ zbWyX&q#AQJm>{qS2j*b#)_Kw#q(oSeu)NHIY-tu2jt#1hTxRcH)TW7LlpowCCm{;T zNFsS3rmRg7vnJ7z!Z9?9fXEIgh_gI}AXT}EQA|clbxT)FL(i3Xb$~}ul|f21cMrxh z9(y%*ED>(~(*Muin?~7nUFU({KKH&?Rqxe+LIH(|BtU}VOoD@`i6S+UvM5@zY{hok zqdc|ap<8j}Qk(~o6h}~;Ne}>up#T&L zHN1M$y=V82d+s@VpL+{Lesni~09q6W6yA96*?WKAx4-WMU{^567oCl$Ev67w@qGU6 zS$0vRG<0452#8XE66AJ(+06~y^dr|on${42LkExJPrvXDq!>qnQ6xNurWr+<6;`;# zHHum zjbs{$9fD~H#sCc(pl?&a3~=;d55M)uRP$iO0jS9G6{C?dls}8Q+faZAOJ~3 zK~z`ocsGWNg)X8r+9^}!3deWrg^?_%2;US}cEK!y|2b3|WN}Sdu_eiF_dl8^U4s~} zv2vZ?XvDw!L4xIUPeN$v`6n2$8RGwmqO5kY+s@*iqG-I*$Yp)tigdzcDPU!;Asp7C zD8uWoCm`!aw|XVLr|vke)+W*>v$(ZcBf8@JiBJ$g){bXLlbxbd%QLPQD z=CJ$}5XEi^Ml7y@1)oQ%it(+0U#I9ECWUL`Wgn@{w!W;b< zp=D)Ude$~P@%)pp7-DJVIJ(&)&z#1lnMvIHjRk!2 zXSXPQKzlO5Cx2!;Zoe%9jS#5W0Hq0%ra>dM7#LvN4ug+eN4WG7La$4B>?y|MyDivS z^k5HP|H{)K9w}m3$mz+cgu-(W+C_0kAI7@xi`-%;14}C%96C5JR^N(W z?TJw^Gm-?z^W1$c7M60r7PLwa3wZB^7vlbBUUkbEnZLGesU2Yrr*jn26i)b3EiKBB zCD6_)u&t!dj-0wlP#i#^gCyHoqK?GsI%chLvTr;iv=>S8bdt>>vxf z;^;NiOtvH(J*zsP2ofM(Q*l!d>FM`bS@WctfseQ{?ya>1y}w8D%s$PbpAv_z zi+O$gACal`6Q_tXf$z3$O_7eaIEA`iKSmudjv8|XI*ItP#)_7WDBiY~XE)J(rT;;9 zvm^v3RP)KmuDP~NVIfL009m;iV1*c#q8(IHLK_o{-$sGcP{UceHbF_F_{)qS zr4~*skK)+!DAG3Y!#`zU8sxtx5OC>x#_+;Ij*YXx=2^n#8DMIPFy2nk8U<#j5;Pm( zYdHTr!aw;mVWC494hgG0#?mt3$Pt5shZsi=H*su^F<4<_-5lw3TDagbTmfW^jWy63 z9Y?R9f{`M(8J^gE0&H7o7=q;#IR>y8fH(tV=#JG)Y&4X4?qjgjK+dZGtkV>fs%DEr z2aeSibP&T@AWa$=<^z~=#gKAro7jePHf+OPPuz!#&$%2g?LS=H17&d|ax}DD0Sk7` zv3;;bRH%6ky$vaXPF-YDPz(r4C%dv4X6UoapE#r5PPk=}z!Bz2eQKz(F~Vam93txXOc5{ne|d{CG-Lu(!CUWtYio+X7l5J)tTD zq6Tl{HC8G(@@fC?2zn=~TPl%eGhr(BKTn}ktpZLI-NAJ7*Fj-LjYtXxNr>!f0Jc)d zrjARX&YwPRwaYM(^8HMVHqdSj@#L%f!PG^TufqGFG9yVF80Hy3sSEQEr%-9C1Lw>} zDcI&1+T(x)Mri{+@{w!Bs#|yucYfmqq!WhAW6$0c6JrKxYGADsgE3>s z3C3r(V+uViF3w}vU%_zL1KZRkr==haV0j4Z3OmZbvjI^8%R>i!=WfDkBj+A6>LJ01 z5;=uM>f-ZUS?)OKoRH-?8c7qm&HP)OUtYu=k3WO~4e|QHXR&47PQ1CeAP^$sL}tc` z`bfavtor8CnnubSVM?SzYGEXlT~cwjs!pN0K%4TssT!oj14Yq$XtN{lM_FT~9>eTP zuTH^ymMCr~jCem~oUo%6Y#t2S(o1chfbW8Bq*^N5%FeXaubl zFR0WcQD7ngb(^cCT(2vpxzYC*yVDtUX{5&BymO{;`-As`l0Jrc*QKB_8cB+Lm?6va zV(Kn6;lx!hP1p2T?jg6!NH|3^T?e)acD?Hy)S1LQeD^D0Y9Qfp7#c-`+DMZ^_;%sh zo3U=9jeSRQm?n@mM$wvRp}B4f&Gra*yoooPDRzF)VEcuP@ix3!NS-r>ec+M%a@_Up zE>0{m@?j3-7I~iGbH6u@$%(Y)iy+MHU%_2p?-Y)2#vpB`n3znkaZ7^DXEw0;Ov3h^ zz!_&5G@3w`6Y`vq4Ghv|15?{)&|T?cywQeTT?OoMtSl{IFlfTsQ5fza!vJIl0IfO& zegZ}c;(;rZ87vJQeN{N#<(weLs#C!mjE}bvr77Xif#cyYCIZ`n+b=?JfG#>9bU~cp z;E6eGY)@gl(LyKd!y7!8yUyymVr^8Us3O)`US6oh{+id*wS5cQQsDtn@iVtdx51HG zXlgItQgP_e zcCx%ivxM5Bev+uxx>UE4+LLD&pDyU9P*zQq2l2rN(R?Odzf?l;+JXwXhe#y4L--YS z-$ll*hjI{>iDyY1WWp6(N48sB)uRY?mawI2m)1Zb$nUwx@9N5n&cvOM-VLM~ z2E#5GnR|>JHZL62iZGAVAr`jAB(C6jEf0|A9i%*l(PSDK=P)M4c^B@`p9KNWJhmT1 zV@Rlt1}2cEqaci8+e{mmU3ey5+&93!*BD7-1e4R_7@M3xb9xLkJBBmPAzX8{!KD{6 z)=wmuJ7CdSvM>p`wX)(f9`?F8@bV#8Yu#T(N?SH;gRQA0C;QzMEG^FYC|Q%FSeZ|8 z^vwh>KG{H{F@n*NQGD#j+qmXqO{5KAq)8ZQ7T?21KRtqHzCVf+hexrpFoNDv6I1CF zFzleSvWU)V2TXmC={tBfg+(7g!%g6;$OMl~oPaqmXd7-I<3()QvKi-}8D2L}axKvLY6_~0DFS{WUTX8fJx1gW+{ zzB(6s=Xl7WDO5F+E0ek6fBhw$z)N+bdOP?iS)`aID4|&h&`u@Sohr>0iB7_I={0Z|qTSqT)MF%Jq^gLf)(NW4A3*Ny60O-7 zmd|+p8MAom<;T$4Mg(j~@qe0j(IfbdoN!HgNHk zDL!;9;o`FlPAuej=6e?3ySIzO`+E54Uv1%%D@VfQ#=xd+jLyn@5pC+lYm6rzp2M~s zXV!k}&pmY*{lOB-Y;Qvb2_-On12PFxlcHl9SU5I|L4N~=gMuna8%0sS@un0%bR*%3 z#|V!<*u)#JO<;MUgVn_j#*;QCT3sxy&SPnHu@FqM0ocIW0e}oiZot$9o1i)`FN}l? zV5e~TyLMLYs>287arofzsL67L%Cd9%W5=Xee@{R9>VtUKxgW*LbB7hQs?1Czbr1g0N;66u^2PU)#~vrLPfH8zaCehCLobN>RM_olE}x zdj6Gx_E-bCS-}1yhhS|NIS-4;jTs}26sw(8fKrqyvm#kd$E?bOB(oii&=gW?A>*Md z=1rWjbxX)<7b^exLw$@UQIBzc z2W+2Zyz+v@&41p-vrl%>Ssq~6TR}ePVeY_2TzvVActwo$vkeRfD@7rL_362{-TE5d z_u(0A*fgd-wtu)~51xB^PTUX0l%5kg8(D(^3=Ab048~z??td<~grf%;U;dL-T>jn> zTzOrBcU_ZW_tOa;xU+#bUuk3c*fP3H9jqU1VX`%a`4flG%LuRuC?T*l;KU$x6P`s6 z7P-rR%bm&8D1Q0Ze!Mct-GBGfe)W>skun_aqr|Nba&(Wc4mvoz^eU#uX0g!g6h=cO zEH0cQjZEZn%iBy;2}6+^rd*0Usf4KGsaceGZUXNj@#zc~d{`~dpd~&?8>XWPYxvTRYVQoyK8hozQ_v$`W zRrVIUoajNR)C@!p^NgYvRkmGD7xa@Cbm80UlcS=-N!8m!G|vti|}h24%9} zUuUfw5mP&JBrud=2qZiPqym7n%3VdJDkGnW<78721(XSEL_p3Kmz=W+|M=kTu+&4w zeZX3eA>?^32AwiT&pIf3SSJF&C?=7hg&aAINt`jvD7J3ftcrR0i5z&fhfy<$E3cTv z_n+ybV^fSzOkrwf2E*1k%!U!X1rB3$7l;bssml^tTc`{RH9e z|2BcSeIw{BbYYpWaeV_PmX2Vxzl@Ail74N}votOWNZYT*-Xam!h$v-4EC|L83dLWks|oH=+{O=` zURyg=aoSsOKx;@Glw@U%=u@S&5HLBog84^YZm75@>A5wMmI#Z;0IIn?Xs=MEh#OF=3xfKsR`v``nk38?YNVqcDIzgV>;(&xf;Q&{@vJ6nWe9oZXHbTB^loo2?v6OMTCgmay!~QXlu- zu?P3v@tQ(R$md}PbVGUd!#J~?p~xC5KH1#nSXn-fey@XWZv>0;ZM^XC6fV8Cf$MHc zvFn{9xbOA`9=dB33x^t5Il6=~HfW7aV{!Qy2Kf>)ZXo9#zypv?i(GeFL5?Bb|B(yv z*js#YvEw4e6G?Cju(9IwR8Q_8E@5VLf-GrCt4tO+2 zEsoYC0|w_f2rqnc{f!W!@>|h~rR0qjQ^kmBCDf`C)e z(k@oqa8=j509{w+cnd@eP!m@u(TX+v?`t4M zNOXWTCDLl9u(XJyCypUU4{Qs+@zfPE>#jLM>iVgnD+om_sgAI87QI{?0f{N5^3=94 zX2wCOK|0n5*AE$g>L$$=C!aUU zLciNVf6zmo6-`KPhhWaY&Z^aNRvRPCJV4F^?=r?7%H_(j$Sfy8nI{0%j1U>;Ssxv9 zY%v&iklQ}8tbswVi+*Pn-}}cYy!icbT=R(rKKyZmcU(;P*4HNS#!F3{IGken*l|pb zug6lCU~+>jPhe~cO9NOG32~dxNbx)W=Z_**B_BR`0)Kn+w_uqZGJ=905tN-wH)mT& zD($tX5zk#^C%MpAhpo-Lt%<5u7*F3nPtAol0vZg|xiTY%d{Dl*oe zZE*&T@f~wfr-6kIBQFNSrJZ);!brw*F|0V ziN~FxH20@!oT_wN)|xP?HD5suM^;X%OcrYx%+@p@Ra*(K2$vTIM|<2dDv-D~fQ_W( zsYp`tD}RyLrINCQkUOplIuq0`cZ`ORT#2LTeaWeTgz*oD?pz!Om99S8IH=rUROcrU z2fC2Rv1f43*mcP^+8TorUo(YWyz4at6!8XnMEehghvR>h&G1 zpD-dCh}HAC&zCLoyj$#@+aYW|M4k_k4Tl)?yZH8($Fcj7G2Hl54gB)w5`6cz79P5* z0koP}nLCCS5qez|D}s4aXw=zY)0PSRn=jpj@rkjhAtwCKpZy|w%LX|*ARaHSNh&wQ z!@X7FV#XN><#t#h>2@FZ0X}lUHXJ)fFhYk2MI_#Y>uY0r6%V1pP%TSH4! zWAR#vgQy9ks=kjPoaJa>;AjBj`jQ_xR7QPLks%N0ZRVLHSFGDb@tiLm3$ zjd<+o2VkjJOtgYl=(B|}Bf(9O3+UG6<_2WJFYl6~Hxe2}14S`UnpvV|&x=dwEU%#7?O-_UBFlQPwkVD{ z55b%lUhizdjuNo0u*Z0b<;)ddUBttMX5ITWh<*AsRB8&V7pFy#Q?LvY$?X7^av09R zCM%i`n<2}G$c8< z;zP0Z6$i&QX`##_bx`VUA$8$p!)e9&WL1;QtXDo2+swMCv&@FCL)0P^j)=A4of1(| z<*blxsN6sIE3-`MyO89ijm}l=sv%was_Vj450s$O;L`>Dt$#_2PAT}QhhC$LSwSjX zBe*aXkyh+QF0~yL(N_dgnZIip8k65s1#ptoIM4gX(7f2MSC8&Fs4#Z>H9Dq9jY^7l z^tPu0qDlzhHMDhxG%Kfj7K;3pMBBkS1c#|6y$KM7BD#I39_=8ZHwdDm!0{W^^b|1p zq5T6aE=?BGtP`;mA}AMv;eEEI_GqmrLCw9BCDZ(4a|-VFJ?=>+$B|Q8dzV zG^mZ^hYH$)0VIhjtVNB1nQCF`;!)gqQ;LsYo8rlba(wHnt5`U?gl^{q2K`lJ!vXTV zn8-6*6mkn!(7A{=Eeq>dJ3-ybPw{h^=esMO2HpbM0^|-#CqOGt>OyB?Mfw=|2{>jo za|}S70LTHGx>Y|H!OBBqJjBoraqr(x;>}lE_>o_1;Fte-iogBRB=(FnuyDX&cDjKB z2j(%cHN)@z#Z}n2Wel=!W&mIQi~I2Rw>$=e)PdLuKm%m9hlXjpB4$C9Beq}x2%INK zlM&z8Sy*gM&cnN>{wbavJcis11;%ZIXE$jfrY&g0#Nqf zhfFpT{_9aemcxcb$4IQyg&p`(91<^;mV(QVi^eFmO6 z^b*o!9H|*Wlh$E%xd{-En51~urugfEcTeJ`^BCu!N%+Ri86LlP8Ow{u(e12YFz6!7 zyB@Z-Y+-E4RTSSwhD3pLjtDV$-T1O7AIIdqP^+^{;QmaJbuvVC^kpFNw$;HYH z26G0GMeaP**;@B!bI13)sXZIu#qY1f-y9jor+%r4U--=ww|=FCA3V7kM_!-D+2@Vo z*Z*J()^8s1Uh!p*@n8PpQQY#yM_|wZlW}523&MKzaRfQ{kYb(ChhUlD@vtWEP3w zLdI}3QB#;K$&hkku8Y50+mr!bz$W)qNfkp9-CuRZqBKEa39F;L*9di*`8D-m>Nq9A z=aiGVsr+$@#dh*&_LBnD1kH#ERvaou?S;!fm&B}9MbyZigETm~eQao?^mCC?{<4y9 zB?@dAVhR1mUTkQ;15I9!BfTfEnj8>2rp^ft37GPt$W!8la9Os3ghp$dijTkd3f%t0 zvq;ed(Fhu}4vA^w*x?LGVhZ6B3U1ak2shpUoR|at>JNI@|5_KFr4#6Pmx{?eA0X!* zm^0*#D=%bNxrf`?txsV|S*cKBsmkxUcO;G%mA-5UwJp;ecn^Vp}MyD%TVkzhiB|hAPg$Bp~I41vTXFxX?J1e6L#n zB%!4C#kgdGXbm40-YUS{mw2Z;2|q^=I}|Ql1{D-fPcfts z2A4zcp?b05!xW9@h_W|CJnb4;n5afU$24wiOjdFI5U(S=Z>k6qP8al36UKQcHLN~W z#R(;ZLp2ahC~i^A-a%}(rAOJ~3K~ypzBp3`Ai z5(i)4@o#?MAs9y)aVHi-*GYdFaE@cMu z6EVF=aU#R>%2guE!Q4)%ZM`V7gp%3W7ce+;?~8L-%lOAHtwXO*_~Fka_~^$*(P#j< zb+erF$$YZU|{Dlf(_~bf!LE#nAB)sw~!Z*3%rXl>W zD~}4KNJLtNO?AY-DE?$%1T~P`RhaewV~rv5!;4@;AT#2wkpgNbP75z{q!{GO0B2}4 z#*3hjNcaQ*neCy84M@!t3{AqMW7x8J9JyJC{rfB~+C?xaq1`I{)>jr8M-DEazp{cs zzk}hhSFEG4DCWrA^SOzft>CV6chwa@@nq~rw961vR1LQPB6O+hj6+>P^Vp{+eRE5ng)-`6( z8lAwQ{tliPB%~mH-)TN-8 z_1U2WZ=!AF0L7D<=(xVf)~=Ij*RFU`&Aa?XqRJ3)9kcXQ8ykDNphv$FDS~oEl?;S{ zYK<^^u1YgvD19yaSbdEf-OZ7x^AQ|Q!tRm9;wXvfMmpU^MyObW_Njo*VacV+_rxhi zq5ZW&%EO+1u<;5>lvS=dd#WVOag?M+VzM*BS3Nu{t$A|=lOK^WN3kcrdghOy=}-f`9kuz&6mbb3oj(n%zSyqcGgAhUf8^Hq!{>m3r2h}Rq->n7Ht zNz+J78)?$U^h^_D?M+x1j$`lZz@=9elex`+ZWox{LLj?RIKE}QLj1-9SPTo{n@fBv zxM$}^<)GtGP>W)I;jY=*Yvs9ToIg1Qe|LFsORk62i5%9wC~63x9K`g+8V>i|!@h;0 zICFda}S0Iv(4>T%ue9w(m`x!Pve|TA4M-~pl=6A zJWL!G$e65$rwcbj3#uIf%Bj*q;PJ(E96{_v?C->SFUe9-A9(vPJk%JZ#%pY%P?8ka zk}Eh-h>P0WmTRvRbNi|t2*^I8CMczx=&3rT%Zzr4!YTZq6I;Kq1`|j-R6<QW#pH9eFDq0X$rketrN>tm6vUUGh9st2Awpco0paL(2b;rP<) zIC$&@AZZ{?#(a?*X3JJ^()>tio3pk1lA4;0UQQ_FZYvq9{6c?MUh12v$6Q#$9C3UEzdu5 zP{5X9y3uZ&tkXDzIf^YwBro_WuN$kDbXd5>mBrkfrV_(Cz$#(K(>v%Jws?+aJH;>m z?_03xtRh*h-z&beu`$9+uP|==uEB=0H{tl}bLjW_xaXclOtcu+T(=G1y<-JA#$YLf zr3~O<;V;e!8nhmLyMXnr&9K7(-t4>x7=ueTU4@C(x#$dsV3R37bxVNp7O$lipww0b z^Cy;ScXx)c*g|2F0zzp`95wL>h9zZ`x+-Ym-%B3cR9xaT1TD`R7At&2(MAkc;o?#l z>*4&$#*TBy6Yzs~7ZmLc;zUdeV@2f*k*~v$IA3KZJUnW^QcuM~I2cnLHSbPZ1G5^e zD4MscY={Lap*_UfMf7w*f9rCtCU9aSa)!AgVhH=t;)|!XtWx8yD&nqKjdV_AhA1_N zgm^`RQ+hR>+#V~1J=rqB$Hf&9he_B-#90(sQM)4!T$oi-*b5F52L<{dg2SQUbP{VZ z5u{y0Q*|q7(yQIT7jq&C`|Xn7Rx}BFxKLTZ`iC>}=&Pvv{ef2|x*7_5s5O{CCD+{= z%uJk*>GoEod|K z2i=mk^45aEx7)9`-D@H$(w)fhpr#B0pNQ2*m9vnqo_NHOi?IpRWK z@1BE-$uRtPQ%rwkyb?eBj6s6p_e*}Tc;uug3L>@4z&#hj&zAe-zVuV#AHk48;{I;P zIGa-AtwqTMv03pm?!P;=Hu=|V{5v*OXaveEcK_Ly@6EkNQ@$c&{P#glK4z#ebAd5# zLLM{=P%<>zI>yY>HUKuDU!Sl_HIIB0HwJ6(k*y>E=6neI;=Zy9e)1j z5=;QN_qL(SDrfICe%_^%c=ty(Am)yCNR4aM1OfPDvYpq*fLY6cBEfrJ|%Ff!Z2 zcxw#nCpKXJ!V4Jk5WCKL4=&sB2`upl@+2!dbBeMGDSB6)b|~)`BfvWnjW_vg66*RD z_m;3PHUe2P^4fIwoWJJ%JsKX5RKjAo$Edu&$hfK8$Zyb}BNY8C$=5^SzVLsq`K$7p zM4Gws4N-qZ_qIDf5Iv?p1=;;R!p~I^N~6wg{~Dw7$F~tgLNgLhTtuI5_-+MNNa6de zdF$ zRs2DURyf*=gixpk<+!lpB;`!+p4$c$v*_>RwK4Ks>00IpHI|Vi(x#MTk+h;-2Fnmd z!8Rm>ZRHx3Q94!0%&J3{s(u4T8QbXfH;x52N;p)#3E8IDGJOT6$Irq3BTu2zoySOH z9gJxg*9fQLT^Rp-CTZY;^JcOCFrhiQ4wGk2<5NFIIDZT9mtW}P=)vQ-`0`ndwY1j! zC;rFt@WL~Papds8L5k&69*Q{=dj)yPK{FT^UcLz*xZ&K&{Csq78Ta4uvYyU}*H+__ z_ApRW3hNX-5Z0L5<)qF+A#J?sy+n{K0qu4JpZ~*m;mn=mh(;YecJDlH{mXf@C)eTD zznZ~kKi|L)eS&by(NSdmNsO#c!Y(f&PZ;+6 zDn{l0`B+)RYR!yZ$1)UF+~oXPE}0opL8;<@?AtqzVnT@{F)US2KX9D;z)`Z5Krt&! zba>B&DrJF6fF<5$R8?iw4E+Ws$?1FMmed5+(F2jUnoc5*R{|<)AW-O5++WnMxHRL5Jcn)&5bbEZj0n@H>82UMVU7sx#ztIl#z%4B`13e=;x#0ugHf~1 zso^LshnAPlM^vEZffIKfBV|%wF2PQFFzR->sUNl{JQY6Ex2gc zRsf6#?|2zU4|g>DUfH$?FfY?uxdp;q4T<}A>-k)E8i3D!{tBGAbF#wGKJ&;tZvN9f zNYfE?I|&ZHK7y~`GLC=xD-FEze&FFdTWI84FdPhF`$J?|g8LskfPS7~qSb~?``9=C z5|Sjt)#qLd&_{Ax%5x?x+6vKI128uAncrzEH0L#}Znmdm6hSlLh z{`#%%caa}7!e?Y_oin8mylnmnh;kM~mbG>AJ7w|#SGNA z@SQH`C!NtN7JV%8g`j`y3;d$dZnZ6~i!#!p}8Y1geQ=kfI*F zZ?AvWBPNl9oVppq(V$%XN~qt%YD^UsepQV@sOIX0iBkP}0thM2nAwHN_Gauq@&vls z0ay%b*{MyNXYj^hLi@}KY`kz3KlyRO19#?l=Ft`OR+o_Vd${`>Z{VHRO=4!YsXqS= zn_BptKYTy_&F|ceqjM`hPM1&`p$N_tz=fA>!ax64A3>|#tX#eK-SGoz z%WKP25U*fNeEv;0oN51Los8h{rSEE`vQVQr|9-Zo>y{%cClR9_4hQAk3 zYNuaK8GPu%a*QCfAK_#nkpKI57Vl zGP~q%{_tTXiNWEy1g#CTnA|aqpZ-aM`GbtRzTQWFc?HAXD)MZAL4SZR{{FN0U;p%~ z$`!X^Qwx9eH#gydJ733xckaOpyAO#E(4yUL;;fz1_|c!f92Z`;x%OT;I=76!|H_jJ z#R`EM;i&(iPhX4=+;Cn6eE+eZy%H}xdk8N)a|qSD3f@9k7ohmoiKj6|wBVQi#nrgx zhO?sQX3WoZ@i%|G8zXIlv56E3B}fuNqdCM#a}~QEY2uPA3_kT^2LEMw6szeZl4KnD zu!mNIu>bJ$nAz0CjThaBefv5%wAumE5(-T~Y(>PUc2O+HV+*QYH~#G>09hpE;m_qR zxDA+!2yj824J$&NYw(Fi7frpnZ>Fu zt2&xQLb`y?CkhKUtWiXUe$5b@DaJQXLfjUw7Dp>>D$7C${m3C36)O!1ISKOz5Z+f!2Z`3u)5mAhS_m!*ff69`((8{50-pe#u0q;+|pe z1H+0U3C$^sZ5Ai!lWA%m_w z=QK);4B%)Py#p1<12wzHgW2hVerg5Xo0L=qYX1K@2p#kVCL#>w#VYu%vUo{x2FI%p ze*ZDRQDGlad!ZvTTM2pQs7#*(9d%gpkgUv8lpm3AndMEZ{MAT$Z-+nxCTaOebwNf| z?$xPub@7gAc_SzW_V1NT)vV~44HK-1aF9s2MyT4nQXK6`a=*7!=nETL(kvTC8P6e9 zM;>&}(@(uuBh>zcMly;LGGRy%$C{%_xg{jbf}h79MC_G07ai8UXq zHQsbhiaR_>ICGWv3BC1Q8=He|+}y_duRjM70K1m@1k#|SfP^jbEWyB;&I|_(n-_=s zNTY$A89B!Xt`LB_;vQR;2Ca^kbr^qMxa)@5rQ4yPLEQCZUCgTSmb_(5YOIAZCm9^b zHvlp-k4uvy1iuU>_I~Q>(%~@e$NqinKS#0gqgH>#s-6smktvVDC!O62Vtj^iG(pFW zUfq9ZXiX2mYc%nwxLGLNi6w2vDn+vTAdxqKJV%B00K(YHpj>$;kD8&fQhnMf?i56E zvOpREi=g5MTuIFhi|8sufCRT}l#L&$U2vuIR9@l~LF67#u7&L*s;lDirov+YwIf~% zzo2%sgMX9=P|_R`m9V>2>Uz?&oa$gp`&e5RKSPx?`szU?typ7T654>p?T8zyabhaJ zUk>6vsyM*KG>e2x#QIKH8gka72%IBxga`;o&P|ub8{)((cHw(TOjE(jvqJ=nB~b#CbwN29 z$_;%>*1`5xFy2K$v9d4_D;O7|QDP$Hiywv$h9!BVt!r(1kWMkvkP)NQn0%%7#UN;y}GZ!ouka(@eU&%shV!0@aFtMcg$Ow>Wp8uVe< zAS$&?6k)fPqDIuE3Wo3)iLDrKHB?1UP8al(LU?6CQ{e_2!Z9d{(X%BtE_M!;MJPgI znBrn17>OcvdI?FD;V>q$mj%fSPGKPB-ZrJ}WVtsh_K%t3Bw`l6@&v8pp!(`i_WC%n)K{yIA<0^c_E^Txx}Eoc#>itZ&^sn6rrB)J!I48PJn+?3^t;C~ z=&m3e_F(ftF_{a)7?`4{zp-Zl|Hp6KiI4oqxwz(|JFsC>Ti5YeN-cgJn_I!xZ+-?3 z-1&;)N5khPnGI3MnDC98pT;}ix4j~&J2tn1r@pr@d?u`~R}$5O)>OI2LeL<@szM_yALS!n1(yNw1P}jA}6= zw9GYl90F%#V-bR^NH-tiEAnAjB94}7nhD*%aYbRSinf5-S#AK-8On&2W#tlAuHjL% zeIyzslD_*Ce?I#7Gc219A#julcb-x(uEvCroVVc``rC64y`0dE7p_!YiYQ>^NaU&% zN507vmC;(g+T)lil61&kw4KPV%GW;&B zdT({&IFcUiVX}^8f=0{gAvZmPFSgtLM$GN04fdLpJ5uI1l4IBO1bH)_v9SafT`-Fz z>B1mKZ`i}PZhHjAOkm@Nv(Ze)!ZcM*aB3}BuFe@{AW;ga4!*vGNAG@9H3*;tGpomO z+h6w3JJH9W-$6d?A-9>E&NIJXPR^qp4ys-44Drodet>V@{4B1yeh1FKbQWixGmW!$ zP9qM>+5hSSUfg{cPkwJdUfezB5G(`fDX#tu*EEnsn4eq0|MqL&z%TuaYjMG4o3Yv% z;K_&gR?c<|0w)eY5M8K@yeHjt|;Lp*fno=S{xO>nW$S_CwV z6pdy5^cxC7>AN1eKMJL~YDNeuG>J^{_ugOyE6YpRv11&UT(}O8e)}a1IK}u(1847O zV`6-Or(fuUOyba%viY@0T=N?2P;EejL{SYn=jESekEF2lY)}gIxSb5j>@b0c<|TM* zXpq`-!a`reG3*Sk2!AzwRUt;Af8&sCMbb%=H51MHi~_12Z{ELNM%fZ83tf(MPUUwV z&M%oiA03d90MZCrLF#*0TubDs5%SstyJnQ_|KIiV|ASw@@f-gW-*U@WPU&Ya+w!Zb zgnG%6r6-T zdV?aM#f7&N?prBfQY5AcfQp=No5R`+u-3((7CGR=#iVY__*1stAZg7NfA(kp_W$*I`}X6|)gr73{3&bUmO_oFYIF%T4May%9NkIr3=z9+k(xRYCHGV! zPsAW>0M+#gA0+pFOjQh0u6L>F#^~#pq~EiifMs#k1vg^#V~0AblUSi5DB*a8Ox~Ev zVTUS-t?IKDT)6?X%N&(37b0XMv>b09c@uyA<$d_@2QI-y7q{`f`(MKI&mP7NH@*|g zD@%Cn(U-CB&1Wz>vjgqX^$MmGaEqu>GIL#COX5Ibc9EeLna$i`~9UR2S z@(i8T6Br-2_|Ww`F|&RekKMBmU%T&l^lcZD>ls&Ez6F*t+;jg^IJ$5G1N6}E4=_D8 z>qV3W)uUDL@fpQFE?L%*kkrOxweE+bZ4wS?g^8fvIJ#E@n#F#NOFmz?2RWMfNdfpi z+L>$I7MWDufd;a&Yh1TX}p1r(`TVQvOWSCw0VSd(<33UEUyzd!x6UDuN3;!EI)Y{ zg-V58c}rJOl-O!_ywcFarG8c2d4s*GUQvuRgIcB*_)E3pBd)=Si7M|yu7$|!U|Cl8 zkQA*_ERcfUH8v!Y1AQ6Kg_2k?#zOQauz>P>cZa!&?)u)Ki>1y2w(p$62d_L2Suer& z?tTSJ3wx0^EiSuyD@G^USYBDdZFfA1-f)P_W=M>|`qnhItY3#lW-xG(s=6r&Qi+7C=lMoC`{gP@PgkXS4rAO*>II`nq4Los8 zC5Z@oByUf|{p~1r2XH#rWt$@|=A| zZNW0qPbHGq?5hK6EzVz$CW6e#tI|~_mZ3->!@5&df*{>k1irF7j6(VrsZ|#CFnBCd z3@Dy_EEef!by@{k(xadZg5pu3(3j#f&$Aqx*E1RoM$ReN=9phx!ry%PySQT4x%g+F zyAij2^oi?3KgYcZh5r>OZ8{3pe)gNy=5s{E-g3ZxgWYqsS{n~_imP+9ISVzqM=S6_2B zF1YwSyu5oJcYN&?taf|YFx$e1Z`y&C)dhV2sUP6Lp`*nc$QkW+8|`KTCsvQ*(D8#f zzSP90-}_Fybnuvfr4tXi$BR{5QcTcb5DRPQU{n*GPU2@^8B9h1%`&Q#D%6Q#^5lzJ zb#-2DwsiC3khsQ5O`p_yZx)JnMjX^vvVB!6ZEf;K; zVrEm>BtpgG0u>^OD`G!k^Gd?=U45aVU1gCnv|S@8}EYbmsvw z7#*ENW-W49eE;cJ@a)t3@W~tBjcY$Litpb34F2n|tSkW|eZ233+p%rKMR@Rz*YNaxPazp$Tzthwtlu<(-Os&* zo4@ugfCxEfATn4t+CokP99`armEj4Pgg}&HI2>Yr>2+lJ2+|~p>Rm8@wQPmw0|`4= zQfph}9n4ro5=-k?b~0?z%G)69)Sy`?%u)72aV;mpp|MnVvxnJPIykB;QZAVrZ%1qd z3TeeoHVcQr5-};!21wg%2tyq=9Iz3Sy;m2+CS7GC6^lP3*gXu=h~-xjQa2JclcGV{ zTmYhRsM58k3;J6^?iwU96f%mnYm#5iiIQo>bR8SakXXoxc}!9G5$&UshXhF+`BDhP zp?fO@T})!)ATjOM!Q@VP>?BjERxy?ave>FG=|vKVoh!H<`LX__Yc54L~e&zT3JSGYy+A}g28YF zLo)cgxkOQ1bY1euKUotaQyfJ9{&E*IKF%s+c#f~sn$#oH?f8{ zNuWQzu)3mD_^vC%OCjcDQGA?rsL>e(GVW4ye=_49+TBV_N=ha~HRwm=M~!&3s^Y0= z>IZlds$=3>`ihBarhJXS7*%UX(F7c+Uf@4tsI@4yQ6lKBVcy65;!(`ZjNro`KL-gn z@#sDK@W9d6F?(hU@B8pJ^m%|Mo_Gm!4;0*Zjv+=&6YbF!RtJmNySNwDg|{;?a+?>P z1JuCr-W=F&1|=8Yr{k zf8B{`gegk7Dpw&!gz|g8f7i9>~iKEw-#)x=*8 z0IY?%j7Z7P>N5*SicyqRiH=B35JwHP(g2+{mN_-Z-Gketx5Iz}WS!t+?X4jd>k71N)Je!YMw0EI?PY@D@ za2IbB0NzraNjHyLsBbMLiyf!sEqqHl5Ul( zyv|0@0^rjH{p1B5Nr=|0UY73jH{PW&TtF76*oQ)ScE<~Ca_?GR4MsV|m6LIzxpl4v z$5gz?{qB~j`Pr)NjD&uY2uvbGVN0Y7xJ)xbe8I&@Q!?*YOo2gb#Xcvy!l)5y#4uF- z%_trfDpgGz`$}UTQchpOwaxuGYctF*9z&8Q$epUZeEr5`SX|kUG#SNYYZLMu7z}%O z{m_2==dT>aJGP&J-}=2D!@ak?fP3%Qi!;t#hadms$MD!w&*8b3AHmj5JFszjtB>&2 zYT4pY080<+5{a>}iHwL< zhzpB|S_l{wDwQumyrRev1PXN@sJsHXTIw_wUZ|(2Add1C;1B(xNlyaRMk!h?gRzFe zf4%uBY}`13cV2TAM#fWo?|ZM|p+}a$7$WBkqaz8B7<2|FuecZf@+O0Vy=osXGpT@hR3Po8P`hWbQnZDtwarpe0`)UznGMzQdrX4dZe@%CWMH<) z@-F6=_MtVp4(*W*7-p-;Fu)6YhuHhaNAcn7FU4Z<3N!YCc@P z9G|OAn%7sWmqZn)R!ikMhQ3*)#mR<9yTWlyfrwBVVxvstihHkIX(OMW>RLZO9G;Z`bm9qM{HUC>YRD-m&{ zD#U|H`JaZjMSE$D5x6XBO98@g5vHHizf;??byiiS4u7VJLAE7(3YADm4T9 zwIK*SMeNjN)EA}!LQ>vWr4t@k{M{Ma)j*>$B^UiVIif0AElC6YcAAP9= zO>%{i0u96!SX2}+X>nM3>APaZ6{UWu=r*ntIMoal1wBa`IBVM(SnYRk_d{=h2uO%A zHfoS@j)mo8SXx*Fkb@`#QR=5t(9m5&p|CRuIWnYWL@3z#3lI(+KY+HGDrRD)N{BO) zuqKsi|8l*tL^upo7)XF;j9-5%MQbIBVFa8XCPfw;HEWm1SQtq_jpC+QV0Dcr3$)Cr z9SqVdU5asYbQ48f9SbjD#3XcB^4{H8MTbqPY9=4_U<4|WM+KcB9mBN11^Sx{2ayxN$ulUoj86YJI)edVtoN$sV%rEg ztk{kx=cUf*^yabLJC4cL493&-7-klS7Y)9A%cD4R(=0yoiFi^p;2cV5M&jZ?Vp zvKj2&yAQo=i1B7q9QD?(0fo~qq+xOFpUFn7ufe!`_=TTb5mELf=~ZoZGy{{kcakMTFWasYs;EQdwCR zlo^9$P*%W{zko5RF)(1jPXNrAGr<@Z28MwF25APQNTnr}q?A%dN+FL3@1MWtufO-6 zbM{^gcDL3(H>4QGz}+mQ2=Cr~r`c<*Z+*?o)lUZlL3@`NUUWqj%=@4{7xs}u^>Z%v z&!qy$;PPBBIS}`7ZiUz94i}fedi?+(55gAD&OgJ>UjZ1v)TLwH1Mp@CERBagN%VRr zB1rHBIS`ug*T4Q1{@EY>2)B2v)(HxE03hZb)n5?GW;jyiUOE3f!S|v)E`-t^Sx=Q! zZlzH{VJTkY(hQG{*JiUf*Ub_tf*`dS)5wf9rW70CB$g~Gv(0mZyej)zDG|?P!%sAX z-+WCpN}auwDh*{388p$Q6RM=ymGw_XjzTf_v1C$wtt-du z3u?j#i`++hNXv{+CuYYl%E2$Qy)|cm6ba0#?pto2Wj#|VX1s4=NA=+r0aygDUOxk~ zgU3|ha4PnamN+A(ffL+r&N1wEI9k7j_38w}u)*igpX0y$&#&;4Kl~p4#ee*7;eYw> zKE+@C%?n7^rTuuHimO1xCxNsgl{IgS#Z<0&DY{C;8ueI6hEwp6G}}$9 z>vbmOi&V|#`HE0#WGuuUoHct|kwm#+KZ$_ZvgDeaq-LVaN(=RF%AR6Qm}S*lWSUf@ zErZ~|+=JZ;Zg~%He{>&w9B_5^0+*MsF@;+QAHZRP1TF@GBx2vQ_!(Sj5}Y(6J? z4eE>tQN6gu{53Lu#o|50&BliI5WV(6(Q2cYn~3U;gl2wenf9o%5UF11Y`7&V8imaE zS|xYYm4w)>lf5Q}13-3LMRlJjHbTi1_xhr-nj_l^#HO$x-S2RAeWq3v@ro_6z!pPY zE10cW-C+_rcoAG~E^vLj#lw5=qjUE$OpKrX{0V;f>pT3jfBqf(_@BIk|MtK68AdN) z*GJ$_;=#{pqN?ACimOdTD(x0nRXCZwtETXoxoTc5k;=l>gwJNeQc+sc7Q^OwCPfBf zy{9$uDN-9wvf((9by%c*qD<5ET&4HOvxbu}vsXfcW{D0#D)*mNKyD1jAzFaDBdi|0 zga7b9eSrVyKiMK&ZqfA{glPfsO9-t}u^Wq7Pza2`Q}RR4YM5Y(MaUMkLT2?rj&Xf= z0q+;+xXLLD0!L~>CKXdEc7nIfjl`x*>9nPg8PmPe@<&qk#oC88rL_gMvO}@Nr5QOB zq&&$xc@2lF9ePmbn|uk8EE^HE{Cd0A6C+n6vnMATk4shdD9z8q z7|=9>q*%pBfVR?Bj(nzB=QjoY_e1X7kjSWHnAeGm>^?W$U}G_;pq(1y2a{zijipJe z$1%=ZDQjC7dM2^^B+(w}c1pFoV_l4?ycCirGW})d3SG+(Z7enmLCWNLYq?c}7-Xb? z7}#UZGv7}M+OH^TzsBVns|G}M9o+2VNNMJ4!^Y)sVWrc4_pN*Q*`Gfv;TSck(N!x< zO+lizbz+^kjaOHvAiBgm55I-=g0LAq{^fuF8268WfAHh);L&d($lOtZJ!rWgvS={H4;bl30k*6;p70vWm;$M;GBb#4)@oDKl(>2{Kcye zFl?{E;SM3}Ko}vIAk-s9`JQ{S@YAQmFxRu7~$SDZT{3)6>T|S{!4sK1^y5 zF3DnryJ96Pl{ndW7F2e;SR^YKckLgp8X!(#z35x9QYmI4Z$6I$e;AbWg89NgF3A;~u+imHA>v zuRsw|Kp~gTWNA^e(T_n)DmbWm zE7az;NnBJoa(SnU-?@61MGVX>loiyX*y?JE7AtuR%23J@F{^}Dg-n*Dzd0T!b{|Pp ztWwSHyj9;Q=DkZrUK>k=eD4*J&#L06k^QEiA5lmG?Ds@ws?t6gR2m3wmO`=FuI`0^ z4V@A-L_#gu80}i*O+o+Nkb8#Nh}9l+Znx@GvX>4}(Z1`Y_)^`~=x$D$gNOB z>U*|k4Eus^fI3OK*6U-R1X9f!$Txx zBA4&FPJ7T3TR|K`-6873TTtRCa|lM6pbMOlcGsd~Bw2;Ns7!0J&4Qk-c($^!Y6jBK z@XU2=9x#MGO|a~HPRLT`q+L^y?Y^o{LcM+kVMx1lPX9O&JpKgu(Z5aT4;MH%eu(XE z2S43_!xj{_2r_~(MHyOp{{wMcqZm^i6@zM|a`joh*ikX?t4TmVo1?_t(MmDT1tsBtn zYy0DCIHBu3Xr0n^C1qqUh%}X(oOCh8U3YGEf0+JVhg--#!wsG>$?Y15^pK^32o!{4 z_BvD?vG$yc7Q!w+0?zL)aC-S1?<`JmbaIGEr<0X~K*{#VLh7u+GDS$BebKUJ-^OM~ zWmVJj@Dff_||;7#JXzNKjlD;VjaC+pL<$bZBO1 zG|4Kf$8>Epi@-tDePhg>g>;nTK5)I9+)-w>f0CdtO#z&Fe2C4bGE=^i7*Qh>($Al? zURzQf5Zf2O#;#IvS~Lw`X1FKt-2vb*;n{BlfAa4K+`A8K)<@|3L-_F!VcNjU1|%a0 z@t-K_?h>-*lo5(3DOLXb4(oo6&9p&wG#kCg=I#xv4|`hF`>0luE=4YinIZj7CeZV+{6&CMJWv46!fpKLnoS> zu9$?gW^1R751@?z6j@9}RG|HyAPPbwdE1kvF4V*Z*6z7<*lA@DfU?J-eZ{?L2+%ld zXXf_Zu)(X#mw*U%(++;PgIgb>WzbhPuqB@f(R`giv+S_BL`|%)==-QdCoeY6Yeu}zfz(L3*nGXZ#Kv)922D(Em z5AWgVt$X;xKj`qM|8fhaDNf>9%ESPNoLp6HBW1?FP*XJ7c+4zwtK_ok`fUO!%z+}7 z{G;}n1$ELpRnfM^n3-ab)Pl2@+N1M64dNo@yD(%j(f<6@JP%aoUgL;EbCgUOh|FSj z)APtgh22l$ad+-9ZWj2~w*=?U7U&jBxZN5Ptw6K_<%W+OL>wS}+J7h6X>y3O_b5YPiE}@{T>^% zx6N(CRjm(+7zTyntdPvw5AD$p%+vDT6!d+NdxqJl0*kf4H=JsMa=KCyC7L_CRS3HA zMArMOG6^WAw((gf6{0}a9y1qDsZEEFHP$e!Si>a7Tq`QT1dr2KFVlYq>}164?KKX& z1-fogCPIN=3?p{K4)@mg6JaktfQ-4ntyZRMV~hMC7dQNzQ7kpuQnO;Uvs*dJb&yU) zxJt5}-aAUOwbNF;r2OxN2q|0~`{>PWv7I3Q4X7ql^C72C!)E1?;>F z%&amq>$gr!)O>Ym(MM`RbksXitzo6cpOXCy)PU*PyIvY}riLhyp>m2SPw<>aP#nPO zvjY>EOXi(nSl7TDNnqsw03ZNKL_t*e_j>RYaQa!m5B?tG7k|~E>!YNNX$jC0L3#xA zAPjJD2YcdRUV~|ib$_p3+XkHym87Nzyiz`-86FIg zPTDC4)wsr%L28@~Yi*V}HPVoSb-0LH7Ya-8$cSl+3a?@m2DlPR*n}{EshDudB6(XgZ$Z^62m1wj^)T*1lpv*WI~Ta~8D8 zXZgjTB5W~?aN2hh#X_63FDIIkX^MSNgz8N$rVG^W>Xo#Ou*U?3jPdN;i76SS(1d5F z&k=IBNQ5bPOu^&&<~8mepMbf?;3sT`9bVs^BZx;A2uDZvpj)7LIoY5@tPlG9$yhzA zqTKEj%U8_alZ>NRIe@i>JRcev0+z;K%M=8i%A^2`Ky<&%Ac(MDJ3M~%BKZnvlth}~ z8>MO&m?=NP-Yz}%F2U$Mh}K|U!!4FrEEo9hcN{KX1?+C)Si%Xq&ylbq4n$L#z=fnS zX-z~orB~O-fz*Y$ax|pI`yAE}rW{}j)zOADdiU4H;7Z-;0@a1fX7y@as8uI$0~71t zTbTAru>eEpYm8Si_d&7B#k?~F>w0M4D`u6$kkk$kkJH~0KK{O->lkj)gIo`GJwiwm zxpV;f6uL5|g2U+^I%MX1Hh+ngO>lg$#`)cA5U1E%>JZ>@(DiWn`_{W~O?xXlXA1%g zq8W^FiKMzeX44)@F;F5?z-?L?#NIQV0;o|dDF{~^E+Sc(Xu_MMNjT%ZICG2-mWFsc zD|*Ez!LE9wA)SfBf;91tveO{J4qN7Hh@K!Sc~8hR2<`hS`XO!h{xGqy8qIiP{rVMl z=-jZK#iV)7HHRirqA|L#kfI2zgbh~b-9}IvXgY;lPy-DcNT#HRX^5}^?$w@i&XY{g z773o8J;&W{lP2R(4vL-kAOdb*zlac?X9N&N9v~z*zdlFLjMd?BlKR+**Mx-7T*@&^ zg_~(eW#%$wJONBGw<`*r0d5W9$rLD37O=VDS*;lt*VjoBry094gZ`_WMqTIf9OUh5 z2a*otx@c0;_29({-N6b!_%87DGXYHihZubt6p9j5J~S0O)SB{Vzi+n2AN%5K6~S>| zVrDhsA_G`f-7n9lx>+cSCQ?Zgb(*JsGUR4cFVr?&w26_5`{XZscgk9z%@42yzM9yl zCv^2bB_b!2fGI@TsCbYBTs{r>&cEr<^^C=G5iMRF15*b^k3c;n&IP_+KzS-X3=-m~()a(ge)azj9^zGJB-DbZYo86!s4%>H+OiKu|RtK|HUA{w7 zR~VuqNwvMS=%i-Wn@FWf(6z3K@vU#RA_t2W)7 zy+hWlt8Fr5AD_e=Pip0rNmqhBfBH>9|D6-McEZxhxyTYMZDFM>Q;lf}&1olOq+Kmh zD?f0pDNRE-(vy)o-pnV+P`h$=YFvz~bCS`v$6tSWb&9K-YcO>fu`AxwLck;*llSoe z5TFkZo&*995n#ZG%j-)l+zS1AnIPtPT?aql{OTNUpS+#IDbx#24d0wv$ZgN=Dp`!$ zoNCozrDVLhZrL8-wi!tGpfG0RNz-+L$$Pk-YH)(F$wf0Ca3RJ8(k3=tdhC0E7GPS! zxdqrQ(5;r>!zF(3G4Sg@Bgi;`(vF@8HGm~hla*I@$I%haD=lq?S{qXfV@d=oacZ`E zr2M_BOJCZM3L6bIVCA!DV>S0m&Ztg&jol}p8SmBIuI!52SYc&OqzlkoxiN17XU$>J zMJIBj%4^7^D1v}P!0iR_;Dm5|#JE~70oQ@J1G^3q94K@k>JVe`hJ?=KRh?8%Z?R|2 z(drPx6tI!IV*PY+a|J?xqfRmS#jH6Bw?Wqgw%c{m$C^~K8WU^^w?Ii*gV|LVl!T?4 zzm(|R8qlM?A~3Uqnq}cu6v@u7d&!mU6ilqASguX4sIQlgKF-Pq746EogKd{RfHD41 z{~d_-jz>cFnuy|Yh&HML8i}C_A}Zh_8^wXVA;o=#f^Kxk@+HJ6n#)|;Tr`@;n`lx5 zH9Pj8{!UWUkfB=Wm_(A=3zMbEwNPP&i=;8Yp&Egip7z^ugJ*m#;Zu!mSM8i&LyOYpf3rArRaRTby2>0SK6;fREq(FxT2WZ1wq0KO5&% zGPcY;^!KK%&6NRdKV>31)j^V{>>$7}>{KTf4+keyq-Yj-X1kjP#i>lXXc|Ebk{(P; zFfBm52KNiN)f$VF4j;Tt`03LC_CET5Q;3Ib_NY(kV%nr9Bmp^>PR6>siE@_{ldPj8 zV=ZGiPt2kXKSJHLi-4Gomr1z>jOOn}6RH7asoc1>=}FMYq!bpVHPzA#Ex+ zN1D}^iPKd(^rA}#m~(c#V0#^1Tpv7Oyguc4UD$!C2gqTfIGsl+CZ|Hf(NIaW8yJ~_ zz8yypvtj(-Zm%&6TP#-#LrK-dNS&%CS#wRI)`T*9Pb_SY);U1MfU5OMdhUbr+K_V7 zv>8j-iwL%Js@h04l(Lo$Lgq6NY(tMGAO;P0rT{a!nb8tBwTdvwb0o8UeX&5+rxs}k z#hG7Ny~b_Wmo&Z^sJZq)cAX$4k$nTX|K1-i?<>&+*HcSmAmdX`&9+F0Ohz&7P5iOE z?ku;US@9v`i^9#v(ZLq>Ft$M&q@zL0L#&*@MDY0ZNn{TbA*8(TG9L+&p$Wj`Fahx7 z!GRIfQhW*?ceKN}nQ*?j!Wab1ak6D5+-~lG?SSrZZGs-CY^EyQJ@*_FLlA7U=V=d_ zXAW|y&Uw*xr+bcMB$PO=}-1ugy2r3y%Y2VGMv2b8G5PC3{0G1%EK-7cX z61-aCK`5H4PZWCEIGI3$rQA0na7HEdX?4pDOy(oCqMGg#Uz+9GKawKqhGMy+i` zPzVP%LyMR-kL=MgScQj}cSzWSUz)$1;lO@meKYFXy%uJS&mW>(&#y! zMClV18(gdtl1Y@3FDqz_`Gyfy`k5g`0e*Y_1@4Azl+0j4$PRBon}k%NO>``aP^1$! zpMMY!=NP+b!ov0NAr`_A;+o=SxI^c6IKF=}lcE)qnFKM5avdWR>d+K&vGA%;YcbO3 z&{N*C*{?}8s@0u7R5F*=1*zc0dHOLmgtjMb|Wv#N^ zIj7(WaD7HNc@UeZMbDUAhmeeenEGfY!}W7;aOqw1W%4EXrr8TCzy!Q#Em4qu8rU||4ijf#36cjS}L}nwNS?lWkH=DCpPz{5$ zgPmO@W`7Vg>#qDGBsGz%6n%&aw0=|2e-2kfVZhndYXlM8Za28tUV$kxZi9&0BXM#L3$f#- z5CbaGgcK+guVw;AC|c@NzH%L|!dRy9fC-N;PVv3BKEQ6X#o_8u!DniURyt{!6=qWZ zN5-C4>-w$7pBS>675+Dovl(V(M(_dG<82`fW(&%y&DQ2XtUL*Hk{d(NrFdSK^0X;V zZcOMFOY{dFKKuZWg82@e zOw;JfgdYE$iNTBnpbIuvg5$&ZdspiY+f9$aF2e6{)_h0^US|%7b$Ki>co2ABn+pQK zJ>%!E{}$i=@P~6Ij*_bsUwW}@YDreI)nq7@2hs*tm84j8?7soVj182Vk->8 zl&6*KhYfyD`7xZB}!yaO@e-ueJb zUX<0xVia5sJ8UT6cy)ws7SEfR`Jyvrz)98_a*v>o6_veowqFpB$jM-0b=olM1tnuNi``1boB;o0daJUkq^ zxCsh54Jy949s#$*7KZ^qzk=(!;`^gAQgZd8rvcosu1#Yh5 z)W;-AUPJ)9B$481NTSlZN_3-HEUq`JCK(gr(*n}EkZV>% zEH*(Ex>_WvDG-yG>n^03?=)kbqd_B!?x!dNY(rV)gL*X*ijj^c2aA?4inc|9SqDUZ zELop~Jv-~n6CeN_0xs@uAwjU>4#OB@ZAU-h?B)Uoixuwmhv<9&Pr%?khA`o5y2OKn zV=P^-JU_FXk!D+^VDc$YFtvGdTs=cI@>J2XDnl$udT&T^Utxz%)Yy{F9mMkc&-u_H zj%MH4na!}CErp{fDOtn%)L3&g=B7kVkxK`PW*2AJmo;b&T;8zI=rcJUor)y9I&-I07aK#Wk;IhpX)! zR!fJw%^eO757E0WKJIz1-UQvCX||}DvfD_*84m$5iA-CIYJy{phPLJ+0^r5vg)tc^ z#x|_H)TQO`vXMXuT!JQ(YaB6-S1W{m1?m{oG2XpT*ghxpG{7f9OcWy|xDTb{%CaXlNg9?ft6yW|A6IWqun=T1a%q)q)PTEEo&}lh zOBJb01rSLC3P=mZ5~;*3Zbd4pF{{4q$Y!rO51sPA$DMj!G%*E)L2&dAz)Va z^~HOD#HANMdih6}K^KjM%eu$fpb7-tVgZ_BQD5>JD?WtCI-XS!m>F2H21(zGMoJ4+ zq+>xHM5;qzHC>SgFs72dK3nT)qaLY2EX8iM$l16u;Pw1OO?8yI-zM6_eJ9Jc zC{L}bd_jOt1hN@HKAu~5(->iJs;L9paRg7dxJL_Y0x*Uo-3@~Cn;X1!bd0s@i-DF# zv-IMF8=GXyThPHQT+s#X!vNiwk+QUsB3XP>(0|v2PSj{sE4{=>tJMCS%E=&25QN^^ zXmgc@-AU5?87n1&atO0Dx@x*nwdb;jES3@c_|V);TfDqH$7->_ZnsUalY>KtL3XJ# z4=STKRC9*}CHvsvokV9n(KZqugY3Wr3^HLYJpu$vx4`J{QtFt1nK4SpZ7jYxeTnbB z_d%I{>Os$j)M5@^>`NTdp(1sUXVVoFH(VIj3<_3pwaSd8-QTAwVYE zS4iHMx^(Zd#(9Z=IHjX!+&>^ZzZP`xaebc+bU2Tm(O4#?S|xWe(F|f|+2Dm?tSyK2 zxli`s7rnL+=#6=mXObdB*);h*nRAMhU{L_QdTRO3c2ciJz!=htdhhfUCap1wrrpDQ ze{FCJNaqKn0*>tP7w-e*={%9*IQilGiEwln$%EPE7n~UH$ykQbAt0hwlk@3%GgyK$ zQIVPiMjbZOlqP)O<9px3caA^C-<*D`&LWwcR}m|YgW{8z;1VUxl?vwunyV6ED86Dn zP)b4{Ss1vm-Ya=G>$OGl>ZP8qH5{llWEHiquktcWbW>zdQUus^#z-0S1KbpF9fIN5 zMl0UBPmek90oNEYB4AW;$s&T+cQ;ra-A^k@sk|g;(%PKj9(~-?=T~%jZ5n3cWknhj znTnvjA;o<~QXHwSx6OPqrEwI>t0 zBsT%XjL%;^0U+3pTSanl$pcNQM!oz!73yK3D8GV$12yPFN|KULes+`*OJ2qU&QoD# zcZq%*1Q>P$eDFBCy}*0N4{E2L4qTqu-%7E*l|3;N<(e>N9BUo3T3F1mO#(}e1(n2W zCn7lXAgnOZ9UudQd?`f6Z7T22B}3m4ZWVE0$ssGTkPSi5F~fBZeaATH1;bWSnwLUy zlEg_cB~At_MzMBeOS^P6s!CzR!)l8)led+Wl}TM~`ZCj3?UoeX-_+E7u~DutRI#}`JoNgeoXXYumy`=*p46EW8I&W>fB{M4_hu?!n{y-wsdY{Zgi*mhA3*+z`?Of3@4 zmai%ri+F~bf~_X;4BvzX^3)%Y8yni^*Qa=O{TiKHU<{MdwNEktCM#Gu;Wb1R5Me@1 zcLVZDHyuh+J8A^LIjUqo5XRs^Az(nj!UIRk6;7`%@!;SHtA3Tp;ZjrsQ6`fQFE)xR z8{*2av;u7~GEa45~NKTiIy*hs?XPd8?^;pYt7Rd6e4lR@PJH=8=ux$ zBIt?H3t>l5&EwJ&6##hn!h;bsPLvRA{fHMgS9s^>2#ZWwr0Q6p1CipZ6H4AjLqcOG|B={3+Nhca~qvniS!9t&c312MrD$bGKzxLThDpYL`u>Kj!h3_ ziYQl}(({DwR0B=~^c{m7Cp5+-noV7I1hK2L*mS5s9dSkT9tVsGK)})B06%%}kMMVw zpTZHL<7x*jdhbfDheL&6LQ6&DYHA`%8)EqkVdnW>$XOZzF-nBiZy*>8U+b+XdkKQ2 znQI0o?N&!5)`O$`x%hnqA8@tVp!Yxzhi&i(h?Ds`bhx1@dS$4oxQe1-1wAqQY1T#VF7N=uK$q<6HPM!DI7utfN3`Z-1imM%*Cs0VXAm>Ezqs6^0A zytA@n6CE0&AXMdHt?fB!PXQw_sVnL+QYegaantTql9{+|L#v;`Vm2ejcx0aHR-yL# z>&ncXWyYb-V~}XCZmQ9!#ZhoiB&W7J7UCM=iptfwfT{$MwiIR3XNgi3&KoUHNqa%*^i*FuQB?7ou4p@Adq0UnJ`TO_m^uhDQ*x)E`h5&Mm3=5=T19(*52n$LH{ZR zy&Uq2!K=?dA``_TY6>F5kVhiM(2Q+eeD;k=44XY)zL98}gmy}=&#z5`v%5pW#qJtk zoV`fXc_rzI__8O@Q^|@K2qM^ptvYyZ$F6H9r%A39cR}$u7sVd!sDmfL1WB+nFiZks zhX7#RIlR2P!Arcx@!=6x%S9>3vz3LRzKdn9x9oV*qAa!yQZvWfy!bqUIxs$X_yCue z7kKjed4$6~C%%9f{c|N%#aSXxFr=`Q_ylpy5T`m#2LYT*21lF@T4r!a2Q32>;?I?U zo1{+2vcTdCZYu74`q7ZNRx@DcZ>V#x=aNk5=an?njp9Z)Ls6u$EY@R*PMm6&g?Wlp zp6(!l6V(Fi^fud9)X$SRFh(MpBWhJVZ`Pg1V?LY8L>D+_LPvn(xJ!3E;638cxqz;V zh!>@EgwhDj#m77Ty_0tH%aAN|R(Ne}*1X2Yhu^}h=@wnzC9nS)-7AezkevqAbrr2* zQK|P$p^!X?h$1zLj^E7+&@7@E0Q@*2 zOd}T5p%;b^*@&4DNFoW>V0__oK!YHGR!Pc9C{?#CNBNgNFq7dmoc`16;>I}pPxwEIX^lE={ zC7+ppRkVKWv)a}Cy{acR<(5=R)et89;)`FWgM<;tC#W(g`_TIN?!p*%PUaoaQ&wRphmSS zgP7n2%LSoxz?7yycn9H7Ah{^H3Nfr97hvH`-%I8_WSGG95D*jSp-=A6K(oLsnq2*v zY6ENKf5E`Nl$rU8^@2s)?;Rn8^1 z+WRs^h&}Jp9TS`*ILGK$z-}W5Q)-VSq@W*dIK_xQ$vHYz@4wZdZsc1j8k88G7`KCm zgaB8bS(=~n#z{>#s%*XdMI$ryQW$b1!7|0$G_>-pa3sYkgyhSz#h{G2!kz)i5+hqv zBPfCy=D8WFcX@qv3xLtFUUX59KWfDJelBuc&R0NnP z05YLR98!cT;&ip!Vgbg2`lO7SpZ_|Z7NofW^Jasw5@cl3EXVTI<=;;W*V+0T-x<(J~0InJi2&^X&CY3^(i*fq}bwhFIMax%?lb* zk`@&wDb{R)G7U8km@pQu!+Np6<@U}n`jK|{0HvZX*z7!dB5eGKgRaA}Ut`@baOVeX z!+`V4OT7Q^ZT$rlf0c@2%4`Hgh0d4&7c>y8ZI(z&*T~)j*E!scTm0?IPq3SI#c3-- z>fTI&mZnTF&ih3U6el+(fslugk9u+mn54t<0ANROoCsCy0bvAo@lbIgPU)s5lL;8* zEIl+j5FtCC001BWNklkwJ!AtHv`Fzy-Z7*2pGd2R?vW61O+MK;|}4?&%6E4FGK2(ui!T7`KzVYVJNgdxpO|eG=hswJQr0D$iEud8f?nKusL0 z*qBWa%_1kWxrY#82p;2hTiCfl+2|%da@4L<{r{!wF$Irt3^?f5*h~{PlgIVu4kz0k z4iDC9uiqf#3U)Q#lxlNz4xY!r`L_?_=;D zuV22vX54~{KS5Rk=!PJ}w8@>Ds@yOWrx?J55lg8I;K2ij$AIfNCV()-i7prC{7i8Z zfUTukY4;~Yb2~P{Jjg~*0%-`VAraPKDK~-Hbd`wAK}u>ztk)nyEh0eHBiy(fHXphn znu@Y=mC`gTS*WB-Ce2!=CCCYs#{rutRwR}?E0Y-lMUG7l+o4Q|BXkff4;eSF0Qdk& z-rwA$wq-;i_kN+oZChELXy8@a1UNzGdUVvO`~YbXlsR!%j8jQ+r!-mTR_jeF6G6wH z=9*hRtIAst(Jp6h&)3yM4<*h(LnKz`Sn)y77O#8Ybu#)6U^{r+-EGh@;6>mO3#=o; zf;wD<9kw!I7p8O#?E1wCr?V1886s*UBu#)zo%^aXAw%viLFNL14}!B{hlzla=)WI!*Jd(C(nJcjEeE-kN=fU(p2$g>yhg^B6Pn{| zc3g$@Vc588x-di%!o_fhPfwpmFJXyhFG7MqzU+ld0D`uT)RBv2D2|_L(Jio~9=Fpb zvH2MllNZI>w>v0Tie%j__i*s(Wt}A8WU<2ac8g`#6;rCdwmT67^m=NNa>6@K>kFW?d2 zF~r%1n!R*-nJF7fq#}~jwTKAXH!eQLYu(lXrv9N~3@_)iRK zNro~)mPn?cZ)tmZf(h&)qkC36QRPxrqF5EIN=f=ueH3VBw<~-1nH_L6B+|L<0wYb!lVC`NTO?+(DzYXgbEoy<03ADJx}q8TN=2jG)nn z`h-^R+#-ppKr5BHn$j8C)4ar~w(Oh2l((xxD48O}GT9qi#GXZRypdA~xVXM4NX&$| zT67e5`98$&bL&S;8I4SaM4H;cM9D2NB1m49(U6({&^v!IVNKSKw|=i8gv()o2jQ)L z1%PntCpZpRlPju_Vv#F#WtnAw89{wh(7(cju9J(ZX@Dpxi`ui1jn6Z26UNPq%VEkz zilG|_ZLFAM_Qc3%iWsCJ%4nE)@`7J{@hEo6f&?;2?KTmMd4B0b*<*>_Yh_2>03@0Kl~IcFp0q4;fpraQiZYSZ z7DHg0L>+_4b2fBl(~FTDr6MAgKT+cr_LNR2q+xs2B<%Dk>Q(L5cvZm$9G+gl3X&*Xc4xwqU1S z{R9Z2j7pbkX;d~PM?w9*Y~iYN*z?V<@?6!Rk#;)^3N@h_sj=7w2z%G^SZ30*AP$^i(5PMY|Q+B?CM{ zBvdMuP7vT`7z>g!h{wj?;@#B&j<}B`PpXU2{M>s*0DZGV{|Y}?)Ip)cq;v{f>*Qxz3NyQ$~=G80|27t1Eu0PpeqJm4RGz;F&x$LzQ;dPAsCyCg#z5=~aC#VQ_jt`=S`MMRs zu1?4rgq5N$iu6|ZjwaVd8PEtRrhI`|brT(IPJvXJmHMnVcCGm!5U7Yq_3~uf z#@lJa&wl#}e)#@}c<1;85a9XMIX*po27zF^n{d#tu^V@Ie0_#7cuXOxDm?{wkt!w2 z-&umzL~QJ9Ch--iM#+!1#u}BiuF05jqT?KBkv)pZ+HMMQ#0yB!Qw$;8VTy4uKH$hL zF@_0Uzrd>R5JH>~FNO{H`WoMO`>jL<^f19h@=hKv|vzB8cQzBXFepyr6>tIr@Su7nR z5GKeF@Z>Z??#n}9cSmr{5ax7!rKYS&oQPOzlTz(nwbv>aV-DjpPc0W;47n|kQgfg> zyw!p}C*?4d3Aiz?5tBck(VL0_xjLPjX@^z8lV-A1_M`a-4UGv&B2|$J&Z)WE3SlT@ zw03f?jha)2LwUDO&Vjgt>l~K%;%Rn$0W3P;>UzX9MGuB4`G%W`D(zPbNvV6{SE6}(hxk0RsF3qbq^9Wi>xU2hF43k>#YZFO^DKpB| zK3fRCc>Ec*e#Fn8eTJj+7Z4HL4ZE`E`r`5oOX}j38%B7U;xQm9<4x_mDrlcRr%qu| z!7{o~=@y5TI~bePCPH9QDuMXYGg-1!UR+EPqA3Rfoj7;^1130O^ynfg0heS$gw5!2 zGY)w4{1higYn-gsU`}4gO!)cpXLx*eUf9)vLe+;$z(iDtFAM?;VGzOOJ-&BxgxA+w z2%>x5;c|)lM{8tP)f~O>-thxGzj~Zf=^R*br!7NX*}WESbO}<8(sI3A5x@loc|jNi zFJAzzC)|4*xHxy9&c$g-7(rZ>F@@@rkaO58Y`ZT_4Na<z*_21Ec&ht&G0RSK?s_QiYRWDY%sdP7WA4NiS)(8()MeiRudH?3#TI4zC;@g7 zKih&`9B%{|$AFj91`n4j5HThRn1V;=7zf-pxd(3w`tN4BOXY2l>e$*-GQ-Z?_=gur zo>lj(e;zg$`r*ALE-s_LaK@M(UA)5C<_bu$qgR_vys_|Q0-9uu(|GXkqDW8$(&I9f z5;al?A;oa5`zjLUN?+Uw#gNW)vruxw36_ydjCH?;pF9SPfO6vY5@M8UA(8-u(h5)~taCt7c9R$a36Rv*i;2c9jEa)r@2_Z9f;$$l^ zOWIE7I)mKu1zU^Z3~N?SSY2gE;nSi_GqXHuSl)>KN@AMBD*q{su?|n6WE-ocXyR<9 zfH)X$Y_S|?o3d65Pthww=OL(XgRD4|%;r?N#3faR%RcUo;at2&$L|AYrvcjyaCqRc z+X=?eV+vzbC=`u()x>jf5FXPk&gofb4{9!q8r?A6>(`a_OvPHr*h$xBCQg4YPnZmt zppG`O)iF#E*HZ;W>f$yutgP*Mg30Cy6w z3lb3%iJw0}@N&0V#9GJB5n1WQLzaF-0?}N6Udo zhdgNMn@P5a|95#Yn8R=5C;aO4vC>S(7ei!%C(Sq(cp2&*jR=R`3OD1BQk+l(6D7e% zJzdg}`l`G~>E=b}EmPSyY38k#`bm*xF&w%WA1OhlEX9Jp2_u%&RT+lFk+?^+$wUa) zZGmAsVL=@NfZMysg!f+X`Pn(1-<)IXCpcmpAFKg(czrvjPZljXU2(C~(`AYdknsX}uoqw$ukx&OFm)y>y z{#=4b@E+cK47Y-3XTZ_B0QZq`B|c7(!Wm~t5PX@$(=#F3cRi>noaP~X1WQ=cJ}hV) zzzUqMpnRfPV5)8Ta#P4@k83^Qg)G-3R@P3z(NZEeE#hDt6Y34n$%RG=N~&396UAv# zyF^Q~1l4(hDnTwu)|eUW96FB0oSoqKL&o1d_Lv62`o2JXz%Y7<1att#LUL0QFL0X3 zgOOoDU4NDg2UCqR7U0497+reTSW9J%u}pPgV^StG9M@C~7aK$o-0ns^dU1|he}_N( z;JY}xyus`10srT3KE@P}A7E{Y`DLKunl&j=x{`Xn}iPfjm!y&KE$GD^Vt%?6uc zzz^Pg9}C9?J;|$-v+V}=7i%~WZnhg--)>`JPI%H70t_=i@>!RaDT09oUMi=FDVbUU z0DExYiXbJVs!%IfsyBnwH#_gdJ;}^?kt8)rMDg#YbY?5IfRt4e6?Bf&Bp4)4^%EjO z8Es{yHo^cz80W))F$hkU{hNaR`+kIgVk(ohs1>GCl2|g1oyL`n^3F|{@y5+4vo%Eo zgLsTSK7bAmfBF0o20uY(K}jNUWI0yOEEi4KAj05*oEfBDwnTu1>mVT+ypYXz(vT1} zI+enPHDMK$s3q!JkkXd|*i4&R@JY8cgh}Fr+7Y9JOHf$VtNRdTc3p8~O8dT!vANsg z@!dIgVTdo71YF;3VhBdl!LR!T4i8p%eRZQkbSfS z_Q`!f0!|K&uo<^lx~@c*vT?A=#XN&yX(9*Eg-8TkcZc}n@BIP(^0Oz{O;aQiNr3nX z!FzR~A*F>yQYGaabYYEr=Qs&Kb2LoZt>d{UlA|_# ztq;0=P6Rr-caKGq+7DLwp4C^Q0qcvdR(p1n&YxCHeQ9!pMQ44p4a{jIZPa|PZEBok zsT{>?S_&4`Jaoq{rQ^kr7RL;?0uJ60oc=jsyPGg>YLixY2iY3{0Ytv4RHzo6P(1PL zjSMVyhb)BNE%5O0e*6qnRXD{6OR?8Q#psrddj@{<>;lg(ukp^wA^hZVd$q%MVq6V^ zKl|)AIOz}Kif`xfr@#6Y{^TG05DP_a<;Ez7neomykFmKKaB;T9>+K!RuWvAT!3bZ@ z!kkYqdf;!KKF9ro72dmdj6>(J^8x3#8(a(n&S{ID2_Xb@;#72VDBP36%1=^LCs79K zL4{|-$+~$#4jnN(0yf^q!J;u2Vuf(!Yi+m`<+>(hQip1l^#>={@Eo)gDze2|SwKdD zM`~3WAQ%x+7KVAX!D&sg@e`&y|E8e-z8^ky#W5IDAi+mnG*E-|G9y@Vakc(B=Z+Ub z9HofNbR&I;P|ze3wtm7eCE`o~UT)6u>h{9s;!5lagM_O6B%N49rJzqCfVsocb-1@$ z;^oa{>J$YXchNW9kIIoq!+_Gdyq4~TRazXAgF^=v7j0zWtJgPW(qBDI z^;5cNixi48rO3iuO2#D9$e-`=^*L^Ko7nJBEihBsm33frAo%ok$4PL0bz64aQI9Wh z<+CJaZwR;@H+XPxj3JEJj3d4{y}+Vd;N){nbjy&DAwJZ!wm@Yk zTN3s}5_-gDLMEE~RBIr&dYo4e_(Eu+P$z4%F1NdC+E>s;62m{4(TEE4XreC**F$H# z>xnif+htK*wT?zFF`b;b@o{QPWC#{UPY!`2LKM=jGB+L}H^^GgT?~<`_MBWoeTX9D z-Z>n;54aWK$rE6j2Hag|>*VPE_rVe2(Q6M1h^mHJTZ6*3C}AUT5b^1q($>d>2kR3Y ztqwq5)c(9GX>v|{zQ!H`mo8Lrz@sOZxO#nu+i8o_=Qq)gR2&8w5h!2-f%jVsX&?Q1 zx5JRt?&>l+bfTq;tEt#u6W8bS4BrQL}q21YZg2iiqG;;qJkJTxquJ=Z{J_w>MDFK zBUHb31%1liM5)^wMBoFka;`{Ws(Vs(e<`+-0T3nx3F#%u@H1n%Sm6HA3a`#@v6)6} zMvq}O6z)$}EcX902xVOHC-L#7^XyPYy;MnO4DJCzcN815l>=2!x2p*0j zt2)@SKHalGM;YXTS^1&`JmRhR72C@b^ z#@?2+#i%l}AU9KV&8J^|pOj>Y=f3zA@lko~8rd=4`pM=Ng5a93M=(iwI=;9#Y^Bv$ zHuP}l@WFeBxV!VXxZ6gPC7+n)p?afLNxxDiq-NQ%i+fnEKJJU2@z!@8b{pXJOW<%h z;pRFZcmcu$7h|Ek7TPC^-b^lyIbTqF=?J;&TzJB}$M1kbwT&%vGu!k* z2yiov_`g5-6hHdtL%e@@h+jTB#nsgYonuUX!XzU`5o`n)Wl9Wj##VOld2cU-XIEEv zaea-m2M_Sa-~M(YnN{NFZs((NWEe0E9zAs!LX^MtMDQFihG1>~)qdJb)>0%SMB;E1 zAlMbf4zQGn=4Fy`l?Pj*qbsR-@xj?*!Wev}up$8HgyBg*A)XT57he<5qT)X^ zoRRGB6i7(|lUBWtZu@23l9}|Z6&I|dn^ZUsTXHQRa3T;moL=~}LU==p`~4HTm(DBv`JH*cx~{1#iMcxeDMF%u}Z+hfY@b=l|rN;(z+-Utq))0*!zKb8NHH zF0-&P$zfvL?KZgE?NAfOU~Ddn=_RF@Nn#wY*SNg9GsL7m`ftS-Fdb(jq8y|QWD*c0 z;A*@p&TCxjkn-Usg(46*H4K^X!l(v1BYUjS#m=3i?89H*U1RhfUFWcw2DttZ&#$iW zt+yZI`|o~)zj^+fnwW){v=wbx*~%U%B<(3-lo2GI4G)v-G!?gIGEL|ZFzq~Ez92k% z1-$bu;PMlIwhrQ_1g*O|eTEuIsf#xy-?bWVY3+JB6QDj`k>8RaCy+@z5&Ir?cEDVd(s^BRrfvmXs-99-w%7KGyuf#*+v+v|Xn2aG3Ygkjua znnrXSaCUtI!5Hs(x&N`4hz+bO@vd4412wgQ81EiE1cD^UosAntMy!GWQxN>cZ=PVc zWBgyAe2RzbL%6VjIKj)|8oR_m_rb^MJR<_|QHx%bK3wj}ql-lDb ztJ^JB++#aTk;ofj0q+x~GUWSfB!UgPgIYi{?Cd34x8}oOhY2of4kAiOsqmAHaAj2p zql`6Pcqi6MHT!)~n@dp)YowlMqy{%3CD4%e4kUxccq%yN5{pY}qA$3NWX`*!wNXSE zMVn&^;hPWF`22hmuV)ZUZ;WNWLO~Z%`o+8#2c`hriidZ=B4r{IS+j#hmO#(I=(o7K+h9A57<`<}W9J?r3-0(au0oQ-;9*rKdKB=W`M{xkhu?9lTPOn?so z6Hf@@3;dt8q&+%-;>$rGjFX3RX`dhBOZCO`SNQ1UA-?nAL;Ui^Z|glFLWdqKK1~K` zI;XlBj@QyBUW1;R3WQ%yGOz%8H+?$|s1rXNh+vcmJW`I%Pb;w-S>4>pfFL1Nj z#C3$EezTF^6_zsrOdakoSGd}2G0+&LL&3^6M?aPZ)WLzqlp`P<lhsh7<0o+X6*kn;uG=!|d=8Ob*wI@&4 zP-62PiXtMf?i{{x@*W)55NB3^EGHh&GzI+CXV0+PF?w3yRy-cx-lBK6>CbRtuDJMl zitj=s$rUF=iRuJbLXQ|f{rnOBy&wG;hv;y-8}aID6CDpRAUi*fK9uKwEC~Rv@GCOe zHzzTQ#HuU_EfcARSSB54PxYpt z|9;_`Ne?Q5q|^oOLhQ1-M2yLaKvN>VOd<(BiqPU11XtS~)?I+(XmBw4fGJEVmz==p z@bdO`lv`1kl76OGG}F|Oy}_XY8UkGCQpYQmkxLAs9{>0ce~iyRJHyk9M^WBXzQ2Hg zjnbm#u!~U56PklFHWd!wI?V!-9@f;s6D3G17H1*FAxKuJ3`$K4Y9UXBE(FZ*001BW zNklu!N(XBT+?=Xfu{BH^W^v4cI?+LbB2kbZ!<4TZA2a?F5{{Pu~lV?kg?9A_X zjz`?#4f%3FCZ;R^H4rtDY*9_ITW0EwT5YDCOn;&F(n=<4Eo7}0)gr|vSp!fL3k9GO zQ_gRGcZvx2qlF*$h?`|(wRXKg(qJsBN@U)5Z(R2?eBbX=Z!1M7I`voKDY~yp)`^~N z>i13)m32|zR%e7vgF;5d`?&XIKZATC!zj~&B(|?ao1~k!|A%yB7;9 zHADqAU6)rZLVi|XiQ}9S>{P*`^4gsPu2vn}p=U@DO_E2=#m?a102R&J5ecXUv}tHs z<x5Y@C^9BEc?hTP&LyGdI9I|%#3xJxY(mjEGSD|5@Yr^=iG-> z?S=bNn(`Uv&tW&fzx&m%_*d`$fM-`%dmjH}Ii@sU(#f?g`TZL|zHudzCOdTs)v~I? zwLYg4=(Bh71*s}~kydr5Z6i!7*}iZ$xxKYEEl$PD=T<85=N?VWo~TnSFmLm7^VN&1 zs`Lt=UUr_2HS0%|HCrXF31ZMkYKKvTUrt|LMmhIHqxq|hKbSmcwRM6FfzE$=!eKM7@t0W&L4mCA&qb4)bo-D1&xjG zsMS5Lx)-?#FiWsisRXG#MOR9Y2G*;NgJnRxq(N78UhmL~f(PF0ZmY{%_3u zmi_m_t!G_7_+O<2v9b6_V?B^2317*KuDC!@nxMS)V9D9@j^5&)^{r$PG^)J*y(2as z+|ZM-m|tJ{9?1k2p$?J>Ay0p_4K!`w_?vKk3TJ1+ox8&72DU@*mtuss2>@Qkh)l`TezZv-=4+iT6$W0a)eTan*P7XHh4d2NPV2qI)B6s}2_LWedi2l7f~s zFuq#U;@HVkk!)KVQ{d`1)}QBYFrJ>?jL%3R>DfMGRQ$EXS7L$LTXXsIE2GzZL!xz? zos{XUPgSBn^=b-Vlj8pHug^|D=V)`pTesh4p$k_JQ`O5RSvc3lo@Hnp#8MKdk{=dh zm084Cy^RN*iScrK&FT7*!?4Kv5U-L2VQ0HKew=JW_s;3EpPdHB?Ei+ywmWyfV;ui? z2?Q3r^Y)v3{`fO8UPULfiE;dj`hI7E!>b?}MlW&MFO_5c?%^$NHk-)~(mlLL7IKJI z3Y_T_xtK?!or}eC_bK!~@_qQm1AhC(3uM@i{AU|uD$$Y529n39X;(*>Al$!w%!})F zehHIdWsn@4(P%C#V%pKAfo0R=V$2$zoL=+x?YDS*^|X%N%>{PGFkwB*gbkN}w&=kz zV#Z$9MV4`sVxPzTV#KbeTOaVzXT}fS5k6mntQ2iDr*)Mtv*qxXVt*VF1JgLsaWTVW zOuMHvF9f*aU3SHOonAr)kvCha-5Ch)>pFf@}H+# zEr#Nro#aBcWHzy6je>#lj5Q&!xsI6HB$>)a_>4f;4}AKQD<^shLBihpZxAA?GP{teEi~yNTS!?H94iU2<&3u zvnL&!*byyGRPjIo~>VS@9-YqIDCtP<^U5|4;!K-UaZep^;?$BjC%*SxII5YfX~jJ zlYlpm?s3r0bNW|R%Z{Lrv&}WnZq7*p{ctlrU<3wY?e_Aa8a?gmRax;URHIh=({;h% zXxGF(3C=K$JbC`I!gA_0SZ!(!)G79y>cO9gznrL~R<=*x@e;URcTPpKO4q`nGkM(T zfR72^xvD!wh-PdV5X-i%!LtAQ=bt<#k(IcZ3kSV>3-zGRj)GR2d;xgh+-mNeUtVv0 z62PRcPqeBu8kjW=tu}0i9;Tx%f#+9iNNxVvir%0c$gGWym^-v2Eu{d(f~xb8A~F$I`xKQhk&zDzqAC zw4v)dq7HdSoZM2Eq+a?pms_*#sqg%|WVUbZ@sr@bqfSzyJ6v4%!)gH*iahv+joI?hz4~Ys+9Ub2d!488-a- z`A76|OJvA8g(*}@AciysEKzh7)9@Z+ko|38brDxXy5=jL3Z_?UvZ&d+*X67xHD0v6wDrPcq?h-Phom z+OAkB+_R&lg!@Pto69t*ew;9jj*0T^8ST9)fggVJ4SxOcb9O|3M`FDzlEF6hBvoe8 zAeL>*gBb&n!Q$7Vxc`)2r>k>L4sUU_z2e!;W1inU<)B$GZx0!w&`355v_a`($J48q zJmVadF-+vqZ>#IvJS zTqY;^&mZa@U1%qJ_Bu+lOiC)tPgfFT)xHhnt(pZuBxqWTy z5i%=4)Fz|meBiXIC5;tCIJ}#0`0Mi>L!>@yOr}!$is~C1r!^)zh8Rr}veI-6Kj~3Y zFYGR1v22(fDK{^BCyTwpH}}sdXy9Nm=k~)HPktMnAZIiMFDRPDi{8mrajI)i#%yY3 z)MyG4q(%orpqUGy4;jDgpV`nGs_Fx!fNDc%1I?_VT`2c|V4OXNXOE3WJGSe{5VyIT zODPw9(dvbkN_U=$V9F+TyM6AS`UNwJ5}`>m?j77`-pttzJq;~M@+4}#i)^|L3sp|z zz&2$ha3jh>7j&99RN?l~oG)Kq(x;AruKGUmfGg}_lB*PL!r?cMiruDECtL%GLAG@Y zCn#sD8@7GVckjJ{#8mO9ql2bkYhgRsB-qL(ExLG{1*~=Q>PE z#VS4*$w_I+B;&K|^wjcqz?m5n>-l)*iq#@`I%yNfU26?K7{z!8O<de?{)0nsB8lJttsN;(RM<=Y{rW=xM^*09ak06~Uz)hah+GfX-1Il71Qub* zvN<3{Wr%r%7aC>W|tLUgO#6C7pF6VXacUrn`JsnA?8R zSpM(ENYxR7lRLRE8QEj7lf>X~n4E0p`^aRj)OS>4VbOc19SUj74}cFp{i0%eBSu?x zc``(hVpr5(0>D&>nCzY_sarN(UZz_s%lAm8o6W+b47fv>nm)8SJ3&=)&-{~J> zOy>UTG}+hZ=O9@Id!!-KUF9)nVP6;DdVR7a{~7CU%l4B#Pp``FbKy|X;L7JxjEtG@ zwJu2$N}Sm51$>z$t}k{I=$`DYpz>tHFZ8A%ER^;Z9K9v{`0tGER(R*z@Uy=*hTiD< zEs`7rRW1Xw{dBB4IkQ^$<<~yy0H(!q7Goap+VShJ;9_I$8g0Omu}#K|41Q_E4PNRx zn`E3{M1&@DEo|%-%T9Z$j}e;ujMkN3w!__C%z3_ES1yMNlkvAADNo_H-N1|WHAn57 znKt#3WRkluSe||`&2RHW$Q(vvMNL^hJDpt8NyM7~qZg|l?@@axudohtlk)JvZC<=s zaW#0BLRHi|nN!Szt|lZw{4zJGnuYzwOD09*m?g3Gq_@^Bd&!H}fqYq)!g3-NsXi+M zI!i<`$9|_hhsW0!`XBgZl2xi*?*a*l^^2d9u}(K^`Wu3@%$p@g?JZPi-0Zf@LZEH3 z^Kys-J&9J@Ooy|{cE}H-RvLCG=A<=88p>pgI5iVX`OuMx54{L+)yH*Vq8#1JQJjdh zWVBY)+}M13D^s9`ClwkPNcK3=a1-pS~*>mt@>q2eO6leoi7CkPTa zoE>nz-658DuBJv9!erQ|;{;=pxz;zXcAu!*gBb^H!=~%87-5KP*NMYBMz@Om{8uyn z)qer6|4?~)Zb%={l$AF5P!6Nus+h>dGQG}nH?Ae_Q-wYyRu?_m=7K5~i=}_=Rzz?n zl_*=r_w1oCM_Zn1wsaleRc>BpEkWAbR~sZnb?ijN3)m2}T7blI0$}OzlNS>yWtyI) zF_kT2Sf}r>R%N=D{i10u1SyUoTiJ$qecjV{TNI-odY8ME5p8lcbQ&*oo2Jc9GYz#q(^CECZ_&t{F2>v-#Du6J z#s2Cdw2s7_84x%=UeHI7o$-y=kNM*16)V~LMcibqy}$pdn)YDUHr$@ic)D8EppxWX z>C?@&uFZ;obsESruK0wEZRhj)E7#)N55-s`lteNJxkTFhIzuCH71y2vr{ z_i^9LZoHZW(NBxABxw8$o|*u@RE z=688*d5`n$6lZKW+bQNQYEKj7(Afzf1ymZqJ7>11CjRZUqA^5jB4CeV-adkd_^#F^AZBv(XmT2=~D z6`M%zXsh(jRsI>GJi4c+-rvR8<~ThlVO z*Kt%X5z~k{S*uXJ1`-w{p@Eq;^j!po+{JmoOJ%B054Z_t;}r?L|AfZPd8~}yFoU1!m7_uv6T%$oSa=76=W(3qoKllxD~ z&)hMfDR6nyp){B%rx!aq$J>fI<4^)`-9BdB?Kod=yz4b$QZBZUAWa_2i`7EOEZh3Z z-kquekV!^_xKBJ+E9dJKF~Pe>_j35~L@QxF-79B8w1lR7hHblnltv*glY|SaR@huT z+V8~&!YlJ7e~%J3+ijhQR#4T%0%8@AWHlg2CONWuq{aFzfH7}a$8U>kp`yVyMR)K- zhDj$s*BRe^^BzBY{A}M5Q75%h^$76wh5rBNK6hN`WM{Ys>(@HED-Zhh?gCB9tZC^| zuC%t6MQJ@LAEr?Wlks?x$kUsfnk+T-|4s>CRJogvi6@6#l6@PFO$Ax?_|?guGL3)s zs#8m9T-eKIM&elg%7pzUVZ8EX-232`v+2H8yfe?;k2t+eCPKD+VB&e|f)XrW$dQOh z;NIdE_ii8Z{OpYD?P?Sg33Yd_1X^vGH_9$Xq796sEvk+{U8x*o#)JE}S#P^+7cyZc zZMD+%5snu}gdi-Mmecih?qpp+^X{E@`0?Xkx;4*xKMnQL7Dka`6&(70(G*$>Buyk8 za`ICVO{NHOAod*>F9L79J7;qPfAurrProbN`!1Yai3h(3^p-F6QgGU&?JO1{pOh?a z1^QL;h~C__Hw&ffGD^05CUw6_9??tiBFQGn(l*^sPmY#~pw-FP-UV_J>&CbocscWV0IAbukxk2yr-;BBfHDwjt$+*ligk? zGz8F8ZAPhTu}7d1k{t$NmV;Q1zpcz~3BUMv1G}yA?RVin{M(-Et1T(^grsiGOMB5Z zGO^An>fKoyO?Wa=$XRvz&gsbhAFS+2|7F1Eawf|?XYJtRGHertTN_{BLbNMz>39KeSMcFo69!P z24lS&yhxU6jVzO(G@(+~iB2g#-Rc%q95_?nlSDG1v;39KpY=W=vA4u89>1LI>cv+t zSsNgG^Nan|zOOIzf8tlF>BLgG-}OV&2{y!+JhQPh$>($aQf)cX4Yrry} zNrLZ{b;8Y-F-2>l)->m+>!jx~A4dln9|(CR3e{d2Y*m}r)T>;pzq~^(-53*4&B$}l zuOa{chI{h^&Ufqjz?Y0~ru*}02C)^P2vuRO5}4%6*6@PJP+xPO5?8A&sL<%lyY*c8 zx9(kUw51IT{`3cL@zY;FVlZ(&H+#aCqHd1#eER6|$fFiz)-=5P)*Zfle8~_ai{+ee zzki#v=N%W@En-9MJCA0!I9Z&qj%$A{`E}2v^<=3+jLT%dV8O+L%Am^3@@hirI>bK* zGb9e!ZcCcYXv4tGYT)VPmft)wzWcti`m`|ml%sor)w8lommI|kG(I3qe!(hA(+Dw0 z73K_s5wC`7eVHcW;h$S*l;ueS3Y&{Q13BFDT~@f2SE!l~;nGPIglFka_dX39H5@5- zTQTO>u3=PLhY*+_wjAA8PCx7Dq~KE%L&}q$8iSc2rO5eLnOcTQzQ{{nxEGbPSzx!x z-?0=yLN5H4hYg!+|JG`DX9R!Vll#uYQfUu`J3kU0KQ*2`38W!%`C>uXUAAEky%cy@0z#1cr$Cb{>qUC(GsTb(DVwuL~ zYITD2L(zXsbxf0nj>%;^v3!aO>It(lgU2RKc}c8QLpM23TVg2)M9xAFR{a7;`wvq&V$Hq)$rFp zh3~y5y!OY+>EC9b_xeiFMzEMh;)>-XxDjDUR(IIjn=ucdey%pcfW)dSVHDg*-s2}1 z7zOdb3md(^$t=Txf+E`ZSUHQx;*c}mV@lQL#4A34^5df>=)6+;;N+V%0PIsxG4;i`rD+1;!i&Na~$iHuBw>2a&oXFm$>YN1-Y1CB_7nwm4UtM=;YD$Bfp0R|7g&CMq5tE*v_SV{5;`G<`Cc#Y zpK?}repqq`mcI~lsa%*;rMRSWT4tc-q7wc>DBhLG+qYI;pmU0I-3O8gzMVbUw zh-EaP?`b6!9<+?Wg*pq@@t`o9pc9!yp^k@5@l=+Yd!&nv#fa8zX%_iSlhc^6?L|Ci z&UeYAo$=t-0iV2h z=7(9Ko(I23<75fpyHQn|kbxqWayOGwzPP#}5oQBTvYdHM@uTN2_BU_6%Ws~3=K4Rw zOc{vvf*fHz;th)zBCdOAV_+yfg=QDo&vGKz{QcgcH zWXQs}VrP^zVUMSj<9KcS?CM}N*zYHo`IxU&t(SLs2J@j`06_je)coxNvlA1MAsw8L})nXYK47QdRgCC<6XRqM@HU6XEf~*YDyosq}ZWee1_0)|NiS-oL;i+FTCUP*C-80K*NHg<6F!_;>GD# zzCy_JpF6kayu98}vIdik6Bn5<|7&khV{yIE5ar40ngkp!7S6!1S7LRAu7^e%8dYxJ zIpXE{b%y9#thToGD(&Nmi9q1?$%50@ZIeVqtwBcW)WqC(n2eKyD$^}sCrb>H#dA@Tck)z4{?`}!ANaM@V|KO~ zcP73!%ADi9;Jlot>tO;qF>oo$y4x@e#^L-JLD{7qGkCeV$#xQz>U~TkRB%po9%&bC zWZAdn%esh1inSvjuE8dF)@myX_0J#0GBB0ZO2w7h9*S@}dY4JYZyue8NdnXe1JS7x zzSz}h_}0S{K7YI(zb?W^p3|ZpZn7FU`KXl~=^B7mS`KE)@!^bTr&r+F&Fkcy}ZTc?y`DelL#|fI*IVg_&%Ok_y7PP07*naRBwvi zM3lynpXI$1*FzkU^ggxhZpY%UxA>c{Z@w~ROb7#?4P4(@x^+@7i1*owYl zYALK;s*0=H&5Iu2Gy1q&lGYJ(S|# zmgQM+-Z_SBi!v`#mv@C>Ep*$#HJVaA@-m@&NfkUQi@SN$ULuLh{M!0#!7JiC{IXn} zs966 zkJC11;d_u$l!RFDE-Y2bWT0^_Me#c~9L#TXv^*jWi6_rigy6Hi&=QEGSP-$<&St8p z9`h&v<-2_OXn?fh$+M@J_FiBHY=}9}-DYSi{{ECBbG7C8l3HJZh*@y8NDHCPxlK$}-=8cyi=Oy==MI_4Fp(UK~^ub;+8L$;2?Aq%LOLr~f@* zdrEn;;^)p2zL)1Wd7|l}#IdND#G(|t<9I*6GFtHV#RpxnXgM7GVimn-b*WO&-(q{$ zb1h*TM)6-!*#tKSCdu}@BEXA2$xW{7s?W1eTl3`P>kIv#{B_taxh;3O>96Tn=L+8Q z!b`O|g<)qfOCpwswZLA?7*fZ;j=t{*ArLJRE#!~Y0!`CQ#(_pkkv9$xcy_%eg@+Ltu6EU35(++Zq6@>!?llHjWz@pp}{P1e!a^|Y~SzB z+Zm5Oy&y^=IytGTLVaY~N?;b|RSB#p+63YNsx7k+c<12*nmFU*M~^`heGhGDShNjy zPma*g@c8LD7neJd?^cC83ViqW8~pOcD&t5?1ZyhfJlRvXk1X}<4YmL?pq~VjKte2G zX+TnsbsIL9Ef3!A*{&L%KX3WTM~Q#={lLvTk?p76%XC0gBti(nuu+1f5nM8z`lz}0 zyTq*KQD(3_`ZJvby2vyS+#ujAb444Y-xU^Ie*K%X=ph`2ZGjZ?h%)#^<_BkSBSgns zs)W%IH?fJwP5ynM$puT2$u2&*2Be`*utHE|5Zam2q(qE)Pi|%myHeD+M|%#bSLVks zY#Q1o3o~<(n$f8e0@4a{AcW({ogWHM9>ec`3)`E>op1E~_B^rO?jR0G>=F8GC5x#7 zqv}qU{Q#rnmv-q(Gn_~#a>_u^1>d;y9%>MSA*w9q$INGQ*4rDdHehrl4K?z#_@{sU z;R}d?VYorHuZd|wMsxD|3NWDwtnk-pqLY&JmB#uh^}wxU)Q9sk1$`Maj?TEpoM5*Kv4- z5AAiT0G0&_o}9o9#yrm;V@S-(6HdN7dQm z85m_ES`?;v`jG$JBqjB3v}x9tgV7CJw*Bhs3;hrMda-@Np&s#I@ix17$Ys1B%21P& znBXu+uV~1TpW=27VjY>MG|*emF!Xe>2N60|7A&y7r3o_*n>pXOb<9VXS3JJD$q(@m z+0qd-#~%i5+{0VH>J=bUEK-F#Euy^h`U#&syYdQkLYS+g$Y~a{OeA+yn_T@p)xr}% zS~N6-5cYh=hiywAOZ=c#p80_wa~s zee0NC{o*GP*wMe zYQD@Zx+_2xQ6moiKKLFn|Cxq_+yy4dolz-F3s0v&a~el2&kwSrWVebwu5@@uk_u8e zyrpa|6T9;FM7-d7$PZlEJI+m zTX{Zrj!RW5DT10ID2_xP3ztZ_)|HUqD3ji87M8qy=Perd>o?5-$A@?Lv;Stn-~FYq z>9#osLRvyNCdNoVTodW(`zz=1_b&cyM!1t(Kg}B7yO$lgWV~{p*EZRf8c@wYhn3H} zQh8+0_9`Sk`r5}@t!zbQ7Z z*nKD6xlCLpX-fJiX_HQ*8+;coHAo>RN?J_{THSZc1)QJnxx^qluKFDbVJB0oE4Pnm(QXiSyH@850?Mz$i>ZeBACk)f!z@6UOJ1`awmHK!7=BjyKy3* zdE~Al1Z@b-jK1&q5C7W>L>P9Fd9&*XRfEv@mO*@^#{A%{%<|^9u-;M~^|cyk66^`MoK3P#TQqFIMP_b?!(sR4ZIS2|+k)Z}a-W zUCwtmdB^Dcv{0rrJ_c197Y1p~l}D7QA#)1qc)Kv(%`fzX#6-7(I7GVb!1?1D|NgIx z|M9<5?*6fH{xi>GE-Lj1%<_IseDzRmM3!oLR|SnhEh@3EUP|mzU%ok?9bTJ_f=2&6BkPifI@a|cd9|@Z?LzAIRPUY*jkv@6e zlua|jGi@w{hQqfN*$Vv)9Dc*N{zB?LQc-5dd4iETm>noxPd-R(iegr11eptA0pXr; z_kH1$M~TOeVS7FB`n|;YDQq@tQtTiOnG_jQ<&4+p+$w+!4tg%4w^Zd=YC;fYU~pDN z)`xuawRd><;6AJMKtu?#pw*T~A11n0bWv=B>Wn}8mv8gp$&Sw+ZRvX>*+5D;f;p)A zWK2OCk}i?v08&RB)?gb*5w#*x8*1TUq98Mbl*5X;e!^QfPZuoRbDu9%8?n)g#hjPx zfqAo__b?cIL|$WeF|IconuV}zTVJiHkD7CYZYB_6}N|$Nxme` zugAOTC_oz$Pd3{;rvDoK`k&xKFBSwM=lu)jVaZW@%w|w_vMIBYDvl6WokPiBF2fV4 z+-b$=(?Ak9o*l9p^6n$rz$PYkwxf+LZJ2qd=sCa?A7tKDC5tYO7zi3z>MTd+xHJ?HF5SlPda9*bbamwhZrZ2 z2^~XSidaelKYI9m{`S$&*jlV28;XbyMWm@t2E0ozTRhXulnz$#skV2iiy4{*WaxPM zdEnu90;@~o3=lg*TOUCt7`FcTHp1c# z$Xw_@&lkJa!j%eRsPwsOWmqS=T_Uc0<)As_MOBFFT!=2-6>O)(r@3WHzK2@e5w=&E z^)3e>2XOaKjBO7;{lK`nfw%6#r~fcu(h-NAG<3{VSZ&u;l(+Y)EPzBGuPRap?O`mU zDM2Dd2-~o1mwe;SJ2c^tS-a!lxZ&o!<@JY&r=M-<$`mZvo)7b9}_#U*g+cHq8TSQVbOjxEa!8KmLWx=uenO{*XRTv z&qqW#K3LFg0*Nixn^cnzr^@ltJ74d%h-OM-wGWTp;ZfrDN@jb-T04bP3R8h81<b+~9thClUjAQe^4UWs<=@789w)YiC+qaUtvpnP9Ku z$Bdi4qw71r^iz(I{`x}y10A}J)*=z1Pdl!=$U$?+ak$5IzoMfb_ctYWP-3-Bn1c$+ zmwQxzC;Ak*HM`}>Z4q+?V;7As^~|(kCUZ{OW7^Qrkv!+Q9GE_COp#66){$4^p&KNK z))R?*_N32NGu_X@7LgGqQU+7*7q!V{sqQa6S~jeAk-MKYlXv6p3f1OW$`;t}4sL+S^5BdD*4JnIvy<5yHgP_XQ`4+Y0yYUv1 zdBkg0J-6D>`)*Q9X*7)lJcDoFdzYU)`UOEsq$ijvO$shd%R~Cyp}T%U3s)ddRT@8_ zRBaNFllk?em{sq)$mNTUld)HBvXCV#_{$_uN(ejbmQ@@H}`^ z*gVg#H6}>gF;;hX>ATmaSmN@3ZdxVwpmXRi^K-eqirL$4qeeu;XixIgth>p_@#@Pg zM#8OoA_@VzwGif@tszUHdDl32p#05GjpxsyTP2QPi>z0$-E6VgW3i_d;X3wpb)s$$ zHO8(#cgJI1L&<0e&i{`LK1R(Gp2PVO_m5uV;4re;7}w_=$iQbGcf^=5iKrS4hRDD$ zTrk)G7PIg+w3)k5RN<1>gQ|hqEKffU50q{e=u#m0nUEbgE(ET{zE7RPoLLBnpl&j%2{{KLYCZK9&;F!v+jm2bu~++ zrOo^r6jJ(9uPP>5`xSWsl4nX3Imq_ZNX*UInfm z2aJYW_m_WS>W#dp6hE^owfX5|55lK z{#)bj4}{B~Wbe85g6$mimvF7Z2zqG`AnmML)k;)+3I35v#~3d~*v}MqPZgpz2?p}9 zyk-ksYTTS-BNsc&%mFZ(_}wCA-%Y;vJ-74#e+fGKoi&ZR5Xhmc?D!5`l$WC`b!(AaD!r|3Gc!1Ov<1;uIdl1ULSQTF4X0`i zT}~$pl7*%-opW+)$=S^%L+TMT8V$sl7*f`03-H=q<;BIy8;_=T--~&}Fl3ZA4rx-6 z4Ck^$3}k?mhc6YYSDA;Gcx3U5cNESQn3YX<>Z3KS`2V*%Lz7mGQPrkfMl>fIqg!lJ z{HAQqz?`*i9*!haioB<`C8yNgIX>X>dgHXXF@nX|=h2VZ^8+ys#FRBPga2%~){hnH z_4S4RPx;VACip_}5t!0ghD6*9SEwnouwWMExw}sN1Wh=OIZNL3t4trW#BSK-^fsMk zOPh{XjhF^hm8b(xRxdbcmmIeTtZc(B_C!kzL=fS@(Sobhj^2uQR;&LzXudof-z?`U zGXFhMb0|ki^AS~7)n~POkjBU4!i%#md#7s-_Lvm6&{07ed{U4KFhyr*Gebmp^x;|l zG81T7Vo{@Y6~E}mn_7}Azs z{`f15!PTllN|A2J1U+SB$p=^Ut16*snH`<*+QSpBA9rkT&PXw$jdFN!KpzKU+!5M* zx!!wo$=Q>R*S<05#iuu1pADnf&Bb7U^7i-n>hd{RZ0=K;AhfZ~8&T0onzL4MTz=uf zMUFB-jux&@*3{-(Frq2)__N46@5B0B`0}$EfAh=4fBhpR{*kc$b-plBNHMnuxjP?6 z(*2F^byaYNNETaKJ{aRJceH`AOBtgs^QE0q7Htk4433CJQtsMA9!riJc(>zOzGQRl zYtX`MAq-o_3oeadB7#)3d8%B6smDn6AST61nGjMxK{3=;ka4Xbqtdt}@a2y}@`*Gv zYzZeng4Du){J^-nFj^8Xe-{~sM7Qf;h)7DbDy(9hFe_{l)u{|lW3!0{XY6Dhe5A3) zyn=8%JK~!U-tkK-xqUX(QLr}3V%czU842pTh7{b|)NpkkShR;o(=((ELmWskUp+w* zP23@y?Acznu<1g+XhW=mFRbwI3;*2(xxtG)GDdl^XlOQ#$MwQNI|EIuR=difJG zA~YeeY!>YLJT89Y{t?e#u8FR2lw{R*T2?A?QiSa>*C%*vVJt+m&CB+Rznr=#qmJFI z!dtA6+pMaMh~^f`5)@S6Fg0+cunxvaS1Bk;Z(nG7=Hr3$>zzLXBlK!a#!OCCjHEO$ zq#jEtivcS`ED|lp-X=+VAfK-<^nVmAqcvQlLQ_p&fea*eX#=LrWzIt9AVP1wqoPY% zlI`!HstckJf(AdV@}6znB`MJcx?w{IGj_IPx7l$J=FFreSwuo0ro`nc5@g9TqRa>d6eA5G%$P5a5oy_Vt1LVUGnPlUIk~HxJ-J}FyCn8IQV(g{G3ZV1 zHd5!%g{)Zq=%+6+8LDPsh#fI@nFeNs=vO+({9XiAW=*J(rK$>HhK4!s|BD4b|F^=h zZAp?58TY@{^7Ip{g`J9U{bEZwJU`E|{eRpx2lf@xPcC7opjvAXV%ZF%P zi)lsRYRLt#+}4&6VD$!=@6s(fZ$6?n&<%*~b(y^7A9?Hi^cy97zI6w5(eZG2VE1f(7IG(^H1f zL5jpQI8`uaizF?#kCqJUVN~}ArEO=-X2Q*CO-e()*ewU(EEg@;Hy&$jiL>*KbIY@W zzwdjJW!q`CwxvpI%$VOqBXg9*>C0^fH)&4KYeeX}{QH&*VYkhtVXUC2%-xs_s`m@K zI(?D7l<`9Qtg3=k5W}*UM^NF4{_mue*Q9ZBHcr#dlG&J>VWX3tsR!M19(*-u7zB)H zd9{`-GNg{)A~D5^)Sc7N20@Z>6Iblm`WhrVcot#)^@aY2JM=J)5o@lpIY7a!VgyX{ zz@w+DO7{a@&`3i^pZBiSf-*j6)3gS)2|v5?&e;=w4AvnQScC;bZdX{$=B&DHwK4>; zJQ^l2YfAiN9?_Kj+2_w+b4mFt$Nb^br%I zIIJef?&!MSope^;Ota#f&lhD-qY&3sltz>XuN`x7w#$~Gf;L&-@b~|7-c70G1h7Vh z^DnnF;t{YGvIXjB#`S5>v(LJm9_7VP(EOz$WhcU)z4Ish<;OpE5l_B$dNB^#Ijf;B zlC4QDcg6KgX!|mm@>uZ}LtU4twU%(sh2{#u#&AjFR`8(y_zs?C@FL#N?yi*Pa zL&@2hh1gxlG3IWd)=vgeH$^RWgBZ7BZT) zol#*%#gJqXY@J`Hx~;Mj8ZBGd5YUAe7CWiCf0#s$`oE`*jj_NPYo9&n1u8ZXL6wAG zLVn%WSf;ZDU;%alcfSK)y-5809}-t*!rOOy9{nm2G_hNEzN+cbWciYu?19VAP>TO* zWoE=Rmvur0uJn7|=CYmf{u}S*qOub0WSmwQ+`bn$JstAz2@N#L$*lv-jMLLBy1jUQ zg@iz>fq8Slty_V!^BelU!&3Cun7BAy6Eu6tgD4@i92_h-I&RSjecTbFQ_4)~x5lmG z1G-_zyZmG{&5T`_M=_>GD;biMKcX-Z9Sa%)K?93cS?_ikssqfL!0|!L>G`IT)l|m} zhFaLj6k|;7n5WNW%@UYs*@K6;49W5ZU2uYii_Eg+vWo-TnAoMBl#C(8nu`#8WhtY5 zd=C$vS7@0}ncYl1LmWBnBEjXc`8h0x*B&LNKG&8Km`MXMvWp$N*fUsU;clK1ZJma% zcj$lkLbuTtHVq~*$zc4(8X5KuKTWX2HVggabQ}{F;xTmpKVUiD`HA5W5?;{E=4R3kXoKU3EY3v z*jz?VpTd9mDg5_;5xD)na=uA~B-k*4beLrlnqT0tK)XyRh=o{3isqmeA^11chWs8S z@}*w+O6BzfeV?(dg0RC_6Ejq%$;CyZV*#VZZdOPfWhY-86)q)9UD@UPI>GZ1Cifq4 zW1i#g?`q0FYyLTHg4OimBgmK*D87|9f|CM$*E4U_FR~7j5&{I7@%rnBY_4{M6mv#<;k$c*adfz3vl$2~Sl@GV z9$AEjg+d<^L-aAS2qz~?w%d-)y3f|ym^hptpbT_fWU**iuebgz`NduZp@Bu)aBv`` zAtwNefkflxdZ6)#HrIfN%&34{Mjf@5@uUWFFRwRr3HmP&qSjwvuffReT zX;*jT^AKoFs@OTDRF&^vU+90>i0*sWW-r04=BH`G2s9FCX!8dtj&Ah-8&V?mTR;3; znlPy*YtE&*r7d{nrk>D~a(;RmcW1^Vr`$``NX!SKjqrnY%#7z-^OkQue2ZrXczfXfkGwpe@XMCQ}W?zkl*~?F`xeW3Zx^&3_5B2p}%$5vRZWxWw0thoCSZsN}`y+ z>ZWJbv`$1TDM$&4#`b2Y+3n(}T@humP~Ld&h!?-x+S`=OgsT9 zLrenAQVCa{LY0hv_TG2-@u$D^{Oj!VzwU21YL~3Keww3MFYaR6E?sk&45Dj-osC_( z#0bNH^~&m6Ssoah%fO>gm7m^;{MmPv!|hm6RwuW(&1a> z@0Sa%#KM|?S6(4*SK(_dKrocu}ice zf3MYl1{LKS?;Y~lCmTYDwPfF2^(XD1Wk8xC!WRw7fWNtgL~NX$avcjQUgHuf|j(Z%Ei?FdB* z6T)BeJ0OVf(Tk(S|LN0EV_MBG{ZfRa^4k1tH_P9rZLvC&%bQ~6P{CZ$eV^XspH zU3-(tuP^jJaG!^oi5?^iMb!Drh5us`tDvTlhF0c&s3aPXMQx>^9kaM%8+%MLn|!7% zt*E0?wSM8v{e?01l*qo2jXM5Njc}4mQZ0ufrBhXQal`K(f0Z-Nf#YS%YM1RX$s%pr zu#NqqxbR*N9Ie(!k~QWv;LV8c~{{ymsrDi>vhrRJ8n+$#V>$kJ(z2_jPWA zq6f)JSwVUE*_MXD$*lv{*O6N@;j&xjLuQv~B-G+Y{h&Wy&WJsEiv#QF?=_6z0K5q#%ipnoS}PleDLq4y-Km_66I(^VIt<-fib{FC&xni*i``*f+l zr=sD!h|Qj787+P4|6cMaTi;90=3ex8Z)I#azIR38^Gw|tggDW z*NEqgbj!HZEasERMP8=gg3gSzNbnF&-VQu^oOtvIwr6mn@bt69FboXcjyMdE60HVq zHrx7q73q{Xa`zzQ%dGb?>J(y{Y9VMXU<64E&H%y;^ne5o zK(g7a?yAbieVmAJH`Br%?s2o(-OFBN5=2#X-p4s{BHYYA`yQg?KKiyQh&=XaQcI8< zouQu7wukftsmy%iB?GbS{uGE8-kghkx)+knD2S*%_SIbT!uuKsgWtL$f?E@x71dKBa_DSARbyI8GAYuQZ{5cr`35BRy(>s`x*waIz?uw<{B}~#Uc<;G7XPTx^#SH zx&PrmrPS1FD-Cr&lWjh9+SsTo0v9T%v{)f$#@-L?z86y8=dN6_YsVoCyBf5!INS>_ zFqRJv+%2njYGzVU)tIt&6WVJEy=v}wjF_BPo@on zI3m7eti%pIc_Nk?e0-=$vVQvff~}1daP{V7sU6q|DuSg}tjmJRi_iX&3{fcK<+JJf zKmBA~{HGfwKj1i=RnCG%2Wk2Bc34az^Q2C|DI6yEZWBwJ*lbAIS=m)OWK)m9l~D}> z23In)fPJ+vXO|0xp$;>ywc@}27ylCf{%`+3?0bihP5dwIhR1S`XK7wAB@aSqz}Lgh zG#S2N+x6*yoo$caLA`++;p6ue-~2_x>xYU@h4H`tjpF@1@Qc4<{HAr>|41lJK|Wz~ z^S!dO;5nOrg>;vQiKUonqnsL={aUmJ^sZ=!LYtn1Hun6CLZf1kH%;ekDU4cyQVCqW zISNw`Cfnr}c*uvR+p$eYD4eI_B}ZPjRz}U3DAY`!z1vQe@*!D zN%1%TQStFNg4;*Ms)8SXRP=VB_Xd>?f?(Ts|IFM_DAWk<(6@=ANgEm7DqhMbkF^n` z0CidAfAe4dSNO#p+vDzK|2Yd=ixg*$;eI$Ka9qpz6($Zn$3}tce{B z#FY2YJ?mbRFd4bsBBPJ%>1Z~`sm$VYf4`10&e`F8Hf4zk+SggO!|q}JDR z&34|#)6=}JgH>)_j`&0@@p>{y1&Kn~vuuBtIpt~H8Z7ue)>aUA7L320qD&_%?f8^~ z7wvSG{2AeauU`38gP9+Vg=B{sWV;~C35DEEz83U9^yi_h0IFw`JF!h`#wQ>yHipBN z!6FBsu&76h=t?WNRSlxQW7}2tgpm|ox_JyK1Jqp6Xpx?ks~M6$1q>9^zlTmU;boL0oWL2oxkF}g&8{S|YY<~<9yW7iD7+xV&Nd4= zM^K67G!v=Yl6ndr8zdL&j6yKt5ql_wm~jh(O&?$Fi9{?q@4l~*jKqOuWHFJ-|}7OY%x zDGM&kg0pd@iAS+wPFm2>2&HvtgIRZ8AlF7+BkeH8A1|1%v;?AnWeP@>~^OSvL<(7GMh)8T-XMr9_~jYd28%XrWBMEWH7NqG?Isu zX_8y+q$*c8cvvQantD21ab{-8_`sY2ll+8}0Z!Vs`h>_dUaw}NM8HFS;>%#|6Elux z#F3BNC%o1bkIOx9z@49}`;J=*6YJ2mS2n|m?$b<3uWm|aXI@bCI>Vjv{Y!Vhb%)GD(iYK;N~W_nkjQOj#Y|;9 zy)~O5NwvasJcgVtGPoyUXRaJX(X+|%=CutmvU$U6IGUzsypmcIP$+fr8Yy@IvwLl6 z0{p|P;^WVOpFJu5$A1U>_&xCaTcEruK0S3503rt%4U0Doo13wK%?QOb`vuB?DBB}S zw%_h##jYzE-BY_msN%9U_wYt@vk-$~x4vVSeaes@J_Vfi%9O@XDWi1BY2|{YR4i=f zNDEgi%vgB^b1@ExH>jL;sl`wck0A?mD`J`BS<%dPpLi5Lv5y9B{JRy;K1^y{?llN* z19Fb3IzpXA2Wf7^Tu>JCp0TOXR9SP<)K+z2!aT>&r45Y#&XU0?>T9}j&S~ zL|G}qS@Vq^++FHKJNCYzi6v7OUQu!9XfJXNMX}@gti&Ff8L4I7eF_C=!UMPpXwpv}1#q}ec+=)P zdBN6iU=-Xhcc{D?Lz8BuEwY#Z=IyT9(B<%Su#&}v17fGKHB#S6N%}Hd0V0RHnu-@; z&dIAVW7P$Og35$n+`sn(q+!WOahk$z_*hAR2z&RKTK}4ZCKa<2p3X+4V`ZSzZVNNa z=6cVrKvUD}b82B0;-a$=#$u7VUc zj5(ZZHZ_bRGr;6X)-Ku@56Gz)nZjc zs^&JHUC0AJ2=!Nl|NI|;UpB?J8?bGPoeJcR(MreOF4(sP?Ksenj{WY={=GG{w&7?u zw059%GXxRoNk&!K(R+6$bAxI}_enkOS!?RWi+N8fY{0`twi=A2x`^cB107t14=aVm5N8^5-!ykJ%wnp{H2i^=J$)hI5s*%-57f9 z956|T+nE!={2w@=8R8-d!4Lc+H&D5s4zVcEMe)*JvG9VmEEA)BsKZD3j(MAt;Aqn_ z5?N3M&e#P8WF8RuBta!_NL3GP{Rz*<2Xt+?tB-gnj8dz|&&E1r#9)#J<{Pi8j0MFB zuGcey@U@`-GX-6{Gj)-$Zghm_&(mQu@lbnD8VW<2w2hrRU9cVKR85Y-1q&}$V6|EY zFZO`y#C#N=NUPhpf(tHnO&bz&W>X~lC>u|o92z@h$E&>Jwfz>`@rwKME$)|ZKwumu z?gjJWW-J~cLYh&F5sN6o87+Fj;=j9}Ommtvi~l6wzfMA}h@=>h*c?p}w4#>Qr^^1& ziMj@MG7AZvX|PK@h08)CEc&r)$BvHf-`}M9VcMqyQ!>_2r)3`{>ne>~Q;ooEwz!3@ zK+}}BOkThlMyM>FZbeQ2w28c8;RQq$wN~R6lxjb-EGQ-Zd$C<|^)&zptQI9%I+AJK z4+3rktqftpMuJ+b$g;AzO{t>jm~@=#i0TJ12u*29ojmmDVA6!j?oFil>i7vmzPk z>*gzQ>WZSt9{lh$7dm85!xcbrU#}hyE2A-eOZf2hovj*Lo&lOJZ!;%j5YlpME>1uZ zNg^(2Bp;eQ?;hkn4p3lIlMPaz+zVau1_a?#(6sqyx|ziq8f=!ST=O#Y%M80+SbVIOLhcI31S3?0($D4A$zTI<}^a3BtaDC=6yX zLRc~TTw_XiFb)t3irW61)%M=uB*$z8MjIf^X6elpP{QuhO+^93U__O}+~E8ZJ9}3VNh|iGNlciPvPj2KIjj zV@y==a@??%6_raqms2Eqru#vGqjwMw)^U#p5QLX*2$r%nH-`oiU^1q;wTu)kk%rzB z)SZav&2M3!3EflQ4?2wQ#`8(*g8sV;`p{p6JtLisBZ=}Km`UQ%73ba12Rn1Rsk-(w zv`Ek~;`Y#S=wSsy=mec7r`;Wg7?vr{Y=`Zo+K%=Svjt*>;tHX65d90cpd?&)LE#Fb z>Qgy6^ym97ng}MU5NT;qsh~Unx;>^SsL8lx6tgf4f`?3A$tf|?gtQZ2QrA}oDa>aT z5y^d5f@Lw8r#3a6!^goEj(n~NU`~NhYMw*#7k0b}Br^GgZId|V?u^pl2f0qb$T>$O zP;o-@jAAA}**w^uv&3}o2N35T+TdB~3^cX9IkErKNMSbZ*Ng=P2Z&77y(6wYo6NZwZ6!~9sO8694>Iq^YuD#S^hD78cJd;;?VZz=Ike1Yd-<1Ws z%=BF(a-a$M_LK=_>a2sI>}jREiROuLF8p~@<=0~pK%70_$M*+d zJpyEy%+EdH-V7<2DM)YKj_pNk^6Iczu_+Wb9c4DQOX|ppd9<)I|3fllucnijl+EwS z+rFa~o0JvdO4g0dtm2aktl-N;W(r<`8z`7Zy!wcNxX z^=2d547TgV9YgIi?`*1okcL-YjC0WsFf64i*!?!$YFgrI?$I?T4r!Fq$GE&L%x#jP zt`WHFs~RKCi7IZ*63DC}VoRFRDI44aGJ+r)6W$;@G7dhn2_u@ll65o!QQ#72#@ zYr!E$e%9*2JWSQq6DFsFGIlw9FKh^aIt*lFtL}s>iHIv_;G6N0$-Inj(9uv-u=m{| z_a3RmSg2xUf^q>=vD7ssS>1iYlhYhZgP73M!jv3MnDo#N)We(oV5JMr`{F6Q`!sNb zz3NEz@rQtzqascj%Ccw85}x*c;R#@3q2EFC)TN`S6-X&bJ~#bkaFpfefk z%m&CjdNjAij>H}#4=-G>x~y30Jw&ZBI%IcKqj{%q=3ACTDc(G*-2-`@oS^7ujcCgi zp1{b&T&nxgBh3zS_f6uFvHr7E0c}uabULu&>V74$aIBNFz&N9MhWK^fD4xxf6nK-% z_H~E;M@;BCb*!8Rn@+C4;>SiTtOtyPH}DK4A%h5S`srb1c;3p7&NrrH$;oOWsF87| z!J)a1*Q*0Ppf|t6$xJ%A)&=1Uq>c#C=`|SqUWOD1L;D%svp6$-VT*C?WYhZMzQuQU z_h=9-TrK^JBCTkc>EyxDjg%I;-R@=(;?kb@ddVW;&Q=MII8^SiH%>5mSZSK)Xvp-w zxK0=eM+J16CTVgwGbKQAgOr%~?V!)cR$ayy$FCZ>v1@}i^T=Q7G8#G9&eb6Lg070f zra5M+ATX-3OR~*JJf^JK&p6m zdBDo1R5-LjyESJE6%-E$G6HxT&6SSA9qjgDw>@T^?h`TjJ*Vja#xoVlS2{6?a+2Vf z7)=M)WJr-N zOTi-M(VzjR>*0KonWI6;M+u}zeVUb&TMgGc$+N_Xng0G8mecW%3CY4#$5ltfC#D?k zf%rvCt`i$6T-WTJs|xgHtp5Xw%ffiR9k}%a@7F7icHmks*remSE@=CX2H?;g6@u4( z!*yA3+Ygtgk{iK{Gc+b_1eeG6?4r%x<7|~^{FIShXwRu%)hUdpy2PQDnkWI>)X5OP zZq2qUfcAF7O>O`RL`d)$^;%F-X!TVc z55)})=S5Oi-{?TSB)MBUukrKw{94feP(hzq>|<^mMHmx2#mS7Id@`~jp!qwH?C7|G z4R)F{gY;xwX}c6L)~q({vb%JSPypokx;@JSlnAZ`bm3#_ELq_IEAC?tjMWy5mv$SWMH>9}aXz3s%$Evb=;~qve z0_m1q)?~{z=GLF_)SpqXKvZ#E?orB`gF#AOgP+6Z*U)u?$blw1njUDffoTO(MJGcd z7h18fqLg(={w6KIs9ht{@mYrU0eX&tjSo%fD=F>||M3p#RLnh)z@$23cN{w*QpHJ4 zJ9PmkFRjeY)hRx5d>@5}ufuCi4m7=C?;Diz-31sKZo*R=IMK5dliJKAoql)cI>&?iBc4Cw-~Y~O32=K-<~J$ zykMxB7M$Q6xei;(3)wY*^pv<6vsjXSEIx@2@XV0~x1OOG2x96*Nzd@ie%45M8gj^R zvTAT_B1uL&9-L-4LiCXAs*RN-EY(kGfZ#DYx=GeI-E}N_V zyf@uU1tSfI-f(yX_TF|kj5+Yyp8SlwqPa-}aY@2w*noo+him{dj^o)l654QUpRvo1 zwLIo$a^-tm>%A#g!m@BSl}U0iJjbK?J#P0=*N#dxYfGS9UuA25Og#^B&6`cdNY_2@ z*x_HVQ{-tzugerW`Z8Asr7bJ4={RvCv{B6s20@;5RN!I@TcD*nwa~rCWc7NCWYLUBxqms}tvn z?{HTXEl^e$fEC{{^I1xgsY*j~6O2?&SbX@l7cf-WnejY*f@0FYi6|5WII1Jl_&skY zlr+}~AU&YSEF|9mbYMu4Hs{^WN7f5e&oeP#_r-6wLy={Hwvz z_2R6GxXFm6EU5NRvXz0=M9HZ`=8a%Xk!PY1%(YDf5KlFs3DQrqA&l>P zyM|OpTIdZ~Y2Ixj2xJ=G`nEqGPq(BlMBs6xxrUSAL{CwvLr$e`Xk@$+@qPAu>Kg~U z>4Bqdw!0O=S_{~NTS{R=7h-HFE71S|AOJ~3K~xuyS-(EkPX2P7gs0Q1o?ROW3lqwf z&{_oQz`P95!CbK8KxIW`HOa0L?v^XI*6_Go@cH%xF2Ds9h0ICwZduUUfrY9)w|OlF z%O1XJq{*Q!&RSN=I<6D929xYG@&N$GcHA8CvO(ukF6dnC-gBca6`*xPzY1SXQrHE* zef}+8m%}pWLAYNZaVcvWel5({_5+9P=+f}gZn(({4%tj9i;nyHEtdL?*-RIcvc6?D z!4*luz@ip!9cPzLE_Q$pJ`sI2miePAdInScE=WH6*%61B{Wncv3Q;&GQw7k7Daf7L z?;t;j3J!V2w!h-@{=po{&`rAz;8k8N70e7h!Cb&%lbVn?)IJ!RIpGfT=;Vfzc-V|~ z9Lk{1AbLUAs)jY>EYV|d8enwz;nIPo4Hq&8Jz}ZlFd*#C4l&! zMw58aVLvBj5tp2VG7Fue;Q=ZwK6NN+t=>FIvh5XP&rrPq5DKqt0h2R}MP?2q2F?`j zdJ2|-I5Ab9zSR#i9*rw0SlNkL4U@z>2BV0bZgj-Zaexy;W~(f zRhfsO323n0nJiNwP!XNvqMQx#AcH0=-3xxjumz^+ZqH^J?Aqgr->o_!RAKC76L%b< z9ILR9WyW6JC+h9ku=fquU?IZG_5ttj-=p_Ep>UNKQ@41q6jMPZ;OIM+Qt|oaBWk^aNW)5IX{$!i83Rzt z>m+$CnuEmT6YuX%+-*+*lLaO-e}@8C%hk>rUhO=P9jI5ZDpp!S^@2loEPQX&G*$ep z{FU9GYD7m7MR&)@CW7u{;z|otcI?tJFTG2Lbb<(BqgMz73+;H7XHPRMxn88Wr`4Z1 zVlRdYC9`-I8kr%1s-$7lDGcCiLH}p}urrZ|zDiH#DD?Ik`q$EovC~_!+nMz~w*jU- z9hzxTcP#4%v@pK8`*ZK~-F55~Q%V>?0CLhu4ubs9q@KC*$ij4nJDqdy`{y{g6y4!Y zJ-w>~2YTDk^ngf1qs9Hwtt(#n&UQ&%P^g-8hgNj5Dbxse$i41Z7*pEk&MOJ!DFF=X zS<%S&S|}y5J419|B+Er(M$@Wg@`JXAt{B64COHzhS;^c3z9m8qmaVzh9k~`6aXOrP zb(l27;% zs9XDT+H4MvNsuYK>vszoOelVTEv1_4T^I>XzS_n*ZYfb}3LFH~KtJ4Ysgk*AiF7|y zO}8zRtWim^P;rT&-EYzb2bt9=n9al84S2}SKGgNTn5LiPL(H-wZ{ljK$y9T7qD&Ae zBa?w(zW!xJaSPmi7;HUjFZgQZZ z;QjI*pY~6<$Z8X$`&T3%z}GFr>S`TRX@jF^NGf(X&?K^K``!WKj{8f+?YZIQIPkQ6 zLS2DFUa@e+$Cn#^xP6abT!CfZ@v-0VNLO6f6(62H6XvcSVc5RzB^lmxvO%EK} z@bUHuA8(&h4MS`QVfE$)q_~!QGnaDJk>=Xeey@->moiPBUkmyl9?@sOnkM+2=_V0MH)mf`T1S#u*>dQOw^WI@cEi?Ru=m3u{mlquZWr0nAP2D46;v!Os!&BO7c8`T zbRkff(+)8JbV502h`-rw!p&(Yp-asTe@2joZ~F<_9}I@M+0jY9GsrjHJ9gw2R1wBI zb1{!5VA|DtS{^Bl+=e9Yh))IdrV;VUQ_p5ZfesS7^uAFyb_UA@DzDqfCHIAjO0;I=>EkPTZexE&j=^${d3eMb)2 zQ)vJIm->KTluPm(C>sn(lA%fEj6j(ukJ_`!v;b_TIz?9qcRvq|7}K4c*R%uJKm@$# zYl{3AzL?pRpNV_h@Y+6usp76)vCx7_>(_$*hyHYFr~G1`U~3JcSDNP2q|fCv?s+4V z{;~u3f-L9E()25yWeK4TrV-r17vZfIy2TT6B(GNbh!y#R++lwPs&JsvLaaOEqyDpt3_1y%Er zW(F4?dqCG7clAOOO^A-kk7#sRnabr8H^C-Pn)J^))W7Tlt(H@RZh^;}GuDhedHj)B62Vh|rw!2sbgI zS^9zq!Qo^ak1!6mx2@Kg-CZ8c1HJd;07O7Yu-OZ7$`S1?ckFVYQo(nZN8m1`g2>+& zq`EFH=j#%2)`Mgxg37=*cMo75SFtzvA86u(u7nGqYKB1UW=PHsbxr~m#vy`*7h4-p8P974cmbAP zpxklDD_+_Yp0-cebVrkh*X@S8_wQ^Sz!eKIZrX9FcjK%lpa><&R%W$;Kd3xmn#0#V zR#xswA%X7LXI}jM7Wdo8dq{_b#{h_K=0`M6)w}xM8*ar;$B?vrE$F{bhd$-^x}3;% zZk#)CJ;B&6UkmHciLpGOT}~TCOoy@k4x1LDV5xs#p%G4E9SsN-xfiwQRQCPXmas z7eFt7R){iwdi@ENUa;~dAK*(_-NKPUZI;%#`AsP(bvg46)L63UnCvshHT}YrWPbc+ zhZ-F_=0T#Gc*!(D_ZWshIzuesTdq98wql1;_%sKcnvxTj3F&a4iW4^`rg3m!5?>(; zDo_3g#v|ag;|&Bt3_Uh0OghJvf&@)Rz)S&8Npx$1qa=RMRT(Ezd}GxGvatc83M zVbpbX9sOX6?8lDgaK5N`(`=t*WzQg}G{INwMmys^HZvQ`4%qvSyURV6j5l^mWtB|! zThtu?;@MQNMIMKNkpR2)Y=TSSR5>WY$Zv&nY7{lJBa#3M4{tW}qW1IeyCT3WOg zg%p(+y!Ow~Zd&V4uQwdBnNu5?0%z+tRNC?M(+j$EG#q$68oD(6c>92t{(_|u1dsT~ z&wr1<{^h?#tt+IPhX4L@@56>-#frgw)GuC>t%yvfSx`|5LFK?@tsps2u;98}@M-&i zLW;X}#rL0njs1AS(^2sG_y8qf-*zmp91QdW>vBOyL&ai*&9Zn?Dp;4xY8CO8V%ybTH6+XlrTu zI~odFQq4npR@nwrYGxRH(nd~%9UW1KMAh@2dGe2sCRL^xI6iYu^k7V;GkP%ooxgaG zK}HL5iP%Ia7LIT`o*aU^1C()V8@B$8CMKhMZO^7(rUgt3Dy%41zTi^sQ6qQ;7UyUw zV@{58*fkm*Q2}Xp2eZ)}*?Vbd!g+X3?z`h!GR(I;h*XnHmV^&PnrO%g85wDA!@_km zKW9etpfsJuRTEWb;@z?ZdQ4<;GLjBk9I&Lq>o5fzVHGNmr$;B!96ZeRhQEFGa6Hm+wx{i=agKv;*w26 zEfvhxs05KOoFBy#`^c?iiEI*P(qYb^j8cr}Qen-3p;^NWMm<4H#UNL~FxVkD3KdbI z{_qyCIUJCG)>LfWP?A+K#hnh>TW}=Ao$d&neiFm2a@f2o6kRrJON&Rqil9_rd%of6 z_zB-WzQ>P0{03ZVrpIl!8@d|7?`3;J@7+vR_6?gHsLOZw^{4N#ELVJf`H1EI9xwXh zBr?HuHCDN}Sy2W6y=k0dsM-1rOEIp%CQrEV6`%Ldcv#-yzFzU0=V!Eb!~47UXtLvJ z|Ab|^Ls7<0?MFxxEX&WZ9XITKM_ntP_ZKXD2lj^TvaXQs$_zS(;bgRF#>LJ`B}|sX z;b%ZDx#Z+ZC4qBduOqFj^{oIS-84sV{GX=n>z`;rpUG6`owKAaVo1WqPW-Gm9ogx9 zkmjNoMHK5aL#O97$*|R&tY-bFpTxwp(hpp^eQw-L$==?_bZ2kTAJtRZj*58y@O@oujc3phxC(Rx#V{S3`mqc{;*^&TS)TuFl@Ub33>Gp;-bqs@Y26x$VIT{8;UF$)q@LORoAIAo zY+b`P1QcgFH=hK_HHoR2C)KmI+>@v zeGTE${u77@OIfhi6`yZEpwxo<`iNhD_!U0xpYiVDot+WV(a@n}QM5naKB5xirEiYB zRCEw-*g>LrxIW_H`VOC-KH%GjZ*X*59Xwv&8_H1_yYA+0*cFEy?!*`9Q9-G9cs`zN z;Ak6e$A;(Q1&1Ce>{I&fN6702r2~QkA76h1={p*3SjrWGhNC~@^?1VNQt{K%_xRbn zzeJaUr9Pr}Ylcc$GHi%pfl5G0WRNBc-C1TPJ}|JblT(Y?#6nIJ`lMnWUhs<3w2#@5 zA=YF;d8e-|_djAjACaFrnV#rODx6JY=p1YSjHyJYgFO$%)ZKiK^L8UFAa7}@Tk>JyDHvq8fhD zR@}$KI0v%X`+G~V)ye2&?Ds{d`T0#&u_l?3(hwyrE7QGB{D2?~_uxTp{Gxf(fhw3; zl#83Z>+d1K<1hk3%92i8{0Yxv%+WVvH8ULSD1EFWH7WxzXvj8^pC3&=2z*k7FwqqK z>+rk~q|YH0H2wT>pK<8?*_8H$3u>*t8Ys!bDB%F-YbjD>ENL{Aa*p%K_g<%lQwqS2 zj3p|fVR zJDxxM6Ry`QZkw%6;7HQmJ9ZEbF?jq^FZk7me*hEVFTVX3*xH6)fBZXKE-OB7pR7=p zf*+rEY{!P5Za?7H+xPh9@(muBcPPque|?W@xtMas6AUXCe0cd0@9rM)!^htM1t_BU zr;mS+$9M1X@%cyGUmx-9!#nIxJ6_u>L|Z1Rt@QyvynK&Z3jXoa-{DnmC|vOI=>y8U z3tqMt++D7?$+JJf#Sx62iHbUTQiSAksG@>!8xDAk*?$yoxK&Cxg~+J8#0^#uPi_31 z>h^U)|Dz#ynjzJgHfAXa222@Kq>eT0xY#sVAHv-PU7*OnrZZbV-lfbPqBF*caksp~-SXZ8R%9};5x|}4Mg*fzNQk5^(`nDYEzMan zM|m)_M^s}j7&Beyv>u@G5TwN;!USlR2A=iiq~ZVNE@E#Q944G>FayS(<%&9Kpmj=I zV&Y--tHX*?lB|a}yY>O&LS_0SC}Ctv!z)9qH^s7Q=n+Hiqx42;PbXh-dP~sE{c(J% zUgU}L-Z>R?dfUbNgy7dlCWfa{7$Om*yL;XI8)+P5GQYQpWE2T-^JqORd?n*Bi2&-& z??Zv^?hoKa7^Kbxu;QG#^&xMg?w{wF{3%I=dXg_nYNFMh|3(6#3Nq5NshmiMr(h+2 zJ=IeUD>EvyC##upEl<3cxrt{r7Wi;!92)zT7BfL{?oC%g7sd1TjGb0oFIUguwoi5M zJ6`*SwXC>XE-1>rTA;MrEg-bM75x3DzsJYR6GRC0rQ)tW;KG(!UTML~3x0O@bNur0&r#S{bW}6^ zr4)DQR0Vayx7YW$?Hlgz9`JHJT!Gy{;4CBpKEA zWj!a%aSeqcYn)ESR%!YfL@3Gtmn^%`?uSOST#VVaa)#|mDJ5^S1@IvMm@FsDn({PB z(rF4v06yR6Tnq(t%J?RqQe{k}NsyZfIl;Xs7G+7pC?~uUW{-y0?dB_V=5iD?|Ifi+ zP&%b~c5ga^*=t8$8PXugWREJzW{w7H#Mn|!#d_C;a*QpQCWWt-s`%khfO#}l5nCvWf!;@_pAg)W8wk;B+7 zdbpg+oGxwcV9@)^aYNz7OpuNj>~vt^1%-Cpm{Hra8PYfbw{kU|b}0kh^Sps*6^kx- z%@G11krFNzID#MzFCP9J|&xP+Ni2aK*UWb%<3^P2A=4rK>XQO^C=znBE z7oYm(^q#4jzHx}tWU5aM08ti)m@WYNl6I$*O!6=*&^JAL7P+?tN@oo#|ZI>d!O)zutQ@vh`I5?*~&995Dkq!rxoc4#K5$^8PK>f=Or6$Bn--@=+7V} z&s>t2j)lbb*3zK8;f5noqoy+H%w5Lk&VIEpw0NRmwRMw3eRLdez%ItOm3 z#n?1A+JO@GQbuLLE;kEPLcw?U-(o#h>`x6ZWy9-n z15t5f96R?a-=WD3h3^0`F7yt>%OHzIAb~qPTIPX4)@S;I-bY* zIsIz=`bPuqQ^A~Z^r^_6z;O-Y5}hEFu`?eBw_?a~q9Yr|C)56A-t}fRoF+G>NqLUR zb39};1-&;nig9N(>Up@S$DRf;D?%O$yDnS_$8q2|reF=IPb=r$H_ZkidhSAFCp3s7 zzJq2NtX#q%i{QMY#KaIjMZ40JenjU?Jo|n*(bB|y%LZYN$3A{aZW9%Ec*99LHt&La zz-QCsuNd9+0O~nEp9oON+df>lgrvD7HM~b`=|2P{onl1A3-jlN- z?i=?0?3&k9(r76TsE}M)VUpx(Xu{6?Miw>Vht)}N$r#qDVN0gBuP0_bzTYb{J)fh6 z(NvO{F>OD&D4w}RDJph2dYIXeuty2g$w!@Hii@xr>}j|o)A?Em?%~fqc@h?9&yzA1 zU6&_B?C)WH~b;RLm_44G?ly zu#$(Dq^Z9ZD)Xl5`C_^zNEbogOluyEQz^=@dLenQ(PpJIp~b zr>uFM&pTV1xEFfjXhgG;<#2MDiw0yg5IMU}dt9=j9AvBT z!lyGgA$`>Ioew_-oehY>V2NqisAkd4<%RErDfuG9#AoCjWK^WTBb%1bYa}IcwCjxp zGa`1=H}Wz_l}ea!p15CvWj^VLozQ1ezi48n;G}H0ha^yE8yFd!m}o&7I#dZ8?PC|} z=1k_>U(&L-aKT#4dx51p(_B)uFgiDJud);q*8t#8{}JcoApU^mlFMpWa%2F5&fGOTm8Z*xC)k9UpGL z!A)Kvz2l)i;-UN;>-8Hv9iQ<`pRo5AbZOqi0VEB~1&20hf5oLfI_a)rdA3*>rFSyn#F3XC`a=~4_ zqLw8OL7hTRRA(*w1f))OvpO;SquZ1&nRXU?Id+Y06rLHZ4@NadXbBCsJ9hRf7Mv_# zRdmu?Q`*|54%-iS4tbYP*b$5pJ7-nfudy$IdA7q%26iALJc^XbFWJ=*_wUgLzL=E;vtU){Gp@(ZZQJ z=&L5P@DCpX_n*&ZJ{o;Dt2wDHhH{0Y=@mVZo8mGxl;OS@G6l5=Ut{f?7QXW0sa{U_ zW1DwX801J>JcCBq<%z&KtcNMkIZ+6V*tY9|O2D<=x!g~%_Z=^{4bR67M{C%6!(IIr z@4xw_Wx;F5YrkPXZYWgo&HAnT3)Hljo;gB62Ue#7U`mDNb69pCL5h=|Iz> zfqQK?e0u!}t#zzrg(~n+eu4LuEG?3*0D!0M6BZHNF=H){XmX%yGjiWa7RF|0t%`+L z9NJKIvmHJ!8KM;Yr5ti{2jC4eSL%LEs)zH?d8-?ZLGn`0|9oRV z^R=M=UJd#@RV$!8c6oY&IguP4|-qGNxTKWpUe3J@9-Scs|C0ec=VydWUtn;Eu0O zS}DWcFu5H9pbTOM4eOEl@GC9@(bV>f1)lipo+om%t+XAbPN-E|C-frS{K$}(VL~(c*)yHi0cM~Px@UetEaL7EH)yhL@F(=aCm95ke*=I1U6>lXKQ2$Yv};yUOV z@rad9cOxFC#npnuB5acbqo?9ciQb%}krOd;|B1v-d>x@q){Ed5xbcWIbMg!QyJB}~ zV}#>`KLce#THMPEFL_UiSOY84(W4>NjzfAr`?t1XI~tS)AGc5V?(%?_+bfz14s?8b z{RUUuqpM)=M;ct00Ce=hVC??#J@-0f}-^f2KI@S$hJM7}cJACF(*^a?ya1Z&e{p8VK z+%k2r!)LAOgiM@2l{fVLA*T#ZL&Py^ay3Q_rFe!o0gx^Lk4;=$E_T$Wi?IZXH<>{k zOH!IPFW<&Y@2-nAUvx}4)^RQ8y)nG$92|DLKPd^OsSY8{-6BtcFfo^pxX%os?>By)ii?2WY@{tyA_1}h=ui335A%!I%xkDZm! zNzwYWGVy}mC-N!3na;?~nTo^s#dYgTsU8NPxI|iAS6s>kaS5S6u29l~+_=a4Bp4EY)eB>`fCU?QPgD$aH;6GDPDn4RlNOR3jB6Fm!BRM-dnitvb6;sCplV5CTS^Um-({u}`X-T2Py6Gc zWY9szo8&4qMax&Y!=%|ncn&LFa9)5&MEK}f=`P!KB4Ho+J!hq1xelOoWrK*THSfcD|! zNcA|{p>8<*86%Xr0d&|qllNe-@Vl}A>x193L1MN0yLHR@j;1v&Z2cZ?-E!{-+QTWS z)v3u5RqV2XT!#+@7F}(ipg{oc=qOxpq3ejVRmEB^SngLq#R$7j+FhJY9~%5%_*B>s zM8%%vs*49Zi3b5mTI2RZpnUfk z)^iXjoh#v~8`P<@)!ZG5BM?AC!)trZPO`X`bg38HZ@Hypp zHV~3TKd3+jlN2s^1Mq+lqz^eeA#9$2dn`=SiyxELJ79Z<;xX=lfQ&7)heumNqnMmX zk2>sMW4~XSQx+9Yj;(hLHG7b7XasF2O=D)|1iI6_gT?YyJ`&#aWlrNt>KIQqDf zd)|4~gb_;NS55rqRVMezd1IIBfkG$e;rO|ZdN5Pk^HJI+@G0(@X!_ZDw#uQ2fI3g# z>dtF~vlKLKcYU&@$xB@)XS#XOkOF}>O>az20zEw!G8r7rLcNYYH3&Lf_-G`%&8<*` ztHwS)!4#U8Dr{0YjOgR^hMyb}!u+R6Pt=javv3lqWSA41JZq65OqNLX=PeaN*&~xQ}P4$a!sMVSjd&|RKnb%U&CP+|3brJg1bA%*CUqwjd_uU1qYZeHr*CK4+a z6w{#AHH(s2ElR@G(cH{XbfOS`xQg%G?TCx%KK6I)GC@AYshGx^(xGmyd+Na?$u##& zG!s+6dPH}2k@lmi%Qt06(;cXtfP#OfVXwU{p&CZ>G z6$?#ia?t?J?s!uKTLcQtJP^*$b5a*TK`Is#I{VB3r+8kW5nUTaJmPPO2gyhLuw~9C$Js~>pM){5{ZD7tNl**um>@!j%Gd(h+T}izVec*%dRC61<^NyMm)K*T-4Wpmgi7h zvWPFxHD#TUCZ6CbN@6cmp`O4UycoeLMr(?UR=1z}TG0RCpU>N;gcF&Zg-DF*&RMr+ zQGq6ZDh8QzP2!dk(7T13bnUL|HrJ!#onyd0T@FuW>QnwWP+Y>n5njS32bH|LCrB45*(>;xO^x2t?#84XD&#Ujf?$j+ib-7)&s~$BuObV9Z3c zA!VZ+H^nv0WA86RD8)SS03-|3$y{dgFQCZ)X41xu40IqJ&5+4mhR77I145rvb|v29 z32xU(;3g?0(kZDg)*n42ie4PbyvL?Dv>Y0fB%d`8_S$t?CH#8a@&q`lU#1r7!~E2`FPR>OQsCKol8>hEx5&D$!Z446MWJK`1SkPHw4d?2xm%2DoNQ6|uqC5!^GgW_e1F3orM?322xEF%7?B zQUZw;^_aBd`{KF}^@l;1K@QZ(kD5-#H@1f#AuEn_P^^vYJp@cH0ksl43m%zdHgtSL zf&W(5PQJBfkKGj&s7w$)2lTI#%3+?SC#TKnq|M($Ih5k9=Wug*ViKvQscg94jZEyc z`jL2VJYiz?w_QA@mh_bN2R)Mo1EQG=Z5OwgrD3dtskpEcu`m_y5g|MXe&%>5Qw}7Z z(+!~~S(^AWY@}66{zn%t>O6A2=kTgrs?OI z@YjO=d;c`)!=cM3Pl(CGnrx}-W+G>oRyQHIv;xrk~l!+;eFFIC9TiWC$dsDOh|Lncnb{sj9rM(RY_XtwTteQ3d z`@i5!ccw%}ggXGU|H2M{vvNA?vM!{xva73763GY;zz%zVdptvVn#{YJQ;8i_jv&eYT56`iX$afvEr#h-0v^n^gk>t>uN_&2dFw+bH)|zCGaTo_ZMTu1SSRW~Vqda59XvqA_<#M?fnuU-D$Y?QOufUR9?ys@pOLdx%P3`NK@1Qlez&c!;6zJzy zqT`y5a#hGD8~OU@C1<_h#qn>KDA|iHIaJ#eIS2ael3gT;Ts=QUfArN!BCIQ)MX~Sx ze6e%GV>ih_ETP{J1Y1Aod%7T;>4h@8cYns*moHyJjLf}xiJc`}qkx63QQQ$?WDXma zIhyt^zuN^F*^6F;dl3|t(5WQ|`(og&Wx9y0lXgwT3|tb7Y)XEX%d~+n@?nY49Tugu zN!Wd5#u3ZJFO#L&iDeY9C2MU zF6c`;9^bo3$RtLaGd|V-{#A%{Q4BBSpg)nL)Q=C z1OhWhyr`?V)6(JjXg9W*CKx0_tQvC4rh$N^kQLok&IvKDPV%YD2OH$a|6L+vn>2|8 zugf>LT7r4NNeBixXjUm_^+vn0-puu~{P*NBlZnE|otDF1e^XK#92vpTFNKu@W&bDV zqJlW`eK|+euok%^;*Dc^!Hmub{fw>{vJC@9h!(X=)eb6&2NOxC)R|-os4hS$iVpSC zh{`;mDRSbM|6Ov}IDHneH2WcMR6C?jaH4qksf47Z)YISV`ieB0*UM#|0>Gp13zBBf zyMCuWX`ZSyc0@Etu>=cHyK>Nw2DknSUZN zP4nlBmUGN^=iM|>vP3JxKAXeYA885=h0=A+^Tj_IniRjFBYyb0){rk*YMho3Vxh_P zuru}7$o=2=#oUlnMNI`c+YUV?Q>zaPC^_)pVITaZv$0FK*zP@92ki$p^FSLf9m6}t z%ZBC|**v5r9tLKE_Q%DZETU8eAXECrvw}o2`jpe5SPx@6a9up&LOKb05sU+l34@@i zx(_j4e8{X~T!IB8#(8s;t<#6JaEK8Z=DyFKU4q%Ch#)iqsTg}kvxg8Ze0obcYSOjy z7a!FMP8N(dkVZxuda-V{*0_}$a!wXBBMQq&j6Mdky+)3=jXIbW#KKURM@iYn-ujyN zF~Gd+*aSGZN0L^iY@T995qrjbY@PJ)P6pdxA-vj4g__$Pee_VFdk{z|u=q?-e=W1A zll^rwOI#XrPcC!BnM| z6V7xuJWN-?rv7)3Oh$?|Npj&LGy#Ven&Rp+PnIz*GG>QoU6os_ww!c)&1@rX`d8AK zxfo=j{`zNDwK5Zm>1Fqy#EMQ;p+q6%V3c&Z zODM3mxuvjoU6%eZcW~E>eAr$r zQl0GJbc>mb790@3tl7cBL&v_DXnh~o)3R6bE;%~cye;f<`a%-B1c%KJtf@Y|(8!dL zb6xPHOYEO{&Jf4A_O*u!b=iq^yHP*8-At#Qdg+EuF2V`^=8F~_)DY1o;b{nQY$XVAEXFI{n zD5W}edt!#uvahB^z~^oZkw_oAjH#Vq7`4&B;Hev1k-Et)BQJcx7PA`b4Snsz#gQI2 zD$8?af1W7ER^3OOBndTTbZOzUcBQdIzBOEj>yt4j#+bNLEzHd9L)qMwhKT*=G3YiHdoKBiT2 ziDg-xD!(rD|M#y~`x$%SEgcM@8l(Ox^Qi#m3 zD2WlNJzs=2Uo2;X~m`n8uM zT}42drbVTlI0fkPQ#(V-$_mJnf|afFRaJWm@98--C}K-``E~C2`TB`xKOiEw?{7L4 zAi|zEl&pDDg9je1;nja2QNortz5E$yqZ?P+Xn{EcL^%5i9>9?rwp_s?=x0YELZt#E zi8#uVwa{qowC66FqRcA&Oz5M7S*Jrtny$y9Map1CJG)^;6C$0=L~1o_N}CH1OH5I+y$XxFW0|t7UGS z1#$n87dk*FR24dL>6mE&y{Oo%jhVjWd#ywnC0U1Nqh`mG0+t}u8#

>8^X4G_7Nl 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 F{tI;;G`j!* literal 0 HcmV?d00001 diff --git a/crates/ltbox-gui/src/widgets.rs b/crates/ltbox-gui/src/widgets.rs index 9eba2731..dce302b9 100644 --- a/crates/ltbox-gui/src/widgets.rs +++ b/crates/ltbox-gui/src/widgets.rs @@ -1033,6 +1033,12 @@ static TB323FU_HANDLE: std::sync::LazyLock = include_bytes!("../assets/devices/tb323fu.png").as_slice(), ) }); +static TB324ZC_HANDLE: std::sync::LazyLock = + std::sync::LazyLock::new(|| { + iced::widget::image::Handle::from_bytes( + include_bytes!("../assets/devices/tb324zc.png").as_slice(), + ) + }); static TB520FU_HANDLE: std::sync::LazyLock = std::sync::LazyLock::new(|| { iced::widget::image::Handle::from_bytes( @@ -1065,7 +1071,7 @@ pub(crate) fn device_portrait(model: &str) -> DevicePortrait { "TB321FU" => DevicePortrait::Png(TB321FU_HANDLE.clone()), "TB322FC" => DevicePortrait::Png(TB322FC_HANDLE.clone()), "TB323FU" => DevicePortrait::Png(TB323FU_HANDLE.clone()), - TB324ZC_MODEL => DevicePortrait::Png(TB323FU_HANDLE.clone()), + TB324ZC_MODEL => DevicePortrait::Png(TB324ZC_HANDLE.clone()), "TB520FU" => DevicePortrait::Png(TB520FU_HANDLE.clone()), "TB710FU" => DevicePortrait::Png(TB710FU_HANDLE.clone()), _ => DevicePortrait::Svg(GENERIC_TABLET_SVG_HANDLE.clone()), @@ -1424,12 +1430,12 @@ mod tests { use iced::widget::button; #[test] - fn tb324zc_reuses_the_tb323fu_portrait_handle() { + fn tb324zc_has_its_own_portrait_handle() { match (device_portrait("TB323FU"), device_portrait("TB324ZC")) { (DevicePortrait::Png(tb323fu), DevicePortrait::Png(tb324zc)) => { - assert!(tb323fu == tb324zc); + assert!(tb323fu != tb324zc); } - _ => panic!("both models must dispatch to the shared PNG portrait"), + _ => panic!("both models must dispatch to a PNG portrait"), } } From de5ed898acfa237fc7a56240f06fc810557bdcb6 Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sun, 30 Aug 2026 02:57:00 +0900 Subject: [PATCH 5/6] feat(flash): Pin the efisp GBL release to 5.3.120-mod6 mod6 extends the patches that did not land on TB324ZC. All four asset digests move with the tag; the names are unchanged. Co-authored-by: Claude (claude-opus-5) --- crates/ltbox-gui/src/workers/flash/full.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ltbox-gui/src/workers/flash/full.rs b/crates/ltbox-gui/src/workers/flash/full.rs index d8e46272..8efda42a 100644 --- a/crates/ltbox-gui/src/workers/flash/full.rs +++ b/crates/ltbox-gui/src/workers/flash/full.rs @@ -1647,30 +1647,30 @@ pub(crate) fn flash_worker( } /// Pinned gbl_root_baldur release used for TB323FU efisp GBL images. -const EFISP_GBL_RELEASE_TAG: &str = "5.3.120-mod5"; +const EFISP_GBL_RELEASE_TAG: &str = "5.3.120-mod6"; /// Exact asset names accepted for the pinned efisp release. const EFISP_EXPECTED_ASSETS: &[(&str, &str)] = &[ ( "generic_superfastboot_prc.efi", - "22471c543e13a433cb05c5c54bcfaf107f2643a6cfd7e46d8d73764b349e8cf2", + "375d3f4ec5ca9f02745077fba6ef8b5b7e7c5ad77c17b7bdb28b794da4fb72f2", ), ( "generic_superfastboot_prc_arb.efi", - "fc55e6a4912f20c1bf0c664bb985e10d0c4e0944f92fab5e4f855b22e2aefcdf", + "d0496c898667bd63fe30809c3ab68a4bcd009dae8f961048583c37ee4a004086", ), ( "generic_superfastboot_row.efi", - "90b16cacc4f2f6aded2c5bf0eed7d20b6a294115f6cf09dab555b4a4496e2628", + "024244ea7d2ac42947ced7688eada4082bf642e1cf205cf64a0b82a7f6291155", ), ( "generic_superfastboot_row_arb.efi", - "99b62f4aeca619df4f480f6bffa3f0fea3ef2516a8fe48a092613c2aa68d10e2", + "defa391eed6164801cb5e8bec0a5175a164aa0ed44f776f9637e2c6c108efc33", ), ]; /// Map a region/ARB suffix to the exact pinned asset name for the -/// `5.3.120-mod5` gbl_root_baldur release. Unknown suffixes refuse. +/// `5.3.120-mod6` gbl_root_baldur release. Unknown suffixes refuse. fn efisp_expected_asset(suffix: &str) -> Option<&'static str> { match suffix { "_prc.efi" => Some("generic_superfastboot_prc.efi"), @@ -1808,7 +1808,7 @@ mod efisp_pin_tests { #[test] fn expected_hashes_cover_all_accepted_assets() { - assert_eq!(EFISP_GBL_RELEASE_TAG, "5.3.120-mod5"); + assert_eq!(EFISP_GBL_RELEASE_TAG, "5.3.120-mod6"); assert_eq!(EFISP_EXPECTED_ASSETS.len(), 4); for (name, hash) in EFISP_EXPECTED_ASSETS { assert_eq!(hash.len(), 64, "{name} hash length"); From 23dca79d9b02b555757d004f4608a5715cdaae3d Mon Sep 17 00:00:00 2001 From: OO <16506343+miner7222@users.noreply.github.com> Date: Sun, 30 Aug 2026 23:27:12 +0900 Subject: [PATCH 6/6] docs(core): Call TB324ZC the Y700 5G Y700 Infinite was an unofficial name. The loader hint now names the shared Snapdragon 8 Elite Gen 5 instead of listing both models, since the manifest requirement follows the SoC rather than the model. Co-authored-by: Claude (claude-opus-5) --- crates/ltbox-core/src/model.rs | 2 +- crates/ltbox-gui/lang/en.json | 2 +- crates/ltbox-gui/lang/ja.json | 2 +- crates/ltbox-gui/lang/ko.json | 2 +- crates/ltbox-gui/lang/ru.json | 2 +- crates/ltbox-gui/lang/zh.json | 2 +- crates/ltbox-gui/src/model/device.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ltbox-core/src/model.rs b/crates/ltbox-core/src/model.rs index 00b65255..1e80d16f 100644 --- a/crates/ltbox-core/src/model.rs +++ b/crates/ltbox-core/src/model.rs @@ -9,7 +9,7 @@ pub const LAVIE_TAB_9QHD1_MODEL: &str = "LAVIETab9QHD1"; /// Model token reported by Lenovo Y700 Gen 5 firmware. pub const TB323FU_MODEL: &str = "TB323FU"; -/// Model token reported by Lenovo Y700 Infinite firmware. +/// Model token reported by Lenovo Y700 5G firmware. pub const TB324ZC_MODEL: &str = "TB324ZC"; /// Model token reported by Xiaoxin Pro 13 PRC firmware. diff --git a/crates/ltbox-gui/lang/en.json b/crates/ltbox-gui/lang/en.json index df571963..2a7d3d83 100644 --- a/crates/ltbox-gui/lang/en.json +++ b/crates/ltbox-gui/lang/en.json @@ -676,7 +676,7 @@ "loader_default_ext_unsupported": "The file set as the default EDL loader has an extension that isn't supported on the connected device.", "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nor qsahara_device_programmer.xml (Y700 Gen 5 / Infinite only)", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nor qsahara_device_programmer.xml (Snapdragon 8 Elite Gen 5 only)", "loader_model_mismatch_tooltip": "The connected device needs a different EDL loader (TB323FU/TB324ZC: .xml/.x manifest; every other model: .melf).", "log_apatch_extract_kernel": "Extracting kernel: {input} → {output}", "log_apatch_extracted_kpimg": "extracted assets/kpimg → {path} ({bytes} bytes)", diff --git a/crates/ltbox-gui/lang/ja.json b/crates/ltbox-gui/lang/ja.json index cf190b86..cc52e100 100644 --- a/crates/ltbox-gui/lang/ja.json +++ b/crates/ltbox-gui/lang/ja.json @@ -676,7 +676,7 @@ "loader_default_ext_unsupported": "既定の EDL ローダーに指定されたファイルの拡張子は、接続中の端末ではサポートされていません。", "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nまたは qsahara_device_programmer.xml (Y700 Gen 5 / Infinite のみ)", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nまたは qsahara_device_programmer.xml (Snapdragon 8 Elite Gen 5 のみ)", "loader_model_mismatch_tooltip": "接続中の端末には別の EDL ローダーが必要です(TB323FU/TB324ZC: .xml/.x マニフェスト、その他のモデル: .melf)。", "log_apatch_extract_kernel": "カーネルを抽出中: {input} → {output}", "log_apatch_extracted_kpimg": "assets/kpimg を抽出しました → {path} ({bytes} バイト)", diff --git a/crates/ltbox-gui/lang/ko.json b/crates/ltbox-gui/lang/ko.json index 42d06632..5017180c 100644 --- a/crates/ltbox-gui/lang/ko.json +++ b/crates/ltbox-gui/lang/ko.json @@ -676,7 +676,7 @@ "loader_default_ext_unsupported": "기본 EDL 로더로 지정된 파일이 연결된 기기에서 지원되지 않는 확장자입니다.", "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\n또는 qsahara_device_programmer.xml (Y700 5세대 / Infinite 전용)", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\n또는 qsahara_device_programmer.xml (Snapdragon 8 Elite Gen 5 전용)", "loader_model_mismatch_tooltip": "연결된 기기에는 다른 EDL 로더가 필요합니다 (TB323FU/TB324ZC: .xml/.x 매니페스트, 그 외 모델: .melf).", "log_apatch_extract_kernel": "커널 추출 중: {input} → {output}", "log_apatch_extracted_kpimg": "assets/kpimg 추출 완료 → {path} ({bytes} 바이트)", diff --git a/crates/ltbox-gui/lang/ru.json b/crates/ltbox-gui/lang/ru.json index a19e87cf..7965201f 100644 --- a/crates/ltbox-gui/lang/ru.json +++ b/crates/ltbox-gui/lang/ru.json @@ -676,7 +676,7 @@ "loader_default_ext_unsupported": "Расширение файла, заданного загрузчиком EDL по умолчанию, не поддерживается на подключённом устройстве.", "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\nили qsahara_device_programmer.xml (только Y700 5-го поколения / Infinite)", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\nили qsahara_device_programmer.xml (только Snapdragon 8 Elite Gen 5)", "loader_model_mismatch_tooltip": "Подключённому устройству нужен другой загрузчик EDL (TB323FU/TB324ZC: манифест .xml/.x; остальные модели: .melf).", "log_apatch_extract_kernel": "Извлечение ядра: {input} → {output}", "log_apatch_extracted_kpimg": "извлечён assets/kpimg → {path} ({bytes} байт)", diff --git a/crates/ltbox-gui/lang/zh.json b/crates/ltbox-gui/lang/zh.json index b8bca589..f80c6343 100644 --- a/crates/ltbox-gui/lang/zh.json +++ b/crates/ltbox-gui/lang/zh.json @@ -676,7 +676,7 @@ "loader_default_ext_unsupported": "设置为默认 EDL 加载器的文件的扩展名在连接的设备上不受支持。", "loader_desc_efisp_gbl": "qsahara_device_programmer.xml", "loader_desc_standard": "xbl_s_devprg_ns.melf", - "loader_desc_unknown": "xbl_s_devprg_ns.melf\n或 qsahara_device_programmer.xml(仅 Y700五代 / Infinite)", + "loader_desc_unknown": "xbl_s_devprg_ns.melf\n或 qsahara_device_programmer.xml(仅 Snapdragon 8 Elite Gen 5)", "loader_model_mismatch_tooltip": "连接的设备需要不同的 EDL 加载器(TB323FU/TB324ZC:.xml/.x 清单;其他机型:.melf)。", "log_apatch_extract_kernel": "正在提取内核: {input} → {output}", "log_apatch_extracted_kpimg": "已提取 assets/kpimg → {path}({bytes} 字节)", diff --git a/crates/ltbox-gui/src/model/device.rs b/crates/ltbox-gui/src/model/device.rs index c69ed956..37dce4ca 100644 --- a/crates/ltbox-gui/src/model/device.rs +++ b/crates/ltbox-gui/src/model/device.rs @@ -28,7 +28,7 @@ pub(crate) enum DeviceClass { /// `qsahara_device_programmer.xml` Sahara manifest rather than a /// single `.melf` loader. TB323FU, - /// TB324ZC — Lenovo Y700 Infinite. Uses the efisp/GBL exploit route and + /// TB324ZC — Lenovo Y700 5G. Uses the efisp/GBL exploit route and /// multi-image Sahara manifest, and is restricted to PRC firmware. TB324ZC, /// Any other supported model. No special-case gates apply.