From 6c120d839d186a6ed266aa11b37c8dfea7b46da4 Mon Sep 17 00:00:00 2001 From: pjmarz Date: Sun, 7 Jun 2026 16:50:39 -0400 Subject: [PATCH] feat(smithingplus): Smithing Plus (draft, community review) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../smithingplus/AutoSmithingPlusConfig.java | 226 ++++++++ .../smithingplus/AutoSmithingPlusOverlay.java | 240 ++++++++ .../smithingplus/AutoSmithingPlusPlugin.java | 75 +++ .../smithingplus/AutoSmithingPlusScript.java | 512 ++++++++++++++++++ .../plugins/microbot/smithingplus/State.java | 19 + .../microbot/smithingplus/data/AnvilItem.java | 192 +++++++ .../data/AnvilLocationOption.java | 66 +++ .../smithingplus/data/AnvilLocations.java | 89 +++ .../smithingplus/data/BankLocationOption.java | 67 +++ .../microbot/smithingplus/data/Bars.java | 52 ++ .../microbot/smithingplus/data/Ores.java | 33 ++ .../microbot/smithingplus/docs/CHANGELOG.md | 121 +++++ .../microbot/smithingplus/docs/README.md | 63 +++ .../smithingplus/docs/assets/card.png | Bin 0 -> 132454 bytes .../smithingplus/docs/assets/icon.png | Bin 0 -> 35543 bytes 15 files changed, 1755 insertions(+) create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusConfig.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusOverlay.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusPlugin.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusScript.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/State.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilItem.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocationOption.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocations.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/BankLocationOption.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Bars.java create mode 100644 src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Ores.java create mode 100644 src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/CHANGELOG.md create mode 100644 src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/README.md create mode 100644 src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/card.png create mode 100644 src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/icon.png diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusConfig.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusConfig.java new file mode 100644 index 0000000000..fbaa2a834f --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusConfig.java @@ -0,0 +1,226 @@ +package net.runelite.client.plugins.microbot.smithingplus; + +import net.runelite.client.config.*; +import net.runelite.client.plugins.microbot.smithingplus.data.AnvilItem; +import net.runelite.client.plugins.microbot.smithingplus.data.AnvilLocationOption; +import net.runelite.client.plugins.microbot.smithingplus.data.BankLocationOption; +import net.runelite.client.plugins.microbot.smithingplus.data.Bars; + +@ConfigGroup("SmithingPlus") +@ConfigInformation("

Auto Smithing Plus

" + + "

Version: " + AutoSmithingPlusPlugin.version + "

" + + "

General

" + + "

1. Bar: the bar tier to smith. The bars must already be in your bank.

" + + "

" + + "

2. Item: what to make at the anvil. Each item uses a fixed number of bars, and bigger items give more XP per hour. Some picks are members only and will refuse to start on free worlds.

" + + "

" + + "

3. Progressive mode: ignore the Item pick and smith the best item your Smithing level can make at the chosen bar tier. It skips members items on free worlds.

" + + "

" + + "

4. Anvil: the anvil to walk to and anchor at. Auto nearest picks the closest. The Lumbridge rusted anvil takes bronze bars only.

" + + "

" + + "

5. Distance to stray: how far the bot may wander from the anvil tile. This is also the radius used to count nearby players for world hopping.

" + + "

" + + "

6. Max players in area: hop worlds when more players than this are within Distance to stray. Set 0 to never hop.

" + + "

" + + "

7. League mode: presses an arrow key now and then to reset the idle logout timer.

" + + "

" + + "

8. Speed mode: disables Microbot antiban for a faster but more detectable bot. Use throwaway accounts only.

" + + "

" + + "

9. Stop conditions: the bot shuts down when any limit you set is reached. Stop after minutes caps runtime, Stop after XP caps Smithing XP gained, and Target level stops once your Smithing level reaches it. Each value of 0 means no limit. The bot deposits its inventory before stopping.

" + + "

" + + "

Banking

" + + "

10. Preferred bank: override the closest by distance choice with a specific bank.

" + + "

" + + "

11. Items to bank and keep: two comma separated lists matched against item names. Items to bank wins. Leave it empty to deposit everything except your keep list. Keep defaults hold the hammer and any bar you are smithing.

") +public interface AutoSmithingPlusConfig extends Config { + + @ConfigSection(name = "General", description = "General settings", position = 0) + String generalSection = "general"; + + @ConfigSection(name = "Banking", description = "Banking settings", position = 1) + String bankingSection = "bankingSection"; + + // --- General section --- + + @ConfigItem( + keyName = "selectedBar", + name = "Bar", + description = "Which bar tier to smith. Bars must be in your bank.", + position = 0, + section = generalSection + ) + default Bars selectedBar() { + return Bars.BRONZE; + } + + @ConfigItem( + keyName = "selectedItem", + name = "Item", + description = "Which item to make. Bronze claws are MEMBERS-ONLY (Cabin Fever quest); F2P picks will refuse to start.", + position = 1, + section = generalSection + ) + default AnvilItem selectedItem() { + return AnvilItem.DAGGER; + } + + @ConfigItem( + keyName = "progressiveSmith", + name = "Progressive mode", + description = "Ignore the Item pick and auto-smith the best item your Smithing level can make at the chosen bar tier (skips members items on F2P). Mirrors AutoSmeltingPlus's progressive mode.", + position = 2, + section = generalSection + ) + default boolean progressiveSmith() { + return false; + } + + @ConfigItem( + keyName = "hammerOnToolBelt", + name = "Hammer on tool belt", + description = "Tick this if your hammer lives on the tool belt instead of the inventory. The bot then stops requiring (and withdrawing) a loose hammer. Leave unticked to use a normal inventory hammer.", + position = 3, + section = generalSection + ) + default boolean hammerOnToolBelt() { + return false; + } + + @ConfigItem( + keyName = "anvilLocation", + name = "Anvil", + description = "Walk to and anchor at this anvil. AUTO_NEAREST = require start-near-anvil. Lumbridge Rusted Anvil is bronze-only.", + position = 2, + section = generalSection + ) + default AnvilLocationOption anvilLocation() { + return AnvilLocationOption.AUTO_NEAREST; + } + + @ConfigItem( + keyName = "distanceToStray", + name = "Distance to stray", + description = "How far the bot can wander from the anvil tile. Also the player-detection radius for autohop.", + position = 3, + section = generalSection + ) + default int distanceToStray() { + return 20; + } + + @ConfigItem( + keyName = "maxPlayersInArea", + name = "Max players in area", + description = "Hop worlds if more players than this are within Distance to Stray. 0 = disable.", + position = 4, + section = generalSection + ) + default int maxPlayersInArea() { + return 0; + } + + @ConfigItem( + keyName = "leagueMode", + name = "League mode (anti-AFK)", + description = "Periodically presses an arrow key to reset the idle timer.", + position = 5, + section = generalSection + ) + default boolean leagueMode() { + return false; + } + + @ConfigItem( + keyName = "speedMode", + name = "Speed mode (less antiban)", + description = "Disables Microbot's antiban. Faster bot, more pattern-detectable. Throwaway only.", + position = 6, + section = generalSection + ) + default boolean speedMode() { + return false; + } + + @ConfigItem( + keyName = "stopAfterMinutes", + name = "Stop after (minutes)", + description = "Auto-shutdown after this many minutes of runtime. 0 = no limit.", + position = 7, + section = generalSection + ) + default int stopAfterMinutes() { + return 0; + } + + @ConfigItem( + keyName = "stopAfterXp", + name = "Stop after (XP gained)", + description = "Auto-shutdown after gaining this much Smithing XP. 0 = no limit.", + position = 8, + section = generalSection + ) + default int stopAfterXp() { + return 0; + } + + /** + * When Smithing level reaches this value, the script runs one final deposit pass + * then shuts down. 0 disables the check. + */ + @ConfigItem( + keyName = "targetLevel", + name = "Target level", + description = "Stop when Smithing reaches this level. Deposits inventory first. 0 = disabled.", + position = 9, + section = generalSection + ) + default int targetLevel() { + return 0; + } + + // Pause is an overlay button that toggles the shared Microbot.pauseAllScripts flag. + // See AutoSmithingPlusOverlay. + + // --- Banking section --- + + @ConfigItem( + keyName = "bankLocation", + name = "Preferred bank", + description = "AUTO_NEAREST = closest by raw distance.", + position = 1, + section = bankingSection + ) + default BankLocationOption bankLocation() { + return BankLocationOption.AUTO_NEAREST; + } + + /** + * Comma separated inclusion list matched as substrings against item names. + * Leave empty to fall back to the keep list instead. + */ + @ConfigItem( + keyName = "itemsToBank", + name = "Items to bank (comma-separated)", + description = "Items whose name contains any of these substrings get deposited. Leave empty to deposit everything except Items to keep.", + position = 2, + section = bankingSection + ) + default String itemsToBank() { + return ""; + } + + /** + * Defaults preserve the smithing setup (hammer plus selected bar) so the bot never + * deposits the tools it needs to keep working. + */ + @ConfigItem( + keyName = "itemsToKeep", + name = "Items to keep (comma-separated)", + description = "Items to never deposit. Default keeps hammer + any bar tier you're smithing.", + position = 3, + section = bankingSection + ) + default String itemsToKeep() { + return "hammer,bar"; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusOverlay.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusOverlay.java new file mode 100644 index 0000000000..c3a0c70a77 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusOverlay.java @@ -0,0 +1,240 @@ +package net.runelite.client.plugins.microbot.smithingplus; + +import net.runelite.api.Client; +import net.runelite.api.Skill; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.smithingplus.data.AnvilItem; +import net.runelite.client.plugins.microbot.smithingplus.data.Bars; +import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.ui.FontManager; +import net.runelite.client.ui.overlay.OverlayPanel; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.ButtonComponent; +import net.runelite.client.ui.overlay.components.LineComponent; +import net.runelite.client.ui.overlay.components.TitleComponent; +import net.runelite.http.api.item.ItemPrice; + +import javax.inject.Inject; +import java.awt.*; +import java.text.NumberFormat; +import java.time.Duration; +import java.util.List; + +/** + * Overlay showing runtime, Smithing XP gained, XP/hr, smith cycles, current level + delta, + * GP/hr estimate, and status. + */ +public class AutoSmithingPlusOverlay extends OverlayPanel { + private static final Color TITLE_COLOR = new Color(0, 170, 0); + private static final Color HEADER_COLOR = new Color(140, 220, 140); + private static final Color NORMAL_TEXT_COLOR = Color.WHITE; + private static final Color HIGHLIGHT_COLOR = new Color(255, 235, 145); + + // Inventory capacity. A loose hammer occupies one slot, leaving 27 for bars; with the hammer on + // the tool belt all 28 slots hold bars. Used to convert smith cycles to items for the GP/hr line. + private static final int INVENTORY_SLOTS = 28; + + private final AutoSmithingPlusPlugin plugin; + private final Client client; + private final AutoSmithingPlusConfig config; + + // Pause button toggles Microbot.pauseAllScripts (global flag). Public final so the plugin's + // startUp() can call hookMouseListener(). + public final ButtonComponent pauseButton; + + @Inject + AutoSmithingPlusOverlay(AutoSmithingPlusPlugin plugin, Client client, AutoSmithingPlusConfig config) { + super(plugin); + this.plugin = plugin; + this.client = client; + this.config = config; + setPosition(OverlayPosition.TOP_LEFT); + setNaughty(); + + pauseButton = new ButtonComponent("Pause"); + pauseButton.setPreferredSize(new Dimension(100, 25)); + pauseButton.setParentOverlay(this); + pauseButton.setFont(FontManager.getRunescapeBoldFont()); + pauseButton.setOnClick(() -> { + Microbot.pauseAllScripts.set(!Microbot.pauseAllScripts.get()); + if (Microbot.pauseAllScripts.get()) { + // Kill in-flight walker. Without this, Rs2Walker keeps walking on its own executor + // after the script main loop pauses. + Rs2Walker.setTarget(null); + } + }); + } + + @Override + public Dimension render(Graphics2D graphics) { + try { + panelComponent.setPreferredSize(new Dimension(240, 300)); + // No clear: preserves the click-target registry for the Pause button. + + panelComponent.getChildren().add(TitleComponent.builder() + .text("AutoSmithingPlus v" + AutoSmithingPlusPlugin.version) + .color(TITLE_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Status:") + .right(Microbot.status == null ? "Idle" : Microbot.status) + .rightColor(HIGHLIGHT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder().left("").build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Statistics") + .leftColor(HEADER_COLOR) + .build()); + + AutoSmithingPlusScript script = plugin.getScript(); + if (script != null && script.getStartTimeMillis() > 0) { + int currentLevel = client.getRealSkillLevel(Skill.SMITHING); + int currentXp = client.getSkillExperience(Skill.SMITHING); + int xpGained = currentXp - script.getStartSkillXp(); + long runtimeMillis = System.currentTimeMillis() - script.getStartTimeMillis(); + long xpPerHour = (runtimeMillis > 1000) ? (xpGained * 3600000L / runtimeMillis) : 0; + + int levelDelta = currentLevel - script.getStartSkillLevel(); + String levelStr = currentLevel + (levelDelta > 0 ? " (+" + levelDelta + ")" : ""); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Smithing level:") + .right(levelStr) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("XP gained:") + .right(NumberFormat.getInstance().format(xpGained)) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("XP/hr:") + .right(NumberFormat.getInstance().format(xpPerHour)) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Smith cycles:") + .right(String.valueOf(script.getActionsCompleted())) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + // GP/hr: NET profit per item = product GE price minus the bars it consumes. The + // counter is smith cycles; each "Smith All" works a full inventory of bars, so + // items per cycle is roughly freeBarSlots / bars-per-item. Can be negative when + // bars cost more than the product. Guards runtime 0 and price 0; the product price + // is 0 for items whose name doesn't follow the "Tier base" pattern. The "~" marks + // it an estimate (cycle->item conversion). + long gpPerHour = 0; + Bars activeBar = script.getActiveBar(); + AnvilItem activeItem = script.getActiveItem(); + if (activeBar != null && activeItem != null && runtimeMillis > 1000 + && activeItem.getRequiredBars() > 0) { + int productPrice = productPrice(activeBar, activeItem); + int barPrice = Microbot.getItemManager().getItemPrice(activeBar.getId()); + if (productPrice > 0) { + long netPerItem = (long) productPrice - (long) barPrice * activeItem.getRequiredBars(); + long itemsSmithed = (long) script.getActionsCompleted() + * (freeBarSlots() / activeItem.getRequiredBars()); + gpPerHour = netPerItem * itemsSmithed * 3600000L / runtimeMillis; + } + } + panelComponent.getChildren().add(LineComponent.builder() + .left("GP/hr:") + .right("~" + NumberFormat.getInstance().format(gpPerHour)) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + panelComponent.getChildren().add(LineComponent.builder() + .left("Runtime:") + .right(formatDuration(Duration.ofMillis(runtimeMillis))) + .rightColor(NORMAL_TEXT_COLOR) + .build()); + + // target-level progress line. + if (config.targetLevel() > 0) { + int toGo = Math.max(0, config.targetLevel() - currentLevel); + panelComponent.getChildren().add(LineComponent.builder() + .left("Target:") + .right(config.targetLevel() + (toGo > 0 ? " (" + toGo + " to go)" : " (reached)")) + .rightColor(HIGHLIGHT_COLOR) + .build()); + } + + } else { + panelComponent.getChildren().add(LineComponent.builder() + .left("(not running)") + .leftColor(NORMAL_TEXT_COLOR) + .build()); + } + + // Pause button added unconditionally to win the click-bounds registration race + // against the first render. + pauseButton.setText(Microbot.pauseAllScripts.get() ? "Resume" : "Pause"); + panelComponent.getChildren().add(pauseButton); + + } catch (Exception ex) { + Microbot.logStackTrace(this.getClass().getSimpleName(), ex); + } + return super.render(graphics); + } + + /** Inventory slots available for bars: all 28 with the hammer on the tool belt, else 27. */ + private int freeBarSlots() { + return config.hammerOnToolBelt() ? INVENTORY_SLOTS : INVENTORY_SLOTS - 1; + } + + private String formatDuration(Duration duration) { + long hours = duration.toHours(); + long minutes = duration.toMinutesPart(); + long seconds = duration.toSecondsPart(); + return String.format("%02d:%02d:%02d", hours, minutes, seconds); + } + + // Cache the resolved product item id so the name search runs only when the active bar/item + // changes, not every render frame. search() scans the whole item database; getItemPrice by id + // is a cheap lookup. + private Bars cachedProductBar; + private AnvilItem cachedProductItem; + private int cachedProductId = 0; + + /** + * GE price of the product smithed from {@code bar} at {@code item}. AnvilItem carries no + * product item id (it is widget-child driven), so we build the in-game name from the bar's + * product prefix + the item's base name (e.g. "Bronze dagger") and resolve it once via the + * item manager's name search (exact match), then cache the id. Returns 0 when the name can't be + * built or no item matches, so the overlay shows GP/hr 0 rather than mispricing. + */ + private int productPrice(Bars bar, AnvilItem item) { + if (bar != cachedProductBar || item != cachedProductItem) { + cachedProductBar = bar; + cachedProductItem = item; + cachedProductId = resolveProductId(bar, item); + } + return cachedProductId > 0 ? Microbot.getItemManager().getItemPrice(cachedProductId) : 0; + } + + private int resolveProductId(Bars bar, AnvilItem item) { + String prefix = bar.getProductPrefix(); + String base = item.getProductBaseName(); + if (prefix == null || base == null) { + return 0; + } + String fullName = prefix + " " + base; + List matches = Microbot.getItemManager().search(fullName); + if (matches == null || matches.isEmpty()) { + return 0; + } + for (ItemPrice match : matches) { + if (match.getName() != null && match.getName().equalsIgnoreCase(fullName)) { + return match.getId(); + } + } + return 0; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusPlugin.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusPlugin.java new file mode 100644 index 0000000000..5c9d4b10dd --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusPlugin.java @@ -0,0 +1,75 @@ +package net.runelite.client.plugins.microbot.smithingplus; + +import com.google.inject.Provides; +import lombok.extern.slf4j.Slf4j; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.PluginConstants; +import net.runelite.client.ui.overlay.OverlayManager; + +import javax.inject.Inject; +import java.awt.*; + +@PluginDescriptor( + name = PluginDescriptor.Mocrosoft + "Auto Smithing Plus", + description = "Smiths bars into items at a configured anvil. Pick a Bar, Item and Anvil; the bot walks there, banks bars, smiths, and repeats. Part of the Plus suite.", + tags = {"smithing", "anvil", "microbot", "plus"}, + authors = {"StickToTheScript", "pjmarz"}, + version = AutoSmithingPlusPlugin.version, + minClientVersion = "2.0.13", + cardUrl = "https://chsami.github.io/Microbot-Hub/AutoSmithingPlusPlugin/assets/card.png", + iconUrl = "https://chsami.github.io/Microbot-Hub/AutoSmithingPlusPlugin/assets/icon.png", + enabledByDefault = PluginConstants.DEFAULT_ENABLED, + isExternal = PluginConstants.IS_EXTERNAL +) +@Slf4j +public class AutoSmithingPlusPlugin extends Plugin { + public static final String version = "0.6.6"; + + @Inject + private AutoSmithingPlusConfig config; + + @Provides + AutoSmithingPlusConfig provideConfig(ConfigManager configManager) { + return configManager.getConfig(AutoSmithingPlusConfig.class); + } + + @Inject + private OverlayManager overlayManager; + + @Inject + private AutoSmithingPlusOverlay overlay; + + @Inject + AutoSmithingPlusScript script; + + @Override + protected void startUp() throws AWTException { + // Clear any stale pause flag from a previous session. + Microbot.pauseAllScripts.compareAndSet(true, false); + if (overlayManager != null) { + overlayManager.add(overlay); + // hookMouseListener is what actually wires setOnClick to RuneLite's mouse events. + overlay.pauseButton.hookMouseListener(); + } + script.run(config); + } + + @Override + protected void shutDown() { + // Clear flag so other plugins enabled after us don't inherit our paused state. + Microbot.pauseAllScripts.compareAndSet(true, false); + script.shutdown(); + if (overlay != null) { + overlay.pauseButton.unhookMouseListener(); + } + overlayManager.remove(overlay); + } + + /** overlay reads script stats via this getter. */ + public AutoSmithingPlusScript getScript() { + return script; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusScript.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusScript.java new file mode 100644 index 0000000000..62959d7281 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/AutoSmithingPlusScript.java @@ -0,0 +1,512 @@ +package net.runelite.client.plugins.microbot.smithingplus; + +import lombok.extern.slf4j.Slf4j; +import net.runelite.api.Skill; +import net.runelite.api.coords.WorldPoint; +import net.runelite.api.gameval.ItemID; +import net.runelite.client.plugins.microbot.Microbot; +import net.runelite.client.plugins.microbot.Script; +import net.runelite.client.plugins.microbot.api.tileobject.models.Rs2TileObjectModel; +import net.runelite.client.plugins.microbot.smithingplus.data.AnvilItem; +import net.runelite.client.plugins.microbot.smithingplus.data.AnvilLocationOption; +import net.runelite.client.plugins.microbot.smithingplus.data.BankLocationOption; +import net.runelite.client.plugins.microbot.smithingplus.data.Bars; +import net.runelite.client.plugins.microbot.util.antiban.Rs2Antiban; +import net.runelite.client.plugins.microbot.util.antiban.Rs2AntibanSettings; +import net.runelite.client.plugins.microbot.util.bank.Rs2Bank; +import net.runelite.client.plugins.microbot.util.inventory.Rs2Inventory; +import net.runelite.client.plugins.microbot.util.keyboard.Rs2Keyboard; +import net.runelite.client.plugins.microbot.util.math.Rs2Random; +import net.runelite.client.plugins.microbot.util.player.Rs2Player; +import net.runelite.client.plugins.microbot.util.security.Login; +import net.runelite.client.plugins.microbot.util.walker.Rs2Walker; +import net.runelite.client.plugins.microbot.util.widget.Rs2Widget; + +import java.awt.event.KeyEvent; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * AutoSmithingPlus: smiths bars into items at a configured anvil, with a bank cycle, autohop, + * pre-flight validation (bronze-only anvils, members-only items, Smithing level), and a + * progressive mode that picks the best item for the current level and bar tier. + */ +@Slf4j +public class AutoSmithingPlusScript extends Script { + + private static final int ANVIL_WIDGET_CONTAINER = 312; + private static final int ANVIL_MAKE_QTY_CHILD = 7; // "All" multiplier in the smithing widget + // Player varp holding the anvil make-quantity; when it already equals the bar count "All" is + // selected and re-clicking the multiplier is redundant. + private static final int ANVIL_MAKE_QTY_VARP = 2224; + // Animation-poll window (ms) used to treat the player as busy while a smith batch runs. + private static final int SMITH_ANIM_TIMEOUT_MS = 2400; + + State state = State.SMITHING; + + // runtime stats tracking (read by AutoSmithingPlusOverlay). + private long startTimeMillis = 0; + private int startSkillXp = 0; + private int startSkillLevel = 0; + private int actionsCompleted = 0; + + // target-level cleanup flag. Intercepted after deposit in handleBankAndWithdraw. + private boolean shutdownAfterCleanup = false; + + // smith stall detection. If smith clicks produce no Smithing XP across several attempts, the + // selected item is greyed (above our Smithing level, or wrong bar for it) and the bot would + // loop forever clicking it ("looks frozen"). Track XP between attempts and bail. + private int smithLastAttemptXp = -1; + private int smithNoProgressAttempts = 0; + + public long getStartTimeMillis() { return startTimeMillis; } + public int getStartSkillXp() { return startSkillXp; } + public int getStartSkillLevel() { return startSkillLevel; } + public int getActionsCompleted() { return actionsCompleted; } + + // Config reference kept so the overlay can resolve the active bar + item for the GP/hr line. + private AutoSmithingPlusConfig config; + /** The bar tier currently being smithed, for the overlay GP/hr line. */ + public Bars getActiveBar() { return config != null ? config.selectedBar() : null; } + /** The item currently being smithed (resolves progressive mode), for the overlay GP/hr line. */ + public AnvilItem getActiveItem() { return config != null ? activeItem(config) : null; } + + public boolean run(AutoSmithingPlusConfig config) { + this.config = config; + initialPlayerLocation = null; + state = State.SMITHING; + + // seed stats trackers from client thread. + startTimeMillis = System.currentTimeMillis(); + startSkillXp = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getSkillExperience(Skill.SMITHING)).orElse(0); + startSkillLevel = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getRealSkillLevel(Skill.SMITHING)).orElse(1); + actionsCompleted = 0; + shutdownAfterCleanup = false; + smithLastAttemptXp = -1; // reset stall detection + smithNoProgressAttempts = 0; + + Rs2Walker.disableTeleports = true; + Rs2Antiban.resetAntibanSettings(); + Rs2Antiban.antibanSetupTemplates.applySmithingSetup(); + + if (config.speedMode()) { + Rs2AntibanSettings.antibanEnabled = false; + } + + // Pre-flight checks. Refuse-start with a chat log if the config is incoherent. + if (config.anvilLocation() != null && config.anvilLocation().isBronzeOnly() + && config.selectedBar() != Bars.BRONZE) { + Microbot.log("Pre-flight FAILED: anvil " + config.anvilLocation().getDisplayName() + + " is bronze-only but selected bar is " + config.selectedBar().getName() + + ". Pick BRONZE or a different anvil. Shutting down."); + super.shutdown(); + return false; + } + // item/level pre-flight. Progressive mode validates that SOME item is makeable at the + // chosen bar for our level; manual mode validates the user's specific item + bar (members + // gate + Smithing-level gate). The stall-detection stays as a backstop. + if (config.progressiveSmith()) { + AnvilItem progBest = AnvilItem.bestForLevel(config.selectedBar(), startSkillLevel, Rs2Player.isMember()); + if (progBest == null) { + Microbot.log("Pre-flight FAILED: progressive mode found no smithable item for " + + config.selectedBar().getName() + " at Smithing level " + startSkillLevel + + " (members items excluded on F2P). Lower the bar tier. Shutting down."); + super.shutdown(); + return false; + } + } else { + if (AnvilItem.isMembersOnly(config.selectedItem()) && !Rs2Player.isMember()) { + Microbot.log("Pre-flight FAILED: item " + config.selectedItem().getName() + + " is members-only and you're on F2P. Pick a different item. Shutting down."); + super.shutdown(); + return false; + } + int requiredSmithLevel = config.selectedItem().getRequiredLevel(config.selectedBar()); + if (requiredSmithLevel > 0 && startSkillLevel < requiredSmithLevel) { + Microbot.log("Pre-flight FAILED: " + config.selectedItem().getName() + " (" + + config.selectedBar().getName() + ") needs Smithing " + requiredSmithLevel + + " but you are level " + startSkillLevel + ". Pick a lower item or bar tier. Shutting down."); + super.shutdown(); + return false; + } + } + + mainScheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> { + try { + if (!super.run()) return; + if (!Microbot.isLoggedIn()) return; + + // Pause check using global Microbot.pauseAllScripts (toggled via overlay button). + // Stats keep accumulating naturally during pause. + if (Microbot.pauseAllScripts.get()) { + Microbot.status = "[PAUSED]"; + return; + } + + // stopAfterMinutes / stopAfterXp threshold check. + if (config.stopAfterMinutes() > 0 + && (System.currentTimeMillis() - startTimeMillis) / 60000 >= config.stopAfterMinutes()) { + Microbot.log("AutoSmithingPlus: reached stopAfterMinutes (" + config.stopAfterMinutes() + + " min). Shutting down."); + super.shutdown(); + return; + } + if (config.stopAfterXp() > 0) { + int currentXp = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getSkillExperience(Skill.SMITHING)).orElse(startSkillXp); + if (currentXp - startSkillXp >= config.stopAfterXp()) { + Microbot.log("AutoSmithingPlus: reached stopAfterXp (" + (currentXp - startSkillXp) + + " XP). Shutting down."); + super.shutdown(); + return; + } + } + + // target-level check. + if (config.targetLevel() > 0 && !shutdownAfterCleanup) { + int currentLevel = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getRealSkillLevel(Skill.SMITHING)).orElse(startSkillLevel); + if (currentLevel >= config.targetLevel()) { + Microbot.log("AutoSmithingPlus: reached targetLevel (" + currentLevel + " >= " + + config.targetLevel() + "). Depositing items before shutdown."); + shutdownAfterCleanup = true; + if (Rs2Inventory.isEmpty()) { + super.shutdown(); + return; + } + state = State.RESETTING; + } + } + + // League mode: periodic key press resets the idle-logout. Pattern from + // AutoMiningPlus. + if (config.leagueMode() && Rs2Player.checkIdleLogout(Rs2Random.between(500, 1500))) { + int[] arrowKeys = { KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT, KeyEvent.VK_UP, KeyEvent.VK_DOWN }; + Rs2Keyboard.keyPress(arrowKeys[Rs2Random.between(0, arrowKeys.length - 1)]); + } + + if (Rs2AntibanSettings.actionCooldownActive) return; + + if (initialPlayerLocation == null) { + initialPlayerLocation = Rs2Player.getWorldLocation(); + } + if (initialPlayerLocation == null) return; + + // Anchor re-pin per tick when a specific anvil is configured. + AnvilLocationOption anvilChoice = config.anvilLocation(); + if (anvilChoice != null && anvilChoice != AnvilLocationOption.AUTO_NEAREST + && anvilChoice.getWorldPoint() != null) { + initialPlayerLocation = anvilChoice.getWorldPoint(); + } + + if (Rs2Player.isMoving() || Rs2Player.isAnimating(SMITH_ANIM_TIMEOUT_MS)) return; + + // Autohop: only relevant while actively smithing at the anvil (busy/PK risk). + if (state == State.SMITHING && config.maxPlayersInArea() > 0) { + if (hopIfCrowded(config)) return; + } + + // State auto-flip: if we don't have enough bars or no hammer, switch to RESETTING. + if (!inventoryHasMaterialsForOneCraft(config)) { + state = State.RESETTING; + } + + switch (state) { + case SMITHING: + smithAtAnvil(config); + break; + case RESETTING: + handleBankAndWithdraw(config); + break; + } + + Rs2Antiban.actionCooldown(); + Rs2Antiban.takeMicroBreakByChance(); + } catch (Exception ex) { + Microbot.logStackTrace("AutoSmithingPlusScript", ex); + } + }, 0, 600, TimeUnit.MILLISECONDS); + return true; + } + + @Override + public void shutdown() { + // Reset the disableTeleports flag set in run() so it doesn't leak to the next plugin that + // uses Rs2Walker. + Rs2Walker.disableTeleports = false; + super.shutdown(); + Rs2Antiban.resetAntibanSettings(); + } + + // --- Autohop --- + + private boolean hopIfCrowded(AutoSmithingPlusConfig config) { + int maxPlayers = config.maxPlayersInArea(); + WorldPoint localLocation = Rs2Player.getWorldLocation(); + if (localLocation == null) return false; + + long nearbyPlayers = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getTopLevelWorldView().players().stream() + .filter(p -> p != null && p != Microbot.getClient().getLocalPlayer()) + .filter(p -> { + if (config.distanceToStray() == 0) { + return p.getWorldLocation().equals(localLocation); + } + return p.getWorldLocation().distanceTo(localLocation) <= config.distanceToStray(); + }) + .count()) + .orElse(0L); + + if (nearbyPlayers >= maxPlayers) { + Microbot.status = "Too many players nearby. Hopping..."; + Rs2Random.waitEx(3200, 800); + int world = Login.getRandomWorld(Rs2Player.isMember()); + boolean hopped = Microbot.hopToWorld(world); + if (hopped) { + Microbot.status = "Hopped to world: " + world; + return true; + } + } + return false; + } + + // --- SMITHING state --- + + private void smithAtAnvil(AutoSmithingPlusConfig config) { + AnvilLocationOption choice = config.anvilLocation(); + + if (choice != null && choice != AnvilLocationOption.AUTO_NEAREST + && choice.getWorldPoint() != null) { + WorldPoint target = choice.getWorldPoint(); + WorldPoint playerLoc = Rs2Player.getWorldLocation(); + if (playerLoc != null && playerLoc.distanceTo(target) > config.distanceToStray()) { + Microbot.status = "Walking to " + choice.getDisplayName(); + Rs2Walker.walkTo(target, Math.min(config.distanceToStray(), 5)); + return; + } + } + + if (Rs2Bank.isOpen()) { + Rs2Bank.closeBank(); + sleepUntil(() -> !Rs2Bank.isOpen(), 1500); + return; + } + + // Name-based anvil query matches both regular anvils ("Anvil", object ID 2097) and + // variant anvils ("Rusted anvil", object ID 39620). + Rs2TileObjectModel anvil = Microbot.getRs2TileObjectCache().query() + .withNameContains("anvil") + .nearestOnClientThread(initialPlayerLocation, 20); + + if (anvil == null) { + if (initialPlayerLocation.distanceTo(Rs2Player.getWorldLocation()) > 4) { + Microbot.status = "Walking back to anvil anchor"; + Rs2Walker.walkTo(initialPlayerLocation, 4); + } else { + Microbot.status = "AutoSmithingPlus: no anvil within 20 tiles of anchor - pick an Anvil in config or stand near one"; + } + return; + } + + Bars bar = config.selectedBar(); + AnvilItem item = activeItem(config); + Microbot.status = "Smithing " + bar.getName() + " -> " + item.getName(); + + anvil.click("Smith"); + sleepUntil(() -> Rs2Widget.getWidget(ANVIL_WIDGET_CONTAINER, 1) != null, 5000); + sleep(180, 480); + + if (Rs2Widget.getWidget(ANVIL_WIDGET_CONTAINER, 1) == null) { + Microbot.status = "Anvil widget didn't open; will retry next tick"; + return; + } + + // Click "All" multiplier only when the make-quantity is not already maxed, so we don't + // fire a redundant click + sleep every cycle once "All" is selected. + if (Microbot.getVarbitPlayerValue(ANVIL_MAKE_QTY_VARP) < Rs2Inventory.count(bar.getId())) { + Rs2Widget.clickWidget(ANVIL_WIDGET_CONTAINER, ANVIL_MAKE_QTY_CHILD); + sleep(180, 480); + } + + // Stall detection. Compare Smithing XP since the previous smith click. If 4 consecutive + // clicks produce no XP, the item is greyed (above our Smithing level, or the wrong bar for + // it) and we'd loop forever on a no-op click. Bail with a clear message. Also catches a + // drifted widget child id. XP recorded BEFORE the smith, so a working cycle's gain registers + // by the next click and resets the counter (bank trips don't false-trip it). + int smithXpNow = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getSkillExperience(Skill.SMITHING)).orElse(smithLastAttemptXp); + if (smithLastAttemptXp >= 0 && smithXpNow <= smithLastAttemptXp) { + if (++smithNoProgressAttempts >= 4) { + Microbot.log("AutoSmithingPlus: 4 smith attempts with no Smithing XP gained. '" + + item.getName() + "' is likely above your Smithing level, or the wrong " + + "bar (" + bar.getName() + ") is selected for it. Shutting down so you're " + + "not stuck clicking a greyed item."); + super.shutdown(); + return; + } + } else { + smithNoProgressAttempts = 0; + } + smithLastAttemptXp = smithXpNow; + + // Click the chosen item's child slot. Count the cycle only if smithing actually started: + // a greyed/no-op click never animates, while a real "Smith All" does, so the counter and + // the overlay's GP/hr estimate track real cycles instead of blind clicks. + Rs2Widget.clickWidget(ANVIL_WIDGET_CONTAINER, item.getChildId()); + boolean started = sleepUntil(() -> Rs2Player.isAnimating(SMITH_ANIM_TIMEOUT_MS), 1200); + if (started) { + actionsCompleted++; + } + } + + // --- RESETTING state --- + + private void handleBankAndWithdraw(AutoSmithingPlusConfig config) { + if (!Rs2Bank.isOpen()) { + if (!walkToConfiguredBank(config)) { + return; + } + return; + } + Rs2Player.waitForWalking(); + sleep(600, 1200); + + // CSV-driven deposit. Inclusion list wins; exclusion list as fallback. + depositByCsv(config); + AnvilItem item = activeItem(config); + sleepUntil(() -> !Rs2Inventory.hasItem(item.getName()), 3000); + + // targetLevel cleanup done: shutdown before re-withdrawing hammer/bars. + if (shutdownAfterCleanup) { + Microbot.log("AutoSmithingPlus: targetLevel cleanup complete. Shutting down."); + Rs2Bank.closeBank(); + super.shutdown(); + return; + } + + // Withdraw hammer if missing. Skipped entirely when the hammer is on the tool belt (config + // toggle), since no loose hammer is needed in that case. + if (!config.hammerOnToolBelt() && !Rs2Inventory.hasItem(ItemID.HAMMER)) { + if (!Rs2Bank.hasItem(ItemID.HAMMER)) { + Microbot.log("No hammer in inventory or bank. Tick 'Hammer on tool belt' in config " + + "if yours is stored there. Shutting down."); + Rs2Bank.closeBank(); + shutdown(); + return; + } + Rs2Bank.withdrawOne(ItemID.HAMMER); + sleepUntil(() -> Rs2Inventory.hasItem(ItemID.HAMMER), 3000); + return; + } + + // Withdraw bars: all of them. + String barName = config.selectedBar().getName(); + if (Rs2Bank.count(barName) < item.getRequiredBars()) { + Microbot.log("Bank lacks " + item.getRequiredBars() + " " + barName + + " for one " + item.getName() + ". Shutting down."); + Rs2Bank.closeBank(); + shutdown(); + return; + } + Rs2Bank.withdrawAll(barName); + sleepUntil(() -> Rs2Inventory.hasItem(barName), 3000); + + if (!Rs2Inventory.hasItem(barName)) { + Microbot.log("Withdraw of " + barName + " didn't settle in 3s; retrying next tick."); + return; + } + + if (inventoryHasMaterialsForOneCraft(config)) { + Rs2Bank.closeBank(); + state = State.SMITHING; + } + } + + private void depositByCsv(AutoSmithingPlusConfig config) { + List bankNames = parseCsv(config.itemsToBank()); + List keepNames = parseCsv(config.itemsToKeep()); + + if (!bankNames.isEmpty()) { + Rs2Bank.depositAll(i -> i.getName() != null + && bankNames.stream().anyMatch(b -> i.getName().toLowerCase().contains(b)) + && keepNames.stream().noneMatch(k -> i.getName().toLowerCase().contains(k))); + } else if (!keepNames.isEmpty()) { + Rs2Bank.depositAll(i -> i.getName() != null + && keepNames.stream().noneMatch(k -> i.getName().toLowerCase().contains(k))); + } else { + Rs2Bank.depositAll(); + } + } + + private List parseCsv(String s) { + if (s == null) return Collections.emptyList(); + return Arrays.stream(s.split(",")) + .map(String::trim) + .map(String::toLowerCase) + .filter(x -> !x.isEmpty()) + .collect(Collectors.toList()); + } + + private boolean walkToConfiguredBank(AutoSmithingPlusConfig config) { + BankLocationOption choice = config.bankLocation(); + if (choice == null || choice == BankLocationOption.AUTO_NEAREST) { + return Rs2Bank.walkToBankAndUseBank(); + } + WorldPoint bankPoint = choice.getWorldPoint(); + if (bankPoint == null) { + return Rs2Bank.walkToBankAndUseBank(); + } + WorldPoint playerLocation = Rs2Player.getWorldLocation(); + if (playerLocation == null) return false; + + if (playerLocation.getX() != bankPoint.getX() + || playerLocation.getY() != bankPoint.getY() + || playerLocation.getPlane() != bankPoint.getPlane()) { + if (playerLocation.distanceTo(bankPoint) > 4) { + if (!Rs2Player.isMoving()) { + Rs2Walker.walkTo(bankPoint, 4); + } + return false; + } + } + return Rs2Bank.openBank(); + } + + // --- Helpers --- + + /** + * The item to smith this tick: in progressive mode, the best item our current Smithing level + * can make at the configured bar (recomputed as we level up); otherwise the configured item. + * Falls back to the configured item if progressive somehow finds nothing. + */ + private AnvilItem activeItem(AutoSmithingPlusConfig config) { + if (!config.progressiveSmith()) return config.selectedItem(); + int level = Microbot.getClientThread().runOnClientThreadOptional(() -> + Microbot.getClient().getRealSkillLevel(Skill.SMITHING)).orElse(startSkillLevel); + AnvilItem best = AnvilItem.bestForLevel(config.selectedBar(), level, Rs2Player.isMember()); + return best != null ? best : config.selectedItem(); + } + + private boolean inventoryHasMaterialsForOneCraft(AutoSmithingPlusConfig config) { + if (!hasHammer(config)) return false; + String barName = config.selectedBar().getName(); + int needed = activeItem(config).getRequiredBars(); + return Rs2Inventory.hasItemAmount(barName, needed, false, true); + } + + /** + * Hammer present for smithing? A hammer in the inventory satisfies it, and so does the "Hammer + * on tool belt" config opt-in. The OSRS tool belt is not exposed by any varbit or Rs2 helper in + * this client/API version, so it cannot be auto-detected from code; the toggle is how the user + * declares it. With the toggle on we never require or withdraw a loose hammer, since the tool + * belt one is always available at the anvil. + */ + private boolean hasHammer(AutoSmithingPlusConfig config) { + return config.hammerOnToolBelt() || Rs2Inventory.hasItem(ItemID.HAMMER); + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/State.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/State.java new file mode 100644 index 0000000000..11cb3f3ba8 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/State.java @@ -0,0 +1,19 @@ +// Pattern from AutoMiningPlus / AutoSmeltingPlus: keep the state enum small. Two states (work + +// bank cycle) covers every gathering and stationary skill in the Hub. If you need 3+ phases +// with guard conditions, switch to StateMachineScript instead of Script. + +package net.runelite.client.plugins.microbot.smithingplus; + +enum State { + /** + * At the anvil with bars + hammer, smithing items. Triggered when inventory has at least + * the {@code requiredBars} for one craft of the selected item AND has a hammer. + */ + SMITHING, + + /** + * Inventory is full of smithed items, or we lack the bars/hammer to craft. Walk to bank, + * deposit smithed items, withdraw bars (and hammer if missing), walk back to anvil. + */ + RESETTING, +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilItem.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilItem.java new file mode 100644 index 0000000000..2307aad1ad --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilItem.java @@ -0,0 +1,192 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * Smithable items at an anvil. Each item carries the in-game widget child ID and the number of + * bars consumed per craft. + * + *

The anvil interaction is widget-driven: clicking an anvil with a hammer + bar in inventory + * opens the smithing widget (container ID {@code 312}). Each item occupies a child slot; the + * {@link #getChildId()} maps the item to that slot. Clicking child[childId] with the active bar + * tier (Bronze/Iron/Steel/etc.) selected smiths that item. + * + *

Item list, child IDs and bar counts are forked from the upstream {@code varrockanvil} plugin; + * level requirements and members flags are cross-referenced against the + * OSRS Wiki Anvil page. + * + *

Some entries are bar-tier-specific aliases: {@code BRONZE_WIRE} shares its child slot with + * Iron spit and Steel studs, so picking the wrong bar tier produces a different item in that slot. + */ +@Getter +@RequiredArgsConstructor +public enum AnvilItem { + DAGGER("Dagger", 9, 1), + SWORD("Sword", 10, 1), + SCIMITAR("Scimitar", 11, 2), + LONG_SWORD("Long sword", 12, 2), + TWO_HAND_SWORD("2-hand sword", 13, 3), + AXE("Axe", 14, 1), + MACE("Mace", 15, 1), + WARHAMMER("Warhammer", 16, 3), + BATTLE_AXE("Battle axe", 17, 3), + CLAWS("Claws", 18, 2), + CHAIN_BODY("Chain body", 19, 3), + PLATE_LEGS("Plate legs", 20, 3), + PLATE_SKIRT("Plate skirt", 21, 3), + PLATE_BODY("Plate body", 22, 5), + NAILS("Nails", 23, 1), + MEDIUM_HELM("Medium helm", 24, 1), + FULL_HELM("Full helm", 25, 2), + SQUARE_SHIELD("Square shield", 26, 2), + KITE_SHIELD("Kite shield", 27, 3), + OIL_LAMP("Oil lamp (bronze only)", 28, 1), + DART_TIPS("Dart tips", 29, 1), + ARROWTIPS("Arrowtips", 30, 1), + KNIVES("Knives", 31, 1), + BRONZE_WIRE("Wire / spit / studs", 32, 1), + BULLSEYE_LAMP("Bullseye lamp (steel)", 28, 1), + BOLTS("Bolts (unf)", 34, 1); + + private final String itemName; + private final int childId; + private final int requiredBars; + + public String getName() { + return itemName; + } + + @Override + public String toString() { + return itemName; + } + + /** + * The product's in-game name minus the bar-tier prefix (e.g. "dagger" -> "Bronze dagger", + * "med helm" -> "Bronze med helm"). Combined with {@link Bars#getProductPrefix()} to look up + * the finished item's GE price for the overlay GP/hr line. Returns null for items whose + * product name does not follow the simple "Tier base" pattern (wire/spit/studs, lamps, bolts, + * dart tips, arrowtips, nails, knives); the overlay then shows GP/hr 0 for those rather than + * pricing the wrong item. + */ + public String getProductBaseName() { + switch (this) { + case DAGGER: return "dagger"; + case SWORD: return "sword"; + case SCIMITAR: return "scimitar"; + case LONG_SWORD: return "longsword"; + case TWO_HAND_SWORD: return "2h sword"; + case AXE: return "axe"; + case MACE: return "mace"; + case WARHAMMER: return "warhammer"; + case BATTLE_AXE: return "battleaxe"; + case CLAWS: return "claws"; + case CHAIN_BODY: return "chainbody"; + case PLATE_LEGS: return "platelegs"; + case PLATE_SKIRT: return "plateskirt"; + case PLATE_BODY: return "platebody"; + case MEDIUM_HELM: return "med helm"; + case FULL_HELM: return "full helm"; + case SQUARE_SHIELD: return "sq shield"; + case KITE_SHIELD: return "kiteshield"; + // Non-standard product names (multi-output, tier-locked, or unusual naming) - priced 0. + default: return null; + } + } + + /** + * Members-only filter. Bronze claws (and all higher-tier claws) require completion of the Cabin + * Fever members quest, so the smithing widget doesn't show that slot on F2P. Picking a + * members-only item on F2P would stall the bot, so the pre-flight check uses this to + * refuse-start. Extend this method if more members-only items surface. + */ + public static boolean isMembersOnly(AnvilItem item) { + if (item == null) return false; + switch (item) { + // Members-only anvil products: an F2P account cannot smith these (the widget slot is + // absent), so the Script's pre-flight refuses to start rather than stalling on a no-op + // click. NAILS, DART_TIPS, ARROWTIPS and KNIVES are F2P-smithable in OSRS and are + // deliberately not listed here. + case CLAWS: + case OIL_LAMP: + case BULLSEYE_LAMP: + case BRONZE_WIRE: // shared slot also covers Iron spit / Steel studs, both members + case BOLTS: + return true; + default: + return false; + } + } + + /** + * Smithing level required to smith this item at the given bar tier, or -1 if not makeable at + * that tier. Indexed Bronze/Iron/Steel/Mithril/Adamant/Rune. Drives the Script's level + * pre-flight and progressive mode. The Script's stall-detection stays as a reactive backstop + * for any residual table error or a drifted widget id. + */ + public int getRequiredLevel(Bars bar) { + if (bar == null) return -1; + int[] levels = levelsByBar(this); + int idx = bar.ordinal(); + return (idx >= 0 && idx < levels.length) ? levels[idx] : -1; + } + + // Bronze, Iron, Steel, Mithril, Adamant, Rune. -1 = not makeable at that tier. + private static int[] levelsByBar(AnvilItem item) { + switch (item) { + case DAGGER: return new int[]{ 1, 15, 30, 50, 70, 85}; + case SWORD: return new int[]{ 4, 19, 34, 54, 74, 89}; + case SCIMITAR: return new int[]{ 5, 20, 35, 55, 75, 90}; + case LONG_SWORD: return new int[]{ 6, 21, 36, 56, 76, 91}; + case TWO_HAND_SWORD: return new int[]{14, 29, 44, 64, 84, 99}; + case AXE: return new int[]{ 1, 16, 31, 51, 71, 86}; + case MACE: return new int[]{ 2, 17, 32, 52, 72, 87}; + case WARHAMMER: return new int[]{ 9, 24, 39, 59, 79, 94}; + case BATTLE_AXE: return new int[]{10, 25, 40, 60, 80, 95}; + case CLAWS: return new int[]{13, 28, 43, 63, 83, 98}; + case CHAIN_BODY: return new int[]{11, 26, 41, 61, 81, 96}; + case PLATE_LEGS: return new int[]{16, 31, 46, 66, 86, 99}; + case PLATE_SKIRT: return new int[]{16, 31, 46, 66, 86, 99}; + case PLATE_BODY: return new int[]{18, 33, 48, 68, 88, 99}; + case NAILS: return new int[]{ 4, 19, 34, 54, 74, 89}; + case MEDIUM_HELM: return new int[]{ 3, 18, 33, 53, 73, 88}; + case FULL_HELM: return new int[]{ 7, 22, 37, 57, 77, 92}; + case SQUARE_SHIELD: return new int[]{ 8, 23, 38, 58, 78, 93}; + case KITE_SHIELD: return new int[]{12, 27, 42, 62, 82, 97}; + case DART_TIPS: return new int[]{ 4, 19, 34, 54, 74, 89}; + case ARROWTIPS: return new int[]{ 5, 20, 35, 55, 75, 90}; + case KNIVES: return new int[]{ 7, 22, 37, 57, 77, 92}; + case BOLTS: return new int[]{ 3, 18, 33, 53, 73, 88}; + // Tier-locked / shared-slot members items (see isMembersOnly). The -1 tiers fall + // through the level gate (treated as "unknown", not a hard refuse) and rely on + // stall-detection if a wrong bar is picked. + case OIL_LAMP: return new int[]{-1, 26, -1, -1, -1, -1}; // oil lantern frame: iron, 26 + case BRONZE_WIRE: return new int[]{ 4, 17, 36, -1, -1, -1}; // wire(4)/iron spit(17)/steel studs(36) + case BULLSEYE_LAMP: return new int[]{-1, -1, 49, -1, -1, -1}; // bullseye frame: steel, 49 + default: return new int[]{}; + } + } + + /** + * Progressive-mode picker: the best item to smith at the given bar tier for a player of the + * given Smithing level. "Best" = most bars per craft (most XP per craft, fewest interface + * clicks), tie-broken by highest level requirement. Skips members-only items unless isMember. + * Returns null if nothing is makeable (e.g. a bar tier too high for any item at this level). + */ + public static AnvilItem bestForLevel(Bars bar, int smithingLevel, boolean isMember) { + AnvilItem best = null; + for (AnvilItem item : values()) { + if (!isMember && isMembersOnly(item)) continue; + int req = item.getRequiredLevel(bar); + if (req < 0 || req > smithingLevel) continue; + if (best == null + || item.getRequiredBars() > best.getRequiredBars() + || (item.getRequiredBars() == best.getRequiredBars() + && req > best.getRequiredLevel(bar))) { + best = item; + } + } + return best; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocationOption.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocationOption.java new file mode 100644 index 0000000000..36737f4cbf --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocationOption.java @@ -0,0 +1,66 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.coords.WorldPoint; + +/** + * User-facing dropdown of named anvils. Mirrors {@code FurnaceLocationOption} from smeltingplus. + * Each constant carries the display name and the canonical walk-to WorldPoint; the script + * resolves the actual anvil tile at runtime via a name-based object query. + * + *

{@link #AUTO_NEAREST} falls back to "find an anvil within 20 tiles of initialPlayerLocation" + * behavior (requires the user to start near an anvil, mirroring upstream VarrockAnvil's + * stand-at-anvil-or-restart behavior). + * + *

Anvil dataset is backed by {@link AnvilLocations}. + * + *

Important: variant anvils (e.g. Lumbridge's Rusted Anvil, object ID 39620) restrict the + * smithing widget to bronze items only. Picking a non-bronze bar at such an anvil will leave + * the bot stalled with the widget showing greyed slots. The {@link #isBronzeOnly()} flag exposes + * this. + */ +@Getter +@RequiredArgsConstructor +public enum AnvilLocationOption { + AUTO_NEAREST("Auto / nearest", null, null, false, false), + + // F2P + LUMBRIDGE_RUSTED("Lumbridge (bronze)", + "Lumbridge Rusted Anvil", new WorldPoint(3227, 3258, 0), false, true), + VARROCK_WEST("Varrock West", + "Varrock West Anvil", new WorldPoint(3188, 3426, 0), false, false), + + // Varrock Central: 2 anvils in Horvik's armour shop, F2P, all-bar, 31 squares from W bank. + VARROCK_CENTRAL("Varrock Central", + "Varrock Central Anvil", new WorldPoint(3225, 3424, 0), false, false), + + // Varrock East: 2 anvils just south of the east bank on the west side, F2P, all-bar, + // 35 squares from E bank. + VARROCK_EAST("Varrock East", + "Varrock East Anvil", new WorldPoint(3247, 3410, 0), false, false), + + // P2P anvils. The anchor is the town area near the anvil; the runtime 20-tile finder resolves + // the exact anvil tile. + YANILLE("Yanille (P2P)", + "Yanille Anvil", new WorldPoint(2614, 3084, 0), true, false), + SEERS_VILLAGE("Seers' Village (P2P)", + "Seers' Village Anvil", new WorldPoint(2701, 3482, 0), true, false), + BURTHORPE("Burthorpe (P2P)", + "Burthorpe Anvil", new WorldPoint(2899, 3542, 0), true, false); + + private final String displayName; + private final String locationName; + private final WorldPoint worldPoint; + private final boolean membersOnly; + private final boolean bronzeOnly; + + @Override + public String toString() { + return displayName; + } + + public boolean hostsTarget(Object target) { + return this != AUTO_NEAREST; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocations.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocations.java new file mode 100644 index 0000000000..15afd69365 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/AnvilLocations.java @@ -0,0 +1,89 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import net.runelite.api.coords.WorldPoint; + +import java.util.Arrays; +import java.util.List; + +/** + * Anvil location dataset. Mirrors {@code FurnaceLocations} from smeltingplus but for anvils. + * + *

{@link AnvilLocationOption} is the user-facing dropdown facade; this class is internal data + * backing it. + * + *

Source of truth

+ *
    + *
  • Regular anvil list: OSRS Wiki — Anvil + * (the "Locations" section table; object ID 2097)
  • + *
  • Variant anvils have their own wiki pages and are NOT in the main Anvil locations table. + * Example: Rusted anvil + * (object ID 39620, Lumbridge, bronze-only).
  • + *
  • Members/F2P status: per anvil's wiki page
  • + *
  • Walk-to WorldPoints: derived from sibling buildings where possible (e.g. Lumbridge anvil + * shares the Smiths' building with the Lumbridge furnace at (3227, 3257, 0)). The script + * resolves the actual anvil tile at runtime via {@code withNameContains("anvil")}.
  • + *
+ * + *

Notes

+ *
    + *
  • Variant anvils (Rusted anvil and similar) live on their own wiki pages outside the main + * Anvil locations table, so they must be added by hand.
  • + *
  • The Lumbridge rusted anvil tile sits behind the furnace (a couple tiles north/north-east, + * inside the same building). The runtime name-based query still finds it within the 20-tile + * search radius, but the walk path routes to the furnace door and the smithing widget opens + * from there.
  • + *
+ */ +public final class AnvilLocations { + + public static final class Anvil { + public final String name; + public final WorldPoint worldPoint; + public final boolean membersOnly; + public final boolean bronzeOnly; + public final String notes; + + public Anvil(String name, WorldPoint worldPoint, boolean membersOnly, boolean bronzeOnly, String notes) { + this.name = name; + this.worldPoint = worldPoint; + this.membersOnly = membersOnly; + this.bronzeOnly = bronzeOnly; + this.notes = notes; + } + } + + private AnvilLocations() {} + + /** + * Canonical list of named anvils. + */ + public static List all() { + return Arrays.asList( + new Anvil("Lumbridge Rusted Anvil", new WorldPoint(3227, 3258, 0), false, true, + "F2P. Rusted anvil in the Smiths' building north of Lumbridge Castle, " + + "behind the Lumbridge furnace. BRONZE BARS ONLY (object ID 39620 " + + "restricts the widget to bronze items). Closest F2P anvil to a 2F bank."), + new Anvil("Varrock West Anvil", new WorldPoint(3188, 3426, 0), false, false, + "F2P. Regular anvil (object ID 2097) ~10 tiles south of Varrock West bank. " + + "Supports all bar tiers. The meta F2P smithing spot."), + // Horvik's shop in central Varrock. 2 anvils, 31 squares from W bank. + new Anvil("Varrock Central Anvil", new WorldPoint(3225, 3424, 0), false, false, + "F2P. 2 regular anvils in Horvik's armour shop, central Varrock. " + + "31 squares from Varrock West bank. " + + "Supports all bar tiers. Less crowded than Varrock West."), + // South of Varrock East bank, west side. 2 anvils, 35 squares from E bank. + new Anvil("Varrock East Anvil", new WorldPoint(3247, 3410, 0), false, false, + "F2P. 2 regular anvils south of Varrock East bank (west side). " + + "35 squares from E bank. Supports all bar tiers. " + + "Pairs naturally with Varrock East bank."), + // P2P anvils. The anchor is the town area near the anvil; the runtime 20-tile name + // query resolves the exact tile. + new Anvil("Yanille Anvil", new WorldPoint(2614, 3084, 0), true, false, + "Members. Anvil in Yanille, near the bank."), + new Anvil("Seers' Village Anvil", new WorldPoint(2701, 3482, 0), true, false, + "Members. Anvil near Seers' Village / Camelot bank."), + new Anvil("Burthorpe Anvil", new WorldPoint(2899, 3542, 0), true, false, + "Members. Anvil by the Warriors' Guild in Burthorpe.") + ); + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/BankLocationOption.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/BankLocationOption.java new file mode 100644 index 0000000000..999e7127a4 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/BankLocationOption.java @@ -0,0 +1,67 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.coords.WorldPoint; + +/** + * User-selectable preferred bank. Defaults to {@link #AUTO_NEAREST} which preserves + * upstream {@code Rs2Bank.walkToBankAndUseBank()} behavior (nearest bank by raw distance, + * which often picks toll-gated banks like Al Kharid over slightly-further free banks). + * + *

Pick a specific bank to override. The script walks to {@link #getWorldPoint()} + * and opens the bank there. + * + *

Copied from the {@code miningplus} / {@code smeltingplus} skill-agnostic dataset. + * Coordinates from OSRS Wiki bank-booth tiles. + */ +@Getter +@RequiredArgsConstructor +public enum BankLocationOption { + AUTO_NEAREST("Auto / nearest", null, false), + + LUMBRIDGE_CASTLE("Lumbridge Castle (2F)", new WorldPoint(3208, 3220, 2), false), + DRAYNOR_VILLAGE("Draynor Village", new WorldPoint(3092, 3243, 0), false), + AL_KHARID("Al Kharid (10gp toll)", new WorldPoint(3270, 3168, 0), false), + // Fadli's bank at Emir's Arena: F2P, much closer to Al Kharid Mine. Three banking entities + // cluster here: + // - Bank chest #1 at (3382, 3270, 0): full bank (deposit + withdraw) + // - Bank chest #2 at (3381, 3269, 0): full bank (deposit + withdraw) + // - Deposit Box at (3385, 3272, 0): deposit-only + // This coord sits 1-2 tiles east of both chests; Rs2Bank.openBank() nearest-entity search + // biases toward a bank chest, so withdraw-required cycles (smelting, smithing) work here too, + // not just mining. + AL_KHARID_ARENA("Al Kharid Arena", new WorldPoint(3383, 3269, 0), false), + VARROCK_WEST("Varrock West", new WorldPoint(3185, 3437, 0), false), + VARROCK_EAST("Varrock East", new WorldPoint(3253, 3420, 0), false), + GRAND_EXCHANGE("Grand Exchange", new WorldPoint(3164, 3489, 0), false), + EDGEVILLE("Edgeville", new WorldPoint(3094, 3492, 0), false), + FALADOR_WEST("Falador West", new WorldPoint(2945, 3370, 0), false), + FALADOR_EAST("Falador East", new WorldPoint(3013, 3355, 0), false), + PORT_SARIM("Port Sarim (depot)", new WorldPoint(3045, 3236, 0), false), + // Ferox Enclave bank (F2P safe zone at the Wilderness gateway, lvl 0-16). A banker and bank + // chest sit on the western end of the enclave. + // WARNING: Rs2Walker may path through lvl 1-2 Wilderness on approach. Safe inside enclave. + FEROX_ENCLAVE("Ferox Enclave", new WorldPoint(3128, 3637, 0), false), + + // Members banks + SEERS_VILLAGE("Seers' Village (P2P)", new WorldPoint(2722, 3493, 0), true), + CATHERBY("Catherby (P2P)", new WorldPoint(2810, 3441, 0), true), + ARDOUGNE_NORTH("N. Ardougne (P2P)", new WorldPoint(2616, 3332, 0), true), + ARDOUGNE_SOUTH("S. Ardougne (P2P)", new WorldPoint(2655, 3283, 0), true), + BURGH_DE_ROTT("Burgh de Rott (P2P)", new WorldPoint(3494, 3211, 0), true), + SHILO_VILLAGE("Shilo Village (P2P)", new WorldPoint(2851, 2954, 0), true), + // The Mining Guild bank chest is underground in the members-only section (the F2P side has + // only shops + rocks). This coord targets the underground chest vicinity near the mining floor + // ((3046, 9756, 0) in MineLocationOption.MINING_GUILD), nudged +4 Y toward the chest. + MINING_GUILD_FALADOR("Mining Guild (P2P)", new WorldPoint(3046, 9760, 0), true); + + private final String displayName; + private final WorldPoint worldPoint; + private final boolean membersOnly; + + @Override + public String toString() { + return displayName; + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Bars.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Bars.java new file mode 100644 index 0000000000..70118451f1 --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Bars.java @@ -0,0 +1,52 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import net.runelite.api.gameval.ItemID; + +/** + * Smithing bar definitions. AutoSmithingPlus uses this enum as the user-facing bar selector + * (Bronze / Iron / Steel / Mithril / Adamantite / Runite). + * + *

Bar names and smithing level requirements are from the + * OSRS Wiki Smelting bars + * page; item IDs are RuneLite client constants ({@code net.runelite.api.gameval.ItemID}). + */ +@Getter +@RequiredArgsConstructor +public enum Bars { + BRONZE("Bronze bar", ItemID.BRONZE_BAR, 1), + IRON("Iron bar", ItemID.IRON_BAR, 15), + STEEL("Steel bar", ItemID.STEEL_BAR, 30), + MITHRIL("Mithril bar", ItemID.MITHRIL_BAR, 50), + ADAMANTITE("Adamantite bar", ItemID.ADAMANTITE_BAR, 70), + RUNITE("Runite bar", ItemID.RUNITE_BAR, 85); + + private final String name; + private final int id; + private final int requiredSmithingLevel; + + @Override + public String toString() { + return name; + } + public int getId() { return id; } + + /** + * In-game name prefix for smithed products at this tier (e.g. "Bronze dagger", "Rune + * platebody"). Note products use "Adamant" and "Rune", not the bar's "Adamantite"/"Runite". + * Combined with {@link AnvilItem#getProductBaseName()} to look up the product's GE price for + * the overlay GP/hr line. + */ + public String getProductPrefix() { + switch (this) { + case BRONZE: return "Bronze"; + case IRON: return "Iron"; + case STEEL: return "Steel"; + case MITHRIL: return "Mithril"; + case ADAMANTITE: return "Adamant"; + case RUNITE: return "Rune"; + default: return null; + } + } +} diff --git a/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Ores.java b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Ores.java new file mode 100644 index 0000000000..0d49eaa48c --- /dev/null +++ b/src/main/java/net/runelite/client/plugins/microbot/smithingplus/data/Ores.java @@ -0,0 +1,33 @@ +package net.runelite.client.plugins.microbot.smithingplus.data; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +/** + * Ore enum retained from the smelting fork as keys in {@link Bars}'s recipe map. Smithing does + * not consume ores (anvil work uses bars + hammer); dropping this enum would force divergence + * from the smeltingplus data layer. + * + *

Source of truth

+ * + */ +@Getter +@RequiredArgsConstructor +public enum Ores { + TIN("tin ore"), + COPPER("copper ore"), + IRON("iron ore"), + COAL("coal"), + MITHRIL("mithril ore"), + ADAMANTITE("adamantite ore"), + RUNITE("runite ore"); + + private final String name; + @Override + public String toString() { + return name; + } +} diff --git a/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/CHANGELOG.md b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/CHANGELOG.md new file mode 100644 index 0000000000..1d3b6d2d12 --- /dev/null +++ b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/CHANGELOG.md @@ -0,0 +1,121 @@ +# AutoSmithingPlus Changelog + +Auto-walking-and-smithing-at-anvil "Plus" fork of upstream VarrockAnvil. Part of the Skill Plus Template (SPT) lineage; see `template/TEMPLATE.md` and `template/PATTERNS.md` in the Hub repo. + +Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). Semver-flavored. + +## [0.5.8] — 2026-05-28 + +Pre-soak hardening before a real smithing session. Two footguns closed. + +### Fixed + +- **`Rs2Walker.disableTeleports` lifecycle leak.** `run()` sets the global static flag to `true` (line 89) but `shutdown()` never reset it, so after the plugin stopped, any other plugin using Rs2Walker inherited `disableTeleports=true` and walked overland when it meant to teleport. Same leak fixed in AutoSmeltingPlus v0.5.9 (whose changelog flagged this one). Fix: reset to `false` in `shutdown()` before `super.shutdown()`. + +### Added + +- **Smith stall detection ("greyed item" guard).** If the configured item is above your Smithing level (e.g. Steel platebody at 40 — needs 48) or the wrong bar is selected for it, the anvil widget greys the item, the click is a no-op, and the bot would loop forever re-clicking it — looking frozen, gaining nothing. New guard in `smithAtAnvil`: it records Smithing XP before each smith click and, if 4 consecutive clicks produce no XP gain, logs a clear message ("'' is likely above your Smithing level, or the wrong bar is selected") and shuts down cleanly. XP is sampled *before* the click, so a working cycle's gain registers by the next click and resets the counter — bank trips and antiban micro-breaks don't false-trip it. As a bonus this also catches a drifted anvil widget child id (another known gap). + +### Notes + +- This is the **reactive** version of the long-deferred "Smithing-level pre-flight." A **proactive** pre-flight (refuse before starting) needs the per-item `AnvilItemLevels` table (26 items x 6 bar tiers = 156 entries), which remains deferred — we won't ship fabricated level numbers from memory (same stale-data discipline as the coord audits). Stall detection covers the same "looks frozen" symptom and more failure causes, without that data. +- **Still deferred / known gaps:** toolbelt hammer detection (keep a hammer in the bank), progressive smith, the AnvilItemLevels table, and the unverified Varrock Central/East anvil coords (use the verified Varrock West anvil for now). + +## [0.5.7] — 2026-05-23 + +### Fixed +- **Pause now actually stops the bot.** Added `Rs2Walker.setTarget(null)` to the overlay pause-click handler to interrupt the in-flight WebWalker. See AutoMiningPlusPlugin v0.5.7 CHANGELOG for full diagnosis. + +### Added +- `Microbot.pauseAllScripts.compareAndSet(true, false)` in `startUp()` and `shutDown()`. + +## [0.5.6] — 2026-05-23 + +### Fixed +- **Pause button now actually works.** Missing `overlay.pauseButton.hookMouseListener()` call in `startUp()`. See AutoMiningPlusPlugin v0.5.6 CHANGELOG for the full diagnostic journey. +- Field visibility: `pauseButton` changed to `public final`. + +### Changed +- Button text reads "Resume" (not "Unpause") when paused. + +## [0.5.1 - 0.5.5] — dead-end iterations (see Mining CHANGELOG for detail). + +## [0.5.0] — 2026-05-22 + +## [0.5.0] — 2026-05-22 + +Cross-plugin v0.5.0: Target Level + Pause shipped across all 4 Plus plugins. + +### Added +- `targetLevel` config (int, default 0). When Smithing level reaches the target, deposit current items then shutdown via the `shutdownAfterCleanup` flag intercepted after `depositByCsv` in `handleBankAndWithdraw`. +- `paused` config (boolean, default false). Tick early-exits without resetting session metrics. +- Overlay shows `Target: X (Y to go)` and `[PAUSED]` prefix. + +## [0.4.0] — 2026-05-22 + +Wiki-driven data expansion Phase A. + +### Fixed +- `MINING_GUILD_FALADOR` bank coord collision with `FALADOR_EAST` (shared fix across all 3 Plus plugins that copy `BankLocationOption.java`). +- `AL_KHARID_ARENA` (Fadli's bank) coord live-verified, corrected to `(3383, 3269, 0)`. + +### Added +- `FEROX_ENCLAVE` bank entry (F2P). +- Varrock Central (Horvik's, 2 anvils, 31 sq from W bank) + Varrock East (2 anvils south of bank, 35 sq) anvil entries to `AnvilLocationOption` and `AnvilLocations`. Both F2P, all-bar tiers. +- New `tools/wiki-audit-banks.ps1`. + +## [0.3.0] — 2026-05-21 + +Polish-Cycle 2 (cross-plugin overlay + threshold work). + +### Added +- Runtime stats overlay: uptime, Smithing XP gained, XP/hr, smith cycles, level + delta, status. +- `stopAfterMinutes` and `stopAfterXp` config items. + +## [0.2.0] — 2026-05-15 + +Polish Cycle B. Borrows from AutoMiningPlus + AutoSmeltingPlus + WC. **Partial** — 6/8 borrows shipped. + +### Added +- CSV `itemsToBank` (default `""`) and `itemsToKeep` (default `"hammer, bar"`). +- `maxPlayersInArea` autohop. +- `leagueMode` arrow-key press to defeat idle-logout. +- `dropOrder` (`InteractOrder` enum) config item for cross-plugin parity. +- Bronze-only pre-flight check at Lumbridge Rusted Anvil (refuses to start if non-Bronze bar configured). +- Members-only pre-flight check for items like Bronze Claws (Cabin Fever quest gate). Refuses to start on F2P. +- Lumbridge Rusted Anvil walk-to coord refined: `(3227, 3258, 0)` after three iterations. The actual anvil tile sits behind the furnace in the Smiths' building. + +### Deferred to a future v0.x.x +- Toolbelt hammer detection (current `Rs2Inventory.hasItem(HAMMER)` returns false for toolbelt hammers). +- Progressive smith (auto-pick highest-XP item player can make given Smithing level + bar stock + anvil compat). +- `smithingplus/data/AnvilItemLevels.java` (26 items × 6 bar tiers = 156 entries). +- `tools/wiki-audit-anvil-item-levels.ps1`. + +## [0.1.0] — 2026-05-14 + +Pilot #3 MVP. + +### Added +- `AnvilLocationOption` dropdown + auto-walk to configured anvil. +- `selectedBar` + `selectedItem` configs + cycle: walk to bank → withdraw bars + hammer → walk to anvil → click anvil → click All multiplier → click item widget child → smith inventory full. +- Forked `AnvilItem.java` from upstream `varrockanvil/enums/` with citation header. 28 smithable items, each with `(name, widget childId, requiredBars)`. +- Copied `Bars.java` from `smeltingplus/data/`. +- New `AnvilLocations.java` with Lumbridge Rusted Anvil (bronze-only) + Varrock West Anvil. Citation header. +- `tools/wiki-audit-anvils.ps1` and `tools/wiki-audit-anvil-items.ps1`. + +## Recommended companion plugins + +- **EventDismissPlus v0.1.0+** — global random event handler. Enable alongside AutoSmithingPlus to handle random events during anvil sessions without stalling. Genie lamps auto-apply to Smithing (your active skill). See `eventdismissplus/docs/CHANGELOG.md`. + +## Deferred / candidate work + +- **v0.2.x continuation (Polish Cycle B remainder)**: toolbelt hammer detection, progressive smith, `AnvilItemLevels.java` data file, level-table audit script. +- **v0.6.0+**: Drop-at-anvil mode for cheap items (Nails) to skip banking for max XP/hr. Auto-equip Smithing cape. +- **v1.0.0**: ≥20 hours uptime + docs + upstream PR. + +## Known gaps (carried forward) + +- Anvil widget child IDs are hardcoded in `AnvilItem.java` (Dagger=9, Plate body=22, etc.) per upstream VarrockAnvil. If microbot/RuneLite reshuffles the smithing widget in a future release, all items break at once. v0.4.0+ could add runtime widget-tree verification. +- Smithing-level mismatch (e.g. Rune Plate Body at Smithing 1) doesn't pre-flight refuse; widget greys the slot, click is no-op, bot looks frozen. Pre-flight check requires the `AnvilItemLevels` data work above. +- Toolbelt hammer edge case — accounts with toolbelt hammers see `Rs2Inventory.hasItem(HAMMER) == false` even though smithing works. Inherits upstream behavior (always withdraws an inventory hammer). +- Cross-plugin contention with AutoSmeltingPlus when both run simultaneously and target the same bank. Documented: "run one at a time." diff --git a/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/README.md b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/README.md new file mode 100644 index 0000000000..ea19517eac --- /dev/null +++ b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/README.md @@ -0,0 +1,63 @@ +# Auto Smithing Plus + +![preview](assets/card.png) + +Auto Smithing Plus automates the full bank-to-anvil-to-bank Smithing loop. Pick a bar tier, an item to forge, and an anvil; the bot collects bars from the bank, smiths a full inventory, deposits the finished goods, and repeats. It is part of the Microbot "Plus" suite and shares the same overlay, stop conditions, and antiban options as its sister skills. + +--- + +## Feature Overview + +| Feature | Description | +|---------|-------------| +| **Bar picker** | Bronze, Iron, Steel, Mithril, Adamantite, or Runite. Bars must be in your bank. | +| **Item picker** | 26 anvil items from Dagger (1 bar) to Plate Body (5 bars). | +| **Anvil picker** | Named anvils including Lumbridge (bronze-only), Varrock West/Central/East, Yanille, Seers' Village, and Burthorpe. AUTO_NEAREST anchors at the closest anvil within range. | +| **Level pre-flight** | Refuses to start if your Smithing level is too low, a members-only item is selected on F2P, or a non-bronze bar is paired with the Lumbridge Rusted Anvil. | +| **Progressive mode** | Ignores the Item picker and forges the best item your current Smithing level allows at the chosen bar tier. Skips members items on F2P. | +| **Preferred bank** | Override the nearest-bank default from a list of F2P and members bank locations. | +| **Items to bank / keep** | Comma-separated substring lists controlling what gets deposited. Defaults keep your hammer and bars. | +| **Max players in area** | Hop worlds if too many players are nearby. 0 disables hopping. | +| **Stop after (minutes)** | Auto-shutdown after a set runtime. 0 = no limit. | +| **Stop after (XP gained)** | Auto-shutdown after gaining a set amount of Smithing XP. 0 = no limit. | +| **Target level** | Deposits inventory and shuts down when Smithing reaches this level. 0 = disabled. | +| **League mode** | Presses an arrow key periodically to reset the idle-logout timer. | +| **Speed mode** | Disables Microbot antiban. Faster rates, more detectable pattern. Throwaway accounts only. | +| **Live overlay** | Smithing level (with delta), XP gained, XP/hr, smith cycles, runtime, and a Pause/Resume button. | + +--- + +## Requirements + +- Microbot RuneLite client +- Bars of your chosen tier in your bank; a hammer in your bank or inventory +- Smithing level high enough for your chosen item and bar combination (the bot states the exact requirement if you fall short) +- F2P friendly for most items and all F2P anvils; members account required for members-only items (Claws, Dart tips, Arrowtips, Knives, Nails, Wire/Spit/Studs, Oil lamp, Bullseye lamp, Bolts) and members anvils (Yanille, Seers' Village, Burthorpe) + +--- + +## How It Works + +1. Set Bar, Item, and Anvil in the config panel, then start the plugin. +2. The bot runs a pre-flight check and refuses to start if the config is invalid (level too low, members item on F2P, non-bronze bar at Lumbridge Rusted Anvil). +3. With Progressive mode on, the bot picks the highest-XP item your level can make at the chosen bar tier, and updates it as you level up. +4. The bot walks to your preferred bank, withdraws bars and a hammer, then walks to the anvil. +5. At the anvil it opens the smithing widget and clicks "Make All" for the selected item. +6. Once the inventory is empty it returns to the bank, deposits finished items, and withdraws the next stack. +7. The loop continues until a stop condition fires or you click Stop. + +--- + +## Configuration + +The three core pickers are **Bar**, **Item**, and **Anvil** in the General section. Enable **Progressive mode** to let the bot choose the best item automatically as you train. Use **Preferred bank** if the nearest-bank default picks a toll-gated bank you want to avoid. Extend **Items to keep** (default `hammer,bar`) with any other item substrings you never want deposited. Stop conditions (minutes, XP, target level) can be combined; the first to trigger wins. + +--- + +## Limitations + +- Members-only items (Claws, Dart tips, Arrowtips, Knives, Nails, Wire/Spit/Studs, Oil lamp, Bullseye lamp, Bolts) cannot be smithed on F2P. The bot refuses to start with these selected. +- The Lumbridge Rusted Anvil accepts bronze bars only. +- Toolbelt hammers are not detected; keep a regular hammer in your bank or inventory. +- The Wire/Spit/Studs slot is shared across Bronze (wire), Iron (spit), and Steel (studs). Using it with the wrong bar tier picks a different item in that slot. +- Members anvils (Yanille, Seers' Village, Burthorpe) require a members account. diff --git a/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/card.png b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/card.png new file mode 100644 index 0000000000000000000000000000000000000000..eb0b61112b9d771d1c241076315bddaafe912d2a GIT binary patch literal 132454 zcmeFadtA(E|35x6ol6ob3atoD$uZWca>ya)G)j+eSbcm`}6qS-_L#D?tMJ`v5&Ty-tX&rU9Z>k z`FuUE>)JGB(il@?Yhw)i^C@&62H-*FD78~m0C#k!39OQ7soN=Rudxwjj72e&` z<@VwuPqSio&oeH(^UbUt!`If25JWjy+E1Nce!J$%#4Dy(?5}tf#9NekIb=5t%p7#3 zRn^!It2ab--&w!bR&g!#d}Li@V^LG(-7RaHdNtK#X4Pi@Rxq%pD6H~!rDwyz%t%p@ z@MP2Mh)Ca}MNL)N^2&qxZ?Z3~nfBCH&{R>LENL8Got^Yzd_kq4>D9!DlDfL=*w?j{ zjX{SNeYs1%@cEe+Y0rN0YEonsr3Bn<44EN(<9OHYc;)5lhL@Kk6~}vdH+@#`k#J3r z9Z-19ab{Ll;=v5p`kAZT8lE{8$`?IPJNZ+&Fzt=a?a6Ca%r8(iytR^K`4?TgJ?>5J z^M=i5>Tf?ztC^hd+-PcLR?CT4%v;I%ySxb1;8Kdf3l-)+p8 zf+Atv?efMqK?~f@WMtQFFCTh6plN@3_q3XkZ-j2|)DteYsk^+T@l9cQWHVS8pt3_kt^Y$oZyg;M)Q0}plV(;l~!Y$0D z{_awzV!^0mq1J<~zhfiv(0+(t zu>LcFX^4f<>T<&n)mq{2o(gN8)2y324F!CjV5d8Omr~Y8**aXs^A*byxXQt868)9O zdKw+`!r#^%E9fF>uWU`!h^v#}9u?ln;5K=jV+!wX5G=`Zk+MO60Vb- zV5gX05UdF1B+0gfSL-JAQA9iICVGlx_ED2Na^-%UnD8L3NjpJoxJt)&9p7p@f4sY7 zzKiH8$Fg_uc(H6_cyP;v4A50To{I11kf{E^u zn6VNUu5YiwQCB_vC>c*02p1Rs;%gGiu``4<1&9e=4$6 zYx%dFn0Bf5BP7x8k`L+1lZPcr(aQ0iV~4p*wdYd6P$J905cA@t++@EhzMqjVp2?1u zp9ihdJDst(taXwejMLvN?S|N-RmOgwkC4Fx=Fselrn7jJ`io^qepvqaA#ZS4*k__x zE@nfhM~RRUiNGY#=vXNJVTmDf+h{|NBgE3ODCX-S-MJJCx>jl4U5r%Av20ExE}VS9 z7{y9nemjwe71E+o6{kG9<$c6$mX6j$1|Hr1P+qFF{3{N!3UZqMrN=GxAu!$UeU>-;Q zW4|9fu~_4)abNLHXe2j0T$Q&5RJuF2?AuZ{O zEI2VC5)K6dy{;rCyt);=1_B$?B9=KQ?z9i=xKTKap8Pv*Qq5qhJ}e;LPb0;xH{u3s z@rOJ;`hJwbja4^Q2+|5pj5ZEYhLQ)L6L95rT!AwRnNoG#6g5Lrd}bm)A}?V^Il_^w zlB6aWDe(}LA*KE@wUnEp%gUToFXdN^ZExuwcUm+UO8avH9*f}SDum!Y7K&wN=p``} zE2+gMw_EK_=_lS=Tx1z7|orONV--%&F2VD>pGRH z+N2EVA0;%e;#;GFO~7}>OSQr2iQsIH3X5_43>j!ARtQy`Jgmgg>3hz~Hilq`en&VC zKF|s^6~i)$V1=b}@#N&h6^!@?DD7tF<* zUFQVu-{kEacyp(&cOnu90@+;NA`qBBKRx)YY_5GEm2bj0mcx;agEt`V5IHCwni;3s zr}=$d?OLOf1nA*Tlg>@HQvwi}CqLqtJh`cgqLRmxi!4$$PMxubgEG=njO2iSs8AR! zEFnxHzQ?~OB3LYIoAN#k3G|_qAlCtfHP=63M|HW8@9c03gez9)c*?rS{tSDeo~oq= zDTWkb8mzR3>x9=tps0hF)1SrP1UT3f;$nb+8-TPKu~O_2UcQn2;Ary4^^un%TFOh{ zYtm%RISh;F%si!?>xU3k`c(y6ret+y1&=*tl92*`5g-64Fg(>wi3-dSTFMt1VAPQ+ zXLK1H=7C&}LDS7@Y>5=mQykU}$cq6utWo4t^W@eHy%RLb!Do?4 zN4&40EETlmR)oiCmO94p)B_pyop&Ntk3@f-d?+QDu2rZV6tS2;FU%kC8wCyi z&u9<`s+`4AJ^7CkZTV}4uN`^7FnyGR4}7US7L0EjCB;f(zu#KSr?jKM43|puC}!!| zqd8P0r~(|CCNv<-XQZho3+4f}BV8an?4n}LNA!Z^u<%2T7zHkv?4`8BIuH?_qj$$b zMY3b7F2m;mfa%Pz99j3k*b>1~;6BD{$_<;N4v$9_NQ1mt(G1oH&zJ#1m?J9$m3?0? zfsMJzcaS%$pK>Ye2rLt{Iq)T50M!+|;>T5`&;-L0UVVfc^Y*5BaiZ)zE9@1sk#MM} z5H?^)4XGKZOUp^0n^7`UN^)g)n@ixvNi)sm7XSoRvl-$5hvxGzu~u4&DBvO25Qd1) z%WQ@8mu$xc=3-bJh#K@2{G6p@ew45iWsJR4EU#-|yfFi{&d3WW^yegJWe&=f1>oTT zR;ZysG{mxr8I2XRrc}g3foI^zNWte=HZvG-626tXyfeK95u;=z@M+dwl9b^hF43)9svC`vv_*I za$sY{9ir?jIV3Y6Str|pOMoUJV`}w+En1|=#a~37TPGXFvs9P&)B#i-SA63*H+h*6 z7+Lqg1#@|FyJA6qMxM)fV+CzA(!dUoj=n@SHN3kg9*-)jgz86#%Qr&v5)9Fg5CfJD z?W`#|zzS5>tAA|MLtwgy8QUI2|jtx{v==hS~clSIWDvqytb1 zoXdD9^_G^GyK9QR-1t+|f97@!jM(hcPh4$Ez>5?y#QVfz zRSSZU7{DA^1D9pwli^`Q2vF;~7Fz$F=%`J}EvRHa&odNy(8NN&F$w`$_awfCK@@vW zxB3w*Q_vMmTm#7Uxf){47^Wvu9@7Ea&<8YF-iv$q6jq5I$T~sxzTqxnKP82|-^=^J_wN$gn>qPhUKF-%vBgqgx&EMKPYYoHOk>b~SuoY}%^ z2NgFaSvJcE7AQ#?5sT41O%bWrV2CzTMdmQM#3ZkBp;TpnTAPf%rZmYkMzCN zj`WC#emr|cscIxGjMgcJACYVga0iRT%;M>R&LAoYS5X24#%J#hdaq5=BLV9e>onIy z!!Qn`0Z4pf@Hl6JnpHrh%9&`HZjveRgRUZ4AAG8f)L)Yr0oLkP?1? zDiBH>I{7PP2Y+Z3OM5Azw{+Ll(C+OJg#j%-g6wjW_X#X{;YEm_)w)hGSmCbvvaNS* z{}h2f5fRAs0$-)0qh*PI@-Iyb;ZOecuO~l)e_fnXcE{|`%=4*ap3%}I16|Z&eN<<3 zE?sn}l7fM%gCm(jiSA`#OB5mMdyHOM9<5QrI_VI|Jl*%4z?_h8GdXNc=ma)-W%OMcc)%;K z!%s0P&U>$t|0^Jq;ecptng`TNCON)2q-^&<6hZ%Oc0z_gW@oBI!9*-WBhM!q(ClrqC`3sZm?$XFaN zm8Ojdxshhig~5-t2!B0!=#lgHJ@^79A%WYN)my7%iyinJ2oQ0-}RN zCGkmWSwI&r+ydnjf6r2*V7%dIc{A8HQGPZC5O+xL!R)gh7&S~<1tR#Gn+H`==(q0$ zoMl1lWM@hQB%jlVLaAwhJ_&0Y^hBpDN7h*rtqILwm$l3gc9w+xOgZ_x8PG?g));dO z!AG6PbO^D`QW5RL`sa9GEolZ?ajp}rmaeb45lMrxoXakX`5_V9WB)zA^3 za)~F+M8|~ndIZE7(8*w(e?avQXq{TC_#VG6>?*^N`-(H(tIrcQ+c<@%JW_Ub#8euz*VC!QcbU?`fBf41E}t+xBzjv^JOVrzJ{ zyGGFaG-Mx-_`Ewh|B1k-d*G!{Np40tuC5HP{_Ib&x!b2FHVbr;ngIXEVuXGN`4UJW z&yk&hu}#xeg$x6eme!TfnRV)5aN4Lrhn+Y~?nI}*3rgbszRhZ1aqunzLA?BLF=oIR znr5Z5#t8u7+#SNX<2PvSF_Q&qu~s(E0J1O?_Jgq@*}96KX(jTw*aj69zyW}W)$)(5 zX$5+y;;duO5vDzW-()3kXRf9tJFMBR^&i#j;_ZY-=F_qIfJEfTg!+Gytxu9{nJ0_d zYnlh2hQtgxV4duuj@GCJdlwpy)RNWOBv{{0ZigNvys_w$!{gEH6Ac%@975eR)>?%~ zpt@hh2U*-mt+@>Hhr$vIUxkJ(5mRHP5HCvCWP@a;ka4u~NgM!GhB8kL5#r})wZy_r zMXgyS>(MjA4n%dWOKS*e8SrNey`=F~Fj0g3zCA<@amhG6i{qQMxc{ZX6#cWP6xF?xRmBR7dx(dyF#`V8Jr}qx} z?tsehM6?dq^f-+eX=XA(B6CYn7(nyr0+-qzUefZ8Al$9B4q^0-O38KuH(nIkoHea! zbdAVi-)xVe?rf+zYc{j?CN*eX)(eN|BMmp)CNnGCyt@(c%pCw#14B7VYtN?8W`tYQl-4@bS^|0u(Ity)vw!r?7J5X)ExCc2 zmmtK&i1;>V^309^BCMHg=NoZvKYU6s*Rx?lI}Wz3fp`F@2pUbq-vd2hHc0E3%7NY( z5q*eJIvSzDP`HXLg){U4K*-{ytXcBI{c9+P@VZ6Eftq9Qy{V?D^HSB61K~f zy7U5rKU2@Y_r3~k>JdnX!1?s2weVB3779$^%Ss*sXFlfkQ`lRf}tsM5B=ZGs`K5Tc4LbfeBWZwkzB; zf8WrU3TqNGy*IlM$zP*|6sL7yjec)H!=?}aRPgok8#>g{V7oxDQ)}oYO^<;f-N!a9 zV%3i7@`*Z@>JP?Oa>~Vw4XQso6J?I=JHz%E>><-SE$`Tp?}N6;q%~X0%=c&7Y4(|1 zM)_wTTX({QwDE zMKrb&4W*-xrG**$W%LrH1h~Q2LCkB70o`(4*IKPhV85*+^sc+mLM5_;7(*l zTXkMW)<|%iv1QBYg-mBt$Ww4#eG)T5i^yq<%1xGEWkGV8pdb zv4pTDI6`WV=@KM`6*iu%uxv}7F1fMMozysCDdO1gOPW~*^*jNUv3n8EF3?Sf2cKDm z_h-Tl%Y3|TQoba32ndaT^q!!Z)H_A!F|?k@5jq6IIi>NnnjgqyyD(VO8u}jF){{J# zHmO{I%+@L%mS4E^!gQM>4m3jR^=jUQfkwA>zk=!o{aO4?H1e=fq$M!z0*HNeuQ?QQ z><56`A8q^5{kT&}oA^8xD{qKBuw%E`^Qzq`StnFj|0(yd-s~sWTZacS!c4CJi4iZ< zjOyTj!k+ej`qr)kV*56<{{hKF)8-~4?7wwu9W}jR4BP&q@lE_G`+QQe4=dX)pID!Z zSU{Ap>HJKsF+EDC$2|3HdkO1SlAm6qBtx^r$r#wzLtudPJ9rKtQ3LI>GZg^eQwJ)d zn?ICHx*eoS+IPe@XVJ=F8-cuuy1rMd|7j;{KyKxZ??!A17*OM+g22kQE(1j|=3yKn z;gJij*{CHWI}p>$khZZ=-I~m4_?r1GLdvE^yD`Iv;L$R#!zTdy#{*!N=sX!DW%Y~mkIDu9;@67E1#-<%K99pEukG8J-E3Rf|%%2HJyP@abIRRnE8ry68$?s~1 z?WO1zL%5RTfy_GjjqfR|dk$@UXH zQ;ehC8T}t{u-FH-K?iJnGX7@J0@xmU1)k{+_W}e2EA7cHu!@i#@`;}>_UZYYsS8wv zBjaGH_)j=ijLWH*4d=+fmTa#N+t=M3wx8C1cI^S8G_#+^v0|DHM+=m)i|ChlJ8QQU zLiivJgtffTGyFsk)cEuo?@WfH!pII;`d|x#^yBMwIi_sMkmRw61Eirtp8GuABgSO|KZ1o!NI$o zUvZTkYxl3Ro4p}%r%S`z^AYdVy|Uh>RVuIb3WzA^<=RwtzTd0mP5E;QBHzvqXneY+ zI(I{M!#n(>m+Mg5HI26yWmmi_Y}^`ATf1S{(%O`Kv!-hsHj;1bAG9C-|3ogT6aF&2 zjpl%AoGM#<^Xd7p7EZ?f>&hMnL~fXTu<6mktcI7%o8CQNl(nYm`J%|CtJ&2yw^tPw zq=hxq9SpN=l=sT2JD;|z=-q>~?8egb{a(K;S@Ei(Xm#4R%4FXg%a5jUu(1N>EO@K_ zk^Ab=|FNzrKS4dTf0ZJ3HZ-+yiunEL8q*@-HddfZd z^D+x%^^JfA^R&`E5t}u;=>Nedp8eASTJqK(_|fy*)c2n>Z6;5e)%fUcQRDe+4z}x4 zXD%d_o3b?W?VHP$ffeUp)toM9oBb}u&9#2vsr;ijL;L^7?tCZ!umxHNHejy>4o1Tv z%CyfPzPx|l(bPh*;NFezJ*sb4+ctHSxlV#NjgDv>i&N8;v>zzaJz!0bN%I@(E*C}C z@MrD2S@-+aNC!G_{2zFDJ`QHafvZc{Ee`*DlclTkS3bEi@#0K=D1`$UiQm0vfX?!l~=vm)GTYaidOza13j=3ISy;{LC* z8&ialcZ~mdt{UGUDZBRcjWoBx4bLXOSzh^~z|8Gg+IG>eMb&e-Uv6-w6K9(-;&bc? z6Geo=Ne8zd*$`pm`v)GhFBYs`s3?CU>xCq`e2L8ULZS-}uckvEEwIx@d)#mhr{ck^ zz|~i-N3ZH@M%PiSleGt%6yksk97SpuC0x9g|KhGZ``yY_0q+)uW&0HhGq2%(lA`Lv zwoRo*zBn!!=P%OEnKCusxOd%cdDh$S8eZ>`UK=yG$?mKEEnmO7mQ_*pMPWp9j~nQ} z!eFyzhdFMCK;UUlCjBQKQ}T4x-0B-<^`A}RMr;^s`;E8#Ump{Rneu9M4 z^19Ec1rzD4_xESlhM5FLWM7N4`M!FuSxu$TU3QW8k?kD%*$n{7Qq=+NLCYVX;oq8U zwAY)@L~L*$6Cc`uy9FZ1w8EUt|1`U~bV`!rnm!?~Dx%oQ=s1wagU$hGcQb4f+HflB zBbGHZESIlp?6F2wC4sc^@sYNE-=-{LLJUr55e`OfEq^>>o0o9v&E;#^b<0-d zZqr^?p*?6D+v8r))ei}4SmWle&$pFu=sJbwjJM_xj)FZyr`gm!q{~g%?KL?428V$r z;zA4DGtsK~IOb8BL&(vt)n001j?H$9+G{sp;v~)SaO}XxGZF_m;gnizA;>cDj+Aa) zoM&;c{wK4dO}*CCT#H;MOW0bH=%_ts(hfd*?JW{SK6cc7w2wccf;XcYw9n~s#L7kVx91?xZ0fdMK->oJtf$}iG2@r0Q~>y6(lRWDxT}a-;IV(dc}A1Pa54t=d1}Osk1hi6T#{fXi4S%Ro60JWgH$< zFz2fmC%)F<#rp)0JH9ZeYiFab+}7E?;69i}8C6iZC$J9g?|-37I;^7K07d09_Z5~3<_d$>WiPn;n3 z{(7CGj=Za0!YrP@{aHtcR`R~woiW1md;5N#W;DHG%P)3gb4M$J2L?KPX7Sxx;dA|@ zl5l}ZO56C8c2jDtuj`D>J;KTVev%%}nH__zM|rq|!#G5spKg5K5&MslGh3y!Re0+7 z8jHdxXRdx4uF9pCk?;gQ?)(7!8&u_K=RJ>mY&ADI&rsl_lr7WQxpuOH-OvQSfoR+p z*km9EFcuTmIhq9y zYA5JkENG4Nv|F4|JT2P)=j(fh_CDS2MtEUHI}4i<{`>bTAB>~JR1U+i>ti)HadoVd zD2xvK3&r&W4j$s8-VWiZ9?nXyDt=2EFYAOc@h@Fw;X75M=_&f-?7@>fuUek}IJ|;V z(7u@8Ml{aYHDP1b4%{$djSot7=)xHo6orL!Ig=@+&md#hR2;tVh=X}mI!V@LN=Kt` z`yjk}6dx07UlW;EJk(Coi(cpuy%0@qJSH~?cT)%qIQe@XS$=oqSEm8DXW0ev`=1kZ zQp92JQk7@0m1rC{Ts27S5^u0Mnyw~GI_a*+qa9&=m4eSRW4Z4Y#+&Bcmhmgbt50fxWJV`IT#H6;0 zlicy##P1PVbVc0B78FscsvCOUC+$zw-{OBrnz#OFTLi2P&a897+v{jTn?1z#yn=gj zn}LfDz0LnB)UWgQyyy_sdQ6I70L_$9pu^Z8yrN5v80$zh@!29%oFkBhe;b9hba@I6 zzRR=v0WogRO}chZx`adsl=jJ>BLFz`CTA%_K@_es9jG7)> z@T#l3#G*u67%nkL;Y?2SstSIfgU8NnL9Z+J&f=+qzoDb-qVYfbR!L`S*P*J%Fgsd| zU5tH=y{4NdzvR+*;GbGrk7E{s^wRsPrD53I_0Tx~h^R%Lu0jHl zO`snm>kq;v#30Ip?h+Oom?w<88o`<|Ht1)M2PaHL@r4L^Z-jiCk~|&XmZMch;SycU zceg-?w>xn2K(BL>RsHji%(ydVHk-5(sRC>o zyPcCzy7%gXoQ^%H(%GDtz#x}prTwX{<>0R*w=S04bXLUKRRurf&L3;m&SLLc;V`A& zjL$?txF3UZYA5+hF;y;oDnAZWf?T3$Cc<5QWHq&f-9RO)bM+*LuKpB#;Sy6St~?gQiK|WfU@E^>NOA59KLG!7Xy6rn zLFvla!i?h}fLS>aPr`cV+XM~@QAxyQ#aJbp%s1uZaE2*%dUI9w6FcIRRpim;`Xudu z;Fi#tAOT2mdJhCV3To5{M;p;N8fmH1u_ zc=%UJTE(8$Llz&}G~`m1XQ+0v)B9rCAlQ|H)`~cun%{v5|c3WV%f@YmkxjpGYwH!uu%2ngE`peo^`HD z8pC0MNR^iId?*#^>lFX~5-Ptycusl;-$y*|bkhdzNp8NlQwg63IDucAdIAgHPwChO z-|B;4qna(&*6g5j_%Y@dMGe4)O13m-Gto!3EMk#ywwtF9t(R_80{UOwi1+;R;~4PML8}3^)I8dfvH>> zD`j6&LGM5b+QoD0*s}RKl(}Q+2wE%wRH^uvdg*a^a)xcXDdO6$CUk<^Px{jb4K#Hf zu!Kmf4V{pe*LHO%E`vEo$fAC9#^spPTtvAHM-gryI4z$*bID$$tCDbye;M5fB?VsB zC+g5K&>=*^)h0Xd>B!69T{Db4}_-lCwE4{#+Ee;F4fF=X6IK430xrb{ryECE~V`RXEndQFeL z-ozM%St5wEtbOMJ}Oo1 zdGzIQfTB*6m@=jW1u+tUcNw{olXwd`rXPtze}GYb=N+HU*t?KJ%d45$fGV_#x99rO%@+|s&Dqp5g%#-bi)8-k2mlaEs z^ib`9l(0lnEr0L>Eh6lr6m+8^*iLY?1Go#ZR(ycpPTrdE2|;?`B;F*O3HrY8(Q+rM z(E~o_fJmK&G~xMNpH05bBUG_k&QQQ5eD;)TEFOOTmuhJjLfUPxrObf`1`8#I$UrGY zzijGCl*?gCWA>&&9z=^ZJPDv(i#EYrHH^T4;VYK5DVkzJRIw=Lcea7!6BCeelQZe` zs$oj$RIF*S&`VztmtQJL4XnRl;`^!^_0vc*;T>^qP2w#>VMUen>wEG2H{$wa{Pt<^ zJ+AzYneWJzVA5@&)#cw|m50H&;}0Y^b({cJ{x337s-epBf0>E=VuTT~1t~Ftg&_I= zQ!W~new{ns`mSPdXJ{p*04gkYP>OV!h=KYs3*WN-fuP6xRY%}D4>LQL6tH%k$Lpo!z}<|IWYYISvf;{`!6JzNdONlvwiyRPN>NFpm9u z5L0xH?B@S-#8lw7QMz~Uf?5to%o#UoxVKHQr&lqNoz2Kvd315zV89Tpx3Qx}8zUDlK00?m&YU(9*g z_Pl_cYqE}G?cf)1&_I-)1?<=eWR?R+F41H-YZot z{Z(gWZ@Br}I)Op!;cMZOcrR8};Hx>8Jsi#6ODg{_5Sqt4iiQgv|Ef`;}1IfRh{DlhRLf27S}Kr?%%*uuE4+oi_oAE=LD`wRMOyf zehU-?9(FOo33|(Cq6NRMSP1V!WqB`5t|l=D|InhxcWR(=Fr5R+ zbkyG+1Ua&=>3ip}b!6JR8D?W)Le~&^pfwJ~j__s~xE2ak6jPX?M(}ZbHcj(MhSojD zYvs(I21FOGmr9<^hqUa@cLaXK3vS0M#hoFFxDMN*O+zHQ@^}`n08J>*8->-J@pqP9 z-sCO|*6IVuC(aYrzj0yHeCQ=a*=^CsJBea(;>;Pjrj zTV4~1i1g7~M6Q_vC>CZoyiY@^j&t(UFU(&y_k|ro>%T->03`=J$EKslgyv6dr^Ana z^qx>?Km@kEwnd~@s?s<0ogKy4ffP4GT4)IkHHW}zq%$-M9hNt(a3Ma;lK3X!@#aF> zWpDy2F)4rLEhtx<;*Q2;sx-dMa#|0P-!*}cqDr+1bX^mnXaddh-j5=VMQ7|i5A0Zn z-~+l7p!kCoad(}o+OQ&c9#L^ z9v;}<PoP-u>a#Ai1nvkLNgh$m9-QGAKTY3116RX|5b#i1kz zL_^eSM&QP*U|0qkC|548o4NS$uo|mtLu*E;>ueTTR7O-yRX?2* z&^Dmqfm`%7*QOueK6x-XI_>_NwD7vyk7HKZh966>yHgQ!iR1*FqS6OPW}@{X=_HRIH*Jn( z)0_P#JVF(5ch(E9Kk4&JF8Z+Cq|U>zYK)Oi=P!t&C}JXIz8V!4NG->abQ~c5lh(Ni zFT@3obNNHko2L%0NEl)ju)0>Du53~_>D8#qCr95lN$UbM3@Xp6F@?D{LcZ0sEYPT8 zDflj@i+`%E{HtERe*0eDSQ5RVQ{#B`rK1NQoSEKzcyjjxE03gC#W_YlU*_kLB4znh zQ|nnbStE~~=Uk51GVxq}z7R7+WUGRtIH2|DRQ|QIsjJ ze}AFA?;w&!O<5@Q;b$&dXxW04^^v&2_-MX554WZN*U8d@zQp~gx9LdPGr}>NWO-gK z9SM~c4F^{LPy(;>@^3#5*lecg+%Yn5cMgA`65x`Xtf09w)hHzxyZp1N0e36??uAwA z7>~|9@;4;@RI`+2)2jAlT}%W0Lu$2N)>Tr! z@7ssx1cQ}+wuz6N{r&DOdpzvzt7STx{^{ZJ9qm&dsw+E22-Z^{Q`4#>{(8Xcrd!0M zKJ)G*mG0fU*)bGJ&_Qtc;xUxq3cfP57^LQ7X{|0T*}%!_$cXPQcD4NP6YFta{`g+m z(HM?~GIh3j(mjr_gt~3TzzkZo_eTteQl)(6kvskIOyAWnpU%1ZI2z@=ohXb|KME>M zVLo3He0$5P{*z6Y7DYaPqADnIYU%p!iLs)*uktUs?eVh?87B+p&1qElHeA|MG~QYJ zWiwhT{Z?fjTIDt(^oP9Qykf;%vKBNmgpxe;_lMJhd*4+;!Nj5qmsq95_q;HG}bbkF}noRj7_4iZesmxmTD zfBxdl=@;`?C(is)DR^8e(bWj=O(W)S%pl^L~mkn)X%yHEsjSZG+!A@6Jjd zmn2tRriIdXc-c7GOq#pEoA303{=c^ZD@s^qIZnY*K*daAFnXKp;}&kh@HiisY= zRKqVqB!=3a_-G6eUH(3ZJKt240HlZrSt~GBNOhCGn2WrKp<^ZwSSJo)$-&ByBlF=_ z9GUSVXG7ul$#0+II(v92cnY-Q-nUBg_oju{muA{5bZA6si+a3?`E1@dP9bUYwufdO zsvo-L%U;;q?$@+^MhMbwW@k&J4GY?eq;bcz7E9@Y^5o^85avACmoV z=TK)c{4{@PyQ+Gk8LWXT063JFN>x7NmpQpEP(RsX=K3!E`#zEF)xg{K1W87-_2WD= zbYM%cURz)PZijiotiNR;d0C?RdAdnVz3pnAb1sb8#aG_d``EePnmr`F;$jx+z3g+XDxc^m}Bm+iI~ipG5ed$0O086^o6 z6g@oK&3hgsYkaf2MLyI=?7#6Fa!kCM+$(kZJdjA}ZE7kv78c)4+y``Q4TWtdXG#=I{6Kb>n0U2AS zOmeH>t^V!!jo-V!>)J|w4rTgdEi!|n@^oB&H#_|GiSFus>E;O|rhVWZtW^hXT@GpK z*?7ys?S;1*h(&hClrMV(+2_ zvpEE{`s(DzU)WV?{t=?$?L6cW@W79vU|g-ue{3rdACUv3+}%GzpWBR>=_!daB+$K zE`uf!I=2MjJBVFc$U`yQBY*2ocdCZHZw>o>BMjYf_13r>F%wVi^IpB`mC=0GDwgPO zmVOs2oO>hd(bL!m)|IQGY^{DQAEm7dXqxPqIbqL$pRhCSroRDtpD4Ax`KP`J7qFfa z>(d~0*(s1-a)?p`VW4~$Bf(2d$OKeJjj)O$fOif-kwMK}$Paj;R3&X_d3M9S%u9E= z-K{)1S&vu_HC*ra!Nv7s+RD$UEx)Ssj1r=w0Y;@0c&W7H1gZF1^(Z66CG3JvY>~sriodOA1QZ-sFQ{XRmk=*8S+HOi-B*x!=woCxg%X>BM)Nrgd%xU@$c1gME%x&D#dv zb0h8IYbdqIQy=C22nDovFudx7i;m;;oD7mnsX?o0?+oHp*r3IO_7^{J=Bo3y>dt8r z=QHohjhTM(kw?ZE)ji_bNW>CK&ijV*OKyIH*|5!zkAGKRZre2VS^8a6sGi`Q=(cJ- zRbp9eyOev=J1=;`y5L_a<2>H15_>4iZTH<>yd$;63s58r3}*9l#}8j(A1B<^Zsx&~}eeiz|9MX_<2$RB|o z8>3HCH)D03l`Vt`_Yb{kOZg+`J3j#59DTd(u4kp9X80>LR3#F1NvH5f1EBuahEe;B z9a?BQW6ic0qOzzpt87Dh9QbMBlPrTq-K6V0@IsOrw4SJDUsvd2e%IwbW0AL^d$E!^ zj)OdOlZesA;^rpi@yNP+7v=|-`=#^uDm8@w^|38n5q|S74G#Fu;43cEC0KKBv}H=y z>Ah{)OMNYNS-II70c0SDi$?1QwEhygum2Bj8u^Vi4*?m$Qvb>is2cO3bB#eyw_dD7 z*U=Mz9CHaB>t}J;%XxDi=q!xh@_AiXz2s7W-ajPhR)T>wi_JEDE&zpTb}qr>XG9)Y zvg|E9{Yo@+&WVNw)xhY>k*`jd-fA=1aoL@S>{%rP9Bl#yq|LjxH6ymDeN2qr_+@k7 z)n?_M=)T{_KkRB)?%m3)t?k47GAizKWPU*Y@Qg8uzU_x5LNY{uA0*b%Du;f76ZhrM zP@I{NoR{YDAoXWg63am3X>CEpO+B(WcW0X;F27S73c?8#k9D$T4=lLzpXG2-+0ak! zkAXyvOXejF9|oIoaQ8oGAvv;zI;2T7=ZKGTwY4J880GVWf(x~zQ`6mkZ^e6mthZe` zDoPeYo!t-sMva`iCuYj=hpsO=n;(+`A^gg$pXAYkIrWg|{QP$bxsL-@uYc_H^XbY} zhi)yX)B#|8+~cZ`P0`qe4{FSYWQNyD3VQcDB1_J)oU5A3qE*9jEjYek9FJ6;%?ww; z)(3Jphzunz)m=a~_PWY|;9l>36{9|RL1lUJ0t&LesEkJ?5SYj~aFjWw$STk_{W&#r7%l`tnyOQ;D&&{M8)JcTfHns#U`P_n8@1 z9TuJ?t$TRmTFmoh{;B$;jEm-pQyX$N8T{1?7msGhVW;1aQLb23bCH<@z$k?W(*fboCJRkWhYbLF#3N7btZ zVfWYX@+p?I^mX<(T~v23H+M#*Vnf9Gr5A2L){+0H^)vp_)x9&ut51e}(>Am+MnU-f z*l#pgSyxy7%@X_{=>JTOJeKru$Jw4X^4%r01p=8^KOK=1X3QG(=Tub#Y=&fP8n-xH zH5mI22AiaG<#rGY^h9XD{yzIALd+o~hzsqnpp_0Q?w?sq+aw&$lxMap0L&1Kgt=`H z2IzE>iRZ}u}g;&kkvMlapg{|P$d?uu>Jzg2x~@f z_wt1MO?G#GlLPazIQh9{!Ai%orC7{ctiN!4mTu66s^^(|1=y*j-0 z!N}Euf%jGqX-tw1sf_4tOolGFCQvBIvh)ZxavFsZ62V`KC%h>#w}uwigo2X`LDn`3 zJB#g?RCGviu=@51wh4S}4RA)IIIG(TGQA&%9SV?0V+`nzc5n5yjdYQorqd?yvxIxi zW%y(!nY2dBA&NpKhwnJtX*dbX+9VtkSTC4@6>Q`1an8n z_KV0@)n&q_9+tg|EXZe!G)Fx!XV-*ZA`~O>YHZMm|8G0TE|v>+0TJmhXvpt?qvH#uVGgmrwEkEBR|ysLOI|B14w;S#|cM-Jp-mQJ$P~ zS>(GR2jtSPdig&(>)0{HKj~!M^Gf-}MrqvPUq&0tyIRRDzy9gRx9WLwEC$|NI$wQd z$u+CWteWBK+g1UV2O}CiUNuFMY+SKOk@|V<&3-W%GkO`&&J~w9w*UZ%+-tqk)6*N0 zSHv*r(B;0#z{1rtURAD5v#B&+F`?|l%rlwl z8utgw^A1O@P`oV+8`$>Zfe_CV;ZHrU80t9GPEE#sG+XYeuH(5D&;T0qw_u&33zCce(bzYx>t@x z>>!9hr_YOE2HPzYyra{0Y%*Xi$?@2o1A4Kntg?!mC3Rf0YG$9_bH*+9i1j#ft)VOd zJ!d6!K|`+>StC77eP6uW=Kp=@lE|!%T)CfalKtK1e*0Fusm<*Y+siKO(2)sMf+-c7 zFIXKozUzheLu?BctWnm@4SQ!kc}$0hwFX#`eZ=-Z6*dT}pUyd0z;jwYX{@E_(gL^F zzs%kn(4la_>Pz!0fYiO8Wz|F}`2($zk6gQ-`FX>$SJ4Ic!%ddR;uicm^zpk9TUIV9 zK~c`AH@W2D&~y3TWe?X%_SV1ZoZ;)D7*;dvSbEu;(|bQFStwN5EIKoDUro&T=-sa@ z+Z-K%)@#LYd4&OEodb>Dt>f$*(!Hxv)mwQd`1hBOiVS+4d2M`3=GoYoUU}BdVnah! z`dp=TL3mMmNEtGO-1@oVVpgu{z#^a3jk&whBeL>}`mA~u;l5;xp6`ogou`8*1?vQk zd(drCFGHWF@Y4F1oppqD=38OV-mm*ak$IE^=YHrS9THS%wniXBY1Gq_ zhACjX9HzWp1uY(I8Cp#2EDdy^Y-z{*yI|M^{KM_HUPg)(o4E>}pDaJrE$~uPSknxF zT=8b~?4mD@n)9?)UgWx8%`O2{*F3&E)euEI-&xkON8_!xyj#Y8(=YAH+q>}0Pq*f6 zZ9sY_*Mdk9Ct6eHa_^$_z^anmN3Yx!*SVKH_yHz6lX|!|Jd1g>J!JB*SF6>G4)WruIH{YFlbWGz*-xJlR9L2%~T#ZyA*d&bmddR%;q_vt_ zz2DS##+HND>u8r?e=?Oj1eW>Go|+Hk{<|2Vi0a(mcF6oeT8o&i1M-jvyHS^xf2pi( z8T#nr+ux>1Rxh?t@V{$%-Z(*E(4nqNpu~nMKe_o5dP0;)vc7+6$TQKsrr*wgzqd=R zaKZGUt7W-&+Z>hBMu{?mq|=p=t!jF99hB>pZ!q4}_rcM*YU6KwoV{v8E2oV;53@n` zc<0mny4Q09Lj5X!Oc=t0Hn=DIYRlZ&lZUQV*_TgkB>5*+!xWhd!+`IkyNP|N0i zfwuQejrioazmn$+8rwGY+Tb>(AN0 z>Wf#ubX@+`i-&C$UADMxhaXq0U3@aRRp6qfXV>p4ab5qWp!)&7&x_2hRsf|MGfXJV z(5oUx@YTT~Z+8`%-#RK8NOD6WHnd7zWT7;Qp zKbxA1xsLNzH?{gr3Z=4Gl{2s3-iiYm_2YLZ=?(hIKQa_4#X|={o0lu=JAH|hiwGDG z%H4LU6on-}hW2IzqK)b^4@0Hhv}Qw^#3QyD@GrK2_=l^4#1JB2|H_d~B4^3p#woY+ z1iv>)ohpW0DOz?B4cf*5Lq^N%KXc1=f7FATy9t0*_i8(5z>w3pdWe+gWR)C$+hmv3 z)|=_)g36OKUR=1a(fNo?uuu6;G~p z3OoJc+r47p@eUC#L30d1j(%8itPPCm`6>P>sQs?-2}7P;_m8~N@M_6vYNN!dBzC)zKR|AAiJGyXpUOx__Vmo77UzyddWFVJ$>2usAHKK zuSSLfO*YgndwAZ_D&?W^H=$C=klFFy$t+fyQwF&6jWFnO(@SBx?eT8A!ghs8wz$>4 zo~3@df0JM#X_BdL`n%T**w9sIx1`BQ7^-_|cWkc*2P5v^pEkRwzWDr)kr&=|3Os&Q zPgY$nGw`iE)6}^!spHJ$4Od}g=#=vCSU*_8GM0>pGa34G#V@jwGjHnl<|eI($<|Lo zV^+^kz|HSAV-o)bK6ho|nC$eF`$b$0?TkMede(D%GG{jrWV2Am_d&hEM1~VLu`N=3 z$3bCn*sn-Ck(u&{+KSiyA9f;Zl*b1HIJCt&I>e=v?R5uZ1wh5Wc{l#Y|HNFVyhCd_5Du>H%T5XhY&sEfbZOJbt!>Mnt|Pnp z8(#jE+Peb^Uc&y6_wb2R#-8F!Zne`-6i$-usXwl-u>lB8#HlBi=C8<3ip2shzxQx# z*704*EjTcgKr}4Nd5ULwv2PoY$&z=|PY(vC*c0y3d-j?Wmn^>%`?xCNex0Xyd~f%D z(NUfJw1GAOhW)WC)P^J{fo)1Rvn$a3;QsqPM;2?AqKPmM9A`jQ&-j-X*t6B2+Kyp% zjeG9}?3TcN+MDwQu>c3V=wN&a^E(=y@gz0!q>+BdzCkioYL zr_*k_BQ1K)deZO7n-jaF{f>dQNU>&=5yb z%(p+26x@G;{S{&#prpH;@o|ow>eQYFPQ!aZzYYk9N>Tfv0C`T*Tl#qE%B^m--fidw z^(k=H+TR^$b$9ukWh*5_U}2%MlCF;3`#FbN|D=#%Z(OGO^K|-e7}$ek0z_OxFO*NTwH9K^HSpQ~!r}X)<`K#O28@N96P7U4K5an}z#)-RG zw~k0ByEXmzeOkE395k4rxW31!+x2|UZ_OH9_IgRm%&)JVsq$J3NyxIkL&)3{fqNyn z?hjUUm^*aKE33*W&#)SD2U+?14{dm6a?ANtm#u>?#gJErZ9$d9_?-Xl?%RTkP2bl4 zmMmIbt17)7&~)V1?1SIz5%ymS6;+&9;HU63@_m{6YUkZb=ax;stFOuoCM{5G2^wC% zBIcB1OV?+|N)OaO=;PLPkf8j&LE}w@@uPDKeA=FTaSQFam<4G?$3K6*c}cWYK;4j2 zo95llE96f5A>*eJp(i{q7aqYSqJ4Qg_pMxYHFaQr(LlH0p+|@GzrSmV$)M1Ap${@< zX3a_~&9Oar|7E@Rq<|fF7vWxBkef?_TK{7wLAgSw?i%tUQ~tSn$3e>>l_wUR2)Xno z_sWVGo2}|Mxs3)L{rs0+DkFU?=J~9+ng^u`jtZge(h}*jM$5?)8_{L#Z}p|y%VTY# zJ?^j?Co~gANF*`dSy_eY9U+e}N6|Vc zX{k>w+eB%wFoY}G{6uQT1ZUrj<8TY{1G>bJD^H9i<8esJ*KMw1ak0Yck9%1$z6nrD z_2lT1E{R<1;QGY7`fbqxuJ62tYW2~S1%jjdR~)dVn(mvCQEz-n@0ib$#~VQG3fESL zK3;dz?PvFSSqBVK9!lem?<;?E^QUW8^$|@~7m|+W_uoI!I{$vru%E+A6X*2l{_|F0 zq}P=IyMPf!!U1G*9yg;`;fe5?GiD+GA9HUW5B2``kIz_AoN`)FDk^EQCLt+0bxJ8z zyp6-8Qwo%1>O_Pu}K`~E&2 z{c+#t)B1Y9mg{Ds+N=Wbx-b0LyuR<&|982tDmd%Dr*O!V_k&(!8+Z;EPv{R40%7o$5OIQTX z1=$%~Z1x#F3PlTgn#|3x-%|`V)0{!vSTi0F;A^&AGB&fL0?+o)0q|3d&Ty;gqMl$! zg*WC=?QgpIK8WnHXE#3-)3!@dcL7}sO}#Qlh901h&ZFG9R@+P0KJA5RTzT+R z{n^5m_ZOD8W+uq@EKNP-)Ds(r&gl_#7x>!%$awXWM z3v=kM#j-clJJ#orR7NtP@g_32iNvi{5A16W(#rN(mjBqNG3P{IpTrSK<|5t-*GkT- zrIq)~4ra^5SO<>i(}TL+2WeJ#XrAJwc^BVLO&aYEP*kGRQhU=SXTK0@+=Eq2W#=C2 zTk=Ni%z?Kw0>gPe{k`uJiYvLJypVb1i%uThkSa~O=<-TOmfyl>w7>I2<&F^nJwLaa zm27Hzf<~{sCRxE09#PNnM{OMxI9*Vqn?4DF&sAKpwlptLt>N;6SFS=9`)@}T^BltV zB-yBeYn^dzN_n6;WXnSjkTO*~d3*uL0^`UKK~w|5Jus6{Vz@61O*#Arv>M_mFcO|g z1np-(*b!1%6H@zEN6A#pF^*L6(p8&Mn!b9$mYMm$(F#?gTM*wUNS-giuw`m8rp82?kdjseTtu=zGuPlufY{4j)yMCp2V`bG>@~b?m|ym*a=V@KGgye- zVX9tT8`5M_WBa{+4->0C6;3&PCcQ_8fbDawXgoLRpwIham&++Xu#Siy&l0~(iXq(n zGW>W#;@3FmLBieI#{i;=yrHK6BDMrj9Qp_PU83zv@i-kM7hj+;UuG+WpOIm1+I(FpV#-(Hv;ciwmc!P79GdPOBBt+K&mId^jd6M$fRC^|sm zXP?S)r}A%I)}cROXPLa z$kP*a8Ay`B*8SXC^0Kp;6)w6vu%`VPCTFofAi=C`aw5M@`!rCa(cWBJV}*cRa*P6? zP+ZfANmlS)HHnK1s>(y;$^vx!BU<@&;B|XQg<4kSHEyI%Dwt;sLK>jLA&JBs9KWzQ z65sWPxDEa!$MQJ@_CR^<+NR!b9$fD+7}h374XN3b73`BfULATL3t@x<^$UgqchD&l zST=wRU&ZWaLJ#;YrdqDMD7}#(GII*u*CFd%(i-#**F=lHnCfoNWMt7xAQP(2XyqTK z0R`#$QV-{n65S0qjfbNW0IrW71u+$=n4$ z0Sit$MzpQOCKf}C#W$Vt##ifMp%pVGb$+&(p9gA5TZ=YtYRECctm+Z!Zs>f*vH45y z1X%puEXrdX8rbD9{r;iGbJ_u4AL%TBT7cYLdo-#HmY7Pvf#@mPnRjrr$E4Fp|=>h6s=$yys>lUJe=v9 z0dwtup#)nI7t1n93x4d?Z{?j8-Pu&=yPHuiKF7FRQ6YK78``-hhf=;Tm^<;V#cd6( zwHHE`_v;V}!WJKq=DxQQo?E70u2*OMgzS#`=csa_Eo&Q%}$|W_JU*(#j4Yo3grDYeQ(#FygXFB+<_Q*0_i&L z9}U@_0n6W3B6!U>5?m%L(N=N(Mgs`_?C(8ujIl2vbBt5_TvoM_*cCN>2`l4Xl$sLa zUZbCpK31VYeVG#GQJ}AsNz>PyV*DZMoyLU63UBGFT@Vfq4y+)s>1wU#55jwDt7Lo#q zb$~U%Rq7ew{?gU|eecAIUlI5KGy%iR$VY5K$hx`=WAH63X=8oJh0#g0|aE`u)mqmNIpf zwWxC(wBwUaB%}o=9L-RMRd#CjG4LZr6Kx%he6v#6H&Tg*T{XV`A*GZlqrS_fFt_WK zATt6`ONkm1yLM2KhXK0eBOuGMZw__Hyy)Y{m(~diT*XlZBWs+@?I7A7Y@QPG&|#f! zV&w{OdE6GLr;Pq0h+hNb?mQGhWU$o2P6Al-?_m?j{{HfH=Nz2*MWA@RpfM$>-^e>D zy0a|r@mi2uP*pa0IrV=F=lDOsrrO*qy}r>>VF}l{`|jhD)dFH2I)lr+6;HKu&8@ni z$z6rOOK69ojuRg~##((vlAbjq3Ul z5lPDkU7%s22a?LKCm-0P9HCsAOaKAi&{4Lp{?Adns&}HisuZd#$O#rQYI%sD=ds(A zDU&?lAYuWc@x^hbDEdgu^z6n}G<#=}-R{2FfCf@n5V9T~G99AJ#`$2G>Eqj;U~mji zw;GK!Ey|*AK(aiPwiA0<&ARg-6^<&(?SfWm0eL?V3OcaBUrXM};?6w?e8Rz2SY=1x z;r<%9^8?z-Rg6I9TNcvB{iv8s%aILWg?nEXR>Q*1Rv$$!4A!=+ZNn|2yC++(20jqF zyAc%Ka*`Gyb6ZR1Z4`wkKUg8@Yvp|sR`OAxuw|~GdnRT!NvAKFL0Z9FdIqfVu2f7l zqpaJn(EokVwx^@O?JAPJJNlA1>Kg1Jm$@Vfv@{bdJWd~=0vIY=^iv0v?Q?Ye)Qk^` z-@o`^HG~bJ=mI3c02K8C$_VCIWmS5(onbv8PwXHY805|>;pohM@?bMd9N*H=5axw>$ov7FaG2wOH3%8l{V43F`-3%sZj%P?UqrH~B=mbN z`gZ3TU^m?KF$7d70VHhaZ2PBIcP7vWJZ0juLY|0CKiWLOvIYcAMH6eUAi&$8vj6n4 zS*+?V8*5XjKX1`GCkd3Z<=y;+0nk}qsKQoy4Ri>a<}|Y|quen(<%eLA|L{O>8clD< zR6BAY%_SYDvYS7a%oNfo{_1Z1h&W|uepAr&MK3jRL-sBj<6u7xHbYxHg2 z@oJTZg?xh(2J7l%vSVMhRq2$-eL=f8C(0?fBtAsbUW^cApR9DNzm3#R3Z@}};fpvX zcSoKH$C)NU%aftP-L?WNytl%(6-vCO)noKf(*?)Dz-INd%3PAOJRwG>g6>>a5CFZQ zk-hUTM0fMmt`Zgt84<;K_D8#4Paey05}4A;v5NA3KKfDQxqoKEkbbdd%7~Vj`Szhq zwvDA^{b0Di7?aZwTIbTQB_MhsdFpw<|03w~ zk|t>ltaD`gww|JJfo9AMSm6F)xQ06|F0LhgT6@q>^>b0!vPI`yGGc%(>p|BWrOmDy{^F}#e*`m3421GO>tc)%GI zX%SM97IW`7EVd{)M%Z|;{fx<@vG)#3gvrAV0s6fh{hfEnVGp*GgeN=01C$qV?w#np z?m(p1nkM<^tZXdFgL;&~J>gPt?MX!nC8K>?Ppu7rL8UNeye#)Y<~y1g;(^))Yv^r}0q z#mCo0z% zf&P}_2i2b|kxp?`K!Jh^CiC^}!=acFVmcEmvWmvCKxrF)CMOmuh2n>#zCI%&157xA zrm#$ae~8x@so0$c6#}rd7ci5>w(rhG5i64Vk8KHheXd)L!?(196*k3I5;(y^q*`HEyY*CK~jlyvpF__7rgj^}$o9uA`J232c z`OA)1Yuc@=c6JQQG#5e^+V|Pkg-O&1{05#@mMURzim^z zmie$&n@*|(*}#uhT4>L@)adt99gjL?`(?^#PH&yQ^QF-){cIl8?8*J6Nf7g;p&St% zIP#N|OoW8RQ4kcvwiAhK*|$9l)6EJ7>g*`B^%*9U^>Eu3#igK!tav9~!~4ue#r7Aa z=WTX3?W8@^^82`$Jy9t|0?BWI5bi z!5QOunU-Yi!Z{2nQglN_IIVkcY^M4BJ)`$ch3)W#$efk#4Oj9M-ZtxvTmOve*Yg5m z;H5uxc}sME+RsrmlPjb;pwNNIHrhv(f%p#iDaplDfP?V3%k>r@9aYn?C^n0ehb>{d zupmq__>5Y5S;YA&au#jSJ(LmC+Jp&a1%F&w=i|2|h-6K){aBnQsLHrdk9zN4&c+cld2iQBwToDV9i zZKNP^1NB{#8&5Uy>Z*Z^R&S#TDpsUz-IJk)aXkAl-BF`Rcq1Qk8!@g^u3QpHFt=uj zGn`s#K$2XQ1B^O6z`;f7VB`8W>UTEBff6nfX9{JLhVt5@m%?^p7%=uLQ5?axERcVj zGRmC+X?=%@pt=oY?56}6%Ur~O?YKjTTkEN(k`~dw0sA_z^mF2BGPx^RLUJiUluZ@#yG;=ZpRvNAF9J-dXQENxk*1mTK0%R!@ z6HVZ!lauiHdJB-_$BH1J>}eC(Ehb;51nHD~a?un=a{r`|VzUyX6PSEn!=uSHms>z! zUW=DG;7U{683KQeDx|EMKQC^bUKr@=;id!360AsQ`#jvdg*kd-g-Rr$qElZpCjo<4 zQmLQdTMtMlvg%0tq|TE<&uAtjef>Zoo*t^+I?>wy+}}Y)+Y+Q)pfyC=?fU>xU2eow zK>z#?VNy8P3;_o;kn-b3{%u^c4#l{kYk!>p)2Nr+_qs6bj;W6K*bO=r3MA#-592M= zA+lNQ@!iH2p!-2jP*^_emUh%4d`^{zI^SR zI6ohp?C=#pKM$-P4R66A(6;qN$XyMoh(&R^DrB*z9+2-1?e7sH1V4Tt5-JQzw+GnK ztF1?TXplQhqq#M7r9xfogaQhj8+A-xTik96teF=2_Kc+15qOMq;FV*qnn)I&tFDR! zg7ZP)zw|%H;6Zi-a(u%Vz;$LSF4M2u)_m=~^1!|u$^qNjC~0c+AGMyVdaz6bp+z;@6^`!T$CAk2A<|+ zYWFMLyzp4x*fwqGeY2x&!9>|LYV^$)6?}{yw`!rSKpc_Eg@e?W4elOj#MTolj<%Dp zdSZ1zWI%*hEX3yNBFVpzYsr|HJ0C*O!kZKPwoGo>1)l+uRpXp%Y@8;o<->i4)nWPS zRM(0@NJz;~*Fb&34MPQWivq~SAYQ0Mc%vvVZE{tmx$}$%LzAz%b}*Um5-_u|nuakz z1E@4wO<&sb39xbD(v>Dw=fpV=maLp-%-j<|XW$VF|KSy`fO1mtaGAfeMXyJbCw_Sm znmTe`ix{;F8phNf*Pk6}GGeg>$W2-#oG$=%pfu|GX@oAgSK!Jad-lxFf}=Xu5JM2- zX9vtna+DYS_R$RZH^mQ1Of)9=tqn+t0$HU+YeFgUN|UM~A`=KSMy=g$XE^P>MWFwO ztdnC23*-2n)T*y$5#_S!awyCI3GZ!o!=*lNH;A42K_m;-VZWcz{1QlEP?5mVbUW9kxemGIzz0RgWxJ<*P=(FdpM@O22d) z=9&dIu|rtvJFE(;G`%vm+Evg36jTXuZI~!1qMqzb^A}+37*?MLMBe>7s=$mF@ZR{J>A!o=8j-*i%XFKeCPU^_ro3x$z;&CQw806d%A0M&97v_%Vp z@MOr&aXwFzfg4+jXlx+RPK1S4Uk%702wg)0L${Q^hr2wq!Q#UYeVzVrMCVi!MQ70H5Tizq+@gmc&B@Ft{*y<-}qp z|D`gQ<&W960P!{O<0=V47o_h^&5=BzdPyN^v=WMk3#9Tqx>h!Wc0;{?3w#x^n9J*h zE~XCde*Fztul(x$3Z{NMcZY`FC|aDv)Ta7x?1VsfOgd^q$^^Z08WefY^dt>$78LN) zZrUfO*Kd@P^hry(pLkjWp#3j0E8-IBjwd#~Db389hFdHsk@v?<2Ud@5~+{fB>r}-&5v4)=cfblvQJy$m_yH& zj#uj++f4czAB=P6HT7#`-FZ5e0}tMnsmo^ztbtMd;ebOj{s+JSKpOH0334`im;jH{9Nmv3gce^#Qxx-ui$$sY4uXp1ad;MfY0 zti)Kp>r03EE`PTI%Pod@SWw>S z_Ik;nDGP8@KL@lEkF^AL76S0jmQD#b@*cz_ec?&`D)^!NVHM?>xN_4kugPn^q)~Lvssak1(Ya?frZMyI-1qM&pfhvq0{7p@-Tw8D=W`**e~f6Gn7&{G z@Zo#9*S{4rKgYkXwXjZe_B}R^v}(pQ2)3hZx`CcPfkP{27gC!vP;#|M0fiRcv4bl8$R7ZH{o5eX1=3Lh{U6!|BWuV{ zD#)hWB{ZZb{~SL-d_ki#)6W|N0O}8rn+JwOZC?@$rK6ewvse#wpkr1_o3Pq(y?yu0 z*dN zo3B7dAOZ;76G5)dt)-2UxeXG!RH4v=CSF+dm_zECxw!qV&<_gMvDJY~EFdXV2(`SI z_#O%FKTmff-aY$XH}S;Y(?}1s#bSPmiShOk?>oLHlM? znZ7^{6-z|{#b}AgC+PhX)7iK3;(szWIHe#*_Lji5w(6c-L*)HuS%y3`t^_!PLh~ZoC6KohT;CwN}1Wmx+#}8LPwP&J_ z4QFaiofl_!V8fdLB7~-Fe>8bp*+0mZeBLO)0+VE})2&V${rZ^0=kb*#yGOEaFgzgH zB}!(KNHs1qfLfV9=Is9wr4mxaxF}GXIlB2(0i=%uM4g-ju}hSmD>ztR=SF)wk2hTR?5fCKbEsHxj(AY( zq@7VyDL=DdfqIj1(TxrSHh@U>n?+W&E$1T8SN@dwA^Bc=6@DVjoPfh+x?u)#XSTOp z(CW48ODLJhktWb+P(y%p^%z`LX#NQ_wnL-0^#L=}pX_;XqCD%2qD8)o>ef?-&!Jk^ zk|^iNFyrp@Cp4X3xB-Y&@`(+8>Pq?T7mnFyz8S4wt-WM0foydB_K0_L`erY>bWSXN zSkc#Y49h`mVUJ1RX}D)g)H|2&yh2Vt;?}so!O%kH?JUeC2;Uq}q=!VPKh*_MOF}%@ zoHy?66lct;DUZYV%fd^0AME)}Y}b1J^WDpt}t>gM2kt9yuKj4j3iP6-PSA4T|uW!GxV@yu%RAca*(>=<4JKev$wyfp9=bf`7 z{aoP0hDMI9493r>l&w|Se{N*GmTSA&S-%?hvhrLP^~CASyzp~3Qb7t`YwG}7%CJ#L z;SlAM>&PLI^J-sB9h)-!&4JOZub%2FaiI1?$Dp`u+DXN&pXIeWigL-M3ueD%IsM$~1Ed@M?`$tCiH6zMa}tf8{cNocA67 z{P4_!ntCDm;m;3hf^OYsHPHF~<@dJ^5`2l8brut2_Z-c_yA6c{tATzsi1!B!~mPcfa4%lYN z3dQ{vd53UYOFNOo&x{Zt?Kq!&M0z694<63+Zx$mpf)jN=xvSNkJEi|6WbL3&mqtTQ zbE`ZVdm(jkp|8nY4UxfnRDJQix9~#@OZ*xbBq0oX-hJL33MbixI6ipnW3TI$1shG3GQD|hE4GeuWAhlu zOJg(by}A43rpz54Bj4#sD;{zPZ1g~fjKDGHkwVTmw1{@9n&frwFqN$FX{k_N@o{!x zS?2bPNFKwdFTUcBD84=*=y;ezfl~$qFD3_i?Mwooo^@;{J85KW=Ek( z3Q*)i{0SY#M-i|M@S_QfqPiB^xi?G7TLsTAAR75n=>wnzF@hO*QIC8Umc$%X^JU){ z_K05)7vYdO7<6CC{q;gX*v+Ux_o8JiifbrGwU?J%4lZ0=NVt2pX<2(prXiJ88{^p; zn47GPr?qFjl<}lW%afgdwUlz>*mhQs$8(nlrY;@dgsD<8Hjiz<5_mwt5a*5LRhp(y zXXu8eZ>Z^uB$2&7qKzM43JE`LHmibpNbh0Hl9Bb;;JtY;uhiH@Y{eJfX^3l6cVR<- zSc>Pw%5FDCWHHzOjrPecaPyjoLLir<3nx}|fnC2QX%2h20F z>zCPKk^g9bvuV8jbL@!k@Zd0&^|o>Rsdo6IGZ)#f>l_Pv^i(}Yw8$@HJg}iU$~dv@ zK$+HLv(~+L^k=tAw>S8VUJ2S%x{v+gV=49?S+|g&K#&|`Cz;sr%av5~X_?|MqRTpW zjTOf@Cit!M=Ah=m5P3*-1KGED%>=dec}Rms!_@ks2hZRurE6M9&yln4%U3>cv>fKu z91^kV|K&`Wid$ZijnV5)2L7)8M1Yo+2TS;d-PW>yCf^QRz4DTjwiL~y5w zzXwYMkq{tzi&`><UN>NS0$rlu_{>_FL@h`BQnylL!CFQKf$1U|2GbRaW zs^I|PKuTAJ&BXH+?gLe-WY`Wqt<|AQ+OhWI)n@bYaH)}JvYX8Pe`_9s=0a3)N5Rx+ zdie3!#%?BOg3?Qu?X$i>C-X6UEeY3rE2wkANKXd zyHh3~hpM}m{Y=J)a${aW9^j*FIQK=FaM^dtd03b}2j(FBc|U`(c*{TE&uGt_0yV!N zoHoh0rBsG%yAw=?<3>w2Ey)x;HXJp}l$3D~2%j34E$)rp@ z7EsbJ(3~DLuf4}i^PLMsm7L^@6T#TL=|^G1gXWW)1)1WykDFf<*O%@XW#`HEuqv!G z$Jq|c-4(j+VD<>iS|ClO*{3&4jI?KdXy98-;*1rVr?#$tOuSAjzbput`gPbWfKCm( zD(H-HNWbW*(Q}G3EeS3=ev80fU`p2sErEy^5u{5RXje3d^1!xu)t?yY>}vQh8J5u2 zT3HLujoSO^>yi~0^kR@0+E=63Z}aJES#NWqDsj_L*F9y=V%^8vjuK@v(SgIaRK)Ah z?biY11;Y^RDu7Xv{+xs6ouo6zSY;;Pqn(@Y!4)iFXc2j+Dqdx)d-W;PLepjCv6AT% z60Zt`9l_W}rLVGxN$2~P+AwkIk!@;ALd6?Vxz%KT*le9C$6lxPa~d*4HbOj5{k;Ai zuds_^=J-izf*z|+Yw}{MRjV00ynifKHRDYPiJ#2Y#E+lJl|$2ytU$B}ipr)TpSo17 zv5jrL5e<{QBUQ-r5h*c;@oMo&LhLv-K4bsK_9P*Nsfvr zeg${>Z255KsFf+np_|-f69;eb+SA8f z`jhPv>?b|5ua_nj>W#hi8j03*I+N(ybjxx{oXthjjyc8z+94=Hq-Q5j;@9$rmogy` zPLI8O)rtgQkcBYI1_7;k73d(DCGZ24j48djA)^8Z9vIa+Yh=TB!X)q%l6am9D^eZR zMgF6TtUb&@Aj(>K*+D3QoM>7hmxy~-v`)%xVPl zPTOU)R`gzyK9(d*Zr@&4?%LkNc!DiQ>4d7QFbLFVwe+H~%KyQW#cT8{B7@6Nr0zG{wdoh}~9%$Oi=A*;BTFKbVA@a@k=Mw2iAHabHe2f>mpQqFdKh3AM@?uHXcCUOj z88Kcuoha_b9u21-9Pk3WV8iLOdY`w|8$jOaP;?l+>}0O)WB#;7X9l1m&nnQL`E-7y zBShn3`J--kQakR}fXp+a+jpo}zqYTQ^Q3Ql%jF&MeVF=;KY)+2UJ(=`Q*mv(qxzou)ncHZ#lpveyh@N1Ho{gk04>w#8=+2WB} zS`Y2*tYS50sl5;h@np@H-JO zy@&layhy_Y-cN57 z&VFo{v;T#@iOd#pz{3eP8nHnWAVa7I~byePf-a* zY4T7T!VK|+XiFE_oa@S_sl(609|~fu|7QHA);ttq{qC*$7#jck*ZCEEVAfv1b11&6 z2NpP2Kbljw#rNUzT9;?H=QsMiEJrSdGK26ra@WslX6-8u;&k-rZ*lBAMOSkQG8>7` zB_Eph=(uq}HQ;fo4)4D<95hJ_KdJ21SubASQPV#7HRBcOo z!UyAyo{1q5YpJTB@Ty(s=>(Kw37sdrW}i&b#1UKsVM$K}{~U{fiv=}}$FMp7(0I-% zXm5tKUkj;7$Ug7KV=4k16oCYTwMtN&^2}Uu8rbddPD)zAY_rf z^zS|BKz4y5%$a&lGh6_q^wWxF>=>#T(69;c@xZ@%{+-f1`td)z&^{s%r-H};)(-uK z%#m-=AFt{~ubJU}p~-*&<%?#6-e;ftB~XL=qfuC}j5?5p9E_%$qo*B*PT&>=kIfov z13&HU%&79ukO%RFwgD7Mx;sS*u0-EorxzXyf#GOwg4Gv{52&8_tf|Hz$yCZjzgKU( zT7#Rg)_4Rw6Cu5|LW-{1D_ow1?%+@_A$Q8U3XPubL4skAiD!E{K~9SplMZWJdLzt` zQrFkha^(HVtnn$^I`_nFlIC)st@Vr~$MU-0z9;04Sr!!4DNr(AyNu@<=UIE1`whpR z`%+N6$+u7G*zwwZBiUV{G6?GdUIH3>P%^^$k?6~ug(eR69Q^CQupFTUhk2kd1QE`CDQSn;D&NsHed<|fs9 z)F5!ky}39s*+ntw(@LkIYxcuwydW)FLl&XBcJ;V74kmP62v8I-j<@#e{XH%7D)lK#MzbbogpZ+;SS8!u z;=GG8*)S;|9&oF-lwB!-&yT?o5{P7kbuoN;m1H(!x`tTAAj~A10K+&VojstVi184C z87?zjt@ws;VbXE}yhb>!4|gYwo5v^n!f`&xT^<;9iz1q#Bvv5IWS6iZ?trQK8#skU zHjaL>rqUmy`5lsRGBfi#VCdQ}K=lP3d8K=QTPQ3sq_M7n0WTms+niYI^f~Y8eNlPM zU$bT8S282qDFYI1cK2%MmkH3^=2@t~-cY@C-B2^bIPPOD(|oms_37rIjmqw+lVb%X z9g>zS6TxLAkv!#gELl4i3J|SL6mMn(GwXZr3TH)12=4;nn8B>18|VfRHpY!+5rQn3 zqWW?d_z4B%<~$MPj}V-la4WOqpC{agyyxbk>CBAXLWh(MkT8U%p($VRg8Vi1T?Zcq zzZZk4eW*!Zg=`M^Y!FD%+>aixJH)s-*9?s`_hQx~<0Ern0U=liAH@9&%?%!RpB4Tc z!G#&mfB{)x45H0tZD%SWY<}(|n|nc|a!ST0uh1mh9bU?cs~Le!RxZ=`H@hSjhBLb# zO)FJ63H$op;}f0tTUgRrp%FG+&Gw8>i zDW#q^h1;{oYI-0>KPlNDS@3{uqFI9T`jxNu@D6E?pLD+{+P7=#9+bcaMJW83Yn*yR zqRVZx$s*b9nzj4ebXJK{piG^ciN?{Mio@og58GDC*`@AIc3Xx?9r2^V7%TuN@k-&~ zzdQ`u|HX$PW(#@GU)sR`#=CIw5)2?P41vrodp7gUd2P*KvHeh~%!OAD<6}%n81t|4 z@5zrMrTVnV86w55wQ_s1ZER-M6qL1_NDoT3PVhi`CK>CWF~}|@itgPeY32R-R$&`n zd1&jO=`=D+e^BFcC@(C^p{e!O^ioQ%%-CQ^*hj5(XKNkIt3DLpe@O{5(m0bClG;&Q zTpOM`wE4ZmjwDyFKbt_2ew}Km7wIP+Ua~Q&r4PlfcqNkkt9#d>23n zGMfM*0`byW*kJ*57~tuFw*%p)ps<0#S!m`YnlFwa%M#2NNAE1d<~kbF0m2a^i&#rl z*@w@rOIX14A6}{!vJ{iXD--}|vZFW4Yc(1Y4u|-n@_keH+czaH6DyO7dX!Hcww!+8 zB9_b#8d1*nsHDQ!wA>x3wB!sQq2zU!mdV_Yc5Va z!!VUmPSjclxH5WO-)aCRrP*jdS$;AwRdzhj@1cry;T-DNVBp!H+HYgssIr4g4&1$9 zZ5IV;3cOz|NC!4t0Mv7UqZI^6k+_@~oNxizObK+8!(421v+V-JVHP;%rWOAR)dy~5 z_F(aYYZul4s%H2VNUlJoui+2h27^Lw0|?g1Yvc!i3S?1vUCmHN!yE+;UN=Vdke$Ich)or9i2>NUIel>)V?`gZ=FG09U(uYAUpS#3i> zRo;cpdHI5G+cU>Ex_2HAO;vjC(GgMc?m>7*N{De~Sfa~P;Ai4v@oF9FGJJyAIM-$S zEA7xF5O&Nq3pmQK3VVqc6p+0C6oUL`DztTY9xQhhbo7e9&AE%jQx>6hz-QC@!#@)> z8UGR<4{XIjWQc@eh}@Ed{t%|x3!}MTu;J!piLXV2v}rBGyPx_m_kMo@qVGeB<*uEF z)rJerr>b>B)g_^h)26rSnPrGs9FG|6mwusckZ@MZGnZ`F5_E48R_3H^Np#G#jozkw zt&@esdX-lPIsNZm^!9gYww7#nb{TZm>4;vgs3%BY$woxcYa=IB)CVD;*FmzlRqUCOkSqA@PqxheZ(oQqG+r+R0my!tLPq zp`!(ZIQF293XN01`L5?M+a36QkObZWo(MBifna`tAD#f%o_j3w^w%E@(S=`)qLOXP zht%zh4>S;#x*7m*&M6H$*OpA6xs9D>)n0#~T$kri^+kEn*tciWr{5MgoaxC(`bZ5` zI)1=?;I(}10omks;Ov50g0AV7ybm7?vQs^DFK^0HGf}s_eN9Yq&+S0$^z@`aQSamV z6Rj$0o}IrfN0bTFRIovG@S%Diplx}41cNNLBkE`~tua9cGZ=COm@@8lg{lf_uA_ev z3@|kTwV@9@Sn8;rU*g@l1!g{7S>_H_WXeOcm{6f15D0!Ork8{_#PbR43VL_257o%iEmN{UsM+3;;4$#k%cFo?=aM$z2MNA2A z`!v<0Viv3DZ4V z-rfc)-c+9E`Iu&%w)R_nq1yYcnZgZUDpRnW14~@q4!mCZ8qz2cIr8au+&B&N()VqH z{G}H{8h(Z?!&-@JS$B?kgGqWd^t9a5a1+)?2Q0&|U49thv}7hr%Zz|KTp|5_4_ECm z(@+vfJCN&C(*oN7y%3DChdvPAds!-QZN}Dt(V4mD0m|ggKZXJ2GT&&Yr>76p0z4zN zs(jy2B_g6AMTK}Uq&QC|X1DNTK8vOK-X6Cmm9W8fU8RxovGD9i=IVAX*KK=y3sv7M zO%%6C`)&@>vM;C~Unv^u)xMgis-2VJMX=33k-WVMeeoFjTCx=k9KbffWidn%)`MCnN-Qm2hCtxB#6Cq$B&$yk>y+0jGc$0e%Us1E_Vx6+;7KMPU2_ zj~qHMM%F#14nVenhIIBih7IDK75t(i6QIow8Tv&jaMsb2L2n5oN@kx7S<(0zRgCmxm_paBHW<6zZ=#H}!Sit~*P3UTdW# zUkg>aCYvbQyL;90Ytya$@@n^4-;)YZWez7CKT9(BM0jjQB!2F@NW22JO@v_lEfnPm zwTmDi&@an*O!(kiDV*{jM-+x9+i;ri%+)gS6O;iLcMKi1(e@&)q3a3ey82_Rdp-6B|Ts z2N^!KPjXb-`F>yP`+%09=!aSk{>iPeSB{;@_sopzp`x--{GO1YOnyBUWX{=`II#*l05dm9yl9*sO!e*@L^7oBjQwH4<`e}Li z4ZKf;w)Te!&hhZv<2=uX6Cp-`y5LrC6dnPO4?J){ZXUtWYxFv@!TQYIhoE!e);ED) z??9prx|$GX4ckMf89)`-l>Bfd!-?h2aYh$ggkU6SUH)Z`GYy~P3|~Tr{z5xRhe|rK z0N;jLveq{bMZ)ibQn`4HgC8}2uy(m-bPZ)*F7pTxLIbBKo z^G-@DlR2XI-|VBFsVQ|)9=U%~uey9{%&ufd?bLLx!WP0|_E4#X$MO5jVEn;ETsn8+E;`5DLA&@w)lWp^@xft5La3N&lRsw-a z*#GMzj_42+fSSY-}lzc&3*9N4U${l&*rF z%0^6LhCvZOnpQnZK(q;j9oqopfJ@n+ni%hHI4g_xoys9isA20--sS(Dvi$`dbYbIi ziz!!Llo{&6hE{x@BS=#kPd>k91jXFdeOB?J%m~j3Jr|0HLFRS4t%Jn9-}l@e%4FNR z-V2s$4z)d{T6=8=NY5JeWbTHi@6sZ@?1zTbJp>6inCz?@n) z^QDf;>+Gwj3bv(mH=p)webpQH0;}DtpK5YWCE9mqvw`e(yO?U%y5RoQgWTK!XNl=o zQdN}-b;mCr_4$jc4F2@F+-q9&513^CFKUGOcZ7F}*w6#TVMMMGfp!S5KY>S{YYc`UY4zN4J+dE{d7!VvZ5EN*3ze%->+empFzT#f5cdcAV{m!_y!v*a z#^_nsA6dh`2dBodj&xRN>b%?QYCKq$Go3BAh^cxyYYp@i z5YuXcsstFUf$GpRXQNPAjtjzUo_Hfv5GVdW(Cc|ozk%kNm!OnjM4K%PI|5Dz82e3j zg$z7U(OReZ!>fsZRs8RWMqLBZf!aiGdK5zqIYGV_tF&qf|{)F$gEekLY?goG&Xa?Hj4o-!~2_7pv$7UD!gfL4q{|%NH;;hlg z7Jz&angWaF{ZcSKit*vdA=;TsT)t`f?DTUqg9O&;1N|8$n;@`jsEZVNCAKDE9-1ff z?^Vn2yY6-WpS$pa472wJ_MDa$g@L&6kbpi6HD0kqxo4P*^TtLkElt98(3QRD(@L=V z7)wqutG@g%m#NS|KZN`OJ`~zK)B8p8CkgV1 zf^wAm&d=44hBG6G;^3fk!ogsW_u|cg8Fa+(7l;20)G}U&9pOVP+Xoz;LnGpmDUsU_ zqsjpI!CB@I#8$Ao;e}k66>P&+qi8~1_a}eI-e$31TYh<;ruXyI-jkKgiHR?4-P(7_ z8u58_37oovUm1)?gY^FZogu;xz6GR6u#i*;w{Ng^j=^``i$euhN$G%$aX)Jq3~HhQ z)u|`7Ez*AmQdz)#dyu{pzA=D6KynjJNKFIV?|FQ_? zr1Rom74qiR8d}5e0{IIt7rWp+{aG2i@-4`yFF~M%GhVcR-`=8>fFp%i2l2^7SspWVzR5)|5UAo03RMwalVU+Q}v20 zY-wCuC%i|CxtuSEwyqjj-7cI*nbM)?Gkniwp6j@6UtiQC?y={e2r$4x{#G<0buZ{6>Ed%}Hv_mzy) z&X4x*l2%^%MqBcym|+RmpA7TB;E2QIu4r@*<7fQ|l+GWx2A5JWff^d2sdVBSB$4`_ zRKAx7f%`KJ%l{Or2|XSZB!WhM18VN;|GbaDx1*9#f2U(23B8UdhHAE^4!(}58`kJ) zn)Xd)d$0tJ4Tezt0T{_X5t}4<&9C7R^Z<1LMk4Tt`uR0azZd3JZU?z7l+w>4VR+d@KRMsh+xB~&ExtWK*|B|2qhSm zSr?9+)iO)x-}$^Dw=7kkQXpUBP&3DL%!4J0m(^$mte`>^#J@Mn*5iI}_9_e3cfOht zqcIbZYzCSPQxVr4xQqiyD$oPSMOeStB*8-c`SjvF1y0+d=oVS1ow!MmILP!8hCRbr zS}Ulo&?bc`B>3CAxe+FF0dWaX3p{Y=XQ6BzK6t?3HEMz~6fSAF>Q5K|Tm`socJ%A~ z_G-(?vj~~Nn_c)RNQr}*Wp1Ue(v00=GcXb46AuG7>|Do)UAzg_b%y)vuCj& z!sI`wm>^jWo|>Bl-0~Ow`xpM-q54Ijb`VB7j$Io!iG0*!@9j~_4h-L>f#%50Op1h2 z^3XZ-A(mvgk{h!~3sOBsEtx^KVDhP8R9OJBrL!TO0}KHh6V*mA!5!m5)bNxdE)cox5f><(Ez7OdPZ&b2ZvuZA_$8>;_e7;F z6waFo6{`S+LkuA3q2Qgq>8}ej7{+XxU!?56psQ&rorT7J{@4uS?U)IXe!Ak3wSA6X zY6`{kge+lSW_@?K#Pr+L(Uwft=X-m8dJ7o^Fi3coz2{o8@hOr|xm^bzml+X)A(H>< z6q-{Y0DJWb=CXV%N=NzrSZ85B!{oMC+_|ba!iw;A*uVI?0<6V@KrRs8!AXY;5}kVB zjgaEw&KlHK;j*#oFdhPpu$*arj3US%ic7FbNH+6;Z(Z(p-g+pp%hT70Q{^>FIl-oEGKYieS>VXpKn^Lr}?O?8HaFMqv zA9S9;o}gAvnp^r4n3sRHExqZ%CL z0u+SdljYA8CwJf=%52vGR{=cX2p2hs!&RswLnP-+8tSaVPzSfX;f)IjWJN&eat*=V zuki*l1ke;?J5Y9^vOog$Z3q|vKHn#jY7_#+3ltNm%!Ply3X!#INu|B3CO zjf}Jg0PMgE0PT@Qh|xK`R{GzgHMpW`Dd00;$b|B5fw3I9c`rthjsR**9b7jDwL22S zAyODfDSqZ!ux2E5eNC@{#5){YLajH#=H6k1|3V#jGK~hM7)m@%;l@#K!<#;?cKJUe zCH?RAwj*Oa{$O2~04_7r$D(0OtJP6pw~D?B*}=e!W?u!czA zmqGHn5#F{=SNR*@V#HWzUXdCHnAebBapLPFcxoPQt?T)gqeMl`9{dhK{@`l*m>j^$ ztp5$*AIWq1$bP810j67V0rTwlkNLkQ;{ogi3Qxek0gZx!-ce@VSoNGPht6Ex2M?D1 zfdAtq-?^WmVh#4D>XdzUGN^OY=y{BfSOCZk?%O&4&6ZZcurZcMS!h|u@|WD z^3Uj<-x<)HVOO9~B&gQ`#}#KTLjS){mI)+uBFzE(X9PJQ*y`U==;z{t%i)3t8ab^~ zJ!=3o3$q(~fLL)OwMXewtYt2XLeg_V)Fi}G{BWOryTiD~&J^x)m{haR0%uP;M4$ZC zl?MY4|5Q;zaSi~_j~W|E{Esu#`G4k43t1ZH-_o2~X`bn&U#opS`t@J7FXBM~y@clr z6nMIi>QAdxee$_dcTO0(Y=~3FML=*!p+V-lrJz@v8OHU|BtwD0f#zo-=7&GiB78nNhh^Y*|u~b z)OJ=sADN`87od5UdJ44#)-S>U} zyTA9k-s{@y-A!h`-{pDO zL}SKY=AF#(K9zsHeZEWD_TbIscJ4vRrR@s}@0dqz%1&v$>GL)yz%4tq)vU4jLUy9q zH8D#wAm7XNr?zsMLr7o#=;DwYs;643Li$+v*BI29)09YpE%4&&osoZ$D-@D?l z%Lhm_BAN1v(tQ<=;iLGvlFO`m=8@VvvZhvIdZ@HDai8zOeZ=xdoX^P7S3N}`9dQFL zWnM03&KDjkFW+A~(IZ>%A-y^HXgUO`Ea&>HjfvMMCY+bd@P-n@8b=rZR=RX6?~HH1 z>}?^#OOEoB?wegr+p>-7t(oM})kd`E3yOO`)*(jDKcmelwj6B?w72}|_v4j9B`Vc-Ch9oyTTc87yeSWm ziIb}pV-SqnZz%H@%AO@HCUr}r4mTtWmi7&eGxy^$9l<~_8E=71b%)@*dniAq25)~? zE*y}ZVzBw)Kz1G^L0pqIk5#le!{Dy-?eHy9%N%9lRTbD6X0xn(RqTE8hWRw8OTsTwdf1zlzZhH zFAS6eprSJ&kRu$887%K6>dksg@|*P9@D|V0hQzX@ke)@nt(fJ zRkR!yT?z9USM6LXA33D*knTodu4cgsz0}If5A*bf5EcV<`}bo=(`1YtgclJRp?XrX zLu|w(3PR6kLjJ_nHEjL>l1 z_^#xcZ>tAiU>D$<=Kh%(Gj784;_n)3G@^W-+#mK6tB8|qSa)p2^ZkBSCK(p&d`*WFWBLV0>Es!j3yGGQdj z2CBGecwpqxIMN+aWWTh?MC!pb@|X1mHt?I&*Dr}!OsE5ABeFSxysA#()NJd}x*{6e zyZ*tP0QM$v3YXW{Au6H%%sIz2Us1EyKHpD@G~R)bv(ZbyC+TQ7=ofB! zl-5$beC(;6Clycm=FG$1d^Cir)tMwFb#+}`n!H(Qbyki88nrs5B)qc0ZqqCkI}O^aWR`5FJT=4>kdlW_UO(NQ2c*qWMJJfI*wv zTOT3nvwv%$A*tHg4ee?{awbk`qc16-C&-0=^%+CdRPqn5=HArYNs1+g>{ zX!SK$z0_YKT^j29`JWl7 zMOuCg2a+fEC%31_H)Hln=Chf*-(}=zNHbx(sZQdm3&AXPheb8df3s6M8Jza+#44#T z{TpBBqaAH^T8jTJWbY5U9zcDO;gtG&k9~3j!j`!En4O|?Ox57JB6s3`yySBJF5h-w8b|5Pi9QWF!}I@2X3vUwx~MQq=mJYQq9NzM>T+Eew(ZRY>-P( z?ODliPegy1Tq)jxiX$?&(u=*4tN$~f@Tt(|kyRnR(XH*@{QH%m2bFjK zR2ghAG*1Z+Tph~+>~+75p5^(#Y-{hf#*o~AC@l10vD4Zuv}gFg+`sc!LB_c7!ogbn zS00)kHJG}KFDxJC^V+EqKyO{$-3nHrnQqnAj8mM3{L*jE9%{`Vt93F!SW+2ksO9|b zkC%SUM$-t_m68a`0bdiPMj z*yL;N_4fNR01BoyZrl$>~w7FswfRMmPDp&pPOFPobk%#*GU5% zn#zallg`-G&|P91y+d>7jd$2NOmSgUmPvYmU~T)$Ife6%^4+!?ec0jS{otgE?V;R) zQRZo{T%*&rm>buQoOY?bd8wSW%a0X_M~hr%#P6N_IwW0popW1#j&Eyi(T9PvOl!jA zIyR~BTOECUV}~`G4C}=a$y+a0#Z8u%+I?I^hxMkMxq@%BrF3g%P<>cQ+1S&C9M_&K z12QW8mz*~&jj|SsBEzE(k+Uyv?QfWyy}`0gKP4lf;_N&~ngoOCKj+|<1wc%2?~L*5 z%9s1}<=sFcBfTJTLwr7X{GZfF#mEawr+d6f>#;nak+Xki(58En77Pop>MyL3IKN#! zHhFiLw^GK3!j}3gh0oiL()m+_xIZG?r($QWM6#-?*`V0e#`ib(cx;KB^rGrkMwrX~ z`VxE-cmLQCi5-&HXMEc|$F>;JQK0ez?msSj*m$j6-O-Ow2)MWFVQJ91?W`wv{cP;b z8Hd7YSs7Oc3)M|FL?<^~Hk`C{@$j-p<>=wW;%-BCDN6~y@q0k?(bSXUj$U zz1A$QOz4=jzy7es^6_l%&Eud{I?0cx^q0T%T0tBn`doJh1hfqkFZPzAIkQ|$_7 z){Od$Yyyoovf4D?v1;7=X`5NN)*SO-w|G4PoqEu4DTXJhD(PgqCKDZwaQ9>PFAeZ+mannS};e;u=-KyFI?^5L5^h!3VL^lsGgU1CsjLz&BRKYlTCPfdo+eUA}ay`NT_%0*(spt9D}Lk}{8P1*!E zxt`W-9vNqf!eA>WHH>mv;K@#4EXxX>*h8T-ZJtnw#FOn@zz*=3fj@OAWfj zs)0uMGhcW6sIx(hdxD!MtuHnV%8g%CxmM|h`Z$VZppF%V9Luma?d;o) z#%UMwr`iN)JypHbaw?~2<%Xi=VQs6T-p7tUd+5@JoAcz@SZJTjuzdg7CPs|cKTuXs=64dFMKyc&$W8RgUT zyte+z^OE{$p-;<)6<>a^@_EAgs{7^kE<>)@oY`G~1?#+w12fx~j6J$|!t`plt@l~3 zn^%;-EBb|{tU5FH+W9L@35vsf9%^oSJ|rkx?|zt;_q(RhN$z|9c;2Qu4*ib%x}s}W zPKhr+uzQ}cy1LrYoF5P^n&2pZdEijD1l&#jhX+5h$TDqHYH+mc@A{sFF0A&*(^aSD zE#785@aMRq7M(s0*vV(-u|lkKMeLgDa+kiia>pO7$0B14&@mQbtBok^dR~1PugO(% z=)!Xqv#r(RZ8ksp6^9sCoI2bu+Y@^{#U%dJ?#Nz;MWHKxo`A*JUW3(?t=m&s?US6) zG7Q#=9-Y@A-dk=Hu;4eRjM&Twi2*MltgO5vLM=Y-`D2TT6HX4O3m=v$>7osgD*!+zN6c6<FRC@wJ2!XL zf#llu42|qClclL+V>6c5{=qLy>BVuPht3Ldu&$lH=*&~YN}oulcj$S~W2QlbvN}Zf z=n}JIsluj{H?wLv<#NIC`%~(pnOt54cV6U^n)09?kt-gi%6t5lYCn#arKoGtaqM+Q zrO&J5p&19JH*EH(ZEz7Jf17EiM#rAM2(_5ei942mmur&!`jz{PCf~8A{8LZH6&HU? z*8C;qC(mR}6um0j=5p95=0rwj_8u~4CL1V|%_(-8qrtu(`pn;qc7Vv3WTiSdLM$c5 zJ{WCkh|`v!)$i&u*xH$0x~4klPtW&!}7`Z76I?&qGL;dcnE#1MvELH zh+q)b5C6MMF6>k9YKpOjfF2E3A9d1CTg0h+wg8iowE@Fn0og=6sd$&;IBJZ@@$ijIvM|=`rM>nX1m)Op2Dj1d5aG?d$k_d-#FFEu8G6kT;h})zdx-Z zG#QCj_dDMmHLEsPKc0~B+odg7w00}ud|qJa)TxU$8vi`u5C~^0=KWnY#%#6w9xbi9 z;_?vY$l8HgxCSc3u)V2rg-K2ZZ)B5AYposUQ9mJCA~J%OGkQ#zIr~CQzG2CYTDs4n z^;UWr!BZTJs*LypD)@brV;Typ4u)Q<(Wgb_GoXj7MBP1+5Nuc$8Tfp%+19}-^&cuW zCS>v3B3AkSHfa%xD6d2z5__v|JpXlhLqhH2%&MeSHhOREIKm%^a~C=GQ#&N)FcrHy ztz|Y1YJ~-qdJ3F4kEUgrpD8L7n;d1>FqU9900s`ImVV|X)IY2%Oo`zV*`X7UfHl5E zA6V?X9jj$2f-L{C5u0510UZlFoF3u&PO^*=x*BB)dCSr7jfSPdNchs2`9R}lkwoY? zN6Vz;w(d4otj-(2fT8Lh<#OgzjB`}4yIinA0WeG+{pi zr3rlvgusN_OD^Ylx&5R%iNaElgT9Hja*6%rLIVcH-3d07TdQ`sqiLYl$gRCb&(hy| za;s|W#)Bs5RaXZ*Tsz}+L(8xp^P9@u>-Mg3+#hDbx2-If3r#D3{A)%SJ;r&%QorBd zzGyOL2r7CA`wI+Oe$l0ob$IPBtla(G!(SY_6TH#ELYp|O9GtXy5v%nJw(TA!ewgy1 zB0c+fn$7Q3FLkXVjkefU(Q|rLwG2PXY<4Ic>v$sg*DSZil+SfWw+Ya7WIga#>{pbv zfc}Z`3b+JwH8tmSp1+yz{(O*Pqx*KBrEZu#mLswurG+Wdv$pdhxcc7j?*1wl`95<2 znN`NKo)xj|&Tf{^JN! zZedv(eZ4}YU!%$9H>E*Ya)X9GXIM`z*ISqO&U)fo01yB6W01{WeIM~UqwEyfliJ}s zxm-)$x8|^!sLi7~Gxz}Vm$nF|rx=6Kix2>8{>nrvBLGSlAXWu1&>OU#> zE;N@3>~;5NCLef_6*R=~{(GZM3dLZgF>y_~9taPue~!r%=;Xt&{JYHLLrhB8oE-f< z19rntcS*~pRLs^g)u35w!~WL2yCxZJ$R?p5f8I-7T z$|PMea$LS(m_w9*c)jn~Y}>1635;GHJUoD{#h2%`dfbF}P%SfT+L5#2zCpj7bU!Yh z$9nN7VfC`tl3SVCVY<2wQ3c|PgQLthXGb@UN!JJ8Sme3Y_`}@NLsm`0Y1u@f79Cp9x$So0JwXTloi8gI2 zDQAO&$bu$H&iW=wPS*s))y;xqDU-?1OUpa#ML%`Tz(cGa6QW3(9%3;uW!S<@BQs<; zYkYYWsTWL398sxkAP~+oxFeKLOr4ijc0h3zjn}kv>mYXO`3Xy#f?XVah0g2}=I9NcW_hU@bi&u?}~dlM%QkvzL%qIpLng^==dCx zqHvYl9Ol(c^;KnseT?$l{c~SzUb9Z-rd7Stnh}TX%bwh_jwP0h{Kw=|{sq}#@6ugs zXrE5hb{PVYZi;b%8MZ8aBdjU#vJ`8oE>IvdGRXS__OedXa{iF4@F6mC#UzSIqn0g3 zPvvw@LT$(_WrAa;UVDU66uFlCYHTMPX*rmW!$MrZE=J3mHa_tcqRp>4m$6#^*|Qlf z)2f~GPu;8UV5ce7A^qkKq`r%>gHdB}~UWf10`bQLjip4KtpJ`Gbt#PSgC3 z)MU>)ct@*LF4VX3wc{Coi5c!RWW8iL+^^8<@a4%31Zj6{tHnxctm-OOZmQgyBGge| z)se7X)&H$%TB(J3TC$e!?VyuW&Z7V4tbBowGHvL z`KyidOk9?D#oBggHFp#`caM1L4k~c@o$G4sr6dZSFT*syj`}8pLE?1k_a&| zC4a2a(*+ehV`e6xx&ge-7dPQOZ6^AMbfgD-eSRrO=uiBA&OLNGRL%kcmgT-MsQVzA z_TsTH!o@YoDFBBS%1uQZCX_R zZP)!zU)(71(YN@gAvwyb7{@6aTOJ4NmR(f)F7~6}GB9RF-L8QmZnh+tb;x#p!iM`< zJ+TT+YE(moh9)WMp_Uh85S<0h*InS;G8QC`KFI`)`1yL zZzN;G0#YVrKh;Z}RCn!8Xqf7;CvKSmwi-_v)=$fmmHF0>Yd+j#z36$vx$DP#lRrtsx#oX^?Of1G(Se3BRPg;6zzmyu&`RIHSyLF@yBGflRNsJ@#$ zy^Q9v_WG8ls%GD8LEY;|$DXEc&U+MArt0VJYP@8f6zR}iBqPL)#fQ#tDn;qFm1K8R z{ELF`+wVTrdows@;4t6SS(9Q-p1s?-_`7H!FHgBodf|Yw1Nix-@|tIX8>ci3yk2cO zaj|V}^VVJIS(j{E-ucW@W-r3kB16j!J=$lFad>blVEDsEu2U9MSTjv@G;!)^p?BTe zqpOCQG(6LzN9}u6bGt>$f1t-yxtzFZ@jtviUT%l0TskHmHczSc*1)$`yYIiM-D$_6 z^?gmQwO^;*sG+&MyLi0vc2;iD-E(httjLygFsj)s_Gf3D@>RvgGannj_P3R(yTfh? z-jl$su@81kH(NnpJaNeSVPkdEUr%6P=8BpROuwl{+i2qzrh<_ZP%-PsFb@O;>Chyy z!p9AIp}VQYMU*{;_ys$S_XBU~961|k`*T9>j_NZjcOdWf;FyZ$zGRvT)wQ>dvZOlr zTU|4d-{M?$Yxc(s<6AIfrrrzn=t9O}6nU9+6#+5CpzWcfMx>B!lgxoJ7sa5)9vxd_ zZxgWCJ8{Q@1>=-ukYZ80-J@thr3+X0?ZFG?u3mF=d3P^Ae39lTJmi`dUvH6aSQ!v0 zIn~V3&OSXeXJ*40rnwwMibJl6rQ-T>Cu7=TtJgED|ELJP7VDg8@5j9H#IUHK$|thD zUXO;`j$Ybd_R7u;bEZfCEc9*ordDg0~5iCcmfx4(WjKwPA&5_56Y$;uNtN|k2$Yv}2V7oBDLh0P%!Ew)%0g0XWURdE4i?{uRnhX3&@Q38qB zO=?H`5~>l=#cvLC?gwvv9$rqrG@dFmAHd+ozj~8?$?`#|Yf>AXT%)8>w0k8sd&B+2 z;O$vzP&;z?(GId0=>#OmppYdGGK`l69QMDvY0Z?rYbs8)RRkDo{x-TirQ?tz7aF+Q zBe(21=K2n^tIdi{8&bUMj^~8Tb{|*1d1VyP;Ao8prM_Br?{Pmxor1-ZGjTEPk zTRwJbjH7c~;;Jom_vgGBt9!9k(*A;Fywx{7TZK-c4$Fo)uNB?ej`A zATzPP_GA%l-ZtLT)Hol56DAh44EsD z*vMaEz73QGa2XgaYUJV}9KKdgK`%Uhk~_Yhv>_)J3UFt@p;^IwkY!wwYber0HlbF+ z%q8xEu@0~pV^UExRaA{TEkW2);}$_VwX=0@qK%#Xkuwa*;N2x)P>u{zqXrR^X)NeZ z-9-mq?_{l-J$K@oRe^(cj8maf2@DV!Vg9M!N2l^SvR@Q-EIhQ)%dbOs{kB!>^M0z@ z@cP`(NrpUL@|Ej`K9|d17ZtQQz;#8iD z)Y$ew9X#T}var^TA+?rUpGO~PEI+kxfY(y1xt?v+q4Vul9{;sy&(-CEx}c4%WoZpt ztB38Tg*u5{f<{cpbd|L1v~P71hA3JGl<2jqwVuoz__%#eK%IHwb^fm2xv>Qd<&Y=ts5JSofO9(YK!?c(k2G$8mRwGJTE`l__WLHI z{+K)D=k{=u#;}K}es0h8+IFUGP7KHho2+ zdu7ILU6))gE2n47(#G=N21nO$wW}lKW8~R|^qi5v-1_nf2DrrVrAX5ukyA!?h?vd_ z$sMBM`0P|AEpV;p6m&!L=+V1+GTE~tfa@^nMhi9as@~X;xDy!A8XyQ*l|6k*S7xdnRq~w~EgNY211CtlF4AQrLfCnLZ;zQf}Lp=jLivTYYXu zZbDJ}(T<{f0d2eh@yo2XWBVUFKhJ8Dw8VG3Xo-ItbiJUaU6|c=d-U0)%JQ7XfGRD) zhoXR%LOJd9AbM789RHcRZG?T>$$+f^6Me;{Ost@|@Oti5i+)$n%UgIU32Nwzxt3$L zvEUU>P{@>^yCERnl)kt)qz5Nr?E--gJ+dEr<;k&nbk+=kJ5AhP*ONteP>Qthf-Pzv-XP`! z;BPD=()K9J zJx^oJxvNW*DP3;8R%=sQ-3yoZdw+I3xX;bG)uaAI&zSKV$tI0i0g{)w?YoNvf=BT~ z=5OIW-`HLn;4iUntKi$Urkd1cNDM=`PI*3UEopUOcC8Q6YEA50FBCPW>8-h(w|;2B zu$K6Ms_gcfGI6?tzN=uuowSZ$!#eH-rdW2N#r%$R6Tyec9gq38f|%ST zcX=ax%uhb3o#x-x_CBtoT_dgC#IE(WUVD@Bsx@LGJdUiKq}Z{wZAUxa7bVR#SoQS& zqesiKmO1oZu|gyGo*5(OV4=>3qPF~vwg(Oe<(jk&>d3ygvGsMw7O%kLg-fRkTwBld ziW#3A^}gJ{J=^x7>Wx*?HfZW-B;!-J7qwZp*9N8~bwt{KxYw~dP0zosJs%HgCfn|T ztKAIV!n!T#YqXmXEiZcpVM8fB3yP5bJSfGUGDD1tg-;a&p7e~q z%*bg8I;fLLA3y(~Y2&_r(O|@H^R7-}Kfvn#6rYz4b#=3+2}OO+WxDjX{&CfL%P})O zAN9uvHy`MtHCCvTYj~rVB!XNN;W5(Et6%tedCPElb`x4^omIr)xl6q|Grw~3IuYmawm$PP`P{697Z?{>p8T@>jIOKp^h){R&tdK$9 z!QJWnh9+*ckr2} zG^)1DcN&17L~R+4+M-4aMII9J$V_n}7ynlJhI!hHA?!hHf@6WP5XXV zE(4>h#B90Ca}^pCYUN(ydIn&{4JP|gIl|Ao4&)Cci32qFBwIwoPxk;hj7aUt zav{r(HzF|Sgboi;adT4gg@(fXg_Sc`;LI5R)3Z}OnL3EIk3Wa!PqqooQQ^jo zK(fB@dh}US!~ou85NbMklU!bZLF^bR{UZeMIu|;Pv@M+JurkcZd&}N=TpfgwGLFmv z4wGTch>C9bkmstvo*{jc7)Z957epKd_)Cd<16L#UfNlV%yt11UJ=z)5G9pFmSyv*K z?qO{pDZ!IlKahW!(DzE#jh7W=CCEw@R(U=AT(L8jVd2twOh9ES2x8@pnR7W25pqB! zGtd}y#V5j>KP^A0tc$H&#NyBJpfF^(B)y;RSmvmop*+V@jEQFuMI( zJ|T7wizhdpP5~CWG+-gDU?4=a8!LdW?CXh#y)vvac)*-dTv38!NeD8Urd-UK6i)m> z!(Vl%&k;rJpUaV}wD`tDJ9FAAH-UjX77Z;&us+<3r>ZCy%GKffJe9K`f&RJ#(VQ~hzc&P%3-gOb2Tq4NzN;%XnH>b($X%9LpKd#GT~?|L>dANCMBhUD{ zNHrP`DNn#Qa-2w#oeyxMqRC}VB%c#cdetwM*g2(L9geF%29S)i|HKO7At&EK`f>qh zKs`d6RdT>LXA7^c$6Mgyzg`4~iG+)jLSpx>?w}a_TO6NGyhL)uQ(9JRffAiHjc#rD zQZ$J!E^U*{zPRs1Fe^iW1oAmQKMf z^5VoV>hSl^inxmH2g|UO9Zw(F2wN~IEbV+-SDLGFL5J+QQ7G%SNF76)o+t5I^+#8~ zeMDpNNZQhLcyLvYKfX9b1c<&1QE)JGjI=NMs?eiVGj#E*6|ErdVfmv>G41U2?aanah<9pn_HS~ z(1Dt(z25^Y4G1H?Ra%a4L7k+J-?n0fI*HSNKW70|kh|x*!`~1_WKkkOO(z7#cPiE) zJJw~0ELjuU_LU7n%P`Hn7mGV%%P{XbatBN=)R!kvC0wjUn} za~a9P(n9Qw`x^Dfl4M|`=>VXENjD0IIS+Hl^U1qu@<-L31uc$}^#Myy7wmi!$k#hl z)q6r}B1h6(5XdTO>DSV{V9?1nuh~aVs7osDkomZI*h=8A@}>z6E8qzt{u4TFIKu#@O zWx$*#aF!dtjg>_kPq)ZpV;ZSHiUlb_R30Y&U=?IAoEU=3gdy6+GA_n?f|78)O6NzaoHIoZc-k}kJQrB!Vr;+Y7a6>#4+af7di~NFLBiZICnwae z4tQwdv#w|L_P{~*em>WH+Aaj@r8Sni$l0dc)6F^?_?>>-UWiU`?hM+dvyT)*&-Kt> z&F=TjxI?O)sPbn?MP6!cxqYvz7D}+DAWhWkNr}>j<8~nywL(>h#D&aD zi?})gc%(X$1Wj>-65kdu@j*DDh}ZyrsA`8L5h%!16-G==#lb}>1RzAQqFb!EUghN2 zUVT3+%cI!0#k-?X?9-C=py64<#))kIwmX3=1@oeSlN7YmTu?>2jm%{Op$APF_FnU z{p=;PC#sA)l_r-cB9~QTvt>7A2c}`50>~qhYKk+-p^Dx`W0|2OPz9r(Btik-Yyu63 z&=1|I%_yK#*U6owwAeWWH7ZFia)>ATUO}un1=|HQi#)0Zo*#P5JE3U7$+0(YK4T3s zzqxVE;uLSgRTW|_JKy@YBA>jYv07rJFNSRpEi1`(l=3W3y8$HWcT22V{9O|VZ8jOm zUYSgAiKUkvBPTVi{mnKS&xM@e7r%(6BR-NJ5D2{V)AYKLCLST_N(7S?_MbQ`L>lOo z1UG=kh>vC^`9F7I&sWxQ8P_^p>6tp zi4@%Tr#P145T~NBwVo;tg<-hkfHr=c#qrdZ`*ZNS30nXZNDA;7Cz9a4#4@1oF%b55 zBPZt*XlOwI<3KV>`Jdp!3D!ZQKxA2IuvY>=jG;P!eO#1+dFX?b2jjpq30DayAkEDp zqQlGp#(F8LprLEZ9UOfot@(BTkksZ|RgM&rXvWh7WRBwFtd3;+aj@+pVvigCnxeK3 zkMA}4o5YtAyjVEeARx6hj)pxFf?u6}NdI^c*E}u>HM%B^Ywdqs(p)(gv74+MOa0q=kY2GBmB7 z$OB`FQp(I(E;8Oh|L<;h_0x65_ZwVZf=KNGk$C$?4-TSBA~A%Nc(rCExDA3bL7}-Z zm94ejr<{9E%VU0>GRF7J zdZD5Zja0gX5IaW4sszwGn-hiW-jB)4djt_c0EKHkEvL4ykGvHUXlIf`cI?xTF|{~6LQ~?b#I0}28^pjiGO^{@WjaqMQSCokrai29 zY$HdHdM3i)Eoly9NA&btQi!dC0_h~Nro2U4gg90tj0r-T#+u01Bo{V}*k-Mf*69kd12 zlZa{5`=_{`UWgFjB*%oL6D1aEpi)5hB+(Y16(yK!84p;ihQ&ELD&z$)2&1kcsrZ9X zflpBfvxgat0>Qaz7<*-(VJ2a_SW0Bfj3NsA0E*zGu&NQOoxsJ86ZgH)U zY9d}gBln--8+0`t42t1Lheg<~?{rR*Ahr(jku>iHm5UK;(q9#e<_f)Un7rO&W&8zJ zk2I>0<_#@`Iz2$@bdm|SgK0UaaP*Z(PdzP=6^O^oB#I$b;GS$_g#rPvW{}hCd07tX zl=UTO8z8Pa-+w*F^A2uWB2kO73zSgoOnnCeY zbM$B{a&=ChKBNwcK~Qm=^ov8{MgTKkj0KCJzFm~CCb?>wTu!hjiZ?yFKerwx9!9h; za?=E|+9(ghY8lA=J+kfw+LeUt$zumv}fbrINLcBSOp%gv2v4=xX~lc&Z2T{;ca zps{AYl-~;%q^}K8po$h1-A|c{^(ryo4G(adq<{B_Pe~>nNQg&^s>RlY# z?wJjb<4ro@n9&hYeV-+k5RkXPrGRWtbEYSlTWDL-M+(M{kU9YL@zU5hsN?*fH_Rjs z978G|Kebar4JYso3yQ@hO@WIz^(82i0NjXSzw*-EN5ho31~)WGj~uz;GCXMN3Wlp8vY48X3wnmF345?qC1h>D5gGzeBqa+T%*>I)xtd2_#$s|$ z5k*~fgKB8CFTnNkb0?K8L%RK?nH^l^vN9qn zQ5AhN4f%!?uVtio$>M=@eo!QFt~AMiBS86T&58Xige2w%z?NtuW~u%dl|g+D^BIpH z(3>=X9ZsJcmkM zM6EKzvkkg;9`oN8^U#ucI{yFWFhk*q<)A}_x;%>8$W+GfApJ-9`J4Pyx+%!`8H73F z@{V(zjPkXrFclF!kgVrj{}GtY;5g-R80S>iLC+^`1WE5`uh9TXOY~sAt1^C!P{;Zo zRsEE`gr|_n`Vc1;k*}5kqRD4FD+S5RW(4&!q`=A)rd`s64pvKXJV>1}a+E?ra1~^P zb5K=?7eI$kXo_MPO(D;Z+)I=Vim$fp6sRb^dQmYLTjV`;s7zFWUoK-YDgx;g<4y12VBE%YHceqKMaVpaK9Zr$I5F2Z}KfL?CAbk>o zzzuemK@LhsGV4~uiDUkmgn|ANWJfxNrtT~M@a*{(*p9?ccbhALu9ac5g267h7 z_FwB6*GLJWq=WJ-5oOZEI|vuRAkdpg2Ujkyc8ncN6-qvmAs1v!7Z3g~1Xma?P|YI* ze=BWwHJFAEDGth)C?h$D|?9>1V zDaTq@~IEnCBQQ2?3KBom=?-|Jxj^{R;q6Woy!zo z$bLu)f@j2lZ$sAYw~FsU@o7|tta$(y2C&mFMt|htrSx0)xV(ht^qfa691(fPNDjpj z{bCTPl-!6q&jC26v~(&}ZTOy)Y+zZ?6bcFIkUl6Cx`xuyqorE9DJ1wkELi>bpBQk? zw3E=KGUai3fJutJj+qKOt*u@Qy`J;pQzX@~LeDzZ`m9FjEPB|3ut zigY6xL*9DoL`M*8gvcn4=pEz#;qb#V?~S3S;oXonMDmUYQWE8aM7Tm^m2c}=x-8Az za<Eg&G(#Hbe7vM&8#>Mu zs86!aY9~uqE)wru1trRcM&Z9BnX4V;F7AV+Yq*r8jr*ShIUp+N9+#uHcQvKJ2Pt=W zBUUK`y5Hsj5lVd>8FJ$_ShJp;g0DndE~iv)%XQMJ>!<68%xTD4p4UmHM|Q`b?+So> z9DOv47G6>^!qh2t6V1X4Eea*7A40-E&|1MunT)|a4sd9e1y^D+dr6^5f|q{opC?;DJ~B;G%AJTX2JZABy@STFgL zKhWWKB6cGX1i*F`_3h97toE~1i7#TxE*<`2X*re}6$!u%HlGGuBn;`1fC5C(R;MFC zx5N<&4a@+3p_xJ?+!yd5K(~NRi!`0l2mV79;cv=mrb3Zu{lF)KBcpLo6+TG_Tr$qI z@#5>(%e82PF(Jt=htnV`Z)t-z^c3)Iv#|NqtrSL2G0wR@IM?$fMmG^_AWGn>u-F0(Nr(~S!KRc<5=i}8;{g;pYVC2V8JsnrW` zlSpFD8XknaNW5pCBskPLpVPPcAVDU3mV`JJPgd+~P^aQ)43$!DjPTYihowDDw-%L> z2|<(*Bg2ogrYt>3+ zM}b2A_<~|d`wtULY| zaQG{UA&dP<<7&5^)nKHu7q2R|aR_QE^e4TMA-N~>SZlJ`17#B0B#U`bN}q!|TSCFx z8$z0drQl%Z7Da2vNQ**xXdp1y*VWX+q?12Nx)sZ*&;|Z3Ki#r20%e7067j`x=N~b< zIHa_f+-u0%IMLXv+R{NZ{ZDi>m340R_&JMK81*w zs@3RRWa=ppTJjwr4)iOZ6K_D3V;Fz#S9@BOLKyi!=iNvtzgm<3F8J4VQh@zE;MF`3 z7=DsC8gCOK5FV`MFfvu((pWibmZakPgF!p4CIZvB&>|ZLx}||&Mzz$X81gUja84Y3 z&8~uuX7rCDC6T{+=fc{*Uny>>hB4G z0iOjv8VC$D)}$*SaE=1?#0Q~$*0huUFd*3P8D-D91bG7N1uRdCL87EIewg|L`S^Ck zt@d=TAcx-6QVldrB)EF4F9sXBz9C`H@lcLw?rEOJ_vCy3kC%ap~ za-&ai;sCZ$@_^>FV&0XT$Mg3t^FaB}p;?z_+g~DB4m5G|!yhT}mrN)?Ug_o%rg&Ic zf40T|-K2x%&8-~Vgwq|)T{9I?A@I*+x@C5`qAUISM-N3iPSF~47!AFfLgKF)61Pm* zN8<<+jNEosPTuwNp8Q=~h*m>XW3QBxe$3={5wQr20ll*ip#)PW`evc11Zf&gbJji3 z;R*r+g>L!n;=bk>)I0piuNsA?4k3qv63mE^5+&~MaE*Km%Uo>s5Z6(oJB5V^LhKRy z=bL-1BK83@JtE@C6a{(=fw5eJi=BiVob@m0IT>MTb{!S60Th&nv-`XQ;lJ#j-Kwgc z2Lj)I$u>-#q;BIUaBmR~E)#OZ|1BezLpjfugD7gKyVodB0+}?bdsrT{z&$cgz$JJB z4q)dB*NNj4@6I@@x&eH14+pG9dU?g9S%8r%!pi~AseWB(fQ=$rk(7nb7;lt7*q0J> zb9MLuPKDCOK9QhlV4E*^il+|Y!&vb5TZ&2hG`hQ~Sc$7YJm>AGIk0^~e<#sTnSBpt zf_QO8EsXy`kRR_=Gt#eRIAx>*(Qmo@FuAM*joPw#DZwm4Ys2yNQ8)#2+Jh(!8o+?l zdP|2O6y?Z2sn@PdNG;-oD+!P2#$&?fIu)ESoKrv&Xs4yjv>dTsqx^Cy8HxC}h$9t_ zTsVT4dsL8ZyvV#{ylpi((Ay~XM28NmAyFwvUPcdxuFAY&Lt5(=b*jdbn*9iK2-=CU7O9VdGLv`WgM3Zrs~Xty#l;d~*f zzvS)yK4WbnjmD)dnmgMP{6Gm)l}d3k^7uXpaMCwYb1uX){lnj5J^mR!;`+>k;~0_s zi1&b+vJm#4r5~5kqWol%O_`*^4P^}Wy=bARDsN*;(;$2HdiyqR*Q^Akv%YM&MI1ns zm^uLQw}Uka&5N{?MLpjKY6=4?U}Y$U@{OekjwoXBio&D_rjpp7T8^bDPn_OW+%YCK z!l7U1Ko9Xok?>W8KOVD8UeFrheG&BJjoAaqg6MGAFLL@s5f z@C^|z>T&X%m%?g9#D4V=L<%*TORVYDBvejQz7@NvzN(nUAnz?egw2>7t zau&2mI5$ly^WninO=nn#&AjT}T-;gdwoyghVjgUZt5mQnjIxJ9WkVwdjfMzHoz05| zY>yw)9i4C0>z{*k`oExz5G%pwW)ZXskh-E7p&PCQb^$shiL9J^#3nF`RBIx4Ui=<> zD(vY6wS|p(6o!GL4ZZCwHP5n!TSLsXMoWW018DYpY5$5`c3bplFpkC?E^ng1W{AV- zzMZxQqK?9?a$B_g{|eBl-wFx-vcgIr-NDSwYW!Vi-lv)qs!F+YphAAW=AmudAEb}$ zZiJH~M!4OD2WAMdk5-!f6k7s|dK2V}7KXw9{@+J-Q_myEVo(Tr6eYN#z}nyhg~K<5 zhc>2jL}*W!hC>=797|l=z>0?{i*in?xW$+ znci;gzeu%KVqw##hdL<>HlC@RXx#j+^%raX1MrDsUlD6yNyT@9*hb%KPRol(o|PcB z8>~y?w6vLPsnIDr9FQHx{w_(i1?uzOA^4x_QB@s+9z%p7%?HGJ8{)LOSd+Amr3L;T zLhau#y0RV-FWvBvFR8ACu!E2{nE#@#?x&WrX_p|^5W?;RfM%GEca!KO%&@oGXL2^p zz7at@n%*?=^#$1z;rzay6VmI`j0e$BGAMbZbZ}z~4L&5WD!2%i5+q1-aw91}4$S1A zm^;*a5w=1)FP*E~eKM@m?^QUsONLYX>p2Ss0JM06)GB$AOgzE@1c1bp@2uLStP(v$ zHudRcH=8$@4^I}39K3X7+=7rmRNT)^@K&_$6Sn{7A8`mU$3n)%%;-7h!(AHN7XS8S za_k;5NtTh0!HOZaMun-VfA}|TpQfqIkAzun0@t%((8g@ix?ya}U7!MIGNzkx(<7z70_II3qgDvje>q(Nzs!GU1Fj%GY2x%1eNmQ>PFG-r)#rK) zDdb&NOVsVE**QEd+nM=cVOjykk-v6gzJ6CNZ$@q56_@Sj(a|1Z1c&)P2V0>g#rsLN zAmK~f*nRktB-MVcjos^@AFU>}9raNl|CB1q1V52UFqu(ars-ftlBm%{Y5T8Ca`6tH zMpCJsxHn;C-35m_mApYG;9LwS*~hIvypp1^DekTewy7)o($`+{mWbj9mA3@eW>2-J zb^3sDZFOGNX=88iO*hl_Oq=Q5CmJ&nkSgM6p+SxcvLT6WRzv=M8c*YzsVB|^+MHQr zyuy+qtw?0_B&`o=8ZjC7w@9+zLS*R4swx$c7fuEuV7n{EgkSyTje3*sdI{1vQ-5!M zbNzWFNcTR(KN-Yo$X|TJJ1P0DrfgzT<_xA#Aei5fGk#@K9*<FPKi3LMof3- z>5;|;e!gCU!9SgO-?1wtzHiGZGExoILqQmu$0FR<$HqY^Mtu-5nSCXB&I!rY=(3o~ z&377Q=`}%(I8r-Z@-`S1{ih6hqQnDkpm(hP)uw=o2@ZJ;Da|LQ>uXB`iL4vIz^7Byk^kUg7Vty<%5DT z+s0Wxs5m=Kz-f5tGw3EQrO>!}BD_uVxToey#1`=#UgOX9A4e{bE9h3GFEA5L##f=Q zSbF&#VPHTJ^E+_1f8u(9F&>Y}hO`ybtZ&-^SXlAYrP}tt7*?aUC7jKKvHL&WGeAOW z-e-QkAnH|9Nf$;J#VYSuld23nyv|;Qbo?-XeH(Ir;I>@96)#%W##xXtG;oJ;F7{|! zxH_f|A(<3yOj#2@6N0JnDx={tB^bo<9!uBY%VaPEF-C-7^!ywM;hk1)v%hHu4fT`Q zT=W^^TMA*|p*%&zCScQ>^lu~?Wnu>%9EIaQ0hA~G>fhcO`!)}g>7C6qbo~i*s-Lc( z-h&tc$xNv`2FxO%lxX&%2AL=qbW$AUth80}>r1K5U-u%Pq}D9_=T79)Vq&9)wfw8Y zyO^L*fo*ZCBLOra)Y2N_vXSi>K=({V?>^K=YKjb_uio2Ppn=t-!twWbPRKQWjiri0 z*>Ht4lotV^qh}?C0Pa#I`X;0tc``aJHP;L?BkPN)JvE&~p|YE2555gGtUz3<|3v33 zK1Fr$Uj&gD@FEfs7h}Q{TL_>plYUVs$XtaAxBl^(H9Mt7CMC*3h&Ab7O?`6A=T&D^ zt!3mOaa1W&R@ctyNf=H3F$Kgk`maFaP(d$R)=jU>Un;v<*gN;6V49(O)_QPwP*pbv z3sxp5U47ygi|gVjvwCknPAA!K1V=r5=4cxz#~JiH>Q#Grl0%PmL_IOU3?PW`kWChU zeP9fK1GZ{ht$`7_2W9Az8h~KYyh<#Z>tTMT%=cr+pckw-*v(9>c|jzeo_w3x4;Gq= zf3a}D%`@(Lo7WTt-X=11Pu8Rm(As_LfUZ1g4kXQS?iT}2_@F|@#>M2kVRXl+RLQpvlVm$@LeN{Uf$&Nj>-$lxij_fl2kO+mD3`+{x zg+CKtgp#kp6d^V|QJVlJgJAsgFa>FYj=)^)UhT|qSXsa-qD8^(Pw4lbXn|claRiMY zNj7GD#D5Ro@i4SsbgFyq0%&l>JOLCn{bJD+%Ky^Y4}-E&m813!QDeJ>HnJ3KOj5W$ zgBYvGoB*MUq=Up#%O$aTP)N#*QTFv6krH{4?T&4 z8Z_>o=EF$JA%=O3P{f!z72WdD8Br{gJ20dxdyNQ2v>c#4Z^#D2plCi52WHs6+eb!y z5#Z=rFtTla0G>z?xcGlKj!K`yyC5>W3Mcj~>?CbS(Zdc3saAnwV6cW#lVuZDR*Kf6 zD7FRd?p&;Ziy2>U`Gb&2_M02Su_U$O$+icar;G2g1~r=aS@xDXlmNYeJH9mYDs6X1 zg6zM=Tg0X2Cji*6v<|y65MiA&Kx;MsK~cz#O>O z1H1MeR+`)U`WX?(J*6KREBv#dLAdT!{n#nKDIF(k-{Ar^*>(U*)Bt}ujT1Lrmb;=~ zit5P}`CQ_|`i$H|&c;U})5H(~U=fx3pFl3670QSXj86~?_?p4db(k21WnUY^)-5HuLo<=Uf9-t&c$uc=q>Ovd!Z!Tu}|}V(_R9FjCRg zQLvBL{jn^fYh{W-ZyAM$K=yR$G?udqDFX3-ld~Ljo?d9%Bq#HrC}Bulw!Hyw5B|!o zohVZCuvS2O0-ZmUFoQ}|W9hw{)z(GTVS=hur0w9B|Eb|5vLD%{1@01iS|GMjD1~$m zT`P+c+$9m} zt@N~4T*lcTb2xvy6gvYLlPrV#8Yu@22Eq(DgGQhB3dMO;%o5lp+fhLcB*0>d9XI{y z;`_DyiK(@cIk%aNt~Dj!(8Y!n3)flL$acama|zLQJHa(l79)BlRi?tv1Bj6^O$cY` zRFtV5GXKTs>X*m9q&o8$sZkgR=@CZF-**Hw2jNBiX(P#>6Bo1ejH|u9Z{y(wJ9wBq zCdN^Ds*D%n>O3e4F8i&Zo1oL|^p;@M@-DBp%w2-rQj3M6_mmQjZ^QA__=kKZf5p3D z#{#~qqcC=9V_0KN+_|TNFMV$&ouZW$B3*gF_wM9c(6wGE96!n9H8Y;g7haB7_^ z>in?%J;IrqU-YXfZk<4OZpzeE)T(`)dj1+xT)&_-0DSd}wiQwvN617v8lbgt^4-x_ zPq%tw_5^IQ`^N+a+XX~F$wVO07H~GH0c}dk>`T-GZF)`%YG#hq3QRcQ zi~F8*t)0Li{Ks)F3UdXnEo0=!BqbPFj)H8KbHJ}e(ULVt*cJfa4Q97se)(q-SdRpE znr^W5UnDN8IY@GL!JQ*qU_S8Gl5pcVn!cRDJWFuopJJ|&HcpgK2j?FVd?M4M2FQS8 zv1o&I%8;NQ*_uI_nMStOwP5vsw@*ZjxUIN__lH&r1Jt{y2_QrfHhRGrfqS@QQw~D~ z>amjVPK~e*Iw>{j$#ijQ)&Wh^JVUak5RhB_LWoH%D7)_F5NZtwAr?@2Kmz=LDPW!@ z^9#$EiA;%=&{*xKF-Ml>KC)cEA7)T(uubOwLI{{oy)FQZy=2iRm#4(_+-u$Pe$tc? zHcelEUNq|}y+2;4bZ-{5_+#i`U!B26d_HPF(mLq>m3QR3Z1I3_DQliL2}QxyKpXEYKE z(P6|P-nD8xbf5t+VSYlQ6^cv*nt2fD0!>ojJs%$hJi=*x*JN6n4IT$|H9W_SVD|&l z#$xUqc8VQrYp`SMvIJfjHic~pZy1*de`g+KO&G#r1xcBnhe<$xeI8T; ztT5(n6({wmX2U0^;@y8ZI>cls4^G{uvpd8_OE~c3$wfQ`d|u3YKc3MFp2-Y;8lpwksgatHh zZkx+pBxYP(_552wyv0>8fiGsy+VDLxi)Yza(|Oin_cPZUbhvOBM8`sOA+gTW2#@4e z#zBR`-vu`($!4WSR4K!WY+`8n8apgky^uMdqED@0Gc^DsKE;e|CHT-t*{c|93L+75L*QR54cC(mb58IuRo~;nQ|S+ z#@r4lSwngs@*rjNHZ$x*LbD21zWGN!gWu+YtO%Ya3GjuRy2|PnNNV3Ch zoqh8??91k*`XLtT6b21~kNHn=?c(=~q!?=?Ih;G?P^lQ<`8`}T0Fb5-ZPPwZqUNPY zbqr^X()IZFUMLw0HOf{$z4>yFmss4ied2rM459~89>!PTwZ-vT0{UkkfQD9*V=0C5 z0m;)vh}2cABrIDzm@F(q{3Gn54eTJN(QK^)a_^LggKU!pVpQc`;YHGb3XuQTm+k%> z`H07sL-3(v-4eZXuzw~VN&qED-ufiWxWg<8hK2Sv=P<)+7odg^g~@&G_k2(t z|G2#p6K${k@{tk+)*-4NLLd^Md6YAKrn=}8mfH_p@OL}Vz_D0;WMh-u=HJ!sr*Q5S z+J=9!SssERao=U6y#ePyS(32n71V6bxco~4>*Y$ zU3HSmhPaD6QeF)7@DLxiT*UJw?a2t45eG-xe9m@&=K`SvrdhF|6=h0#B&UHMW6?~Q zr1_qTl58wN8fiF?ZS&Yn^xsZeLAiZdoI1^QpN;j$&`wD44mnZ9oYdXz?RP|b(iD;C z$RyOXsy=cw;}}?ZJH1Sli|k-9rdNFcA%H6F{83efORobIn4>jSGeT`c9r!LtX?4Q0CIwP@2aV1=gQ%ye*!WVZCD# zY)*1%Z}65XLD@hCOH5zP1=Zj$$o<(vO{a!~C;nTuPflS0%xHJNL$rHFs!#77BN7Tr z+7&3o)h>Tz9LCi9h561}!t+;3o4cVwpQ!TL4eM)r23I_Iy231J ziF35M^R0VvvHm8!?@z_fyYlK{#jzio`nS{dr#ob`$jg`w6)KB54P!Th_;=%?%Ukkk$*F<@jWrrfU}e&DVuJ6Ds8~w zFW)6E?`Wo6qBpF5QY^s^(5cL0le(rfE-ure-}}2K57?e&N2&WW63P^$m%fws%E5f$ zVD{I^@e@&qgyR?!=*%DP;#yLr%n{CBkKKq#>ItI_Na z9>$xxybtE(=lIfXoJH|$P^X>D;4tkMH6CgEB+@j>3Ko(1G5Po((E^4Z(w<82B#iAWg&FRm&!m=77|7=!rVZ2 zs4z#9Ex_|+3-Gds7vNQo$elZbm?pNQtg$~eT)x)D`f@&Hm&>reoav#GusJpUMBUkW zTeoU=udOC~h!I&p;cbN!q_(QaBE84GQSPB{WP6g870VBDV7Y$Bq?DY+JTP)YqaRJ~4PRQfMB0a`C4+ zD9EB79odB2+RyU5BRB*I*_9g}P$UeQUfbHA@wfp~YeZvFD&q|fmVQ@IW? zt_NFlx2{)r>MRMi5NG!DGNZCpX1grIa}2iv%iH{jbM%9WbMej65jvi9=Zj5m7MvT5 zED^6}`^HK|X6*;XgZ~VCflz#X;7a#kNRwDcSlpfXk{^@u$rz0fC>CIe%nU0?y84g- zR(VNk**w5G94#Fq=o;P+fk&A7Ay)iMKZGCVWv5$s{wb4=JU^TsM4fqFm$EC7d08!k zQjVqWD{(pfC5PXEf!#TL;R zR3G;XrzPMjdE!ic@I+9!hc11~KNBRpgo1?i?tW-< zHmGR7O|dy-q!b`+wOA_5g#2@O`QbLM{P0s&epo|Q5X8yD`^v`Rgj@(pQVs;2PHK7c zT<66j0^cstc7a>h)#ZlK+RsGI!sJ;zWl0o2@U}(&_8benL0#YP2CL0_b9x4n&W=14 zWv|V(%}s%c$0_QDjH8bq&5!%U$MdDf9F>UCCJYA8%Z00)6VhNW=sT$kvbL4rIgYZ8 zkTmdY8EW96gBDGCvt3bEiqz@;lFT-cd>M?$jr0$2VBkrk}Ht9 zZfA8dpi5}9E%e^p>d7ReXe?qHP>Ovj-aEWJVjD7CrCo`*SWy!QQdq{2OqXLwT;~n* zjZK!13t*27q2MT6ltjIPoo81iMvFOu@0+9Y59w}wr*!<2?p+az*M;JnmnWsEec%=o zl`?8weGczlkkRL#<{wY{G4x1&<&N%_YTYJb0>%?lGqK;M%xRX3wyaVf@#>1Voo!TD zHyHLGBR&2)b(-X{-+Xtc$PR0eEaa4faY04xvR_O0E54T*r_1y)%d-wQgj)791CJ|p?($YUHn&A1X zy!X8~n)dZt38&e8K$*yWz|*qX+WhFh5@VVjxhvKsl1uG2 zW}yqzu$p3I{wU5_g~}78yiDRUdWQ3Y8cH3-TfMT~y%kRuBYqKkhUcVnY0#cokFZtM zGISbfFV%9+^s8O952rY;P`vnUyq9B9f)jKQ3Rd;SPX$YCA(b zJ>1kGXS&0DhK zHM+EN2_BM#P<@ZOcN(3fVrJr#ZtQ<78gE1a{|%C`G$@V!3qVLSFEy~4zM?lu(* z{Cb@W3r;o+8k+Ccc-5L(I+oQa;NaiHv>4QRrZI;)`slJ{DIR!LP>F_FboJuq@zQV$ zSzGO=CX!ftEFMNW!`f=Y9(L|>B0*X46Ck4Dr9CNogXABMV~1>b(%Q$j;NB+lskFrG zQG+T!zU^U64NkNuc-0eLCh-xY?%H#eB0BeK25!=@Hr8!i@G7!sC2kC5Ne-6FcyeF- zMUqs8uuNlWsy!QIM49SAtf>}vt}HnDd8}EZ(7HqHG|MM*eJBr}#tFJWY0*TU9_xNI z`GV3HnOehy6W4&+9<_s>;ct0X%s(b+>Cq5i>6jv6p@MAkl#7FG8Yv~2rqHL1CMF*G z;%2$fvu0AP+fGqU%~+@O`UuT}jMmy5XQBAUs(Qa|1NXyioDB!-!b?{LbX{w@9Gq$5 zSK{}McUx|OxT+%hxLId~etv+b&;9M<*0Vj)VSxkX$*$Xb6%JWw*j}t?yHPrRmH+mx zrZK_wdI6P=ncbI4FKP(u3vdZ2+s>~HC~4xY3UKb?)jOUDblhOlQ=xBecByZ?C|{_* z%~OqU-g+{uFr%kgzu<&l^~H|D{@c~g0qq+sj;4!uY^*MNIxB6kShHaAK$%r?^gw%0 zX93lW?0mwntuVqn;GM4RtHhhS zdJN4?{Bnxszm}!5qalC0UrEy^{D6*DQJrQ-;Xrpure~KC@;6olrK}p>nfX_)GZWL; zV>>gaQiI5uuP}_^R)8k<=Wc}}73%yj&MGSn=k`6U#PHNS78Ax9E1yndOzAXuaHbN4 zsYOj~7$GF+2bZ$SxozENOJ4ytKAk$F5MeNN-nltJI2KC3b_{s%T{7QSd)e(Bo** z9+#5Cu!j_nN7kgLbyH0`OXnwkttppVI_UydXq4L&tpSXD%NrwYPvS;3S-}~cgS4*T zw8Pc=3^~1Aq!TKI*c%{BbvJ?G2uh%|lT%j}ito6^nwqy8?p)Y=IV>>1A*;9EuO&Kc zpiUHc%&fb$q%Jwk?G>Ls4I2mV#-=Z#Q@3|r>oCj@JO9~>AwgTV%~2?sX3oj8`c zb?$L6$G^L zwCZvec18u7s`3vhN4$AD{fPhe$OB&ap)Dato>WROhJAHdx4{s`^pkD_OBA=Wm-Gz~ z|9DC100)hPX>KYp#8|;4rBk?)p}jyuq_r|DTA_b1)E$v{KsuOzif0+GD z()!nI9L1F{`pmlTwh=U}Ss*I6==acYEU9=m=j&9@9k+s0W`I z=*-(W@7pz(vn#!dIy<&};C0(igMU(?@uX#DKtcD>Qk&wN7JWti{h~@=O@~PDdlQm% zHCo=+>-c7Qrnh2aUf9CR1M%Pg8?(d(e1MDSRK<;pP9kb0hhvZwn)tgf%bG|SgQ`9P zx2|l%zqN~SLg2y}9H)gK0uDE*wCSFkGi4nE#prWf9+d7u7FVUHXxM?#1<{ zAwEXC2I9R7!p>{IYPs2_aPpqJypB>E(Vq5XOP^;^e*Kwk_Uq4&wAJtF_RqOmIC2(N z@f<;Gq{Z>M@BCwPjbm@__;LLG89v>;{bgZhzBo#*X-z&BhRf3Y`1>|F3VFS^oHG~X z%zXdznxM`P3`;*cZ&ROq1QAI-*{{beKBuG5*kyWO(IHeZuEXozgbu&AN@oAC;kLj( zE2g|9RdnC)pCmwsqL3`cYP5kuAP+lLT2w0Eq>h01hbc) z_d9kZeL^dHl5VYJ9h=CC%P@c6kX098dVy zVB9ghHz}b8PEZXC@sy2_-%%Vhp~7;W*r}W+)(UobDIU@zIeny3=gGiZpEi0HnifPk z!I~joRADrZ&KDeAQd6ulbxHkaSIr$RuLCMR+HAii>p^yO|E3J>zIgpq-Diwc688g> zpS&{U881Q2)1CbxnUP`Xow>SzIS*~!FwlEiSg4p+E~wD?xS@0X+7YuZSxk0XpY4&8 z*x6%Qtpe=VV zsyU^%B!uOk=r0!4ubRD4P}jCFE2%{=3U+OZk%&13Ocvb`xSVGwIfNsT13RP>M4%M= z$CN}s_5f9)@$?H0o72VO$z-lz>KSjt1@7VWrfNJmxT&MMAVG}@5#Sr%2Gkv=hC8|W^55x6}h4x>;jX(Y2ge5)gXm`q_lw)HZizU^c@LLxryTJ)p?7G z?xd!CxVj#PjKSPV#vAnKd~`nj3%9pF&;K^<&an-Db<*DY!%=sgl@Mnu7T@rNheWBk z#qn?Zra1ZLsZPyG3N3JN%J*_mub4pfOX45w96P}Y2n{+~! zKIP>jP>PH3>AaekaNMlR)9<~i#*)NPQKtBd=mPV;4}$UTxp@_}mU##;iZG(23RKEN z6_EcXaEUkM4j2op&(H0pZ4h4+$lnpbTTuNWDHKA8-)I2S0=qF1bR1tUMfjD?&MJG3 zqkI8B63XiUI)QP6?EKfsvfIZCfxN&xG+sBc>AStgTXjDUynorUZh5`ib2r+|5^>F` zk4tp35>20*c&MPSW6x)0camOeT!3c3k+Z(RwR0rhwdNmKk6uWNo z6kMEC*^>Oju2vJL(!)=?H&sQIY$|=mZc*%Lcp)<@Ei8l?JOgdP{W{HSfh+mjivzAq zn(p^ogPdH*GjUzNI!3u+AJ13ZW7sR@O1aDNhcrc3pV8G(-on1J9~yTU?P|`~Ur>Kr z@ymeTkovmK7v3;E-*C=5qi-I^aFf@ikvhInLYOyWF+p ze5s?cm&Y$(X%|4fLL4lKRX}SyR~cicJG>FZ6^lW0(-g+d_yX;x8lhrsDk#M8K^QNm z4rdQvEkz4PDIxw|n*QloRW#jcf|M{5*iEMWV48|#k^l5N<+#Pibq*`d+K^!!z1Z_g zCqHy-A|~-yoC{N0UaYz`)zQzz+zZ1vK#Yok1ATQldj?`!qDRIB>j%E8VH;-A=3WIQ z|uBQh>;IB6MuJWPGnUpDUJeUWg?zvm6V(bc?UHhiOpN+>?vbJR?4Hg3MyDTL_OW=>sZI%?Uk6FIU|7C}y$1>5XH<>FYIJnw2h?-l(sZS;D zpQcvXpP~6$R?^vNWg=bknhh@mdg~+}`nYLThu`^ef}}s#wT23^@g#&*#}}|4x8<6k zlu=fjtEq`T<=!Q7qm?JvbWBA(A|8H zm)&8}-qyEudtk|m4zu%>eV1|X5B4N?l(@}pRpjrV?Asq{8JUv#?mXRwv`F*W!qt^s zC(_!wH1j9-G+1?%sI6!c+aOtVZj{^Y)wMT8fxcd~DHjVeLk8YXj&ZyFaYJ>^iG`}M zm>&jvDhu;-++PtDnze?PT9;H93%{z^dZF}tf&So+_0A{X9-BDpQnA9Tn&$mQCHFgu z=9X(U?$3_Ck{#y1Im5Sad!YDisrtoAZKdKVtE2eAlTD8)c3sF@cmNiAM6HbKx8G0$nBq31|lwD`oTJzEdi+BgRGZDkn-a)nmV*F2`s>X%g% z7%`cHz*^!U09QqJ`WOMto{w-uLI1#BQhZx18T`$lloee5k1J}jW6x;_?36jdRxyQW z8)3xNNqe69j4!;CMRN%;IPEVk^%NWl6y=m!TC{zZ+-I-729!!?3sB9?#p$w_};h1uGW6nes_;i&#mlCcx3<6TncFk#vRZ4W5JK)&gFmmJe ze;9j-zR$U67~1^D5=JLXpy%OuU(psBU5+}n5X17Sf%8}Q+Ge52j32NX5_@Rfq? zD;I?To=Y-%DoW=Trq2_xB z;K2jK`sD8_y=psm#-(+%257JKuUEBrO}Y58X+qT0h>FG|0Ufzb^@aVr<1wiqb^C32 zs&uKk+A8Z9mCtasuVw%eIAH)~WFo=>X%3@_dm!yciXxevhQ!P?-50zdp?N;Z#li)H z&8l?16jOU`muIxV$0#Iy>Cn~xMO9H z?R;$PncAA7O@JXReADuPC3yFQd4*BSgRB-nE2+5if`(g`J&#xU#{^n zGHLSTYVdsjEEo0DPzJ~`nv&F6a*Lo-kCm&lcTv@ZKHwAtUjertK?SL6$4dK70I*Yy zIX*=w5;(F7DmpCFKO@1j-$PXZA2Ks7QQcdxa$^9rPqodC(h$$nW{g?VNB68@EVKkKs9y9h_ez?+lEG8hBSRlc| zAFBEh)n#Mzkr1si-3{hW^GEgLjFaTYFT+Q~>Vahjv&m@6<+!M!u#z9}XOgCs#1@}mm}aQ>r?1S&8#y5WXUAcri|K(IYlYowe- zwnn1%W^jex-BC6WOq2eP6|qa#VFkuU8zUKrWr&R@593G2$o>)(49LXp_Uzv-q zAc^?RTJp_v$z^&z(C8qwwSP=bH)`T?Rf1m%;W18qZ*bX6WI=YlW^?1;wG#4WOR zE-TiAE!WQF57!znOl0wq4UrJq5Il4Yi^mOzu1yp%f0^V-|Lb#jj&Zq;<{rx5jd-DT z!@=GM=aV$MTuuk=9_0D?)QvbaaYJxvly*uGeh_eYj)22bG)N&5M8ReS`AWeTAt4X^ z&uX$;>Vyt!Y_LRTJyTl(USP^@F5*chc7#EQNpfW!HD!w!5zNwJK?JYJA<`*`l5jnf zd{Rh%+%ST4G*De#Fm27%36>VXyO@#pSf+~MUO;B|T7wBEB8c}czTFQf`c85uqKWm7 zC3+xQBCCk5M@(Tu@#6~wpkwhM?WF`!v<_xL3%4H`&u|2t<)!K&8Wh`CjN5^!4Z~G_FZBHbQu#1{a;ygu(ktMc4 zzE>ucdSy(m(`~`S@%smpY$4tCbN0nTt;8u8m+Xo?$jRJ@iCenG)M+1bAW00rWW^Jx zwC2m=paA7Rs^eJe)oeKk}BXQc_MzqkDLH$;X}bfgqFaRX(YNlHIZ=`N{<0Uu7X z#>J^+ufh^w{|}sR7}&pZ3*v>6XJES13hIwS8wQmABepp{kWLu8k%hy7~O%7kC%SWk1cn> zafRMx$*W94Rt)-*@GbnnoQqTo-hQr$nXIF7H2$wD)NdmLiV|;aC%)oX3Ld7(`}bDr z|F(n|Ng(6axEue^EMF8Oi$&&-J^27BGWZ`oeV{>~z>fDv$JLVkGEP~Kj_@+%2LH12 z5;M9P;RfT7%X9l1| z^LUh&CQ#M^T}*5;X0t89QfoPJI3oVR2-rJ^h16;>K{kd}4kJiNYjw$1kh4*;SvW<7kp>)i z!hu`ROU{KZMRto0ePCq@jf*T(u`%MErNX@(Mqf!`vOlKsoW7j3^*n8gkK^m_}nezs-mwIib~SaGgHwROenw{DHvS||A7$* zXBYQ}QvczhNJ$Q1=4t?)?aZp?yo>9%CG8s*tARgFF#*6MgzlqlUywP@!LptWf*S;Y z5e1&XG)X_!=O&JkSW<8yFSN$LQT)HMb*&7I8B3@dxAIfnfdartRaj%lEc%VX3L0uO*9M2>QyyX|H^iM9{9TdpL0d z%qc8qP)bDLErV9em7WH2i~ad`t_4PC@|Cz8h*-?%u1NpFsfLpfTR3iz>KS_hlt@z< zrJvTK3CsX6yrS3&+c!hWfp3*a{Qs0SFhh~hEqG=kfk=QlQlRv66hM$^F`Sc`K`+j5 zdCVj5TN3Q6qC^wCR5|8iLWeHUbX7n!qJS*5nxUZNA%1}#!PC^N6gKt!p7OPd2E8mF(F*u`hV35PpLFQkW zhb3AT8J>}_kzzC8C(@xq{m;5^ot_hq3cW|BNDzhacS%P&2Ivi)_J|xsXk|$? z1Qn?yQh0-`|845p815Dvi6c>#3=33X-Z&sg9B9iT03dvTuoJPD(1)|o1v*9_?h!F$ z}bWu8%z z$I3hqTrvf-Dvyy=0Y{(;_!FF*aJW5z6AbgP4u*INzhJi>X58OFlLxjU-hxb?lFaIw zhcc@br*3rDL2Zq+*y!K%4gUumVk6k11L$buvx*o9B+&G*AjIdg#(@B4E=kT|PotiE zlqBOeK#h=KLDykDe(BfQGGX5E07nQNxx zaz~iC87ca5x>WqxaziTtdVh7Wzb;J(^8&yx#~A}d!Uc=lTV?pO? z$8%D%pN7}``HmfkREu>XY_*$hxS_;q-$ckYoHVcO5 zB`ac-$qNp?1YaN{I!7>I5vy&N)w6CJ6%6kQ%Am$A z{9RBo@~vwSd78?t*7tm%H-NMgSm4TuXsU;VEQ-VzqoA#4-?!{FjK^jScvT{$kX-*X z-g0EmlSV1zup%%I0Q(>D06KN%LPiiVs$8>jC`Hw>xt{ZvLkp7fHri*nk#EhPMdP#l znOk#kxS$X0Po(O3VxQfa@&7F$Fuy&tjNi5sGNu2OX=jl^xmYvq-Mmk8VrL&vz+bN| MUioUm%TDk8A92*7;s5{u literal 0 HcmV?d00001 diff --git a/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/icon.png b/src/main/resources/net/runelite/client/plugins/microbot/smithingplus/docs/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..cf28d14cc9027fd3bc041158c5e9a4d17c28fb29 GIT binary patch literal 35543 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