From a1743dc37ccc232543c541b38506732294ab3ec4 Mon Sep 17 00:00:00 2001 From: PhatPhuckDave Date: Sun, 22 Sep 2024 16:22:38 +0200 Subject: [PATCH] Refactor AutoLoot to use options instead of hardcoded values --- FreshShit/AutoLoot/Init.lua | 178 +++++++++++------------------------- FreshShit/AutoLoot/export | 1 + 2 files changed, 56 insertions(+), 123 deletions(-) create mode 100644 FreshShit/AutoLoot/export diff --git a/FreshShit/AutoLoot/Init.lua b/FreshShit/AutoLoot/Init.lua index 2cd1474..e4194ae 100644 --- a/FreshShit/AutoLoot/Init.lua +++ b/FreshShit/AutoLoot/Init.lua @@ -163,6 +163,7 @@ Filter = { local goldFilter = Filter.new({ ["name"] = getItemName }, function(slot, provided) ---@cast provided { name: string } + if not aura_env.config.goldFilter then return false end if string.find(provided.name, "Gold") or string.find(provided.name, "Silver") or string.find(provided.name, "Copper") then @@ -175,6 +176,7 @@ local goldFilter = Filter.new({ ["name"] = getItemName }, local orderResourcesFilter = Filter.new({ ["name"] = getItemName }, function(slot, provided) ---@cast provided { name: string } + if not aura_env.config.orderResourcesFilter then return false end if string.find(provided.name, "Order Resources") then if debug then print(string.format("Order resource filter pass for %s", provided.name)) end return true @@ -185,6 +187,7 @@ local orderResourcesFilter = Filter.new({ ["name"] = getItemName }, local mountFilter = Filter.new({ ["type"] = getItemType }, function(slot, provided) ---@cast provided { type: string } + if not aura_env.config.mountFilter then return false end if provided.type == "Mount" then if debug then print(string.format("Mount filter pass for type %s", provided.type)) end return true @@ -195,7 +198,8 @@ local mountFilter = Filter.new({ ["type"] = getItemType }, local ilvlFilter = Filter.new({ ["ilvl"] = getItemLevel }, function(slot, provided) ---@cast provided { ilvl: number } - if provided.ilvl and provided.ilvl > 800 then + if not aura_env.config.ilvlFilter then return false end + if provided.ilvl and provided.ilvl > aura_env.config.ilvlFilterThreshold then if debug then print(string.format("ilvl filter pass for ilvl %d", provided.ilvl)) end return true end @@ -208,17 +212,18 @@ local professionFilter = Filter.new({ }, function(slot, provided) ---@cast provided { type: string, subtype: string } + if not aura_env.config.professionFilter then return false end local enabled = { - ["Cloth"] = true, - ["Cooking"] = true, - ["Enchanting"] = true, - ["Herb"] = true, - ["Inscription"] = true, - ["Jewelcrafting"] = true, - ["Leather"] = true, - ["Metal & Stone"] = true, - ["Ore"] = true, + ["Cloth"] = aura_env.config.professionFilterProfessions[1], + ["Cooking"] = aura_env.config.professionFilterProfessions[2], + ["Enchanting"] = aura_env.config.professionFilterProfessions[3], + ["Herb"] = aura_env.config.professionFilterProfessions[4], + ["Inscription"] = aura_env.config.professionFilterProfessions[5], + ["Jewelcrafting"] = aura_env.config.professionFilterProfessions[6], + ["Leather"] = aura_env.config.professionFilterProfessions[7], + ["Metal & Stone"] = aura_env.config.professionFilterProfessions[8], + ["Ore"] = aura_env.config.professionFilterProfessions[9], } -- Maybe implement an expansion based filter @@ -237,12 +242,12 @@ local valueFilter = Filter.new({ }, function(slot, provided) ---@cast provided { value: number, quantity: number } + if not aura_env.config.valueFilter then return false end - local valueThreshold = 35 * 100 * 100 - local applyValueTostack = false + local valueThreshold = aura_env.config.valueFilterThreshold local value = provided.value - if applyValueTostack then value = value * provided.quantity end + if aura_env.config.valueFilterApplyValueToStack then value = value * provided.quantity end if value > valueThreshold then if debug then print(string.format("Value filter pass for value %d", value)) end @@ -258,13 +263,13 @@ local greyValueFilter = Filter.new({ }, function(slot, provided) ---@cast provided { quality: number, value: number, quantity: number } + if not aura_env.config.greyValueFilter then return false end - local valueThreshold = 0.1 * 100 * 100 - local applyValueTostack = false + local valueThreshold = aura_env.config.greyValueFilterThreshold if provided.quality == 0 then local value = provided.value - if applyValueTostack then value = value * provided.quantity end + if aura_env.config.greyValueFilterApplyValueToStack then value = value * provided.quantity end if value > valueThreshold then if debug then @@ -286,6 +291,8 @@ local questItemFilter = Filter.new({ }, function(slot, provided) ---@cast provided { type: string, subtype: string } + if not aura_env.config.questItemsFilter then return false end + if provided.type == "Quest" and provided.subtype == "Quest" then if debug then print(string.format("Quest item filter pass for type %s and subtype", provided.type, @@ -308,9 +315,10 @@ local classGearFilter = Filter.new({ }, function(slot, provided) ---@cast provided { ilvl: number, quality: number, type: string, subtype: string, equiploc: string } + if not aura_env.config.classGearFilter then return false end - local ilvlThreshold = 800 - local qualityThreshold = 2 + local ilvlThreshold = aura_env.config.classGearFilterIlvlThreshold + local qualityThreshold = aura_env.config.classGearFilterQualityThreshold local isEquippable = aura_env.skills[select(3, UnitClass("player"))][provided.subtype] == 1 @@ -327,26 +335,27 @@ local classGearFilter = Filter.new({ end return false end) -local arguniteFilter = Filter.new({ ["name"] = getItemName }, +local nameFilter = Filter.new({ ["name"] = getItemName }, function(slot, provided) ---@cast provided { name: string } - if provided.name == "Veiled Argunite" then - if debug then - print(string.format("Argunite filter pass for %s", provided.name)) + if not aura_env.config.nameFilter then return false end + + local names = string.split(",", aura_env.config.nameFilterNames or "") + if #names == 0 then return false end + for _, name in ipairs(names) do + name = string.trim(name) + + if aura_env.config.nameFilterIgnoreCase then + name = string.lower(name) + provided.name = string.lower(provided.name) + end + + if provided.name == name then + if debug then print(string.format("Name filter pass for %s", provided.name)) end + return true end - return true end - if debug then print(string.format("Argunite filter fail for %s", provided.name)) end - return false - end) -local ancientManaFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if string.find(provided.name, "Ancient Mana") then - if debug then print(string.format("Ancient Mana filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Ancient Mana filter fail for %s", provided.name)) end + if debug then print(string.format("Name filter fail for %s", provided.name)) end return false end) local reicpeFilter = Filter.new({ ["name"] = getItemName }, @@ -359,66 +368,6 @@ local reicpeFilter = Filter.new({ ["name"] = getItemName }, if debug then print(string.format("Recipe filter fail for %s", provided.name)) end return false end) -local bloodOfSargerasFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Blood of Sargeras" then - if debug then print(string.format("Blood of Sargeras filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Blood of Sargeras filter fail for %s", provided.name)) end - return false - end) -local primalSpiritFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Primal Spirit" then - if debug then print(string.format("Primal Spirit filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Primal Spirit filter fail for %s", provided.name)) end - return false - end) -local apexisCrystalFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Apexis Crystal" then - if debug then print(string.format("Apexis Crystal filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Apexis Crystal filter fail for %s", provided.name)) end - return false - end) -local nethershardFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Nethershard" then - if debug then print(string.format("Nethershard filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Nethershard filter fail for %s", provided.name)) end - return false - end) -local bloodhunerQuarryFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Bloodhunter's Quarry" then - if debug then print(string.format("Bloodhunter's Quarry filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Bloodhunter's Quarry filter fail for %s", provided.name)) end - return false - end) -local arguniteClusterFilter = Filter.new({ ["name"] = getItemName }, - function(slot, provided) - ---@cast provided { name: string } - if provided.name == "Argunite Cluster" then - if debug then print(string.format("Argunite Cluster filter pass for %s", provided.name)) end - return true - end - if debug then print(string.format("Argunite Cluster filter fail for %s", provided.name)) end - return false - end) local boeFilter = Filter.new({ ["ilvl"] = getItemLevel, ["type"] = getItemType, @@ -428,9 +377,10 @@ local boeFilter = Filter.new({ }, function(slot, provided) ---@cast provided { ilvl: number, type: string, quality: number, equiploc: string, bindtype: number } + aura_env.config.boeFilter = true - local ilvlThreshold = 800 - local qualityThreshold = 1 + local ilvlThreshold = aura_env.config.boeFilterIlvlThreshold + local qualityThreshold = aura_env.config.boeFilterQualityThreshold local itemType = provided.type local itemEquipLoc = provided.equiploc @@ -459,6 +409,7 @@ local artifactPowerFilter = Filter.new({ ["value"] = getItemValue }, function(slot, provided) ---@cast provided { type: string, subtype: string, subclassid: number, value: number } + if not aura_env.config.artifactPowerFilter then return false end if provided.value == 0 and provided.type == "Consumable" and provided.subtype == "Other" and provided.subclassid == 8 then if debug then print(string.format("Artifact power filter pass for type %s and subtype %s and subclassid %d with value %d", @@ -473,32 +424,16 @@ local artifactPowerFilter = Filter.new({ end return false end) - --- local azeriteFilter = { --- enabled = true, --- ilvlThreshold = 800, --- qualityThreshold = 2, --- filter = function(self, slot) --- if self.enabled the --- local itemType = getItemType(slot) --- local itemSubtype = getItemSubtype(slot) --- local itemQuality = getItemQuality(slot) --- if itemType and itemSubtype and itemQuality and itemType == "Consumable" and itemSubtype == "Other" and itemQuality > 1 the --- return true --- en --- tostring(itemType) .. " " .. tostring(itemSubtype) .. " " .. tostring(itemQuality)) --- end --- end --- } - +local everythingFilter = Filter.new({ ["name"] = getItemName }, + function(slot, provided) + ---@cast provided { name: string } + return aura_env.config.everythingFilter + end) ---@type table local filters = { - ancientManaFilter, - arguniteFilter, + everythingFilter, artifactPowerFilter, - bloodhunerQuarryFilter, - bloodOfSargerasFilter, boeFilter, classGearFilter, goldFilter, @@ -510,10 +445,7 @@ local filters = { questItemFilter, -- reicpeFilter, valueFilter, - arguniteClusterFilter, - primalSpiritFilter, - apexisCrystalFilter, - nethershardFilter, + nameFilter, } ---@class FilterService @@ -527,7 +459,7 @@ aura_env.FilterService = { local itemname = getItemName(slot) print(string.format("Checking slot %d for %s", slot, itemname)) end - for _, filter in pairs(filters) do + for _, filter in ipairs(filters) do local res, err = filter:Run(slot) if err then if debug then print(err) end diff --git a/FreshShit/AutoLoot/export b/FreshShit/AutoLoot/export new file mode 100644 index 0000000..2c83ecf --- /dev/null +++ b/FreshShit/AutoLoot/export @@ -0,0 +1 @@ +!T3tI2Tnos(TmAEzw7Du8JYNj9SPFJpusSBhzhtLKUFEISPiHKqBksfskz7U7OV9TkCqcscsrjlLRXBM1TeiqH6gvbquQtJoT7yAb)jQJzyhZn3OXUBSvhZHDmDW)h8W(b(32X8OZ(qRoMD9dCibhyzFJtG)OoMh4s)J)WkWz61T99DJOqtwJJg4hC2OiQVxihU3FwVEHKOoT2XWa6GNn0HZ9PEWJoSzR2nVqc4d9D9dGX0QrNwgDATj7VBX(72yJiooYYMGTyAzlNcZWiRGi(Cr9OIp1d(y4a2NHVffq73NeeYHE74gyF8(reeXdSaqnUlzcXlYCCVE076yE1H7B2(kZ27Fb0r2t6y(AILB0GoMEwdjcsmCeX19yhX3CiDHH3Mb2x380ZF57onbYNhqyq288MNcnpgryZrUw3diJjooZb(3EMhma2)DFGmNqqOo2lbNz0Kdn83h7XFUPLRlNNmH0M3T347aCQN2Wa7RTV74HEMCUxdKpfrc8SCFpWta2iWS3fMHqYP0Ha(0fHhTpGeN28LCgmBIr((acT)GOoVC7Dm2AxJg7T32pBNTBS1oD690T3PJPRVftTjYYfi2nXpoCmOAeliyTNRzBxRWWCTg47sY1Odfen2ql3NV)i5LTrQhOcpEuU2hnzubitpUUvU2bPSDUgbM2vCSh4AH0)ihca9PRWIrvbVbtbVbtbVbtb3yJDWoB5rhAfr6CaaBkyf6(R9)9Tp6x(9HdogMaBaLzsqUjdoP8p10PpOgy(PXwbKPx)YXUUtV(ddOaGmdi9bYHRp6CpO2sT5SeXqnrSgWgZq)aM6BOnXZb4BaYeyFkXRpOU3cK2aYW0pATdYRDOJdHHHg12GLyKLx0lbohqHMxS)rh)otjTi4LsZuHbNNVhIpGzh2HR4ngsaqb2raAm0I6v9EhBUxT(hjPDPVPg7IU6OoCU0fhbWX3EI06ypJTqYefh7poY)uF)yaCShB8g8H)bQdYRa(ZT8pT72sxEVma8xWbV5Hx0SzlgBRhTVWFf(yWTKvKft(ENeZE6EBBGMc3My9IubvXdBGFeNlJOriXTNW9A7ZoNzaJgyXE(Y6Hw4pKHyr(97d6xM3qUN5Ul4(ObGEWlPUrO7juZa8jau)0RtEkZg4i8rhWDk2XSPYdDi9SaZbutvWt2eqOwBMmRdiwOQmcMw4WHEgrUdq64rG((bdf94zFFxhjggpdQtlhNEf0nWWq0rfuwLQ6Z6ey1mmC61RHg8uWzd4C9E5ZSGhq9ME9qqb7(1r8ABeVuX9ueLokzN8uIc(KqdCe)munB61xqc9hhytsObfsKXiy6JYUfQtO5ZbvGSpiYS7Cli2Ru0xD(g6dRAfkqp2x0G7CQ8n4ttOnvvLNn3m4NxfgCd5uFS7e3I5Qu4P64LcLKBh4hcYekdguObRU(tGgIga)PpSCSh(zGJpauFqCdwqoXl14HDv1g7IU9Ud7d6UjmImIHMji8qk3ixG4akiN6K5iMcA9SNzKJiANcxAm3c)gBwzP)Oa)EKq0dQGBjqMK2luB4CLHMrLGJfkodyl2cE9i2aYoXYDmr4wZ8qxFHL0H((3GEJaNiMnb3XWAvSVUngoxqxMhBWtUDaDe3rkSCWjKBjU2bw94DDpGSiwGyna1inFdbIE4FaSayDgqFdSszrPPLatOMWeALHIDrSRlIwDrKHHiDXzVloHDXzQlc(UiSZYActP4KI9m)(KASZCzZ8EKpxSrdtmuIvtxRqc4m1NzCqObC)PqacGFw2y7WxtUqlLduSus()QGntkehsCrJzJrEIiv3qQragCLaB)rJqqT2F7VT(0R75dFmeS3WMyQMJCLefq3Whbug8s45i6lFzLKEk6IHbJfSxbl6PGB7pcghdFA7dXxBFJkXNZY69jisiVZ5SEpIaqf4AeU4kfYZgdqRJdhZxveBe7fBPWgpB(9N88k7pPFa5(5qdseDamO3NwBmBGbmWMrHwff30yPQhQQNvigKrZ8lLkNwEwQLm2SOWfZmO5tRKZbMSk1n3CZ52N4MBnx(eFlSYdOMEmxbTixJFc7fRp68p(jom4lxIOW2ZTf1M7uGeILM6Riwb5uYZlqoe770RXExwqZ0BKH6WJcPNq5T7yGiSavakjensrPrKpO5XG39(JbDylqrgGidL3D5ftuHrdzONnGdiTg(EZ2C)zZPf(BbnsA09zqmKfM)jcJuxqFa9WHSS)10R3MhDjze1guXhnoyKlzD9uKaKPjQ5pi6nNLN5061iHkvu4enovQ2bi5k9Uj9IdeoVZPY0Zi)mNpnYgAs884(E(4(FCiS6qo8I)q(J4ytZpn2kc6ETjeQlYSTc6J7ihPgxDT27fTVVSDg6P4cK6nACubEf4ZX(O76HdTa)tKrwq(9i8CPOvUFpPxm2EjIjtqThWNAx2EmKWidZroIwLmgZS4AD4JE2ucMw1BS8S6y6k2khifeEuZUGJuKJI78h)zDze4cKC(wlQi7aFfLegj21NOxPPRprX14wBV6CAKgps7Iq18grJDwMUlspX5SKxoonk0Neso7o3ok2AVsL9PLH7FE6KbTcIO4gUEU)TKG0(p2x8OPxZEO21HuWd1JAOOdAW2hit)B9GXnITfR2JdJ8h2gOQ3nYb32vZXI)RSRSnwTR2dCWm0FShiualCgyaA1)kWOm0Ipe4B8E0v5SjWwfDpE(X9n32cubXJoO)0RFbioTCdjtpHcUi8Wad(aX6M9hhyfAAnbLWWIUE5Bfg4F(zqGdH6v0q34W7VXs)4fpQQazdmkMdTShqkbCQDsfWtp5Pp9P)B0Hi4(l0fNcU1d)bbKOXbEymDbq231LF4V8OUtprWS6Xo9dmdG(ewevNs9UznewRdW)A()qcGd(xatpoCbUkNHA1IH(gGn0qRO1QzYgalcfgX3LWgAT1LiVa4cebCJEdJ6EfjcdJdhEr4IOVvhxYatzNrPndc8O)zi8tCyJNnPPru5eGZED(apH1HLVqa9BS6ecJDluk4Xc34f46S4EbT2M1tjqo2RNphVYGyIXTqseeOpmjco7RyjcEOdFnmlOctsaqKGaMOzggQSUPbpyTx0uGKNQCFxUChNhMmxIgzL7kJDUK9sa)WK7YzFfl7nh3n6hBXVGcv1a2Bo0asg(xjLabcm)6b82Q6sJKje35wlW4BdLaJzPdWOovnGTNdna5GRmlyPk(zZEkHptk3gJxAc8DeEJcO2P25V64r5b4My(ejthnWIlAIfmHyMbRaTj2(69dP2Ky7et0KA0OIQsYr(LxnInZRy)hGxk2UmDSZpKI9WyYlLSFRkk7tn8V8kajt)kwl4TJXdon6(Vc6aFsm1QYNTQye(kJDEeolVG8LiW8lEAcnUHG17YHqffuUFDKtREB1pj33QCkcZ0onzOF5ns)uSaCvgVFZpnMo6u4HyR)Gg1prqJQAapVIAakJ9Rq8(YzFf7M(y7fq23yRT324Be7)yCP4O(Tr6vzPAJQgXpFGZhpy5fXpm7RqH)bupNfA3E(EWVFxbXLsSx1e9ug8xEx)YjpFAE)BB(5SloDewt9Oe88CcqNfb4Pcgz11L8)fVmaiXzSZFsQyS(pLOzWA4V6677sS8(5Px)xIPubWYZOphCQZEL9MqDio)uUzv)eGtT4ZtprEep428NWeu0WxUKKMjyLrAQZLuQkLzYN5rULFYnclY1KKBDjIPOtMn)dIBpHED0qsKfddx7p)C9uSYS)7QRaflYDSbMfBK)7ZAMuC22iry8cfjJ((2lrY2RG5joAfKsIFkOPxhv11iR4KCw0Uq)H6KacXtghJYEEXyV0YdCgJTuZraiG57eyLupkuuk1ZKh3vU(XCgNwcWCfvOyM5RbDSoHVhqJSObHRLceGNhh)IHqguKRtkDtpzTc4i6qC2GM(xP8HoZbQcaXjCYD(oc4SrRbWmRNZz9pPga7usf0YmhCLMbP47YB(OWYiS4bPfIABulNxX2Ijdu8sTUE9M5I9p)SBTnk51CCpLjgR)OkUmAKK7IHItPnapJR9NtV(YA4HDv7JQbhWFhH(C9eyMyUotocBbuRWivJU)KFKAXRFaaxpRKfudER)UI4nzd(vXzdv8pD8b8ZJxphIzrlIDa8iVMeB2qC4E1W7Ecg4KFjAPLcat2B35dcehY25yeelKwt2yJ8vdLyeligMFQNewtrOXM91NL1TKhhfmMurLYfbl7zfh528GLP1au19xpwVx3vV57tla9uYs0wiZ1zkCzPrEw67203(kNfIWRq9uL7GLw1tmaO0QN8KMwUQN4SSGQNPiG5tRmMlMCEV1y36SAlhfqXnytJAhFcZilXg)6P8Lbzvu5MFKTkkEjxanT6D4JtR3jov2LRIhonX5eoFkEQeWcQ3XFf5zxdJmT9ZLnFTtEhpxgQPPFr9v0s5pGVBgPWVVEAPPXvfL05hxRIsA27TxEv1CGTixM1111q(R6r6ElFbuI7)k0xBD2zf(aC)MNdvITqrjbr8WeSDYUrr55xS7VPGBnlmr5ArEzJpwVuWYVmOlaG3SCaNCZsxayVv5WgVMQlau3UCOQCNxxaGVt5ap1fODba)ULdEXTXDba8ELdy2v7D61)JPxZUEVlWe8SYNGZcweG(CDa9Z6SZE6tXB8X94o2thoYLmKDhqWDYNC3ilp(1QwCbklA)8kkIP2bwoKWBOUUvkSjHT(LXGs4)5JvDVJQ2cfQ3x8LAayvBjU5F)GwCYALhQMYvlUslaY6F610Ep)nsstNLVjeP7V8QOSIwdKHHQNfGelwWybtXHwGfazJxjSUxu6uK0XzargGI1d4nPLOkzYYDTDLeyYmi(0)RYCL8c2uaHR8cY9Z5P)LryTIBhTgJFX8YdwK9LVEb0MblvSLNdSSkgXzUn2vYqw8gQO10S(QZYNR5SIm9f0KQX)Y2Bqow9QXJqrxk)Im3unotEPNmML12C7qPmhlZQMaSCCUSmCYuKzCLprk97)SAznOmxt87c8tcvEf1yVu3XodQxDmj7jzjvawF9L0rKTQJf6KhopwNJ1Y4XPvYRx9JjSmM7c78oUer842qO3LB2AOX85ZTOuBy1VJAz3HUq1liuCFMVqwozH8E82KAbsPz1iWyPynBYa1NhNyPj6YCzSQdG6KhoVstQspCEvv4rlSLFMk5rLS8lyVZRVucXBj5wr7ayVnSaHNEePEdMxvUJsDqa11gM4S8yvx868ceWc6flNWEbcCKQwAk0g3yzL7Mcb7NYu4jQcKZwSkkdRdzs5r4EdLg0SDwk8sL3R)35rJyvJO1QXltY1wF9pQB)Kq)ZnkYFF6zSGZGjdZmDVIdA4N1XE(sSEGOMmXRHsLCaocmpgH1CmjlYAcvimYVTwtql)sZHiTC4xR0ictQ6pFF(wLOI)lGxor5r6fXVAjHJaw8A1QJcQINRw8HHY6A1k4nQ7VlHTsYXv6ODzQqxvxw)iWxmtk)nZKbXz8gzMuSk4ee83HSbU(SYWTyYnP(wvv3mzXcxSo7eJgvvHxpus)sRmlFgLsYzNPxiX8L5riWTywsV0qFDp2G0KYk81jkGqTh99IJPsFR0UGytHyx5VGLL312e7bEuif0L1BUgFU)2)fwllEUcvSIRaAl9mGMJeAM7KLQqcnAhhE)GsJxYlY1xQ8FYMzJM8HYLStD(fBsm0s258SRyLw4kutx8eC0xM(EyP2uyf4RmmvTweLE)LkBinvVnRXdtYT1BRUw6AxuT9dg6huB2lhjlwikd9deRr(EZXyBM6g0w74wVV9VDEZRE5XTEvZlE4WP9fh36xA2(HdOdp9S9)LhoyA18WFz2o61wlAsNGzvg7BvUA75s8Cwai19JmE0st0zfJLcQxqMWPqqTjbZ6w6BAzJLBqAh43Cbs9vTo7OqfFJhfxkADrtBvxAPl(YYAkwNLSaDfwSTY7AiRJSnCI6KRVXf)KtM9ztp9KpxVsRGUGhKr9KYXc1P4JDo1cLfM2Sw(9Strnvotk1LiJS7PLYbBCOVx44H42JnJta5m2lDNM(iOzE3Ewr29pST0jPKWoIxsyR8XIKULyCfnJULgni9lGr1Z9vu62YYRQRL1K7GgN79ikThOCc9szShrMG)m9fE1rJhoATsIzC(48Z8qwwoC(vahx7D1x4(lLBVS)sy9nDQUscjRVKCergx88AeG6nGM3VFoPutW(Ey23B7SawHE14)s5PXbzR0wMZuq5jjxnt1gt)cMO8KK7pHsJk3EiLw1DL3uEC23jxLhL5G6RRU6r6Dhr5rt0IVjBJxDXvQnx5HWKembleGNelAt3EXfEbSSGZlJfCjlFnOFUK7kVCev4IYNdyzRTbGUEyBF(VVffCN4JlNg1LNHBYfDpbvkDhvN7ZyrjU74DWSKAy88D0ddi23WSqL1iKuBuIcLk2QKf7ivI3dAPZyLDHwyT(qQmaCq8txm2BUlraFPlmavQt40uH6TqURvDIc8L)9uAZ)tibhUlFMyUYqSBaX6Mhirvs6gfVdmPCySHdJmwtHKwVALUdCafA(NQYfPwTaCs8bKAHWW1lWHaL1xolhulXkX5tBuU(Cbuk6dbbdF(UK(Xzf41mO(YRljPOA5uNNU1GdYsoy8ZlBNJowwdSYx2Vy7QbVAwvkiAvSJp(XM9oVB88Vv3(dLA4YV8t9HyVwR2)Xd9YX()xV05xDdp0w6cf152tM9w6lrb16TGSwpvS6clQ0cGssrx4HbNKkVWlQEH7y2)OlCPCoQ8DPPYGR8lMxo0vQhkvkNJ3Ua1I5iT0Txx3nFAH3jMKcxsM38K8br9bRGaQAv34YgfYHE6tz7e70Rn5a7KYVtJgApnG03Rn995nqsxL2HZDTIKPJ0qBpmhGLdSWs6dq7SnhUmY5mpYtFnO9Z(Hh6osyPtz7B9RENpW)2Y7WRg7vEhuXT3yzphi3S795yvGkyy1raZBH0mQoguHUdkM9DTOtMbMAgznRU8s2VgvCHD598i2pe8L3Ndd8dd7olP3hacnuJk8NtLe15wUwoufxBxU5JgFFzn(mMLXNXJgFfYfsz8zuzJpJky8zujJpJhGX3Rh7LAFIUCRVPS9AmtBpJky7z8Frl8zmx2Eg)iz7992cFx43xDN(VC7VKMEnE4l79TUPNX30l7vjtpJvQPNXxHL9wEMEpKL9opGI3LOeBVDww2En(YeY5xbBpJhT9kZ2Z4RLTxJLAiNllBVgfA7DeAlm96FXJ2FGQj4U)aM1NXJz99ywFF7L1N5aRHQL8(l37hWS(A8yONpU833EHE(gR(Qj99Shd8876apn(V3K((ElWtGgD9TvENmU85pA89OX3JgFFjm(EJVNQLxdJVZ2SZgpgX5QoIZg)Wz614BIS9okym1r12RXJh0WJB25dY27XS9QQThziQ)L7y2BS5J2GFxV(3pQHE24l9H9TQw)7ZkV3NI3a1d9D9ZF3MQ9FAS522969Ch8F4l0mEXEo3x99bv2h()NSph6pCOA9Rt2RgKE9mmK96DE2f0pdJ9mCINXlSci57J1wBTdHi7tZruBDy1ZmsMVtj9jEowb3NVJKDTTFwChJVUFAqmB7eY81ekK4S)qgpTtuhZEupA4GoTHpdFlkGYKNW3B1a(JSb2hVFePJP94Wi)HDmdh3LmH4fzoUxp6DDmV6W9nBFLz79Va6kE3q61RnBaVU5PN)Y3DAhZXEuyg41eUoMSbdpLy5gnOJjRgmXWIyiFEaHbzZZBE6PIbe2X80ZoR9vx0C)J(TeKHXQIBF6jXV2(QfYOdVQnDijyJ97H)(nASrd17vSMx7943(6nmTT8AYM(1QD0zxT)7AFgoB1wp7DYJ9AkduWiIR7Xoc6XgVBrXemhLVIZmfTbYysa12CG)TN5bdN9F3hqSjXm8RgqDGVebuGdcuynOyjdk5ATzPsRXEIPYACKF88E4alWm)nKWqR(Kcz8QmzfQVaUS4YcKCd2Eb7h85tfFxLrxWD)aV(sAUoBW6KHe29FjHrxkJRunuDIbPgMcrwv2VPdn83zSdCMTCDH)W(sBE3EJpm8wpTHb2xkg)GNL77bdnG9bYUD7yEdHmAFqXXo6cSWZ0Plabp6qwrObLNHrwbrjcwpFp4Voahe7GGocj2(GtuCogAr9QEVJDcuT(J0lj0kcFobXuGvFbPp(REsIJdYDrxfoWYX)2F9SE9cjGoQHe(4DagEUOx8p(epXxTrp7C4G)Vnz)Dl2F3g)RCy98rHwZ7gfakW3ADFQ58qfGyWaIbdigzacV3)MkgYAM427CFkobOQGYmAs)dqsUPHstC)CN9U2NECRMI2T8Sh4hiab8OMxC1fh)Qx3gLQ4tYnJ)oONr7beXHnBb9UJzGFeWDBZ4nTodbmFK)A2roHgs76s6CaxYmGGNfFNw7UDhtxFlhMWWYfuTzUigo2nIg7UN1EUMr1WCn6qbZiBOL7Z9Oai6OCnYUkS5AfxJsOrNgeq4t5AK61pWF8OCTpAYOIWCu6KPre6mLtUCcV9la2nBLmwhpa17J1fKYgBFFxqTXdLohrdz)K5GD9pGvwzcgMBwOHiF7jsR89m2YaEe1b0PGhJUYo1Vp1gbhEJVr8oZ9Jgbr8TUgn0kSohXM1zv((riO7YtJttr)CfamddeTZwcVXXK9MwJTPCLTXVMCTU1naLFUK4YIdqrXbOK4auqa)zh8p7I)zp8ppd)ZZz66MA(j3dEgISzUv64uNCFTXVnjnpotjOSJ57ju2V4z7h0hdBbVwy77ztz)Um9glpl47haRrjQr9MqG3eiqbO1ZdaF2W6FMJObu8odV)iYDuio1ddUhCHJv4LwemBoWXtawUdKZaUah4cGv6ryGEalnZ)hyOGSoia8mKCJ6rCwZD1hLVZOi)ICvt9vGlMkKUQtjoBzlAayBLvPIfcIjZqBCIwnUT2Xa15WWvChnWcvmmVL6aXjY8QX9d(Yaav5M0MhErZMTGvLrBRJPK2U7y18TpNIEqqZp2Au3P43ShowiAjRioWXf2Orc1WOe7B2ABru7BU)iXAHqlYGTaBCanoBKY4UxzosTcqwhha5mIXx5HxG(rE3ihC1uZXI)RSRnD6ZWFUJZWuXcawXEajp9AzmAo(xnueoxx2349OBMi9b(cLbaOhIHEqsGEY77jWvaNBya7sQNfn3wPUgEY7YQmwV4Gchg2pFyHXxCF4P)eeCJ9G1Qn4jxU2g)Z1FYhLvZXA1YnUKFtrsp27w7jo)Z1Ldmv1KwHk45VM521IxAZYVGLELDxnJHBfGXgSoRVoMilK846rzPoiVT1EYTj)lMqRjYDvLEJVmZ8BXkLDVoJzC1LtXjIRCESa0jW624BM8SLELa6ufMpf9cjWYcoEXxiI4eFTKL5SwB61BSrmyXpw7srBCniwtFe7n887ep6t5(TjkgBGiYdXWPcV8VNVn16cGM9WdZQiUYhQzRlWFdj7l(5XSGUq9Ci3jtfcZcDT1RRRsWe6heLcofR2r1FVDJnWsXC1ckyX4(yOZX1GUAS0B0vuFi3blNX8aGiFAcHX904RqdyCuDJuTHGbs9Ai3lDC3pZuMxQBCHMS9u3AImBArbjmNj9FL0Np8173(Q3y(QRYKaDSQiwmpQZ8bSEApvRP4w438hJkl2ei)sEM21wVWkEOo1D0on(BfpcPNHmodQqnUsKEUmH6uKDMCVzyr8AEP2QK0ByuP56RBdN(6MMEbjpNkbBmZvcM1IlOV5s6fPM5EfaqQm3lV)YPk1ugWYuKN4u2OCEmN(FSYPxF64ZBs9A3zGIYPV400lkXET7cqLZPFosup92xjZ0FEtF)yXwjiYEpv(kfMKIsImS8vgn8nnoyNbV7tV9KLs(kZ2uJX(MaFE7nXV25)p \ No newline at end of file