From 8f008b620a24515651d8450004330d47a04a6adf Mon Sep 17 00:00:00 2001 From: Indyuce Date: Thu, 29 Aug 2019 17:54:39 +0200 Subject: [PATCH] restructured abstract class and interface moved getType() method to itemBrowser fixed an issue with item browser inv update --- .../mmoitems/api/edition/ChatEditionBase.java | 35 ------------ .../Indyuce/mmoitems/api/edition/Edition.java | 7 +++ .../mmoitems/api/edition/NewItemEdition.java | 52 ++++++++---------- .../mmoitems/api/edition/StatEdition.java | 37 ++++++------- .../api/edition/{ => process}/AnvilGUI.java | 48 ++++++++-------- .../edition/{ => process}/ChatEdition.java | 20 +++---- .../api/edition/process/EditionProcess.java | 38 +++++++++++++ .../net/Indyuce/mmoitems/gui/ItemBrowser.java | 20 ++++--- src/main/resources/default/item-sets.yml | 10 ++-- src/main/resources/default/legacy-configs.zip | Bin 74179 -> 74187 bytes 10 files changed, 134 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/net/Indyuce/mmoitems/api/edition/ChatEditionBase.java create mode 100644 src/main/java/net/Indyuce/mmoitems/api/edition/Edition.java rename src/main/java/net/Indyuce/mmoitems/api/edition/{ => process}/AnvilGUI.java (58%) rename src/main/java/net/Indyuce/mmoitems/api/edition/{ => process}/ChatEdition.java (61%) create mode 100644 src/main/java/net/Indyuce/mmoitems/api/edition/process/EditionProcess.java diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/ChatEditionBase.java b/src/main/java/net/Indyuce/mmoitems/api/edition/ChatEditionBase.java deleted file mode 100644 index f451194c..00000000 --- a/src/main/java/net/Indyuce/mmoitems/api/edition/ChatEditionBase.java +++ /dev/null @@ -1,35 +0,0 @@ -package net.Indyuce.mmoitems.api.edition; - -import org.bukkit.entity.Player; -import net.Indyuce.mmoitems.gui.PluginInventory; - -public abstract class ChatEditionBase { - - /* - * saves the last inventory opened. it saves the item data, and the last - * opened page. allows for a much easier access to this data - */ - protected PluginInventory inv; - - public ChatEditionBase(PluginInventory inv) { - this.inv = inv; - } - - public PluginInventory getInventory() { - return inv; - } - - public Player getPlayer() { - return inv.getPlayer(); - } - - public abstract void enable(String... messages); - - public abstract void output(String output); - - public interface ChatEditionProcess { - void open(ChatEditionBase edition); - - void close(); - } -} diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/Edition.java b/src/main/java/net/Indyuce/mmoitems/api/edition/Edition.java new file mode 100644 index 00000000..0ed7ee33 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/Edition.java @@ -0,0 +1,7 @@ +package net.Indyuce.mmoitems.api.edition; + +public interface Edition { + public boolean output(String input); + + public void enable(String... message); +} diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/NewItemEdition.java b/src/main/java/net/Indyuce/mmoitems/api/edition/NewItemEdition.java index f9bfa343..a83a9cf1 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/edition/NewItemEdition.java +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/NewItemEdition.java @@ -2,63 +2,57 @@ package net.Indyuce.mmoitems.api.edition; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.scheduler.BukkitRunnable; import net.Indyuce.mmoitems.MMOItems; -import net.Indyuce.mmoitems.api.Type; -import net.Indyuce.mmoitems.gui.PluginInventory; +import net.Indyuce.mmoitems.api.edition.process.AnvilGUI; +import net.Indyuce.mmoitems.api.edition.process.ChatEdition; +import net.Indyuce.mmoitems.gui.ItemBrowser; -public class NewItemEdition extends ChatEditionBase { +public class NewItemEdition implements Edition { /* * saves the data about the edited data so the plugin can edit the * corresponding stat. some stats have complex chat formats, so the object * array allow to save more complex edition info */ - private Type type; + private final ItemBrowser inv; - public NewItemEdition(PluginInventory inv, Type type) { - super(inv); - this.type = type; - } - - public Type getType() { - return type; + public NewItemEdition(ItemBrowser inv) { + this.inv = inv; } @Override - public void enable(String... messages) { - getPlayer().closeInventory(); + public void enable(String... message) { + inv.getPlayer().closeInventory(); - getPlayer().sendMessage(ChatColor.YELLOW + "" + ChatColor.STRIKETHROUGH + "-----------------------------------------------------"); - getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.translateAlternateColorCodes('&', "Write in the chat, the id of the new item.")); - getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Type 'cancel' to abort editing."); + inv.getPlayer().sendMessage(ChatColor.YELLOW + "" + ChatColor.STRIKETHROUGH + "-----------------------------------------------------"); + inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.translateAlternateColorCodes('&', "Write in the chat, the id of the new item.")); + inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Type 'cancel' to abort editing."); /* * anvil text input feature. enables players to use an anvil to input * text if they are having conflicts with their chat management plugins. */ if (MMOItems.plugin.getConfig().getBoolean("anvil-text-input") && MMOItems.plugin.getVersion().isBelowOrEqual(1, 13)) { - new AnvilGUI().open(this); + new AnvilGUI(inv, this); return; } /* * default chat edition feature */ - new ChatEdition().open(this); - MMOItems.plugin.getNMS().sendTitle(getPlayer(), ChatColor.GOLD + "" + ChatColor.BOLD + "Item Creation", "See chat.", 10, 40, 10); + new ChatEdition(inv, this); + MMOItems.plugin.getNMS().sendTitle(inv.getPlayer(), ChatColor.GOLD + "" + ChatColor.BOLD + "Item Creation", "See chat.", 10, 40, 10); } @Override - public void output(String output) { - if (output.equals("cancel")) - inv.open(); - else new BukkitRunnable() { - @Override - public void run() { - Bukkit.dispatchCommand(getPlayer(), "mi create " + type.getId() + " " + output.toUpperCase().replace(" ", "_").replace("-", "_")); - } - }.runTask(MMOItems.plugin); + public boolean output(String input) { + if (input.equals("cancel")) + return true; + + Bukkit.getScheduler().runTask(MMOItems.plugin, () -> { + Bukkit.dispatchCommand(inv.getPlayer(), "mi create " + inv.getType().getId() + " " + input.toUpperCase().replace(" ", "_").replace("-", "_")); + }); + return true; } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/StatEdition.java b/src/main/java/net/Indyuce/mmoitems/api/edition/StatEdition.java index 53cdf4c0..e6574cb9 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/edition/StatEdition.java +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/StatEdition.java @@ -3,21 +3,24 @@ package net.Indyuce.mmoitems.api.edition; import org.bukkit.ChatColor; import net.Indyuce.mmoitems.MMOItems; +import net.Indyuce.mmoitems.api.edition.process.AnvilGUI; +import net.Indyuce.mmoitems.api.edition.process.ChatEdition; import net.Indyuce.mmoitems.gui.edition.EditionInventory; import net.Indyuce.mmoitems.stat.type.ItemStat; -public class StatEdition extends ChatEditionBase { +public class StatEdition implements Edition { /* * saves the data about the edited data so the plugin can edit the * corresponding stat. some stats have complex chat formats, so the object * array allow to save more complex edition info */ - private ItemStat stat; - private Object[] info; + private final EditionInventory inv; + private final ItemStat stat; + private final Object[] info; public StatEdition(EditionInventory inv, ItemStat stat, Object... info) { - super(inv); + this.inv = inv; this.stat = stat; this.info = info; } @@ -30,36 +33,32 @@ public class StatEdition extends ChatEditionBase { return info; } - @Override - public void enable(String... messages) { - getPlayer().closeInventory(); + public void enable(String... message) { + inv.getPlayer().closeInventory(); - getPlayer().sendMessage(ChatColor.YELLOW + "" + ChatColor.STRIKETHROUGH + "-----------------------------------------------------"); - for (String message : messages) - getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.translateAlternateColorCodes('&', message)); - getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Type 'cancel' to abort editing."); + inv.getPlayer().sendMessage(ChatColor.YELLOW + "" + ChatColor.STRIKETHROUGH + "-----------------------------------------------------"); + for (String line : message) + inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.translateAlternateColorCodes('&', line)); + inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + "Type 'cancel' to abort editing."); /* * anvil text input feature. enables players to use an anvil to input * text if they are having conflicts with their chat management plugins. */ if (MMOItems.plugin.getConfig().getBoolean("anvil-text-input") && MMOItems.plugin.getVersion().isBelowOrEqual(1, 13)) { - new AnvilGUI().open(this); + new AnvilGUI(inv, this); return; } /* * default chat edition feature */ - new ChatEdition().open(this); - MMOItems.plugin.getNMS().sendTitle(getPlayer(), ChatColor.GOLD + "" + ChatColor.BOLD + "Item Edition", "See chat.", 10, 40, 10); + new ChatEdition(inv, this); + MMOItems.plugin.getNMS().sendTitle(inv.getPlayer(), ChatColor.GOLD + "" + ChatColor.BOLD + "Item Edition", "See chat.", 10, 40, 10); } @Override - public void output(String output) { - if (output.equals("cancel")) - inv.open(); - else - stat.whenInput((EditionInventory)inv, ((EditionInventory) inv).getItemType().getConfigFile(), output, info); + public boolean output(String input) { + return input.equals("cancel") || stat.whenInput((EditionInventory) inv, ((EditionInventory) inv).getItemType().getConfigFile(), input, info); } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/AnvilGUI.java b/src/main/java/net/Indyuce/mmoitems/api/edition/process/AnvilGUI.java similarity index 58% rename from src/main/java/net/Indyuce/mmoitems/api/edition/AnvilGUI.java rename to src/main/java/net/Indyuce/mmoitems/api/edition/process/AnvilGUI.java index 81982041..a6fbd38c 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/edition/AnvilGUI.java +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/process/AnvilGUI.java @@ -1,4 +1,4 @@ -package net.Indyuce.mmoitems.api.edition; +package net.Indyuce.mmoitems.api.edition.process; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -12,56 +12,54 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import net.Indyuce.mmoitems.MMOItems; -import net.Indyuce.mmoitems.api.edition.ChatEditionBase.ChatEditionProcess; +import net.Indyuce.mmoitems.api.edition.Edition; +import net.Indyuce.mmoitems.gui.PluginInventory; -public class AnvilGUI implements ChatEditionProcess, Listener { - private ChatEditionBase edition; - - private int containerId; - private Inventory inventory; +public class AnvilGUI extends EditionProcess implements Listener { + private final int containerId; + private final Inventory inventory; private boolean open; - public Inventory getInventory() { - return inventory; - } - - @Override - public void open(ChatEditionBase edition) { - this.edition = edition; + public AnvilGUI(PluginInventory inv, Edition edition) { + super(inv, edition); ItemStack paper = new ItemStack(Material.PAPER); ItemMeta paperMeta = paper.getItemMeta(); paperMeta.setDisplayName("Input text.."); paper.setItemMeta(paperMeta); - MMOItems.plugin.getNMS().handleInventoryCloseEvent(edition.getPlayer()); - MMOItems.plugin.getNMS().setActiveContainerDefault(edition.getPlayer()); + MMOItems.plugin.getNMS().handleInventoryCloseEvent(getPlayer()); + MMOItems.plugin.getNMS().setActiveContainerDefault(getPlayer()); Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin); - final Object container = MMOItems.plugin.getNMS().newContainerAnvil(edition.getPlayer()); + final Object container = MMOItems.plugin.getNMS().newContainerAnvil(getPlayer()); inventory = MMOItems.plugin.getNMS().toBukkitInventory(container); inventory.setItem(0, paper); - containerId = MMOItems.plugin.getNMS().getNextContainerId(edition.getPlayer()); - MMOItems.plugin.getNMS().sendPacketOpenWindow(edition.getPlayer(), containerId); - MMOItems.plugin.getNMS().setActiveContainer(edition.getPlayer(), container); + containerId = MMOItems.plugin.getNMS().getNextContainerId(getPlayer()); + MMOItems.plugin.getNMS().sendPacketOpenWindow(getPlayer(), containerId); + MMOItems.plugin.getNMS().setActiveContainer(getPlayer(), container); MMOItems.plugin.getNMS().setActiveContainerId(container, containerId); - MMOItems.plugin.getNMS().addActiveContainerSlotListener(container, edition.getPlayer()); + MMOItems.plugin.getNMS().addActiveContainerSlotListener(container, getPlayer()); open = true; } + public Inventory getInventory() { + return inventory; + } + @Override public void close() { if (!open) return; open = false; - MMOItems.plugin.getNMS().handleInventoryCloseEvent(edition.getPlayer()); - MMOItems.plugin.getNMS().setActiveContainerDefault(edition.getPlayer()); - MMOItems.plugin.getNMS().sendPacketCloseWindow(edition.getPlayer(), containerId); + MMOItems.plugin.getNMS().handleInventoryCloseEvent(getPlayer()); + MMOItems.plugin.getNMS().setActiveContainerDefault(getPlayer()); + MMOItems.plugin.getNMS().sendPacketCloseWindow(getPlayer(), containerId); HandlerList.unregisterAll(this); } @@ -73,7 +71,7 @@ public class AnvilGUI implements ChatEditionProcess, Listener { if (event.getRawSlot() == 2) { ItemStack clicked = inventory.getItem(event.getRawSlot()); if (clicked != null && clicked.getType() != Material.AIR) - edition.output(clicked.hasItemMeta() ? clicked.getItemMeta().getDisplayName() : clicked.getType().toString()); + input(clicked.hasItemMeta() ? clicked.getItemMeta().getDisplayName() : clicked.getType().toString()); } } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/ChatEdition.java b/src/main/java/net/Indyuce/mmoitems/api/edition/process/ChatEdition.java similarity index 61% rename from src/main/java/net/Indyuce/mmoitems/api/edition/ChatEdition.java rename to src/main/java/net/Indyuce/mmoitems/api/edition/process/ChatEdition.java index aff5db74..d5b260b3 100644 --- a/src/main/java/net/Indyuce/mmoitems/api/edition/ChatEdition.java +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/process/ChatEdition.java @@ -1,4 +1,4 @@ -package net.Indyuce.mmoitems.api.edition; +package net.Indyuce.mmoitems.api.edition.process; import org.bukkit.Bukkit; import org.bukkit.event.EventHandler; @@ -9,14 +9,12 @@ import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; import net.Indyuce.mmoitems.MMOItems; -import net.Indyuce.mmoitems.api.edition.ChatEditionBase.ChatEditionProcess; +import net.Indyuce.mmoitems.api.edition.Edition; +import net.Indyuce.mmoitems.gui.PluginInventory; -public class ChatEdition implements ChatEditionProcess, Listener { - private ChatEditionBase edition; - - @Override - public void open(ChatEditionBase edition) { - this.edition = edition; +public class ChatEdition extends EditionProcess implements Listener { + public ChatEdition(PluginInventory inv, Edition edition) { + super(inv, edition); Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin); } @@ -28,16 +26,16 @@ public class ChatEdition implements ChatEditionProcess, Listener { @EventHandler(priority = EventPriority.LOWEST) public void a(AsyncPlayerChatEvent event) { - if (event.getPlayer().equals(edition.getPlayer())) { + if (event.getPlayer().equals(getPlayer())) { event.setCancelled(true); - edition.output(event.getMessage()); + input(event.getMessage()); } } // cancel stat edition when opening any gui @EventHandler public void b(InventoryOpenEvent event) { - if (event.getPlayer().equals(edition.getPlayer())) + if (event.getPlayer().equals(getPlayer())) close(); } } diff --git a/src/main/java/net/Indyuce/mmoitems/api/edition/process/EditionProcess.java b/src/main/java/net/Indyuce/mmoitems/api/edition/process/EditionProcess.java new file mode 100644 index 00000000..3d456b68 --- /dev/null +++ b/src/main/java/net/Indyuce/mmoitems/api/edition/process/EditionProcess.java @@ -0,0 +1,38 @@ +package net.Indyuce.mmoitems.api.edition.process; + +import org.bukkit.entity.Player; + +import net.Indyuce.mmoitems.api.edition.Edition; +import net.Indyuce.mmoitems.gui.PluginInventory; + +public abstract class EditionProcess { + + /* + * saves the last inventory opened. it saves the item data, and the last + * opened page. allows for a much easier access to this data + */ + private final PluginInventory inv; + private final Edition edition; + + public EditionProcess(PluginInventory inv, Edition edition) { + this.inv = inv; + this.edition = edition; + } + + public void input(String input) { + if (edition.output(input)) { + inv.open(); + close(); + } + } + + public PluginInventory getLastOpened() { + return inv; + } + + public Player getPlayer() { + return inv.getPlayer(); + } + + public abstract void close(); +} diff --git a/src/main/java/net/Indyuce/mmoitems/gui/ItemBrowser.java b/src/main/java/net/Indyuce/mmoitems/gui/ItemBrowser.java index 3e7500ad..e257b43d 100644 --- a/src/main/java/net/Indyuce/mmoitems/gui/ItemBrowser.java +++ b/src/main/java/net/Indyuce/mmoitems/gui/ItemBrowser.java @@ -29,7 +29,6 @@ import net.Indyuce.mmoitems.version.nms.ItemTag; public class ItemBrowser extends PluginInventory { private Type type; - private List itemIDs; private Map cached = new HashMap<>(); private static final int[] slots = { 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34 }; @@ -41,9 +40,6 @@ public class ItemBrowser extends PluginInventory { public ItemBrowser(Player player, Type type) { super(player); this.type = type; - - if (type != null) - itemIDs = new ArrayList<>(type.getConfigFile().getConfig().getKeys(false)); } @Override @@ -52,6 +48,8 @@ public class ItemBrowser extends PluginInventory { int max = page * slots.length; int n = 0; + List itemIds = new ArrayList<>(type.getConfigFile().getConfig().getKeys(false)); + /* * displays all possible item types if no type was previously selected * by the player @@ -113,8 +111,8 @@ public class ItemBrowser extends PluginInventory { * map at the top to reduce performance impact and are directly rendered */ Inventory inv = Bukkit.createInventory(this, 54, ChatColor.UNDERLINE + "Item Explorer: " + type.getName()); - for (int j = min; j < Math.min(max, itemIDs.size()); j++) { - String id = itemIDs.get(j); + for (int j = min; j < Math.min(max, itemIds.size()); j++) { + String id = itemIds.get(j); if (!cached.containsKey(id)) { ItemStack item = MMOItems.plugin.getItems().getItem(type, id); if (item == null || item.getType() == Material.AIR) { @@ -156,7 +154,7 @@ public class ItemBrowser extends PluginInventory { ItemMeta createMeta = create.getItemMeta(); createMeta.setDisplayName(ChatColor.GREEN + "Create New"); create.setItemMeta(createMeta); - + ItemStack previous = new ItemStack(Material.ARROW); ItemMeta previousMeta = previous.getItemMeta(); previousMeta.setDisplayName(ChatColor.GREEN + "Previous Page"); @@ -167,10 +165,14 @@ public class ItemBrowser extends PluginInventory { inv.setItem(49, back); inv.setItem(51, create); inv.setItem(18, page > 1 ? previous : null); - inv.setItem(26, max >= itemIDs.size() ? null : next); + inv.setItem(26, max >= itemIds.size() ? null : next); return inv; } + public Type getType() { + return type; + } + @Override public void whenClicked(InventoryClickEvent event) { event.setCancelled(true); @@ -195,7 +197,7 @@ public class ItemBrowser extends PluginInventory { new ItemBrowser(player).open(); if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Create New")) - new NewItemEdition(this, this.type).enable("Write in the chat the text you want."); + new NewItemEdition(this).enable("Write in the chat the text you want."); if (type == null && !item.getItemMeta().getDisplayName().equals(ChatColor.RED + "- No type -")) { Type type = MMOItems.plugin.getTypes().get(NBTItem.get(item).getString("typeId")); diff --git a/src/main/resources/default/item-sets.yml b/src/main/resources/default/item-sets.yml index f533684a..2eae0431 100644 --- a/src/main/resources/default/item-sets.yml +++ b/src/main/resources/default/item-sets.yml @@ -4,8 +4,8 @@ # This is a very powerful system for RPG items. # # You can also use potion effects as set bonuses, e.g -# - speed: 2 gives permanent Speed II -# - increase_damage: 3 gives permanent Strength III +# - "potion-speed: 2" gives permanent Speed II +# - "potion-increase_damage: 3" gives permanent Strength III # https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html # # You may also add abilities as full set bonuses. The ability ID @@ -20,7 +20,7 @@ ARCANE: magic-damage: 20 '4': max-mana: 30 - speed: 1 + potion-speed: 1 lore-tag: - '&7Arcane Set Bonus:' - '&8[3] +20% Magic Damage' @@ -37,14 +37,14 @@ STEEL: lore-tag: - '&7Steel Set Bonus:' - '&8[3] +5% Damage Reduction' - - '&8[4] +5% Damage Reduction' + - '&8[4] +10% Damage Reduction' GINGERBREAD: name: '&cGingerbread Set' bonuses: '4': damage-reduction: 6 - jump: 3 + potion-jump: 3 lore-tag: - '&7Gingerbread Set Bonus:' - '&8[4] +5% Damage Reduction' diff --git a/src/main/resources/default/legacy-configs.zip b/src/main/resources/default/legacy-configs.zip index f3ff6490395e79fe44ca125779a7147f8506a3a0..5a1cbfdc923e7a3ea5bc0f9f5373d654cbe92291 100644 GIT binary patch delta 921 zcmV;K17`fg!vxF21h9AKfBA+TPf)ns90>ye0E7ns01W^D0BLk(Z7p+UbaO6wZETfQ zQBT`25PnDEKb$~YA4Xazu%Wz_kwK@eLv3HC2_ZMRB&LoX*$!R){qB-7N+=t+t*Yd{ zJKy)+`MeKfj|DjN4itK*O$D(<;SrS7O9u<|D@5(U=Lm^RQ?#f(e@OCj8|eP-&OV&i zutH&_&Y-B2m!-lrFtw&=A~;bX?{?5Ul}glTVI`HKjWnjxH&6~nAXpe(IdrhfWt@Z5 zF-3EbONwQna@(W(x@^;#=h6Xv1>B>pp)@PBX{Er`jyb2s!u0yGjlmA=^OG3~4MMqg zhthayG$0X=Nh9Gle-k?Z>}Tv2z+MXsT#1;3Fx-Po-czzA+CpfSY{nKCkDubDW&s`E zCZZ4-hH$*a)05_z&tcqp=iZkt91QYm(RZcHj4$H8vDx5G+>6A-ZqU9R@ViB|TuMJ^ zw;NnHe^J9`&O+tBP#fF}QMcShl7Lu9CB4LkHYukzx%Ww5e_TUq7+-LNqH-Rb7uHiv zDc|1O9Q0sOano=)j8-*En{ZT%O+&@l-&8*~I+a;v5&Xs;v7qRMN${YlF}&vonM$-x zf|aX;qA>g!O+Sw&QMkJUv@~@^2)*~ik)_}WGxWXIvZk`e@#-D-HlBDWa}sa<@o6_M>yx~!rr6t?AP%Pd>9_SgYTRa zT!?~_dIC7Pp{>dMn|@k!P1oIK?6Fw0c@%x?XmvL8i0X|}wIT%;lPYGqA)Nk8try|j zboralOR}84Tk8SShk#xBAC3;Ypa!(Nb2*+|M$_|Ye>A%22oYb>I77RjLz?_sj#u#e zxV0(ns-mQhd6|1Bg>4F)yiS3~2KY*w@;qti@599S_Dn8nNH7&Nz7Lu+yE1mk)A4FF zpGMEbxe_#*{-ewA&AL2HjiZhuFFyGpd>em>ZllRXG<}YUjZukN>F0-#7tfCneoSt! z#`BjIFn{E=P3++f1Rwv3Jr_&VUHhym3Zwb%N${TLmhgNlrjkZlfgb7Vp-Ux~zE6&S z0JE9u(=-kFh8<5(xZNBH0{{Somw6unE)rQM{MmV4)d9ux2Gx09)dA?$m!TB_7MIT- v0U80Jm+Bt@UjaUsN+1DW0VS8JAOU6pkCzc40cHUcmv|uoMFw{H00000=bXHE delta 907 zcmV;619be$!vw>_1h9AKfAUfNPWpm;!vO;T0AmLL01W^D0BLk(Z7p+UbaO6wZETfQ z?@!w>5dDtC|8Nq5ei&_8`7xAlWn|Eab*Sx^X+p?NE{UmQN47)Bf4{pVKxru&ZmTM} zcjxz>?eiXtJm%ogJ5cDMG9^S7g-1|QFC5I#FA=o^pCQCDNzkJ9e;_H#t)P3mJ9}_Z z!4id)I)%JcUKR>lU}8;PS8yUnp6#%HDwL?u!crglT^z<>E5sItD>PZ%cKMP3V1|YL1C6?lTv}J9BWRDg~{zzQ-c#Y=MO6q8iaDq z42AL1Xh0Gkkw?P4e-I;Lhk(75)4Jda#5jNfr1FtC7HD&!*{LZ9U^HrAQnOzU?_-gR z6azTkOz`Az>N6NMNtySB3;O-6ocCNIQ{(ffXKdPk5RW1@k?S{a`}}TRE*8@F8`k~X z`Y)`x&)AmC=W0c1E~-YUh+`0Qsic=!izJ`as?r|0i7ljpf6*mZ$V=zJd0{=RAo1p90t2PKtt0W2%vK?7+NZhFh$>KBCV7b$D?!HS$X0?iz1`$^WqGSR~He|j5fH^bNFtuhw7UZib$m&kp4B?lKwE9kri&;K6Z!I#0&KKx=fa9Oiy z0S(~fj^?EB6aBPU58bYBz7D%IorU4enn~wVkElNBQR7b6Vq8YNzXCY@$fm9E_k4Nb zv(1*%{nihdJQrM-zXh|qb2S=Yg_Da(IJ{i*A-bZbe}#5VXEXlTjsK8$_7?C^<^^q$ z?V8u-eoy(yR#jUT{wGb!4W!n+2V>)#LpZM>#zateKCBPv(%1zzzw6;_5^lJ1EvOeU zsSgYpeA z%pTl9DEI8e?3q}gUXM@9JU5!JmKYzYQ3=nNULvW7<>--a7P>Ps>3fv;53`}_(=?aR z7Xbtb`htAJ0RsR4W0!#+0WOzN9{~skEnP)=?nRfq9|1H0nV0e(0bc<&mr@`BUjiNU hlR@+sm&zakP63CP86g2?0SlLaApu1OZutNJ007qLsoMYm