From f834d1e91455d84251643088cadf8263d92d34b7 Mon Sep 17 00:00:00 2001 From: iisaev Date: Sat, 24 Oct 2026 10:01:11 +0200 Subject: [PATCH] Equipment: slots, gear traits, archetype limits and stat bonuses, equip actions and schema Co-Authored-By: Claude Opus 5.5 --- .gitattributes | 30 +++++ .gitignore | 37 +++++++ locale/en.properties | 36 ++++++ locale/es.properties | 36 ++++++ locale/ja.properties | 36 ++++++ locale/ko.properties | 36 ++++++ locale/ru.properties | 36 ++++++ locale/vi.properties | 36 ++++++ locale/zh.properties | 36 ++++++ manifest.json | 15 +++ mod.jpg | Bin 0 -> 87048 bytes schemas/equipment.json | 31 ++++++ src/EquipItemAction.cs | 30 +++++ src/EquipPutAction.cs | 32 ++++++ src/EquipRemoveAction.cs | 23 ++++ src/EquipSlotInfo.cs | 32 ++++++ src/EquipmentChangedEvent.cs | 10 ++ src/EquipmentModInitializer.cs | 33 ++++++ src/EquipmentReset.cs | 14 +++ src/EquipmentSaveable.cs | 29 +++++ src/EquipmentService.cs | 195 +++++++++++++++++++++++++++++++++ src/EquipmentSheetSection.cs | 87 +++++++++++++++ src/EquipmentStateData.cs | 12 ++ src/EquipmentTraitSource.cs | 22 ++++ src/EquippedCondition.cs | 24 ++++ src/EquippedLeafParser.cs | 39 +++++++ src/StatUpItemAction.cs | 35 ++++++ tests/EquipmentServiceTests.cs | 83 ++++++++++++++ 28 files changed, 1065 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 locale/en.properties create mode 100644 locale/es.properties create mode 100644 locale/ja.properties create mode 100644 locale/ko.properties create mode 100644 locale/ru.properties create mode 100644 locale/vi.properties create mode 100644 locale/zh.properties create mode 100644 manifest.json create mode 100644 mod.jpg create mode 100644 schemas/equipment.json create mode 100644 src/EquipItemAction.cs create mode 100644 src/EquipPutAction.cs create mode 100644 src/EquipRemoveAction.cs create mode 100644 src/EquipSlotInfo.cs create mode 100644 src/EquipmentChangedEvent.cs create mode 100644 src/EquipmentModInitializer.cs create mode 100644 src/EquipmentReset.cs create mode 100644 src/EquipmentSaveable.cs create mode 100644 src/EquipmentService.cs create mode 100644 src/EquipmentSheetSection.cs create mode 100644 src/EquipmentStateData.cs create mode 100644 src/EquipmentTraitSource.cs create mode 100644 src/EquippedCondition.cs create mode 100644 src/EquippedLeafParser.cs create mode 100644 src/StatUpItemAction.cs create mode 100644 tests/EquipmentServiceTests.cs diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..3030c1a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,30 @@ +# Line endings: LF everywhere, on every OS, whatever core.autocrlf says. +* text=auto eol=lf + +# cmd.exe misreads labels and goto in LF batch files, so they stay CRLF. +*.bat text eol=crlf +*.cmd text eol=crlf + +# Binaries: never converted, never diffed as text. +*.png binary +*.jpg binary +*.jpeg binary +*.webp binary +*.svg text +*.ogg binary +*.wav binary +*.mp3 binary +*.ttf binary +*.otf binary +*.woff binary +*.woff2 binary +*.dll binary +*.so binary +*.dylib binary +*.pdb binary +*.exe binary +*.zip binary +*.pck binary +*.moc3 binary +*.res binary +*.scn binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c301ca8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Godot 4.x +.godot/ +.idea/ +sdk/ +bin/ +obj/ + +#ai +.omo/ +.opencode/ + +gen/ +obj/ +bin/ + +*.tres~ +*.tscn~ + +# GDScript LSP +.godot/ + +# Export +*.exe +*.dmg +*.apk +*.aab +*.pck +*.zip +*.log + +# OS +.DS_Store +Thumbs.db + +# Editor +*.import +*.godot.uid diff --git a/locale/en.properties b/locale/en.properties new file mode 100644 index 0000000..f655552 --- /dev/null +++ b/locale/en.properties @@ -0,0 +1,36 @@ +mod_equipment_name = Equipment +mod_equipment_desc = Gear for any game with stats: slots as data (weapon, armour, accessory — or an outfit and jewellery in a novel); an item becomes gear by two keys of its own JSON (“Equip” — the type, “Traits” — what it gives while worn). What is worn feeds the stats, so battles, checks and conditions change at once. Put on through the inventory's usual target picker; actions equip.put and equip.remove; condition equipped(who, item). +equipment/verb_equip = Equip +equipment/not_gear = This cannot be worn. +equipment/no_slot = There is no slot for this. +equipment/wrong_archetype = Not for this hand: it is meant for another class. +equipment/sheet/title = Equipment +equipment/sheet/hint = To put something on, open the bag, pick it and press Equip. +equipment/sheet/take_off = Take off +equipment/schema/equip/put = Put on +equipment/schema/equip/put_desc = A class's starting gear, a gift worn at once +equipment/schema/field/item = Item +equipment/schema/field/who = Who +equipment/schema/field/slot = Slot +equipment/schema/field/give = Grant +equipment/schema/equip/give_desc = Grant it even when it is not in the bag +equipment/schema/equip/remove = Take off +equipment/schema/equip/remove_desc = The worn item goes back to the bag +equipment/schema/kind/equip_slot = Equipment slots +equipment/schema/kind/equip_slot_desc = Where a character wears things +equipment/schema/field/name = Name +equipment/schema/field/order = Order +equipment/schema/field/accepts = Accepts types +equipment/schema/field/accepts_desc = Equip types, comma separated; empty — the type is the slot id +equipment/schema/field/equip = Equip type +equipment/schema/field/equip_desc = sword, staff, armor… — which slot it fits; empty — not gear +equipment/schema/field/traits = Traits +equipment/schema/field/traits_desc = Stat modifiers: a flat amount, a percent or a formula +equipment/schema/field/stat = Stat +equipment/schema/field/add = Add +equipment/schema/field/percent = Percent +equipment/schema/field/formula = Formula +equipment/schema/field/archetypes = Archetypes only +equipment/schema/field/archetypes_desc = Empty — anyone may wear it +equipment/schema/field/stat_up = Raises for good +equipment/schema/field/stat_up_desc = For the action/stat_up action: stat → amount diff --git a/locale/es.properties b/locale/es.properties new file mode 100644 index 0000000..d3eb6bc --- /dev/null +++ b/locale/es.properties @@ -0,0 +1,36 @@ +mod_equipment_name = Equipo +mod_equipment_desc = Equipo para cualquier juego con estadísticas: ranuras como datos (arma, armadura, accesorio — o atuendo y joyas en una novela); un objeto se vuelve equipo con dos claves de su propio JSON («Equip» — el tipo, «Traits» — lo que da mientras se lleva). Lo que se lleva alimenta las estadísticas, así que combates, tiradas y condiciones cambian al instante. Se equipa con el selector de objetivo habitual del inventario; acciones equip.put y equip.remove; condición equipped(quién, objeto). +equipment/verb_equip = Equipar +equipment/not_gear = Esto no se puede llevar. +equipment/no_slot = No hay ranura para esto. +equipment/wrong_archetype = No es para esta mano: es de otra clase. +equipment/sheet/title = Equipo +equipment/sheet/hint = Para ponerte algo, abre la bolsa, elígelo y pulsa Equipar. +equipment/sheet/take_off = Quitar +equipment/schema/equip/put = Equipar +equipment/schema/equip/put_desc = El equipo inicial de una clase, un regalo que se lleva al momento +equipment/schema/field/item = Objeto +equipment/schema/field/who = Quién +equipment/schema/field/slot = Ranura +equipment/schema/field/give = Conceder +equipment/schema/equip/give_desc = Concederlo aunque no esté en la bolsa +equipment/schema/equip/remove = Quitar +equipment/schema/equip/remove_desc = El objeto vuelve a la bolsa +equipment/schema/kind/equip_slot = Ranuras de equipo +equipment/schema/kind/equip_slot_desc = Dónde lleva las cosas un personaje +equipment/schema/field/name = Nombre +equipment/schema/field/order = Orden +equipment/schema/field/accepts = Acepta tipos +equipment/schema/field/accepts_desc = Tipos de equipo separados por comas; vacío: el tipo es el id de la ranura +equipment/schema/field/equip = Tipo de equipo +equipment/schema/field/equip_desc = sword, staff, armor…: en qué ranura encaja; vacío: no es equipo +equipment/schema/field/traits = Rasgos +equipment/schema/field/traits_desc = Modificadores de estadísticas: una suma, un porcentaje o una fórmula +equipment/schema/field/stat = Estadística +equipment/schema/field/add = Suma +equipment/schema/field/percent = Porcentaje +equipment/schema/field/formula = Fórmula +equipment/schema/field/archetypes = Solo arquetipos +equipment/schema/field/archetypes_desc = Vacío: cualquiera puede llevarlo +equipment/schema/field/stat_up = Sube para siempre +equipment/schema/field/stat_up_desc = Para la acción action/stat_up: estadística → cantidad diff --git a/locale/ja.properties b/locale/ja.properties new file mode 100644 index 0000000..58a05c4 --- /dev/null +++ b/locale/ja.properties @@ -0,0 +1,36 @@ +mod_equipment_name = 装備 +mod_equipment_desc = ステータスのあるどのゲームにも使える装備:スロットはデータ(武器、防具、アクセサリー——ノベルなら服装や装身具)。アイテムは自分の JSON の二つのキー(「Equip」——種類、「Traits」——装備中に与えるもの)だけで装備品になる。装備はステータスに反映されるので、バトル、判定、条件がすぐに変わる。インベントリのいつもの対象選択で装備。アクション equip.put と equip.remove、条件 equipped(誰, アイテム)。 +equipment/verb_equip = 装備する +equipment/not_gear = これは装備できない。 +equipment/no_slot = これを付ける場所がない。 +equipment/wrong_archetype = 手に合わない:別の職業向けだ。 +equipment/sheet/title = 装備 +equipment/sheet/hint = 装備するには、かばんで選んで「装備する」を押す。 +equipment/sheet/take_off = 外す +equipment/schema/equip/put = 装備する +equipment/schema/equip/put_desc = 職業の初期装備、すぐに身に着ける贈り物 +equipment/schema/field/item = アイテム +equipment/schema/field/who = 誰 +equipment/schema/field/slot = スロット +equipment/schema/field/give = 付与 +equipment/schema/equip/give_desc = かばんになくても付与する +equipment/schema/equip/remove = 外す +equipment/schema/equip/remove_desc = 外した物はかばんに戻る +equipment/schema/kind/equip_slot = 装備スロット +equipment/schema/kind/equip_slot_desc = キャラクターが物を身に着ける場所 +equipment/schema/field/name = 名前 +equipment/schema/field/order = 順序 +equipment/schema/field/accepts = 受け付ける種類 +equipment/schema/field/accepts_desc = 装備の種類(カンマ区切り)。空ならスロット id が種類 +equipment/schema/field/equip = 装備の種類 +equipment/schema/field/equip_desc = sword、staff、armor…——どのスロットに入るか。空なら装備ではない +equipment/schema/field/traits = 特性 +equipment/schema/field/traits_desc = ステータス修正:固定値、パーセント、または式 +equipment/schema/field/stat = ステータス +equipment/schema/field/add = 加算 +equipment/schema/field/percent = パーセント +equipment/schema/field/formula = 式 +equipment/schema/field/archetypes = 対象アーキタイプ +equipment/schema/field/archetypes_desc = 空なら誰でも装備できる +equipment/schema/field/stat_up = 永続的に上げる +equipment/schema/field/stat_up_desc = action/stat_up 用:ステータス → 量 diff --git a/locale/ko.properties b/locale/ko.properties new file mode 100644 index 0000000..64a3f46 --- /dev/null +++ b/locale/ko.properties @@ -0,0 +1,36 @@ +mod_equipment_name = 장비 +mod_equipment_desc = 능력치가 있는 모든 게임을 위한 장비: 데이터로 정의하는 슬롯(무기, 방어구, 장신구 — 노벨이라면 의상과 액세서리). 아이템은 자기 JSON의 키 두 개(“Equip” — 종류, “Traits” — 착용 중 주는 효과)만으로 장비가 됩니다. 착용한 것이 능력치에 반영되므로 전투, 판정, 조건이 바로 바뀝니다. 인벤토리의 평소 대상 선택으로 착용, 액션 equip.put과 equip.remove, 조건 equipped(누가, 아이템). +equipment/verb_equip = 장착 +equipment/not_gear = 이것은 착용할 수 없습니다. +equipment/no_slot = 이것을 착용할 슬롯이 없습니다. +equipment/wrong_archetype = 손에 맞지 않습니다: 다른 직업용입니다. +equipment/sheet/title = 장비 +equipment/sheet/hint = 착용하려면 가방에서 골라 ‘장착’을 누르세요. +equipment/sheet/take_off = 벗기 +equipment/schema/equip/put = 착용 +equipment/schema/equip/put_desc = 직업의 시작 장비, 바로 착용하는 선물 +equipment/schema/field/item = 아이템 +equipment/schema/field/who = 누구 +equipment/schema/field/slot = 슬롯 +equipment/schema/field/give = 지급 +equipment/schema/equip/give_desc = 가방에 없어도 지급 +equipment/schema/equip/remove = 벗기 +equipment/schema/equip/remove_desc = 착용한 물건이 가방으로 돌아감 +equipment/schema/kind/equip_slot = 장비 슬롯 +equipment/schema/kind/equip_slot_desc = 캐릭터가 물건을 착용하는 곳 +equipment/schema/field/name = 이름 +equipment/schema/field/order = 순서 +equipment/schema/field/accepts = 허용 종류 +equipment/schema/field/accepts_desc = 장비 종류(쉼표로 구분). 비우면 슬롯 id가 종류 +equipment/schema/field/equip = 장비 종류 +equipment/schema/field/equip_desc = sword, staff, armor… — 어느 슬롯에 맞는지. 비우면 장비 아님 +equipment/schema/field/traits = 특성 +equipment/schema/field/traits_desc = 능력치 수정: 고정값, 퍼센트 또는 공식 +equipment/schema/field/stat = 능력치 +equipment/schema/field/add = 더하기 +equipment/schema/field/percent = 퍼센트 +equipment/schema/field/formula = 공식 +equipment/schema/field/archetypes = 허용 원형 +equipment/schema/field/archetypes_desc = 비우면 누구나 착용 +equipment/schema/field/stat_up = 영구 상승 +equipment/schema/field/stat_up_desc = action/stat_up 행동용: 능력치 → 양 diff --git a/locale/ru.properties b/locale/ru.properties new file mode 100644 index 0000000..a086f3d --- /dev/null +++ b/locale/ru.properties @@ -0,0 +1,36 @@ +mod_equipment_name = Снаряжение +mod_equipment_desc = Снаряжение для любой игры со статами: слоты как данные (оружие, броня, аксессуар — или наряд и украшения в новелле), предмет становится снаряжением двумя ключами своего JSON («Equip» — тип, «Traits» — что он даёт, пока надет). Надетое питает статы, поэтому бой, проверки и условия меняются сразу. Надевается через обычный выбор цели в инвентаре; действия equip.put и equip.remove; условие equipped(кто, предмет). +equipment/verb_equip = Надеть +equipment/not_gear = Это нельзя надеть. +equipment/no_slot = Для этого нет подходящего места. +equipment/wrong_archetype = Не по руке: это для другого класса. +equipment/sheet/title = Снаряжение +equipment/sheet/hint = Надеть вещь — в сумке: выберите её и нажмите «Надеть». +equipment/sheet/take_off = Снять +equipment/schema/equip/put = Надеть +equipment/schema/equip/put_desc = Стартовое снаряжение класса, подарок, который надевают сразу +equipment/schema/field/item = Предмет +equipment/schema/field/who = Кто +equipment/schema/field/slot = Слот +equipment/schema/field/give = Выдать +equipment/schema/equip/give_desc = Выдать, даже если предмета нет в сумке +equipment/schema/equip/remove = Снять +equipment/schema/equip/remove_desc = Вещь из слота возвращается в сумку +equipment/schema/kind/equip_slot = Слоты снаряжения +equipment/schema/kind/equip_slot_desc = Куда персонаж надевает вещи +equipment/schema/field/name = Название +equipment/schema/field/order = Порядок +equipment/schema/field/accepts = Принимает типы +equipment/schema/field/accepts_desc = Типы снаряжения через запятую; пусто — тип равен id слота +equipment/schema/field/equip = Тип снаряжения +equipment/schema/field/equip_desc = sword, staff, armor… — в какой слот встаёт; пусто — не снаряжение +equipment/schema/field/traits = Черты +equipment/schema/field/traits_desc = Модификаторы статов: прибавка, процент или формула +equipment/schema/field/stat = Стат +equipment/schema/field/add = Прибавка +equipment/schema/field/percent = Процент +equipment/schema/field/formula = Формула +equipment/schema/field/archetypes = Только для архетипов +equipment/schema/field/archetypes_desc = Пусто — может надеть любой +equipment/schema/field/stat_up = Навсегда повышает +equipment/schema/field/stat_up_desc = Для действия action/stat_up: стат → прибавка diff --git a/locale/vi.properties b/locale/vi.properties new file mode 100644 index 0000000..b02eee6 --- /dev/null +++ b/locale/vi.properties @@ -0,0 +1,36 @@ +mod_equipment_name = Trang bị +mod_equipment_desc = Trang bị cho mọi game có chỉ số: ô trang bị là dữ liệu (vũ khí, giáp, phụ kiện — hoặc trang phục và trang sức trong tiểu thuyết); vật phẩm thành trang bị nhờ hai khóa trong JSON của chính nó («Equip» — loại, «Traits» — tác dụng khi mặc). Đồ đang mặc nuôi chỉ số, nên chiến đấu, kiểm tra và điều kiện thay đổi ngay. Mặc qua bộ chọn mục tiêu quen thuộc của túi đồ; hành động equip.put và equip.remove; điều kiện equipped(ai, vật phẩm). +equipment/verb_equip = Trang bị +equipment/not_gear = Thứ này không mặc được. +equipment/no_slot = Không có ô nào hợp cho thứ này. +equipment/wrong_archetype = Không hợp tay: thứ này dành cho lớp khác. +equipment/sheet/title = Trang bị +equipment/sheet/hint = Muốn mặc đồ, mở túi, chọn món đó và bấm Trang bị. +equipment/sheet/take_off = Tháo +equipment/schema/equip/put = Mặc vào +equipment/schema/equip/put_desc = Trang bị khởi đầu của lớp, món quà mặc ngay +equipment/schema/field/item = Vật phẩm +equipment/schema/field/who = Ai +equipment/schema/field/slot = Ô +equipment/schema/field/give = Cấp luôn +equipment/schema/equip/give_desc = Cấp ngay cả khi không có trong túi +equipment/schema/equip/remove = Tháo ra +equipment/schema/equip/remove_desc = Món đồ quay lại túi +equipment/schema/kind/equip_slot = Ô trang bị +equipment/schema/kind/equip_slot_desc = Nơi nhân vật mặc đồ +equipment/schema/field/name = Tên +equipment/schema/field/order = Thứ tự +equipment/schema/field/accepts = Nhận loại +equipment/schema/field/accepts_desc = Các loại trang bị, cách nhau bằng dấu phẩy; để trống — loại là id của ô +equipment/schema/field/equip = Loại trang bị +equipment/schema/field/equip_desc = sword, staff, armor… — vừa ô nào; để trống — không phải trang bị +equipment/schema/field/traits = Đặc tính +equipment/schema/field/traits_desc = Bộ điều chỉnh chỉ số: số cộng, phần trăm hoặc công thức +equipment/schema/field/stat = Chỉ số +equipment/schema/field/add = Cộng +equipment/schema/field/percent = Phần trăm +equipment/schema/field/formula = Công thức +equipment/schema/field/archetypes = Chỉ cho nguyên mẫu +equipment/schema/field/archetypes_desc = Để trống — ai cũng mặc được +equipment/schema/field/stat_up = Tăng vĩnh viễn +equipment/schema/field/stat_up_desc = Cho hành động action/stat_up: chỉ số → lượng diff --git a/locale/zh.properties b/locale/zh.properties new file mode 100644 index 0000000..d2606e8 --- /dev/null +++ b/locale/zh.properties @@ -0,0 +1,36 @@ +mod_equipment_name = 装备 +mod_equipment_desc = 适用于任何有属性的游戏的装备:栏位即数据(武器、护甲、饰品——或小说里的服装和首饰);物品只需自身 JSON 中的两个键就成为装备(“Equip”——类型,“Traits”——穿戴时提供什么)。穿戴的物品会影响属性,因此战斗、检定和条件立即随之改变。通过背包常用的目标选择来穿戴;动作 equip.put 和 equip.remove;条件 equipped(谁, 物品)。 +equipment/verb_equip = 装备 +equipment/not_gear = 这个无法穿戴。 +equipment/no_slot = 没有可放它的栏位。 +equipment/wrong_archetype = 不合手:这是给别的职业用的。 +equipment/sheet/title = 装备 +equipment/sheet/hint = 要穿戴物品,打开背包,选中它并点击“装备”。 +equipment/sheet/take_off = 卸下 +equipment/schema/equip/put = 穿戴 +equipment/schema/equip/put_desc = 职业的初始装备、立刻穿上的礼物 +equipment/schema/field/item = 物品 +equipment/schema/field/who = 谁 +equipment/schema/field/slot = 栏位 +equipment/schema/field/give = 直接给予 +equipment/schema/equip/give_desc = 即使背包里没有也给予 +equipment/schema/equip/remove = 卸下 +equipment/schema/equip/remove_desc = 卸下的物品回到背包 +equipment/schema/kind/equip_slot = 装备栏位 +equipment/schema/kind/equip_slot_desc = 角色穿戴物品的位置 +equipment/schema/field/name = 名称 +equipment/schema/field/order = 顺序 +equipment/schema/field/accepts = 接受类型 +equipment/schema/field/accepts_desc = 装备类型,逗号分隔;留空——类型即栏位 id +equipment/schema/field/equip = 装备类型 +equipment/schema/field/equip_desc = sword、staff、armor…——放进哪个栏位;留空——不是装备 +equipment/schema/field/traits = 特性 +equipment/schema/field/traits_desc = 属性修正:固定值、百分比或公式 +equipment/schema/field/stat = 属性 +equipment/schema/field/add = 加值 +equipment/schema/field/percent = 百分比 +equipment/schema/field/formula = 公式 +equipment/schema/field/archetypes = 仅限原型 +equipment/schema/field/archetypes_desc = 留空——任何人都能穿戴 +equipment/schema/field/stat_up = 永久提升 +equipment/schema/field/stat_up_desc = 用于 action/stat_up 动作:属性 → 数量 diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..3399e8f --- /dev/null +++ b/manifest.json @@ -0,0 +1,15 @@ +{ + "id": "equipment", + "name": "Equipment", + "version": "1.0.0", + "author": "ct", + "description": "Gear for any game with stats: slots as data (\"Kind\": \"equip_slot\": weapon, body, accessory — or outfit and jewellery in a novel), items become gear by two keys of their own JSON (\"Equip\": the equip type, \"Traits\": what they do while worn), optional \"Archetypes\" limits. Worn items feed the stats as a trait source, so battle attributes, checks and conditions follow at once. The item action action/equip uses the inventory's own target picker; scenario actions equip.put and equip.remove; condition equipped(who, item); the Equipment block of the character sheet.", + "category": "gameplay", + "sources": [ + "src/**/*.cs" + ], + "test_sources": [ + "tests/*.cs" + ], + "depends": ["stats_base>=1", "items_base>=1", "characters_base>=1", "ui_base>=1"] +} diff --git a/mod.jpg b/mod.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3e5aad0990b2379167494ddbdc0d324b72287155 GIT binary patch literal 87048 zcmbSyWmFtdw`Jq*kl^l;;I6?Mhi=>w9GXCA+=D|pje7@oYY4$D!7VrqAxI#&Tacg` zzV~L$tTn%8=G3ZNKkDA9v#aW!Q?>W0e+&QC0Hm5~8fpMEGynkYX#xCO0w@D8F`f+l zKP@IECKfh6HZ~R(HX$w^4n8p<2{ADt5fKU5GYS$?Dl#G>3R()P=hQSbG$iD740O~C z&!}mr|8o$ur=i$b*aXjyAB`H6-0 zUk3P}hK7#uDsF=8fq?EL>imIAAP(u@JXk=_+YG!U{ z@8Ia<>;m!f_VM-e4+xBmijIkm`v6NxO-s+n%*sX-6_=Ejl~+_&eQ9WHYHn$5Ywzvr z9~c}O9vPjPMa|9sSopd4dwpYbYkOyRZ~yH4&&B1{_1~M@|KLIcVEi|%r}n>r{U5l< zo^YXKVq#$8{0A2ry5G}^L57LNB7{w@WPoD>rC=2f$EAFgTv*?O$0h1;F2V7>T*1zJ6L)#Q;up0VZ|{ zPLn#q9FRtj2-PG-JD4vtPeVHa5@;IMm3K+nGy0b;ZKeJBYq%6}@o2=stZO0WE{16Y zrE{Wt&)eog(A5op!vtO|O^c;-wCAV17&l(}AgFGBkx1+>zhTz)W%g*DeA!xCVBKmh zxIauJPv*}aZ0PTYwdy)d{}a&Z*7pyLqjpRP%8F!v-ZjR4()YA+*t1F?VKq}4C zxkCL%${@lt?~T$NziQXP}qT7#OE_0m=ky$~UsU|2~lDOJ5F`c524 zW`b*Yypm%_g(@nG8EdMy~hoqIrm(yah{9c~!z{8MvH9j4E7$I~nQLWayXmFkUZs@4{hrU?UV z$pva0oVo|J8#2)RZQD#lEoS%qszm4x+*+fk%E{{%JM-ytr0#E9S&(h%643Z#blh-B zCH^c_TN$dQ1%L8QQ`47w03Z$rR}26+xd&wa;}UHahsRkGK4i+gJ{8q_OC!PcTJs~7J(zTPZMy_VjEr(qQud-iC0n#Apr^Q5m7Au(9y}D; z6)^c4^0CVbA9pd3k+--|oli0A7Y~W~tCAehO=u&o68y}#P)e_y%1l2p+?WMk$(&a% zS>T-Ib{_(kMBt7lC!wl*ek%xjg2LNh>(om*oID+bm*coxJfBppVzZwmYO*BvZBqG zXSmf?RTJ8)eD+dS7?7#}~MSv?pTEG>kBCcGei{MHc z!o%e8x5-{^dVe8opl=;ts-v-X;Y@9 z9rP?=v$M@L)qLEtpGS_&xHUXV&W_A|YYU@vxIbu2T+tXj1;UDCsLToe-y#7fv-(cw zm4VJ)<(3vX^}5;9I*o^7?`k&_?Wy39HwU7Ap9$zP!AVxny>;@hiWLyFr>2`KZGzIN z9>`IrO?{cXsMG~Q=!jhPRKZ-`z51zy<>_JO7uj~%jN3Hhtq)-LPsJXQ&8tFmjN#P? z%^7%dr`7tp|NTKMJ9s^luj%HxVvC<4G7$A9VX(ts^!wZFJgIG8mR2PYXUh#A}% zqj+dXZ--qiuCZN~M5-Hz!ht!*a7q<-2~hT9lyVo-JLX_xF{9~HqJh*tA!0h2)pVB|jC?&ObTs(fB^h{NJZO+nru?|;`}=Z4|;!*g*agA#S za}Jgy{u>cD>PjIsZUQp5QhbO`<62|wGd6+&Ne+z!Aw_d#TJqd4d04UneDFA~COJ^a z&m%q6o>FKDSzqe72D`1~_bPXcYKmy4#JVQ4CMTG8hOp6eBwrw@Cz0PX>EKX>*<;bY zQPo;ivW)Q!{g2QDGfQHLAb8-FRGxiaSx)UDqbn9lM0v&sNSnum(7!BeuZ)jMe7d=u z2j*h!vTV%q6vWDx)H9z#+E*SZ=x{spd(nD5F%fm;n7wZqRnbO09_0)#sBwn7H7>4< zEE$xn!>_fN#+Lb-K z5bZa!LWm@ElV4#ZrTob?$;T5UUCi%3VWjGwM}|CxR1#L;G(%KB#Eq4MTB8t zh6U^$X&Y0M8QQ3$5K7$OA)NW-pUX!CLj@)0*~Av5%naLsPNE$evS+&bk?f>8Jd}h{ zDR4QSBeGz!FgYE`p>+8)m=@>s-zh9#{n&(%eNGxFj00mUz@GLZba*`rwz*R=T$VPu zEOm7P8t%-&k3!fdH$TPYbRL!%x<3{7&6sQU`e=IK2;3tb{FP`)K7H&~&$9>;1B9Sg z>U?37?Hl~S1YWBlC}a9F{^(5pgM?x+3T`&mvQNyh^z`e6sWHs>C9G^i<~mF5;8PwF zT`Y8wdQ|~V-Y6NQBq734aT6gsg@XiWW4$mmWOU6#592YB+eHUy(W4Dmh5K?Z`peE? zNs2YNK3g&*l-h?_N4`QQQfFS)48Ih6(-(OTzXRbmmj&fD)(Uf@(SVl_&ANagsS5P) zNJZNh;%DI+Y1xhz1C9Q50AfwdWUmRO!O&Lp#<#K>^4Y=dF?q*d+OzV#Y-q))9hiOD zA}y~9YNq+zZYHXYg_oKtasGTI zBi>b|T~2sY8)Fj*=%<4Xd z+-ux*ZZJe^ISioRSHnRftd(4+jE#GO6&jLNC7Hn+3B9Ediz#f4k#dYl%3nEt#qugk{C8&+;o#JB|*j7kJF!d2)Yce{e@4jyjp>LHnfa{cqnGweE{V-cp#(`^Jw~ zLJpw~@V2TuHCN5s>7&}M7U-C}{v!_4Oy!{z5MjT|He418+H<99 zgzK`xjmSB96iX?=fOR+sCIkdLg*-G}^e|F<4|6~zm5ZedZZ)VX2vlV_oKBRH)WaBL z_z{n*)D%WORO+l`KcR@P!43e7aLp7B&j@i3pkcSKVp&+Wd~|acsH=JVb+C6|>*GN< zp$2XKC-!qsJWGJaxP#@M$<+@c=lOBUeY9lDXd!g}m4}&tZrM{^$y(pX-OiJD&L*Sa z#xFZWCzA?#^KnBt9314Y8AyNeb#=@fUmR&TC5_IQzcb`tu15=FOPxh*^k?>3HJBZZ z97HDewrsS7OVI{v=EBVqE}Ug82%ZW`eEs9EXDrGk9+S&3^}WZ=Be}!Y}c5| zn=pzrfLdyDcD{PBnoy0Sxh0R)(=I)LalbG9et#t)6Y8<)JhSco%{Dz|=jxTe-BDkl zV^OKRn?b2m>+Ue)a>5*jDr^qsUv8|S-y>}=>y|uQD>BK@vvZ&my^Mv@<`Qj6}uiJ2BVHLyXg*NtpM*v!MF6fzQ@t5q?~&@fz4Kf$xCVp_slYCoju$OG$F zp`Rfe*J@6JVhfV|5$Z9hc>POBxMjCQF{w)Ned*B$kHRejaZvXQt`%J_2F>@{k4zr}n}L&onnamtd`- z88D0|#~1%9!#7=n?(1kKvBnRjo&foc&&^tuhLGrlOj(Jkm#sJ+tDo`_)g2Vyh3rlYHUq(*+hXz1b6_6n3mdRlqz-z-#8wqF_3c|ZPXvDuZ*>uvk+4YhUz>jlADl+)w|%e%eu-9f`jYO6%SKhJbZbP{ z*z-$124U-5ofl9Lt|RBAYJkzoz|)O-GaJp4`F4^}?hiQ0&uPBOy!mI`B{kLC83%#5 zvXSuEa?u$HZh2IV7bl6fmySV}beQ3K5?K>T5T4+*92V%<&npKtbGGr0@^$AX& z$E&@bO7|%b3&70Qq!2mC0|0>PtRv3~RIbiW+Ev-U0+C5I-@MlXjVy38M^?h9=e9N? zVH4Uj+!%!Pr!K7%ro@ewp6ChNd09Uv4PMchEwGXX-WoDra#dDZ1s}w)9VhS%3N6^? z_Qz!h4>REIOWw}O@LcJ{{I-ZZGN+cq5&Oh?^L&Tt*D_Aa>$9?`J4Bz0nq}nRS>#^N zgF?E>sL(j+Fy;p?qe%tL6w^@|mi=-j^OR)62wpBUU75KE>FsL4<;^)(Q?*Tc-)b5x zrK%-4Uc*Uc#iV;sI1nf~1PP2#M-PW#>CoEm%oO)rRO6SUse?7*SzZ0VO9p$8?3idJ zj~Z1 zztdjY0&2hYO;V$#S$<;!n{(IB3SxmC4d-WL^)>-@ixyG1$w@K9Fjh_8BixwNgi<9yZYYxyxU+z48G|`jbLOvohU@^ zUoARjI|;0ib})5+xGWc6x#RqJKnA}a89IfX3s|i+oIZ9`*Q=+DPEN!~ z0UQFXRT2cdPZeKSxE!?Lz~^0!Ednk7tl0Gn_z<`l8&?zZjm_koq=2up9zRYNUW&n3 zdZC7IzNQ{g(4}MLekU)+B=_{cKmr|GGFV4=$)zhL*-pjg+`)+ZLGN-`vSp*!vL)f^ zpZf|c-)SdXjo#6@dp-rWiirfYwMYwXQhKYrCM7a zIK>AF01TzIumg{!W`8r6>V<3zxV$q)DA7SY;5EgOo_X<)i&t_(GgZ5@c*)3B1@6(~ z{jUXgB!32M_RP~haE>_QpGoHndI%j@5tlkuIWKnAb`WI&YvO4@X6B%Y6%XP_`jN&3ovzgl|!*0z;l{cz&a zg|8Uv$VyKeMQ-u=$ZDWGc5(fsv|fsWrDte5)>SI{t0gvLakv2$0Ppnt6%W0b(1ze`&E2w-i4r48ST`V znxC9${$P=vF2rWsfZs-praZ5;4B?!iHpc*Ti2{?R6@C`w!*3^9uDFk>+Rtr9Nd!q{KV1_lG+SJVb4{mf>L@0ae>f+ z-Av~0WAf08>f|gV_CI6`M>pb0f-4P2KQ5{~ftxuVauwQcM0Sm-gD#0Y4x4|p9ecJ5 z-=(isscbj~nd1D8!0` z04;}jTWOd#p_;66XPN+I_$;|tr_y?eU;k}?d+oPM%h%Rg*QMECJfs2Ayb0YNe55&u zAi+t%qiC)^MbNx=2x3th#)9v^pzxv50C40{TjUf?XNd+n>bxGhsDdhOC4_ z8+*XifH%kV`UhX#HZbid32oPf8qxC2{b{HtMMo%;XG`V9-nF{`)^hLWh(OGkUTCvh z3X}J)`i2t80U03feeBR!nO|j_Zxiy%6nMv)-U@+Sb>|wk zU%iJry#Ga?IA$Lz2IAyLz9h>ra{pWH2Y@ETB5KsfU(u00J-A$$AnwwFWXf~MKnID4 z%ZX9c%nt;BzTsL7lak3%(qz5I;G-b!2nY^iywly{(l! zNGohxh}|hhZMUzr);!3fepc>exjMu~pybgqTvyE~ZObZ%GzeCrA8GYAY2XSgSJ~3# zc!5np_T^sQ_->%Y`9#O`qU6AM$IaE42fIN;`CW}d)MISDSSQ3!I8BDyLKmW{*_!co z9BvFZXE^AdDJ>bGL?0tvLx0K?>}UJFEA6py@hYSJ04r#APeJfkU( zOVl(WK!2fQs=8gAAU5*zb1Wx-gl};D?P966WEz<$;!3XHSp_te{MYckquYn51M-TosSBdk5F>u=0$e? z19&R^Avvq5R>jsA8nAvNz7__ZRhZ~7m$JP;rBB-?+C!r;nz#P}Xvf5-YHHUygAzQL zJSL|S55S#&xah7E)psr{vZoWEEqgOn+}Xl4(^~l}z}Sc1kq?m0OpzrPJ34eZDV!x( zXZKpNk#9hzybBY*J=*c=gU$W^FsDXmhcPCG$35^N={@v)wcoDf!P4&Rkk4uRTpEe+ z=wp!AkYbPh>j%7p$gBcYBWicAlgXR=YLng;7ed<7Pb0CZqZwjcCvN=2a*sBkxhC4c z+<$;re&gRSYL$5R2ounDe`BwgpAtnb+?nXvl-HzI$l)DWtl|XIFCOR1&Xn1Tn8K|{l_jJth3#T zi(jv;+T=?|8-IW5^1NjvJ8U%Pt*ex!ttDQT#V;vmJwWPcP~vIL!>fTKhegfyzi7%@2_pSituj*i_Ts==D$Boyk?pvg(oa$nC=0>dnw}`I+{^(XEn6 z>6X*2@%~=HR{8Ss9kU69D;O-KkO98|Zi7%mjzp?X2QNIe0Zy)hO18I^ zmkiE6JK@^;eql0m*(s?5s;Q}~Vl3dPSzo)Hsc<;^9ZH4%qB1*1$`V9>*!$?+|Eg~) z6uX!mkyd%2v!obz3UPIj{V+E?e9Y6~JOFTO*4#368#1r$C)Nl3boBR?8rBs81M|fJ z)C>@D(N$1MG7amSe*1X~LSN(;Y^k+*2b2Yu&B8fv(MSrf?*tF-ddUErN0SPfA5us5 zxY=fRE=v~=$-o`K@w%{70G6#Lhi{g5c6qV5B&$s}yM7yOG7oJS z^&ZjZAb`H8K=KJ?uZwCP+6^jl(r)5Q;buBa!!JpLM09JLbx2dwz88To8qZeBdI#*; z*(T0W;Pw{!;#qQncna?Yr((768kH1=g2a|S#X$X^K3v5B@kLpNN#6!OGc4(*% z)Y22t)9UwsbmE?_+!o&qPkbdELZt6JT94i6hWC@77yAd=XaB8$jnkEzX^!T@GqYb4 zgBk5@pWsdyqRaPlZ9*{~+pV-$W>u^P84eu%_Ap=VpB@#-$w) zquZ_l&r6cp)RmDit3viYd$Kz_g9FBDXn_+|r+RU7Uu8y+XZSvG3CSJC0t6&{2tU z*wS=*066ir=Fd|jcqT#~DcQ;`aG$!BHtad3A0l*c0{i`fEl(z!)%R^R74sdviGZ9F zhgVskstjGbZYgoP$I_dGZ9KIRx3ae-ky9IgCY#*%zOqkyU%bg9n=N%5ekZM-M79^h z*{VuzS4nxOl|cRIQ&U;qhVRBe-vXRCXC1(0Pbw}-)NCnVm1;$onWAf+A3Crsfda>H z*ypcG=>r+lL{UCLdnmE*i8uCLDt4=Fm1)L(pnZ|oXY?&eU2tI$i=7NxjbOj4k;hl9 zH*MqQX{m^EmRgvHfw3AD`&Kod&~_3nlz!@2iy*#`E`e4H;>CXnSW9`RH#4n=%ug~m z4~mG`G91JwNIkBGC2JT@!FR=44xn0=cA_#ch1JvdzgR{mF#wHf*E2CxE6Go?1JTox ze2(ezXPXQ^9`;uXOEL^js2`ZHCOo&<0%}}9BV2iCRc60{lG}6(@o-M-j4}-}`x&J> z+M0xVe#(jjP4U|cFJ;;nUx+t2?yHID%a|PW$a)FCoN9oiDBrW#fmwT zqnY2vxy_Byv@yco*e`rDLz~>_4=#fmWPFJ-aSR+$p1d!|Tl69b3?rnJljCct9GNnf zD&n5|^r9nH+c9yCMR8e*W;Y~W$BlIuXh>t-({``MJI$YbBt&{A>MSUJIDvC>Rb@MV zRAlH`l45#v$@LF_;xkteRnKMv-13YYwcWsyXY(LYZ+>YtKNu3i-z)sNoll?7L+BK( zXfJdaFR=&o*!HC{tpLa-kxt#eJ2jb@sT-IltLm6)dD^Ri(*+Lix>EDXSO1g>9C9>G zBHuf##))SJ8W;aQdd01}(n-@~d&iz9E@N-i+9$lpD3tU>H_c77U7e7a@BQh9Pc7AG zNpeBE*YZa@-~Se`SbX3AK&Jdg?m{SqSl*28yUk^veNgzGbfbrpvvj@`{`59y8CR{DDCNz{%%SM=yz_jo9PmX?d`)7m_7+YL zM$ZXzEM!HFFshpHD!aX#s1&AUS<-4Q;fpj70kgvlVia;!AOXZ%^q!IxpS=t}*a>Mq z7d=I7GMR8laR`0Wbizvo4sZg;!~ z_=nD%fIfldNHR-Z>L1FEU&&zfCW7<;CSvBD^=_YL%6(JhUUt7;2qm2UeWv$u8h`j7 zU{}1V4WY&qfZB<&Tube7$IN0u3Tw`NwNSU}?{|G2VPb>#NzCO&+{PxVF6N^D&VT zTs6dTb}1=EMTA{thu~pLZm42kZb)KQ}asy<)oQ0}6+wnVQ`@n?BPHzt@i>9Ib{Nvb}f z5~nL^f<2WkaiKjyqpQ$N9$5dhBg#ckC8f|v5PH|GpotFog8KEu6@41A$|?G+I3a^`^wNG zV7R7@f&>*xRqVWUl$mF;r7+W&>1ns1jSlHLGz$YNM9qy*a4{Q#cv4uSb%iE)o=77Q zPc8Ohp6QsUaNc0i`wsJLQppn&@608C{SD$0`Z=}o#oSD2{#8W~`tnZ?4K7(k)Wh1> zCP!5O+z?GYOJirIK@ILme1oI6PB}7?Y;a|l5O4z01g7IXvV6%ICG;PViR+W&sqw&) zP2d&Z3PTbOFt~gl5uNei`QB52SEO@Z<;RY{%hp2&+%y(TbEr+OKaWH#t$`U(bLe}Z|37)-f9~xyB$(r*IsR?V6XfRs+joGGrT zE{riYO%dN6SSfW&v1e^pv0)^0?CV)hV0x3@*nv%Llp=DF1FKzB0;f4Zj|N`H9M1>9 zU6@TS+wv|`-6&$EzY|?g1E)Zaq)QUzvXaVeWk%1x z%Be`DilUuwjXRdA5>~aUcj8ahF5`I>IQtVQik8>pC-NDSdZeH#AtFZ&OLU4*c_vGT zr({TU1Wk`J4BR_4$a@E~1V^0d5&#Rs46C?JCm{B4R5M2LxOJoy6(;o0Ol=<%YeT9i zOqz)ID1$S`QGkH$1&NFX2#qlZaRDqs2uLrCUvK=(fkxv{*NHbZr&#bM@+51%I&Toc z>a7?#K;;22o_a0?4Rx8(9Uij%!B?TA&l(=hpRX6+mtV(y1XZ9ht!&8t16&^D|Lt>} z4Q8Ejm*jJ;ZVcTRi~9UvCpImZ%uY5=P-%EZX)Uan0@U1z2Zo> z+(B6TjI;)Sq78?7XzW|Ak;Dlru|`^W}mv+0gbv?PcXa(Q;ZnctD^UxAwYOc$J6iqSpNV^Mc8rjraLx zC66B;#j?HD=Ge}Qp+1DzK&(oo&B4&diNbJG2%k9J2pZ3%1O#``NOaC@3L~RFF9k_eZLWRivD6g zJI;3Fv2nf18t;qgA*;2T2nwzkI<2#55uthxa{E*EaPWqyGhmWEC4fFpgGP$;^H=OW zEuR`oK84Jyk1oh!W={!~rNsJ0{KV^pE2<@BH}WCMKg{+EHQ)kw945^_(3Id2#td@a z@r+=x-*+(`R$gHAC0+P)35wjpzmkK2^CSsPR$Th14L6RJWU#A)c!c^Zk#Y5P0Wa{J zyO58^*oX5HyC|gv-V5}$4@Mu@e~7ZwiAZzE@y8(#9lP4j3!{G~7OaKnK@#pXQ+{T% z^K|LbVA$88K*uQx?T6o#VF?-zzTbz(LNvzR;n@bF-?Ovg3XR*b+vnYTO>-pb6ljRrRz_s#+FPCeotgX|JSFuDt3Xn_5`c*D| z*lh74{zQ>LxNuV{Ka7jShlk5R z`&>qDhmiGgb2e~71vc^z(13qhpQy?)b-C-}?LW~`p0yoJ2*0En_|?;tNVPA|*5J>X z&V*KM3l~|Yr(O3U04`%&0@UrS79j0>Ijyk34tnpiHKXUcI^GiE-!GIEo$+8cP15g!B-qqvL1# zFvE~7IqE>8cy(=~2)S23ycV_2BLak4uIW~%u9@QLZ}(s5hzj|UOTO-(HP-v&^1$l{ zzc|{{Ng&DRmt?3q{_we%dgtAa_QLpt7p#RnnA@oPs;mOAK}~6C%jo-C*6NiCGHE)K&M+RP6G|x|? zlYpI(J-2h%Ygb||A&du()IHX&G%+Na^DlM>wLl$}6N&?3x<7EHwo8-N-VirYnPJ~W z42$O#Bh~aVsSkP1Qm#fg19&A1YE4dS;&I*OU75Q*%caU<1fD^B_2(@BJ8n)xY`DEn z<=B;Y*~cCt2HYbf<*kwfg2b-MLh8b3pd*g%0kwR8#}bfMWGawIM;f5v9&+lc@xwN^ zZSTOS@d`hSFDzgZY2Iqnh=!sa>1c4M7i(V&heOAWJ7rE1^Z;naAm^C{*<3wKpDOLU zEf;DhF42sQAoQU>c2p42K>!tH05dsppqDW#jhu@{0(a8OQf-(tzF`7V$=zC2Uy2L; zb6U+i>gD>fg^$%?@E$THKlc*u3x-LhzduwK?Ppx@PgT|zIk|9hoaj@Ruf~mLYf8we zK>`z|=rWtWb#J~PR)3er+^?w3&;;vA$430J=`>}b*I>;fEdOixFg>#QBR8&g{l|-% z<5CT=$^p}0S@B!%z;d_`)zsS(J#k4I+3(+@4?!=)D-S0WFUA92CLW1;pRp}F`~DC# zZLd&m&(dOHw)sd37?G63z!3X+fH*F!-ltf7ZS@^0J7KP2?>RPvO0~>ud3V*tb1n>i zQg@jC99cp`?0seVP{2<>7DmFJpvbtB{3JNm z$wl!$_YcMPfG)NN5nWwFtyFf#K19~Z4Y79NPj7$Js~pg@M9L3U9x$@DwxTR=4iEB( z184T+dFH%l*_)sLv7iWhB{BL~m|09>OXQXM>Y1+)#^$#ZTdsDAv2RI|w~?9^y`6q) z&zcg=jM9(&$hcyHO&@hGjBh!McDC9-0Gpmt#HbC`*?uw7-gT8&tc&<$q_e?+ z5QD95thT(Ej~G`jZf)MD>@r=iD}?D(Z@^fh{(bNBb#9xE<{UCxC;eaGy!wbh?4yLI zy47A#E>rlfRk2tA+t#NQVJ!(~`&SJ9HYcVHirsmVbw#1fe<}Jt?_ak(3*2g|qUmg% zIckng1swenM%yGz!Vdb8allB7y7=DQ^tB=5*BcLz(bA7{YpKiKAljos>oZV@E~GJ2 z1i022nPZ#7!rEeQp(Fk--KHxYxb?*rXNp+jQ8tLSz%gZiFE>pzMO=3dgZ&omKH5jk zEoVaf*$iqJ3fs^BeGS8EYV1?`y5vQZL9xa3iy5>O+l(ev-HZ^={k=ryw=SiGBBmAK zu^^&8oE6*(DQ1%J<(nF)@&D9MJ5XWLm1d?=$kx*0R9b%7tB-jcVC|FG4!z&+VBLe;;{ zVVB7RPL1Q=ZTnXb?9q4s0}M5_qD}t(BY3Y^bvq{B^?-LJEDO3C$gq9R-=%Cx%-GE44l>Gs@P!_) zX4HtKH;~>lbzJRJy`}8Ufq8*vUNc2PITy&FEE^aIZpn0&$~0dHME*RT5stjK@WeT= zf;owNKp4*A&yQt@cdxxx`Wy399X(D-mV!C@xKGTBnq}!Pgb9J(Fh-|vHc%wu)NC2#!-53dloWf(+Hf`oC>KSip)z_a#`^b^>3R-i1 zcuxyS{Wu-6rI0cD^G!ALM*PAe3AI$6N_`Z1IUCaN7wuf_VW$jMCj}LYH4lpiJIs*Z zUU9nFs5L1;{S?7t2(8+-#387yXv0iPji+}m)@aH{CwH5 z9`^&-cXj6L*xbcSjDxoaRe!m(&G6_->#eeAHskU=ofh2cu+Of;FX-d~Z$uyD1Xvmn zqT}_v4Qe+_oOqHWi;}yZd|#>KMt&B<`~y_2cM{N6nc~eq&o&W(Zul>j_&$D*z5Col zlbpE5_a#D(KyS7@%z6Hg4l|28Cr7q$>xTUO+>>JdtlQMT*7Rrk`sbFxS$L!$HQTN~ z((=N6&=Rq@4gBj++e4CF{cF$M;{7CEZPe_e&_HYAUot8P6V|Tp{db?B(7pwW!h1AF zg)HRd4jY;WG+f6Mu%6;}Y{F|n<%V>7OZkxiC=m4QL+BIff-d!LzIr9az~pW+1#-Yh zV}X%oPQiLOz9pSwCY;C9KA~%UZB%{{xW6a2=Rk zdwkB|F@fin+%m4tM{x#`^dWV1NM6q>p=q?m=UnxP&;A1>q*`ac$d_u2CoFc>Z)NPG zT9?+@$#tVV%Mq@!TiCdFT|S<7HEIbN8tH0IcwD|6;O57fGnM`a=yr{yV?fB9rmTph zd}|QW-B$~3%482FgYDI+XOA41Q79^ts*8kfBs3g?jhg|(ipT~t`pGp74-4&)zEc=R2e z)$BY5lEvQZy&uf4*b@psKOQyRX$ghr>i+}y#OlA#hfFR&u5$UCua%OpiO#2>6PKxxP{m=DYZuJUcI0kQ7^gFA=*fte7^NmZ5>uA@_Mm6IDBicpYcH#OZ9oLOjg#z zw|;3AW_qUj*mka6MWd&*Q04j_e;2_p)!O9R@jZ!}y@kU-O$~41o3-!|($bKvp^e-t z1BuIlj$1s~-G+HfyWjbeB%PqmmcSdQJ@UsNg^4x|efCmG_V|U%+DY|x4bfpE;Bq)B zQSXx&bz)e%0?n-1>aw|z`1zM-bQTQMfn>`;CLwFDNmnfV6MAi@SU+YBp0Fr%;#fle znq>8Ho*;d`lC-pcJBvv!S5e04jI(2qho-zI{1N-1EXQin7Jm7BUGGCv(EB*)Ew~8} zz2NFNEvqs$0EhWKiP+AUzYXT`X3wr8JiRELZjf*P9$!EhrRVFCwj96aDTXK|*IVlJ zrXu$HrW0A)rK(Wr7Y=)}2EjKJO63y@d&sna`)=$kA2-?~-(S0egYS2cY4LRLR|Q(% z^Y*2(iJ`rvJv6kNRnA}hUOBB%?DAZE-Acm1j3Mzp$ns@6^CM(6{GLyKL#4Gv60x$u zl|%zYOeXk}hmlat?LKmS``q#jZr9$xwcXhMT3F-)CtZGDsWP)MW-*;n{`VUL%M7cRs?#7oIe11jCE9N!K2_@Ku`K;XVvPT)7Td);i@X8-2xjt-Z%>LejiRnOv{w0uIcG z9vE9pa(bx5P*u^?bJw)IWQu%@z4{*jqCj20IWT06%UiMRPu@?Xa7Ur~n$H?Eo5oP} z$4>RMYxHJrk5qGQWKn))B>UB8wruppclUlBxO=ZEC|Q_+fCpYHBI853h?SB(rj#)$ z^&GJ6X=9f#F^x&*98*LkNF%7N=F=rm%d;ces=bt`*kr9$RLtEbi!MLW7EQU_I#yl6 zktXEeA4=#n>vMCbyaas6c=}W~HY%fFRc0MZ)JADL7brHabM8ySv9X+ErD4pQ9I5In zr;^uW9QxKiqX9{`0l}`ANgUIQG8uc+WE!&SS^9M1m{T3AYnU`@+X8gRh|dECo(LrI z%_W+XrYQRH_|m8&t!8L8Gl0wJYc=C5bis3ib62y8U%1X{8QbOsI0WFDXqIEjI0mB~ zDp`2|0oRI)p~Y%uDCjCk@?N4+Kdwb?R~}os^+-vhZe&W#FF# zuf!c{2&BKAnk^32Wy@)`vy;@5UW4(Q z#E@#fJ)2F^@g9?Q#HdvJkOq8PMJF^BQ8vqG%S081Y{lv z^{LEU)X>B+UWYNuW6w1^A!mN^?Eou&euwhKY3b52w+42OAL3od=3(j-bB}so7sn!M zfU1R323tJiAE$rHsOYoX+uj+P-L7V07d>{Zcc$e8&IXib(dnKYyt36iIxMBPzy8sO zb3ouHl_Xi*S8v|jGVBi{8RNZMTV)P65CQH@a;bAP+Jst!C4vXcYJ{Sk3?2atM^V@E zu9ow}8olJvURy1ml_V+vI&5A;5sY;QIX%vDaa3kf~*3xzl_BtK4a$Q@j?s zMxTs}&0cl1jlbOw^FRCrO-~*F0EWCVdXriBowbX|m^v<#YUVXz$o=fQM+ebOc@_S( zYaQCO(@(13NI=}u8BR}5PI7&@HLD$!)yNI0T{W~vt);61`1E(=DfSzWu%+xH6?qTa zNxMX!;$Mz$wd=H!;Kyrg6sBQo3kPzq zaVLS-CbWa*+?gwEGHZ!tk)7R{iOD47pL0tM+|V}oq-1YZII6{NZjLR&lpJL7Ru@jX zF@f@udsf;l%$52I*AiTv?~Ia90~I7_+kx6~>T3Oliz)f!WZTy#fImJeYoD^I^2OXN z!>~LL#8z%<_C|^ic2!HKg*N2l*9RYot&Jrlzarv0!2#Mq1+YQ%`WnHS+NFf;7!XOo1nx%P2?RjP6xGUf)k@^j{cw&hN!m+Dvz{ ztX8)6@!ZI}xRzbG2k1HcPqlb;rm1^#IxF2t8YsysdI9O~YqPiU9-jrJmA{F!wwBGJ zD-_n}<|+<5{{Rp_pX6(Xtr=ZkR&`UU9-ABXI@XgE<)_qa)iN@YKh$&_p0#>!9cdmP zvbO&KglRPS+&=4rd1~%l_S)o(V0Hqy-A41n`g}<=Mrl_YqmngH4tsR2PV-YYw}wcz ztRUecJyd^RtwlUKmc0w9S;s@uHNT2F*NLsXyPZqyaFLI*!MZg3aDH#Z*A;OfEKG8w zndI$p{xz7A7E$}AsHFLU!j(0=D5z-@DOGaZnt7!_Nr>_O)l@f#T7`a>;LVoC|k0&RZ zamFwyHs-WOYy~_DYN@G_4JN>JYt33%#(rJ}Mve2K#cSh@fpQM%SdA}CZ&WD;L{9eHKC?k#UyS9f@M47#R5ROp&0qGv`%=8xtn1y~6cho@Tee~50gcvJ1Ml3PvGVsrlNid6opfY#LhBt=hz z`R?ZHKQKHuBD%kZ(*FRW__8zndUQXfu(6P>L(k6b@(y zxnsWM%ro~8l#G4@uleS%-&MU~fiA)5fC^E=KCE)YE{OEGd_`n9jyG?1AP?(RAH*;Q z0#%ANCz8@~2d#OW*Hg?%mU*8)-g0RoIV6LSD`kd?GI)tI*KJ-K?=h`pj&w|A;%tx0 zujx*Ef0w0lJ`cHgwP?Z;L!FF0kNFkpO=@SgmQBAjdvZs7oOAkDHCS>z4vKTf8s?nP3QaRj8;XP_pLz+^gRI!8DkHk>eBww&nvZ)6L)K{>+lcUe} z9YLb=j;9LDT^xmt$-}7iA%W}1&EC9<(mRk>5HZd%^5Z{B_HT!frmx{U%^`!dwv2Br zf4z_gn1k0U0}pktHy0~fS39UKhHjzZJIy$?%n>x!eSFm)bJ@KpUe=|zDgtkml zouKvvXZhxnQPwpZ>%Xu-2ojGaV2ts}7zg{roOP{jL&H*db5p*vRxHs;99x0=$I4Ph ze!2YV(v!Enxiu2Mx_HmUt7sl9%?ddYt0^PV$j|;fD-XktKj9Fw2#b|6sK5Y^-ZB2Q z)O=Nh$D{eu#$7*o9^8?Pg<<&+Ynt$FyHDXL2S6m0AN%kB0Iyz*AMTU$I3}%8`Wn;z z?$c=bn1BbpW8OllnB#B(LHFzY&2%?07{QQ%gkO|@TE)AEe0k3RV>F_|Naik8q19wY zIRyv5HMgb)wQ(eQWPVEipW$5n{F`r4fzD11Z0Og~Zg{tOtfXNVp1rGi{3bB?j<`t+ zG-lW^`2b>0cQzQK`uy3iG10a?;J0|>mDqui z$OQU&oc?v#`2PS>T?aw7@HL!-G;)2fQ2_q{%VIuA&N}Q<&%0x_c$kIHB}sMsk6Mz`DA_2Io+Sr6v<`IYOIf4@QsdHO66JbGgR9o@l(qG z0KCDbMlwmRg`tDhjfp;Nk%b(q9P@LRH=o>srnC!^ZI~){47lT|ar)-?aE~u1RKYEHwWB?F)7wrQ9d?Y61DT=Nk{G zd}6xTv_A?B3Vl;mytKc*vqkePtX!%)6O5TL&Q1r)F`o62apPsV(IwFB6YSb<1|r;d z$U))cJsG{a4ujUX*fm$v{6e!CM370Crd)ma+lB;tbspdv;k8Py-gdFo?$cTwJ=cq8 zTZTGbkECh+vmLON@&5FikMgYh?-*;)saZ9BvT>M%QH&3Nm-MJ^pgK>9C$YRx^2NJn zKP#MNTR+_(hW8k*Ust!4Z%m5C(a!|+&%JL7FmGciRFdjy%i|l_4%^5y+vU$9=E^cp z{0IPlTCoJ)3f4f1_e{9bCT;}wav7q}yl!_7!M_UP=G?7=){-e*PC>0*6>oP>LKR1S zbvwJihqrcCr&H4|VZPIw^LMX*)$SZ6oY6S3 z&uMh=wl=qL%iUNW8Bd|euR}UMf#dsM_?Fwprt5$f`wVCIS01Je{nq~greyQ{C$(bh z&Wru#tGTMB8jIc0o)I;u!6kEC-nANxDh{3N(Y#OL`~3pstkE5f%CHh9DUY~aG>4Ez^c+@x!I7ls`mcXRpIN$72c$d2NGQ!i89->agEEL zTDZu-9^I;*pB~*xA&PCi^zPlFQ<;Db|7f^s`mZjMfR z@M_Tv%aHQCXPRsM+zzzdl6j>7mmG0g8Ioe9wMKim&=J?YMmp8Y5BU9D^TDLXji^&H z41vccn!wF)anm@bG2`Xy(x$UelOS~5GtN5JJ8Es@HcW@v{lSWI07#^ehn?I3g2dF2 zkDE0wVXez?CgH%VDH#NDRqf_zrX&DILJvb*Fh;XPWko!F;ptq{b~<3LCA4I?3NlH> zdxydcpZG>Dd{M8us5)kn;x|23Ssi0sekA@?Gn|vptyOz-j=);UqQ%CdvgJs5Q!gb*q*mA%wdr5ozb zZ|ubJj((KMo;xT!*#j`n070CePeJ(8)5KQx^B0D~E4CkSPoFP7rA7;VG6$$Ng{*5g z8imlGSkziqLA4=JF&g?R3@VRc1$IJ|pTu#_vR?_8e=Wtu*tniZ<-zFa7%w~p9WXQB z*0wBJ&8`WAkTU-ODuBOIF^a;QQJs;N&e$sd0D0GWKhm@H3;WZEr!tZ`5%mCl1$Fy2 z?2b-!ozB81PqV_-%^b0zU>F>Namf1ASJGVEh^+0xERupxI43+R=jadTT=s+F8+%)Z zwz|qgFAUAdQ`nzQYqZkrR`XLg$jGsl0x1tb0Khr)9e)#9xH!FyBQ+#Rrs&q%bYX%k zOn&sZ`H!}H4`KM`w6pT#psROwR~EMq1=R8*1Nrv?@YjYFCWUOlarD^Dw-TO93CrHlGMuM#^P}7Thlz%nB!u( z=}@FxX9EVONYP_FbL&wekrcoTg6s4qtL9kCY<b1S#Mj?;H{{+cnQ#?Jh=dNh|xv=ygv4{eoE~Rt*qc+f?IkVn%t#Jv)2X0d%Y9 z$jUIKi62hY?!!~k{AH$0`caWCb{1;d8ewbFah2ARLHz>{HSb63|M`tWQ6)uioW$ILErVLY@~*yUbw3;!M*S{{&dwb zf$Q`YBF~N$2jfuNG)T1#t2^NbHL{vCvD&ov62$@m{AUFH2YSbbS;x)hY#!WIg>Bu- z6WsGzNwY+du2CBa^LzBA4KN&BC{Cj zS0c0-=~=m!qFd3eWWT+%uuykTGD11)xxoB7)=$J+i0-~7YtzEP(eLJDBe)NN{{W!Y z{iEFJ?e?2FWQJ7)2_qmff(nue2OJ+tGI<#}`e*5_ z2CsHSXuBOxhV>0MHNTR=g83 z+<1AVSp$Ehzsd;8-~a*i$mj8{fJYJ6qFI13%0x^Lbz`*tjB7^uWuXakMEKLh3%6Qn zF~q2?_<^+l04nMJ9KLP*N)K&5B0umdD#h_tl$MtQ2>}mnG?vYuRXF}&)&Bs8(iJ-T z0r#}@{VrlP>Ahlkk@$|TKw2=X)s6*5k(FQz79+XuR-%hB?{klo$gq;?P~7vUZ9-^J6aF$~%2)mY-U= z5-_yPA-c#;=@0w}^rFm`(bZmGCUbKt#H+{$n(K>;_E5=aowLyM_gDR*GJ6j7&tG3p zcz<}oV+Sh|aEthN`krcAx#zjLlIG@VCYnYr@<_#**!Lv$HDBykQZDZ(sOyqIs9o7_ zvM4rK{V6`Ru^)%EDMsT5mc5IdRHwt&ag3FXkNeeEMDnwpar1C9^ryufpoUdB_pMnh zt`bukMjiXAkl6gXel)9NdOrQW2iG6UtC(D---4NAyd{Et^)2Qw8&qex>DImT!@3=& zuVZqS7utQ*%+DD6BvF z>T)CK&k<;M_D%LnojT&d$iPdO$}PjvkVdxd}kN6HN)^tr<;lIQnEz!T>5!PSs#O!6Vl=>+=$MnuCidcC^W3Dxnk1L+p zw&04&xIl!C{*~&UD)2V3;meT?{hks`i0%;Yicj}j*Vy3uSD#+#%^Q)l)@te5nmtv~ z&B}$3O0HwAd2LvBII2>{SG8>!8MISqa)j^&Mi&Q)oq?u=$>~-}cEf8)hJB;orF%!h zbc(}Ui(0zWVYafilO(jD66JVMy-)a8i`qxG_l`oS>(3|YS~mLB%I$- z;fo(DK#gz!^CZX}`3Ak8;--PA+<0<3SuLN=^P|hgpDci!WDmzZ#d*T%a%lQwYcf9t z*v2`2ym9*1bqqq4G_G=0qSWtVmEN9b41nPZ;N#cQxE*I$v{B^5?Qr!w5O@<2lFs&D{G6>2#Z6XKS)F9&?;#0a?d;edKF;v0@{!jzG}ckU43}o^k!b_?pJHHVyJEe35jp zvR?BuygdT=M@Bv>)e(N!{{Zp~wtl6%Oh@-rjx*GX;V*9`zQ2-LWoadu%QTWVEX49j zKIg4i@dt=6^}R{&FX!_lZZZY{1F!>t2cY0rJv{qC=BAA&cR6m#sWom@vMk-CkX%ax zl`R{TVvHGbIN^r}r%_a1Y#*7bvr5j`72J4p!J1~H@c#f*@n*N;D{VH~(abPg?eizR zmu_|<7O3>Qhj^jj8MgHP4O0j5 z8KYoOkViSKcDuK{(hIC$T;vDGdg|A6lTD14C0Bc34^LXBIcXR&;C(AX?llEdvWye& zRGR^CNX~IuCT7u-_*0iH#@bM$JoEIaP=)9#LnJ7P$j;s><%_CZZFB(i4e3>cxNKsz ztnHwlJ^2maJ;h9(nwJ%>gy^KPE6D3sVJ9aC2M768YiR;ZeqI5_D%*raV5~Xx^fj9_ zUC7mN0I65y#wrj_Y2mXV6)b4E0Qs|Be}}CjNZ$JI0uk~IjP573a!?#sd!|`lYfWzi zJ0rJ`3%QQeLVEpA(f`|0`$lE=Dnl9z8jlW_yOWI z+TUpn1mvECMMQ123Rk7*9m9E+ISHy(Yw7uF?fvxTC5FCO2v}dM$GCF%# z6`<;^6cgHz35ae*Z1B0{d-WLiucAD2a|D`&&Wm|#9KJ(5GRJV6fgs_Oj=0F|K?ej7 zKsDqVH-XwO5o$MgSC&@RsS7j_vpY28uqzt;zj$C|u^bBZuy~ltji#*s05i_TQIe~8 zyQ3TXFIT>}V;Tr8$;sMq6!#hag0wAsH)#O|XK5SJcpu|kO~R~k>|PZ{1!taKsp2Iq zv?WlCchrtOHpng(*$22MKb~uo)Ge)TwX29Dk17}rN#l-!yO`I2D~;7O``E6gyOQ2j zibpOP(11ZbL9H;-yq(z?i2JI@q`n-3SGo~HFot&j09UwVG5+p)^IhJ72#dp3*8FaP ze5T_ZkN&X+xZ61-hT%f74x}|99E8a@z09&LJs`d@hhxzobsWx-LEzeH)x8l7j zTOR{y$)Q@@UyTCVOWWjjN#AfQ9C;rp3aOm1C+5cjyzY2H+&UwNRbrul#_Swt6+-&* zYyEOJowpbkJ7mvfj0FSqHM?nK_aiF1fWbeFabm3$nb(HAn?;=>+BiUxNcT-9HfQ(- zdi_mze;TbunW1=ZO~wtro`JG?-20?I`Vgl4Iq-D;BJquttH#T1<_Ra2xCs*S#Gj}0 zsXjD#cg32oj4$<%>`SSvW|W(EwO=^|L*+mU=N~8)U#&+JZRQQbw;8P{kv`7xmQ~92J&hBPLMCcK0g$YS7j^(3^fjfU zSv1;>t+ozYMN^MV@_#JVHb(O{?XH(ewomM%aLu+@J$EmMOu+yTx&|#KPSTY9d z+#mk6b6zRGnCcB;IE7Af58w3sD~k_N$+#n~v=aA>2i9cp?}@iq-AFvA5<_tx8;4_$ z%vRru^@}eW>5Hn{EO6?H&D>E8CC?ZV0o7c09r}(&D~$0xO%I3~-2LdGi5u&%6a4Ek zBP?zm8I^}d2LxAdu#2?T=P$N;#q1=Dh9aXGC+SkpBS^)Z?sLgLw9IUWC#!!d=tc~U zh8vnefJPUd`R_sL*Xu?Ado-01%R4mBNS#Yfs=y0*4PUJ}gdK9qHhNlfm@}7p~m+=Ep(luyh zYfCd^tK~~+Zwke^Gn|GTmjsdv6Wnw)>eu?UrQV5at?5$7J-o@7-A__8+pz=yLFjAe z>yQW|il4&1DY?)tCbpMz>DLdsM8-;3RC;bZkN$*fGvVVy4~nkglopES!gz}J<7)%?s5Jio7-~zYc$-wZv~c$G%*?FA z8;2MpJvvrzhN0Ev*5j8%({8Wl0h7zOg{34il|OVI#{0%eNIA4NYHsuD@!Tk3-ceyP@W#VVY=kUY!CeOZ=3%470^7! zBr)40cIbMnLvBa8>VFei7q^>7mY;dLnzY#sBBI*b+fH^!WXBuG>+6B(QyC(g5i}tB z9{&KPQv~L_pNBdWcbdeS?xhPIH%|TINM^&`GJd)GfRTD{JWRNa=xId$RWlI$j% zXXU`ZEPi8VS+V?Y{oM7y>H5~4u7z!6f=RI~{{T)G=s&Mo^-U|oR@QzTc`hJXt|vQL z*z&pTKAlZwH-#={CDI@Vxy5DeR>r=`txq=9=1UtVx{@$eP5|AF#QlF7&;HD~)NP`c z^#aDq7(lJS&-agWj@8)ez7Ce_#Id!^JMFC_8$%qUNW_wH-vAG6pK6BUD3Ied`ZZx5Pt^YU1@Xk~z^M2EncE zBUYL+5o9~m3|XL~DA;r{>?BI>#vz#~IH z&SM^{o}=6H#de-9_X;-uB?%O(`6(F zmK`78*!ueQucZC}{6(?RwF9SL>c}l`lx|rY9#pIMNcJO-%hI^3&{nzGMzeYxJ^hi3 zb}|QScdmZo1Czyl9r0V?{i4_(75I8I7EX6u!57?!lf;RRiceA4ob)_+Mct;>AdFWU z_gU2KBy*-NdQ`E(sJ>)_Bm2I;;Z~-DZ$Y1WBt~sFcpM|)kGTg2^!+OCO{`~6D>uv0 zM?fmNlao?7$*9j2qC_@qMm*OKZ-)Ke@~TEg0Nuy8Ca>DvJa{|8mYqJIZ#A};WiiZ_x@;odU)hNHn0ph7;n!Xf#>+Loo1Wpyap}clPjwj^Mshmy z)~ht2j?UKp?jRuqU>@PU@r+hvg`MdlxiLE@CN|-h*Wckcm@d)Mp36{`sw9Yvniexs1<9#aIxYzWNJ4Q{B?OHpcP7fQ!MZ`e2uA`j@4vZa10N{g>!QlQh-zi!+ z)VeDWd1JSy`QoIpw=-S~Z#F30_mQ@N^*z3(smkI?$E^5n`fYaJ&P|)8Z!#%HdE5^t zKd;c&p=p|(rIZP2r&`j>t^|w2a7I7!nEj zoqv$ea2mUf8rkn6EgGD!JXak>snG^&>K-)lV%-RnUAl?Xz2?BeH6Z*b)A`&e}talhIstFvbfH72E(^__04&~H)8!R z;dYK#m^w&@1xV;cN>>?9>+RYU_cm=CTihd*kyw23vYcZ*uxmQP@ZMeBrlW9G5+y5v zmS*G+#~fFpd__xrYe>^PQ69zAE@BbtD66$hsxTxT><2xv2Rzr9M`nw9Sg=-n0?v39 zaI~V|Qk!X_$`zjED-w|}-Aw+c-o2kxw}(*h29>HLS@Z1;w15xeh?V|DO?c*&0^I75 z+vjfi0_66|ucNK3qCW*8jyT3G^#(-GJTzec07~G;%az3H!mHf*?rl0Li!7=mag{Ek zpU2c!nQIo(Ti#6sssxd-Q-hJkdxoc{x@&I|t^;yO>^q;pb6!8>74Nhr%j!a}ZVsaAbF8SI9EMM=zCI5Fi+O0$Z^uWxayA?=*zdj z?lA_=4ofX%+%pFPFiGw}t$RqG_71ozK4v|to!tIeXl=j<4l|0V_99EEiVKcB!TD5+ z<`vJ%N3}&#$HD7bnGXut1m_j2rcW9%jGPwYslxaLN`so8?4*#%#Y61Nj+&!h+SnV1 z57RmN)$6z;7V9(%fDYCko|T6b_b|zV$3BO>Z5xG?PEx#ioG|nvvXW_}i^}S9){{V@u>%#Y@U4Fnb;Wy(0 zjBt1Zw>9SB$Z=f`kth+of>lYP#E1)Ha2;{(I5o+Lr+A%ICutoC@h#eGb6h(K0dh7m zIL3Izb~YO1Z8TFwA%_@rZgLO!f-A~gIhsa8xk1TpoF0a^% z#(nFKwjM1mRCUp=(|2d9{6d85lG^y%&M;F@P?w6F`FBX5KmGJD9i7BD8hi0!eQpI=nI=Pc|u|IgVuP>U)pn z(ANwn?4Pr#@;apsbl%}#{igW9tc9o4OR8VeI>Q~;8e&%OX7^sK}mHFrZ} zl6#g!ZyF;ykQ`-6?mAafr}(Q{w(v#fg=u%V$BU~-W}s94A0%f>lN z%K*=6Tm85RB}cqxkM5e5^G3b!&Z%!>s>X;ztdUO}?}~V2J4BJV;gFIJe!0QoxqVXG z?6=}rmk`gEP&zAr68$oAJ&3OB!FsiqiL|fyS6(NSEEh$;vNZ?$))!6pMt|puIya}xx)+6&r)SjBl#hqM3Yn!IUbnACKi-1Ob@~|y{Dpa4_lmVR>K5;;m})QM*J%k%FKAWmI$-_8eE3-CjGnr!*lC3sozq!BC<9o z@h-83Pwfd=NzNq0{-hIGlIn8ES?0F1m5*}>U;PIaL(L_5saEpYG^?9;wMUvpMvh`m zV*@z@>ye+OdXS`}vN&Z?z1SU17a-VMAE9yo0JBoAu>u^8F5B^W5B|+r4#cshVAkpg z$C;fV@g>BOn9>L%L)0j5@us$*WKWtn$I)vA9~EFZAahdbu7gu%lya*%Bn{rQ_Lz~# z)-0NmZi5XK?66CmRhi>M|7v0OO%Gt7j=|HUNRLc-)Urc>Z8k3{FCvoQ~C{ zrOFy3Vg?-FUc1;2$X>@Q+} z_((p~8a9van0U_f>Bj@8IqhCuqiTzdXZRpByRQLW>yxPQ<-Z8eC;%AfzV@=N4 zI0O#Aop8pBjaMbH)hen~(q}W{WexEQSRPO4@*QE#Uql#-*RoRxn>S-n!ZaNMHT13Go&{b(jQ`0BXtuh$_7#z?6CXbn$ zEmIJf76^oIoMRbVt zQTWx^ZMtApt7{f)aa&e8RMXEK5J4oe$abW0sb*v70OZzkk)&c~!E4is)3mdeY2$(j zURh*qi5zNKocbsnlk~3s)8Vi7ZIbFfG}U6zt&b~gpiOlrutCE9Ir>$E@h^t7X^x-Z z%_d6;r^GU9_p*7n0SUn?**=R|txF%_p9?>RqSU-);|nB*PS7oy@vS6vW|nmsM0FY4 zgS6oDlAKq`9wzY?rQ%-|Uu(L(!%usAGfgY8&n$WmVbFU4Ur_vK@s*N(&X>AYj}f=F zxz!@Fj5ptsHB&1ydX`|Mlg~WY$9Gq044HQ4JPzi)JRCjN&p#C>dmUGXyg_l{?QT2h zGU<;lXm?;u86zrxAVKUvJ*(FIU*c^V@8Hg{3|A>Ux6;@fQ@~@kNnMzZ#4g}RVtp&X zv};XIUcG3o7t4tTWRn>R3BVckC!nuH@tkm4d^*y!TPtXyhSuq%X%$DAD?E7I?bMvF z&~N|%R+VEOc)p}kl(`z{aMDg9;zP8b;XE4Yd?(=jf5v*3*fd)p(ht1TIE@pG{LFYA zE05OX-{Dnu0K5`~C)tPp09*OfyalMbPjw1Ahg?dVSguBS9Cpq)s(0mW3O43Ro|SX( zuFls{mdjW1?uBnGPGgW-Tijk1AmD&Ps-MoUT6{V9S!o#iRtSbT|p(ZH%7|Ho-HiEw}^XfOjf49YL;3lkg}JMgjC(h_26?{$JpnN z(o2b8m_mc*W>N>?oO4Yy^hkKk90OD*N>i=U$_s|%KlaA{v7Z%?z?4o;$2F6Z7)Z&`Q_Aa+hk<+3;pINpseai zCa!5tEv*bK3KX%k^KNj2^~mH8Ppx%&KBE-6ftp5997mIkX=lQ(Yq#)%Jt_BWUsqgJs-W9QrM?ka8(*yUDfEb>n z`k(QyN{_@g!q9J2h^WHs84Nut-QlE3ic{5|boR*rDv_!T^aB-ARtirQyLS|qlgTtu zBBMFlLBPp80h;CJkyw^i1ZS>mSn6jj2&W+WRxRzEaw9H!{*`*>cF&fF=Eh0%6_qq{ z?%n3dNbXqHh{>F-<+DR_@v!6?qab0ETiTMBZNz-t>mk(g2qrVSU>r=z$h>VJbQ6#pK z-^oqE6NZlH8E2bNE2(Ii8YDoD)CNv7^# zI@QT7%ElXv9D#x}`F877Btj2Lv}VR{Ijgpsfq*nlzGN-;kox+A*!%t!K#WsHb4{ed zHjTlx*K}ucdj9~8FvLjC4n1m=4)OA=L90USmBfe}+;D3)nk_WRQrMB6KNC~M3hu)( zAB9jZ%zi?1>6&y`a-(B=52>kXvXe;abjy7@Hxpml%QPdZiF~r&!vNPs4~Q+S(2oyj zu<4_E`IkOpOFrEF-!T2qd+h@_)FMp&WUDyI3QZUk$=!1Xxi@vmU!}DtXIf6T1AWTK2tg#sqHVjml&>!A80OKS9$vrEjVl5Q6 zIh`xB%q+BsmrDXiSPLP30muOGz;!q{Kb>vI<4OEEIkVGPO*;U^7zf+vFh^2)3c~Sc zi7xef>&ve=2cv&C*?fg64)KO@<7FNnjG(___EX_VPb2j$@RwYPEV=FUcgnT zb1TS)K3yVu_NU?q?zJV+ynASt7ci9u_QU28smUOr&PI92_uzG?wYyy-!{{zFRF3}u z%md24ozhhY8Op{60mmS|eTNyW?~B@X=lmo;+RK>jUj!gwfI}U?_b0wKIC2PwUbN3i$d}G;^k_S!72&_~Sk1{oKw7FSBT+}|tVfHOiTJH8~e$^yzD*~X5 zk1&pMdhHnFt~jhMM_Nr!Q4`0aX;v|93T^FTV1)N#{-NCey1B;YIhULOpMYo z-opfp@Nx9TR$EZVJOSRWHb@$6ofn3*Uph;DU0p@GTzPIcWUCLD4_}yaK8?>6^p>5b zM&AaalJ4pYRg&|}21eR2tGBK?^)>T9h3A4@MoUuh2qOYg%t$U&{m@5j6P_#Cd~c{+ zTlh~y)49ljt{F!F85LK89!hGKjDE6O$9MoYPwiiOXmcIEM!Nf_g0 z268uXvPjtkR(#0Ha7Vpq+_S3!Ng3pGRAiN#t{dtr=wWlgovvKBk>k=2d?k4FP#!o}DSA;b~Fwcq0U6 zn1`=gwHtuLHCMejH_UTUC32$dYKxyO11=yF&B#DWj=;<8MIhAHahMP})v zRXt9vFVCEOuz@N+3Ryl+Chx6HBK zN+SrqVliF7@-l^cgV&BmGg`M-7SYQ0T71a%jq@m1%SI1HVbmVg=hwr=e&a`N8qF?b z&sFh9fn<9o*L*K~9uvtc0G6B6U;s{cDx6(PdlMjpQsM4!g!XXOa14u(Y2S z>Y6R#n@!ZDw~!sB;g@MW`i`Q#Cr0?m6tb##r^EVYvIa9g4Yk4dE}Sv?t#Zm0sm9Ay z_?xLylexibmRELq<<+&);$)D9AIl!t#w$D{0n)uQQos0Bt?Clq8N5lRysTZ55L|#y zC%PO~azpUaJCtSB{6lgx!ixwHAI?Mkt4LO~Y}3D?5~p{gI9t18K8-T6egDJ`z(KH4f~moD8mGBNZNj*(y)r<(Hlxv)bdkfIT#VQ zyIzba|d=l=knNAj=IzxYzW3I71-K+!+%(fp6!qCP43MevtO@K&>{9|35~_DdP=0|a4$k+Tot^#Z>hv5}VW73_KT9Y3v6S`@OlU`RBYxYM!HTFT#R+kuVTgY~TzW)}d0 zLC$L;-d(pa&PD@;Bz;H!09v-hMoX1Iak$_gO2zJLxzOqweWacqI_=>aNuWofyVL3Gmxf@omod z2idgf+icg;E>s@sgZSIqpzcRX_d6{M!ru?{8;gxT&vM{4<@OmHqMojQ-y_P>TG{uD0r|bjDgJ;!C4C**x_mWXD$lI_E=A_|r1%#Fvq+^O zcoUz-v00(xJB~TYGX3vPr^Swn+|A^K6Uy zDx^WiAxB)nx1h+D+4doM%RXV*s?o<-^ole3a__xI@w(ml5~FEBB->23{XRBsyrCRC z&C)pnw}15uE-ZdMxVFi#0u~ZX7g%1@Sqd(2^phGvXA^_n1ZDk>9K z{|*YQmQ0{&O7?Ds%ZyFN#op-1dAwMZg_~B6tE|kSX{(LK7|&gb$dkw$JgucW7!<1; z&08iLgN$RrGzCoxR!oG~E$1usk<9CN7FqPh)jlUe%510Hku&!EW-4Za4~O<6U*C3I z(=a2@9NVRxIed~+9FM} z(`=?mpB~%K1Jclot+r8PEz&8R+*n zr$g_U98ON*0Fl2!_OAkj=SG%?b`*f&$h)cGe6Cu`){d5Mcbo+C=fIgcRQ>GsESp@( zp9%cec8SM`Jw+AgHl?nvAXUzV50e&3?_88HUBzv;Q=*;U?fFWL_~p2Jb9QlP|9o~c zhj*6<#Xs(S14&d}`f}g>5P0c`W-sQh1-F)Dl#UFIHduJN7bMJ%jJrL`=^AxSd`J2_ zMx68@WdG;yx%X|{67@gMNMK;#=f?Ij>y_7Sk(9>q8y{oJu6fpBH|#KSN%Nl?Wz}C6 z=8ue2Y5gq#6+!T|Z&d--6BI)@%QF~q1$Hk7#UbW|kGWwR-;gNYZR1rzRERx7&C1kE zdA?x@{~NTaXt^C%UHSr#W_O8U{lYLv>1TST>-Vh&b^D&=zH%d{wM0Bxn)_@&$n9v)jZOQ!&8Yl+SGRyCe67g1tbALaMNaad+VsA=IEsuuzy4ZNL+AN? z9bqvj^j}f6D_9ZGL5c&^=ADooMAR~JM5FL63%?tP5GNGQYY~7@N1b-TJkG_qUZ#V znOQOYn5m2~zNDYZhCFq`HKa&| zB1*+OK9?|2R?uWmLSG$Y4Zz~Xd+*^mG3`8$b2+GAZ*zZ|7izO3%9=qhUkyI0F2E4@ zM;#jl2Rf$+dKoKKQj~40dxD5gUYrmIuK{sGz?~@D3h7LQlEOpnP_OZxKgPeToWUVo z#iUNE0Ny4U2>E*Qr0x^gBQ}F?g7aK)eJN_4GrTRRI z8OC0-UFlcVtg{P@*@IP;3GM0%A)G_W4Nx^HA~8*(-K^0h^@DD~Oy*}ryhc;3&Q<=U zv?t3YKPYLU3#z4(C@+G(+yxylsL;tQoduGvFTq~$yjUGn()z= zwR-|Hxy9+muUvoc_66b}Z6o#jRg&d5B)*FpV~m~Do64aDIcr6BXaf|mI+%U(vVGJ~ zbJ{-TV*uIfdV2`3g_f$o8~js})Vp{5#!`pd8cQaSe&{bIOqMBZibME7C0(EvDR<_e zt;(1)nD}h@Pd&w8t>rx13_~hSU_xRCxMs~hb3 zy9a9Yi{#38^_>AbLh6uRW{SUFIv3?%i;CE2xC{Mn*|2-jrDnlO>G6AbUJujq%MGDX zE!9qSV|%Ty6yKiCGn0$m9O_7tZQjF3&EO%9{Ip^DuV|kr(MMnI#w^UMbzYZCmxD=D zxDix~CD8`wTYBa?6;PA*B@ zEr0>C{=R~ijv-LDn#AF2$ziB`{Pp*;&ca{DUtc9Q$gq#tAS7gPaS}WR{R;+?z-eaW z5q-j0pT~KAoSE)Aea)tEwLNi71ZqF%OP!l6I8-VKr8FJ zQym8xjWjBU+D*@0(@MT$T^~j^MlFZ&aqG_vuJl0G>hKJ;RmbbmqeqhZM?1 zo2m{;8T@p?^!TBT)2RHlzB`?xESPqup3<2_UYi zEYTT_YrZ#oqUl%K&{NBC?eQO{CaPH#Gg+-O*_QM)n^_$-#IoTZw8)i-beceeEtO_F zWS&~HBRtaf?sytC^iRCoj%w&7Mq@1CejGv1)~jqKpv3{zKl-!}0t{l(Cc?MllBoh{ zzCRS`%DnD#q1B0)`TRLp+p4uQemZ5@tFW7hTEd1 z#p{>>S!T^Gsz=IZ?rO9S4EB=s*-tE57-sF*~PJ`o<#IB5BlLfT=QeFO{Ez53pMv>Rsu>M{@zZC^^Ni|9WFT2#Gbr zX-83Rs!7Nq6H-D-R~BO(DvwK+kLYKF@#{{iKeM<@@i8=faRh#`Qf$rB6wtn6XHHE- z&1BUyjk3uzCxGivUT5R|u>a8S1UvDj-9HEo%oJ7#??JvU-9AbVdUlWB3#r%dTO(Rj zWNma>W$Fe{Ctq*^Ku7%~d>Ev)cKKgd6$u!*qLcb}DwT+uYGxlI$YAraEM_=aQU2m1 zKV5E!=+zkbl9d!6rLy|hxOc;aTvTRopeC9KvL-a_U%u|w_YXi}@F&p$=`f$rV%#Z& z>km3syfFv`+{Z+zm=2c1e@Z_Ka%A>|UzHF#;#-@gZjOI3!cyqW+VtuP{EIxcOy85H zyJzBf=E8Gjw}3sc67A~%ltFn!!5ZI{_~&kfHiM&Z`n&Bn1FUy2!VZ%E(B1LxYsvo( zgfwoNhnW+(NCJPZ89R#9s=3$;BAb`CMQ!6VY$%3?s?&m>*1kMN$dj zfxP1wnD2FqI^RG4wHR_<+?Uf_hZAR)lK1iYNp#6hFjq~YyP}XC0sjg|0OF&2uL7P^ zkVEV6I*D?XJyX&9gWx9{DVuIIi;iloE?&E)LmdI`5#!Po?gh*D`n6~^R1tW?h0EW% z@1S-ydXB%Ah)}8a)1|XJzH3R74a#yO2c#UOIN?JfX!NDS?BH-X5ze8IB#@6sSNgG8 zx+p%7c(O?x_+qTX;^;mzWNft* zWF?_ax7?MsojF4e{ck}2e>RkcL;(yXG2OO9S5J%=ISUp;>4G7%!2$(+g=K!vv$;%q*OfpZGRd~=Sc!-gfBba)13d#tuYiP8U| zoFt{JLms|*PAwZNatf@fs2k!ipgn_h%e%wY2u~I76e8Ro#O|G25tt{Z#-%f+>W=Cu zehw&7gIOUd@BqbuQPE7Zh*!I+f|=DMh$YcG_n-^LQX7Cqjr+IE9>_5pvk ztIXfAkOL;Xg@&JR1_EHzj#*6b=T1quOUvgPbItLeeUnB!kpU^k0J1>>jN)q7xW)qZ zRLK5#1XY`PPO5rK9DIrxCo*;fQZ{Nl+e>TK8ldk9Uy6Fq>eouA>u|R?#N( zn$5;zQSIpF+W#BVMwi+;efHIOD-9O@mbaJoQulIx-WK;_pMa2p z>^Zrmr#Q!{mY1bvIE(u?Job0QZ?I@yb^OX82H1KvfulP?g`_~yyUwTg{O!Qqh!`E=Dyd`KFAx|Zn(>%h@7rF%$@R_Tm zQ9!l6)qDdHVn4wItDg>+lClj^9O`AIBfef2a*y81-_ehvnm4q2UC6BnISqc8eR?I+ zJ(7Z&fjDdMrCukKkdDrE(yl)wL{tZ>M5)YrXYf=OH>VRaiI9}H2+J~j4i%IaKB7og z9@0a4EFl@6{7{6OV>SCvDubwq+R- zWLV6-J97$8yFBQc2YLAD_HO1$LMSjkS=nH!legW${?0nH#5d1(wV;JTwS)A!L^$c{yy?=;*Uqk%6o4mrguoR`L~DSqYq=o zApCnk7UdVcmg5L>MSs$3VyoHeCl$Q^dHGkIo}F!VjT#yKQP=^TdhGYp(p zDj))s){EfM4!-+R ztg3RO({)#6PVn}qntRQrM*TZIX$z*4)M=GcT!3Bfr`X>4LwWgGV?~rsj0|5w7or=5 zp&aX_VxhCox;MV|L5ZxB(x7Q0`o%{hFSDW+cbZf4JNzd;zp4W4_mTe2-nEF+J6eA= z<63w|eD(Ep-(Wfb;`41gy6Q2~hDVOvV<2Q0*aMC7Fcd2EHA;Tp6aM7>QVjn#>kI+~ z5_gEKgOABUByzst=j>UQk~=1;HaIkNAqW#8ZB)WB3@zA|rCa(BFvMwqvkv)Xc@s=n zOq!SS4-i{*Fg3NCZYQgbjq)6R3?m#b_LnD9 z?lVn+7V2I}gJDRK@L)ECP!q$O2^Sw(m-gX{o6u8V5o=tZMG!}ERRbe2n{TLI*LP{e zeG~fUQ?3%(KlbO<)7od88-zY*B-ocu0-=6xOEaNgp+FnmpI4dZr+Wf*JQo}<)F>ie zF{-u5VQ;t&y(~`-r2Vel)YDNRs8hXno}DcnBIc*;s8b`wgd_bvz8SmCt4GQ}qbHu~ z`b8R~b9vqlgEUH_Qlz|f`iE;xSt*kA{b6o z8N?q8940GB@mnH=ONyC&ed{$S7)wL?9GJ56=;159hjTv_DKv02+#_@C|3)eh(xt#Y zTrwS=np|Qr2SKztrLbQb2$#T9?JO7mMT@2$E-yj*%prP%t5^1)%)Er+knHEM?J?in zRRo%IYIg!lIcxetTh6TD#pSBm57(8OhyunPHF*H#-g40gdkm^(J$t&(25sMfBak z8@E}jf?D?3L*y^gXaAyqcuic4Kd$cxLJDY2=eM2hB!w{jVC9TGUcdd}{@!4(q&)<2 zBwB^@alY{$LM&_lkjLpr(Vd<29x?35H>TrlAs&ID99cco(y+Qd&;Kug6q;dOA_OO5 z6TICnn-sr>atL#G*p?fYSLnMne#_JEt0L%K-_odm5RKQ7Sa&UO{f8>TG`VnRp*w@;K;<-JMY(tCuHnx&4eWRESWxhcPxwbi$BdhF?; zEh2=Qfs@cUlVE2)&Ft%i=YJse^DIgrz=>b>*dQ(CR>Yxy-5#%5&pToJE0cuRWodFf z2hZMi!Mo8g0VArkc;*Gm2GY6wW|~CnB4;BW0AfwZ)0dHBJ1F+`b5?_kq?y2(MbEJ+ z69oM;hB&E%(YfH9&hbiR*LMTWIBY`HF4Qhc%<{@B+7ez#xh=)ctf`3uK3wm2!9FGS zF#ro(21j+8XFG8_8GSpr&u}#e)8i;^qJBHMMu`2aMK|Nrgo0jn`#E2ayd2W^Ds`uf za92?9nBJdDVJA0PGd0VIpBZJ3VfiAp_AB;AC+OMlE>BzCOG*b1!yC1>{mzzrj$bJ+ z#I+I{7Cn8+Uo}2`*n|boU@XL5jA@vwRR1T@1IWJ9zKDn!tyHtRWMQH#Dq^Qyn~xb! z4DWgNcY4~kj18KOr6fLZazIyv!f(EAfcDJw*{;e8Jd>FcR1*JQ4aolY5AaSl;kImj z&j4E!SdHqxbIc=KZsT3S=e(4JPE(fTk26z;^$RfDm?%gYNj8Bfmq9O!|0X}T%&s2t zI-b5noRt_2votPy!EX>2eFvO6Cvl7QQl2NHLc|<9i*#>W!ZM&`J>H-U^RZUQm-2Rm z$Y<1Hg%J=P(>UWmQNE`)N;VvJB!?O5W5bC52H_Znk~UDm8q6YGBM5|+>|`+`Dit6( z0|B$BJw>eakgcVKU7pqchCV{w6As_Y_&0_zLmWYv@W$=UDf5%82i7^v(_ld)Yqwt| zSegMGyVOcl|C?u9?T@=a*k5`HJwLQSN$)?v9i{m{08Yt2z~+G#)|eZgbi2rH178s= zUX_vFubu>=?9C(o0WLYZG58w)00Wv3dr-vKJJ_>kHX!l=^bbI-K1J$?b5W|$7tUFD zW*_MTqDJ*;oL#4oX8Hxa{VH&y-)eWM`H1bW4o0kg>IlPpm=?&zpq@jLC#g4i%G)HA z_%kk71E;LI5M%?w?>9C?R`$PY@Si?5NcbFfUV|3q-E=hD?)EXcqwdLlIvMfrmg0?6lx3K>zN)f``2dJv;Oul`bgYS7%&pMU&6X&KLF?%-{j3aE zXqey6NzUxM;lKNhE|7O;4|U^JU@CEMmm8x4Td3azMG8t+3OLwBh9sU}@YW#TPrtZ2 zx6Gyn$xFh1bxQ}!ZjOTc8D7D3X0K>YPIklsikx9TE*ZkyIXV+6y?8jsZSs*zl-^7HEFZ*>1Czevg%Wdy~DnKL_yvW1SU7&oXS@+V!{(0R8v~RIemxnn6n!|LB4x6BNz)tp{ zW@&hj6n_&;E`2giN!dH_4L*h4j+#(Yo_H31hWOAbo!E+fNX>^XYS+0pat>U1CLB*v zy=jn)oRXl`5lK%5tteUdIzOo6Z-R6Dzg!`9UO_mPyJsL9G$;}O#IB{4P{a`Tii>5h zC04LXs>LEtgtq0q44LLr>g@B-T*zPy??ZV-wQBQ1GHu}}+W1mNXPdy>lEY(jgO@1C zwGFGr;^W?XLSxti75D_lES|;ICSZ1D+bae2<4-p(+F)eHQ6K*wfKKSlr!!}^a=7(9 zE6vA@CVpxfe7{Xap&Q769P|^08+7%w1^a(-UO<&+t4Z=gT)+~{(MRp`$-iZB?OTpx zvdU7U9GNap-@Q01PAh242HkNx-B{~1$P;eF3n_w?6ftr}ZGkWU?n;xPR*IJox*J8l za#vP1Kf&e~XehyxGuft#LSXB{#Mo;3!_!y$zJJ-O?~1BZF}y$fkktdMZz7aEd>D4D z;s5=h^E;iN>nb^W!L(ui)d7Mr=5GTmI$W8B=jNlehWI-<%%M8k3z5}xrPBGH%0d( z)2p14wo5B~wO~T*=6P59hlZgnSo9U+nQzIDhk~Pj0N3Uqh=kq4_b&o*aSxoD6a4B= ze1t+so*$Qu`OEd@0?*i@j5Q|L$;uwKM`sEHQfh!9OG`C-61w*g3Y6Um%FqZEtDL)) zO<>g#pAA#Xt2d_&_CmqS{JRIz+ZfV=n9YFonRzh;-yiRPTgNhJSBLQ(Bp)U0bjS;( zHFqWa_l{5Elce`$MeA{)Uevpy5SuIe16vk<{iA85@abSKW!D*|+V@7kO;aHzz}RaT zhx`ZMiS8GHJ;kD+DzMH;mF1iBb_NKNb3+)4AuczkTMU72LEx^nrApYQd{;G22R3gK&H!_?3U z*>m##2Y}Em9GQYBZbs4$2#BR_Ol~B`a)bPaU;5h76Geq9?@w4fOH1}s)zfifvAa~< zlm3q2#XqE8vzn6B&R<*JWsq+?@)Wy!BL<3eNit8Y0sCn>J@tBCNf*78ni~D;E@B4g zVP0Tf59tqDi-r;4W_9+NIAxiv+2s0(Iesg3Sb_Qu%1Zs-?bKcUqs}p}Sc6rYo1mZO zRghzu2vhD4__|-yHVPyl5GuT*gzaa$57XxE^J8mG^56VGxZWel1;OHVrP8BB*v52^ z@yi=G>kU&jGo(;MICG9Gg6#<#?f81&{2s8!Edq(M@4L?BLYl#-(ae5tSYlQNH%jv8 z9>H#%6q&ILM%e7;3;UzqvmH`Ov}I#wSF@qBU=d~_$HYc}y}%1zrD z`z_0)nMg0RzS<#|ZkiTbJsPWt&v@)C5B*26Cy{c*4;Fyu^46cR^{uG(-+0{S&jMnI z)<-$%OEYhn?I&#JcgJHxnfy}*Fx)VGBxQfPm)L6=Q6+szX7Hp=px=SAU=gQ7^E2<; z#vq{6a_A)F*^jojRrNt{@fn;Hb693b}h}ki_aqG)r@vDf!I)72-Qi_qOlz>aGhlZ{h+st>3%yy-+?6;h+`3(--+_>cFP0E>go+Y}=GPG7t zm@j;M7drl57+|cx)Bgo#J9zkB!(R_bjF~WsYnmiDzG6|6e@+Cj!IcKBJ7JyEB@kQ4 ztq9oqAK)Wl^}|!g)obobQl~1mK^SqvI6Vp`-!*4%ZC%2gcl@8lGL`Kss-tdR(XHLm zs<~E3w3$%-8U82NU|F9RxiY_K!6APyiky#4uIb1%eh6{1HnMV;oSe97cops$nb_@Y zj(n(#eDAm;-uDt9syhbgIpS#gz6m8dq&Byk3YINeQ~L*ytUO6tJI813qDPv?`e32T zZa=|(r#_s(M0>LS&NQLD@=LUG#hYqZt`ft7)YQoc&d0La2c#cS`XX~elk}>D#nsxE z`bDhZ5ox^O_btfo2)p`OR{n!PN1bFnkl}VK~zx}!y)X{5`n1Qgp@@AfF zIEcKhA-?BTlPtl1`m)Hu71wV2YRWu1xcx59p4NLybooWv$({d6Hai`~V)5$LWJSoH zA*@txpzAps@a&rd3!lY{5=uS0EMQF_&Rg8pdnv5m6!cAP6gj~DSA8Jnu zBlOOG7lROE>z7z)bF8}hkS0{1_HrD}5=w=gbv>1iy}S_RtkHru!Duk$#fGxzuh7Ob@5RPpD-qJ)WvYH$9ko9{x_K<{6nf^2X>`h~ zC<|r?{d`}?{%NR;@k2}kBo#hY5=E3BRg;F;9bST+#3)(X(L8SkzA?9b+<0kxEKSUR zN82gJW1IE1=7Wt5*pG;09iKQUQTD2$a8X~OjI{^vE%TU8N-w;bQqps%pJ!9%1&!1b zozIQ^n*{SL-=P=#MpV~zw;RIixes6(Ls#cU-o-wyvBcsJ$-;O6ho-?dwM7keM+!|f zpIo?alG2k}eQ}D_@iZ)9M%x?KE&>Egp6`N zS6ml{jhuzu;q71vfHRI##1C`C;Q`g* zwe&x;{eIH)<&?Y-r4yD4A?-A_XI-=7FWjNZ=9*eS2Ourd zmig0Pv(va@GVbzp%YDMKOFL$`omOF64`eihk3&#!;8eL-U;f4hboN@EdJcAE?`lX6;!8fv}}4SqZ;LG`i4Vlk%|C;TruQZVJilejo|;vZwSN>Idyq}CFE zaSWevE^X7Pp-fC|{!Z6~kao z_n&x^P{!21_S^ev&_^)|=n0&!19sURg?HI=pZ@{4h!l%H#)mo;vJ$=JQ+;_=a(pPEGLc5qfUaW@US+bqr$QD}Z98cMqmWsXEU#+3w6dj6)$ZY;a6TYntL33-Zv#oMyE zs99C#8S%Aga{h=TIHrYeu-)mIHkLnBew-;I4kvZ?sSHSrF4P2lCjB#~OMet!R=L0k zZ(0Fh_Aojq#6Z~%V?{>v3!KHG|El^)f01U^?wg23Cd5JFJ|Rq5~R;Be@Z)zY4H z-KMY5dsPm^CDVDe^x4XA{hV%VA5qd_0wj?MS#5asM^&WXoH#DrYOZ2O;ZCLC3U_A2 zqx$o`dRRd5-9+eqC5ctV;%cmmM4wm1{>1MnqGVHrijs-&1xg^AITyRwl^1~>=k@&U zM*T$Jqb_`r!J$Y8neKD)lx$M@YCgp>5^w&61)bt-W6aEA-1R>{|IH!^*uHA z7}PZLZ|+O;rC1S(7Oci568q`)pksQ)w6X@cvwf#op>5n5}sJcXwk#Emzl@i3UpRZCSe;uI}TZZ7=L=!SCj0 zh0gJhHJ-;JL&p^G!TX8FXa*UFva=-lpxrQ)3TC1Zb~0>KZoLmJJMIlVM;-f`A)B|4 zkX;DHJ@?uOb$|Q!xA2kHn#8v^3VOi#i|Q)QEz*ThJV-3@D|~08;3Eim>;w4lZVvj( za~_qTxLNLkV%fxMtD3j?=haD}RR}-qq<4j@zc(va555Qn_%ez5} zPKOag{>p<=^nAKRvotYu-BnR5^g6mOG6=A{_#J+vjvmp z?q!_2`Q@GV&1T8FY8_7?`L)-AwglNQ?Xh4~nOEhbL~ zBA}n7dH=uHWW6@z5eoUd^;r3CX4EuYegRl+^qQ?t+)*lYm;`dVID0Z!>Hs_Ea_qj^ zC&k1Xb)#7u-b#z1x>JyS{lxp8pi3kD84TVFl=;R4cIVCxyMM6PSpBW*Z9ObO`t?_m zN3F|$4?n$}pIs#wLfLPu2RSxj1srbhGjj@Ya4?xjWbiPuc1aVJUh$AuPam1B`7VBm zeTN*hu4b-=W6p*4Y%vB!FJ>fVzMqnt@YF5%fIU$#l%mDAlxBYlhc!2GUPq2Pp%8gLg>4x?PJLC5ERKk&8lZsOC)cv0UdZd5&R;8OG zgTNwuUt{~gj|p6k@8w>+0Fasxr7X|CE@!4ND?D2+iw?t*@N@hA&U3$MI2l_^Rx`MQ zga=L;pg&Gf4KQ=uJYLnageJ>q~t}s-bqg)75jWO6`m8KpbRm76t_6$ zE)=HU1V3yH1glPH#lAXUwl&^n`inHDMgP|iYM3obj^olYQ^3Ek9m2jT>mEIm8$YBdcbRFl?uVWtf@d>fOQM)0G^=vPZ7d);Q+d zKY)ogeO+OYRX)eiL0ZMl+TYa;_&}u{5xTlajA@_C=Q^+YD|P@jyMRpBF~5t%O5_Dh z)lI}YA2?hC;P9o}hVg~!LF%_+$}izVL{iL2npmFr`N{b^S5~(6mk$CDMH$cqzX8#c zL{fA{LibyqD#&!q-7XrdE0>lJnOj(?tolkFo|yj)-G`|neVRheFO~UD?tY)nMAH7r^uH!cB6$nA0_WRaNk(x)DF@Dv%hpfh1SjMLqe<&zk-n+y80iw%ZKNNNmj}_%3bt>>ZN|qtW z=cms#xUe!G$hrN+(qJxC+upb(2f4)YH|!KN@8wnZf{$eP!p^K0?DD?)fj~bZbP7b) z!Gue`mAQi9%Y{O=jK&eeN4WfP<^ zP2ce)wTG*do0Ik8-)+b ztKgX2_LE?r)zXuizc%mo4`o|52=_H{JhurdC?Gw&ou7+02VzEJn-P*B_0}Hfw61O; zoi2*p?tTx@ivScp;t}@3XoVDoI-0{S7eK2*clyZBh;?A>Kfn<+?`8EUw;Tp!g9QxC z#cn>ACR>CE!16GGf{$r%qR;x^;G{xHh8+nQ9*UkgESntZ_5%obug$Ia{s&2 z-cTD(rE0^fn(|`xKvst>S-RlURh70{{aOGKM`5}<-?8b}Fk^!;RgUr3Pvai`z;_Njq}T5##@9LH?iEu-lM0mihV{ot=W-|^{<@~AF|NBlG!o1=nh>MN zr7X`}I!NsUxRxnxTi@xGm>$CwMRrz5?e>7N5lu-MZk3)d!@Og9+)*qU2R^4RK0P65%9yR*1NHP zsokonceA))#@*<@pBblqHMh#;VuMMNpLd_>1li1J(bXZ7)H@$mQyV-wvB45kN76fP zD(>srv@A;a&lTHWSmy@LCi7@)sN+WDx(7~ehKv5dr)EnTm9(+!+X6_zL|#?Fq1mrhxVnrM?(+ z3<`D7fMX|47Qox5!|1e*p7*P%HzM)aLP-z_OSp0)gHaciTt|+W1hDpZrzeW8>=0dE zR(WAwtb*p^XFv&AYiQ3bh;_sg z+#Rys*p1qjw*Sk^usi(Ll|;0<6=KWn;X@jc9w_TPT6{p7`VU~GOG3Is7fK0-^wEtZ zQowx|*y#30vGWtoZz$T$C16xHJx{|^AC~V*-Km%J?Uvi+{6p`xl2RI|aDCRLR0GQ+ z8uE`qN=d-GRWRMyGqZLY^uZWm}bZ;GK{asi1uIT_e4Ebs0X>yOw?#I}EPOHrcvM{;tai`6XzJwVwE_8$ zC8s_6Aq^v(GIDK5jXidxcPdfZ*H%;B_m^!*^*SNZiQOaLqy{C-*wzWW20mA#nL8)m zSs~Igz7X+Cgo*(;6Kv@BR5mEqSgr3=p@awVw+RojAaqGA@8b5PC|fTrQSnK~8>WOe z-#GF=g#qXRWdT*uaI9l9yESKwck>4L7>#{znkoJR$Qj+TZAg4Z?QRsa;oPggzD)*I zhJcYl7$tjbVRSfzt$4xa)c)4mm;vNiPI+#cU#$r+U)1^z$KHEywFAciIt88{H`Vb7x&l`vP7DbB)OWECkkh)mwxHp7DP^oj6VPSATip zVP5CdzBZRJvJKbg;qnyf4IAQIr*S5`#{aqXXNk?P@)96G@3=+sA*3r ztUT@w;m!x5HfQT^)Eq2=jgh`vY;eePo++i)qd?5De|2RCwme}T=_|y}8~dAlTujpOeeOA$r(BIYc=c=3L6u-_mZS$u$txlvwx;3hZ zt;&YI#d92_i$#w5HfYPosZIQU`e!;f>@A9BTskgW<2=kT!*0^Ls!k0T8KR2(-DI05 z8&uyMb5+hed$1iS9~k5+OJ+?}ZZPOtCl}sgCB{w2SBhWe_#JZ9)cuKu;&S7LCIJqh z(_&z1@TYse-!>2V4Yk?F&8@rpPpg)$n^EbwQ;XQE=L9F#QSVU8R*b<8Ps|Oa| z#SJ$|TZ0cMGir?y%z2?`dt2KoGK_AG6Yh#m|WeaBOf&XJ5Yk|;Ykua->x z1JnV=2aaXyKwA_%kkc)n>!j)!h;_2@=1KXU;8#+Nd_vcp(3`QKT;+Q;Dr{i1F;dK2 z74pE4dg~E#zC!h4$a((2{P;~#w{15S8Jh3iKfpKS{C3lip?MOWxUDme4J6@FQoYsN zl2&@~ara+IN(MgjJ8K6B@)o>N&vc?|2CobmzQ^~>;nx(yEGwqOYWXpPJ#{ zn<#TZo(S&5D8&5(fPXBL5HNgbJk2@WU0Zr4AGNLyLM6Lzr zsc6^8QC5z17lnS4j|0E40D%#&(VT}W=oXYAcF5M#O?lb<-{P-dtE=W~1MNGxthc6E z;uyoa{{Cvp&;7fTNXH6CePthOKk{+hAy4`jHb5kOg8Z{X1@Sc3z0FWzf9cb~HM~YC zUbVR4(%z=?DZV*HsF>`@Zv#?K&I>=Spe5t<__)|`1ri16#=BuNcBJC9>sd)Z;ca6j zKjcWt&dSV@2^vgI{IL5Wj_>4mzzH#HW2s0R0-83cyyL(PLmQE}6O$bEl-mOoLZW)7H zFGN0f0sZUY;@N2oFDFl~Xb^Fuj6Ko^BwNY&HCIxcye4POUnO}v~`;7J1C;Gn+E!E^yDKd9Te`|#bACADn0Ft zb+#-@-ijn~eNm9)P|TI%Tem)3%x$j|oAy;gmwh>S;L#7Fixg$4_&){Y5BgJz@{bB>lB*9tl?SS zU_CK+uJZA@aV(ZYl>wz}utC zuv7hg#X&FV!u`N5CNCMnXP!MZTEbF^))!75_TCO1n-e0l@NewMRS$sKDhzaq&#~uKQY2Do3$HjY(JyM`!-5ZX*Gu<;%l z;`VWof(?t%ko|$i5A{FR*_Oq}?+To_W+Y~J3iaf&5%5?I|I8pCLWzHrj(n#&&ZBC| zh|Bf>K6s{o7>SEX{fdOFYopoD>{3ddUZO?rzT|nHWpL+lK6m=slJmzC&P)=f>vcEXPn$|ruF{l)cn$U&8~)BIGG)w$ht)w2rfSC4lwhAsEdOWeee%+l|UrX=iA zG*MnJF7WX1K;o^%i+b zIXJFnX^CT+)xNzF0u+8Htzk-X*{;elvN~UNNWek{M=D%7s+)s>MWP{_~$|zkhzJq8omLsr9U# z_!(r~p8csUfwV;=(&z8BRgsyxnz#f8Pu{x$^s4s@2tT@F-&)ZS%Gvd;JvQrQq_7e? z?p)Sk6skyJO{<|NXLEYQZ3~Y|(o;8;QqC&Yr>Tt~vRX^fe?= z62JjjNvR`9rkOG+b{VZ{Ey%W11Fi)m764p`(nXXEeCeDXJ;&i&a@uS$p+mg#bKBau z>Qq-pT{?O@lr8MAgCewT>NYp8Q8y-Z=mZMjz8t3_h|q>@Dx&iTJ&!S{7CR+y{OWyJSee8a@lz0 zoXT5hBy}Bs#=PqIik7-oI-vx%SNo3w)ii6kY`~HLzc;5j{&mYwr?yC8UrK6TB=}jb zJgul`7y4|E$(GjOJ`cLL6~SsA6!7M;BM%FBhSq6`J8dt=*=29{OA?Lr+$!ken$k!o zNlVD`5A5bIfI#&*=~=QXB-`R8O14z`9Pn$i*7Qw7O1pbY`#G)W92AvGkUpNC_03#B zs)e)9Ok%w{Re7~I>eI1og^^Zd7+DlJ_Rnw6Bk-?J_z|VtYM&c4IO7M)wV2+_-GWA> z^Yvn*@vkq^kDsT@4t{7GaQ^^xkMwW-3c7C$c(cS_5x)xX8^seQV>(e~VubX15MJU8tTTx75J)xR-9k&~qRpKAm*4M*-4R!r@cviEpnq)ctJ%lg*JVkzNiRAl3K1nOf9R9V` z>)#tbB>0y=xY0GQ7GB-hT!6D%xInG}1OtT!s2%Ht5*BQlO19t zIPA3F5KAqbV+n73g5^|uZ^<7(aZ2rO4xRN!-=os0>YA>bqG=Oqn!WwKjg%uYTwFLr zU&q(ja%Qh zNdExcL4{wyQP0^4QGHqUe}?`p{{X^&`#@>hK8R(9LA8qJMcy{O(};-k9ClHkm46e@ z1KX?PKiQBppBtca{5BUS{{S6P{cG&XDYnyWnz2erBa8UB3w#doI3M%mfAl4V1=f2$8f93K7)>Z zD}Pb=`SDZ1+NaoHk~nOm0b;Y)wq0E9AH^XJxk>)+a5{6=w4+tOb(z+oXUvbaao(}K zPvXB1_&3AyYhEPPA+WPfjUmfOf4Yh}cJ>wVmaF?({7sh7!vxwTjD&xzwX(|(ruJYz zD)CPf`18bGE7e<2*R_kiO6c+C+{#?2^ik1AumD#|P3(?-RJUi@zYhL0-F#C0qL#|e zDJ=9mD+`%z?O6QIepT}&BaPhfIxc&hn)(cp>MQcE!yY*C4}*1csrYYMxYI8lGYd}v z0hvhzuORWj{Hw3N{h|IX+E}ZBp4zv=FA-^I zH$B#wa|(gnn42H2EAqD3k*>wql0P%XKU(Xg{il8}mcaOftAXj}uTT5ty!Ef-YrnNc zA>LceR~>Vl=kuoE`jrVJe!kf!m8RQ7dZZ|)@K7pqj2>(APRrxZ#i6Gxr{V^_$Ri9% zxg_-U#aV~r@5M=3bK~822mYQ<_)^!gJf3H1@%38U^LJYDHm~AMT1{JA)b4NZp9=HbKKEc33zPI1{44a6!2EnK@Yw$Vs8z52 ziCUPeGU{xRx_ztXj}iQCKMp@>ZEHr>gtr<6%RppQ%RQ?YQ}>8FkMA#jqn^J*lg)es z`%6w2_Kfiv{^^4U(-22QwY7<-YqZb2^o?Un*R*JLZ5L3tzpd#-}b=xsRh56Gw62@{{THD)9~N; z>jC;zE3r6P=+C^d&Iey=@js1!A9Sw(X*W7AhNp*7@jHTmMnlJApW~49E;}c$Cj+m_ z9w_~#ekypL&PzL=61}Cfi2rC zr#02=^36Q5G?F~0Ebd7x%uiBDCpGj3?0II_UmI?2hbw8N&g^|RG9dnDzH({fmxd~F z>)N_M2l)R0#a;luxV-R|w{fM-a~OtJgew-!Pvbm_Liqbt1KZ0P{{Y7* zLUc?Ez@_zq2omA&hQi(~Q{v0CCmN z=%&9ZwHU;A&H?#L5-ZlVPueTu-mRqFX}A76)h4yNiQt+SC{{#ZRg{gr2qagM%IQ3% zTyc)oP>W9Fy{uJ0rd$(%d-_-1pRjGKCWqrY!;OXQAqU?QvHoJd5R^0$;kg|{4&uAd z1AJrg_ru*j=TGpDiLW%Pd#MDoM+V$Gfq+g__TsK_y3kR557$ygdW!HL+ZN5P{{UvT zod#CZRkoG=l!r|IZY$#Xe`-&SYTHl59bcY=G-Lk&WUQ|ce17<&;@=KjXg(nErl+WB zw>y06X_*Q>7%AoKo@Yjh1*Pa}e_W++X zwoZDyWB8QyWc)`t2j$~5Z64wGv-(wwb1w`I!RzZ)INWi457=D;#CjKsv`F=j4(isr zos5Htt(-6(%sQ#|AR5%geoFXT#{MAihM+IJKdj$rw%X+0#Jyq`f<0y}IwtG=p8~?z{{VZI{EaSakJ+?+ed9lfJ{9mDn%6!c)Y3VK%vMp5 z)6M?sXMyf;J?r8B0FK`i_0Nf_UgVoCD%MZ*T|PJ5iJl9w{y7Lgd$&M3=ZwGA?)3}D zy1%@ZX(T(OnpZ5x+>_Vwu76n6gIQd`6D*Mh8GQ4c_8x;BXtQk;qN0q8IIX0)RM@+{ z8eE~%56j)2P?%~skH7-GLq##PI&bd@=xu>Yz~d!>+AxHCEO(aL{0q- zc%l8GelY(4(D|zVY5xGk*CpeBiat2;){Py9io8jCs@uaSn-q5iNJqvpFr%>|rD`0G zI-YNT0-K!RZ6osk06f)LViC`f# z&fM+?rsMh7rCR>d9~SNcGx+0C+T9ok!2J@jnzOx%O8rl_J~5$};17$@Pe0jmpUVgO zSLU7RKWcxeuU*x?F8o&2bZd=1{{Y5Xl=gQ~G*d#`Hpq-HRN;CMYsv1SK55No7k6`I z7Zqkzw_>vc?_XN}%zqawbjXi@yhC=D@J}(9PPmn@i6edJn4W=;Dtd0n?knW2jHfuO z+I{!gXWsFwi-I;W;PJ+P!ig@Z6`Hd@R{Nd^Bi58xz@7{Jqy8dzTFN^Z^++`fD3=Ls zsv(#vkKtFya6JZ1cVqU+@fe2(!TKqa`@-U2KQI2h3SG!_pF`{#`CInWl#MIF@f_g2 z+y0Rc>s%ha`&fKT)gfrK=`_6=PZ_he+~9jOg};?}--tXz;y)JZ4}Y&}*V?4&GG)7& zq$)GpCje)##STM_Hl5kc6w4fR&w7?P&PNq~-p(fb{$n3Rz#pw>T4@r^AlineRZ=yL zHpUw?ytG@+a~2|#xg+=+@*7Xkdey5a43ng77%HHX>wpRVm9?b!e(~;C3#vIb8B_*KdntFf((yZIQ z*ydd0Dm&G2NOQWWqEi(jTbq*2!YJrF)K|ajwxGbqD)pw+Szl=1w~x-NO9l|Ujg#7v z+^&TLk93^##YH@OPJL?Pg%W<0+t|v+2qzZ8vJt{Q> zxg(!yVkJ|ahP1THr?k6S1`j>WX6(QW00-03t-}j21n^Bntk$K)wDddM*u>g9$f%{T z8`tuxwl+n`IIO!Pd-B^Oe1r@FdwN%WVWLe8Hd0)9YL`pB8CW*}azA~*F6ex z_Kx->(JU1uGCGZ_Gm~A8nc)V!w_S5um}#0gVyirZGF%XONK+$wdXhq~bK1InBg0xA zgQS1LOX4_u%{mjd+T1=G{$MlZucEJ4ZrukaxGxm=vrzE{uJ@OcrvOJ3Q4O&`gQRh< zMN!y(Cz|q|M^;ae^i&j8nblu-`VB6|T_?eok?A&UyCsodb(bsJC`9fY>PUxZIMV`^f9j zl=l^MGBPbbBkS z6!8X!6Ae1y_DKUa=Cqd?F){84$yV+->J2euH=0$w(|@fCG5$GT!4ElEQMQ{<+JKN}6iHP%CKZ>T)FT+REN*xKAadKMoeehskx716Pd=ZMavH9$u-t9xwmO!3HtT}f6` z*p3MN>VZntGd75YI}~lfr(?A-2&0;r1u<5oQAvR^@l!5p6&W>Q7NwMl6mwQ%UO}jl zO<9c%WZ9xezJAMam-xFhnBqM$a!;mOG5u@o0&C;1fj<#^6Y%cORJzw;)aBH#86rlu zfn5?6=NT*xOCEUWqP>}aX)lLvep`Ka{{R6~{{V}p2_&^DT} zPMh>x{{Tw)E5mvW8kVml+JvhHn`%7kshze3Uc+(epI*a0)$W>??FsPK??t<{y|>oI zw9veAlWMpM!)g9Mf6o>1-^7m_66xWM9{fq7!-=GH!nNFokkSB7FfamS5a%JhJ137MMHhZQlRwK`I=}(X|e4vm! znj?x8MtNLC3JklR!`s}}=~%(ai)`23PF4>^)6j>)O%OuU#S| zX6&;sLVX9Y=qf#HSbL}YHKLf{QM3Wrf1dT15&?iHQP%7nw6Z3QVywY_(JMtD;AE-v z_NwG!GHSf1gWrs2(w&ps6q-A~wnra?EiIyN-bjPY_5!Qe+!1mR^ccta{Hs4KwooY< z8%A(`>A>Lrm1@P>8--v7LFXeinu4+ zf#1+p6429Dv^}@hzdb)`hsW(H;!r{V09zLx-b8iv5&fyY5dojK>mT?oZ}G2@em{7> z!yYvF#d+dy3EbSxXL}4LL2&_vmQ_%U06jqpr#|MAS75HUJm9uPSCEfYsAMFmT%XRE z5QV`fKDDw$wm71&>4WW2Hq{v?iX@d{Ofl!M^{QKo5jT zW@$?84YYfA{AxTL(wwiMrjT4wxOAjDyOB(HV5jEVJ*u;`%km>~c{%M(AzZZsMwc&> zl8d|ZIH~;YYxioH-`7tn^(=QIIW_h0V(z(8SODg>?4+00=yJb70rw!}k%} zD9L%95RP&8Nzdt1DMfC|jAZsl1t{K|NXQ(6+*LM;RmlojNAUq(t!40E#kU_k@kMTc z^2Jzz_>c$dT@9bX{SwkPeP_f9%)fdVC0)nxKnO!nWt(x zoyx(d*<4*a90i6l`TVQtEgQo>4RqU>^P(BwBXrZoA0PMGY<>c+YZGX;SEl1YxALAa zJhme%@A8w6TpVz4c&T`fi4?HiTRe_$gnl{Gygu5!{*IP*>Q{7APQG>UmJH|r!QJG5x$mEWH$f-fvFe@igPjh7m zt%xl&-4{v9TWOF?6y+pvRgcv2--bmc)$G!Opd?BC$d_pU02BDst&CMkha6J%0+fWB zuE!N+*BwPxWcD>kmPIGdgdT)eWcDGgrBX``hm7^(jQ%xtdz*VueEHE2p*;RwYdT$e zD9IMq=0nqTybsH%{VIfV{EnlZ?o`vgc+<_aA zr?Kb{_wP$^G zr%SpA0a*OV!z$lVSgP z`jP$4lxBZ-bT=<-@44%LlJ^b&`ATZsCJyy`B033P#EhwnplZ*gHuHt zFmGy9k2$RyD`4UH?NK?|8b%i?CA5vuRn@U}{mdntXD5tg{{WxoTlTha8&!oNX1RA8 zSRMfM$8%lYpQ7oW5z!;oJV$P_J;Lv`uqSMn03W``tZ`?*-fn}rt{S+mUAH=+hwfwe zN8!Zx)-S8-_g1=Ql@Y|3cSMCAz<(2a44UXA@h^bVTXe+EvqbBoKB_lqCAXCr$ z36IjapA&e)R`CStZskRS5w;6xS7cBx_fZD`d-XlZu2JNbn4H!MlSM9aSi)47?da9%^#~P-QsHNSN z?6&hM;z-*Bk3u_-PXUpyi(2e++|?W9WLXrA#^K zd|MSRT8Gb9_H7K#nO4F3%g8m4CAlsD9Z!1n&l2f2seH|B2bSx-8G11Ke+l&!#9msM zcV&I6*r8cT9&KtaEWnXAoKnO-_tK@6dFf1#sUFqYeGW@%WiT{ENSS`LvH}e;P9>Q^d=txH=K3?w*b04{s?rrti~Dg{e)+xDt16n8!9w$p==!2K$h za$jPDWEyOs=aGtCS2f$-62K0~GtF0@<E#q3FeEq9^JuLW>)BbrD(0OpO~3Aq^QKDB$nx*nO~Yr7q1#2SQ9!6FAs zVx+kzfC%nJ8>bx&Y5Y+!Sm@yyhXCK+DqWahr5iQJivXdr!71>dHB+-7?vU85~zf5&Jxe5=7EU!y#9o8R}1A zT(i4&M^tQ;*`;Y?y_6N})84u*Ps6fk+A?11P&^3ZBe#@FAV6~jpn-r)FKp> zKJHz}Uvbl)!o3^f9rcEz;n*y0^qVWIs78FzJc>uD861*p2T$HfmF-_dc+1CcEyBbZ zL2*8R7LY`i_VNnk8nc2Zk~-iO#YJbev8bE{3SmHR!7ta7ZG zaSHi{Zl}gPw-DT}s3x zq~f-tSEC}OKB!*|Yf)*JlH1?J)9IIKytSVE#ixe4x5h-Kku;LopKUFK|EKbYc`*1&;)>G?PcWu z0I>XijHCYgu25Opu$bJ+(c&^wYUguy2he-dQnrE1bDLzqrmtGHEO=v4ZNaT>X3zzx z0@5g{R8njb6$dps3SzBJi&EK162>{JagLd&qE0hb(*I{1&RHI$I(_VRqn1k+&u z02lBNz-0YMuQy5VE@Uf%A?x(5jd5qa*Dh`@os5pWs=eypDc!UC#zz#?{1RP*tP+X{IRJ0O>;A6VP-jIY?DG)C9)Q5zXR)<2L~g1`$gIl%O_+2zkT&%`^{?mstj8{XcOXBx9sd9kS@ksN zZp9n8WMA|Ha86a&w-iETFmJ20WE>)R9$wfFX><{&!Yz=BxdkL08Ok|?}02$zZB-VZ0 z!Xjghk)PBYf%#R9Q&F2!yJ_WBL>xy7eaP3aALG>4OCeS)z50r{uI6%UpvF>3V#KlT zX+wZ9wv2Y9Dr-VRK9q%k6q{J|G=UG8a&w9Wa2Y2(`+HSenLNBA0$sg1IIE08Mp&K& zL2T}BCqs{$4V-rAieb477Sj|fw_szOxA<4I_)pIk#*p?o)=q zRXk^>HRT98=Djn)nu|%{gJ{pqteK1+xNPV3$LCnpZrU?yDPL4~wto!17Q*1PbKD&N z0LxP&XYeiu=~v~n@E?aio$E)PK1#6k(U1KXL0kc0>7IWKu~pna`k(Nk!?D#rLyF0~)$A>a zSGq#Oswd8WO68}zyu59*+)Xh*!dQ{{4k^*;S8@;aK3e|(xAOj-YLXLO%eOuw2O`$g zpZ29}euMmLCgW4oE&&g4QBUy4@(=O-Yf>!@00w!BdmzC4&09+wdvW`yRZpqp{${9_ zb1~Rl$@45lLH;J=Kh~~ArN*N(6Cv~*5Am&sN{pw{oyfVw>vo1cW^jW8A%FuNMtG`G z-Lia=g2UIiu7kuWw^faR`_QgW=l=lKtVy6(1d)U4D|qaTCAl)NbPS9LJ;gf}ngq7; zaB=8ILsufXM>}8TZ_w2ePLAt?DxIL>>T_xIs44aQqq+y5Q-|(qv zl$v8LQs&-IHU}Z&Z{g~uyB`M61fC>?09fO@&8+bb0`K53_Rc{1_U9+Ny9E)WSMQOPC1Di6NWynEL*TB`iF)aa*A zsn~d4!$#3Gx%^jt!umLy5J8Qh&t)g5EOI@ST=x~lc#B`ud_%5WYI>C3Z1Xl)frS8Y z6+q~qU;)?)x2xSt1*|$AK#tI#Fe&@epT2$ZfTP)c>liG5HsVfkgNos$9bDzBf05Nb z$fV1;2*yoMWu#tTxl2n~XJ9hIBrHJp$3a)()6yvxYvg2!j|$DVk5i6+0s7Z-py=Ln z2(<9bk%221u7EBH#^q6fdi6YlYf0i1R)ofjlhoy{`~|Pe8!*yth(VUbc_4d=Yxq*` zEUUuG!>W;jKMMMfz`hM;vss>BHskLTB)Rgz;{{H59;dHr?e$$A!ellYrip8+S_t>~ zj~HHu2WyT2A62X)TBO%Ctb$IQA1>_pTIWcaaJvs)m5q4;iejmp4lC;~7yKKvxUiQ} z@PyJ%04&;c+{!=en|~Mkr=LP==PhqWduiEOc**UG+LczFq!Nr|uM?3*eC^K}&lP`8 z)h=wV(&7o4DI+1{bT}%&@ImZqwZvO@DuMN?s!BO0p4HVPq>K}BXQ=9OLE_CCKM~tS z8s6kXsKXkC23&lz06K2~=l!KVqP*i=wb^*lZ6j|`dsgR!HGk~=aU+$=+T4#K;D4}4 z=jx{nJ;i8iniSJ(m)dK>sj5Klh~w!#-dF+s;sIgn)6%)A-i-Nre_xTT?NS%&d5qS) z^sT)o!B_gXg*A^5TD_>Y(vmqY7D@9!kmos2Gr;E@ z=bk$bm6*3ujp(jGBajbT^wX4I8*gCdgF;(K9x^zG~y`@Ma2>yn*yZ+0;@@%G?B(Bl22;{mlpy! z#!2h!J!;AO$Tkz^nV;5~ zc-V;%RA!dgiB$0)N7wQ&Yzv4h9Du=`xXKB|L5KUajzpLW5HAZKF!c z#dk?_t%S|KV&XYa(3vVO&CCgwVFv79+&-1T88#nCa zk==!dzMD6`ACE`z5*|;ZZmP>)icn*Tt*HZxuF&5hCA7h8;dM&rdA| z@6F4T?rXTY_*t%Ad~3M5vWh9R>94-lw=E#swU{|W{?{a8u{Ey&Yx>uZby@W*c8pJX zJdZv;P)m|H{*~dX)YmJ%$n|4RPX1?)#coTEE1|Np$}R<2zR+63Qj**-lp_!wM-A`I zY3bI45D2ZRRZU$L3U+p7$StF@)4tUvFgV&elh{`GhxGf6M@g4f^1~us3t<}db}6|) zKVH7o$@re^#rA6yIP%Ay`1Rx{{SW6}lcsp5!~PlY<(1O3w-ALA!i)efD=6M@I(lc5 z#T2PakxtsOD%4!gJrV6b4ESqt4~D+isN5u1GcMs8CPFV^lU&ZL;Vnj4TH<$!lPBa4 zl6^7t{*{Yq`$OweKs4<~L59lJ*UMXo+?GM=!zQ(tQn=J~=ev!Ipg4Bw2YeG#QkN~X z)KsS@d%X`Z@q9^Xs6Duh0fCi04;=CRE6(n1wJjo7)U*a@!i~>tMp4IHr}s~OIIi=> zw+(yZ1F#m^faf^d?fx}E_O+X#bjvAG$mEgw*1Y_YOL6jZw)Qam9enzgrSnO0lB-MR zqT~im-*^@5GtZ|yQ?-~fq=Cq+e+6lh+W4aOUFu5eW3}7;Kr8L}W0@gO8Dp59Pu9E27lAJ3XlMV`XJ!H$wDPwe!T#y|8)^J2iodsYW>-S4q=sKYI3x3}utg$5@JOt$ z6BXx-1IYfrl~vVjE-vM3^o7|jKX_SGk-wvl`{)z@00I@$Cv8r6tLS4U7H8#_>5kd1@y1X5^G`${j!koV=ZbIjJ9A>P7_B#lXw?4ztYOf% zs2zuHPg7j(#(a~;dSusa3^yz0mgg0GPdB?AgqHGW&JNM-PmaRwf0@Bi{?X*o64}7Q zSteFt+??X0yYUQBL}RrZpZmw4uHQq8)V{D=SjJvQ$8UD37dp&n8)yxVqdh&owSzV7 z#l(f($tSt0=O#eCsiY?&X>Ok4;L9<|Jw1n|L2%hBqw7jRRv`7Jk(c~G#;B1aU(T#3 zQkzK0?NF~BIOeRvps->;&-pbhq%p*a3Bw$8Ao}}NPc()hs^!rt8BYfoKE|^dj%YyH zyQW-$7Bj$XRr`4gY9N0J%MbJU*E?f5Sqcy^af;dVF(fjM&4c*yQqf7Bjiu3KUz>x) zS~4BA&f3mUV?0)pT#~^~FniW*8m38id3_bErrvKU0{UdJ>G)PZpFHkO!|q@(4^BRn zsd{r^FVeBj2+89e52X=8Y>@LzljM&*&jO?K8zd8-dX3$S43crv+NmOL8;)>C<5H`r zULys+yvH>GH1YngKD{Z}Nr>!Ab>!1W9q8{&c04HRc%~vb-#ibx59Vo>#}})U_kkbQ zn=57TIt~R!7_7+tj6cGTfNPGQjw`b8V~?}luNhWD_z-`p*Ap8Sau{HPT`z?$e63=5 zGl47w{wjA5&^2W>p|l>SMXKnt-(8D~X_ZOF^l`&uzI|~{w$r84;llxf*(FIl_Q^G~ z3x*XjQ6y~<0Hb4Y_4?KqdmGrsWETWR*!hSVH5k-1t3A=hZ*p5CH^=}a9DU+_s`J_^ zT;e&72T*y(<5<@*BI*|dYJl!s4`%tX`IAYz8d8Tdvn6eHS1lE~D|Yi3x9Bna>ZHCV z)ednqP$&H}h-V*G%`Lv29nA78$jYmam3o}}{&k?5WrTSD07q9Nyq`Dop=wmE7h?gY zH{nj^nX&T*V%YrY$){b((h`gP={`^^s6eW_Q9_SJ82(f+$s>=brc0>Kb}br5awMKG z0sa76Kb|W5S~Zf9x-%jF0BygZtEN4Y3}9~K9`z_v7c|InY=+_pZKIATqg45F!A3t0 zDx(36RMIqz#1aSwppnMn0OFbFeKoAo|FLuv6bhoMzA!bg&cP$wQ8-QlziVRlZ^iWT2!|XCzp>K_Adp6jHaQ^f~G)NUrD#kU&1w zPHS>GUPq;Bn3S$hJmR2u!0(Y-T#FQ=o#O#pEWZ6kO}%7Kl;<6NMI^C;yo#>K$@2{T zM`~gwJn(s@fXKkF9^#`DXNTkcp;Cqf0yzhfiefcwH7}SY&wu%72P5h`{{TAB4Lot8 zZw+o+C{*Q7(Ek8WdgoV~yJdYXqx_{=8;6O;RsN&;^`&8^dbPH0ejaHz9a`Pxw{M|h zN9qsfRnTRrz8ThRF8nbziw;tDaU^iL%V%&TD}NB{j^p30XpKHaI0HXQ^08j*wLM%n zy&VZHK3?Bi?6k=4^$7JZ6VE7lEQC@PVV%;mgibr-1pffQYn8OKo@<4ID4Cg#00O;K z=tE8TC2=zICDyMLXV^yzHa+=z@$oWSE#KsNbd%ij`=}YFcWy~yNhi5A%)_eLNqP3m zri@uaXRd zNVd!?)b?^n^i40snl;9>@k=T&cEZZ+RXIL{XCBq`{{X|S3ro4OhUUuN*7a~y$!8%z zf8FP4{CWCU$sQSs2h-(wVU9r0x8_iI1OEW8UbFD?Rn~kle)^Ax=WitOabY8Fj%EJ< zbns8NAnrA6W?ZQ;3p zv&hT^yGtd!Cl2LD3&*d&q3xRE^v@jG_=`$|SkrD6()9+$SLIOu0CG<48)F`-eF!zm z_=DmNyI$P1F{4Wg{P71KV&D=&y5yX0Bi|yic$o5gIIT?MhLfK&Iy?U!!65mkKSk03a^f8#Jv#z0J16q zK+QA^VK^Lhrn2l#M>QC7B-|;}NM9TQPQ=`?r#M|s6Tlnl-PS`MgPZ|ba4}ichhi&s z@-5OH0)xmE6493(QI^n_1&aW^$u!s(5t0W4_o-w@U=eUtPv=TiisWEZ0~+ym+&4XW zs>*mH-mTn*YnBax+Nq8hiqRRfY&ZZ6jybHh`Q&5jb64aWEm`_!f%U2?xup@ZHe3vY zQJ;F2LO}wfJ!*+#Xr-eR2mz_0Q@WWF?s1yk)wJ6kHs%^68N@AS~{{RWk*1LTs{nilal_&UzTHxc(Ypm0*0@y4YS9bly zyWzsIa@GCeW?JoP;*4_wf#^euL6J}HF0 zUNU_TTxZ&+@II_Gof1cYI~g*QW1JqUN9$Pg%<{_4H1jm8ogP1{-=Mdc!$ClHgH|ttVUQM^1P6NJjTc% zkU9a555F0%b^au4IuD00tu$DmF<2Ht=S{{V+`SW%@4aZ%sY+N|X_a(hiu@@omT3y7BP?bCQ%?cT(X=~$Mx zlZBOLVGt4$b`nD6x!d^qd)DpAiVZb@MG{ECRAZ5zas2C=pE2A#Q3%QbzjC(i#~JJN zKT6gOO|mAOQaimbOt#W=FkzA8X~zEmInbeza@$B#&|u_!YZp^u`5miX+wI@jw$R;3 z(#sSojC}wdK7eufRST<0WJ9(x*cl`Y*O|?Exi)vkHiAgzh;n$qxQq;2)4 zuy(|EOM##7u1fx6aQsDgLYn1F=BZKhGq<~eTQdL)H^|4=)Ai%=swnLynKVI&Fu0j; ze}%BE`s_8i6k>1P6M+8!E`1MU`QorwY#PCiUzRr}C-zntKbCX&R?Ae;i_xZYnxwM= zSW4ONlbYvlE@ga%5ub94pU)N1>T$ZetBf*|t?Wkzxw(|?HB{0R+qn;!xydm`IK}`V zeR|ZY7e99%z|>)LQz-3PvJql0FC(b+tKnb@3QAn}8%V`xqI1PufeztN%SDHl+Sc9Y zo>h)C8D?(P=iVUkGhfbCV~rqF`>`O&9{A~#`c;n|>Tb8u*+$7e7GWz3dkpia((bH!`7+=DoMxI ztiv3ObQyXNz0L+I%QdsPCOrG&tpHMucQ20R8gv27C6crTyd>9oO~$0QJ;D-Z+Pp ziZ={yW7M2y@~6h8A~E-K`Bb)2Mx~s-WxAa6(EV!ka_!?alWg8y!5R5q^fh}tRF!jH zSp>Rtj612USxyGg-mTkAcDyH}sRQeZqE6>0Jq0AJHtsNzI(pKv{OJz@m`MkW;;4~F zCy`PUQ4z;_Gm2n5u>Q4Gnch;_!j7Kw?d7rn&Q545{)6$L2*~bDLoA39hJI{tDe@Ah zEy&G9CzYR=sXo*Jp>EFnumg^wx4b@f_>#{g{L?C*aDG$#>z}iAHtEkRmCvyM03xr& zG?7TNL~!UsDfb+YO%yFAE2sgt0g&e>)1E(C(eqij7!`=KY@RkFqm2CzAJ(;j!J<13 zx5QaiH6SF_b!vX&jtxFRKexO~w#3^U&uter>0I&Ii3Zl>A$d1ovC0DPb6ij`BjPM(?^ASAC!iOVYjga#ap zjEd0Ibi1uN{{VcT#!du_(Ek8|_BEJtNv#o+(9^fn%)`r=1%80`K9xLjfIPVm%b%2= z;XmP6rG2XXwCOO}yDq&)dQA;6HK+{Q4dRi?Ad~5}hyMUxxB|Uv)K)dRu%6Y2&hb2X z^-`zx2Opocd8}$0Ot9b#n%0xt%Bs~6Fvsruj!*bidA?j9!lub-8IN*m3$OJA{{VD@ zTA2_&2qK~*0E$pc9Oi@feX58nOBevMkHVoxc*)04L(tWx6&Aoy1JarTNM=VkA1VIn z{*^m%&TBeI%Jk$_i)UsGti1Le*1S35JIS+SguA6JBsu#2FhB-NXf|u`u_m+>x&%)DsKG_%oN;eD;}k! z>(g6YEQ#fVocyW*$9~o7+THE_m%^p8lm#iPzU5^H<#+=RYmN=>a#75IgJEWQx zG7^-Ojh_v^-8IwFQ=h~N^q&mg7_6pHdxKtSrWArriblylnCbm%snT_6^xKI%rWlqs zg@X*`Td)5BuCm2L+Fr#_mnE)tH+r@Gr`sx1cuHS5(p!=(DvrL`wbQ5_yMat1sg{NL{yr1>Wm=|^MEmgT8P5Jt!QwME^W^V8C=I_|TFKi$Pr zD}#!06ovsxMol{ucjBm!LAAm3HNAADPC+bK1C!UKVPk2{Z;#&T_VN+`04&EpPAVtR z(gjx=QveF8$Jej5T99FWf~mIS#tuDcA+tK^e7DFs2D8}aQhQdV=)@xUI0u5@6 zp60FF0UF2eny#ug^HN*@H$lk0VVgbA0;6My_@uTQE4j(!=M>KT)0&t?Q38>SQs9w5 z1p^-#+s#=GkPd37llN}862nQ|1)KDD=NxG?SQSkMvx;2$zMsl2FM^P2Ua3w@hi(B;r&oST@-Tv>&|Ea7nR`))u8_g{MP%SmyJS7Bu=`b@T3 zosGjOY)G;x<~bDf`ho!;TJiC8+?BfYJzO;GcX~gF6~>FP?I~ zz0N-@)`%_7m{pMSN#q*Gyt0bkEzu@n9PI-oN7B7aEmg{?%c1AuDZ9DE(b4bi+g4Cn zNjw}LN7lM4+p9|}U$k6L8mZ3E2qm%TE0VPu9pp{>xFB@^mU%KyJ&ER`m{~x4s}hnD zf907Be=%BAgl8)ePI8P$wLMnnQJZ3BILY}Gb^6wih5R>j9oW9qKvYw?P?4D%ImyB4 zo@y&iA~c)r7t$#me5B-`sq8+LvUN03fVcyo2c=_PwWG;M){Q3LJwv7!FK)tEq{9y4 zsXnQ6_eJH9uqPxAKAeiphg1a$DkOoswtiaFwY2+6p;H$2{s7-M*A?dSsQgIpz4j8? z!S8ip9ke@)l3@`CB$L1u)cjglv~3qj@O(Eh<4lOX-qXWe$;+R>1yS@hp`_eccpJm- z;|)R;H-xlWRkL-HVZoG-?kBHyz^@bWHoI}C%`L>zvpbUP%-JkYa(k0iLK3Sa*2v1N z)Ke)=Eh92D)4LpD7Cdr&Nj-&Qt;CSsr0}-KMh=8_AmmkMxMuszPaWz%FdFt@O|8#1 zb5CR4EH0zJ(%`;}8z(^^9+~Pt1CjVvZnF?KWL9Gnx?@aBTBalp?g{VtR5@#8QjV8oFreGK@(o8I zWSOzh^UX^WgoRX$_nvQtxbc@!S6)g+!=-+jhIT`-| z8p)e3<>axrYiE`?*v5l#BdU*FdVBV%qmz6y)ylHta`a?A{{Z9A z(=M!4+|6j4T=MWJz&`2!0L1=Yl#}jLk79~QW0hagf&FSe6`TXcO$U|8JX5BP5dl{j zAQHZnRv@m~GH&fp0)nO>U$5Vpxc~&^|Rjtr~d$6x=ni8JsR2w_x|1YT=0p8Ncz-RNDICxC{_~vMRboBb*|WR${i>xV{Ne1}G7^;ptt{Xrv^ZhZ+2j z^sVLK*EOa{BGe8{{XXBT^HTWbIDnqFn2|?8DXB3``b}*VRdg9BlkqFJy?9h^#k*$ z75J-`_Yp;I8cZH~RI<^=U^-w97;##WN#;P3e|Q5_E+P9p+}7iyQZf&wc>OU}wDtzs zqwb7H;CUa`lufH@lPxJdF;c0fD)Ukiu{Rt6?^JV&PC2U6&GPLB8R&f}KGDA;1asb? za9N2o>?@Wu+tF!u8Pgg2-dWqb-|8#8wbZSy&@6Ic@%LY;{{R~Ef`=HzXjxs3E!qBI z_fNm2M5A({D`{=Bbtmkx4KJ&>JAQj*3PY^i(+TD2g?2>{^$PyTlrQq zjtD&sYMsnlvCvsuB(p;#W8^Lsv*>sr*PY#uv)xYt>aNlLOh@t+(rL|dw};Aakq%!y z$EVh?JV=CiuJ3Q%^I3=E&-JRNtt%5z-CWHCF6{NrYNgbh+hFKFojO@c9QvA$ILxwR zw^Ds8a|?~Ljpc*W1mvF8WTNfcfyGV~1PH1XM`28mZ9-4sMZ(r9x&adspd5A;OBiep zm1cPyw!w^bH5T6V(3u+yj8iR1^N95a{Ay+#)G++Fs<;CUkLgTCq-&0AuJBx^?bAef z1Rv;sp{`OqU~ye1g_~xi*f=Bs{{W#@ScQ6WHp9DAN1r}ob>u~BmDV{q=-ECy6We3fitYaDcTXFnrth0tc3-}h}#W%xk%%t0C=z6rIa{mBC zQ=j*Wit&9$_`HsxgDL$!zV#SrDwF10Agw-F*vy*tU9AaYv6vF0rbcjnyqcukHsR8l zB%{qBkbT8C5w`^7dW!a=8y-xZ%nRfGohcvQs%IqC>(&1NO_S?Xik#xRBeBOV%R`$e z&!-hlzVWMyF=W45rzhWRQ;4J>2d*ik{M;TX2{`Lc$L{m*R7iyO99H#&o3so7NmeRP zwsTl2rJA-ZT&0w-05DiFK9w`rxIILbimAuzRN41&(yiU`kELg`b5j&kBEA0rk8V9h zWjL)nhXw`*@T}MCT13u8rvwp?r8UV5nvuIyZZavMF@SoGDl^uc&4GY(ijS=^F#alV z9MTT8BB{n`5HZ5wbu}z2jyux=^O}|+^NLKQU5_JeY_1m72s*Dj{!twcc;>ZX zy&!D_fO}UhSX}C*J06wb-xtr}y-UoDM>H}IF5=p6^>fC0qYvbJ9&6EL@NS*rdtdm$Af%HeV|;nuMOO=h(SOVvAmFeQ|;;v zc{r>qUi=-I=+Lg8y7n(>`g_`6wY)ARiZWD4y&D{7@$Kzd;5S2E<)*daj}ijKv{VO_nsJ+5;t<>|27_M63QV>BrSEXqBCZFN$DST1m z2^uRl`K_%G;%oLF!k&rh=YiWMnR$EQ-vz+4Xv{{Y2$)VhuHA`A%O zf<7aHG0_lq1NG#Z;`JGG3v@r2>+q_vBVSs)6AI}xx5b+?dWbn45 z{iETiBzD~_L&}rtIv>Phx$7%xZ%Onqmuz~Gh0fUICN|Gt+qPIK~+mVmPr|}K9lc*U+cFE7v*Y(X%xMp_~caR4^UWfGtvz^>-i;j-W zk6O@fv^{d`O1?!~i)jpU1YpA>(2k<0EO<401;@?F^{AOZd}5(DZA)PU4=kx1QM1V8 zDxwUQC!hnltWSv-wi*S1@b)3Q*4cyI5O<}B>LMMQUWJeF^cC7^cNaDu81XKtU_xKo zX^$nez-6Lha9Mp0GtGScG?|i1nc1Xm$Cf!P$GJ7zgr&^+pF@)sRmF0yrbK}5CAmGx zsxxyiUchA5gsfgd#C0{E+{)+GzxvhcqstPdg$$CS58^v>QFp5r;Gt={d1H^Q4cHR9 z7WVIc>v(_>slWr!RZlR8$sKyr7ja?@PaFZWxC2wMTZt6s%mnfeQCB8Xk|U?x=~N!o z)aE`%rg^LJNG7xd_2|Rinq;&qPmEv;(+us70Q_mPsY8>~)|<2ap;RFq_a0Gm>J3NV zoQj8I1C- z23j`$@cyH?{415c(xkVzZ!Cp%Ir&c>#2iwVn?|*;KHJ-{^ zMlAUm=)8WtYB+TVWN5DPBwymkU#(Yb$uNAi1Kqj(Dv=GF*1{;QcR5HQ>Pulk{Cm`w zJ~y<|pz`#KXznK+C!K$Gr_?9$emr{`0C9?^ECN^^4^l8IPf%7sBwzwDz|V8->seD>D)60s z>X9tYk1C}|!vlgS1c{tuIRMk8EhL-C=>{3go4;P|Bs389!f2c%(E8yJ@Hf0voo&^jS|s{`aBxtHMbjmvWMSgfGmf%X8!;_m4T^gtqC$f3q#bX>c8SD);FTa zgfh1wheK9kxNK~coc3xHh)9>tF6>5nnY6z zd1@QxQO6a}c)r|69fPRGBY3m)ApZbb(huG;n)gmBWofU(NHez;dN_n=6?=6)ri*)T zDV&~Juu1)DV};2*1#fc{hA{}aKY*%oxnq;t^r<9bNoF-&%VVFeDWNhBT30966u7{r z1>~G{=ADXUmCjEU1fZqHM`9YS?EUV0b*OGv<{sjj15Hj3<6B-IlWwsZj^qRRkMXQ1 z+bTWOAJVpbKDpJ@ws^r9{{VSvYWxh+m&A`ihbqRpuL3X-QB9tf`jqH>ZitU)!x^sePi^)P=~~Aj&!( z3b6j^91%^_d>Q?xrODzA04msZXlHO97Vez=;r-U=dUdWPbv9#+WsmvkT3SbmH9a>| zOPe{|NC8q9Z&p*)Sx*H|aBGL^@`kb8>UEsM#jVw17Y^;tHqc`Q0~R}zvYhj4r<5=lQm2Q}MSY2j^RTd3AFMZu3bX%2If z{n68orvs&KU1*}h<)X2)NKhOpRRH7M)`pMZ-E&^OTYD=hrgP5N)Un5{MO;dnyLLs> zpy8oH$|k$Gjwr?kM^4q~Rz4SsR+nGZZUvT)Z-FH3%N%eK2k}U8!2C}Fnz{#t{0Ayc z;w@b-bp#py%&>6HpYFVaw%W?vZHC=_6n8$Xc{RkN zD$@5fUCo@;IP19=#D5n{uU(;vF>7ILo<*IawnQKaY%nP+YOLGu@uN!^V z9>%a_{{ULmtj=E31d=N*LHpJo^x=M@pOFoyVn%R{{*;xS37_7Em;RBkuvKl5TO5^gVm>hiT_==rsH+(KT znqp;gymO9erAVnlmg9j>F@JmXr*T-X-nBI7?OIG-`I`!yd0-M79DW(=S^Iu$3h4YH zapC(<7+73*rrz%7NQzMRHujkFB~i}6NdN+H3G~fG-J;5Z)XI|Br#(eRtBUlGi@y-` zuZTV=w!G0iJ8hw9wpPN@+R_z3+d(ID?Eq(<0O$u(UUY+VU<}k!l%*8ptjd~Ec1)hz zgTLObO(tgpJpii83ZNZ_T4$M)pI<a8E-{*K3Ixr3tlipn`WCjtA$SeJa#4;qVP* z!ywoIt1!RKocFBUO;nAT=EYu{RA?>Q#c)8zUqzER88`H!zk9gAlGx(Jm7g3(WPy_hyY@?OG@2ms**L7v_ z?#9neWt&9O=bgUl#ck!H{eEMg(!N)=za}zE;{&&98&Q{b0~+9-SqVL?bgX8YpHW_X zch|KIDtPpXEOhq4Wf5Dh=@&i5X>R*!;>!KZRW^6lu!Bo+9zQRgGD-2QUZShTW0sed{*s zQJIiNNF%7@7^tV2L@0p#-Az%M{%#INE4CDo&pM2_j#>~sd8qE&FoEi6B0nPiDYr-E zQSVx%sgrsY!K)C}b?H`N>C&l^iI9B4yKe$&1`Sp0T>O^{^5^^O$o$4fkhtqneD zEv}=UBZrNHuhbmYQ&(0rgR?zbS%6QcZrh!Q{QkeruvQKFOE3iaG5}ArgOAmJTI!%N z>N;A>5&hl7VVBz@`XA+3`dmI`y6F;|*Hm9EooxaD9uMewFCpFL&7B z#@kNj6oYEBo`7bvdMF+1O7QKqVd_At0A&4Z(np*kt~oxLsqo)sP%(nUpMIa?QLx|v z>MC){rr$&S{{Z^cG8{^)0ZAAiY#&imsti=m7GucjDyfx(g+lT@YIiJ{fzqKY$WFu0 zaC_2kFT)V0`O=jKk}_$n1UfsQ$76yIy(^7_a&o?&l~O^qvO3hU%f?6ID$^mM=2M>3 z#yJ~_!1XmI6~;nm@Tjh1D#AVh2cNACf<*RF8Q2r|bDzSrn%*af!yw8xPQ-mZ>N^4Tst`p3MRIol|Oh4Mk z-6OtwcgIR`uNL`bxrFFSKJ<1VvA&M_*h-%(^mOj0{3>gR)_9bF1BJ)dxtl58+T~_W zdouq3cvn#iq_L|h46HH_ty@Bju4GH3$$4@ki9*Z4CC&gI=hCS)lE!v4s~{YFoj*F? z)&hTFh1fTV*K2nf4W54iSS$kV#~C!DIU;ym#Tkw@3NzSK-U8stPd!aG1TP>8GJnrB z>&x3{AShpR5s#PpdevB)=tLek&rFfqtwVRMDxp}^G@hX33d)}4%sC!oehdCI_)<6|R#gKBliwAk zv@_~#sT=cMMw4^C(j%TzF(1Q``V;wAB&P?O*U{(OGsI6&9DPUs09cyNOG8*aPV&WM zxJNOr@TUg{7(YsJlLr8TJwdKgS#=nuKV`U)Ban^ij7LA#uUK48EyB1U1A)8JvE?@A zTN_h>acv|Aqp4rcxd^0q*sH3ZNF&p+71Axncsy1PqMlx-CI%Ky-Y?_V^#+C5r1dr} zCNo(_Avq*-_32WVtgSk1Bg3ADaQu4z0H1ojxSlAn40A|G!0%2&o+=a8rH_F_5jY%B zRN{n{(E^9ydkoWuoivLYD@e?62YQl`0}#31s>iTBDxJwPDNv&au>O_MOQJkbZfTIq z-2ncznJt~l@L@lJ6efn#Bhs}&5&JCdwtZV1OY=ufRwqtyyB=+1+218#D?3b&zO2N$13>r!N>J9qP0Vlx@R)LZ)4b;@l|F#?a#TX+c8GWF|~bv zL0Qhl-yXf|p&ZSKPWR97j-K@uz&SzcaaL6hIKZaO5!$RsI5h4ih(glsrvXQ5WRSlN zRi^p&pRHSE-sB#FqPS2aU#&1Fw;-y2x+`x*ZMvGD_D}N$x%+dpFTWMFrOK;*q@Jq7 z^rA~fR5v{~Q}VSyuFm@tmOUwCkTyb*>zbu;AxQS2ARec=uN6f09IROTTSQ8$bI_W6 zSJUnomA?ixkYqW@H7qwGCMA(v6(a|>dyjEc>7rFlPMRHFRZt9sk>54jXx|q6SEbr5 zlIq6h%yITx)LV$L{_BH}!xiNdOd^?;WZi?;82)shYasB|&nzru(A8J&d(wPN@ZIIU zb)N%i?s~MEeax1p{`vWoR*jd$4~7a0!{E(DBm?-b)qwhCYv=2YL`Q0oB&z+%T>5*| zR{E1H;Im{CgY>RvfQv@oSk(6&W8x=*MAJ#8_$DKAa8`Xr@#au}-Cd*gt`A=Lsp6~a zCa{kEY;2o@YhsIU86Jct3xB|gt`kzfVQ|VDu&mi`nq*=*U@~#(>swL4!ZvLgRK&fJ zt@imPa#_jds$5*LW16LDF(tXDPD@FVU89Mu^RY;>y;OmS5zSb5^Mv5I4En>TEJpURpJMku)d0A7CzYMv>jps%T6 zep_ST`qq4)83`RTS_#do4|>m&iJKm@M{tnJa*BoIDBLDTtvP4^0AoKxnzBoA5UsfI zG2X00HZEdtIxzfeIVVEjyg2&Rg_bkQx|7#~Nvn-A-NF@S80c!Q3pP7d+rm8dW57Js zJ>+npa(dJ)i(-%!2|ul3NyLl+#cY+&-(p9nO3JxVE?8lBJ*uKahi7QqdQ^K!a!oz6 zj8cKpv>;#{@zhj<80m^O(a_QaL`O6(MLm>(lSztV6fwc*y+{J>PTsY&P}$U(?Bs|zDP zJXIiZTAC)WHjAr8s6h?1vPZiS+{7h}JRr@{0@IQv8zP(n%A8XD$R+Jy&F9L0OP|yjdGqAz5dVf z6}+r*6Q3$i_gjqq2M6%4L-7Ts{W)$2-hsLQ0CezwBeeb%&h(kO)+QdQ5;fCL677y~ zCqO#}TubQc|`U_;C~{28o+3?z{Wuq_&7o{$b%q0;JqB%iIz^ zwFR>xNM7D;vH{OV9SuO`iOB#8*0=&iD&r&4vn5s^F9dcy#WG6n+*P!ML8PVN3SLIr z$m#xnty2nQkSOn3WO-g3Z_fuz7Uom#|+TP;ZO@c;WDSvp#aCq(c^Icw%(;C(FUyS zZ|fQ^gRd68(IXmN<9y9&);2xL`X7TPyEV}xH* z=qqh(>};b65c6gJDGz_}9>TLU?LzlTGZtp^7)V>=h)TjN&K70)Vt=F8aV|)>uovq*S zAbxcylZF0k0bH{x{ZI6&d&YSqH59I@g@_-OO@ijEYYAP= zbrPuRbGZHhbNs5*TD7&B6|=WyW5JqJhCe_$3gyeOP`Ui7RF#wfeqry{haTXiV|Gn$ z<&P1@KDjjuYS$!kBO~em0N1SHIxxmaK8B%~$tskG1a~`yB@{kpSi04oY(`Qh1G5d^ z%+p|!Y3C8g3<<{K!ZDBs^{O62qm9EAucow7AuQ{?jz9X;+DT|6+j@_V1w`7TkLOoU zmik22@;A=$Ho@zU{=O<81_x@Zb1`eMV#5$XQQL1%)~9joa+h3^fbs|=e@d?$PV5fh zyVE!|V(a9(e4O%sEYuRkzYGR&e=%JLIXc5I8%}fUijLwrV~c(_DC#?kYKC9B$MdNS z(uMovkA7*65F06FJ1 z72o=$$6VBrjs-Sl1PuDukheWYu|czrl-mTq^I&sx!rSs{~p z9jrPUQi)NPhQ_^OZFI0+FdcUAduN*BZaFpDUEV8rVd0V#a>xRck+YG=_wD%C86e4} zLiW^E+P;Ncb5||mz$Ep>LL(&cS`kJCi8vV`=C^FdD9gED^oIHhh-6iZmHqeND!CPC zmRO4(LC2}8asM{T@=w;P%rQF;dP{J76y$bB#?PTW>Zu1g0Oqv{22Mq1O50d~ zFhS<25;G)lX+!%`WFGW|g7rMp6E|2HA&rY}`9?n~XO=P>-isFVEF;fhik;LLk04^R z*w=kXSw`IB-m+)FxPAdSHL$00kZUIGN?o$`>CfR+5@a(R)A51DIn)qN2el?R0<<#> zWKb8WJ!!yFfk*~OK1z?ARI>fbj+mIDoC&6ZPEd0|5+_5Bv;aK9Pg;~HM9BKoU&T^U zI)Uj^gMcyLnuZlEf$!F*@0ylU44NdFrZf9xBBvF@Tc#W^Qh=wQqqot-lCavH_%ke_rDr!gZ(A5Qc(&o%~$PHE-Jifmi%jP zO4Dv`)=43VxQ`pL)Muw1Y9}iq;;zR>7XqxLe$?cT994vlx!jFX76`fIepTw4Rm$p~ z9f_y;i$-FYdyka=0FUEdZv=db>pU@ZVV-M7KP!(hexrl>WAd!0sjPGF z(7)F_AIvGN?-1WDhlZ~2m#V}{f4oKq>P2aIrFLp-I`Ac4f8Jg{mOm=td|!Ci8U?k2 zHVl&&e`GmCJuVEfTGp5PA zVd+i_v{E77?IG$-IzzR8TB1b_w%cgx$0n@B5BfRJRv~}JtH7Jw1JHG=>-Uv?2kL*w zsAh>0C=sR?j@280dsL2bRh~~ylprIQVC*WZ)8&&VtwPQ70qSX@K_kS4i02$tyF~v0 zObSLr;A7jNp_DYrsB@JWKT46;Ya=dr<3H!=NsVYzodt|+j0h-5Ap2Hq3fD3;jyPkF zpsT(hnWn#W?slKA1NzfogvN^)A9Qo|?@euSJ?uv$Cf_o|PC6CrMRZ;o)M0`PrfCn_ z3WY)6Z*%(ol|kXmdq-u*<5>Y-HzqPvso?h&GJ=}1ahr>|)I|eXjk7A2KQLj)e{g%! zd4-&{Qn1yQNR6%XjAw?&A75&^V^9f+#E5!&kMXP=T6&!^nrS30rIh#bNS5APNP}>V zqzG7lvywB9PPCet+R)jk`-_f8UsF)VH%y^=gPy%ABqnRQCT1s`0%*3k7Wx+=1Ixi5 zLOP0u=G`Y_mCS%}6QR&z6sz950 z18gCOK*JT#UR|p12r#NXX8wcTv(gs3{q4d7&&n0BRC{(ctY+=0&njyE=^vP9vXNxK zU_k(MsN=n5B|yTTUezqNQm4%e`GdOjZ_2Y3Suz_r1n_%Rt1=sLJ6OUcrtD{G=L5Oz zS<<<8XFW-(+D@QRe$Oisy@@?4#q6<1F37-UVUW4N6fFVjSCN$zu{f&E%-wRM`=jq4 z@TvTuRNPL-Xy9YNvi|^$Rd?jz1JjCLH2~ zgxJX3q{`ia=CuJC$nRM0z+?~3w5_DyY_Hr5AHt}ErO_wdX>n@ZR}&}U!+wN*Rj0cc z#dBJ9$Jy^=l%JFwAEDsaLH9{q{nLuhOH)|A3lYnl_NjM(xy@Bl1vs{8SgV;=k?p^b zkGkJD{CfVmt9CPy35cGDaQF58l*{zYOCbIe&(Qw>kyPT8M=BC{&JWZ4;+PvAd*`62 z+DDR3ae@5mCTwx*QbvAWlvr0JP)DUNG-u_e?#Q44#(J7nk<5X1jGhJ!F`A~cj6BUF z429?qttJT6iYQhg9I&e#e9Q?1no|azh)g!S9RC0ja!9Czr>PmL7q>Dro=UI)jF3N- zMVWU+fpYTPO1x}NG7nm{1YbJJMovK$lLqumpSVak9cykjQi@c94G%#rPFqxq7t$#M zhhh5FEz21TAtWA$)9YHg=G4_0PgcW^#8x%IRol4ttz)s2v}K$lF5tr+pw($)%6z1C z>rHi0b-~9R)7=LjOjRK=6;M~HB=w~u+t}030-D_^k~agesBRC+zgnNQSGhkbeN8k3 zw*LU?m)@@1sgmJQPhaWHQiq6B=~wJ>Z%_`r{{SOR>@~UQ%gTZ~)Hg(k$JU=7LV;1; za~S&9l9s2Y-i0<|deb?jYHo2_*u+*$4Acy~)rXo_L`QaILA3!tbYz?l#FJ3BN@y8g zPq|RI`F|R)=YlF085L-jRlDLv{{VDS$*Nt+qeZ1Vp|y%uofpep%FF<7n;WojILSo!YrpX*v@kuO8Dk}zP+>jgt%A9k9(~nx#)gID)PI;^?TGrX! zo+uhmFvg_tyRb8knXD^p`GU38(8q>3sFK#@#pz;Ow*LT$EjLv*ZUArDYghHJ#Z&IqGWVu@T(QxnJLO?NAls zt=t&=-2BInr9sy?7^+0E*57fywOVnDhO3Y+6#JU3a6i%wHMl*9)O@v0_8mOie@TMHxu-x;(-8PlQiWNcH*3%Py@*Q)iFj|r7Qb^ z^`@%)+zLY`LJ>Z^Q@p{R0W@s~w@xX+Mk-4il6ndiNi_Ym_?I#PNDJ{UA|Fbw{{Vii zD8zWGxTr<20;Ex%DFCOa_Mw6t1zNY^8mr>0#4%AKNv$vg+5=#uUn}E zR#P;Is;i!A#7WIZ0NgmM(Z^ivo7j9QgIZSd8)@UYT>kBY5$ZY-`4d&5jP3M(Bb9BuIVHoK&wU}bgZ-FLgDVgBpKAXAz*@WQV(i7? z{{SO+R|Ldax&;Gvc<~JPCN>OLMfyrw)=BXJ8@5Zmn3$o@*Z+{ z0-7X_M&_eMEtl*%Q)O|uk;osdSdDOiVwj6o=W_rDOx3Nb%np>KyPDRv zwp2jEMDsw)G3dWfe|m=OXpx7jS(r6Nxg|<5#?#eKKl;?Ru=$c6IO=OU`t;vwxke^5 zY$kjA{x!F1p;rU=fTyx2b~a2!H<#)<)@{UFXKZvQbzi$7uGkLPALsL^?jtUP9FhE~ zpk-x*Y*z!=nze5Yz=*sA;2u_z0sE3WR@RqprWf=r)6bJ$6C-`v7lAxDx^d&y9pO7ROeA4#EKu#_aBX1-WvnftI9Cuk{q=&&AC}O zM&yCiW12_Y(wAo~z!^1V#z8&DdV!JJJe(FBk6O_)Hy*^W+!GnLVtlf5x6!?77yIRX z4k|6&ZWQK`c9-r?N-Qgg>=1Hlv%YxfDILoND~_sjPQ={WL$!$PYooK7rLc}y$v<$PQa}3Gu45sT5ONRltz9Z?7q=vk z<8p)j;r{^E%}kMTX2$L*!LmBk0jc4!P+iAJ715Q3RE!^`Vn`WoJhtkjt5(+IS=X`R z;bjAc7(Y?}0M`Cg&=w((%Bh@;3?HpqQ-Q^2TE5w~o{h)jSAp$7GF`@#2N|XYr7jc< z_vuJLO-l{PNEuLMgV(iIVozRuyHnyEAJT?2UPrsHK#| zm_fP!0EAV`A&U_ke8-T-*EKs7oyN*@F;(fDDE94I5FuDqNd)w)nS;fAt`0(|EuP>S z*HiPl1ITQH?MaPpVR(T`T*V+Hk`8nA{{ZV&1m#Nco_%{)N#Z0Jw>bV5AFuxaUb*L7 zF5}Q1YglY$J;nlA@=sx$)Sh8HF#JVCx%q~El)1%Ufk zPj>_L6s4kLj;$Vnj4>Yd9QoN(5zjuf$w%&ud24ghdlVZq!a1o(B-Cw%?^>A_wCytY zR@9-e)9s|VxtX>{5)76;f~s6X@J{haFzCftdJ(~^T7I{Cq)#l`eC8Qth3(nY0(Lms zz#hbmjE;FVMWx-(Pijk={y^<-G6x(QO`j(^Nn$ZmTeCz-036bL4Q^cWg2Kd-PAZlv=h_>~A)_3ORbVO=%aytST9giy zD5({Bq`?RWHD)#WY9PHT!VE1-DkI}UdR5pqs^EeT^QzH|Hx;Ih3#eBLc*i69)^cXC zLt_OPw*((bVl7)X>#*#6eR@ZiS=Pykx>meH z7^sm*(U(sawwAJ);&VJ^O^DesjF1C*9y5wa(9~#27^^X>vn+9q(m4vF)Sd-mlQg-; zd_uZgJp^FlYqR!r=l)r)8bkP0eXzp=d?j9VlNb#%Bnr)PuCbMo^bj|KUkHWOL3Rw2$vX?Buk5Yg7_0o=Z zO+*Ri+~cEuBPI1p#iOFM=NjmM8(~mLu!M zLe#gRiDeh>lpds${uR+$oz`jx-d;b#vh3joc9aeQ!2Y$Z8U@%_p};@W{QK3(iYQ^W z3cg_^mN_}~pp1?>_NgYy$+Yx5{xu0aQWMdHU=sUA0XfBP>1nppJ=o{)tQ6tM_2#wh zWMzY3I2oap679@;j^IbrHBIe9jjjPx+pSGcR$ZS?wFR8@{eXynO+Z8S52%$zt`z`${b1vcsPh(I`6K%%Y ztBK>tKQiZ`q~cPaMrbntx$jY#Bz7#!G3kn|vu-;{!SppIc@;LXSGguKgs}h)^u|y+ zaw*^frCXuvO@EO)1q1S+3N!qSeF>-PHv?smi1_eQMDxxTADx;|Db&j1FqOo8~r*_T*KeOhvnA{oc;%e@eL&jT?tk z^C`%zxZh-;^aq1im9a|0Oy60<4eAL8oO))T6pq}m13d+2Y4VRPqdh^$`c=@}=AokQ zS`2BE$L8Cz4!uG5q*nQ9OJGtc&J1yp#yPDNnO-3I0AoD%sy7R=VnF#@k@fHXed(|_ z?>4a{bpz1Q4Vofs^!;hT^(Q&^s2A^Knv-`FSVWnpml4B|GR@Fcef;swNLzCjY-jmW z7%qCT$vsJ}3s=NPzcrd$6!@-MJ~%5$p{828lgxdipzH5fAdv2j&vgKw!ynSK#t6!g zLFj7SC-*DukyByZX1u$tB0i2s>7VIb^niH{T?VO^(gPpikRR#&Yo24q(^n0MmgEE+ zan_MeQ1<6E;AsPGZk!&Xv><6Xq|GTGF&>;!QxJ4DT5p=?A3;`oRdvH%^ZoDTKo-X= zezmjV*u2eh9y%~TmQVDoRj#AL5qX-aY-eh*{W1M&YP&&~NnU8{`cq^dx-~nl1w_Lt zYs^QY%;^JiD!E2tdE&3h773`*6SlNW$)bZrj?~SyqVSA#s;;0mF;xBLMgCE3dyCrIjSjdJO6=E*q-l9SCikTM# zpIR6pE@i$I{dWwm-l9$K@kvHfF}S|_~U{F z1pq96i>WnB88rCUa3gjxLj*0%kr&S_-SBFJm?t}NSBz>01M{kvI0RsVeFX>^N>phH za54uK0mr3Z0|Ol@q`)ksaaNfYDzX8;BPSQj$ z*h+`}Dl@|rZ|?*AK9yQgw;&FNv7&O5D`yxW*3|9uwmB7(i%)Y%w9!{!XZjq{U7;}( zj@0-`XCRLCB*1wjA4+>L=w=04aOsTkO~p7?rXh+kPQ@-bpaL;XVf({UpunVY^XJ-u zjKxa|<@4!H3sb@{q~eAMRvBzkh3QL zHs^}H92;WFK7EL(ld(x$f2Q?60YVX-|{6q4nUNalxgY=}D8$%RvQvuC2SEWj$ znoMW_;;cr$Ekp%ajBsjMXp$g93ckA=0F3==tV_*ZMFz2vtVLM%45=gAH058L@uw;S zPYH&_L1@vmm7tLw7^?%2M`K%;y1o9ZGu`S}lU+{029{?m#~nE}gAm5i?^lyM2=}ge zL0;zZleLR>syF7e;}xH3hXS`5f`J?f>=%%OA8RiH3}sY}f4eeqt(JeF6uJ8azhVzYqxm+M!rTNdDYwNTH@4N@hF z%uK4FWCN30HsA>NpH7vI9#1r|Bl*>}m=ytz*6D(2GLbp^xF4UTM>3HK8NkMIQf}IT zO5mD?;g6Sr(>(nuP%^XgO;p^}tZG=m5$33oQZi;6aq`xxaS#L2vXVj(nMYIl3cVbF z#G^jOrId-JBRM~HMon|`NYhO3{7ui$R;Hmg+cw7q&fmlT0M%Kxi@rkLx>HCSFIyl; z7p6L5t+7S5CGY~THCiEpM{MSy)UFEKD)q_!RW`dS_C=#1p4dsBn05O1{{TMq9F3I9 z)^3?}%Xra9av)Ghd6cQgsIC&vJu zwG=V8n#gcLJHC}50Lagr_7ugrOMA3;T%#Sl^v`Nw6Ipz$+zfJRfoF-aox{-9h27=H zlteMcp^i>DDl0$EEZb*Mll(%MuWgB=xDA1vA45&KmxWCAD9e4~6jjJybYPQ{(A6E>bNW=) z@&P8?{qN^Y4H#wer&l8&9)6Xq8{a;M*090B&!u02V%FFlRN&HOBJ7enoFNCfBcH;a zkH6;61B_K)Fm29h2J?^()jpkSY&(``+bkz*4a>+G>+Mv-9D=8j$TeUL3<|2_WQ2A+ zidG%X1du#omyFWn?#61AGVN`rq2zsP%5%@HFeh9uN>cdaH5N{2rC=YwJuyq198_cP zW}n`W7cFu|-+U4Ls{CvOVL+^?A8eTQtMI=3usQ8g(MU~Ai)qZAfCrCbTPZeFW9?DLoSb^o0?IdP?tBdn<++<36ffpU{*}TY#d>#wt@da#Nw*v1$JYRV ziL5a$)Y-lnUS_<>@|uTl6?SC#4Meg2<<2`-p0+#LN>s_FFe;;poUauik9uPq_N%>& z%=RarUe#6OB$9g7_lT$&6$>R=C6y62$QrB&gK{xQR;Go5ji!bpChk03zt*aCV9)0zOw)R4$?g1u?6u1#iWTaA8n6?F#~_o}fE-Vb3{5OY~b(k6wn;YDdgII33b z@_|+-xQ5coS?(O9QK6DX9YT({_dN%>tgUxsUF@#TKgXKnk%ZE%-vO6&gm>+a=U#Ow z$qQHYJNb1zQft{jR*|w0bVcYCdjWx2g||w5tJ$MZk|`cdTAcE@=3o?>qIt>ns}nd0 zj^?Xpirpg?QN2IBRP-6DQfE6yrfSu}-E!yCimNC3&%+7Uq^rbZ*jgLh?UX;S6 zcwvuvOklG-eakOQ8k9<`Gmt^+RV6qeR79NQaDAw-7Y=t|bf--FQ)v8Zta8X00>F=P zQW9iusl^r%ZC7om80T$E2_djY3~7u%bbggGs>f}8Qam^%=obgk^8%Gvj0JqKfRNSOWqXPtk`cqWqMm>foXB$pFZ>2;7o!o#4 z&lH9XOEC-EsXYZ(Dgb9=z#VZ`GKm>1La6Fb0;pX|CLUaQ3!IkjX`vCxIFIEZ5<7RS zd&#AmW4XRicmuU+c^@f1jbqJ~l!AH9GEF;Mk3Jup?+gR)?@`?Oaj*w0NY2sPps_fa zk8Qu!rkzKeSo4r59rPhtdXkHd)fDZ#=Ztm&rP-de$xwM&1E)0X7a>4N$m>%pk@vqk zjW{6Gn8>8T5|+y2J$uu3lG)(>DlkeCJ5+&z98`==xTcjE$l%l4^`s{QB;uL@q~!Fa zUv4QGOD6-0R162r%~2)fZORX=ScXln^K?8Kr32uU_2g9fpbZ0(cAmNC9@RQG7^;vy zXP!JwWoQSQYq?DRAM;ZEPq38+JL9`phW@z~G>lGtCRU9yvEu|Bn%yO2F<%q$il z2?H%s(9v!}UN;2w2D#;svH*BJD{Z73fECY!waWT&P9l(<4%60`G?L&*G2WTGnz9Kx znow~}2A4FzZ0+)e^)#`JMx*hlByG~;@T&_<36N!g^{-{nEk4iTn@I73Q+fK6n(`YM z{M-0b)xiC0-X=gDQ**h!|7TP(4#Z&7%NrTc&kjc6R#CWhE*#_tMjP$ zsYs@CxMLMWkX|SHN%{(=>sl9M_uTplsLNLpWL0IUV;?09ywlKpl|&*bN62ciUTW;4 z_hzdy(?Vn{yi>9A;+2OK5y7eg4dqGNgFdE`N1jz7+~S@FS-9^_Y~whfL<|*I0A$lV zzul`2{i)6mH0J*RRe{==74SD^t6c%d8O>TJYUZlVmgLnXsV`!S3U1n!hcwbKD$K~3 z0n)G7AM|D(jZ~Oby*&Q_tRBG9mc>VM&>VUk=8@zaibKvosM!vE>MU7Oly#tvX+W(E zhbZSYGV;Qs0MyZr^bHQjG}imn@xjF=-c2H1qV}F`lJXOHj`re3 zGOT0T7} z0X$WifX)Yck7yLcFaixr5X_nMrsAf7NnSge1WpNVquQz8+?hv~hvZ(QcQs<=wngQq z-aY*VQk5{OgSn+)j>l^BSoluQSd3@_&$Cey7 z)~7;bVy@pP;0npLo6DbRI9A~Odm6ju`6}e&Ip7+WicGZm9e5R5TeOUALJ9Y(vQF+e zCmyDt3Vht3PV^)fC1-h`bCQ3hIY7-I7+P}r)d+J8j8{E<#pC1D*F{|2@BDo+^(6kZ z0dCDoz$9+`eJWW&EJ);1!MPz(!59Yz=~7({vYZTX59v}qgaVs@QwOClJ?V_t;~naR zMpI}jPD8nK_!?Z*7 zC<4S%d2R{m(2r`n(BrL8BL=L%`=Z!-uTOD98Z3szJ8>hLi$1jM_NlPNb>4($p2yy* z=Z;6=R=ZVch8uYA){6mRDR-|Yky7sBs3UAUzdEpF0DAgjkPdXQ^;S&fC&C+dF{PNsbd3^=G@jH5`X5K&hB~$BKs^ zG5Xb#M~a4Sl{p5Zm3SXoq={t~7&RU`)s|2}sKk8L5JR@6vjt^fdx|gz0-XRReg!A6 d*5v9)b_cC4K6ALxzw4QgN=);g=TK;W|JmU+*0ulu literal 0 HcmV?d00001 diff --git a/schemas/equipment.json b/schemas/equipment.json new file mode 100644 index 0000000..40e1520 --- /dev/null +++ b/schemas/equipment.json @@ -0,0 +1,31 @@ +{ + "Actions": [ + { "Id": "equip.put", "Name": "equipment/schema/equip/put", "Description": "equipment/schema/equip/put_desc", "Category": "items", + "Params": [ + { "Key": "item", "Type": "ref", "Kind": "item", "Required": true, "Name": "equipment/schema/field/item" }, + { "Key": "who", "Type": "who", "Name": "equipment/schema/field/who" }, + { "Key": "slot", "Type": "ref", "Kind": "equip_slot", "Name": "equipment/schema/field/slot" }, + { "Key": "give", "Type": "bool", "Name": "equipment/schema/field/give", "Description": "equipment/schema/equip/give_desc" } ] }, + { "Id": "equip.remove", "Name": "equipment/schema/equip/remove", "Description": "equipment/schema/equip/remove_desc", "Category": "items", + "Params": [ + { "Key": "slot", "Type": "ref", "Kind": "equip_slot", "Required": true, "Name": "equipment/schema/field/slot" }, + { "Key": "who", "Type": "who", "Name": "equipment/schema/field/who" } ] } + ], + "Kinds": [ + { "Kind": "equip_slot", "Name": "equipment/schema/kind/equip_slot", "Description": "equipment/schema/kind/equip_slot_desc", "Folder": "equipment", "NewId": "new_slot", "Order": 5, + "Fields": [ + { "Key": "Name", "Type": "locale", "KeyPattern": "{mod}/slot/{id}", "Name": "equipment/schema/field/name" }, + { "Key": "Order", "Type": "int", "Name": "equipment/schema/field/order" }, + { "Key": "Accepts", "Type": "ref_list", "Name": "equipment/schema/field/accepts", "Description": "equipment/schema/field/accepts_desc" } ] }, + { "Kind": "item", + "Fields": [ + { "Key": "Equip", "Type": "text", "Name": "equipment/schema/field/equip", "Description": "equipment/schema/field/equip_desc" }, + { "Key": "Traits", "Type": "list", "Name": "equipment/schema/field/traits", "Description": "equipment/schema/field/traits_desc", "Of": [ + { "Key": "Stat", "Type": "ref", "Kind": "stat", "Required": true, "Name": "equipment/schema/field/stat" }, + { "Key": "Add", "Type": "number", "Name": "equipment/schema/field/add" }, + { "Key": "Percent", "Type": "number", "Name": "equipment/schema/field/percent" }, + { "Key": "Formula", "Type": "formula", "Name": "equipment/schema/field/formula" } ] }, + { "Key": "Archetypes", "Type": "ref_list", "Kind": "archetype", "Name": "equipment/schema/field/archetypes", "Description": "equipment/schema/field/archetypes_desc" }, + { "Key": "StatUp", "Type": "map", "Kind": "stat", "Name": "equipment/schema/field/stat_up", "Description": "equipment/schema/field/stat_up_desc" } ] } + ] +} diff --git a/src/EquipItemAction.cs b/src/EquipItemAction.cs new file mode 100644 index 0000000..23570a5 --- /dev/null +++ b/src/EquipItemAction.cs @@ -0,0 +1,30 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Items; + using Cthangover.Core.Settings; + using Cthangover.Mods.Items; + + /// + /// The item action "ItemAction": "action/equip". With the item type + /// TargetUsed the inventory's own "apply to whom" picker chooses the party member, + /// and the inventory takes the item away once this returns true — so gear needs no + /// equipment screen of its own to be put on. The replaced item comes back to the bag. + /// + public class EquipItemAction : ITargetedItemAction + { + /// + public string ID => "action/equip"; + + /// + public bool UseAction(IItem item) => false; + + /// + public bool UseOn(IItem item, CharacterInfoData target) + { + if (item == null || target == null) + return false; + // The inventory removes the applied item itself, so the action must not take it too. + return EquipmentService.Equip(target.ID, item.ID, null, fromInventory: false); + } + } +} diff --git a/src/EquipPutAction.cs b/src/EquipPutAction.cs new file mode 100644 index 0000000..aacefdf --- /dev/null +++ b/src/EquipPutAction.cs @@ -0,0 +1,32 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Actions; + + /// + /// action equip.put item=<id> [who=player|<id>] [slot=weapon] [give=1]: + /// puts an item on a character from a scenario — the starting gear of a class, a gift + /// the hero wears at once. The item comes from the inventory; with give=1 it is + /// granted instead (it need not be in the bag). + /// + public class EquipPutAction : IScenarioAction + { + /// + public string Name => "equip.put"; + + /// + public void Run(IActionContext ctx) + { + var item = ctx.GetParam("item"); + if (string.IsNullOrWhiteSpace(item)) + { + ctx.LogWarning("EQUIPMENT", "equip.put: missing 'item'"); + return; + } + var slot = ctx.GetParam("slot"); + var give = ctx.GetParam("give"); + var fromInventory = string.IsNullOrWhiteSpace(give) || give.Trim() == "0"; + if (!EquipmentService.Equip(ctx.GetParam("who"), item.Trim(), string.IsNullOrWhiteSpace(slot) ? null : slot.Trim(), fromInventory)) + ctx.LogWarning("EQUIPMENT", $"equip.put: '{item}' was not put on (not gear, no fitting slot, not allowed or not in the inventory)"); + } + } +} diff --git a/src/EquipRemoveAction.cs b/src/EquipRemoveAction.cs new file mode 100644 index 0000000..6fa9032 --- /dev/null +++ b/src/EquipRemoveAction.cs @@ -0,0 +1,23 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Actions; + + /// action equip.remove slot=weapon [who=player|<id>]: takes off what is worn there, back into the inventory. + public class EquipRemoveAction : IScenarioAction + { + /// + public string Name => "equip.remove"; + + /// + public void Run(IActionContext ctx) + { + var slot = ctx.GetParam("slot"); + if (string.IsNullOrWhiteSpace(slot)) + { + ctx.LogWarning("EQUIPMENT", "equip.remove: missing 'slot'"); + return; + } + EquipmentService.Unequip(ctx.GetParam("who"), slot.Trim()); + } + } +} diff --git a/src/EquipSlotInfo.cs b/src/EquipSlotInfo.cs new file mode 100644 index 0000000..207ec75 --- /dev/null +++ b/src/EquipSlotInfo.cs @@ -0,0 +1,32 @@ +namespace Cthangover.Mods.Equipment +{ + using System.Collections.Generic; + using System.Text.Json.Serialization; + using Cthangover.Core.Factories; + + /// + /// A place a character wears something ("Kind": "equip_slot"): weapon, body, + /// accessory in an RPG; outfit and jewellery in a dating sim; a cyberware socket in a + /// shooter. Slots are data, so each game has its own set and a mod adds a slot + /// ("a second ring") without code. + /// + /// An item fits a slot when the item's "Equip" key names one of the slot's + /// types, or the slot id itself when the slot lists none. + /// + [EntityKind("equip_slot")] + public class EquipSlotInfo : IIdentifiable + { + /// Slot id (weapon, body, ring_left). + [JsonPropertyName("Id")] + public string ID { get; set; } + + /// Locale key of the slot's name. + public string Name { get; set; } + + /// Display order in the sheet (lower first). + public int Order { get; set; } + + /// Item equip types the slot takes; empty = items whose type is the slot id. + public List Accepts { get; set; } = new(); + } +} diff --git a/src/EquipmentChangedEvent.cs b/src/EquipmentChangedEvent.cs new file mode 100644 index 0000000..1d34e70 --- /dev/null +++ b/src/EquipmentChangedEvent.cs @@ -0,0 +1,10 @@ +namespace Cthangover.Core.Events +{ + /// A character put something on or took it off (the stats already know; this is for UI and mods). + [EventKey("equipment_changed")] + public class EquipmentChangedEvent : ModEvent + { + /// The character. + public string CharacterId { get; init; } + } +} diff --git a/src/EquipmentModInitializer.cs b/src/EquipmentModInitializer.cs new file mode 100644 index 0000000..cf56f5a --- /dev/null +++ b/src/EquipmentModInitializer.cs @@ -0,0 +1,33 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Bootstrap; + using Cthangover.Core.Mods; + using Cthangover.Core.Scenes.Parsing; + using Cthangover.Core.Utils; + + /// + /// Wires equipment in: the equipped() condition and the new-game reset. The trait + /// source, the item action and the scenario actions are found by their registries. + /// The kernel removes the condition parser with this mod's assembly on unload. + /// + public class EquipmentModInitializer : IModInitializer + { + private static bool registered; + + /// + public void OnModLoaded(string modId) + { + if (registered) + return; + registered = true; + LeafParserRegistry.RegisterFirst(new EquippedLeafParser()); + GameLogger.Log("EQUIPMENT", "equipment: condition equipped() registered"); + } + + /// + public void OnModResourcesReady() + { + AppServices.Current.RegisterResettable(new EquipmentReset()); + } + } +} diff --git a/src/EquipmentReset.cs b/src/EquipmentReset.cs new file mode 100644 index 0000000..e88908b --- /dev/null +++ b/src/EquipmentReset.cs @@ -0,0 +1,14 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Bootstrap; + + /// A new game (or the reset before a load) starts with nobody wearing anything. + public class EquipmentReset : IResettable + { + /// + public string Id => "equipment"; + + /// + public void ResetForNewGame() => EquipmentService.Reset(); + } +} diff --git a/src/EquipmentSaveable.cs b/src/EquipmentSaveable.cs new file mode 100644 index 0000000..578da01 --- /dev/null +++ b/src/EquipmentSaveable.cs @@ -0,0 +1,29 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Mods; + using Cthangover.Core.Settings; + using Cthangover.Mods.Stats; + + /// Saves what everyone wears in the equipment slot. + public class EquipmentSaveable : IModSaveable + { + private const string BlobKey = "Worn"; + + /// + public void OnSave(ModSlot slot) + { + slot.Data[BlobKey] = new DataBlob(1, EquipmentService.Data); + } + + /// + public bool OnLoad(ModSlot slot, out string errorMessage) + { + errorMessage = null; + EquipmentService.Data = new EquipmentStateData(); + if (slot?.Data != null && slot.Data.TryGetValue(BlobKey, out var blob)) + EquipmentService.Data = blob.ReadJson() ?? new EquipmentStateData(); + StatsService.ClearCache(); + return true; + } + } +} diff --git a/src/EquipmentService.cs b/src/EquipmentService.cs new file mode 100644 index 0000000..f9564dc --- /dev/null +++ b/src/EquipmentService.cs @@ -0,0 +1,195 @@ +namespace Cthangover.Mods.Equipment +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Cthangover.Core.Events; + using Cthangover.Core.Items; + using Cthangover.Core.Mods.Resolvers; + using Cthangover.Core.Settings; + using Cthangover.Mods.Stats; + + /// + /// Who wears what. An item is equipment when its JSON has an "Equip" key (its + /// equip type); what it does while worn is its "Traits" list, read by the stats + /// through . Neither key needs the items mod to know + /// about equipment, so any game's items — and items of other mods, through patches — + /// become gear by data alone. An optional "Archetypes" list limits who may wear + /// an item (a staff for mages only). + /// + /// Equipping takes the item from the inventory and returns the one it replaces; taking + /// off returns the item. Every change tells the stats (sheets, battle attributes and + /// conditions follow) and publishes . + /// + public static class EquipmentService + { + /// The running game's worn items (replaced on a new game and a load). + public static EquipmentStateData Data { get; set; } = new(); + + /// Slots of the loaded mods in display order. + public static IReadOnlyList Slots => + Entities.Collect().Values.Where(s => !string.IsNullOrWhiteSpace(s.ID)) + .OrderBy(s => s.Order).ThenBy(s => s.ID, StringComparer.Ordinal).ToList(); + + /// The slot , or null. + public static EquipSlotInfo Slot(string id) + => Slots.FirstOrDefault(s => string.Equals(s.ID, id, StringComparison.OrdinalIgnoreCase)); + + /// The item definition , or null. + public static ItemInfo Item(string itemId) + { + if (string.IsNullOrWhiteSpace(itemId)) + return null; + var all = Entities.Collect(); + if (all.TryGetValue(itemId, out var info)) + return info; + return all.Values.FirstOrDefault(i => string.Equals(i.ID, itemId, StringComparison.OrdinalIgnoreCase)); + } + + /// The equip type of an item (its "Equip" key), or null for an item that is not gear. + public static string EquipType(string itemId) => ExtraData.Text(Item(itemId)?.ExtraProperties, "Equip"); + + /// Whether the item can be worn at all. + public static bool IsEquipment(string itemId) => !string.IsNullOrWhiteSpace(EquipType(itemId)); + + /// Whether takes items of . + public static bool Accepts(EquipSlotInfo slot, string equipType) + { + if (slot == null || string.IsNullOrWhiteSpace(equipType)) + return false; + return slot.Accepts == null || slot.Accepts.Count == 0 + ? string.Equals(slot.ID, equipType, StringComparison.OrdinalIgnoreCase) + : slot.Accepts.Any(a => string.Equals(a, equipType, StringComparison.OrdinalIgnoreCase)); + } + + /// The slots an item fits, in display order. + public static List SlotsFor(string itemId) + { + var type = EquipType(itemId); + return Slots.Where(s => Accepts(s, type)).ToList(); + } + + /// Slot id → item id of what wears (empty when nothing). + public static IReadOnlyDictionary Worn(string who) + { + var id = StatsService.Resolve(who); + return Find(id) ?? new Dictionary(); + } + + /// The item in a slot of , or null. + public static string ItemIn(string who, string slot) + => slot != null && Worn(who).TryGetValue(slot, out var item) ? item : null; + + /// Whether wears in any slot. + public static bool Wears(string who, string itemId) + => Worn(who).Values.Any(i => string.Equals(i, itemId, StringComparison.OrdinalIgnoreCase)); + + /// + /// Whether may wear the item (in , or in + /// any slot that fits); is the locale key of why not. + /// + public static bool CanEquip(string who, string itemId, string slot, out string reasonKey) + { + reasonKey = null; + if (!IsEquipment(itemId)) + { + reasonKey = "equipment/not_gear"; + return false; + } + var fits = slot == null ? SlotsFor(itemId).Count > 0 : Accepts(Slot(slot), EquipType(itemId)); + if (!fits) + { + reasonKey = "equipment/no_slot"; + return false; + } + var allowed = ExtraData.Read>(Item(itemId)?.ExtraProperties, "Archetypes", itemId); + if (allowed is { Count: > 0 } && !allowed.Any(a => string.Equals(a, StatsService.ArchetypeOf(who), StringComparison.OrdinalIgnoreCase))) + { + reasonKey = "equipment/wrong_archetype"; + return false; + } + return true; + } + + /// + /// Puts the item on . Without a slot it takes the first fitting + /// empty slot, else the first fitting one. With the + /// item must be in the inventory and one is taken from it; the replaced item goes back + /// to the inventory either way. False (nothing changed) when the item cannot be worn. + /// + public static bool Equip(string who, string itemId, string slot = null, bool fromInventory = true) + { + var id = StatsService.Resolve(who); + if (!CanEquip(id, itemId, slot, out _)) + return false; + var target = slot != null ? Slot(slot) : PickSlot(id, itemId); + if (target == null) + return false; + var inventory = Inventory; + if (fromInventory && (inventory == null || !inventory.Remove(itemId, 1))) + return false; + + var worn = Of(id); + if (worn.TryGetValue(target.ID, out var previous) && !string.IsNullOrEmpty(previous)) + inventory?.Add(previous, 1); + worn[target.ID] = Item(itemId)?.ID ?? itemId; + Changed(id); + return true; + } + + /// Takes off what wears in , back into the inventory. + public static bool Unequip(string who, string slot, bool toInventory = true) + { + var id = StatsService.Resolve(who); + var worn = Find(id); + if (worn == null || slot == null || !worn.TryGetValue(slot, out var item)) + return false; + worn.Remove(slot); + if (toInventory && !string.IsNullOrEmpty(item)) + Inventory?.Add(item, 1); + Changed(id); + return true; + } + + /// Back to a new game: nobody wears anything. + public static void Reset() + { + Data = new EquipmentStateData(); + StatsService.Changed(null); + } + + private static IInventory Inventory => GameData.Instance?.Runtime?.Inventory; + + private static EquipSlotInfo PickSlot(string who, string itemId) + { + var fitting = SlotsFor(itemId); + var worn = Find(who); + return fitting.FirstOrDefault(s => worn == null || !worn.ContainsKey(s.ID)) ?? fitting.FirstOrDefault(); + } + + private static Dictionary Find(string who) + { + if (who == null) + return null; + if (Data.Characters.TryGetValue(who, out var worn)) + return worn; + return Data.Characters.FirstOrDefault(p => string.Equals(p.Key, who, StringComparison.OrdinalIgnoreCase)).Value; + } + + private static Dictionary Of(string who) + { + var worn = Find(who); + if (worn != null) + return worn; + worn = new Dictionary(StringComparer.OrdinalIgnoreCase); + Data.Characters[who] = worn; + return worn; + } + + private static void Changed(string who) + { + StatsService.Changed(who); + ModEventBus.Publish(new EquipmentChangedEvent { CharacterId = who }); + } + } +} diff --git a/src/EquipmentSheetSection.cs b/src/EquipmentSheetSection.cs new file mode 100644 index 0000000..1776cc6 --- /dev/null +++ b/src/EquipmentSheetSection.cs @@ -0,0 +1,87 @@ +namespace Cthangover.Mods.Equipment +{ + using System.Linq; + using Cthangover.Core.UI.Theming; + using Cthangover.Core.Utils; + using Cthangover.Mods.Interface.Theming; + using Cthangover.Mods.Stats; + using Godot; + + /// + /// The Equipment block of the character sheet: one row per slot with what is worn + /// there (picture, name, what it gives) and a button to take it off. Putting gear on + /// stays in the bag, where every item already has its own action, so the sheet does + /// not need an item picker of its own. + /// + public class EquipmentSheetSection : ISheetSection + { + /// + public string Id => "equipment"; + + /// + public int Order => 10; + + /// + public string TitleKey => "equipment/sheet/title"; + + /// + public bool AppliesTo(string characterId) => EquipmentService.Slots.Count > 0; + + /// + public void Build(VBoxContainer container, string characterId) + { + foreach (var slot in EquipmentService.Slots) + container.AddChild(SlotRow(characterId, slot)); + container.AddChild(UiKit.Hint(Tr("equipment/sheet/hint"))); + } + + private static Control SlotRow(string characterId, EquipSlotInfo slot) + { + var row = UiKit.Row(UiTokens.Space3); + row.Name = "Slot_" + slot.ID; + var name = UiKit.Label(Tr(slot.Name ?? slot.ID), UiTokens.FontBody, UiTokens.Body); + name.CustomMinimumSize = new Vector2(170, 0); + row.AddChild(name); + + var itemId = EquipmentService.ItemIn(characterId, slot.ID); + var item = EquipmentService.Item(itemId); + if (item == null) + { + row.AddChild(UiKit.Label("—", UiTokens.FontBody, UiTokens.Faint)); + return row; + } + + var icon = string.IsNullOrEmpty(item.Sprite) ? null : TextureUtils.LoadFromModGroup("items", item.Sprite); + if (icon != null) + { + var picture = UiKit.Icon(icon, 32); + picture.TextureFilter = CanvasItem.TextureFilterEnum.Nearest; + row.AddChild(picture); + } + var label = UiKit.Label(Tr(item.Name), UiTokens.FontBodyLarge, UiTokens.InkBright); + label.TooltipText = string.IsNullOrEmpty(item.Description) ? string.Empty : Tr(item.Description); + label.MouseFilter = Control.MouseFilterEnum.Pass; + row.AddChild(label); + var traits = ExtraData.Traits(item.ExtraProperties, item.ID).Where(t => t.Add != 0 || t.Percent != 0).ToList(); + if (traits.Count > 0) + row.AddChild(UiKit.Label(string.Join(" ", traits.Select(TraitText)), UiTokens.FontSmall, UiTokens.SuccessText)); + + var off = UiKit.Button(Tr("equipment/sheet/take_off")); + off.Name = "TakeOff"; + off.Pressed += () => EquipmentService.Unequip(characterId, slot.ID); + row.AddChild(off); + return row; + } + + private static string TraitText(TraitInfo trait) + { + var def = StatsService.Definition(trait.Stat); + var stat = def == null ? trait.Stat : Tr(string.IsNullOrEmpty(def.Short) ? def.Name : def.Short); + return trait.Percent != 0 + ? $"{stat} {(trait.Percent > 0 ? "+" : "")}{trait.Percent:0.#}%" + : $"{stat} {(trait.Add > 0 ? "+" : "")}{trait.Add:0.#}"; + } + + private static string Tr(string key) => TranslationServer.Translate(key).ToString(); + } +} diff --git a/src/EquipmentStateData.cs b/src/EquipmentStateData.cs new file mode 100644 index 0000000..7527ec9 --- /dev/null +++ b/src/EquipmentStateData.cs @@ -0,0 +1,12 @@ +namespace Cthangover.Mods.Equipment +{ + using System; + using System.Collections.Generic; + + /// What everyone wears: character id → slot id → item id (the equipment slot's one blob). + public class EquipmentStateData + { + /// Worn items per character and slot. + public Dictionary> Characters { get; set; } = new(StringComparer.OrdinalIgnoreCase); + } +} diff --git a/src/EquipmentTraitSource.cs b/src/EquipmentTraitSource.cs new file mode 100644 index 0000000..64f0da6 --- /dev/null +++ b/src/EquipmentTraitSource.cs @@ -0,0 +1,22 @@ +namespace Cthangover.Mods.Equipment +{ + using System.Collections.Generic; + using Cthangover.Mods.Stats; + + /// The traits of everything a character wears: each worn item's "Traits" list. + public class EquipmentTraitSource : ITraitSource + { + /// + public string Id => "equipment"; + + /// + public IEnumerable TraitsOf(string characterId) + { + foreach (var item in EquipmentService.Worn(characterId).Values) + { + foreach (var trait in ExtraData.Traits(EquipmentService.Item(item)?.ExtraProperties, item)) + yield return trait; + } + } + } +} diff --git a/src/EquippedCondition.cs b/src/EquippedCondition.cs new file mode 100644 index 0000000..93775c7 --- /dev/null +++ b/src/EquippedCondition.cs @@ -0,0 +1,24 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Scenes; + + /// equipped(who, item): true while the character wears the item in any slot. + public class EquippedCondition : ConditionNode + { + /// Creates the condition. + public EquippedCondition(string who, string item) + { + Who = who; + Item = item; + } + + /// Who must wear it (a character id or player). + public string Who { get; } + + /// The item id. + public string Item { get; } + + /// + public override bool Evaluate(EvaluationContext ctx) => EquipmentService.Wears(Who, Item); + } +} diff --git a/src/EquippedLeafParser.cs b/src/EquippedLeafParser.cs new file mode 100644 index 0000000..b4a8f06 --- /dev/null +++ b/src/EquippedLeafParser.cs @@ -0,0 +1,39 @@ +namespace Cthangover.Mods.Equipment +{ + using System; + using System.Collections.Generic; + using Cthangover.Core.Scenes; + using Cthangover.Core.Scenes.Parsing; + + /// + /// equipped(who, item) or equipped(item) (the player) in any condition: a + /// door that opens for the one carrying the old key, a guard who salutes the uniform. + /// Ids with a slash are quoted: equipped('rpg_plus/iron_sword'). + /// + public class EquippedLeafParser : ILeafParser + { + /// + public bool CanParse(TokenPeeker peeker) + => !peeker.AtEnd && peeker.Peek.Type == ConditionParser.TokenType.Ident && peeker.Peek.Value == "equipped" + && peeker.PeekAhead(1).Type == ConditionParser.TokenType.LParen; + + /// + public ICondition Parse(TokenPeeker peeker, Func parseSubExpr) + { + peeker.Advance(); + peeker.Expect(ConditionParser.TokenType.LParen, "expected '('"); + var args = new List(); + while (peeker.Check(ConditionParser.TokenType.Ident) || peeker.Check(ConditionParser.TokenType.String)) + { + args.Add(peeker.Advance().Value); + if (!peeker.Check(ConditionParser.TokenType.Comma)) + break; + peeker.Advance(); + } + peeker.Expect(ConditionParser.TokenType.RParen, "expected ')' after equipped(who, item)"); + if (args.Count is < 1 or > 2) + throw new FormatException("Condition parse error: equipped(who, item) takes one or two arguments"); + return new EquippedCondition(args.Count == 2 ? args[0] : null, args[^1]); + } + } +} diff --git a/src/StatUpItemAction.cs b/src/StatUpItemAction.cs new file mode 100644 index 0000000..d59865b --- /dev/null +++ b/src/StatUpItemAction.cs @@ -0,0 +1,35 @@ +namespace Cthangover.Mods.Equipment +{ + using Cthangover.Core.Items; + using Cthangover.Core.Settings; + using Cthangover.Mods.Items; + using Cthangover.Mods.Stats; + + /// + /// The item action "ItemAction": "action/stat_up": a tonic, a seed, a book that + /// permanently raises stats of the party member it is applied to, by the item's own + /// "StatUp" key ({"str": 1}, negative lowers). It lives here because this + /// mod is where items meet the stats; it uses the inventory's target picker like gear. + /// + public class StatUpItemAction : ITargetedItemAction + { + /// + public string ID => "action/stat_up"; + + /// + public bool UseAction(IItem item) => false; + + /// + public bool UseOn(IItem item, CharacterInfoData target) + { + if (item == null || target == null) + return false; + var ups = ExtraData.Read>(EquipmentService.Item(item.ID)?.ExtraProperties, "StatUp", item.ID); + if (ups == null || ups.Count == 0) + return false; + foreach (var pair in ups) + StatsService.AddBonus(target.ID, pair.Key, pair.Value); + return true; + } + } +} diff --git a/tests/EquipmentServiceTests.cs b/tests/EquipmentServiceTests.cs new file mode 100644 index 0000000..3a82a9e --- /dev/null +++ b/tests/EquipmentServiceTests.cs @@ -0,0 +1,83 @@ +namespace Cthangover.Mods.Equipment.Tests +{ + using System.Collections.Generic; + using System.Text.Json; + using Cthangover.Core.Mods.Testing; + using Cthangover.Core.Scenes; + + /// + /// The data rules of equipment that need no game: which slot takes which item type, + /// the saved state's round trip, the condition syntax. The equip flow with real items, + /// the inventory and battle attributes is covered by the rpg_plus game test. + /// + public class EquipmentServiceTests + { + [ModTest("slots/accepts_by_type_or_by_slot_id")] + static void AcceptsByTypeOrSlotId(ModTestContext ctx) + { + var hand = new EquipSlotInfo { ID = "weapon", Accepts = new List { "sword", "Staff" } }; + var body = new EquipSlotInfo { ID = "body" }; + + ModAssert.True(EquipmentService.Accepts(hand, "sword"), "listed type"); + ModAssert.True(EquipmentService.Accepts(hand, "staff"), "listed type in any case"); + ModAssert.False(EquipmentService.Accepts(hand, "weapon"), "a slot with a list takes only the list"); + ModAssert.True(EquipmentService.Accepts(body, "BODY"), "a slot without a list takes its own id"); + ModAssert.False(EquipmentService.Accepts(body, null), "no type is no gear"); + ModAssert.False(EquipmentService.Accepts(null, "sword"), "no slot"); + } + + [ModTest("state/json_round_trip")] + static void JsonRoundTrip(ModTestContext ctx) + { + var original = new EquipmentStateData(); + original.Characters["rpg_hero"] = new Dictionary { ["weapon"] = "rpg_plus/iron_sword", ["body"] = "rpg_plus/leather_armor" }; + + var restored = JsonSerializer.Deserialize(JsonSerializer.Serialize(original)); + + ModAssert.Equal(2, restored.Characters["rpg_hero"].Count, "two slots"); + ModAssert.Equal("rpg_plus/iron_sword", restored.Characters["rpg_hero"]["weapon"], "weapon"); + ModAssert.Equal("rpg_plus/leather_armor", restored.Characters["rpg_hero"]["body"], "body"); + } + + [ModTest("conditions/equipped_parses")] + static void EquippedParses(ModTestContext ctx) + { + var two = ConditionParser.Parse("equipped(rpg_hero, 'rpg_plus/iron_sword')") as EquippedCondition; + ModAssert.Equal("rpg_hero", two?.Who, "who"); + ModAssert.Equal("rpg_plus/iron_sword", two?.Item, "quoted item"); + + var one = ConditionParser.Parse("!equipped(lucky_charm)") ; + ModAssert.NotNull(one, "negated one-argument form"); + + var threw = false; + try + { + ConditionParser.Parse("equipped()"); + } + catch (System.FormatException) + { + threw = true; + } + ModAssert.True(threw, "no argument is an error"); + } + + [ModTest("worn/nobody_wears_anything_after_reset")] + static void NobodyWearsAfterReset(ModTestContext ctx) + { + var saved = EquipmentService.Data; + try + { + EquipmentService.Data = new EquipmentStateData(); + EquipmentService.Data.Characters["tester"] = new Dictionary { ["weapon"] = "x" }; + ModAssert.True(EquipmentService.Wears("tester", "X"), "wears, item id in any case"); + ModAssert.Equal("x", EquipmentService.ItemIn("TESTER", "weapon"), "lookup by id in any case"); + EquipmentService.Reset(); + ModAssert.Equal(0, EquipmentService.Worn("tester").Count, "reset empties"); + } + finally + { + EquipmentService.Data = saved; + } + } + } +}