From 0565051302cbc765fbba92b9eed95ececc25e002 Mon Sep 17 00:00:00 2001 From: Florian Berthold Date: Fri, 29 May 2026 15:55:25 +0200 Subject: [PATCH] coa.10: CoA reputation factions (data-driven) + custom-class icons + all-professions Skills - Reputation view rebuilt data-driven from each char's scanned factions grouped by in-game category; CoA custom factions (and future ones) appear automatically. Old hardcoded tree kept only as an icon lookup. - CoA custom-class icons (classes 12-32) render from bundled atlas Altoholic/images/coa-classes.blp (texcoords from coa-details) instead of the Warrior glue-icon fallback in ShowClassIcons. - Skills tab shows ALL known professions (dynamic list incl Woodcutting/Woodworking), not 2 fixed slots; DataStore_Skills scans on PLAYER_ENTERING_WORLD/SKILL_LINES_CHANGED (fixes 'no profession data' that only scanned on ghost-release). --- Altoholic/Altoholic.lua | 21 ++- Altoholic/Altoholic.toc | 2 +- Altoholic/Characters.lua | 45 ++--- Altoholic/CoAClassColors.lua | 72 +++++++- Altoholic/Frames/Reputations.lua | 162 ++++++++++++++---- Altoholic/Frames/Reputations.xml | 8 +- Altoholic/Frames/Skills.lua | 139 ++++++++------- Altoholic/Frames/Skills.xml | 48 +++--- Altoholic/Frames/TabSummary.lua | 7 +- Altoholic/images/coa-classes.blp | Bin 0 -> 175956 bytes .../DataStore_Reputations.lua | 27 ++- .../DataStore_Reputations.toc | 2 +- DataStore_Skills/DataStore_Skills.lua | 66 ++++++- DataStore_Skills/DataStore_Skills.toc | 2 +- README.md | 4 + 15 files changed, 428 insertions(+), 177 deletions(-) create mode 100644 Altoholic/images/coa-classes.blp diff --git a/Altoholic/Altoholic.lua b/Altoholic/Altoholic.lua index 437115d..26af057 100644 --- a/Altoholic/Altoholic.lua +++ b/Altoholic/Altoholic.lua @@ -732,13 +732,22 @@ function Altoholic:ShowClassIcons() end) local _, class = DS:GetCharacterClass(character) - -- CoA: CLASS_ICON_TCOORDS only carries the vanilla 10 + DK on Voljin. - -- For the 21 CoA custom classes the lookup is nil; fall back to - -- WARRIOR's coords so we render *something* rather than crashing. - local tc = CLASS_ICON_TCOORDS[class] or CLASS_ICON_TCOORDS["WARRIOR"] local itemTexture = _G[itemName .. "IconTexture"] - itemTexture:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes"); - itemTexture:SetTexCoord(tc[1], tc[2], tc[3], tc[4]); + -- CoA: CLASS_ICON_TCOORDS only carries the vanilla 10 + DK on Voljin, + -- so the 21 CoA custom classes have no entry. GetCoAClassIcon (defined + -- in CoAClassColors.lua) returns the realm-authoritative atlas + coords + -- for any CoA-playable class (incl. vanilla 10 + DK); it returns nil for + -- an unknown/unscanned (no-value) token, in which case we keep the stock + -- CLASS_ICON_TCOORDS path, defaulting to WARRIOR rather than crashing. + local coaTex, l, r, t, b = Altoholic:GetCoAClassIcon(class) + if coaTex then + itemTexture:SetTexture(coaTex); + itemTexture:SetTexCoord(l, r, t, b); + else + local tc = CLASS_ICON_TCOORDS[class] or CLASS_ICON_TCOORDS["WARRIOR"] + itemTexture:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes"); + itemTexture:SetTexCoord(tc[1], tc[2], tc[3], tc[4]); + end itemTexture:SetWidth(36); itemTexture:SetHeight(36); itemTexture:SetAllPoints(itemButton); diff --git a/Altoholic/Altoholic.toc b/Altoholic/Altoholic.toc index 00f8720..e3a2b04 100644 --- a/Altoholic/Altoholic.toc +++ b/Altoholic/Altoholic.toc @@ -13,7 +13,7 @@ ## Author: Thaoky, Telkar-RG ## X-Edited-By: Exiles (Sub-Net) — florian.berthold@sub-net.at -## Version: 3.3.002b-coa.9 +## Version: 3.3.002b-coa.10 ## X-Category: Inventory, Tradeskill, Mail ## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU ## X-Website: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx diff --git a/Altoholic/Characters.lua b/Altoholic/Characters.lua index 9c5634a..8a6d365 100644 --- a/Altoholic/Characters.lua +++ b/Altoholic/Characters.lua @@ -76,8 +76,6 @@ local function AddRealm(AccountName, RealmName) local realmBankSlots = 0 local realmFreeBankSlots = 0 - local SkillsCache = { {name = "", rank = 0}, {name = "", rank = 0} } - -- 1) Add the realm name table.insert(characterList, { linetype = INFO_REALM_LINE + (realmCount*3), isCollapsed = false, @@ -87,36 +85,27 @@ local function AddRealm(AccountName, RealmName) -- 2) Add the characters for characterName, character in pairs(DataStore:GetCharacters(RealmName, AccountName)) do - SkillsCache[1].name = "" - SkillsCache[1].rank = 0 - SkillsCache[1].spellID = nil - SkillsCache[2].name = "" - SkillsCache[2].rank = 0 - SkillsCache[2].spellID = nil - - local i = 1 - local professions = DataStore:GetPrimaryProfessions(character) - if professions then - for SkillName, s in pairs(professions) do - SkillsCache[i].name = SkillName - SkillsCache[i].rank = DataStore:GetSkillInfo(character, SkillName) - SkillsCache[i].spellID = DataStore:GetProfessionSpellID(SkillName) - i = i + 1 - - if i > 2 then -- it seems that under certain conditions, the loop continues after 2 professions.., so break - break - end + -- CoA: characters can know ALL professions at once (no retail 2-primary + -- limit) plus the customs Woodcutting/Woodworking. Build a dynamic list of + -- every known primary profession instead of the old fixed 2 slots. Each + -- entry carries its own name/rank/spellID(icon) so Skills.lua can render an + -- arbitrary number of professions. GetPrimaryProfessionList never returns + -- nil (returns {} for unscanned chars), but guard anyway. + local professions = {} + if DataStore.GetPrimaryProfessionList then + local list = DataStore:GetPrimaryProfessionList(character) or {} + for _, p in ipairs(list) do + professions[#professions + 1] = { + name = p.name, + rank = p.rank or 0, + spellID = DataStore:GetProfessionSpellID(p.name), + } end end - + table.insert(characterList, { linetype = INFO_CHARACTER_LINE + (realmCount*3), key = character, - skillName1 = SkillsCache[1].name, - skillRank1 = SkillsCache[1].rank, - spellID1 = SkillsCache[1].spellID, - skillName2 = SkillsCache[2].name, - skillRank2 = SkillsCache[2].rank, - spellID2 = SkillsCache[2].spellID, + professions = professions, -- CoA: dynamic list of all primary professions cooking = DataStore:GetCookingRank(character), firstaid = DataStore:GetFirstAidRank(character), fishing = DataStore:GetFishingRank(character), diff --git a/Altoholic/CoAClassColors.lua b/Altoholic/CoAClassColors.lua index f4f1e3d..29b8888 100644 --- a/Altoholic/CoAClassColors.lua +++ b/Altoholic/CoAClassColors.lua @@ -24,7 +24,8 @@ -- Source of truth: db.exil.es /coa/dev for the full palette; -- _G.RAID_CLASS_COLORS at FrameXML load time for the running client. -local AC = _G.Altoholic and _G.Altoholic.ClassInfo +local Alto = _G.Altoholic +local AC = Alto and Alto.ClassInfo if type(AC) ~= "table" then return end local source = _G.RAID_CLASS_COLORS @@ -45,3 +46,72 @@ for token, color in pairs(source) do end end end + +-- Class ICONS +-- ----------- +-- WoW's _G.CLASS_ICON_TCOORDS only carries texcoords for the playable +-- classes the *client* shipped with — on the CoA Voljin client that is +-- the vanilla 10 + DEATHKNIGHT only. The 21 CoA custom classes +-- (BARBARIAN, WITCHDOCTOR, CHRONOMANCER, …) have no entry, so any draw +-- site that does `CLASS_ICON_TCOORDS[class]` falls back to a wrong or +-- blank icon (Altoholic.lua:ShowClassIcons hit this). +-- +-- The realm-authoritative class-icon atlas is the 512x512 (8x8 grid of +-- 64px cells) BLP that the CoA Details! fork bundles and renders for +-- all 32 classes. We ship a copy of that atlas as +-- Interface\AddOns\Altoholic\images\coa-classes.blp and reproduce its +-- per-token texcoords below (source: Details/functions/profiles.lua +-- class_coords). Keyed by the UPPERCASE englishClass token — the same +-- key DataStore stores (DataStore_Characters: UnitClass()'s 2nd return) +-- and CLASS_ICON_TCOORDS uses, so it is a drop-in for both. +-- +-- Includes the vanilla 10 + DK too, so a single lookup covers every +-- CoA-playable class uniformly out of one texture. + +local COA_CLASS_ICON_TEXTURE = [[Interface\AddOns\Altoholic\images\coa-classes]] + +-- left, right, top, bottom (verbatim from the CoA Details atlas) +local COA_CLASS_ICON_TCOORDS = { + WITCHHUNTER = { 0.875, 1, 0.375, 0.5 }, + WITCHDOCTOR = { 0.75, 0.875, 0.375, 0.5 }, + WILDWALKER = { 0.625, 0.75, 0.375, 0.5 }, + WARRIOR = { 0.5, 0.625, 0.375, 0.5 }, + WARLOCK = { 0.375, 0.5, 0.375, 0.5 }, + TINKER = { 0.25, 0.375, 0.375, 0.5 }, + SUNCLERIC = { 0.125, 0.25, 0.375, 0.5 }, + STORMBRINGER = { 0, 0.125, 0.375, 0.5 }, + STARCALLER = { 0.875, 1, 0.25, 0.375 }, + SPIRITMAGE = { 0.75, 0.875, 0.25, 0.375 }, + SONOFARUGAL = { 0.625, 0.75, 0.25, 0.375 }, + SHAMAN = { 0.5, 0.625, 0.25, 0.375 }, + ROGUE = { 0.375, 0.5, 0.25, 0.375 }, + REAPER = { 0.25, 0.375, 0.25, 0.375 }, + RANGER = { 0.125, 0.25, 0.25, 0.375 }, + PYROMANCER = { 0, 0.125, 0.25, 0.375 }, + PROPHET = { 0.875, 1, 0.125, 0.25 }, + PRIEST = { 0.75, 0.875, 0.125, 0.25 }, + PALADIN = { 0.625, 0.75, 0.125, 0.25 }, + NECROMANCER = { 0.5, 0.625, 0.125, 0.25 }, + MONK = { 0.375, 0.5, 0.125, 0.25 }, + MAGE = { 0.25, 0.375, 0.125, 0.25 }, + HUNTER = { 0.125, 0.25, 0.125, 0.25 }, + HERO = { 0, 0.125, 0.125, 0.25 }, + GUARDIAN = { 0.875, 1, 0, 0.125 }, + FLESHWARDEN = { 0.75, 0.875, 0, 0.125 }, + DRUID = { 0.625, 0.75, 0, 0.125 }, + DEMONHUNTER = { 0.5, 0.625, 0, 0.125 }, + DEATHKNIGHT = { 0.375, 0.5, 0, 0.125 }, + CULTIST = { 0.25, 0.375, 0, 0.125 }, + CHRONOMANCER = { 0.125, 0.25, 0, 0.125 }, + BARBARIAN = { 0, 0.125, 0, 0.125 }, +} + +-- Returns texture, left, right, top, bottom for a CoA-playable class +-- token, or nil if the token is unknown (caller should fall back to the +-- stock CLASS_ICON_TCOORDS path). Tolerant of a nil/missing token. +function Alto:GetCoAClassIcon(token) + if type(token) ~= "string" then return end + local tc = COA_CLASS_ICON_TCOORDS[token] + if not tc then return end + return COA_CLASS_ICON_TEXTURE, tc[1], tc[2], tc[3], tc[4] +end diff --git a/Altoholic/Frames/Reputations.lua b/Altoholic/Frames/Reputations.lua index 5046711..556ffa1 100644 --- a/Altoholic/Frames/Reputations.lua +++ b/Altoholic/Frames/Reputations.lua @@ -14,6 +14,13 @@ local DARK_RED = "|cFFF00000" local ICON_UNKNOWN = "\124TInterface\\RaidFrame\\ReadyCheck-NotReady:14\124t" local ICON_EXALTED = "\124TInterface\\RaidFrame\\ReadyCheck-Ready:14\124t" +-- NOTE (Exiles/CoA): The Reputations view is DATA-DRIVEN. +-- The hardcoded `Factions` table below is used ONLY as an icon lookup (faction name -> icon), +-- so well-known Blizzard factions keep their nice icons. The list of factions actually shown, +-- and their grouping, is built at runtime from what DataStore_Reputations scanned on each +-- character (faction name + in-game category header). This means CoA's custom factions +-- (and any new ones added over time) appear automatically, with no code edits required. +-- Factions not present in the icon lookup fall back to a generic faction icon. local Factions = { -- Factions reference table, based on http://www.wowwiki.com/Factions { -- [1] @@ -151,8 +158,96 @@ local VertexColors = { [FACTION_STANDING_LABEL8] = { r = 1.0, g = 1.0, b = 1.0 }, -- exalted } -local currentXPack = 1 -- default to wow classic -local currentFactionGroup = (UnitFactionGroup("player") == "Alliance") and 1 or 2 -- default to alliance or horde +local GENERIC_FACTION_ICON = "Achievement_Reputation_01" -- fallback icon for factions not in the lookup (ex: CoA custom factions) + +-- Flat icon lookup built once from the hardcoded reference table above: faction name -> icon name. +local FactionIcons = {} +for _, xpack in ipairs(Factions) do + for _, factionGroup in ipairs(xpack) do + for _, faction in ipairs(factionGroup) do + if faction.name and faction.icon then + FactionIcons[faction.name] = faction.icon + end + end + end +end + +local function GetFactionIcon(name) + return FactionIcons[name] or GENERIC_FACTION_ICON +end + +-- *** Dynamic, data-driven group/faction model *** +-- currentGroup = "" means "All factions" (every scanned faction, flat). Otherwise it's an in-game +-- category header name (ex: "Wrath of the Lich King", or a CoA custom category). +local ALL_GROUPS = "" +local currentGroup = ALL_GROUPS + +-- Rebuilt on each Update from the union of all characters' scanned reputations on the current realm. +local displayedGroups = {} -- ordered list of { name = headerName } for the dropdown +local displayedFactions = {} -- ordered list of faction names currently shown (filtered by currentGroup) + +local function BuildModel() + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + + -- header (group) name -> { set of faction names }, plus first-seen order for stable display + local groupSet = {} + local factionHeader = {} -- faction name -> its header (last writer wins; headers are consistent across chars) + local factionOrder = {} -- faction name -> first-seen index (stable ordering) + local orderCounter = 0 + local groupOrder = {} -- header name -> first-seen index + + for _, characterKey in pairs(DS:GetCharacters(realm, account)) do + local reputations = DS:GetReputations(characterKey) or {} + local headers = DS:GetReputationHeaders(characterKey) or {} + for factionName in pairs(reputations) do + local header = headers[factionName] or "" + if factionOrder[factionName] == nil then + orderCounter = orderCounter + 1 + factionOrder[factionName] = orderCounter + end + factionHeader[factionName] = header + if not groupSet[header] then + groupSet[header] = true + groupOrder[header] = orderCounter + end + end + end + + -- Build the ordered group list for the dropdown. + wipe(displayedGroups) + local groupNames = {} + for header in pairs(groupSet) do + tinsert(groupNames, header) + end + table.sort(groupNames, function(a, b) return (groupOrder[a] or 0) < (groupOrder[b] or 0) end) + for _, header in ipairs(groupNames) do + tinsert(displayedGroups, header) + end + + -- If the previously selected group no longer exists, fall back to "All factions". + if currentGroup ~= ALL_GROUPS and not groupSet[currentGroup] then + currentGroup = ALL_GROUPS + end + + -- Build the ordered faction list for the currently selected group. + wipe(displayedFactions) + local names = {} + for factionName in pairs(factionHeader) do + if currentGroup == ALL_GROUPS or factionHeader[factionName] == currentGroup then + tinsert(names, factionName) + end + end + table.sort(names, function(a, b) return (factionOrder[a] or 0) < (factionOrder[b] or 0) end) + for _, factionName in ipairs(names) do + tinsert(displayedFactions, factionName) + end +end + +local function GroupLabel(header) + if header == ALL_GROUPS or header == "" then return ALL end -- "All", a Blizzard global string + return header +end addon.Reputations = {} @@ -194,46 +289,43 @@ local function DDM_AddCloseMenu() UIDropDownMenu_AddButton(info, 1) end -local function DDM_OnClick(self, xpackIndex, factionGroupIndex) - currentXPack = xpackIndex - currentFactionGroup = factionGroupIndex - - local factionGroup = Factions[currentXPack][currentFactionGroup] - UIDropDownMenu_SetText(AltoholicFrameReputations_SelectFaction, factionGroup.name) - +local function DDM_OnClick(self, header) + currentGroup = header or ALL_GROUPS + + UIDropDownMenu_SetText(AltoholicFrameReputations_SelectFaction, GroupLabel(currentGroup)) + ns:Update() end local function Reputations_UpdateEx(self, offset, entry, desc) local line local size = desc:GetSize() - + local DS = DataStore local realm, account = addon:GetCurrentRealm() local character - local factionGroup = Factions[currentXPack][currentFactionGroup] - + for i=1, desc.NumLines do line = i + offset if line <= size then - local faction = factionGroup[line] - - _G[entry..i.."Name"]:SetText(WHITE .. faction.name) + local factionName = displayedFactions[line] + + _G[entry..i.."Name"]:SetText(WHITE .. (factionName or "")) _G[entry..i.."Name"]:SetJustifyH("LEFT") _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) - + for j = 1, 10 do -- loop through the 10 alts local itemName = entry.. i .. "Item" .. j; local itemButton = _G[itemName] local classButton = _G["AltoholicFrameClassesItem" .. j] - + local itemTexture = _G[itemName .. "_Background"] - itemTexture:SetTexture("Interface\\Icons\\"..faction.icon) + itemTexture:SetTexture("Interface\\Icons\\"..GetFactionIcon(factionName)) local status, rate if classButton.CharName then -- if there's an alt in this column.. character = DS:GetCharacter(classButton.CharName, realm, account) - status, _, _, rate = DS:GetReputationInfo(character, faction.name) + status, _, _, rate = DS:GetReputationInfo(character, factionName) if status and rate then local vc = VertexColors[status] @@ -276,22 +368,24 @@ local ReputationsScrollFrame_Desc = { NumLines = 8, LineHeight = 41, Frame = "AltoholicFrameReputations", - GetSize = function() return #Factions[currentXPack][currentFactionGroup] end, + GetSize = function() return #displayedFactions end, Update = Reputations_UpdateEx, } function ns:DropDownFaction_Initialize() - for xpackIndex, xpack in ipairs(Factions) do - DDM_AddTitle(xpack.name) - - for factionGroupIndex, factionGroup in ipairs(Factions[xpackIndex]) do - DDM_Add(factionGroup.name, DDM_OnClick, xpackIndex, factionGroupIndex) - end + -- Dropdown is built dynamically from the categories actually scanned across all characters. + BuildModel() + + DDM_Add(GroupLabel(ALL_GROUPS), DDM_OnClick, ALL_GROUPS) -- "All factions" pseudo-group + for _, header in ipairs(displayedGroups) do + DDM_Add(GroupLabel(header), DDM_OnClick, header) end DDM_AddCloseMenu() end function ns:Update() + BuildModel() + UIDropDownMenu_SetText(AltoholicFrameReputations_SelectFaction, GroupLabel(currentGroup)) addon:ScrollFrameUpdate(ReputationsScrollFrame_Desc) end @@ -302,12 +396,12 @@ function ns:OnEnter(frame) local DS = DataStore local realm, account = addon:GetCurrentRealm() local character = DS:GetCharacter(charName, realm, account) - local factionGroup = Factions[currentXPack][currentFactionGroup] - local faction = factionGroup[ frame:GetParent():GetID() ].name - + local faction = displayedFactions[ frame:GetParent():GetID() ] + if not faction then return end + local status, currentLevel, maxLevel, rate = DS:GetReputationInfo(character, faction) if not status then return end - + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); AltoTooltip:ClearLines(); AltoTooltip:AddLine((DS:GetColoredCharacterName(character) or "?") .. WHITE .. " @ " .. TEAL .. faction,1,1,1); @@ -346,12 +440,12 @@ function ns:OnClick(frame, button) local DS = DataStore local realm, account = addon:GetCurrentRealm() local character = DS:GetCharacter(charName, realm, account) - local factionGroup = Factions[currentXPack][currentFactionGroup] - local faction = factionGroup[ frame:GetParent():GetID() ].name - + local faction = displayedFactions[ frame:GetParent():GetID() ] + if not faction then return end + local status, currentLevel, maxLevel, rate = DS:GetReputationInfo(character, faction) if not status then return end - + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then local chat = ChatEdit_GetLastActiveWindow() if chat:IsShown() then diff --git a/Altoholic/Frames/Reputations.xml b/Altoholic/Frames/Reputations.xml index 88647e3..b36c483 100644 --- a/Altoholic/Frames/Reputations.xml +++ b/Altoholic/Frames/Reputations.xml @@ -213,11 +213,11 @@ - local faction = (UnitFactionGroup("player") == "Alliance") and FACTION_ALLIANCE or FACTION_HORDE - - UIDropDownMenu_SetWidth(self, 100) + -- Default to "All factions"; the dropdown contents are built dynamically + -- from the categories actually scanned (see Reputations.lua / BuildModel). + UIDropDownMenu_SetWidth(self, 140) UIDropDownMenu_SetButtonWidth(self, 20) - UIDropDownMenu_SetText(self, faction) + UIDropDownMenu_SetText(self, ALL) UIDropDownMenu_Initialize(self, Altoholic.Reputations.DropDownFaction_Initialize) diff --git a/Altoholic/Frames/Skills.lua b/Altoholic/Frames/Skills.lua index ae052bf..c726531 100644 --- a/Altoholic/Frames/Skills.lua +++ b/Altoholic/Frames/Skills.lua @@ -81,13 +81,10 @@ function ns:Update() end _G[entry..i.."Level"]:SetText("") _G[entry..i.."Skill1NormalText"]:SetText("") - _G[entry..i.."Skill2NormalText"]:SetText("") _G[entry..i.."CookingNormalText"]:SetText("") _G[entry..i.."FirstAidNormalText"]:SetText("") _G[entry..i.."FishingNormalText"]:SetText("") _G[entry..i.."RidingNormalText"]:SetText("") - _G[entry..i.."WoodcuttingNormalText"]:SetText("") - _G[entry..i.."WoodworkingNormalText"]:SetText("") _G[ entry..i ]:SetID(line) _G[ entry..i ]:Show() @@ -113,28 +110,26 @@ function ns:Update() _G[entry..i.."NameNormalText"]:SetWidth(170) addon:SetCharacterRowNameLevel(entry, i, icon, character) - -- profession 1 - local field = Characters:GetField(line, "spellID1") - if field then - -- icon = addon:TextureToFontstring(addon:GetSpellIcon(field), size, size) .. " " - icon = addon:TextureToFontstring2(addon:GetSpellIcon(field), size, size, inset, inset, inset, inset) .. " " - else - icon = "" + -- CoA: render ALL primary professions the character knows into the + -- single wide Professions cell, as a row of icon+rank segments. + -- The list is precomputed in Characters.lua (field "professions") + -- and may be empty (unscanned char) -> cell renders blank. Every + -- value is guarded with "or 0" before GetColor/concat. + local professions = Characters:GetField(line, "professions") + local profText = "" + if professions then + for _, p in ipairs(professions) do + local rank = p.rank or 0 + local profIcon = "" + if p.spellID then + profIcon = addon:TextureToFontstring2(addon:GetSpellIcon(p.spellID), size, size, inset, inset, inset, inset) .. " " + end + profText = profText .. profIcon .. ns:GetColor(rank) .. rank .. "|r " + end end - field = Characters:GetField(line, "skillRank1") or 0 - _G[entry..i.."Skill1NormalText"]:SetText(icon .. ns:GetColor(field) .. field) - - -- profession 2 - field = Characters:GetField(line, "spellID2") - if field then - -- icon = addon:TextureToFontstring(addon:GetSpellIcon(field), size, size) .. " " - icon = addon:TextureToFontstring2(addon:GetSpellIcon(field), size, size, inset, inset, inset, inset) .. " " - else - icon = "" - end - field = Characters:GetField(line, "skillRank2") or 0 - _G[entry..i.."Skill2NormalText"]:SetText(icon .. ns:GetColor(field) .. field) - + _G[entry..i.."Skill1NormalText"]:SetText(profText) + + local field -- cooking -- icon = addon:TextureToFontstring(addon:GetSpellIcon(2550), size, size) .. " " icon = addon:TextureToFontstring2(addon:GetSpellIcon(2550), size, size, inset, inset, inset, inset) .. " " @@ -193,20 +188,6 @@ function ns:Update() end _G[entry..i.."RidingNormalText"]:SetText(icon .. ns:GetColor(field, 300) .. field) - - -- CoA custom professions: Woodcutting (spell 13977860) + Woodworking (spell 1005008). - -- Ranks are read live from DataStore_Skills' name-based getters (not from a - -- precomputed Characters field) so this stays self-contained. The getters return - -- 0 on non-CoA chars or chars not yet scanned; still guarded with "or 0" before - -- GetColor/concat. DataStore methods may be absent if DataStore_Skills is an older - -- build, so guard each call with an existence check. - field = (DS.GetWoodcuttingRank and (DS:GetWoodcuttingRank(character)) or 0) or 0 - icon = addon:TextureToFontstring2(addon:GetSpellIcon(13977860), size, size, inset, inset, inset, inset) .. " " - _G[entry..i.."WoodcuttingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) - - field = (DS.GetWoodworkingRank and (DS:GetWoodworkingRank(character)) or 0) or 0 - icon = addon:TextureToFontstring2(addon:GetSpellIcon(1005008), size, size, inset, inset, inset, inset) .. " " - _G[entry..i.."WoodworkingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) elseif (lineType == INFO_TOTAL_LINE) then _G[entry..i.."Collapse"]:Hide() _G[entry..i.."Name"]:SetWidth(200) @@ -215,13 +196,10 @@ function ns:Update() _G[entry..i.."NameNormalText"]:SetText(L["Totals"]) _G[entry..i.."Level"]:SetText(Characters:GetField(line, "level")) _G[entry..i.."Skill1NormalText"]:SetText("") - _G[entry..i.."Skill2NormalText"]:SetText("") _G[entry..i.."CookingNormalText"]:SetText("") _G[entry..i.."FirstAidNormalText"]:SetText("") _G[entry..i.."FishingNormalText"]:SetText("") _G[entry..i.."RidingNormalText"]:SetText("") - _G[entry..i.."WoodcuttingNormalText"]:SetText("") - _G[entry..i.."WoodworkingNormalText"]:SetText("") end _G[ entry..i ]:SetID(line) _G[ entry..i ]:Show() @@ -250,12 +228,46 @@ function ns:OnEnter(frame) local id = frame:GetID() local skillName, rank, suggestion - + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + -- CoA: id 1 is now the combined "Professions" cell -> list every known primary + -- profession with rank/max and recipe counts in a single tooltip. if id == 1 then - skillName = Characters:GetField(line, "skillName1") - elseif id == 2 then - skillName = Characters:GetField(line, "skillName2") - elseif id == 3 then + local professions = Characters:GetField(line, "professions") + AltoTooltip:ClearLines() + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT") + AltoTooltip:AddLine(L["Professions"] or "Professions", 1, 1, 1) + if not professions or #professions == 0 then + AltoTooltip:AddLine(L["No data"]) + AltoTooltip:Show() + return + end + for _, p in ipairs(professions) do + local pName = p.name + local curRank, maxRank = DS:GetSkillInfo(character, pName) + curRank, maxRank = curRank or 0, maxRank or 0 + local rankText = ns:GetColor(curRank) .. curRank .. "/" .. maxRank + local recipeText = "" + local prof = DS:GetProfession(character, pName) + if prof and DS:GetNumCraftLines(prof) > 0 then + local orange, yellow, green, grey = DS:GetNumRecipesByColor(prof) + recipeText = WHITE .. " (" .. (orange + yellow + green + grey) .. " " .. TRADESKILL_SERVICE_LEARN .. ")" + end + -- localized display name where possible + local displayName = pName + local spellID = DS:GetProfessionSpellID(pName) + if spellID then + displayName = GetSpellInfo(spellID) or pName + end + AltoTooltip:AddDoubleLine(WHITE .. displayName, rankText .. recipeText) + end + AltoTooltip:Show() + return + end + + if id == 3 then skillName = GetSpellInfo(2550) -- cooking elseif id == 4 then skillName = GetSpellInfo(3273) -- First Aid @@ -263,22 +275,13 @@ function ns:OnEnter(frame) skillName = GetSpellInfo(24303) -- Fishing elseif id == 6 then skillName = L["Riding"] - elseif id == 8 then - skillName = GetSpellInfo(13977860) or "Woodcutting" -- CoA custom: Woodcutting - elseif id == 9 then - skillName = GetSpellInfo(1005008) or "Woodworking" -- CoA custom: Woodworking end - local DS = DataStore - local character = DS:GetCharacter(Characters:GetInfo(line)) local curRank, maxRank = DS:GetSkillInfo(character, skillName) curRank, maxRank = curRank or 0, maxRank or 0 -- CoA: getter returns no value for skills DataStore_Skills hasn't scanned local profession = DS:GetProfession(character, skillName) - if (id == 8) or (id == 9) then -- CoA custom professions: show rank + recipe summary like the primary professions - rank = ns:GetColor(curRank) .. curRank .. "/" .. maxRank - suggestion = addon:GetSuggestion(skillName, curRank) - elseif (id >= 1) and (id <= 6) then + if (id >= 3) and (id <= 6) then if id == 6 then -- riding rank = ns:GetColor(curRank, 300) .. curRank .. "/" .. maxRank else @@ -303,7 +306,7 @@ function ns:OnEnter(frame) AltoTooltip:AddLine(skillName,1,1,1); AltoTooltip:AddLine(GREEN..rank,1,1,1); - if (id <= 4) or (id == 9) then -- crafting skills (incl. CoA Woodworking, id 9); skips fishing/riding/Woodcutting + if (id == 3) or (id == 4) then -- crafting secondary skills (Cooking, First Aid); skips fishing/riding if skillName ~= GetSpellInfo(13614) and skillName ~= GetSpellInfo(8613) then -- no display for herbalism & skinning AltoTooltip:AddLine(" "); @@ -381,17 +384,17 @@ function ns:OnClick(frame, button) local skillName if id == 1 then - skillName = Characters:GetField(line, "skillName1") - elseif id == 2 then - skillName = Characters:GetField(line, "skillName2") + -- CoA: id 1 is the combined Professions cell. A single click can't pick one + -- of several professions, so default to the first known primary profession + -- (opens its recipes / supplies its trade link on shift-click). + local professions = Characters:GetField(line, "professions") + if professions and professions[1] then + skillName = professions[1].name + end elseif id == 3 then skillName = GetSpellInfo(2550) -- cooking elseif id == 4 then skillName = GetSpellInfo(3273) -- First Aid - elseif id == 8 then - skillName = GetSpellInfo(13977860) or "Woodcutting" -- CoA custom (gathering, no recipes) - elseif id == 9 then - skillName = GetSpellInfo(1005008) or "Woodworking" -- CoA custom (crafting) end local DS = DataStore @@ -431,5 +434,11 @@ local skillColors = { RECIPE_GREY, RED, ORANGE, YELLOW, GREEN } function ns:GetColor(rank, skillCap) rank = rank or 0 -- CoA: skill fields are nil for chars DataStore_Characters hasn't scanned skillCap = skillCap or 450 - return skillColors[ floor(rank / (skillCap/4)) + 1 ] + -- CoA: custom professions can exceed skillCap (e.g. ranks > 450), which would + -- push the index past the 5-colour table and return nil -> crash on concat. + -- Clamp into [1, #skillColors]. + local index = floor(rank / (skillCap / 4)) + 1 + if index < 1 then index = 1 end + if index > #skillColors then index = #skillColors end + return skillColors[index] end diff --git a/Altoholic/Frames/Skills.xml b/Altoholic/Frames/Skills.xml index 34a5186..9d62dea 100644 --- a/Altoholic/Frames/Skills.xml +++ b/Altoholic/Frames/Skills.xml @@ -108,7 +108,14 @@ + - - - diff --git a/Altoholic/Frames/TabSummary.lua b/Altoholic/Frames/TabSummary.lua index 866c078..4fff08f 100644 --- a/Altoholic/Frames/TabSummary.lua +++ b/Altoholic/Frames/TabSummary.lua @@ -160,8 +160,11 @@ function ns:SetMode(mode) elseif currentMode == 3 then Columns:Add(NAME, 100, function(self) addon.Characters:Sort(self, "GetCharacterName") end) Columns:Add(LEVEL, 60, function(self) addon.Characters:Sort(self, "GetCharacterLevel") end) - Columns:Add(L["Prof. 1"], 65, function(self) addon.Characters:Sort(self, "skillName1") end) - Columns:Add(L["Prof. 2"], 65, function(self) addon.Characters:Sort(self, "skillName2") end) + -- CoA: a character can know ALL professions at once, so the old fixed + -- Prof. 1 / Prof. 2 columns are replaced by one wide "Professions" column + -- that lists every known primary profession (incl. the customs Woodcutting + -- and Woodworking). Width matches the widened Skill1 cell in Skills.xml. + Columns:Add(L["Professions"] or "Professions", 325, function(self) addon.Characters:Sort(self, "GetCharacterName") end) title = GetSpellInfo(2550) -- cooking Columns:Add(title, 65, function(self) addon.Characters:Sort(self, "GetCookingRank") end) title = GetSpellInfo(3273) -- First Aid diff --git a/Altoholic/images/coa-classes.blp b/Altoholic/images/coa-classes.blp new file mode 100644 index 0000000000000000000000000000000000000000..7d408b770ff142eda92a0a8d31f923a2ef473705 GIT binary patch literal 175956 zcmeFZeOwdgwl;hxfKH&)aktday?32KB1vcpX`2GJ)(n0Wu%03^B*vI8)bdf=2+|@5 z2|-j;T3e0UZqxvxFc|4qs;wdjqGF47w+5^SA%X&865|a72=f2ju*0t6U|7P-w9E1=TA&&2dZ`KH|C8j$D^<@e^1w?%axNlIEwC=2=AmoE?rS6UxHVc&I3t7nTBA#ZPI#|1nj{#o{jqvsvzTG}W2>WS zZZlgQ-5-l+hVi3Hgud$;`VhuJEW3Zs9no3bd)pqAO=6*i;#v8k&{}Nb(W5$jDTy>@30<;- z!f1s{qTg!3;5Ox3a4v#*kX7Rd^UX&aUys3cj|}iFIL)$A{-KX8Q;O*fPj5G)FcFD0 zaArPd<8w*hecm9g;vb#U%&tnBE23G3yC7)>Nl%QR8*!~Ttu1i*k$PFPQ4_3{Z$bf!K%*FbR4Y{`@<`cJrM+V0)c zkT;&l(ixL$)^Jg0MRTLhYakpltCRYfGAcA`HDN^2<1U>J?LopKeQpYhMR?k!uTP+8 zM9|~KSxAX+M?mN5cB~Xz&MmE}3q6h12T3GlrFB#3zVEo3vfrLcD|*LPZ>T{hzw9_v zzQlmil*aU3jy7BnTv0w{1Boe(I`fFTntyUYLjN$q6?qmK>5ANqqIyns-JQbnlqfOF zCU4VYM_&l!e!Md%ogT5FA1hDupS_Ybe4nl1e{;Fq4RiZn8ck;ixIeV@y>x`p?gAHq zABy85v+i7+9Av>AuxRy-^%;cIDY@J+zK zq)qt@!qk&mbY`v(|5mG3hp?~x&4^n<@v{PXQ=Z`Q11KyYKoD{O`z|26F{sZH2M7&G#ViDMh%5)(T*o~l?GXRE6& z|Lg*j!UA4iuBC8stMSsvQW85*&%BVSzfKfr(iC$Mi2|bpk_2on%&+5y0KI+@7@V>m zFYZHFfMEGI9sH0GSw->auC>g>R&M2)qdQ%!;={s|&#Yw`RuN~tl>z=!Khop;A)JMoNY-BiJnN1$VPBsQ}`uSCSdwqR< zD?c9f!Uw4x)p(GT_M$;9rnN+|222Nt;RysJg+(>8b^&R@>rC!u0Xe{rj1)5hvJ}^u zkvVD9fE6vO;H}sS{^qxi@EM|3e%45XBxr*iYbXzn_`dL*3j6?ie%s7=14qzuUCqgbP>+I%G}cI@|?H;H3p zg0^q^9CVDtF8Az=0Q?hQpEw)@R%pu7xxixSIV$xH>;U$#Fugy6cK{POoX!I~4u#IB z=}4r0z{CY37Qbk_0sM_3P0e1%=`_ufpDM%2@{+2WBe_B8!tn`HPcHa5c^r8V=U-56+f1f>_a%*eQ{6xT3y@Xi0)xSLC2 zg7($xeo8msJTJ>Wwc>5*r5u_*Bo#=NY6Y`NdOezDn{B7%o1|if4V<|c$r+}u_<%7! z7Q(u-bh9CuWf|IFG$>&i(D6n}`QCYRUO&Y51{nRq5{x2bOlY5R@h{hmZ5IRoavnREf5$Xw8 z$j#3m|D%GtiBnu$oPU!Oz%iNf@_qOp8@ucB;Xh;8@KWVsT_!?0}GIXeiciABd*uJj#dvVr?JW7JD5V$;x_`xLYgD z%uP}5vX@C~L#%o0&b0AcmEA?z20hmK`#1K)Oo6DwU{v}8j?8AWJRWfnlVvPu+8d7O zkO2GZ7ss}h)I}Bbd6wE+FMDqOYtzx4y%QPv>n|MLDP-x}doS$TcAjn49Np$j&sU#w z<*$7!p2@m$`I)uhC`X+}ci;k~=)RHObYTXfoq}6`KA9jA2|uJ{@6@AT+2x8iLj_2= zOHlFUted!(y_L)*Pw|(pTQ@si+RAqdf*4C&yi_ER$P9*Rs$9}E``TbwR=HsBoL0|V zj80SP2Kc_jHIV1SKf{Q5gN6RcWa^t9E*f;Cg5QZ8C9xi*;r!_W4w@Kyc>A1zz^C__ zOux1JiGU6A?i{#P>TG^jKH6T5r>Rrsk`VV>vS^xuxbL*m^y)&0Gm75dVmvG2#9!SU z`4(_*t7~w4%SP@P+jBB%nrG41Eyl4rrRRym6*ad;pYF}xdaQ1|@WaCqstYG7dtbgY zxL6W3Vajn*c+algF|nRAiG(@6;6;Z4S8DT$zU*uxDuRP+f9`xEWp~2JhX^8wEX3Lc zaXMkq4~IWTdr0C`c|}CYCDQ1$T0?AJ3RkD5rV+o)N0}ERVqA~r5+PP6?efMarz(?e zoO@wJ@ui)wxNaU00uM>k)gMIQ?vA$XA(M|}W#pqV3RQFrJS374VXtqfLkURum=_2U z_UK4skPrU@{r#=&_yNobV^!$&9sE6e_RKvUhH-)e1o5X!u~fBMdD7E{XSNGMqPMLS z)l}6Vcr*LFYIt0uJ+CTHL3I;pk1b=O&#N+%7=~qib_DSMuy>=h9C-1%3!bKF1?SPH zU0qH2t--sdor&I1T#%9Re?xx+`Pd&j7si+3A8$WA<(>FLQms~HJQue~YS)@PKHQtt zW5XyxAe98V>CJkiq-nPp*{&zBTt6#np%Q2xm2`#0(hL%Z$Wi$%e&$e(cV9y$j{+i}HJ?WWKbX zId2f@XYd|Put|G|V#nXId15mwy0JI2cn5X;o+w8iZfTo4fv z(+xa8p1kXbkN+p%baW#d%J?ZKdjxGKiC6ah-sZYbWLibGN*E3(l;|Z>^?57vNKjp5wFzt*H0(0z{k9TIk_`l)*op^+N=W!$+@t^OeX?qgF z&4?$9UUEoED>TD5<5o#&t!a2w-1X>*kvf|o?sTlGV8pgyahp5{62*X}rLm~n#Kdnt z9m@@x-N)Hu&;@E-PL3^JY0hI!i(ZxEUM=0eTL3th1=pIU!}?My(|0^gU?Mnf-}Ftq zu`$Dv*A)f~rdc*yYe2G!{=56Sx6e?}&Y*ppev7nPo6Q+7UiN=|dT-j(0zIKlNk1PO zAm;}NtaL%Z9WLZ!>z?wjMhJOpyzba_LgsKd%Jk1KIs9n-`qc&c=$KbdoVZ(JkeV{g z=t+x#bkp6K`;>u%^q*<`bX6Qv*I)2v`FxR&mw&Ia;HLf4Co?Gq{P#x>ywAK-kI4i9 z!AG|(S!Qnv!uYj!RfikvBbVAMQd)n%zw(R13o7HPxK~#nPEa+}aO_c)RHFIVt~%yY zgH+SVaJSva!su}ZznJTw zPmR_P)@O)vsxKXT^z?4Jby++{@7hWK?$L4VjZ=azvxL>8F}BFxxj|_1UACdPHa?ej zc4M;!AfTJrfutJ#gjFEeJT!L}@Os{cKK(oEOvM>k5<+C=8LNNm+uco9E{Ur`(FIAzwv~hXiBMx?#S^IooFi34lb_d z7v$tzo}AQ57!3vaPYqTRg0foo-cbq@2m%5YZzHfv_aAuf-7sKBV`7ee>D1%NcXVo$ zjIiFE+;rgoLI$RRu#w7&h;J^FLf1on_#__jOFR|=3lB|967Cjr%XJe0eAJVwlCzWL zx)z?mH9-Oo?5-s4r4t$;3PVdv@x-$;|789=AhaStAdsIcNv3jD8sGuRPHSx^v4<3@ zAwZxEQn(ua;KTpJhY!6z9bosaeU(GGlX$-GZ4{A67W2w0dp$LeBh!ud`JF{=fJy;U9R5FYk9EIl}*7onk_cFmOYz(G*~8oHE%vN%N(yG56>>YE_&< zQ#>x9HpK--9&f&$uz=!5Ha7(#(M&zBIO zI_(_iIvUByu)PL+fY#3~8i=hHLi*bPJU-e~M6*8p`|<;Hhj( z*>W*yulGTht#^1;2|{75R*X^IDhkPm3BvS&{Y^KVuMMx`!MfAj3K&xZU+ z-o!Mj-}}QvdYsF(=nPUlZqUd&O4xqjGqj|pD=ZGO$l>`ztppwAa?V2~XJ_(ky9_U` z!tGJ7z8W7Ik2!ZgGwqY1YhgfBWsle~_Uvqlb>xg~p=SO1^_E#Th_0ST>`KvmvJTd( zW&KK#TPAb<%Fg_T!{z!7d*loAVT4@p>3(k6AFPFcv%KPi*wN}($m9GzWg`sPtLMK_ zG>Wj+*0z$3(h~fYD?k6XC8>=leDC5%lT)gQV2Ry6DW#hK`jl4PP+|$bQx;G@w0J#;wgPzf%P+tDboBav#QmaC3#Lvsw4IgKU}4IR-W)c?P>~)6xeVH83y7Jtn-o8zuMFElymbKtD72$hc z8|rFeS(AF&!FuN6><8?dty%ibuXl$T_9sSc^1i`!@AMVqZ zJ8M}_9}Y04)8 zDagQDfwYa^a_k$={J1uJ9C*K9hCd1JR5HUjz^Cn&{F7%G1nC)X{e|wzm5biG_?dmw z0C6nm$!tayX!|uSdK)igPUFS5cC!bTI`X`-qV9Q=p!rODfoG)P$>)VlC)oUxHUN?HuPZNZ-j@ICGq@~V$Hte0?x~Qa8BJ+L$kBe@A z&L15e`OxO`|^7@JpBwm8XOlgLwK?do|xpE56R&O5x{Oud|mW@bch* zh*yUO2*~TwZmIl9yImrgoTA5hoh0igkYiAVuGGf1aSP?g~M#T6g* zdMtPa3?@a6Icf!hz+62(bLL>$%^V6-rY+YJI)eY_f~@WqXYvJ zo148uaR;S=f#N7tF#-Bn-%)lNN1plFOkVSQoAFZY`DfU(yjg4BdU=m}^q{n^s^UPZ z{YY+$E`I{<*nc`^7C^m(mYup$j&OHgYVY*jZ3OL|as$pAwZtzhBnZ&hAW+ym(x3Mq=0_O(ul&a^-w3YZres-kncAc;z`8P_CQNK)B`~HnY;|@ zx3uEPO(_Hh`Tvvv(0RHYIVFch6{5JOW^F1e6wgd-# z&Uw-^K%}ab$?s%SxI_{a6`5Ym?@CKmzX9=I13HnJ_=zflg9wP5 z{ED)GfG3uLek~A``Ba8)CRdb)1MiVv2qXai3HlO_AMkUbz^XN&n-uZU4+hGBbC7%X zY&*4PE|#KJXpy%xmc#LDBfKjJCGhu~TjpUM72QRaJAwSD{iZxQ>n}9w3`J*_w)4|7 zZ#G=}v=;r8oRTRY;YPde-n;F?zf#>(No0_*DkvO~a*{BavRn}6!B4R4+fz#sl>Z!) zHf-ieVAM)E=xZ3O0RQ9TBe%{K@p(tH0Y z_~FeXmk7)$a~Aa*No;j{ZA`0YSbqp{-pGVwZ*c`ljHQ6fR^d{Fkj^K?*Ype#!fSthYt*sSFVXS;Gv)@13M;0Rf74a?<|# z#uImd2Pic8`8n^@L>tRvw8u3ipj&Eg<-DWU`GIaQ^&L#5+hRNltr!s>pTu{POv zhsRan83w)*a76J9I2S`)ilFe(TO%Vy-^@h7p9Q^Vo?idx@{(LnAM^{Kd*$7<9(D#*>?*ZiWvhuw!+t1ZY?#!b;e{D`J zJ~))9%l_VG%#BDn&NLiX*gFk>{p;SndoNrn#7^vdh@gf$IbUfBj?of|O}#+WlX(x5cI2f)3SS45!T>t+)^!MJwE*_9P)kZcXhGCc&OtS#2b8hysoVz zI5Hh-U6P2GI}1VI@9DWbIi;VF88FeHeAXq(0;1My? zrvF??VMD9lUmKA^;Uyd{ick#@8l}>R>g35@$!srj5k|ONqwNyx`36>XdhDj~JYZKsrEG|2B68xVHGUS~Y8x!!PBbGd2Mt&SW(bs<|96kK`{%J4!OM-clsF(VpYHQ0n+2+dk z1H~s5Y~QSRHA-XuzP>%MS2~LA{$;k?$=cXWpU>?zp09fbke8-b<>!Wzc);G(g6)0? z)!9lbS`#EM9fNx4-6iwm1PYUPYN|h_yyY})D>Xz5c4wEzT=%D9hVt?*4+IDgo$4QN znRs)ZfafJ1uz3nbk{m zT?cTW;WF3YN|B(nC97?x2t9&Ck?>4LeKEWl*PQc1)sPUQT^n#21XA-_5`SUEGv z0Kd%7hP-20dP9oC!mpLJTbFt^CiYL1n~O$Q#&vX-1+0X8Jvx@p|6WC4DrHYkAFIa& zKnOt(Ks`!h>xEnk|8jE9nuBozL}gtaQ%kLozHW6pB2;B@BaKb62vsfhqV?OmCHy-( zlD3G&pLSL8Q+qCTXQ&1fQ`HX?kS`GVs)BsNNXU6S$!x+!nL8Xs_L9v8rLeBSgWRX` zef*Q~a-mL{^L*o7X><6YMTFd!1GNS1y_&I8dx_15%>WRE}mYyQfigO zM5L~dT1L|&;-}W~;u)r)Y{`ZvmkIhz>`%E#N$;D*2tjME-z<2bO`JD+eRMG53!>xn^y0ufU=`5F=X6B&ex345RmdR!B>x) zU8Aqcu@Fd1M_;AT*OwQs9!O{tavPew(eJdyy6M`GJGlYU272_#Z4Cm^#m>&oH}vyG z0RaKE_VUe?#Ws=I-*Y&#R7TVCiJ--x=NB?dXU6GV$HwXwrxWZH-Cq_KZiqH1XyYVm zo{-Co)C=OuVq3IcMQtoah|T$QX*5On@?J_v@{6;wMuMh>R>)!e&HCc9y5VyR*KT_Q zx$^f#Fgu0__lx0w@V=fO_w4AVqa6*Wmwv5?RG+_8yEu{_(GDMnsN7sI@k!IXg0|KH zz5VoAsx#T)9i~1kh5jPu{(+b&Zi&@ z;(U*vNRDNh5$L`ayc`xn(P#-?^uE$i7FWXO`pu{+i<>9??&OJM5vp*}lv{nx5vmn& z6IZ|7hddD?i_ulS4oyP9%{u$y>guY_ zt2T`Co?&`0EkW(ql~s`Re2U++Pj+ zV#qNxu#;<0uAz|L?spx{_7-Z{h=p8FFvo9S#8dumNZd>KfAWVsp7SrSR`G)&5d2MZ zlN3iqOkq987Rf*u^x+hLw)_XPb{mBg*?WYnbIaqg@yja-$0-5$jp>%@eB1#KKfO~r*Bia za06?;&s-b=fkE!Y5?fjd=q-zHL^C5<1(M1DDV&DA@j!i+Jdk0Yx{xlUH6zTz!gvC7 zE2Ul-#)o!hh7^K7bp!u{K4VjnX>{K=w{WXNCMdMNLmD8l{H=5|zUYrU_-g^@}Lz+(3VGz$1r=ZT4w(FUh z=}p`XUwrlR-{p?CMd~z&^X!4RPW>NRV$kB#`K*S@fT?Mzsj0+JJ6;PqT2*!lmYkB3 z<9eWj`lT%7_Thv4@R{M^8`#L~?%tH#zqdcX4Rk^0m+h-}{*c=3ez%fQA@jMc8NFKz z-QFub*VwtzMT>6ay<16Qwbl^X-#l_$}i7@P7wS)RZBLQRP{wJGC(HOx7V$_YH5% zKXKS^_Qi9n;J~K{z1sW!&3+}q1~2VVmH_@!;5z>Kxt#UB&(T)Z5d%)=6^&IB(<*fE z$Jnw~K4z}5|7is;-Y~*2k1o8h4B8pX^7m30tZSNp&p_DyxBbA&$D%`aMtVm@i$kM3uTF)1Tzj+HWW51=1c9=roA}DUvv~ z36wuDpcc~`iPwca9~2cOs07j|ua}N2JV2lZmW|AvA7`7;(g`UBA|p$sAPKz?XevVi z{u{P1krep<(a~F5j$23Yvc%=|he_WfSyOXVQ0_b|i4lwU_RYu&?pWp-y*(iOzN26B z!w;+CE>Aotcp^7&YQ{u%&Zz1<<~Y>x@JPx+((Vkhyq7ydvB9SOFK(-gTevUS6;nH^ zT73V8`+ninbm#3a*YEGE$D=;VR!y9&$F{UmMVqj2^!slQPwG=hY|^Aj8~yEu+%I?R z_<3&bOfvP-&YhfX)i6J)X(grApzkVxm6x z?GzFPb#{Qv1RKL%YFEdKUE>XApieOzwn2_rLFvli7}1O57^MA`W3$Z z0@izShUfra$c#P;7q#()-~ zy9KqB1q+70VNy;AgM&pPDua|qMnyI1ZBzy~NYdnT>-PX$XkvmZPtECwuzVI49RiM= zV8ari?Z)bwpbE?g70A5?+zfiIZ6Y0XYpXzhpE5$k*K&-ye7N0=+$dK<_ofE;e(dmY z{uso4;n;eOh7=+`)E`X;00kiTHO=HfKh;QqB4ODE6yc@C?9w;ZUl}l69FJu$Ycde%^ z(4V~eT>6@Sp!9$Lq^(d7bkc4`MH`W-)wi#bRulJouKc~4FfLQV;2-ILJY-Ik0sHLC zGXWgXg%Mf~iT?lI!+-n@WB^oe_qr|M2cnvqzz>j!%QTqQ`UBVVx(Bkkn>Z4QAa6G4 z_HO!iNgJ*T2%gs6dkgx?LY#Ce+kB1_6xHNrhn8v(s;+1IPP~h3rqpsojfXta4%+-V_{Bx?jxk_bGKrWQyk zzEAJ+my&!`OnVLB=MUA3#d;wn?1Q9)il&6l5J52DUpN8}Kx`!sVc$jBUp>5ai^zSu z`Gxa;3zyD$GKqfo>u`~4cjlgVN(G|sj|SHNEw4PzX_ei+y6cIlDs{JW$1+L$k6(MP zevb7xci2_$3X5+zChMv zJ>Z{*@o?bM6OYIw3fs8x;9$)Gz3R))KI`MA&kue2>F1seOPY)B-+%C+73U&(ON*J< zIgeB=S-fU$didi$G#5M>pjN9?9N?{x#xU0|9YR0dqbdk?p|rfCq9VP!R{G4eWy=jm z2Kg_XW8EcPtKtQqRJU~|;Op1#n{(}f1y6xS7$0kOT0yB{39J(uU%rR>04&#yCq31V z>p#%<3VC&IXGa#ShpWLA8LAl~x+rW(V4($Pj|b-Qa_33uqW8ymh5jPi`NxI2tTw*m zXue-kVL0@sY5RS+FR}}snUvDTS2zMKgNfl%UjNARZ>aQmK?BoDC6LigqDVhVMRLa zq{F(W-AzHfXVak{z#%yo|MpZ#WJ4hL>&;UQtwBMxs(HxdeefvCUV}e%vt8EV90ch2 z@t!zi;rAp1?n}eqrDV6?fx6JHv3~QWq#==J7@-?EXGLyz_ml-EgtKU;m+R*}N5*`g zb2+n6K%QBnR?Pp7z^v}Pyp>ShSFFC_po9n=jVa;jeQ_TeNdAe|&J?&$f?&aW%i8$x z*aV%jqJ{wc(asfZQ1?{OFD&sF@i=~5h1Gy1<*5Gcd;k3Y|H=BUAJP>TE(S$KHDA>u z0)6(`t;W8|*Ab)x^hW60U$}5tQ(zfq-(S8ab&OTe1@98juRc;h%P4#wxPh;ppfF?M znsqfoJ<B+#B*v6W8rt2K56r(B4q&@$956%M`DkJhr~{uCx2~ zz5**Tr+fd&lR;B;W~BQ)iNU-N?t4X{D=;|EVp2pwUcdJJu)-<|-?Qh+HRwy6^{SMt zmX_iVAP?$?=l#TDhT&w_;QGwft7}E`P)63sh_1_kEy>MYbBccoXK&xGFdwhNWzfH_ zyIo2|z5d*OmmBmdMXGu*9_rH)iM{HoAhfM5J%{{yfSA0nPz%o+VHG8%7T=@rwQ&EI z18bAPg4*i|C*Mz1ro3$+u_|7GwW}SW7_G_l6!6G2^>TWKh=ZV@L~~%h&@mBHwr)j8 zO^sr`nKIJO<_7Qs`F2M$qu(w!yMf5I{7PmdE-Dk0{KCPWU9(8Q`I5v^ z74G(u+Z+Ua!UE*s=A#MFb@DlPcyMk${6l)b9{ftOF~eon1OHc;CKx^V8!hx}f)#$i zj%+63v(P4>?FfxW-X;l;d2t4c3S<<*B}2$;W8JHA6UE=tPI~2uGNj6hw|p`P^%uCl z3!Ulslh40&^Y)#{y(XxmWUnv9q5tmJ6(=_E{RA@m>FZ}yie6!0538%Wy)|gcOt0=U zv3N_u+b3p*u2s;rhaEFRt&*U?R*3WM?Rhl97x?5AG;cA&FZDQSihw*FaJ?`d`f@`o zw>pyuboAv{tbwyyi9(}MIbYO9I2{3HcjDWG5SL_2)*eopw*S4n+c5wCKEH=u{-=Y0 zcWEc^O0cXKcotZ%$L*%THn48@0Qf_R!%06AP=l7c1FRuRIiY@hNcT^ z@Yg5Le5LYO8-}1hE)y&e83?B=xLzQ-EObeu^p>82&1Ee*?@G;CJh%*pD;0FY8 zP((#ynnTQozBrmWMEOhIU1Nnl-2dgW(XcVjAk?*Rc{LE|>*aSt$&r>tQDr zh0cWs($u{t_TGf&Ap{jF>&4Kzz!AF8`e7&omG#f|?hyOzQtQ-b;V}#PQEel*=Czo}X$irs)?KW+0`TWh=-b%JeoZPSjheUbKkdT%Mj#LHx_j1aD8*-Ey-+u4BH<~vWCaJkr z5aN68SHp;fe;y(+s!ZnWP(eI|ejfw8pXThn?ECvsjY8qWJ+x0g#=je^&wq&Fz5ml7 z;d@ZVD)RAA5cD3eGvD`D;LvyExZPP|rV<(&xD6%S_4%}y3#?yn21^6(^Pz2tmG1!y z_sjK2zF7vsM9WWHd|FrP{gPj*g>SFOU~OIwURGAoso%^o*4O)a^_wZ<__&P*Kax>A zQAdMc(P>%4>W%tj6N4CihCW$44pyg6_~6}^tXkjsIjz?7z@yp>hOG3*=Sw@^m};}#a3bG5_XG4QPA4t4?nh$M)${O6+4z3B=2M3~S%ELcf(4G+wZ!70s8pMmb zV*&);K~;nJTmhe*m;Oq35q*`leYQRy9!%^>#{^bo%ajMAty|2cHwlB~0_G85N}HnzEJ`915Sg}EheQ(D z@-d-z!@_WVDqrJ!?!Dz>SAuqY*arKFR!lHvSAtGR7mu{SZvMj{;1%qSmV*Vn(x>h} zJ}=3sTVNfQx~lJN!g3pfPTi_1q3K3T)t6?NS99^TPl;HC*+zqv(-Y&gPuZkhh_M-c z-&dLu@|~%#l>Hxv?_DoDXAU8Rx`*lRF`spNnL5Y|`EGZ8q)tf?_6BjF;Zu1s#D%D2 zmi!pX;Y#XSZBsDIfvDq*`kf`uLw~sV zOON?s>Y=*eI|sBi80(Wv99IHEexWvdhQaRmh$4Hai2>W0Vi z&BTN2aK>^iOA+9{hF6bMke|r{zI@1ODX~qk=YOMcg;L(qmaGFlPnU2+1U#N6+07B@ za7n~B-G(@hC@4x&+nQ*IYXp5|hM|fNaUcnfi^3=KIA$FBJlF=V4kr-H*vuRQfuL+2 z%rR6grV%``*Klg_>dxTO0Skd?lOo9b)!0{ zlS#Nri03rK<}~;Vtu>>qT{dY^=IvouE}BJqonw|RIh-#$<)3#0&f2&BoTq&2skS4% z1av;Tz2n-3tvbB@=8o6=519Gcs-9gR-XRj*-g{%e4PM&G zRoYfiu(>woC3W_#U%NOA+A6*m?G53cx_jSCzx3ma8gqf> z?u-8-*4QRaE?RgOW0-;%IDg1HfPX)(=h03Bl;7Y!D0GC+HU;U{5SWkGqiWDy3knKa z?)lz#3ebQY?sJd}J%a1i>bBa-3FL0F+iWFhvBMr2NL1TOn(UE5^6yY}UQ<+%uC?W3 z?RXuMx9Zj@Oe40IPtj7aExtJbnWWw~PoPfDHG_Yl^YTK>9ve=}c*w;Px0kC6Zn;?U zXS%34sANK((FhH6CAUztOXKvSdPFEB{fd^&u?U2OLR`> zoGFv;pW05ln}c?+EiJ)~EIa&b=})O2n2O47S^DQR9}oJNHS{aGWdRO$@D}htR~LKw zE<(emM{LPmluyg{vZQNYutBXJMJ{Ex)%^tr0P4sz%l3q?wY z#|p-g6k&D4`D!h@!Yt_2tLBYe_+4KIJe)7QxflZPdCzidYxF1@?RPH0+n_A`r4MBdQPY0N$ao zv4sEhkP;^L7f^w$+S3*^#UKn6<^q1Qn;YI8Rwp6;96; z4|l5|*st}9hl~SxdU>zM;kbKm!0>I?68rcT0j>5dsm(6jV$JVb>ln|9V#a%aul&4x z=DuDw|H6EkEN0u_ysVOn@3Udu!OD9)pzi(neExgZ_kA-#obW^~cg>J{#ERaKHQN;n0rTZuhj8)`Ugg zynUOEd{bOjVZUK|bLp#9RW*LEzbSnY5if&3$a}GFPqHhusOZ@_)0<6({a;KS8qCOf z`6VY=0}G*HS$CKb`h{Nx+}CB~7kvI=6kMcPS2gq_GIa||b=@1M2Djvc>f(#z5ND%- z4>@Tk2mE|0I0X3`h|du3Y#+-r>l?P1&Fkb?KInV8TcFb<>h-WQ>~S#lBH$BFnz%1t z1Laz!>to%TCP@&NV9;k0NpO(uC;6Aq)g(dp%s^$O2|^C#$~5$M#P7bHqn4KgpZoXq1mAqZ zjtHOsfXB!OK!0|$+a45jDqo%~^B#}nw%Uvp6_TiXY{?ZUj|aWQ*7PgVlr2U!?3N=qSn@GT zjwl{M%wlcVpgsOPpY^|YcOWrwFWdf`c6YGfYb?>?r&B9xTTCyUWT+%xNbl0|$g$E+dKx<7e1bQjtr>B)bbxhrmVI63?? zcLDzTGs9)W;}d<_Gj|CL+R=Y3yL-S^RRcr|ZE%4O9Wwb3lCSCDl_cDh!#Y$OEtDJ+ zZ(ZHjzgUl#l{YZea9l3aXy-hB{(qq68c~JAb6Rz6mMVUL+vyB57%0MSZ>q_uPMrSm zR^yGD68>hxPtPz{PZ5QdIwr>hx=}DU@bkfh1IIiM)EC+_5BMDKkL~r)@5j;?o6bMB zN1AROHjkJTiyX`W+X$=8ZmKH{WU`74z1LL=bxQ6(__;#i!+#(59 zc|88Rxc7a@jId2opS=ow3BZ#pjKiAFFa=q1z+FM zpiPDM&*NSI+-sLT9AH8dLqTUb`7dEiXp_TXoxkK49^2eJ=UVnovF3k~_C9b;m3{yC zwN3JDv^;i4&g#xHbn-6(y_HXubLt(;b34iH5U zDQjsKGQdBf`R6tVWCR0L2vba*Lu5O@&!N2U`?;Uz`#jJ6{I1taFSeaO*SXI1`TzcW zE+DL0x-Jt@MFRZUCM%tzu^Am)zwQM|H}a> zV~nRhUho~B8(^cH1I6PVa+$;4%V-RV5Gjb`M`ooa+X;?t94?u42E0!j_@zOAchuR+ z$wNrzu-QU6xlQHv!(t_Ia9<8u?~wTFjEoEd9@^n@dAJ_PS4()%rX>p(uBH#64;*#1 zBIYzv<#5!Boc(lT9r#u02hM)r3%<+)=WTF{8kugVnsN3S;dH2fk(z1+?GfNaawp6G zJbmz9r_M_=)fL;@NH0?J&2}0!Ajz~7DT}NdL8k-)=jIV^`$z9^{Qg;`0{shRQ)g4S z=V~sNJH|uZfExueIUV!X(*P%)b!9a%FJPQ@Y49FGLiJpCadIExFTTV)DN!5dD=-;| zdBCs4J(o+3;FtE%pXL?%YzYcl#g^>{EeQRM{l%rUW9T9)y(1U%(buf`b3|Tv#>?jQ zue-cHr-Svm1KKm+%bLHV4Qhj;jrc5x&CI?yOdPRTDi+)rCg#OEEPkJ}=&}{!lAK(& z4i082fbJ2*C5~5+MPLYt_EZrI z46|y_n|W5R%8|V1m8`1zY^QSIUH$yC#WLK6WNCt+y&yLz7Y^3{Mt09TK#X{f5Dw6ccNjZJ2drkru=YG)fr(K(Z z2hx`Ge!lr|d{AmuZzEB~_fq#;2qX%$igQ3OnEi6K>;bx2G0K6GCa(*Fd_2bW~=~!=;rJj z+_=M-!`DGSuS3dZ`=D3FO&%YL68fvE=z1|KEA*MptjwF*-=Ava>~;qffFN{q;2O4G z+Spg+`er@kJJrf>rHhh%^jO_7U=kjTtPc>oK3PT|cUUq3R-} zQ=FAESD6%2?3u}<3nzX^Vq@kf#l{cw!U1LJv(BUZ$dPAMh25ER!3p|K@^69*({ow& z`h670>G=gtgiV+2SU+b_X$THxq9!^CY}#nCa8#fF#;V}p=!xGEs2vU-WBc}HhbUAYdTzBkh16pu)7WEt5=VevfXvxEk}fll(%7 zKjOSi6IPRtoOz$bxcX@@6C;h3@a_VvbSux(z)Thw9%~qus>L9f6~kzry8Y56yA|X< zv_B62&mBkazyP@Ug~uJSE4hORw5krCkK{|A=nPbwe3*H7XduD&A!#BoPDA&T^9Vu) z>0~?;==(N{<*c`{R9Hh%O&1lV+n#NuDjt|VKYX}C_yOD94=}wk!|ZG9k>TN-(ybq{ z1&Ua;myPkP@0h&>D5Wh%(<1Y@ofqVVPUHJmkUb6@br*+`kyox!NsTccelQ~MuyZQK zU?`NI7PCS~n2>_@$k@AYG-cAb2jqT}8S2pipF4dYNgxhhJhzSi8StN3bK0b^7}V3| z^dU?ncc{4@ITI+J5lPHKv4gi25estqI|XeB;|UM5f?EjkVO!R~1RxdgBV{Uyov4ue zDIniBUD>#?Q2}~ab=rio2>q1BT_%AU_<$Guvx*>e0>mui{8kzSZjv~iLK-9nysbVJ zP*s_kGxs}a$%#V$z>t=PKy}>OHJi>7c%I2rI5&%d_~$J{LllAYIluijQW6I5A*nAwV85 z{c_7&N%~Je(GRv*B_(Y!MzF^d49X(UwbW7~EiJiiNpHmzz&Z0-Hg!*IY|Ii)UQ}P7 z513?xWW|N$Pk~fd>!XkA@$AFkQKFXgnlYI`Ff9W7nZO=OK0QA-NF|4y#>4MG(hxe# zu3fV<7Y)WX-1g#zSH=cz-%)$4R*zx~iIf=wy&+M3A1?B{UICxE zE1Hh+UxaW6MV#6Qc{Ntwlzlarc4=a}>6j1b2|jYN^&Cc<1vEME*jRWU>c5WNi-{O( zeA?JI;cO;%^0Fwzc2bJ;iSOdGCpaj2U;0x#F-7V2y@GM^$UXQdtl}UzSny>yqzTqn z;Gu|yX0M$boROr{k=JRW;5@0Y-jO1npixiXF-0LU4>5Pi>tMEvq#pbA#6;sQ`(5;t zimetg9=mCah))xsuTq!piml}&;KQg~E7VD?Bm`os*M0})!A^RtcT#ErPvMc`{J?43 z?RR-7VA>PyL=S;I`NR|Ztc?&SjEhrqbHFv;FfA$YDJUqt-jFPk#iyHw6>3=k_zmVM z?wFtfCI5{N?f0Yq=l>6uaQcA5&*(12n}tKP?^_B?xk8h$_F07GxhQIMFv9GE5U))p zNPy#pHEbkln@m<``n+rF(z-fXX@jCv3;>KbSn0(Yh+ns|f!;6z2|i%2eGYIKW{0<{ zQYb8hJiJ%?^+$anhM+&nW9YUOE~$}@ZU6GQ2Z%nCuAvZpqa8*|T3C9cOn69gn;q=} zf;Uuq{Es4Lu(jH2lEkN~e;(@~aan^}H8Hv@!t?e1@2&>~se? z+Mng%8C$CIlONHG$91ZZgw|jD7I3NIj?CoTI>>LxZS}cY$Cg0~5ko0Ze=LH+CyOdZ z=->7uXYW!Dz9LdFRS>ej&iS@3lEa^uo_Y?oLmaPa$t&2i;1JVwzAlW3SxPytP32{z zEWi5b*h#4Uc44u-6GPMxBS5DDP~&^D?Wle^$5+NRWM2?cT1{N(5~%kC3S>SG*tKBa zngTothkC8S1^8qoB%Z?W0Pv|HL0-MfHNXa;Df2GsQlOSK0mi9J; zgBm5bdl3$}JB=0ePYnzRw4jTeLPh*QV2c*5Ui5H%mfj)o0?_|UhiOB7>q>?4r_$1y z(`Jv?T}Lz8+cg^A#{`0OD9yv;|6e@;KfrC)d<*>CVUeAEY!`u;oADH&LQxF0bm>2x zhcWPhgo+Hdny@j-Qi%V$WMcl&hOIS)*Jn0+be}t156neg^JSZ@hJT+8aB=xX_t~@e z<|QY_d)TC-fcF<%W(C!76+_WI=hl~M&nS~GN|Rq-q@twszzy#54i*_@h26tnu%)Hb ze8h#T*f~AM#8yW^kLl~{Lz?xRJ+965TuS=Tgf}f;vl3>X8-F$rD3|kJ^0$H}iiOk& zKH@X{s>)KqM}n;g3iOS#^VG`d)Ks1tNy5b7aiCF5HNeGq5au6KEjkUFEP^zi|D-R? z{nCV|Cu+4iJr8(Rr|i`e0wo2GYmN`7yzG@8MOg%;%Dr9|VV=@?6tFU&A83L8l?jR| zb2kLc?mN&G4raE{_uL$PYi?R>--+^tzg)jkD$09m)Y!^ghtS(gU|#C7q4k=Ha8w^Tde4IJ=>YU#wVyw2FvKKG z55=A$Dy@mzsYU|Xwe^2mZkB8~OC@~s3c^)3L0;#IQ9??@FYjFO9j`9@*R+pLLjAGP zrm_zAlp5i%L;kZ{0e(S)#y*o59268Jv@eoIUcFi)c7DatdwTk5$ubPWZNmsJz`#yp z&yVds$Jqnc-g!u+=@vVC--4>lI|j+a$0I+2677n^Zz7*a!x8emc^GB$wK~u1BgMh> zEOQ?C03;^n<8v@RUnKe-&&NZ-0YUEwM$OR3I|QaXTTsB;IkN67Iv0WY*c>9BmzE&2 z(m-Hk-wI(((mDb;AdW|VK`!Rvdpei1%;BjGj`T9$KwW2s=VCrlkNyueUGSrCxeZmho46!tUaWug`f{(ApVkfaTN2LjqZ=b~bNU2aPq714J*j08etxrO zSDxTSjNX1ZB={UZLNa-INhQeC%28ZuenDTVQ^YxjTg3aAgFx_1fGbSc5 zc4s0#ttZgfDB?Hj%OyoOR7S-%figEYp`kmSTXzn>Ca42q>P}WiCK2EVNLh08o;@7= z{LKT`q_G^`PZ^+7I>-4Ge#yQYVQ62wbY5&ZaY3!t9N4o@&jkOlZe_`G{pIwSoMY~{ zYdjhHg~oI9W{SkV;Xk(6YO1`Vi%)k_75bxW$&%jH`Ndxy4J;Y>K5u@J8J*38k{)a= z|JDIB-kBSnxzk-Rg()kSdf7Qakbh&?am_4|HdB_5p*~rHBeY6&Og1*lHSSXSi5|iO z%jq|;SE|6$Khj~w({da_wznL&QJEXt<|@&*-QscCxk)JFr%#@7-+O(V>YjJl19$~d zV|v@F5}o95O|?iGIYR$I=4GYx!JG~yPZgo`biH!b%y;qlxR})-x4C^91{Jk)q5fr! zn0zl7`S^l}-pgBVAIjA#*FX)!O0QP8hKS=28X1@G>w#S>vAXLCIze3$d#y)I4s?8a6(q+yWMx)b-er5<6 z;HHQV!CruT5&HuIuc#@Op*tkt&f??2YlNs91r-Q4ou+9kp}X#+3kyxJXZ{9_>8%UtjxQe0DCfAY+vLr3?dPQJ@F9kTcZh_|x#zZo^{9Zi=_4Q6MurlFy9 zYu~L~ISqsq4R+Vq=r4F^!Pyf9+|%ua_RmiVfhQOs zkHk9C;~tfj;kd&lDiO2?;CI0A9$u$m6Gvy1gZV~*B_wF#8YEH-iOLe25+bAT-@jkV z(SH@-fAm>N(O`~J(#?_4s>~X>b=#;Q@OyhFW+QzywzNmuh~N(rHl%)#sAM^uSwwM@%#!fa3QllJD}+8Y9< z)Ye0YExDVT@<>cx(43}MLSFy$6YHAKg50o$7QJ;2_Fyq4Iv%h@6tLOmyX-ziI?#Qd zU_I)1iWk`x1nGx0{u=3gU*Axh zwRh6v^XG3F6Ce#hH})5ft^hqCVaQ0+hv#CTAIlYM8s-DN$MII0=3D!Qw7fXfM~XqmT<<>LJ}*=sCg zx9gMGtE?Xg#7GtaA28D74|EDg|5k`&O_=cPvjj$d&x1x__Uk})hz36ZnE$b#4gg;O zg`jla%wAZlynRiCX=t!*sq_#r@5_>scEuqS4)%)vmtY;SU_n&W!}a{H{ohy}?(i#! zdY>gm@W&+fyS?$R$NlSP>H7-0CN#{~|ER9i@pW}b$UXl?xy4~Iuy5rdQ6u>}`*|$l z7jF0~ORggbJ2{p`fk5}3xt>Xx*2*fX;+v$!$ZE}OjZHK0$<&FlxO0O53UUnQsaz_M0x z7Xdk(ioi;-_{n8xrvmC)g5Lvv|28;SBuGk%y$|xgDIqUb)p3L=hn`{skvU^d^aM7S zC2PtP;-Q|MAc-IS#{B41{|tS^*I$40qPe7um=2E7hCF@5hUce!MVFXxKCI_1zzwy# zJf1FviO_nF6?NxHr-0rVW_RaDfc@S>bS_I$yFIMH;=lgN~w zu^txEtrN)oV`qC@8j$)$Vc2D6j_f{W-Q&JlaTabUiLmSzSQP3x^uQZFceg;U0Vpr zHnkzw>uwB3-72c2m#=`p5hY7S5=V8FXx}EYWXX~Q&G|(-tfb^g%hr;KQ@}sJJ>vv{ zozWX&;Jyglz(_GwA@vQZsnY@dLLQsVI-qzF(km(Jz+Mc}C)D#|D{zpTiMoT!!M|^D z*iT6#ArD)lh$KM1vnuCIXOMMBtI|y^4Fa46#S7L+`@EeF;0nP&rVtNc=0p8X3sE}< z((*VKiH1KRnATu`^= zbGPghxwy%2$Sqddn{?mYIQzn)(X;*_|m1!2{}Zg$T4EPd`8|7e1<2hVmbBv7h)d%-YEEQEZFr0woyikHH^`RMyE zPXu1Ot6Be6R-Qy&q<0(vc?_$XLD~*nAD3d_?i=$KZ%UE?Q>?RQS_N3?K(`B18{G;4MRmRDw1SSHY z=Z199C&2GfMj*h^0X_x%{RJ|Lf{K~gX9^#`FCm`^;#_LbH#m7rH30r1B&ep&ICxi#B4bCz6gv!9xTG>`!5Yy~?41OZ*ke-Xk= zl=Y%>-rN%>PA~+lGtd5CNYMKsPGoVuj{tvNJ8T_B;q|lkt+aaSqmb9Q7!5P0eM9P7 z8@$##zGI4SlzNHl9NvrPMc1uEECqB8;C`rc@GGJ7rYn!xo0#y~6aH**enX7#9|q=m zfc4TeNI59~qFV=fo|Xiq@EaEP6)=mZ53{F>eCyT>Pd~4lp)zi&Cuj6EiA0EJ#@oj{ z_t+S4MZiE2!$6cc3H~6Bog^w&#Ej_qz{dB(cmGz)YXthQ4)Ohs9aRQuXZkAkktw&F znU2+Lg@Q1sR0EI+#IUX^G??D9*pP#NKas7&yAE-jAPJYE+UhFs11qsQ zs1LKe#6PGicxw8JYje^lDo&lBaYYaNb5+er6C}Ytj%Z?UWKb9sl4^?`wB^+S{#Q-+b>-=B7d6XYu}y(>?w&Trysc3mAMfzvSM+2_{WpF$ z=k2DXN5%+wPIk`QT2G-+=RUr9&6?cxriHNIVTZgJqWmDwKbriG8}_x!Rh*;PJw*C1 zHY&74DLL{@t^P33;`A|vJ!{=WR7}en>ON}^-ys(ZTi90)Fo>aAS$KWg)3m!z zneqFSYvQrNi(5zN$9h#<#B%SSC0)3jo*4`L#JN zQV8?Q^&r-{9$UzL4}U>7@_P)!eG&x0A|Cmj>lD%k9O{0Cl2c96(3(11*GzJ1NR7>9 zckBFReh$zB%5l&GVn(IGehaENbwm9`R0w&}_BCDeRYuxb8d)lZ{Vj}))QNk&IY#Mt zJ1z>Yb(2$h`6F(=1hyccH$o!_S8pCIHV9Pgz>7MSd679^F%YjJKZLU)8w;b`@y8~Ube#!88LIhdqe5QBad-;g(?*RbLMbRRA#FQ^Ye*H zdS@@h1xDss0dJj~(SNUPVUr4h?)9tO-%o+zQ1h<#V-u!N5BTBQDXjga&8fR!J%anm zCHr;`rtGh7I&g0kzUINp;?G#}^E~IESLjkUBCj^_p{P4_?-7X-|WmZecoVn z4r-|`C==-HPt7HhrSq)bR!b>EkVV-ll{AJ3WCn9`Pf7}K6$IW2@MW0FJ7}dBLtb5h zA4Qi-u?6xS+Ab4M;&5DY^Jv~Ymn<|i|1(~)9DtXt!~BnY;khF#?+Tg7t#8eyKL|P446QJVi#v zo|^ppw^puNb&qwj2acEmrBw~ZwiHV)>fnqAIt790lK+$dcrFvQ2XO=hdxVQFE7XOVzsKkSwkA!mu~ z!cEeQnGLPQH%raW1T^czS?fZu$2@^EN9fbixdYafr5fV;ca}X-P+hk6D{_WGeW~q6 z9vPl>{osMA&mp|2u%_nxU!>TGKN;v8+;Cj`oxcCw{tvxFIv(;Tfu0(IzzztVWuvEp z9smr$9BG=mlA|+Lz)Lz4R^Qd(j}~XU+s*Y#Zoe{zZl5kLXZ`y1yf|Jkz;gR|!Nhni z7~TZXziKTw;FJxx1)3t#IrIFP^QRS``g3~6)`m{qiwnX3L%(Q}8jPBF<{}`TX4mI3 z-M`Bl!2NRirp5k1A!!DMng)H*#4wDLi_aBQ$bhat7778!dy#AebHhWQCXQx$s~N7h z)d%yL%jnP$0MBULTFB}9G~V!lfl0F7C2&oWSPng=0KzAM-_-bu_4 zQ8jqW^q7st)#-^|az@+p9i+X#WLz1R3Yszj*H{V(!`qGlUeQlhJZ&EVI2jeCgYPL7 z?5Fa7Y*XA(Qm!sYh_W!qw^lCO%x;_lb>fT9T;<{ImHoMoe7Ov7yw&PB&(2X~JEo60 ze)JZ*4GQ5moz|6t{i#Z7e`y{O zZq3xH2$CQwS#7oyaL1@`FpHyqZ(pVL8pj8;EL(ujL8+BihExbpPw`p~ zuXIP&P%eIZ_s!+&v$71gDrySy*SOf=i36i7ix$Pk%-yvtKN{Mj_vS{Fr7JhxxmQ8B zHL$N&?;Kp^@DZG6&5LDbqw3lvLNc7Iazx*BLY}s;aRJ~9oNAThL^;jvSGcL~ds1Si z6CF5<;Qlu8J(gS?>T6doa?=Y9?Y0|_!RMv~m95#;uvjkaHooG3Lcbk{Ym`OZ5lOey zaUZ-5xCx4?@U|k{YZLoEy#vkg{Z#V~`^G2*z4=AYu@z;3x!Lh?t6qe7!@`2^5EkSEoJlNgxMbvkJm?i*5DC!MO3hK1JIbbt#0@~`Vzq>Jn}`_`B`{dqBw zV`ewBC_%rY;<`R<#H?lICL+#0le4pF&>u8vu(!uMae(U%f;}-p|74_n>Za5E(PihQ zyr*8?)Ywo!JT=Vb=AsbZcrK3@Ee2nlK^;#5uK%pu;vygp=Xba-lPRPn;Qym&$d7Y6 z`!eY}Tzo(-=j6S^BdVqEFp$?;#S+)8rzsbL9zL_Eig;kX2vu_^dpFJ1FO9QGNLXhq zWep^;XG22j?J*>t(Cu4G2a2+QdJdEG2wev`eGs>!3WLhcZd-i8B*E znQ`RF-|;Z7&ICGl_{ra}=&;Dl#DCk)|5x@Pg)jW%6jc~hf!DxBZ9lg(PXRykS^2pN zJQW_iFbM3VT1@mB@B_}jP|F@aWJ=e>=N(lTtW3XF`f(|gXGo+PHtN7KcN%$+9}H}S zVz~N_hD4Q=Bmuak+dL?@~eo)nQvmz=6%9aH8?os#w z;2_N%8GGawsXu;gR8oDFK%3vu9noKfRLAQ~xH1Op#d|uu1_%aiR=^1BD0*8D#IbW! zI`>5E=ybVU*}H7LGwz;h*{(hL7RaO5yC?0sB@ot>u?3rh5u@#5eRio62W}__PHbM| z8gp9c6%>Kq3sKhcsCKl8-2!qQ=$mRvC-F4c=@+YDaJjEO5raHK_}anY5XAzgy2%V4 z>qPKOUn2ItfB1&{n}#f7)p*OY%q;(bTMiko(p z;=nIjl}Zv52^hNbumTsBQP!}!=33D~fG;w*`F4KHP zu&An*(nm^zt@bLgVTkiSPbQ?6emY_YOrtf{sX+dTWUxZ&?CZf3lk#J^K~Ry{D5{o+_bwZXhiF(xo>0MbJMjJEjqb2rLKmj)#{b;13tvi0grD z{?GCoPXD(W@Av2XJwM>TxIY0`bHMjX=wW{nc>yLxE{JnhV9SuhA0f!R;r6efda+0h z%;c(v{Yk6W=g z@4xl9&M(RY z_Z>RIQaZRVl&Sb1dN1I(K#;)>9?P-_P7d0dHjVTNa6VQW_K)juTmr60J?tM|pN8)f z47D}_e*Ne7|K^mD^#^fKiw%Avvj-rbR#v^fwGQ%@zNM(I>U7wt<*6zAxgbge>rchDuARC?`k?H=gF8X5jqkU56Sqix z$5t|4?Sk>mxRZhXwa4zo`>i>uQ}Dj~Ac1Ka#)EKACN<+E*yB*>K#JBuq!LlzZ0G8g zSWvz87G7wk>BLnZAU?3ty(gig^=*`=(rx+`V$`8oynE+lp10{3(0c zcsO9*0Euf1kp%>H)6L%f5UBfm+(?bKqUf zxMr#9JM=DEv-Yp2-`@uE4C1>}TH6!%P`GvW0tXZ=rYV=g_E0vekJf@i>1vk22 z)w199HTZd?bpzdkyM`KDp~KSkO-0;!*^mJB$Ipm>KPdP;U?N=KA?_}kWyW2dHv}1b z1yXHR(HIlZp&oFsBgc8fH;8%M@leM_4LvK$F`EEqOtGPrEF$2!MEh71_;2{kes@DS z2qSHjn+)VbfuUEg5jY8mG!n181~CU8A{@@w8qzsFK|$`s?{bA@f9JpKNZ!wgKKaK$ zQ=;KGC|JSO_bdHv~?2nE$1^dPgHRCafB}1%#BZ@x*g;@wtFad>4Nd! z;anVzqxZ^wE%hDXZkRr=wgB!6^^y_+2@UHo4cz@y=DE$WR?u&? zyVKM7GK+lohM$*{hzOprYWm}6VISE~x2r>7{tcbEUyd&faIl?gpC1qD;QjvC7qI#Q zL%DH7m^HK<-jp!3ruH~^Pbq>hT!@O{Q{}0!1nhE=#&Z>%T z!rf5dNpZ#`sZC6g@l#>HvzXXv72hIk^0O0aWDrkpzDoI>0)GqC*+IYexy)qnhfx;a zvOQiYPG#EbD_I3D7wR=9y$ZtEn(dhTCBn2j_|B_mPb072x>Ur>9{2Y$#&$lg~VxK6sY~}cX#)NVrqj0D$3;Ezzh ziHr68hgKB}>lxPlQ}9~Unwx10(g@_3^-D@hbd%)L+U%cUzhGQscE#<3{TD?;l;h1H zm=O_`c|D;FSHc8dAt0U-N2#70zYp)eotbb7aJGFpDyjhFJOamU5{wVxSc#twNTKef z(7bElw=BCcSNmIDQ7n*kZu+uUq9B|zZq|y85tKYHM!V|Zc!AYso3NIpL_%Q^+nf96 zPhTD*V0$~?yyc|n&JEf(5%Wt;=h`158Rh8>@8Y+{@&W^^UI97?-1ypL&;uZzXN1Q<>}@N$0{xnlC`CVy zKq)CYg&scd@*C&JeGjm^xaStZd;?(pP`-E(=ik4x`HBSa^uXm6KQM4iLm5JnF8~J) zdi&b=bl;ZplEE_wUCStXhI9gY|ydO0Y)XWi~G$f|ODwz&f0VUx}L%ahU zQ<%(-wRur}2sNrz3Ps;Y+@fhLfwD9$?f{T~J%zbmT!?@|c+G)#5n+*ui#M|5MwM!utlG^4 zHlVFm736dv@n2X5EM@zIFCJYYlTy?TpVj$hT;=J8eaOwQ zkC*YlD5(zPJG8^ggA~~Fda(uKcECqfntuFU!1JYNa&+Gh1-XIxVcUqIp``;-h?|Nl zSoUnfpf{Jw*mfYnsiB6ls7X<*cE`BH6?}Y*UZXnTuS8J(-!bzAOvuqG+u12+>ttfK zclHWCdQ8lo-#ypPSk=2XyiECSvM=b&eMvfIj98qjecXR#s%G19Z2Ksy(`bA-;5?to z?Y1v@1oowFov!+YCk1^lj!F^g5x9G5wut8O_@P0=jJsa4-pYdWElcE=cAD|8)=r;3 z#|w4nDD(4kSj9RxO=BvgV=8K?D*AJ~(brcPOn>b(Y=beOuL;SHO%P`!3GA-N0oezZy zD!_mQb)U}z4IiG%FE?Nr^fqA`+4-dPc^5?_zx-r}2=GqodO(kA9X<2D^+Cb=tzC56 zbCZ2(b(vxJBYiE?eSguH&YN7!Lxp+ACH>&9R07>+sW8f-^$E=EDDFbi)Nr_QUSQE$sQDQ_Qs!oeq}%^G0`!0J!tOS{Z6t9iBRr{C+U4| zzEI}V2lOxVIa>#IBWS~+Xu|+cXDhOIocbBfYt^VPl)IU5jt}IsU`GHSfI3SsZmQ@Z z{pW!E2LFZQ=rJ?iq&fVKqYmniW$uuLoi*b-f&zUvf4fIDO8 z3?R@R&ch3!iE#2Pe%h!Y__{4csl#S3$vVHZQ;)+ovD6d05E_I^GS4jmexOp@!CQ$k z^@)kxyv4#me!-V>c{Z8LFn?@t&^SW>IXPgEyY+yRsVH7+yP>bqC&b^*`YviXSF7E< zAdd(r%1BVXzytkCqYV`1LERi%=dw#;}zJ)1^bGPh%LDLGm zQ@r!>_{@YSeb^mKrV2rznXvu3P}BS9BAMLc0Q$%F?}x-T=tt1vIDuCM z149P+ydyX`m<%Ma*0ky>`nD9yXqH*bA1H}jkLrbTk2D;1Z*|VO>D+oqw$`x$Dx89T zMV(@KhCWnFEoY^lL)p#HE3l40uQocrqa`-+nIeYKc|fxwrNczH3K-nO_xP|+=umKU zS1e8&StlBxTU_iXm%qMbb95opvk@O}7PdjaVA@IDXwB%phWtqs`=bZ-MdOfUF%xH{pT z0r?mu7YkS@X1!XY)pkBP;YqlBsP@Us$Km#x<$=3>LVcefvp=>hu)J!>LBuS6rX#p& zNc>h=jHRYZ6q3|K*dcLcZ|ZT}Aur6NH;H)sK1ypZUBGj~g-(FKpuX;#qcO#1+)`03 zdT)I}kP>!^nrc}lb$K2HA2~Nky7EkV++Qk8IFxJo*?4Y5uXm2}2YydcVt*m@i`TzG z!-K%(sQ0&-@rq(8|8~hFX(Hrbee0eS#NkK2bzh56LtXOGO2D%H7jaUK4l~k?hIc{! zbM)`ui~sHrvN|Y)=CcC@%G^+gNyh0NmoBx`A=CsT zK+NrY0#|o>etPT6Wf6)+Pd{4`@z@EFtJGTuWU)s+yG0ikEt>*l&>jGKKUZh{;rn~o zXU;~FJ1J)?s-s6q_fDIz>rv2mf7vkYneew2*tjLD_QU}ns613C`}id21M%v-kI#*) zv&MZO_nkwTnUV0`2L}g-7Nh}P1L6I-_k^UO=homG8JiOrXKHrmOF^*~Kbh>)f5r6X$*QZRZ9}u-WRQ*}o3Yv_c)i-MJCtQ`@Hbs)IXs zbI;Sc`{x(zBx&EBYY7$?M`^FZ1Nhc@sL3GDIUJo2^hStlcYr?-{4lQPfDhEv9;l5U z^*s+>PhtIpEh5g(`yKcNfc%F)|C54~`=Rx-l~_tmVdJq^M@jTnWZu4}XzKnK#`u4_ z?}=>ng$oxx-8VY=a7mkCO>xjn_q|K)e_gUk3ENL>;^ZE3O(=(p&$;v6EMfFDLh<$)( ztNxwtMV~DRn(45G4TL5^UEMENWIy#U`u@Z9^03bby7$zF@K0iMQ0?`qR5oA^g1j>! z8!&rXw7%z?Vj0({~>YPU;S? zt*@IEzH8JJ$or4)&$~i69HHjQqPan~yusEvJC{xAtG%w$ndb{thEys__#J}%f3AmS zkCK|5#?Fj`*QQvm?hn3G192c_Op9_XLT~HT@4WdOtOLrGx8oRtd~I6Q54%VN!RK`mb-~gWU_`&9M0{c~8J62eJfGYhUK43-bliwW4`?f^XcwR;5Qw`5W80$)IxfTL;!SU=ovFZc&sP`Hz`6Jl~aEZ@x#49`dY zDoX$zCaC{52b3Xj1bjb#qM{=)PScl}N6hG(x9LjYmb0+@;$A=TZfbIJpS23+?{aKL z`edMgnzSBHx6El_|z!Ot)KZLo(Qq@6kwt;b@LiQi`I)nS)cpA86qn?U2@ z6Vi0p(Q|s?B*}vgf^*+d%R%mQ`?PcPp9ux~@q8E$wBc)2ijr@=-fvnSOVhxEq$Paw z0;HkYcfV2rxHyeEN;q053=#V#ZrG3H0I2KCec(S$+~@ltykPMEa^Jp#K=t5%@`N2n@E#pC<||FgA0RI5JswqY;q}4g~JtQaRPesguI{Xg5Xyx)L zvY=qmql*YKxFue*GKrW$!us2P8vJ>199;UpZ70FM@40_}9nd}4%NF?xj1A!Y6P*)0 zPeD14677TmtoF7#zVp$|+(!1)W+6L@0w48e;blSD{XkHo)q>95PX<)R@&ZGOlD5v@ z97!A&Hw~UGnW!+fdbB8N>Ysue)!T!{$_0avZW1KC$rHkeqJ<|R539fbV1Z!#bl6|$ z_Cd37lQLZ`d)kC$?KttPMGm&}m{6j}p!oI4qzT@o83hdwfLelr30yjtL6``5|fy@{D)=9*pr#<^P+nYLcv?{v)!(~%a zUpvvYLO&;HQ%JI*qZnR9f4jbCgGvS?KNX> zcZ(gZHZy)g_T;Bg(H#F!#m&L|k==Rgwm$;-@Ac+_I2f@f7Hzw!A6~CrdZ|Pd%d)M- zL8)O$Z>)kHLEhLSiA`5FMS&7;Ha9eD*EZvYygb3DxjSEMQ?Y3GhBwB}7Aw`W*Z%3L zZ!0|Pg!oV9@M~;qv}^wq3<3T~cFSqp>C9SJ@|@53eq-#7a-e$~@W0_ljw4DY7Ek8= z{0QRn_^$!oyWoele?BdAxE!I+1PnYL3cv?;g^{A4lL^@^d6+L_Xg}8KGrnEc5W~6! zr2kehZ zvx=cmc#jO^|6Brcu(D1MWF^qZs~gHRGJMiYw?RE*HDO<#&f%C>l=lQiZwd}xQ4Mw+ zyg+z0|DnP98Hr~cwkeVUk0WS5X`%&Oz$BB1x#VHli3^uUSgp=mQOY?AfNS}F9~-2k z9BkN^o1s2^V&Xjlt_FPPf28||H$90>#LCL_sht7uVm`3nC_7>IGXUo~w*B!5V{UY+ zWY@8ueFQQYnlF5dSI>HWK8@G#a&tS!{UWIwwMiNCg!LoIsN#lhLs61!%9Fjhp3-@L zdaf#1q+CWE9px+uD7^htGu95{P8%C71T`}=S{NiWs?}{l!anRf*#Bqsz5{Q&W`&9e zwwr~V|Lm1lCq53_e3)dR5Wg`R`(6n(fgULH4VWe6cO5a#e)3e85Zn>ScI>_UQpDWy zuzP0?<#bM;+1ngj&{O&RE_V+RB4P}?+$P-6=AbUsy&BzIC={RO=mpmM!{>h3bM#N! zH`<9d$QKqiD8SW;5t=n?D&0gl=(}Q$55#EVZJ`5*_E3fB|Ksglz?!;)`~M1&*+F9m81SXx9OA&3f;YHg|R)(V112qL{0ZLOFH zDxyVgYk=(r5>ezz4Q&Dbv~x4nLzsN%|h z{!;MM#Eq=Pob;R975i4Ct-rqHMi%rRPJ9cZI{)^-;G-4vH-c=s9;=30Xz&*xjP|eV zVM!_m@{Qx;dm#P^^)G9{?)UW#kC5^&Q>kPW_Lkx+|<<6v{Rg~m~ypI4uKu0>o%F%Anwl`f&O>sL5luDJ@PdRK@H*I z^SApo%}Y?3*vAw0NBbgTee%&8(TJMwPYj?d`D7fSRf8<@Zm%P37qSuLcaz~xA+XUL zTSi#tr*ktN-`hYhN~@(TzEkQ2xh@L|^p38NjP zzr2#b2qu#eh&bc~OfMfJD9?0|_YgUdC(2>S_kMRR4z?}I^`Gp|vX;BKq356;2oe}Z z;PnP{}`s5#{{g1{j{L5RqYK*J_>EM&PRu@U*AQbd_V=LdMx9zdtAJWsD4lOsZ0m@=x~lAmzVnvTHJifim8OBeSuO!7RC{c(lBaLHZx12O_*j z@7#KLLu#bzEK>e&r`0r>o`u{WC|VX+rK8SobvfayICi?n7V+{}Zg1#uTmQewGH21*E^Av5VRGkZb9K*=!_dbk zDTolpmgCus1GbZ~P@YV82LG{R!uxd9M1iE4-ih}SatSU~upyrq2DHcr`yn25Pn;|k zO@hA8%98!#y@=4M19G7n`RgIt3jBk3$(gGUeYw9!U;B8XfD=0Jeu|#haBATE@n3$L z@ZJb!Bk2Ipk;Z)J8@w)Y`g#73-#ZWV9*N`kAa6i@)=WW2 z`Yay^0rG41n;9A42be2@3w;hb}cvmlPzjiqb&Ktp~&WURfM^=3jI2zEYw_4 z%{jQIoO!vC2bFPM7X;ZF&dDmR?#bqUOc<4(zTypx3*z7P`sUh@pWoV(R}xbja_aQy z0c=|ShlZx*U#DA&aIs)D+za40FlolnXuk;IzVgG!$o3z-75BRD|02Bm@MDM{Qq)t% zCv7l+LWgk@@+54GkUvMzr8O4Em8WWudyBnbQmv`e8>ft2lMtv-8)+g^{)ejfXTkQ$ zU3V4grhxxb{uFpXvs#L8Gy|?*P&V?~57ZRW-=(Hpk;5)V=9$?ihxJ(A_x2#*LM4)D zz@4Y3-z;f<8{#G=9I`P8itYTfo_#v62>1Sfa+rf6NnA7E9IoX6%&z;lg$JMy>OI?f z&KU}rE#d}xn*sg6Vv0HLE*9ULyJmTWyC^%XxF{-oR#{syg%-E+#eyndCeOE*t%zO3 z+{(G^RPfcM#!<#=3;wE00qjD{cfCZ! zLSWUAZ|by=a&N5xzhU#{L`mdq46$bK2J6>{!or-FI8cc&Ab}eAo)AegS+gTx69Vb0 zJUQ(DbN8rZ*kJ_Sm9lHImcS&CW=`H_ma8SO9)-$Q>s((1skJ>g3~8&t_5DcLyz>+B zw+Spt3^=K?gymz3Tr#n4yzlc_9_$P1?^00jovEopK)4;XGk`?aKcDBn`&s{3!^zuW3i}NDktU~IJKYfl`UDD)*%=40 z>f)O6`b2L(p9^N$PkR^)`Lalq>|-#w>sv+k|25kX6n?7XAlFd+WoBQ+L zYEDuvG+^4yL*;rzm$jve3;nT(zzu#Y)l*XZgbd>nX7|u!8OG_pH(^Cr?)STSd)yig zeHrhxw_hXWzrK)4B}YSJP!MVVO(wCF95otEsXEpR>I!1BobNs2o@^_lV|O2yFxY%I z^&ohH{stU*Uik#taGNUa$TOF50{VBzrSz&P=EQi8?ew4kg;UtW{>K%NEo67|~;s}3XjFN^1FevwW6=fj z%E4%v^k-0W*XTZ`l0R{nS2^MCX`v(IUiPcPaL7PuY#BQIIJ4Q*$DyP?~_ z@CT9&8e{idCc~{}?bDgOa2KE#uzuiSo@HVet`2%RBKT9E1N}nb*h>wsEZyLV_BhGA zYa5QwEn|>+h_w4U?cneRkozXsSjD(zK-Cn>B?ja_cWSEFAMF1daMUJ4k$@aJlE-*|J``5^y2t~H4asUPmir_2fNUy?6I9Kn-BG` z-Qx%i_<|?4ET=LWRl~@>Knl`f%~iKRoB-|vedL)!+M#Bz7sx*DV!YZF@FBmQyy7_< z;v)%Sz!_tJH!-_oYQWN#@;i{;<{z+$gb?oQ z2Dy)=7xY;oe@3`Zy1m=3_N(9ihTfShyvsxPY~GlKL}5scz=Y2RKBV@t(QNE41+CIF zgZDw&Hyt8}w+nh#@Xzn%nCj1c{O1QSY@&Ok=i|aB1NA z@{h;RjD+sHiqSLuq7OO~l3Gc-4fV1Ae7^tca}M$DDJnHp7HZ=wEMpnDM};0pLA`z8 zOfU~w)-Bm{a0L&AzHF&q#mKq!jrs?NAue4mXv76N1A~N^#kN{aDo^#o0f!Zpz|GZCwN)f#@_Pr`jgH$cx zyr<#l8apk~D+@uRssp1|Zu65f9gg~yE!v4|fPaa^#(RBm~KR6@NmF4S6{lJAw2cL)OD!XfOi7UG_kE(EHP9IEtBF(u$> zsd2;=-|-kltPs|Rb@a+Z%;Lo}LEf~o>j6eMj$?oq;OzN-#dVBY1nLvYO==?=1Lj|e zCPIb+=JnUCe?Ol6U%l^t{{40IqSG?(nFtCveJ=)!2~y8k1qI0;x@wW(^pz`LTOf6g zQp6^uaSgMqkjT4*RnXae&qvxqfCpyAzC)U*y-o^c*YNyAS;w>irq%uJCJrQvSiOP)+aujmD_b_o*+IwMP$ScM4|~LqP0{fgP<>X0!a$ z&XKd-XNMEdn~}9s`6rh5*gV!UsA@~k_>z1OpD15jybxu&}NCrQ!00mg0 zn6{_@B?JAQB;XbF>BEIQM1q@CsUY{b-iO}eDng>$+M^3#A|U;eAcA@%aIf4%T4b6Z z!o`k+?GWwGL%2L-S7v51Vxb^(L3z2>rasJv`1)z$WZELc_(Ux^Nch3N2m{-f1#w&o z3T1iVzzgB~uq^;D7K0>`T!lSBIACV3!QCL#!a@xNMra%Hzv2J>`Mo?liUALT3EzAa z!R!;=S=vuLLyCaF|HI=Ly5i3M)o&5|R@`LzHM~r$+qgOH^r9cnh|oPd8!!3pBIQZ^ z|LiCK`NaS9`DfGmME}yPqvMxqqA!&_eD199LOYTqZwLAEko+Xcu9X1@+9R;yR)1iw zT5iH$eno@XZ4wde7PxS#hNY=ael-71d}&4t1`O$dD|{oP9DJ)g{wZ8lCp#;Ay$9N! zC5HMd==BGfxtFXgIevq;3Rx=a9VGP><(pwL`zpV4<(x z3j1{!9U~(I_O%Ej|cKd92n5H$xQ^tCG*DW!x*+%3Vc0-aK6ZmNyfXh z1>`&+Ln(+v8CfO*`v7q~F$S{=@?U<^s6j18;7vkm;$S=UKX$YN&MycOpo8djlnDf> z{t%Z7fPBb$&Rr(#_tSM8gL6kHo2ui!PlIUdPuB`nGhc>`!Mb3~)pvOUZ`OzupXmYm z6uwVEZg3E_TE1jK5!u%%;A7qp^qCA`9_Gz-%}*ax!)gD`vDFX!BKW&{kaO4u;CE7a zXyYWyv}3aZmDW2ngCSryrRt@p0mtY7z0d-Bq0>UW41I|ZDx@9#VC*yoig%=nP_-bp z;n$5$3rtFe*l*=p=;zQ~6|-`yU;opE-X#$vZaM+SFkvwGH(Id&z6j#NBITa=fH06_ z1@Ww27%ca743B8AAvx9#`#GbrnZ$F-eeDmqfiMpNjw;9#vGFqwh#xXt%5D?Um%t6M zpCx9L20bA2I;`BfG&(pk2P0`(|OV*~!PbxPTYd@RDIw;2|%rjDGlBZNr#r8DnU8c=gdRNY)Gti+dl53(MEUN zA5UwYOp+PykEed*%tDOMZDpTzO*F82Y(x1+T|gR$szs3QjeY1<KqS*-RL6V!rLm?lf*EeAh7boTS>~n+*Vr_lr4@`a!=D(m42|Gs*XTiPzt*LRQ zBd~w4cHH~pMjyhlLLfUG`WuSlr7{fkM-aauPzdi0=q3B7zXt$C9$XmIj+o3l{CoaC z{Q92`Y+4VzqQVe*IgUepKGLBq6f8FvaKS&21m9j00<;)UCkU!vYE7r=YuL}X_)Lu| zdwFO>hn)2*;Mc`+cE^rSNj)Gnf?grzSq=Y9AKr=-kRZ*;8HsD62OWE4HJc!w?Ci^7)4-tYTrk3cGE(Gg-p&PO)m6H0csqH(r+9PvCjQg^VgGWsX%TYxo(}XvWdn}a zf}UVP#BeQ7gigY(Z3BHkIMh2yKLNt#Z#lt4gLrQCT?zXMn76?d2yz(|%99M>-%=#v zJn}wm(Dxhsej1BrC;k0KgAPU^rmLsgIz3_n$W5Y(k zI8=a%EeKV^RX+fmjGyciaZ{2zhp$LPSTasb%IicJOiO^}Hxj4oVyS$JamxU>g2BED z(%lGI7e72am{0R7;DWielOwn%L?2cKW2LGE9vf)VB=E@pzaFIhr?IHt4?=yPzm91@ z8LcSrjoCN2qKxtJdOX8*faCA48P^1hY0f_LPGDhW{!gDjpQJ_aacYiGSk`lYaH^|^ z_zUds0bNMkhH-dUEBg@Q{gqlZjHKLa#Tl*)@C&r!7?68%WWaT9-c;}W#O(4uz^|z1 z%-#ldrA2vvJmXGKAcOWd+e@v9OPJ87=5My1W(4W66|f*468o1<5exi()2ZdnjLs&1 z=GCRA7P6X^u})rvu6NSXhYJ@rquJRbMk*r(^(giU^_mUupODGOc%T##s#Ofw??c|} zACoGFb^2^idl`mc$C&U#QZB_ng!q6Ic!DJlI ziaS7$V<68a9H|6+G29^ebDPOPP4UG*{`;rv{eUh8Ng>xAZbtuX!+JVOggIojQYJl%_ zo={BUgRFt z;|BmBQtp9H&Ga+x5RY(R`0sv)csqCA{MYvYkM;lQ(2&>1?F;sYU{IzLpRm>sLlVa> zC6Io>u2sP*FCK<$TDvxz+z#US#g$d?eUr66QbGRR=D5v)l$(g1>PdTpGJ;r{{>+_} znG~F*w7G#|nv<)%=s9KM!AK?s;|$o#jgeW z%9WSTh$srlKD0F(rUkJzu~-o>+I3980YZE#n+P9*(VCVRPyQTtOzFt)Wvd)h)(b`vAg%KPTVfu9o2KG2deX$7EVPb4z?zG-cRyn3eTnu&= z@M_ssS*sBIKBB1Moy-WXthbKwS@oLWWSK0~Jh3g<1bvqs6L&TEux0qSBTl}s4aptN z^x&v-#3m8^eR}$yf6c>@_XY0q^!-`kLCMc5cu?}WA&eQMfO#>QnwnZrz)P%%L6SmGK$p0aiZGR5{gC@MaFmC`p zP9Jr;nwl!O52(MQpQKD*zg>t>kc$&_b;?EXKFZzjSHhvb?6XhHiO#<*KI&4cXzG;C zIx~aLxD3Un8e>jw1g8U{a17pGyr9lw*G9>827*8vy-Wl@lh7Iafj1UhX$mbF# zP2Ud`E|H_aDw9=$9}IL%eD&8tu#-V7OPi3}M3pC9DaMeAGtfUxfgrO$l4>tu=*5+Q zYXkn^L$kOQI>5<`sg+3#l0SP8v1$o9)Z*5Jot6~cP9>PH(Cz>Z)ETjH`0 z6(R5E5snCmSIZIx;r~!aQb|UyLGGut+LO=8`LzaG9>SR1hZJb0=R0Ye>-1=P7wQg7 z(9j{z+{~3JG|dbf?9YJ6N7oDc8c9|ZMxKYT^$bRNa3X&=IvSG_$qnqAqTSQ&4}-K< z?uN9YU^UIH>b1;Bt~mes;EkvV$jeXp4@8l6i$I2Ar$=2Y`Prbe#H4s|?2Q4`j(V>! zLRG;wI|4T8cbCw@iPts(QZ0AUV{McL601X!2#(}JneucP_>y9A6#{Yx%OIJ&AJEs+ z>oO1a{p4pTOU@&o7xYz=2u6Zvgl={i0(7Y?Z-!=?A39*+I#)fP%^F|$Vk;@vmu=_Q zkaB(5c6%3mHoiK5H@q6epqYt_9sWyw=w@5o3s4W55EO9GH77|bC9eatj^c;~7}CFX z$8Mn$2K6kPr71AeKvU$O0>4kUScLA&X~5UCD$sGkeU|cWn7X&Kg0Inf)6M+9yFPiM zRGOD>M?1?;e8)q+Uqpc$7z7`4cUtu8)8~f=q`-MVP0KuBgpZs49K|wEQci$ZD#nz; zDUgJgaUN^9+3U>_bvIk%IaZm6iGQc&)e@5fQQV#~FSUh!@p#_xZx9r1Vh* zSE^>Vk2n-u2Hi*S;lve~*(LF39940MvC=f+IJL>BTKv^(gov|I0oCyEN2Y(#uMnQa zEfOKrnKlGkt_V4_2;i|z`_sRHul<{Y^p{NV{Q?-XVZ`9KAj1$iAS#Eauno-VCz>*6}zF^aP{1fGRxy#~%|j zdOf22>e`F06X+g^(o#5lZv8HkA;|xoj=@qr?6c1Fj$F$hu0mM1qxC?GsPt>74T18M zoc+LiV(RSZzP6$$WUIBmJr(5M-oT(mF;b!4lg}?iqbVf5@ft?~cD<2#6|%F0P8+{{ zJOb8D_O3^ye*irHsVgE7HyL4~+=KWKyBx3LKKPXnxSDk~d%xX zWTG->z#}3b1D`##0g!oeRL-4AvGNyZyf_EmNBnVSg|iWkXRKq4d%!!giD_lL0sN0V ztAd-4XS8WBxFHR7v1>1?7QW!}f{`kgvhYBF^sH9H2Q*>oQt+E{^H{C<2= zk%J=V3*39Ow#XF}_KamEwt(X{$E2nG@kl#_*w{12&-7-G50{ko`s)FHlrwZ{AW@Pt zI9QuV=XLfze@@E(_{|$P$oil9dKS%@5rKvq2x7e})OSqPr|om>2mL508zwwa`^wX= z4-r%{t^#(%gXHDcQNcbXf`2Y=r@9_$Hzv*3g+p$wR@zRMej3L2yQ z?xKNjJ}o|})#lms@4&V)CciWI1;9_>V;`=J0CNjSqf)_z{LYw!7p02hWxj78Dn$?t}-@on4p}Z%n-q zbF(yPYVLKw)kyQ#pmFqBOI{6IgVJZnA&3=;u5luPyjwtziB*olaFBli6b!2<@EPiO zH1M3NjPwZC-iH_k?8^_fm_1a+<_jypuO|61icJdO?_bsA+~bw_>;j^0?M~q|B9`8_ zMF|7x=@z{fuI`Z0nN+Pmjg(Y*+G5Or3giVsZqc>Y+W#v;4;M*=ygB*4J<~xC^h0) zqs*c#pJE~}F@q@#Dj<@WFEPQNWPQ&nXTtgkSUfL>27lIG;XcVE4596T9P=yzqsrHc zu0uyAZKK=JP2h1M+t+XmG__ocujPc#5NcR1_Sq+#VOrVw?B@)KGn)za3MR=5x|`|7 zB>7)O_Ec_rds$g+se-dhRKRF?)PgbiZk^TL9)L@S`1=>B92$eZ>}tPXVyJtCOyh`% zh5qM8(UeEn=s@pVk0&Tx?%}^j{z#Nuv#1fuS>m-`D+F2^3HCUiSC71Ii)n)X#g?{H zwS}Mt`MPUFc=^`XgX9#<=R!Iw$;5u^1Qqrfq}>@d3OK!dBem( zi3AD-Hl)yeaW$g;Npm`krkCa|etbGO+=os-F_veNs`CDRxo0d*s#GHt6LGoJCcLw$ z=i?G-uH8j)DNZvobRl%HZ9Eg`eAL7QYm;G8DXkzr%B3RI?BvI&--P zKfo`iC8r;Q8<#d%FV0a(!b!KdOLnRnUfo{p5Z>;F|#ELVaKWvx)e{lg}=w zN*@2_Q(utt6Sf^0ukJ6des!FC-I|TNeQ7)Lf&%aWK>=;90E0`q;d&M7?DM6MPz5>4 z)J`xD<>dk@L+AuF$Fvs4Lo$BGik&M5UOclq5q@?yrO+tcyflz;6oB=|x4*?C`7;cJ zBLU2E*&;FVDw#*<6fh}L;KOd^ygT#Q-Mg{t=}{cWTe?Nfs0F-Xe7qL*L{w9`Ve8;I zE2Oz^S5Q2W*sN4h73j4L$V=Xv5TSwKuU;gEvY1ARcLH$*1Dv7n`aL4#dprI|x}%zt zBeoh2UQ%!bKy2=Fjt)BqY|-`~Bh$P8@P6#|iGuU$vgLxJdyi6T_&%ZAe%!JG?|8pE zrl%;{RBmMzkM2)j#->_W6JCizqb^8W2zn0!0+j`TIbV1r62hznQ1|n%>jQ4{fAnYp zMF;ZBulW}C2}2iW%>X}SJXM+W8|5R)_a{&CUSj@6Dc1+GJ3#KO`UcieTTfP8Nk;I5;e(+(PV)EG7Yd|FfZX{tL{@peGW3Gt7wP zq^J8c^JnL~04}^?_3Txwo#SV#7ckwOSr9n*3sW#H{}J}JD}Z0V$ahx+3U-^}oIwjo zg7w_oy(R=`BRZSA_i?&o<>~{U6rpN$AzS2dPSnsCY>J%{wR_-P*A}QpF6NuW!$iSF zXwxYeC)PefsLpfm5)pra3GA{F(Kc1?l%oE{ zz~RU2z~5LygFGG*5A_579XzBA{3w(t;Oxp6d-ji)iorif z`M-a@WMgBX21&Z}VH*2pPP~i=%=BRw_nAkTDP+DgCZ)z#p5qw$DVM^{g9ezY2^uD- zP!a2b%@d@bs~Y>_Qf}_#pm}0EZTaF}aRnhcr`4*{2&)r!I46JP5k^5H;KlC`1AZW2 zsjC(8(4e4t8@Ug#pqFXtiXdKar@C;cB`F`kK|~A9AS7lMkNCQkjJeP&dpMylG4~H@*Hu zXoIUTBC=)Ds|_XPJ^zDmnQQ8z0+5?uYU(gX_vob*6kZcN z`W8jot(AWbe7sFTTe9eI(Sl$5i(zAz@u3L$F7^Dpx=UB1$@s?5k6wziAhfmjL>zhd zh0&{;DoikM{`_@UPsJ@?yzpYo1YhA#9ki7?d<)e%rurL?qW2^PBI?0M=K>L%P- z{vX_zDOwmc@r#Nck=l~2q>7WHeT$SqKpekjM0CsBUN!)OJ{xxD>i?W4=xY`PG=JAgw zJS84}4(BWWgE%mjJ~)U+69ZY|e7TX4F}Pw-oR{b8dJ45SF{r}s8czFA@>8wpfe>(0 zlJcWePU^0WiG0#-0ASC1fd|M19*x}sc^2TfVnW2FpJ<^YjzLT;NnN^16%&%$QgA5D z0DW~M6j?mDXfoc}LHhl-0`>SCc|5f3+MjV7*jE!2_&qE(BK~+l3Jdr(kN3QmDPR}s z!W{u=gU~mCo$eJp70$|<`=M8`s#m~z|M=;!Vnx^aWnZLks{7$A?Y-)NxOut5V=7`O zY8dKoI;w}F2vdXa;@;b7Jtnt#G9vL(4`D&vi7j056tl7i_}akQAoG5R#K7!W{NpI7 zb&rg>4)A~kF{&Zu9KzxV*k$ko>Jc)&XR;cY!was0+y^m(JP*3+8(GxNpT)ia_rGc{ zk@Zg7?~{(tdq3ReKb(G_AjS&Ipy1@P?K8c-BHYD1p7{cV`NU%$2f*LYkxu*jd-JE| zesIc>Px=??Cl0d$O>u&L+LCJ5LT2BTG@*r=$~3|Ce)6nl0^Cqfgm-v}BAW}3E*j#L zm9brV6UyfV0+5bqJfW&RaESHgo0r~5$j`}1T0i>*2=B;W^4a0q{(5w3BTwrrl*^Te zTmxoMC+R8gjmlq*NB5Uxu+&m~*Q(k_csUjEJu@N55ogQht%HaQILO|G;AcUdoTW<6WwB_K z2ftF#F1dz^HB-=}hx~iMqz`f{(VPVT0M?xpmdk(hh#=)hz3mdny&Jpo;HanK_e*R= z@u-H|Ea|Laol4;p?MlKuLIAg6CraL@-la4(_|cwGaVn|TUt#9cbvowT?{Ep{#NPRQ zC+@GVK<}X);GE`Io5F*xa~P1%&dnV}11Y(=V~vAo0;O5QxA1o`Yu?ZpGe(@#Oe_2W zg}7(A8_l8N(j*DuUm#8|FAMFOxZ??Rph=Q7s24&Q`~zNF8HqB=q0-n4c}CeoR%Q)G z@}(se0uNdxLx87rKYs&(jc-mq@Wm&^=aTXdX4izlDC_()-vsHjPV(o3xzoJm&)@4i zzYRIUrn2y`OG^sWlhXNnE)2^dOy@soNQ*VGH5SR4)+k+uIh1?uM$~9EhE~`*>T$6l z&^(c;k!9svG85~=*cW6f89@WSYF7Di(~?bhBWL=WiS1#?h%6y|{D2U`1~@Unh(oAs zlgzgKTd@{-cDdh0Bg?5AzC|1a{1Bg=Zd(ud#drx5?6lb2NWJZ`-4!<({68lB{HA)Q zZB39T#Nz^vjm5vpFFUDqyS=Q&UauSe(zYREv9~j$huD34uVd=sm*d~g(Fm22BcA>X zEx>EXTzD0=fZ=}x_I`3IH=oQOfc!f|FiIf+uHh8U=z=41b~Q_T=~B`f)+wglZcrC{ z(pmbN8a5HmUQ$?Cz{ur~^L%_(uWnk$1@ZUCh{lQ!Xfz6?cYD(MgoJyaz8e0Pr%?VR zIL^P^$D7V(1pAjb$4a_CjpYThPF8ERXBZn8l8nLSw?PBovJVggO^4K!l^v?)Ze=uv zUg#8YcGCDq6Y^)iAVSMc;+)4C1&SG4fap@eVL@PkWAoIoAU^cbSXC5a%)M9`7Bi-R zfRN5H7-CKM4ta99#aFypB0j&Z>}6;ySoPie8`l!5fQ%mwh!7pqB2GL2mK}IRV)kI9 zJik!Z1NbSu{z-uyLmO%YwD+wb_j-fQ z|2k&~{O_soR&+09L6r$8;{*j+jpKcsJW4MBb~V^@O4f!lL51^03IJOD_Ape=n&P3+ zyPOL8(s07Mkt=gPf9}}l?ksbVL=8B$*(cojK={E+k%s|4bRhHv@fGW+zQ$Ok(D;?3+g8Y|9ZL16cSvekXwT#ReZfSYYVnVR2L@?A<30z^H|adP zpp|%7mr~%oyv{)htB~z|a=SeO`{Qm((SfW&OamEWpVEO%84!4l8rz>mtE({$Ok9IL zDQ<4#kE^(AYmUa-V86aGGg*A>0|g3nGg)gP{;$*3Z+>^P=d^!#8F(pgXT{;m%6X`w z?5K=39?8MWm$Tz80FGL%$olEDhHI7Le$02scymHLWm?Xy=EHzj!FNPQlk(qax9|3) z0KTAqXjk|7nY*k3tYU8C&n1COCY7l?dV!25T)12cU0JO51y{><^Id4n6FqakaAq@# zrH^-&Fx7H}%5k(hw1HjhK2a2$1aY+iA>eoAI*)L|lUrTD=6_dzLl_Uh+>Df>;GMNg z&-$l8SIp2(@!5hc7)_VBd)73PfW}^DyXDFT;*DBD%ab=VeRbn+%m)9U`gBgT(f_e2)#XcDZDM-v=c_H)aT~cmYO-~{3T8)`>3PCT z`p4}Hx4S~UYtB0GD=a{)N9GNtrc^4@?n7H_oScX0&#qA}U0o817q@ce1)os2erz90 zrUtGOU&dTqoP%5r*DhrHxbHTscYC3ud(yJ_&8cNo)x~V$f^0jvUnCCXukZM5-n>2Q zI|COj+qWh=V%B`mlHv3-&awUx^4Mc9FZ1WgE*O*Oytn2!0zpIjhB7w@6ps@dsF_FRunpLq#dg8@T2cI(3gPj``IB|WSmTCq+QQ#34_4z*?PyR zXc^A8-W;VT2I5G4wCPl|F&QfF392aV;_B57qE%sCI?K7owq`}bvL&xxveEn?sIP4z zYU0YjvLqh2J<5Cn{9i{2d9YHE+6Ecr5O`eVn2u3s}HKm9m!OnG zK$XfRoQ_jjK`tEgj0^W9CEqO|oOQYQ(wV-5b0@w>u9{!rYPaR6i8+g?xx?en+ieJz z3-OnBn<$NhD{Q-38HQ6`yHqAsBLE>3SWRN5)NY6kzP+P-x~c85fMgP@B- zLC;5#_WJH3?|l;B=rpV&X4xw-IJHV`5xK9(D)v>@VPl$%MM5Im;wwLSm)(19#( zh4sQE-GMBhM2#_KCm(sti}Ba#oQOhBY%1u3Q&i64h7D(b&fCfr4!)IgcdrL(Elb(7 zu^j5WWxK3S={(dVPNgIERKQ!5^DF=UbhWNTt|Y{T90+qwWF$qP#jt>iP!Gh^&{*o} z2k|w?hs``oL9Vo@Z>(p)=W;>KO-2MF1;IIg+Bu@$pUKE>3@QM>P&w5;s~{e?)=&QM zQLzA!!r!+jiz+{z>nrVfuez;8@#Ndj160T?I-}oB@0( z4&st6AE{#Y+Op=5d_P|Yyt6Q8uT<*4kk3%&U{y@k#^Y(CKj!Z-hqBj&G|uw_J+#g5lrJBywaw3o zXHgr4eb|dsWmk8++3hf#g$WaMA$$~p-?Wv<3H+?lo3P_+}iYU1#pKZcn^h88KGgD zaK$|}SEr_0AGT;paPgo$wf;()OeVG5cF0p21m&iqw&5R5jauEeW9l?D@Z+T9s)bsp zv;A^h9Sq@XB|)6@CG%CD=?{Won;CHPl90<{&zIcpc@WkN@jK}Ig$_Nj7+pA0XF9}H z5}1UO7Or1G|B?bUt#X1wAX?qqiG<7sd7nUPg^vIVShPCAomk|{VvLww!YQDpl;PCX zpeGQ5R*xF7}n(X!w;^sAk8fY3NYO0kG{}?4aj^MBnI6aC5D!z#j> zi}h~aLVj*Eiu!8s+vv=a{_r-XA)+pdW>L6#KQ1R>WPUB1EG#oZ~;Y6&)Ig6s@gYY#wSS zaW{V){~G~uUx8ca@4XS6gkzjVr-%aK=v2J;@|#GMOKD^lblrZjS>CY}s=Mb-H#TIX&H(v`ee>A}SNaaqvmS)rxlwG{)6l}LWpUf zmoL50)9!J@wG`rMkv&HO$oSV5V#nsmJ_i3ZF_@?*4br*{cyFY#yX9Z^UezF$pdHcU z*K-G2ZuI|+Xg>w*zX1z*KaaHg2J;b5GM_o-F--3FbF>iWC-bgkoG&M5Zw_hqr3vvl zr2G@G55Qow5-Qp2KD;>s!KzhHLe(=m?sa!v!>XN0-kk#>+x+wm4Ruj3QGJJXI-Tsz zZ6Sehf8nxieh9SzHy?T<08Wud)MhLMegk}e$o=KG8w0r-R`&8qsKc#YvDUBa#QF2J zA=^TlbUKZP-yNR6e@TqY`#z)R#rZyj_k9Y8v)JkdJna^-b?t(eoEi{qqZe?=QC;Z# z!D=VJ!coA@r&j^sS!MQ!o8vSE4MW*;4zqIL!s#BnW*Vf!y8Ve+ivTG7L4ol7)m56R zT{p5mSdCOpiv4#jUrq9P#-w(O!GRPf%0@RsUj_LW;woPP_5+(`7^2Df&-4B1@Z2e& z7XtK9U+}Gv!z8S@S2YrSyz8yEW<6G?HAmbUN-`sHAhzXZ+XJCnS*nC5`f?iUPD&%eHVNz}t12LqU&10YDAM30}7@*9&>*fXg4-N@!Ak-uprFrbYyX zc%mc~y$byewYt=Qk^eV$4MyF(IpY5G+{oL7kx#hi8lmZpor-*W;q??&&G9FhjbH6W zs>&~XePUK-cXx-W=h5xm2Nja;b2T4->?TkV#|%t~I@fADZ@3ZFoQEeLHEi((Z&C2Q z$t!r3-P%3%qf4&j$&mG4)d6AFh;QYx>Y`xC8zhnOe>^@bx&ik2WIX+w02j{!Mj-p0 z%_jn9EY8i<5^F=$G#7oE?Lib3F$yOgwBiJT03S0w%qd&8tjA7d*{Z9ms(XlpB|-?` z&0P{3kdy-vA&;R2AohbKE|`@67Lfn^y_1uq{m&;H)AFC6s~jY8$3Xi!R5Q!STGiCl zL=2pEk!{`;dD^$dnGXIy>xy-L4M8r9!4(HWz^$BW4LK0Pf`Y1nko_TGADFiyL|n4} zT5AYDBufqZ)R1){4Dc7o?@c+TEH_qc^}7I#ZU$G>hGeU99a}>jR3qTZWuY%pi`vt6 zy+Hkx0{MZc+67asWHu;&1-=nu&{_8fjTjz3+l;VcKomAf9{AP{e9=6o(A!8|GGF=;uB z*Fo_mnV_o?Jhw@wMyg<5aMdu}`G4=g;A?nxHeU2C#`*ohgDXEfu(;8FlUuK?FN}Xh zd9UG2W!QVrpUJgD6bJOnh;_m%s{z*I?A}6+Wv|rY{YlEE$tg$D!!*&RZb|MQQvQLy zOn%wDX*QqH980*XUO>PBFa#MGptk@BL(HiJeNM;-78CRj)CAJxY8D@`rA}#S>2lRv z)f|i5Vv)@;yM)f0yQpHJYL3+5cpg3{pA8`j*xwtRk3zivYltTxNHzZn!wF5mFX!fhFIG(yIRlGt}x+=xBLMQtS+_TB;E(=kLtZ$XE4s{>g%_=)*_&H zhmAix!ZzaBcH|K?WOV3FMa)aaNQvOBvIE`T{>x}7+qY>r4fy6F-_Le@)O`1VP`@y|Dk^xtrH zeU&pJTX400Q*U31Vb71-!c_UW!xI-yhncdA8F=H3Fy)4Znx8*k6YSwf_ld9mxI{6_ z`|gErYoii#hbxtuwZYj0@#G!A?*grd;0WyZSpk88xoh8e<_~~*%|`)qo7|``mF@Eqo9(NgJc|QkTL!9APDof zhDh^=EjK_<2tpxHC|Ws3=U<|@!>yQCIhdYnhR|3d7=%p5E7Yc@a3XFI-}UG239H;O z3|7n}FxrP*GZW**jD`NQVUN-7H~TAA&alq^Fl#AGDa}u2&k@kQ7v)%{77x0bhxi>` z^VopSPpJH3ZYfm-`I9QnQ#v)gA{^m(F$l+V$3wIV`ax0=a&%nORX#+kQI$i7J_MYT zDt)*arsF?7NS3K994f2P6h7B52evD?d5&zR%%MY6FS^fkgLt;1Q$~+q@cG11)l4X7_|C9U<#N0$ zG5JNFodtN|r>j}dnN$MRA072Kh>;BxEk5f2&Jj3{-O~jp$WHywy zMxrUucjOfG69aLcmVf_B45U9|n*aCWrHmAQAjAJ$`PUzhNe4>9&czl7QG@swFS%%x zv0aOH>yLcC2wb(_D|Q`Gb?a#SaD1ow#pDk73+DiPww{K)IOxZ&( zmA1v+wggG<7Ooev`=k|rlx`E2f7um#@zOU(h){7t=($^Rjc<_@==->}fz z71HARZvrwr$Uc&vuT2q^^lg+Z>3k4o>)uti_6%=D#6gW8lYpdbrwY&%8cYrQv|3`# z@$e}NW1H<}D$u-7o+3Vb0rqRmk&Y(|$^4@7<%6zJ-;{HM_XvePb+K0g?*sG#ISPma ziXpL5zyW)P6G8jf)R}&Pfj(E+VwDgifiSOghH!E*8r|wr4hz3dbZ|c8j~nV%w7sO$ zshdh(8Vmt^0QI9+(pN%xu3_dY(JQ4ngO>D_jFtLE9ddfbte2sVQ$ZEQd+Pj~rOqPv znUW6Zui>s*Sk#u9)%(J$OqEI&bl8H~eCfOxuE4gdUi4-9?^kDr|kdPQQHW*jUX@tv7%CKYpUB?8^9<8Q{2|5wWS0Q6&1DH25hSmKon5w zk2ZoxnCCm#?z>N)-TS`Z_pkT5o;la0hndWrnfaXa{e8~&2*S~%2IAx0ZMX2#=uoK2! z4%U%Lq&DEPf8uMe&F6|51rMR@!{Q}i4riXdJ~rJ47Fe7GJpka*2b^Ew7#vK4bxvDq zgIus*3*FoVa-rnq+eq-@Mbg>fEs8vPse<45ooN9~`zPc3Cq*%SkGK(tbGT$y&V9dR zz2?65AiYlk^W%wg^hpI1*O+R(CIq#em<#mJ*#Bb!$MR}yIcaG42CTyh5|?}9v8R;E zw>Hts1fix<*Hru4*r9{z>YCDJ*nQqZ;*C!aVB5iCbN|3p5%_2L`>%4)cbcps4BV!w ztR>Sgd>xNU6$Yaf^F`pEfZc@lf&VbAzzVe%9A8rdVO!BX6!b>h+2bf1Lecj>|l(+S6~CafrO|=e=*{IAH=*@X>Ku9#^Je z(ZQsghg(-9_8W*KvI6#D_Oe(VYua zm6b%(363O}Hgl$MKGER?r8q zN(yqf2A_cZf?4?t{eyXsqZ5eG)z*RGLRc?58`R8=K_|vXNM&ZfC#^vvbp8hVLN{mu zW`b_7o(SPcJ@2`5Q`dl^@aFWnVOy{s!(-3;huQ7b{%_2@H4WBR1k9fqHlxSwPD+f; zn+l#_4L`R4~OpOO$NnUv>W`x-NEGbHdk-{Y{6-~PZFF65u& zBtQ08Kw?;^txNF!V=%v%7a!=$BbF2lg#f*ed~HJ^JUGrZSs427%NiUW1MxbaT*rC;o@j%vX+M_mNk1X?qQFXiuV zX4VJ6=MWXQfM3HOU0#uJq?0G>yv)hcf<4Ins&IvP`X2Yb>M|iLt0j%&|H0!<=6b&v zA2goh&vE_Xnd#%hV13I+;Vu9=!fz2STmuz zv&a7m?4!ry`vx}(A3iMqv1cpfDSA8wA*no7CV}fnmb893A^N_3lh$k;h-l;w>or!B@WZzJGVK=1N(XX zMBgZK!IHOg^eeSs_vMI1McAf|8?TM!S+T0B$+c4hPb1hL`)T}Ev7l6utO;GY6tw`u z^gmfF2x?iAcD{6MAg~o;YVdV|i?$J=!Bz~^1^Tg>zGyno^Vxw)#Ir-*mVxDn0{yEP zTkvOQJw3C(09>cCLJf!Xl)!Y@2eWQsvnU-~0SWoG=fF&yewTULmZ(i(*w;C&pKM>h zE-z2>{@!z>)DH3H73&W8nJgC1{)jABmZ|iM!#}NgODVNGK01@MmyaMBNB@d@|Jd`v zj3d2CTgN_mbxQOL`w8N2oau+f(a%nimZX05c-BvH_wgUk{bS4BAHP1b_CU>=YFoA6 z&*tg{Nx4e!(|2PaM}x{0uE~3+a5=sQ%N5=u$L`-S>&r?1h#Q;QQ_!BTjE#~# z<>=lsXWOLVBQD~z=M%y2HbT4$`aZI?6XBDlO^|~8J#g?$ASlGd>7uDT*x!X<^nXa# zuC5R$u*zfkM4?cGhPRj2C@>s>xizxvnT_Kmy+ySrgO*M}kWYHdlYaa&VJJ`h_()9( z_?JEz*fG&O{iUIyx56jDwC~I}p1(ECTgxS+&o2SrIqZ8eyCuxQqXyd}-ka=(xYwKE zj*#ZeObRk!KV>4-Bi_mMQ?NY>XU|Ld&w%%ET%PJHkWWs^2`kZgb8#fAyWmmHb z-&=};TGiP+hc)5yTiz>+BjTfU;J>9`69*TqpJ4pEAHTBPhrU^4 zC;qsMmzuf7X$|bcXm5>Y8PGlC2k^x6u3@%5O2yFqa1VmI0meb)2$$E0jnI|?(Eowo zP<=2a{%xUYlK|FJt$XnX^K%bq7O-M}5O%!1Z4!XnkZ~>i4@+!61y`1PM1nh=CDwiC zIH?T*d?LM~OsLP%X#aHP1Av2YRd(K=q&x+TbgpwxR!2Ke`_Do8Mjc+wuRb?xP-Er%lB(nCFT8eIzB12pe=63tMc;_mzJjR?dBh4N zItcA5-Jh2*{iyyDz6|X1|JVE<+F;B7MF`Zj_ep#pKWO{yx6vM9=!-yG?T}7~qCd@# zXW~0g$KRR8)Sph{g)w#Fv{Mp&XSoThfxNJKz5YKzg~JbdP#}-$==cZv22Q}x=cBqD zY8a=$AG+LdTHXl}q`Yi{fuU<u z&4-1`mmr@H6oeK8LOvb~_2mkz1oX^~{tQ8Y)`@VsT3`uqDdqIDu5*6O4?I+Aq+r8jWuE@994Q z_`u5amAR+)n=qIrkp7<<$KeNt{+T>wjQky?PZz{Tf$lxv7Xms*6!<;5?&y&i@?&!E z>I5Xrn>2y{hyxSEnBPGj$|v_KKu+?x+y{-$d$3NYt4EKR^&}>+H-T-9%75lU6Q(mj z{e($i0?nGk`HlW53zNrEEXKd5c3AD z0X1$oX6XMI=>3fRx7<&Fd4Xa+8d(L?t2L@Q3D1u1Bk%^AHy&;ebJC9my2QLf>b3#e zH#nViGHPxt;=Ade1iJbLgJR$Uv)+SC(RQR#lMM$ZJPvvg?X{FY%X0xEb&jlriEJ{k z8{j$6z=tgT|JFTh{T~p3ahFNA<*buHq3PK*xIvES+uG$AE@^GQ(7q1bhx)~@mQETR z&TpR=cDWRqAzpf?Qbgost3x+cF!UeyADTuu{J_vZBafLpE~L=}_5v{<=oWtA0DVK~ z1=e$P^^_+u^UNkc=yE3dhlMS@3;qX~*FO1yo|%sv1m`WVyrYua(RHz{uExgg)nl;V zbyB$y_=v}|&J+pj+X}Q#RSfC{D-?~uKlHH5i{T%S^nXUqgZbg-J`Im`l1Z?8Ewe7` zpZY$-HQ>;tyDN$;g!ce?@3nmz5z+Yo31B_DvJm(J2Lh9vp@!bC>EXNecM^B{^Rn*?mGx$=>IqzGW3s+OqG<>b2(IZDLhY!QzPLJms*l^ePslKW$+U% zbQ02&PRcTnh53M7chm0$?}CkK-E?5!Wto+r2C|uDrBE+`b<{o_>z-S%KV6E-IdT)) z^YY35tx%gWr{`@!Y$JsRfeW(wKY-7ce~Z9VtHF;1{&>UqPmY3IDxq)hfW#L>A3g8{ z*KOj7>Dw<61s^~8M1Fgz&-5|=oc8^V7y^2DW_4V!+fLAx?<@~)ZYdS_tQw`C|HE&F z!&4dh-z0f7{tE~7sHK$0>$(H<4FbxPp~v9y=E)DZy$~)QjK9n6b(tM?@pmD=EYLyR z0}-=tmkiE#sFZ2L+z#&db;qKkxxG4&|DgXz>PG2aBxrQYlTwJrJLNl0ZwU))R5N@= znSzk7$R7&AEKY|1INi8FnNJ~vF_M}iWwj%LHRepW-5Wcg|NY568sDi zETHF$px?U)Lf6ZzU*t;b@5(_q|L^qA@KN+V4tVmp&K~((y9GQG7kQwX) ze8hQqaCrEx(*qtsicE6%2k@Bu@iznCLB}&ef1q114y-e@(9=+BDB_Sbe}+c0HcdY8 zTA-aD)K3n)huSdM%9gfcussU#D(^YO%s0|qc?|9X`QQI4ye-eq;w`HVgFGF*LLa0~ zX6z5Pun7F02+-~O1m+-_-_`xFcnQXP^rsL{gmE;xCJse+SDtD+j!%U6Bt7w{f2;7%Hvw-eqnke&@;U?s=0_vqi(;0 z8OYe8`Me0QZhZK!2Cjnr$0}j}foFYk`uc2m_dzD_l^Km>V9=fF^*mPoL%*@*cL=0o z6OY1hCSMlS-GFVAiFW#$kc4YYg8UmG7Kws3hy%D}0WY<|Idm!I?96g(b>>$7vojfb z$j86f%hXcz6eOli0)?}(_QY48IAy*Yv25hjDg)@8k-4p`St>+a&w zPB&>}A{-!oAyEu$Eym;Kj<)Mm6HGi&3G+G_y@Qeerfcya|6Q<;>f3@TWBvRpQXd2V zz6$moc-AK@EW)uhPzrv%zDzr$DTnDaDL9=dV!lsAuSWhH-Wbk6l@N16Y>}P<^QJfm zA6O0fg-PeDy!r5Oj?X-3$5uI%GdA`O1lxSHBY4j4i%CiGNLTSFy1~38TUZ1hA@HYH zV_`hPdP{mq3M{jNi1ftO5OyL8E(FbVUsb8vZwF3--LO4T3qjti2*=Gh5rSb{d@gR2 z=rY8m-g~||aM0_u2gM&6&jJ7Z^8M$L|Mm+jnbw*8$9}^Zhd&tlKk%FXA1iaJlSp|v z(7#w_KGJZ9$qY%6ojnTFIz1>TjZ(1LHuBpFiir6{?G%)|7W#Yj)^c* z?v94l8^B+bqy9gbPEA0QOrAEP5UykPJuQ2n=uoM&n!;Yi_hEH3p?jeCW*FW>-s=+$ zmpT=2oe}oKWA0lHjEd1te)A`!5@s_6dC8FZ%L)$PvZJvArK0 zaF5IbH-;hUS>7tp|K$|bZ^H;FhoDBbVMH3qk$WVJe>6$x&&q$MkJ$3>5s01%Q8urO z_*4C%3-fU#zf%5`geH4mLDZ`p>3=f`36hq#B?bvyfaLoVf zk;U1Q7;4B5XSFf&CmH`2ZMgK@vjmjmH1*kxWc13z9m$y||n_6zv?@BIs`*m9O$v zBQD5wH+^f=-dUc^%!VXV7`k`L$%}5d54I^DJ2lZV0_THB;1kULis8JK5FMcqdH*p~ zV2Uuiz2^ize18lNR@2^)4&QH(e~mZ3H{^RxSdAyXH@*WR z^4?`Y_d_EE+W7B7>M6@$PJA=>@0Ol??c^`IES4dys_T#*B{BX$i2Fe}aCF`P^FF`n z|4yLG;yLSF&Wo^PPlct@IY@0T6`Ng5d|nJP5_LG8&qDqph!0>ezsXPrT)_~>o!?+&X7#@`RiAQ5#4$3W^+lv5oo5RPIEUkxaoKo|K85o`aAdQlkO=oo9#rG8sJ{?D#(U^-}P|xMbx0 z0Q96R49S5H9M)J6e*INg_N7vX1>QvV>S|k9U;r;CzaU?J{~V*w$v`i_{=8F@v{`_U zn9WmAG)w=`TWtAH2;{E=c?SXS*-Ly7W5I!}3BRz9XcWS)T}XePv&PDx{fPW$76z@cnz& z4vTvzziW5nX6o3;TMd;aj5HX)>u(Z(SR~4!eMav8M*oalHV28V7B{sS>=}aE411C~ zDP%dV07*Vc?{r&^c|7;;Ixpdoz((ZY9RR-r==ZQ2F*ASA4fjJFl!VVg$`3x+Z#m?H zfqKuSEaYZLppwtjm~F^KT1bQQ_|-IWw>;y{Z~-AV0AEN-Qh)UHBl?&3R|CIw$r$=C z$<_?GM^<3!Qn^kYLMsKN0flwj^|P`yqX4)k3O!1w2QoLFhH!X#4{jVGE1E?-AGw^v~zJ zh)?n$PUPl@>)JV}g#UF;+qQIU{{Bl3v*$s4(2H!E)l)^Th}){%z2$<7AGlnrA>yCE z!Fc@VbvRc0g$VV7pWrup`d^=c!@=+ApBaxP-~*MAXQ=C#2?KMRxaMr!T}Kc9?EA%u z-5gsT9a4X-l2cvh4XOA2JCk1}q#opaAFcKMd*cpE--wo>d$&=mDz9uzvW0~umI3`U z`Y=QH;EoubU!*N4C}2FAjQ!8Zf5!eU+)QnTe5f?FgWBu@f`T}mAQ9q)PLSt3nM!E^ zzo653bJULc@WT(yAlEU-^Tfw7=V_R~EFSe6K%kJSRH&JJv*d2lFbEER5|jgf$fv;6 z!v$KcJOfw5_9!Z5{y*b?%=wl6A@2mn#1*C_u0VcDRUS@{g?Q-XPqxBLK=9)g%I}w8 zMCqiR)cvzC{~<-`_V!_tE3g6s>Q%tE+zkJKgd|Q+21e*ZKk#vFWBADv?vd98I{k2K zlVS`?TIco355J8u`S$`q{xi@2*FItYW)b*30+6+BgB(sy+#iQgu&!_7{wcwp%XjWX zFAWGIxQO%g(c7`5jqAOMc}19Y`qZO8zoW;bjmas$0RQ-})+yo8=I`kr;?gkhpV0#< zD;tFhl+y=^n*`U6sVRg`SWIw79^v~1SSArJ@B^5b{etaXmc||Kd{s*0j>gSon)au{ z(-j%C_Nf*U^amzCYdLPh7`kWderQ0>)I^dxZ2zzJKgiV0jQ^k7Tt?X-Qo!(m0=j^< z9HTZfet+N(NTW{5!r|uM>=>92Y=*sV4l(kdi61cZFOq}41cicNX-CI{2Xdo4V|arG z{>Mptv!#-u`@x}~GI2GU3t>4MPW?uI%^36iUaT4REu=l*RuF{2hb8dB&|8@{8+rc~ z6kR{Ro22*QL{oED0PiuxdWlQBu6$0maNgmq3fXI z*XtG^Kw}Y;c;oTo_ zfN{=TPs6-mre^p+MKA~K3z|Lve#b}S{}KILfbL;!!vM9pkYe-@Mi20qAr5$2B+Sav zXUa*Se{qXo4`3_uQJ2t%p zH{eNGpori}D5-DcA;@&Rl6lUIU*-R4K{NO%X}T9Xje)x0J&gff!|S`>tHiqDJLOki zM#9}c5{R~8suWE!FYqk0ezt}ecm{#{bHw7^!sHb#Mpwk>;NbzncLs(ofkMO3eKpL< zIDl=!fbH1e7@h+jQ?O%L`Ooy`|J?j?df%JC(zqtFq4j{ z!(e_827v9z7pX4E+%VKk(7>V&4qW#+ zw8Pv7v$g^sMO`1&-vvK9e;9sez8@}U3yT1Y0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N z0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E+;N0E@u?uMoJKjSxW) zuEbb{0P0I`$0!7zs&dPnnWAfJ!u?~_qPe%vG*D%@TnManxd#^h?^GFqD=kfwRw9XIIRwB!#jRAo~7_ux!GmEG2IH+}TJo0#~ zB`ZZY1gXZ$JAD#kkud_HyRCHDVFe-Uw->qf1B-9$8!}M??@>wJkec zLeSMdnc48WHq{V|A*9Mtr@gsHgu#8X?^*!A+Hf@RQ&%W4a<=^ED}cxCa?2YB8}TKb zPW}5$ToLhb67_ylxp0Z*mLBa!_$MAcCyB2zS)ACUp!shYJzC>jYTew}H2J9r-^lbKzUzPceI3T{ShTiGSZS-IlW zyF2GdbX^s;=B>-4OucQkS67xK`&5q~MyQ0hSYADdp zp~&qXY>ceH!@_LG8+Q0c5uTP6^~V55!t5yDaU({pQ4+=@uPf33=!`|aqEwA?z?>eB z%t0=XxAm7?lg(cHrNfZzUujfDTUSUdmYkfO>6I9%)|waWd>Of90chRE*HNcIt$A`) z2Ildu$etu=5blcLaw;-oqiP*8S*#;nkkw$>g&%2zepjVf?Y_ZcKCh&=HZDr3(W+MO z?85nC7qN2ZBoXPP9U&4Q7{ypte|H=}AqC zYKo7_y82YmoG4kVm^Udjt0^R^tE9OX85MY`-#EVWGoK8zIY?Gto*w$$2fME5x{Kti zi^p!(m&9Sioj1G5O5doeeydEhTO?nYs{MzE#D!^T!^2|&_hDKn-5*t8GoSfradmDi zn)2tv!=LR8jeSV}l5{3@MItq#RoRk5W1W4O1?$fzBm%YZqECLd(?GhNzwiGkA|&7e zzOTlLgchz}5HD67rOhAgyEgabn1BGOBX;wNB=~$+?2aOmDp*(Q8~oQG%8B9cKY?RM zG+7U4ymSpyUzLWn-xlC3e*3C8`3UIipryj{?c)0G8^Yw#o_}|A1+VGtD(mU-dh^wiZHpit>^IEgCq2f z7(dbcHH(Q$+g=T}^L)5RcmAZ`GL)KnF}FF(_Tll=1x=@OR7XbwqOSWVdTciQZt%T* zggHojf6r-w$}E=tXni#}H8oYu^goBA-`h}Bk9!FZx9DST)N%f8TSImQW-M5uJv<n-%*Rg^B3sM6GG--T8o{mJavbK47Nbf0xP7c`j!E{C}GgR8w+-7Q`Bo;v9(QmfU; zTi*|nh&`?=V^g^jW5MFR=icW^p4!#sYIV$!tXZ>Q;X8-pqnZ;|=i$dtq*WI5G5Wh) zuqBZ+#P*wThuCZ`ymBgf^9$|wb^WoC>+%ihWjn-CK|y90xmz)J_lw))c!ntSm)G+O zme1G+d}m3*$>c7{qaR7B{L+v z@QU^4Cs;``!}weO$0dyNec8puI1c=7sv;60+-cOTOs>FfwlW?sak)ZOFw)aa9$4TX zZg=#QbQ@d*G4+Jt8!i=bHIF}8C!B3|rR@FWoc~MV5)XZQa1NsSJWJkG1--a-?d2}~ z2mY)&+Ea*6c zQJ!1x5-vWk=od+XR+XZOS6_qoGmnc?n}nXNMpfn5P=Q_ zRw}mhCs-SBTD35F{dr%}!Zj=AS0$GVzs$}~KbgRl-1xHT=j#i&l9eCK!q(a0_iw-b zW^AHf5S#z-XM6`PUuK!ehdNWHM{#wd;|WFSinfKkbiPzw)eS@*+RU zuGZHsbkr-<@SR#wk_gYq+0fGyj8KW);do`SZ}6gp3m2|PTqY6|9?z+$O%n5P#;O}J znWyo{wlt%mQ4r&2uQ^t^B~drmU<$9f zkj`CDWW7qS`Eb)BPm843bmga#bwpeP=}AZ^v3m&4cVnZ}nl@KSZV`+Vb&ft%0sJ{{ z!yi8F5f+w|lpficAsHOXNqub3^#!xv@~+-lyEJBV`C?c9iKYdmFF0=2v{dWU)VZGF z+HouS_FC@`_S2ZtIjAvZHwwqiTl`6(<829%m#y9;DQiL~bV}jcE@5d&hb}!mUJ|Ch z`}u`^l9kK+0{mHinpNk0Z)beeniX#rj7{cB(ql;yuaqY}D3MBiqU)=sq-NSo zThfKyL<;V{)iBpuF{r8kwmVXpq(5V+-zTV>?&!yNG~iYKCQ3nyA~X9)LpK(Sf~L=& zWi2{^<>qFmhuJqtKz%d!4ly7#Bcpyl8g&o&s=eZrXu0UT9s;!1Ys&yknG;d12J|Umvb(8!dhFUrOdVSV6yg; ziOTJuCu&lZguu4~xm?BF`4fA6T)+qmg__5U0>(+F%O;CB0a9`M?cn8NKOUDJpxaG| zlDA)|4pSQphR{h0LCKBQGogu%(MN%=*|J`anmyy_z}EH4qImX_=JIP*x|Qon*R3j= zs!*wdWc-~?(S*uCy`B(@4;2t8>7fc-Nw{3cHuMR2yk^}y`}!10uS|CStL0e)adq%O z4lfw>e0q7+!7~c?&_hr1wzGPdqvp%C+XB^tJ%O0ruVgf+%jQeE|v_hiD-DAPEpV+{1W0N-L8 z3;e;|lbftUf9;JNr#*lx=Ai`7e`0!#ni`(dW9&scQ8C ze77R$v_36Op%&rB{Cw@HU=eaSq_a+Z{&HYkgDC*pvs?mjx_Yl1NLHq$X1%_0nTPmOnxPQu;>QGDNx4mVEMgiu$kXmI&fa0`iV})ys;)(7LZ_DVE$QeCPbl zhlx6IRM&$QS+6L%a0G_HjfA4mh`M&|3cW}O#{`zBz?tVOq7|Wpr@#O4^swM>VcdOI zJ6A9BHh%SueQ~}Q2 zCZT4R%TsT|4eFE>jhs}-4Mw9;6p0Is#tl7wJQ0$53D?~86Nu+<*iXFg7u=>)XH~gw zDAKp`r96AQB)9+YrKa~ci3nn3@YF}AqJTd{?5jQ%<>=4Slt&`0<8Oakq6#l|RdkI3as4G-G;3ek7fd1chhkqkMADX-J_Hzw#1x~o=%D4s4?*vf;HKQ+t z2V|E>_yI-!0of}gRF5$&dGP^kM7v9-T6<7Z#X(NI_7nb5D;>JY^?2n|`;YZ_x3gkp!oQH2f9#Mf+X1;a! zgiz|()wenOW8oAJ3 z*cj`67YDu4#Usn*0vB|I`(5W;hcr9@{|qhC_EE@PMnw|v0yumps0m8>!07d2$}1AM z>=xAVZJC<3k(&B)T?NY``i0||F8xeTOE0Q-)Rp1!mOqGj?jIF zFJCe#EVw(vs4nen5E7+aH1}>rq?i{FP>zr76tZGS}+De!naDQj9SLc%5Hx?1an9_WCe8>VDp zkg{P`cN9_g^&rK3e@g3-vKSI`f&JKf7)kQziBsRdTAxGgn$G{AwR3^(*)e{`^O^ey z6AGJtK4A|CUCZv)6CV`}-!T;82>V5uqQrp?L7gOUA;Q9-mc#iGsMl;mOg{uU91On1 z;Qkoqm>?0R$0#VbL@R=~a;vGMw?8=(uzK7MBgL5LeE(DPj`vy3W~3thDlVaO&IWM-0XcOgPqpfFp? zajdY^&yPG#t+&^NbMT+##~spu0Q{kReV^M+lG)6Axq?WqNXMIeY{a5=dd(p4Enr#n z0i$O41h8uYsD6}A%H-o7L!2>x<}5&%QcYpF92Yq3(sAW~$LG2{j#;nKg=J!~n4d(K z^&NdN52tT$M}nZl=}6#hUvSr`1ZA>s)_h#?-NXrJW1v@r<6q{4O1Zf8tt^ zJ@&3X1EC`C$)0^=Kmh;4jhAARLVU-J+jvP&8eR+;yUbl5N+>l-lcFQkC!o4YB&ipw z@`o&)i|TQ(7aVi8niSjVi7tL?Y|P%U(pjq{wd?#Z zzM($Zn@UZZCXekBm#1%+Azau#r%wYbfMnPp*N$6Dvl zM2IApMHySgFb>OLoVZ-BC#TLkhZwzN)x4HqkHZ}F-Ly`equ1L~XIh2mo;Gdn((`Eh z)Y%hHt%~GmZ4jXAl6U*cF$P>@V?tL)vcUU=r2`de~2 z=!L4$ulV&pTV|$>`L3%l5MEuSKvf=b$>~_RT$QHP6lUO|4w+PX`kHgIEB789LC2l} z^LN%^+W$-BbnlkkpYwe=B|r3jzvAL^p6pBKZl>+Z=>H$~elR`s zIF5dJ>4oX>$LweJ^AI|D$tTo_w!RhbMnYZcvmDXXN&st#8l?T(zJUlkaYX{#R+xTjxyz!olraav*%=muYs+ zkAH0lJ*F}^k1Q(}QsLpXPraiPc$FzC;M>?!FaUgtC4rjM?0|hAKO5NAHvNM}@M|bj z)a1ISPYKHUY1P)aKEaa{UD}Sl+n_hfwSHm6g72Uo%JWVOT8fLU@-7k&w_Ry-4?Ewj z4u6jC{>7rJWCq%0XK0eTwU+9qaK5aac6!Tnl{m*C|Be(K>QgE$Yj8{++uT$SxP$r= zRQRLf-DjRUT326&K(21s@UQ*P{QVj{9?TNir#o@R|EB7D8eyF<-s^Yca~-vI>D#~P zK-+PNcha3d@OaXI59k$V_v{vi=F)S&doDIfQ+aEWVK`sqD(yxYGXCVy9W>ZP#x$*U zYklbDhaO^+8^>f07vX!zCkeMz+qq7kNP}rhpN|^h1pxtEL?Xe>H%Nnz1o#l>$JesT zgj3I?wfU|rk5MhrW;ev>qgHGCEU~GIDA~G!x>xozELc-kQFNxMG1EI+tDNfqI(dnz z-dGeH)91dZ4#|#9e(B^}Z!JA2XZWA_+DD40jt}p@ba}cS7qFHh!b5v3tyancBee{%y~}>!uVWjsQoQla=1;q`l&a%qJ_e` zzP+lS##<_f^FRE{{wQbX4=SPZWQ=Qwf&gWQrwHF+N2ys=|=Ext5Uj_ZWaKa731&W zg4Ay&Oz5~q3V3JbB)$dc)FGAn(e8Ia90wersYW8-O}V?=a#g<3E#E2^s28qTFE2-E zK3K;(8$M*~SpMU5*SdV`!Ysr11mYcdq){=d(c1{$y zi-}cxmZx^!>@du{@y*V?Lo2y6Z=_iJ=yjZ{18ePhHTErinFzB{X{y~vbOOrsCI7JX zh9XzS-#E=$ETOmm5_Ih9*w})$0Q7YGsbKF_GUtW!2~QswH%{hik_+y9^;3>QBbp|S zklH&w#)35(b+Rb0SOD&{Aj=1hGYV~eBR;F$Gf?G-iqt5kp|5wjoaUt%T$Yutc^!l9 z_vok?g)D7lK>7ooc{w5byrQwEHHXFO~Mt)Ch&B9Q}y8uD+;0^z#RenwDMZo`pT)}q7Fs}2xb|13EEsQ)Ye zQD$)1?UM2BlRx8^Zngbopn5BHwqLvHyRH?F_Y<}Vdg&G|VK4g2Pm{`P`R>$P{S9B- zQKu1|-^h&_#xzyOidaFA8SKFv&@+@NsXoy_-!hpae79Ot zro+L$ku@n43M{3~<=VKjB9$P#(k^{bauD5z%4>^KRocZ}otgFcjN>m&QRJ2hO*u-U zFu4O)d27a&pN~xrviCo1bfj-gA(~zD^yO)GA_jiFu|cS`R2R;5gega8lut z@rS0J*DHos8P%(I`owTOb>lAX3rR(U%H_GfF{aPK1Gqu{r=%!9%r^;mRu6amUqd99 zXMTC<;mf?RbTYqSC-5D28?D_3_JYl6B&zfZY=%@E^x96a$26cf#EF6fq;>~sjt>O0 zF~WCYJoePCcC8{04;$8KvZ!ea5jCV$IcJE1BO+=YXk9$g>tka#Vm_;P?AX1NJR=t{ zek&aM_4AHiDad^RC*Zm1iV^vl2)l>q@KR?eP)w{c0*7_} znj=@MQvE(!QT1)@+lhvrtQD_?;P{Q#^jUYeiGbe+S+|28lMH&`KRf={KMEi9zxmvi zlWSz9x>V`a=9tX|{k`+781N)qnXIUh@{8W2^$kUOEitK~V>9Z>NdrBRbmwbT zqydkn+&QWu;WF&Guk%N!93PZ@yUy!F;aI8EUej04F*?Gf#QYy7?bhbFiOIWtBG-|F zeWC;(RR1$gHwj}g^Q_t7;+>5O+m=s-Cvtt$3EDdwKJcaY>!{NI8}3*)4p%plJu;!Lrs%n%+`eRTU-629=mA#1Tb!av4Q@Cr9fQ{a^D3tR|Mk*YM-!rfmCX*6&35I1u^`z zbTX#gaHmtT$t0*KEGey@rwCT1X^d`3hhSEa*-Yk53Y<4@-dROneem6%jT^}IazR$& z3%l_5_K8U@RHvwx z+&(y2QZ%lX=$|=R^yepEa@>0YAvo`PXM+Mu$WBv1H^Xp;_y1ji?*Mzi5F zoP*WPo;`a`?TLgx{bA4LGuK155vpNjh_y^;u{d)SxrM@!$^e(oHodUUADiaR!E!}hO#sZ_7W7`7bK-{QSjoH}|`lMfa+SsO!(94cIRd|y# z@`vfX?8mPvqD+H?>*cTTsL-u_Z6`hwiEiB-dTXH6By>nQ-bG65f-Of|Q}4uyu&XI4 zX(H%v=-&dS-x=r{VH_~sE{1-Gx~BWl@sJ`IM*$Fz5yk05QV@J5vo7rHY?{y&mka!+ zzWAAQUZDv1v9VB8FZk2my}Qaw-81ZdO$7OBhrpPYrrLLy6y|xPTI(Jh+SS~%gaTiN z2e{=3G4^O&5stZnJoZUjaZG=vdza6LIJSCasuG8{`VxLuKz$2pgiOf7yeQIP6#QQZ z=NY??Il~le#;AOjeg@+LPIJy@i=fWc!1zWHaAG4|?{zt(*9GZVmA%?_5?hMf;J$f0 zD_rM_@ZGu}YR^``T&P`qyHTb+s%8w@Ph9#J0sEY$XJU zS7jrtrKQ-9(cb$ALMeWlc@LMkWfjEj%>7}VAc%&+0Mmscj3PWf@rQAsM@JJ>;TD}S0Yr8Gatq1{S=(R@Ih@i-gfZvtyA;Cr+R;5-ESS*h2xy-Kf zxe6>bMWqZ8;mEZl+2YI81l<#w2>g*)mwr!jT41saX)lWQ3)~}G;(l#0JeQDt;FyF6 z2gg!SSAi3CVRZ!s>tC$>&Pdj7x<84}cU*lb?K)QJ)}$%W-Z2z~P!d;%QZ!m3SA2rO zNf!J^9nf8xM(~&d#jRXI%=N($v7+%|!VIWEUtPUWELxbAmBq+IcPHQ6kX0z;KJ(2f?~5(RWUVF znDGGbZ%#;MYIB>iv{67vkx5xBnGt|03uMKoVw~!?mTZc`N8<;R;2wA%*?vrftl(er z4?79(?~-NDZvuZ`T|j)6D!|{J8s@7Hnoud`qW$`l0`(D-`$WPijF1~u_G}%-mw8-C z8_R{N!GPKCf}Tk))@r(-znSs(d94C-m|d=4nsk^-nc8*s)p9}Ytl7tF{(@r`(vTL~ z1pVz0TN9c(lN?mr$IENWGAPy93d~!yhOpa*#hobHvuXRyrH(>*lEP0m*#X}ThMF9{ z(`+_>aywgriJQ8M+w5~B1s~+AqBHm%+io4YS{RHBg<}*|naZjtGxEz@G#2X;e9ewCBe7$Q&LQJ*5e0($doW zeBgaN)^T=@2x+xx>c{5Af<7kZt=ZrkoRfLRp9K9Q2o#_~umemUf+$>1;``5vgG|+& z7=llfT3w1lLKQ%4x=w+8X0(fbz(ciZtzTKbK%n>Kq%+(JU{>API$Gy`zELM|6js@H zLfjzD*7s8O(m7F<$Mu?Nngda4l`AhZ79n>=Y8pP;?}Q7~1BPD1t=J!?0!5Mef7%Ce zU7*z%nvc;k>B)qj$8+M`XybzM@o!f}KesG%Ot7ZSo?Et_=R;`Ih+8Wg1ZHtb=TF(z zDCJwFv7bTzt5dU^JE8x9zT5`TKbg4HuGW(=EwWu{DzL9_=4(JdJr&M@XKy@=GkUPN z`*@+@=}+Dg7q^y0re5x{b~n|}O>bI}x~Zu?V~I3jez&WBZf-{R*7901Iw{UiRs?n% zGY&po3HnA=x2ONBlQFb3VqCzUF^Niz+Gth4_*156TEY?5+fppM0C7gXs-6CHr3o{3 zjeBX$Hii$XdJbTdFrzUw?eHES=oi1zpR<=K+=Itwm}kbKtPRT6w7+6Jms!j&*sggV z^oGmyCws#4+ouP#?^^WYx0f!d9|l#Rt>8Cj`d@RkElBA*)d$>=;%=mQk_Y91Y>E#7 zeD(5Q_F-vPk6Dg?a5iz>$e^>$@z_FUd?FzN|E||d>2M*jW(_gNCC3SHWN@#DHfLQP z@Pc3OnhZoFt_>IFq@`&#eSt6sPwF!54%B$);X_BQ%NKaG z)0>sW@iC=YN3#fe_|ux;0pR=>H)BWP1M9c z9r8hyL&_e(Fr(JmPAb;;2l(-Q&gK>?G)H>V#Hr_ah*GO=C?vegFcD~b@ypY$PA!S` zPmv>orfz#!3WdZ4O2=O|)PwwVO`m2(h#z3GEVLF!r4_6^bGQ~qYISNV{_FGixp1Kj zCQub-h-)o~sJd~k&}b$OMW5`_Wu&-vJvqgtFphmosoGbI8;tPY4ael6&4m?~Wwl6P zh)Xxznui3vz0IY6sqKm$7cskbd&|qI`4CtblL&D#wSnC6BEu(K#QeqOf}e&~6kkYJ zU_UO#g$ORE=;XI8aj)aH^sq zx~0FnAFRHMFz&=8jl96z18`dY&}gBY`0%7EB1MySG6xsH=gFPN9?}1M=kQREtpDNX z`#MPjbZ|oA`UEnhn2lrQviJHLe+`Yf5B`}evDJUo?36$`jg7Vrsll=8r$(NSD z+<;bgQkI2B-98>~1n2!Dlg3Lql;v1!b^4Kr0QncK4Oj!n6pL2f7ol;@E$U2={LDyiS8lV`(Xamn5?*QvtO81#KZ+O>KB_ZNv%tK zNi!zKdB>PPKg^0v*hbR!ddIGhXWxSjEV{?d-9D3H#sFWGJzJm7l$DSW& zr?2E)xUle-HiAffM-oQnzxCF$i?JCRm`{g8zk44J9l}GA&@L8F9rJ!yWT~H6W^wN~ zAr6=49`H zFOwv1fPa55$v}2RgFOJ>4dnK}l}Gdsfw1YJypk2`m#pITU|$`uSO4M3a2~KLen!;n z$06<*uuL%_Ag)t?={5gtJWXl}kr=p*7XhV;>Hl4-HcXlR%%AxsqAzY7SmLS;F#Yv{ zb+yTzvv<$!>bzb3pT9V8Ud{o(#z^BcWngEk2BoVg=!bRMCJ~M{XbTpjxj0tb)HHu` zBbr<9)vESiM~2zJ5E5GDN&l<8w~uP#-2TNU3E)gZG^m`0*6IX^5)c7TQ^D4n09pZU z5g8I8F0esu+lPPEEB|Bm_`VQQNNp+o~W40*a_@1Ybga zdu)5x_uSvTf82Hd_Quv zS{3S&tb|0097oAGISz028rb_x3C=$CTYGUweg8^7e;v`#u{K^J?kz=Oe}FiA%D=rl zoRIbpZ1?UW`{-8hU&Z7-fCTzqbZWv~@>fA@&8Yka;dkS@3kd@AyG>OUM zxYJG?ZfLlI?Z7~tk?w$TAAbHkyA~+<{Zse0u7K?k`~IHm$qbOYXGSM|x}dCY{MUP0 z?|IwJN+f<{NjB%W&% z%H2U=FCD#;k^%v5d>;pS_p7hI!uOH-D)?J=a*$Q45)%H@|8zLK2MoXHV~F7JEd=pT ziQLEj^0%^vwl*Pik=6P|Tfb1M9;_?LA?08E;Gg=jNDKN2+() zUey8l9M~;__{bM$9eZBL9SyC*sdl1vBt8@ww-<=6c!r_T;674$oM&Z?T+*`EbC3YI z@0VbAsOzjm#6pN4NP8IPd7x)nMC#PgN*1-rN~DGMu_t;OtoK6J@>UU&UQ!R!52s}d zd^{olkyy_w4kIWJZadSzWD8EpRqbu67Ud1Wv>TLSi&tX4*X0gD&fG(VWGpqVgat|E zfjvmr=sP)UPyJxRdqJZ6W2}bDchB*f z#iT=ip=4V3I#AE|Ef#%Emm#M`(go}{EC^DD*|&BOo;1q6r^y*o$%A9cel&Az!JN6_ zoz&H7Te*>c`^Lta0?xsEG~9nO4$~5$ zLp&Bo6ffbQ8chr7Cm_`4;~~!i^c=q{&Kz~iyc^pZIq<%565eVp+t%3RAEl_mUljP3 z8#aZq3JB3eu@8>e2s<*kObBt(MtVZWy=9;WGiTi1DllkGYG#Hft4A%9ap1mU$m77_ zW_DY*2-t(zn-&K+V?x9Niqv<@*I{H_`kS#SZ$KKHCU3N>ajz@GFR?pns!A=1tAOu! zeYIeYh62x%7%w?F7w+4rcQ3l-hwHG%{ABivzH1fn~wHVgZ!B9?XRCWyjxG#h+OSj zmP9qYos=J-7sScGg!~LXGeUC|N1ubEFiDA{3=2WH?7&g#c7ixpEkN_B5ElbGh!~_3 z;ovt0Z*D_GCrL%aZ@A2(Bn~u+D8wP=s@ z(Bw2!vz_a{$aMz2!2aI5uT7P?yv?9e=R7U+q0&!wZ|R>M^We-iW$UflH12{~v(~ir zrto!Nb)xs~mB#+kS8{paXte!t0@^*55+he>jPwJKI~9bubi#ZAG*d@(-gk^N1yw z8?&`k?ejBq1tBf3-CK2J84N!?&w{Na0;mj0M@Q;HRsLr`?MjCHF{_`kt~ijejv`9n zBjm5dlH(3`NRtw1V^c%G`q!%XBeGfsLeVXi}0f%4_3*>s7eOL+O0r_RV?QURCfr9hSmReZ%jRC*j-u($h zJ9zr*+n*k+^YV#&XYV!&)G5fe!gb{ME6_W%;4{_r_0u>Q(YSc=q6Jf?{&eH!FW-Fi z^bH2s-}xWRo0_4N%U!3Zvi9%)_V1s&9)Wz1>C@k)a*-wdZ@o3Su@d5^7Gl-yq%^^{ z%KLPv587aT`Dob*8V}?RvSznu$fIjFyCWVo? zkki*Ae9^% zF^i5#;$*U~U8i6N`B|3z?#odmo9LF!iFWHL!koKB+4MMwE6{Fv1^wDXwU}FLLkjHU z+KTH-m8(`5EsCd0GTOO15qB)Kgb?|(tQ~0EbX;{)w{dJsHbQL_r4B5Mk&2auin`ez zMr(0i-R2hj>Id@3r5rEtSMhbJ2NW!SZkMX^^1QG(HMPuACPbkAC+9KCKV__Jm~t%p z&4GKtBFIBaxRvZf$a*w8uJptF%S(!a^$yFQKJBg9nAPA%zcKMIuNv?}OGaZ2x|%Y| zuUDeI1Yk()c)bYxHBzY-_ANEUp_Hz@=(ERFRjF@O(cRq_1-yLwpReDzcJ0Z&>D^zE zeuj5H{Pqp7k~KRy58bbPm?kuBaghu)YhlojO5=bXqSka7{RaRZq-XObR|#aYoeb)$;w0`?^a12f-5 zaFKl+soVvADbXBGlGgr(k4&0@AF zm6M`E(fo`AVkjNdni^+jKk(n3YxrS7!;d+QekBp&lgGbQNxE$BT2$Np{f=!vVEJix z;M}$)d#Vlxf;f@=YB?XAu`#v7cXcT1bc|R&vN4PeiObflx9jIOW6u1vbC0JIo#Q?3 zXQz7`nKba#ezd2+erQ4C*tcF(kiWr1ty^xsOvVMhKrNAqKzt&nzL_~oId#co@3;0` z=W=+{)fxmjuyie_vXsZPADZ#Dzd!fArjNyMt08csA;18v*>$rv**W0sWq|r$^bLwZu_+wTgs%=S{-dAT?crU#ur)tRd zeBgrvM2dyjdwZ#J+4v26vsI3Abp)ZjT;Wq*t~Gj}p=48=WCfE45UpL0F?ZY&tfrgP zaUUMI6MSHfP`tjH5_HqZx6N&%2-7npqC93NcEa16I&0216p{3H@SzV+QEIBnHL{uA z6qNwMXHBv}osOv7f-QE|(tUNeTpMt`hFZ92!J=uJvvIOZ_KOD?O*ZT0vDUBE8mc~W ztS6d~%1z-N0v~!wd&QQgUi&$#RJq%pwn8F#Ni)|{z4H3?y~O)%Ta}682SZCeCSf!4 zCtijZxw!ez3Of$(SF+vDUM)53C=aer`PJ{UwZ-U@i8zt>o@5lJ13%@!T~76bm)Y?ZkejZ!0KVS;e`PSIK zykOZ&u6Xvtx>u{KVBSfjx#~g~f1U2N*XkE*Xh%yh=31WTBr1)9%@02k1nYn}R4^Ds zHGqGk;CxVd0rQSrB8*$dKT0Ph_^UbNW zal38tJo_{ae7|7bEZ0&nWbH>5JISQkeKV&uO)i@$G3?fT<`G=T3|r>=!N>w?epH-@{p4Dvo!AJ=F1#y_lqAw4)-e~%yO}0 zV82(;$ucIfY|m0&gH)ch)?)yju-k2gmt8!vAc0nUvpH}yJ?>`uCjy@-BX!4GcCST= z#hT%z#;S;Z@rJX@b2p>P7)e|kdo$AAWN*5@pS}{K6;b(zSM4(8Z?K&*{*Yua0@KHz7==! zU({%;TYQ)&mTQm;Av}N3@Q*%NI2dGwglX4z2Elrs7{4l?M-;>5@c`t3;!3Ul7tn7fc4t#dEEy*Y?VEtl#WNek51=yQ)2+GDyA z7uH(IrfUmCHKo*`>+Y749i7EWQ5TQuH|ovFh>jM|ace`N{MT5ty`SBvh>5M~SjXu} zO%y%YJizknCJ0}hi^s=WKB3=Hjn28GCTdWK6oYtnaoda@YWiY>t~zq1-%&%&^y+yT z$7j4I%G|SalYX!sGk)_}8=p=PCu>yM-2n@T>j(YQWH+vL?XA14*jkL%zIAd$F_Dp- z^I-m6RzLvLc6WbRyt{!p+JAx@sUGekR)rt&fIx)ZrSq648K6$-^uaWy0%Dt+7R`mY zc_GSyJezNR?RRgTiZT6-&%Zk7ey5CYdA2o$X)iDj2fcM^K2#;UUtSnL50Q5oqP^an z`S3-y>Y&%+S?|ulv@_pxr>~O9#NqwkyfR~=XkER*^3D(ds zhZ{8A8v{LG?2YxI4RmDK2{WU$wY3v{C{$BvG{fXRMB4vdjj;Z8?#6fTRk6!)jf@TR zAOq?cVJl}r&>G=nKz<}l5b7Bmtt~1uR@L3{X}QpoeHi`*W){&3l#Ig z5w@Yq`R{;U^t`rwAV~}MMobvEH^}-0!kK~~_kognc#{FcNO}_j_9R{WCw=)R&DSHE zN;U^+vFj_%Y$ZyCLVq*JD|JCyngIMS1P{Z?j{^lgSs+KyJmDYlAwB#)JPrbCIsu;} zc?yCkH$lAiXh|6?H5MTk2+o84-iT2s&XH?je{e6aeAtH*28KSVKGGwxR76B@sEx>M zu#p}nv54nAdTz`*(Dx+tS{T0^_&%vkk?&9Dg_2YO=e|H&{`|b^PbvgTJ_q?c6F_mG zssOOfBpU=I2QoFUIHcM_$8p^{mI`U z&-s7Saq{y&?@kr1N@Oq_nstWR%&V8 zqwgiE*z;ZUcLmO^XW3h_&edu8hbl>SH@*V{H1lMp&? z<-iIz!g%D}%G(<-Li)?Qy&bL?pNJDTpYe06h3~hVSO@b(1YTRmL2_WnLKuG#Al==> zavJS)oW1*vMAPu|XWiW^JVj&oGge4kd_R0}%AMmuj*lo7hws4fXBGCq_!6*h?<1+D zlQv{7F9g40_>h84bnV&aHPm%l$C|{Gb+z_&@#TeB4gI}{CKi6c!@sbDy zMY9v^7Fd{yAq0hRAk+L9@^L_4sCrkd-d1sb%S!9fc3$IMP5d4+-=6EX3j7(ITMtm8j>*4sGaMC1 ztD?zwcN`#dMyntnip$KuR|WZJYR&V5&K`7wb5izqIHHou>{GIokmt{(rXCic;P(;Z zz_hF^QZ8w)k?YtD<0_HExIY#`*w7C3ec?kTR0PIf=z|myR`WF>KHZt=+;UB;205{; zGFXV@=H?fe263GC{iamY4Ossst*sEoo5^(M77iic=QL>)cR&s@X;cNw2Pj99^jyPn zCZ#B+{5Zmrum3Q@)51l${6+laqPY+^7KxMt%P~@Z+IOu1G|EKpAr9IAf$`*L-ak{|@5ztD z+atk|;QgbJ&F@qp<{Mg8N;VPK!bT8~-)ZHwIJ>!!16hr*6TtWgen!aOix=Jz1d`{% zJ2>oYCRO=9h}Vb+zDDzE{r?SNYmQI<8<$rEa-0wKN9EQ*VOI9bl;v)khjM`iF-@G0 z=`opTEF(|Y`27FG&>wDn3M8jhL&@*evc%EbY|6BkIVuhq!bsyiHjLezj;&Qs? z5>F!<{n+i363%P3cFy*SooIXZg5P)KaTu!8Y(e#vkN93u9sw(*=!cH)F~u&Nf}(LSVGV z1p7SvUe7gH_kinBUJG?H6dF}iD-gT|g~W3Bot5J{nQ+qS?9@5z8R|$#J~mz&~ImfZ0zx z-^@Yg7BTsGWwSkGc6E;9)q8LoB`#442({ z)Hv@rqq=k$T>#JNlsSyvbO-sgdzd91pFEgUeFTN_5zyn;zq{VV9_zwtDu7lVI{`UE#>GepJ zTFWBio!S(LTLS&-?|+UzVmkF|{0VX%kl$;*fv}{~d_rCh`v9N+ib^C>NcBZfMAJ>+ zDG1a_)e;<-CoufP1@Om__lIm+H~2o{S+oUZTES1U8{#aI7$Rx^5y)S!AzCt)K)x+O z9D(cM35kEXQ9%DJ_#gB5kGFFC-@yR~2OJ!5aKOO<2L~J+aB#rE0S5;h9B^>J!2t&c z92{_Pz`+3r2OJ!5aKOO<2L~J+aB#rE0S5;h9B^>J!2t&c92{_Pz`+3r2OJ!5aKOO< z2L~J+aB#rE0S5;h9B^>J!2t&c931%X%YoV;93e(9N@$8R&kDd5oPEk=M3$XeI<*pq zvJLkZmOn!yf2(WSbgo+sfA790G%eIm%A_rU6+TCcXj*SYOCZ#b@t5aR23q(=TR`sY zkZf@r@vAW$A*@XQH_l#**;F{3|J@GE?PGB#Hzt9L*j|j^4UO+*%lQ07p$DMfx=5To z`=A%};ZCM&;4v@H9d~QaYl4YYJ$3CjB5oT!yJFivKI0dHqvpxF|L1W{h zMU>W1pYO&_1~jVyzjo5wvv3uH$K~g$`_tM`gEP1PD)hrWVlbR{P1+X2ttlYH=c3XR z)3rqi(hGHlh~`2F&Stt>GKYlDfY&)(s$^fD`tqAgTzmINZ&>^ph676@ zr%KiG!6n$=ofuo^?nC3r_a>TG>~>md`MIiY^Mg_akyVg%bfuO(IANFl!*D6&=>6W_ z-EDq3iAKKe+ovl+N7GW$P8&)&Yf_`kRXeCW!s?HO>cTiV@e+~YY!W9!nM1f-P39TP zti)sJui=kvO8s)rnxN~k(gd=f@bs>{#toU?y!w~9lJas6ezZL*J!yXtPC45AIP8Rz zP$ZEiRBWU8kahd(78arXqaz*ufcHGHDv=lr$(#Z8l!CF2-N}U|BbGjRdv_h**b)qQ z5ozOlr+uX6TP=acx09HZ(5EnZ3n>$2_^W`<{p|eNLn1Hym;MEKVXx zh4-h|85(^qA63}Otd`kl-WMtpiIF++p|}VdAa(9=4ee8GJjgsy9Ko>L)n)aU(jsh~ z)_)jQgtnwdMYTYm%@9b=kCu^j=EOq`C9^XpDK1%Xgh&Dj|67+pw7Tqrx41vC*6jQ(Zt85QXsJ+(1N@e4PJ~lXxj4?~ z6QlKEh(tNz5kem*Kl9tZdpi$)Hs{N9)MLDE4pV&aSd7(1wFe&@WTlCtWqn1Syv$8` zL}+9mo55RjaOs{qI966;9H{QadwX+aj3fl{s%Y;|jS;dY>ZL?+NF}=gDzAz|D%g7D zETPyb3}*V*)oCsliYLhu6YqS<3Et7(_Z<2IvjN^mQyWUwZ8zTHH69MCS#T(k*SLl! zn>cf}?u1LIC2wb-AeF4+GWwSnLLZIOgDHYaIolZEN9pM;50(vUHTVeNasV(DGNK8z z^@w9R8xgepEY#Tvgh*VpoLZrQzMYmv|Me3BmDNy1oBGuIKUSA%w=r+^ouZ!F%lC@E z6PWTz?5C54)&@0t;`-tXEk1E6TF)ePg`3?z@zT7qki}iFplNMsIa?Y}XT*+Cct(a^ zA9$rAUZxtJP(Xd@$ps7MtZ(y-xA>QozIHApr;dV^h_6H)C=e{`sK62QCE)Txe-XeR zAo!xQ@Vqum8?b}J0(gGe7rv<;On?4@U&BICDpf!6BC2lw#8bd~&70@jWh|>H?=uOE zJO)?ryByC?k&ojyO+GvdB|z}2DbOU(6;=ET0elM#Q~V2I$3j2cNujUmkKH4n^TCV0 z@wlRk$g-L;ga4DKp%<}|BI@*~w2JW*m3YNd?|+=!T5>;0AxGyeWXDhXkqT{R3$naU zAp$Qek!KbnXq|ys(<`L#M8|5&@9kEE82f9uE_*m3i1Z0MP-+$)KRxj@tW?7y`wEt} zttrLIu#cY_FBYv>@rCo+_!GwHn0TU72l9D{rvLiWbHW5g)^dtyfzJ{RN;9j~fa75|(U?0o)-r;Lm7w^p|gg{*BC- zG3VV#PrS_cR#D;JlZ&{3jx<}vfpKM)4gD6L z?irbAYpQH5(uVjqOFY2wBfSF)!pa5pj%-dcf7-v5rS#yhCNBqgRADp}^f4SAfrBu;wNNMm7M zE1Ow1(tjtpoKrs0MQ|i->^*yC1PfNn+1}G6yBV~-G*v+!~(#L`V-4|MQ4xX`JCCj@;(2Ojj1+G%AFC`GBBVi};Xzn(mn>VzIhFwv@wR+hO18uXajLv^H!_+QSJtK0bc4 z#mI@Vob)%e7?U@*oxjjCv^zPZL2B1PA$iT(0u*kYi*xwiJ{sgFnq4}Nc zUs0fzk$rn!0C4{Ls8=|i{`#0U=%+%}3`A@}@>GL8Wze4mP_F#-&=+|qNgBHz`o$)! zPA!|eqL5`VmPD=D4>%!&e}&U-0ZK3sB&Nx#FXt`c!Ts%NxmS2pMDyG}>-vEF>Rw_THIZZ^I0QB;B)iH*-`3fK&|t4FI|;Xgw^@7TVt5q3odhjMo} zbz`+M??zRrP*du4Uqq`%0wtMOuXddA<}~sbHAYn{06#~q_LNxraS#I#gD1=j3rq;x>Gs>;Y+L1IUe2AG;lGuwLzSuXj4s~0v-t`iV zHTwVdUDfN2S{(h|fKbdTNq$ti0FlIO5-sTv1Veu*VoAMO^UI^h9PSxB`cjoj)_)1{ ziOPtVZH0b1fFsM_QN3B1p=@DpjmP1>B8d|RL5=|M*siu@mc`O7&P?7ayb{o8-MFeB zY1)fuKb6$5Nc|viJ=e{mV-Pp;B0}lgCy4CBX$vc1V(~ZJ3(A#=L`k^72d20FaAid> zz<22)8*s?+PxZx~kB?8Zd(g2%hYlUkbuUYVZNbmIsnv_B5kzzSm6$~KLfYp>;@_yV z3&jW;m7YKdmw8+E`9Mzyu@DK3O1Ei2FN0-jf=;#^0q}YS^wXR7gTcCdMh%|5 zVEz+QL0V}tuF3{nG9CqC@QKl(5NNZWO*DMLNk+dj&@`7~IA|#h)DfNnJ=_6#=m5LgT(y5`{DMR3qLx;twDhZsZGNMnyJ%Q{_PnvBfL|-O&(3UP zahWBh#qm@m_9VY-#bzPOj0#mc?|}O!Boe32q^&HwnEu0oTM;Yyd|N|8$NbX# z=~Bt~xQf0F>FPZb{JDkeR>n12A}x0#jK|D%m-o=p#`xUHmk&63gbL)h71wdVU(YTA zJXms^dhWs+1biI7eyxI4)1o?ci1`4`mJDlW%^pPol?%~fO-?-~Pg^7RYliKaw%ao_Bb)Pl`e0OjE+B99_(&D9=OFi^QxyE~Gt?agLhG*&K8Z<*J z?b@1IgeIk@tm7S`nR_1H zIGj;G)g2mM%{g(&_uZQW5op}zOAk0gJUY+<_;`b&%9{evJD{&XKhDx2UL9D4oB8=C^Ld}d{(Zg1V~wHyZ6kHZ61 zX)5K#yz1-C`1Xs>yY!9KA+`-4hAO^w0r_Ih+Fa`5ar(?Dk#o{g4imvsBa*67a)0PL zk-oYV8Vkf8xR(6_|2)xcGc)76T=S)@diu(oy3%13)=BEr=j)n#VbP>L1m%lDm zYqPj+ICA^u%ZUb26+=tUY5c)PE@63(+K<d?IQacXv%Rsucf(tb`Ico+L-N|52Sm%i0Kh^F+p#6g?k4|9obLs70w=rX~1WwKuEBe7Fh4c$?Jgn0KE(JB2W@l zB;Zd<>M2^dmc-K|^%nB`RiL+6$aA>vKjT-B_Z@=I#|@-DqvPNDZXE}qfA{j4j_Nis z-g$Bh;9x+%qS(p{3Kp@c9i#oM4UX=~u=HJ1uvPNov&<$XYjun&+SG%v5^^rtD;^7c zN)(Ecif1@mnVPCJT|?0Rk-q2N^%u}P%^Nq>d#o{5?~4}i0Q&lDXKwh33usi>h7ItT z|E0$pd9QF^EHjQ>;-!=gJyS)k@d%J6tV)T(U+K9@R;5W?uF-@KX;T1?+&BDZEi{EM zA2b8rn?w{Br`d;~F-jT@`4Mn@<{a3E{|tR!Zhm)|#OJB$F!gY&*CIztN({}nTrsT7 z$fpe4N0rbiqJRGq=tHZ_{x5xbxcLki0dju4Q>H|pA7xshI~IC+P%I;Hjz~SfC0Kzh zve^iye*&&e6X1%JD_NSJ0+>%NIM3G?(d@)=8nhjeryvOHZ!^A;s}YuylaolGLVV;Y zX~cQu7IYEZphj7X{!5j#ra1lx`Z+T-ac%q>Bo}`Fzxw?h_jho>!2t&c92{_Pz`+3r z2OJ!5aKOQV|93c08-kz^ueSx26x`uN^~g1VEo)L~F{BKI2zGTOONr zM#G?oS}xDKzsor!pphW9Wh-%Yw#@!v`uT|CX?3%H%$WrCx>;~HUdgMhyiH&`guE7Q z(FT1ybUHl#TcS^lSJ0)8vk2w>!W5&wk?`Eb5#*}lWht4}tVW){fwAK-uf{U59r*!p z^G8~=f?x5KStTu*lscSM7M7V=9f6?P{ly)VCj`r^Tz}@g{{Ex-YX?poJ{~Fryz!dw z+B-f{RlJOwL*eCdjf?$_RZ4~FGZDSfghTw=f0dymr-k}8?WgrZh;IZSzkQ-$CuXSi z;&+zKXIi1pN0bvFsqeZGYC|FpE;3q*CXfgzG$OpT8$oiiA3YD_;pj?9CowwFzp-qn zn>hC$h+w-(EehMIV1EVi`tail9Qs2`TZ=p+bsw9RReLIgqg)29q^L5agXjD5r^cEz zT9cL-O+Zj8qc7u1rjSK8A_z@3vljkv)KIZX=+V=#bwIgY&XUzN^36ZVahWW;XFH4o zVezN=uL4|OlUn-o4Djz-$_gVQp+AdU-kX*nM8|T{#!Hg~Xjfg5ylR(ckOeC$D*Bp? z-^%rAIhCxuoTM;xA;ceZT1q}l3P+ll?IqGr1OL9Mx$x4{x9%d=u`%x6ygum5SZ6Bw zMTql_MvKPgyc+!21<49IPTBscl!IJSQehc>I^ziXt^ojBnB|4qLNcl$V+#L`pHPjt70VAxzM7IX;QSoO@Ho3Y+8+r4m_p zB}3oII)eE2lNNT5J&!oW@WYIZ(u^70-!R|dk+S#OXldimZFaxgeRzS=tUnwN@1K{s zD>dEBUXqz9IZ;)F7gWvn`M$M3aKrQQ;oZrk-&+?Da&{@!5~>ov6K6vBT>pSgi>d)9 zId>eZF6JGr;xJRI3vuPe?Ph4N%jzOTk808csNG^LE#Q8M#nI^vlIh=4n7+ri4RwSG z?L9?Di_dUl9zFV{e@(oL+i@B;vM$}(BX(W3bnl6V4Bz{8R#wp@;jd}i5Z0C2&;VW| zv9PHH{EbrCfM=XYuBH3P-oC`S*<~Fa0RJeKCzD>=<3!Qk7ZHBY57JLp)A9ap0lU_u zuX%n@i5i`q4acJt&|gNJZ9cAL6Io?dW)o0ZZseVPI4+wxn+}w1J+ZI$eZw4%)z-B5 zeZwS<4EkG>aS#&UmGrlfeJadw4vp7{Dxeymq<`)QpbGf=E596^N5DDhe=`E*uUDc> zZjJ6ir~v%X;yCZ0l`J09NO=FKg!~05(Q^t9e(iovqUksue0{WlD6T)xdS|~4=sDJd zwK9SNzbpE`@S{K!KkDc7)^~aU)XON6@spfyS0F+wmNIP^N}{_5Jj!psc#dHT3l2kiu~(LCxkY1M!|7 zu-TgfeXou-xAZKt-VfVAOB1r5+>}U4uge9n2j#SGtH905yws&T3PZ|9n&y3epfCiZ zFdD8TwBTzrl~U!xs|)u6mUz*xLUzGO$;hM_1*<%U)AGyxSk~1X7-n@d+{xydNkTSJ*_#1sG*A-T(wW z3jgE4e=q(xhkyO|J&vu?1RMPA1v_@P2n-Dw@yqvkM-qvP8aWXg!sI>nx(Y?s8|9iK zHDBbM4O F|37+e`t1M! literal 0 HcmV?d00001 diff --git a/DataStore_Reputations/DataStore_Reputations.lua b/DataStore_Reputations/DataStore_Reputations.lua index 5591e5b..f1bb674 100644 --- a/DataStore_Reputations/DataStore_Reputations.lua +++ b/DataStore_Reputations/DataStore_Reputations.lua @@ -15,9 +15,10 @@ local THIS_ACCOUNT = "Default" local AddonDB_Defaults = { global = { Characters = { - ['*'] = { -- ["Account.Realm.Name"] + ['*'] = { -- ["Account.Realm.Name"] lastUpdate = nil, - Factions = {}, + Factions = {}, -- [factionName] = "bottom|top|earned" + Headers = {}, -- [factionName] = headerName (in-game category, ex: "Wrath of the Lich King"). Lets the UI group dynamically incl. CoA custom factions. } } } @@ -59,13 +60,19 @@ local function _GetRawReputationInfo(character, faction) end local function _GetReputations(character) - return character.Factions + return character.Factions or {} +end + +local function _GetReputationHeaders(character) + -- [factionName] = headerName (in-game category). May be empty for chars scanned before this field existed; UI must guard with "or {}". + return character.Headers or {} end local PublicMethods = { GetReputationInfo = _GetReputationInfo, GetRawReputationInfo = _GetRawReputationInfo, GetReputations = _GetReputations, + GetReputationHeaders = _GetReputationHeaders, } function addon:OnInitialize() @@ -75,6 +82,7 @@ function addon:OnInitialize() DataStore:SetCharacterBasedMethod("GetReputationInfo") DataStore:SetCharacterBasedMethod("GetRawReputationInfo") DataStore:SetCharacterBasedMethod("GetReputations") + DataStore:SetCharacterBasedMethod("GetReputationHeaders") end function addon:OnEnable() @@ -125,13 +133,24 @@ local function ScanReputations() SaveHeaders() local factions = addon.ThisCharacter.Factions + local headers = addon.ThisCharacter.Headers or {} + addon.ThisCharacter.Headers = headers wipe(factions) - + wipe(headers) + + local currentHeader = "" -- track the in-game category so the UI can group factions dynamically (incl. CoA custom factions) + for i = 1, GetNumFactions() do -- 2nd pass, data collection local name, _, _, bottom, top, earned, _, _, isHeader, _, hasRep = GetFactionInfo(i) if (not isHeader) or (isHeader and hasRep) then -- new in 3.0.2, headers may have rep, ex: alliance vanguard + horde expedition factions[name] = bottom .. "|" .. top .. "|" .. earned + headers[name] = currentHeader + end + if isHeader then + -- any header (pure category like "Classic"/"Wrath of the Lich King", or a rep-bearing + -- header like "Alliance Vanguard") becomes the group for the factions listed beneath it + currentHeader = name or "" end end diff --git a/DataStore_Reputations/DataStore_Reputations.toc b/DataStore_Reputations/DataStore_Reputations.toc index 7e73be5..dd015bf 100644 --- a/DataStore_Reputations/DataStore_Reputations.toc +++ b/DataStore_Reputations/DataStore_Reputations.toc @@ -2,7 +2,7 @@ ## Title: DataStore_Reputations ## Notes: Stores information about character reputation levels ## Author: Thaoky (EU-Marécages de Zangar) -## Version: 3.3.001 +## Version: 3.3.001-coa.10 ## Dependencies: DataStore ## OptionalDeps: Ace3 ## SavedVariables: DataStore_ReputationsDB diff --git a/DataStore_Skills/DataStore_Skills.lua b/DataStore_Skills/DataStore_Skills.lua index eb6ed69..22b04b3 100644 --- a/DataStore_Skills/DataStore_Skills.lua +++ b/DataStore_Skills/DataStore_Skills.lua @@ -7,7 +7,7 @@ if not DataStore then return end local addonName = "DataStore_Skills" -_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0") +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0") local addon = _G[addonName] @@ -35,6 +35,44 @@ local function _GetPrimaryProfessions(character) return character.Skills[L["Professions"]] end +-- CoA: a character can know ALL professions at once (no retail 2-primary limit), +-- and the two custom professions Woodcutting/Woodworking may sit under a different +-- skill-window header. To render "all professions" reliably we don't trust the +-- "Professions" category header alone: we collect every known crafting/gathering +-- profession by name across all categories. English skill names are the keys; on +-- non-English clients these names won't match and the list falls back to whatever +-- sits under L["Professions"] via _GetPrimaryProfessions (caller handles that). +local PRIMARY_PROFESSION_NAMES = { + "Alchemy", "Blacksmithing", "Enchanting", "Engineering", "Inscription", + "Jewelcrafting", "Leatherworking", "Tailoring", "Skinning", "Mining", + "Herbalism", "Woodcutting", "Woodworking", +} + +-- Returns an ordered array of { name = , rank = , maxRank = } +-- for every primary profession the character actually knows. Never returns nil. +local function _GetPrimaryProfessionList(character) + local result = {} + local skills = character.Skills + if not skills then return result end + + for _, profName in ipairs(PRIMARY_PROFESSION_NAMES) do + for _, category in pairs(skills) do + local skill = category[profName] + if skill then + local rank, maxRank = strsplit("|", skill) + result[#result + 1] = { + name = profName, + rank = tonumber(rank) or 0, + maxRank = tonumber(maxRank) or 0, + } + break -- found this profession, move to the next name + end + end + end + + return result +end + local function _GetSecondaryProfessions(character) return character.Skills[L["Secondary Skills"]] end @@ -95,6 +133,7 @@ end local PublicMethods = { GetPrimaryProfessions = _GetPrimaryProfessions, + GetPrimaryProfessionList = _GetPrimaryProfessionList, GetSecondaryProfessions = _GetSecondaryProfessions, GetSkillInfo = _GetSkillInfo, GetSkillInfoByCategory = _GetSkillInfoByCategory, @@ -111,6 +150,7 @@ function addon:OnInitialize() DataStore:RegisterModule(addonName, addon, PublicMethods) DataStore:SetCharacterBasedMethod("GetPrimaryProfessions") + DataStore:SetCharacterBasedMethod("GetPrimaryProfessionList") DataStore:SetCharacterBasedMethod("GetSecondaryProfessions") DataStore:SetCharacterBasedMethod("GetSkillInfo") DataStore:SetCharacterBasedMethod("GetSkillInfoByCategory") @@ -123,12 +163,20 @@ function addon:OnInitialize() end function addon:OnEnable() + -- CoA fix: the old build only scanned in PLAYER_ALIVE while the player was a + -- ghost (see below), so a living character that never died was never scanned + -- and every profession rank rendered as 0 ("Skills shows no data"). We now scan + -- on login and whenever the skill window changes so every character populates. addon:RegisterEvent("PLAYER_ALIVE") + addon:RegisterEvent("PLAYER_ENTERING_WORLD", "ScanOnLogin") + addon:RegisterEvent("SKILL_LINES_CHANGED", "ScanOnLogin") addon:RegisterEvent("CHAT_MSG_SKILL") end function addon:OnDisable() addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("PLAYER_ENTERING_WORLD") + addon:UnregisterEvent("SKILL_LINES_CHANGED") addon:UnregisterEvent("CHAT_MSG_SKILL") end @@ -192,10 +240,24 @@ end function addon:PLAYER_ALIVE() -- print("DataStore_Skills.lua") -- DEBUG 2025 07 21 if not UnitIsGhost("player") then return end -- only scan if player released spirit and went to graveyard - + ScanSkills() end +-- CoA fix: scan once shortly after login / when skills change. SKILL_LINES_CHANGED +-- can fire many times in a burst (once per skill line during login), so throttle to +-- a single deferred scan instead of scanning on every event. +local scanScheduled +function addon:ScanOnLogin() + if scanScheduled then return end + scanScheduled = true + -- defer so the skill UI / API is fully populated before we read GetNumSkillLines() + addon:ScheduleTimer(function() + scanScheduled = nil + ScanSkills() + end, 2) +end + -- this turns -- "Your skill in %s has increased to %d." -- into diff --git a/DataStore_Skills/DataStore_Skills.toc b/DataStore_Skills/DataStore_Skills.toc index 21ec2ca..82b7f05 100644 --- a/DataStore_Skills/DataStore_Skills.toc +++ b/DataStore_Skills/DataStore_Skills.toc @@ -2,7 +2,7 @@ ## Title: DataStore_Skills ## Notes: Stores information about character skills ## Author: Thaoky (EU-Marécages de Zangar) -## Version: 3.3.002-coa.9 +## Version: 3.3.002-coa.10 ## Dependencies: DataStore ## OptionalDeps: Ace3 ## SavedVariables: DataStore_SkillsDB diff --git a/README.md b/README.md index 7c1ad90..987c7b9 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,10 @@ Altoholic: modified development for WotLK Ported for the Ascension CoA (Vol'jin) 3.3.5a client by the Exiles guild. Released as `*-coa.N` tags via Gitea Actions; see `Exiles/coa-altoholic`. +- **3.3.002b-coa.10** — Three CoA data-coverage features: + - **Reputation** is now data-driven: shows every faction a character actually has (grouped by in-game category), so CoA's custom factions (and future ones) appear automatically. The old hardcoded faction tree is kept only as an icon lookup. + - **Class icons** for CoA custom classes (12–32) now render from a bundled CoA atlas (`Altoholic/images/coa-classes.blp`, texcoords from the CoA Details fork) instead of falling back to the Warrior glue icon. + - **Skills** tab shows ALL known professions (dynamic list, not 2 fixed slots) incl. Woodcutting/Woodworking, and fixes "no profession data" — `DataStore_Skills` now scans on login (`PLAYER_ENTERING_WORLD`/`SKILL_LINES_CHANGED`) instead of only on death/ghost-release. - **3.3.002b-coa.9** — Reverted the 1.4 default scale (it only zoomed, didn't show more content; scale stays user-opt-in at 1.0 default, applied on open). Hardened `Options:Get/Set` against a nil `options` table (`TabOptions.lua:442` crash). Guild Members: guard `Level_OnClick` against cleared/stale row IDs (clicking AiL crashed). **New:** Personal + Realm bank tracking ported from coa-bagnon (detects CoA `BANK_PERMISSIONS_PAYLOAD`, personal=per-char, realm=per-realm; surfaced in Search + BagUsage tooltip). **New:** Woodcutting + Woodworking columns on the Skills tab (CoA custom professions). NOTE: Skills "all professions" redesign, profession data population, character icons, and reputation factions are still in progress. - **3.3.002b-coa.8** — Title bar reads just `Altoholic ` (from the live `.toc`), dropping the "by Thaoky (Edited by Telkar-RG 1.04a)" string. Window now opens at the AtlasLoot-ish default scale (`UIScale` 1.4, ≈ 1105×640); scale is applied on every open (upstream only applied it after visiting Options), with a one-time bump for profiles still on the old 1.0 default. - **3.3.002b-coa.7** — Skills tab: `GetColor()` now nil-safe and the per-skill rank fields (`skillRank1/2`, `cooking`, `firstaid`, `fishing`, `riding`) default to `0` — they're nil for chars `DataStore_Characters` hasn't scanned, which crashed the Skills summary (`floor(rank/…)` arithmetic and the `>= 300` riding check).