From 24224a450b8fb175fe5c964a408c5a5efe10ab00 Mon Sep 17 00:00:00 2001 From: yueh Date: Tue, 22 Sep 2015 00:24:40 +0200 Subject: [PATCH] Added an option to toggle oredict subsitutions for patterns. It adds a backward compatibility to convert current patterns to use oredict by default, which should be removed with rv4 stable. Closes #1156 --- .../appeng/api/config/ItemSubstitution.java | 30 ++++++ .../gui/implementations/GuiPatternTerm.java | 66 ++++++++---- .../client/gui/widgets/GuiImgButton.java | 4 +- .../implementations/ContainerPatternTerm.java | 35 +++++-- .../core/localization/ButtonToolTips.java | 2 +- .../appeng/core/localization/GuiText.java | 15 ++- .../core/sync/packets/PacketValueConfig.java | 8 +- .../appeng/crafting/CraftingTreeNode.java | 50 +++++++-- .../java/appeng/helpers/PatternHelper.java | 97 ++++++++++-------- .../appeng/items/misc/ItemEncodedPattern.java | 6 ++ .../parts/reporting/PartPatternTerminal.java | 14 +++ .../appliedenergistics2/lang/en_US.lang | 6 +- .../textures/guis/states.png | Bin 12259 -> 12358 bytes 13 files changed, 248 insertions(+), 85 deletions(-) create mode 100644 src/api/java/appeng/api/config/ItemSubstitution.java diff --git a/src/api/java/appeng/api/config/ItemSubstitution.java b/src/api/java/appeng/api/config/ItemSubstitution.java new file mode 100644 index 00000000..330dba7d --- /dev/null +++ b/src/api/java/appeng/api/config/ItemSubstitution.java @@ -0,0 +1,30 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 AlgorithmX2 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package appeng.api.config; + + +public enum ItemSubstitution +{ + ENABLED, DISABLED; +} diff --git a/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java b/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java index db16bdfe..0efc688d 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java +++ b/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java @@ -27,6 +27,7 @@ import net.minecraft.init.Blocks; import net.minecraft.item.ItemStack; import appeng.api.config.ActionItems; +import appeng.api.config.ItemSubstitution; import appeng.api.config.Settings; import appeng.api.storage.ITerminalHost; import appeng.client.gui.widgets.GuiImgButton; @@ -41,13 +42,20 @@ import appeng.core.sync.packets.PacketValueConfig; public class GuiPatternTerm extends GuiMEMonitorable { - final ContainerPatternTerm container; + private static final String SUBSITUTION_DISABLE = "0"; + private static final String SUBSITUTION_ENABLE = "1"; - GuiTabButton tabCraftButton; - GuiTabButton tabProcessButton; - // GuiImgButton substitutionsBtn; - GuiImgButton encodeBtn; - GuiImgButton clearBtn; + private static final String CRAFTMODE_CRFTING = "1"; + private static final String CRAFTMODE_PROCESSING = "0"; + + private final ContainerPatternTerm container; + + private GuiTabButton tabCraftButton; + private GuiTabButton tabProcessButton; + private GuiImgButton substitutionsEnabledBtn; + private GuiImgButton substitutionsDisabledBtn; + private GuiImgButton encodeBtn; + private GuiImgButton clearBtn; public GuiPatternTerm( final InventoryPlayer inventoryPlayer, final ITerminalHost te ) { @@ -66,7 +74,7 @@ public class GuiPatternTerm extends GuiMEMonitorable if( this.tabCraftButton == btn || this.tabProcessButton == btn ) { - NetworkHandler.instance.sendToServer( new PacketValueConfig( "PatternTerminal.CraftMode", this.tabProcessButton == btn ? "1" : "0" ) ); + NetworkHandler.instance.sendToServer( new PacketValueConfig( "PatternTerminal.CraftMode", this.tabProcessButton == btn ? CRAFTMODE_CRFTING : CRAFTMODE_PROCESSING ) ); } if( this.encodeBtn == btn ) @@ -78,34 +86,43 @@ public class GuiPatternTerm extends GuiMEMonitorable { NetworkHandler.instance.sendToServer( new PacketValueConfig( "PatternTerminal.Clear", "1" ) ); } + + if( this.substitutionsEnabledBtn == btn || this.substitutionsDisabledBtn == btn ) + { + NetworkHandler.instance.sendToServer( new PacketValueConfig( "PatternTerminal.Substitute", this.substitutionsEnabledBtn == btn ? SUBSITUTION_DISABLE : SUBSITUTION_ENABLE ) ); + } } catch( final IOException e ) { // TODO Auto-generated catch block e.printStackTrace(); } - - // if ( substitutionsBtn == btn ) - // { - - // } } @Override public void initGui() { super.initGui(); - this.buttonList.add( this.tabCraftButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.crafting_table ), GuiText.CraftingPattern.getLocal(), itemRender ) ); - this.buttonList.add( this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.furnace ), GuiText.ProcessingPattern.getLocal(), itemRender ) ); + this.tabCraftButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.crafting_table ), GuiText.CraftingPattern.getLocal(), itemRender ); + this.buttonList.add( this.tabCraftButton ); - // buttonList.add( substitutionsBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, - // Settings.ACTIONS, ActionItems.SUBSTITUTION ) ); - // substitutionsBtn.halfSize = true; + this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.furnace ), GuiText.ProcessingPattern.getLocal(), itemRender ); + this.buttonList.add( this.tabProcessButton ); - this.buttonList.add( this.clearBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 163, Settings.ACTIONS, ActionItems.CLOSE ) ); + this.substitutionsEnabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.ENABLED ); + this.substitutionsEnabledBtn.halfSize = true; + this.buttonList.add( this.substitutionsEnabledBtn ); + + this.substitutionsDisabledBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, Settings.ACTIONS, ItemSubstitution.DISABLED ); + this.substitutionsDisabledBtn.halfSize = true; + this.buttonList.add( this.substitutionsDisabledBtn ); + + this.clearBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 163, Settings.ACTIONS, ActionItems.CLOSE ); this.clearBtn.halfSize = true; + this.buttonList.add( this.clearBtn ); - this.buttonList.add( this.encodeBtn = new GuiImgButton( this.guiLeft + 147, this.guiTop + this.ySize - 142, Settings.ACTIONS, ActionItems.ENCODE ) ); + this.encodeBtn = new GuiImgButton( this.guiLeft + 147, this.guiTop + this.ySize - 142, Settings.ACTIONS, ActionItems.ENCODE ); + this.buttonList.add( this.encodeBtn ); } @Override @@ -122,6 +139,17 @@ public class GuiPatternTerm extends GuiMEMonitorable this.tabProcessButton.visible = false; } + if( this.container.substitute ) + { + this.substitutionsEnabledBtn.visible = true; + this.substitutionsDisabledBtn.visible = false; + } + else + { + this.substitutionsEnabledBtn.visible = false; + this.substitutionsDisabledBtn.visible = true; + } + super.drawFG( offsetX, offsetY, mouseX, mouseY ); this.fontRendererObj.drawString( GuiText.PatternTerminal.getLocal(), 8, this.ySize - 96 + 2 - this.reservedSpace, 4210752 ); } diff --git a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java index 45e9bd3d..529c3142 100644 --- a/src/main/java/appeng/client/gui/widgets/GuiImgButton.java +++ b/src/main/java/appeng/client/gui/widgets/GuiImgButton.java @@ -34,6 +34,7 @@ import appeng.api.config.ActionItems; import appeng.api.config.CondenserOutput; import appeng.api.config.FullnessMode; import appeng.api.config.FuzzyMode; +import appeng.api.config.ItemSubstitution; import appeng.api.config.LevelType; import appeng.api.config.OperationMode; import appeng.api.config.PowerUnits; @@ -129,7 +130,8 @@ public class GuiImgButton extends GuiButton implements ITooltip this.registerApp( 6, Settings.ACTIONS, ActionItems.STASH, ButtonToolTips.Stash, ButtonToolTips.StashDesc ); this.registerApp( 8, Settings.ACTIONS, ActionItems.ENCODE, ButtonToolTips.Encode, ButtonToolTips.EncodeDescription ); - this.registerApp( 4 + 3 * 16, Settings.ACTIONS, ActionItems.SUBSTITUTION, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDesc ); + this.registerApp( 4 + 3 * 16, Settings.ACTIONS, ItemSubstitution.ENABLED, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDescEnabled ); + this.registerApp( 7 + 3 * 16, Settings.ACTIONS, ItemSubstitution.DISABLED, ButtonToolTips.Substitutions, ButtonToolTips.SubstitutionsDescDisabled ); this.registerApp( 16, Settings.VIEW_MODE, ViewItems.STORED, ButtonToolTips.View, ButtonToolTips.StoredItems ); this.registerApp( 18, Settings.VIEW_MODE, ViewItems.ALL, ButtonToolTips.View, ButtonToolTips.StoredCraftable ); diff --git a/src/main/java/appeng/container/implementations/ContainerPatternTerm.java b/src/main/java/appeng/container/implementations/ContainerPatternTerm.java index 07ceda66..fd56633c 100644 --- a/src/main/java/appeng/container/implementations/ContainerPatternTerm.java +++ b/src/main/java/appeng/container/implementations/ContainerPatternTerm.java @@ -71,15 +71,17 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA { public final PartPatternTerminal ct; - final AppEngInternalInventory cOut = new AppEngInternalInventory( null, 1 ); - final IInventory crafting; - final SlotFakeCraftingMatrix[] craftingSlots = new SlotFakeCraftingMatrix[9]; - final OptionalSlotFake[] outputSlots = new OptionalSlotFake[3]; - final SlotPatternTerm craftSlot; - final SlotRestrictedInput patternSlotIN; - final SlotRestrictedInput patternSlotOUT; + private final AppEngInternalInventory cOut = new AppEngInternalInventory( null, 1 ); + private final IInventory crafting; + private final SlotFakeCraftingMatrix[] craftingSlots = new SlotFakeCraftingMatrix[9]; + private final OptionalSlotFake[] outputSlots = new OptionalSlotFake[3]; + private final SlotPatternTerm craftSlot; + private final SlotRestrictedInput patternSlotIN; + private final SlotRestrictedInput patternSlotOUT; @GuiSync( 97 ) public boolean craftingMode = true; + @GuiSync( 96 ) + public boolean substitute = false; public ContainerPatternTerm( final InventoryPlayer ip, final ITerminalHost monitorable ) { @@ -88,6 +90,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA final IInventory patternInv = this.ct.getInventoryByName( "pattern" ); final IInventory output = this.ct.getInventoryByName( "output" ); + this.crafting = this.ct.getInventoryByName( "crafting" ); for( int y = 0; y < 3; y++ ) @@ -156,6 +159,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA public ItemStack getAndUpdateOutput() { final InventoryCrafting ic = new InventoryCrafting( this, 3, 3 ); + for( int x = 0; x < ic.getSizeInventory(); x++ ) { ic.setInventorySlotContents( x, this.crafting.getStackInSlot( x ) ); @@ -238,6 +242,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA encodedValue.setTag( "in", tagIn ); encodedValue.setTag( "out", tagOut ); encodedValue.setBoolean( "crafting", this.craftingMode ); + encodedValue.setBoolean( "substitute", this.substitute ); output.setTagCompound( encodedValue ); } @@ -269,6 +274,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA if( this.craftingMode ) { final ItemStack out = this.getAndUpdateOutput(); + if( out != null && out.stackSize > 0 ) { return new ItemStack[] { out }; @@ -282,6 +288,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA for( final OptionalSlotFake outputSlot : this.outputSlots ) { final ItemStack out = outputSlot.getStack(); + if( out != null && out.stackSize > 0 ) { list.add( out ); @@ -347,9 +354,9 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA if( packetPatternSlot.slotItem != null && this.cellInv != null ) { final IAEItemStack out = packetPatternSlot.slotItem.copy(); - InventoryAdaptor inv = new AdaptorPlayerHand( this.getPlayerInv().player ); final InventoryAdaptor playerInv = InventoryAdaptor.getAdaptor( this.getPlayerInv().player, ForgeDirection.UNKNOWN ); + if( packetPatternSlot.shift ) { inv = playerInv; @@ -376,6 +383,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA final InventoryCrafting ic = new InventoryCrafting( new ContainerNull(), 3, 3 ); final InventoryCrafting real = new InventoryCrafting( new ContainerNull(), 3, 3 ); + for( int x = 0; x < 9; x++ ) { ic.setInventorySlotContents( x, packetPatternSlot.pattern[x] == null ? null : packetPatternSlot.pattern[x].getItemStack() ); @@ -412,6 +420,7 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA for( int x = 0; x < real.getSizeInventory(); x++ ) { final ItemStack failed = playerInv.addItems( real.getStackInSlot( x ) ); + if( failed != null ) { p.dropPlayerItemWithRandomChoice( failed, false ); @@ -450,6 +459,8 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA this.craftingMode = this.ct.isCraftingRecipe(); this.updateOrderOfOutputSlots(); } + + this.substitute = this.ct.isSubstitution(); } } @@ -519,4 +530,12 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA { return false; } + + public void toggleSubstitute() + { + this.substitute = !this.substitute; + + this.detectAndSendChanges(); + this.getAndUpdateOutput(); + } } diff --git a/src/main/java/appeng/core/localization/ButtonToolTips.java b/src/main/java/appeng/core/localization/ButtonToolTips.java index b740b969..9384ee8b 100644 --- a/src/main/java/appeng/core/localization/ButtonToolTips.java +++ b/src/main/java/appeng/core/localization/ButtonToolTips.java @@ -54,7 +54,7 @@ public enum ButtonToolTips LevelType, LevelType_Energy, LevelType_Item, InventoryTweaks, TerminalStyle, TerminalStyle_Full, TerminalStyle_Tall, TerminalStyle_Small, - Stash, StashDesc, Encode, EncodeDescription, Substitutions, SubstitutionsOn, SubstitutionsOff, SubstitutionsDesc, CraftOnly, CraftEither, + Stash, StashDesc, Encode, EncodeDescription, Substitutions, SubstitutionsOn, SubstitutionsOff, SubstitutionsDescEnabled, SubstitutionsDescDisabled, CraftOnly, CraftEither, Craft, Mod, DoesntDespawn, EmitterMode, CraftViaRedstone, EmitWhenCrafting, ReportInaccessibleItems, ReportInaccessibleItemsYes, ReportInaccessibleItemsNo, diff --git a/src/main/java/appeng/core/localization/GuiText.java b/src/main/java/appeng/core/localization/GuiText.java index 4d251ed7..fd7d0ce5 100644 --- a/src/main/java/appeng/core/localization/GuiText.java +++ b/src/main/java/appeng/core/localization/GuiText.java @@ -47,9 +47,20 @@ public enum GuiText // tunnel names METunnel, ItemTunnel, RedstoneTunnel, EUTunnel, FluidTunnel, OCTunnel, LightTunnel, RFTunnel, PressureTunnel, - StoredSize, CopyMode, CopyModeDesc, PatternTerminal, CraftingPattern, + StoredSize, CopyMode, CopyModeDesc, PatternTerminal, - ProcessingPattern, Crafts, Creates, And, With, MolecularAssembler, + // Pattern tooltips + CraftingPattern, + ProcessingPattern, + Crafts, + Creates, + And, + With, + Substitute, + Yes, + No, + + MolecularAssembler, StoredPower, MaxPower, RequiredPower, Efficiency, InWorldCrafting, diff --git a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java index a1cb07d2..762aeb73 100644 --- a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java +++ b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java @@ -59,8 +59,8 @@ import appeng.helpers.IMouseWheelItem; public class PacketValueConfig extends AppEngPacket { - public final String Name; - public final String Value; + private final String Name; + private final String Value; // automatic. public PacketValueConfig( final ByteBuf stream ) throws IOException @@ -158,6 +158,10 @@ public class PacketValueConfig extends AppEngPacket { cpt.clear(); } + else if( this.Name.equals( "PatternTerminal.Substitute" ) ) + { + cpt.ct.setSubstitution( this.Value.equals( "1" ) ); + } } else if( this.Name.startsWith( "StorageBus." ) && c instanceof ContainerStorageBus ) { diff --git a/src/main/java/appeng/crafting/CraftingTreeNode.java b/src/main/java/appeng/crafting/CraftingTreeNode.java index 40431271..06672d16 100644 --- a/src/main/java/appeng/crafting/CraftingTreeNode.java +++ b/src/main/java/appeng/crafting/CraftingTreeNode.java @@ -20,9 +20,12 @@ package appeng.crafting; import java.util.ArrayList; +import java.util.Collection; import java.util.LinkedList; import java.util.List; +import com.google.common.collect.Lists; + import net.minecraft.world.World; import appeng.api.AEApi; @@ -41,8 +44,8 @@ public class CraftingTreeNode // what slot! final int slot; - final CraftingJob job; - final IItemList used = AEApi.instance().storage().createItemList(); + private final CraftingJob job; + private final IItemList used = AEApi.instance().storage().createItemList(); // parent node. private final CraftingTreeProcess parent; private final World world; @@ -50,14 +53,13 @@ public class CraftingTreeNode private final IAEItemStack what; // what are the crafting patterns for this? private final ArrayList nodes = new ArrayList(); - int bytes = 0; - boolean canEmit = false; - boolean cannotUse = false; - long missing = 0; - long howManyEmitted = 0; - boolean exhausted = false; - - boolean sim; + private int bytes = 0; + private boolean canEmit = false; + private boolean cannotUse = false; + private long missing = 0; + private long howManyEmitted = 0; + private boolean exhausted = false; + private boolean sim; public CraftingTreeNode( final ICraftingGrid cc, final CraftingJob job, final IAEItemStack wat, final CraftingTreeProcess par, final int slot, final int depth ) { @@ -69,6 +71,7 @@ public class CraftingTreeNode this.sim = false; this.canEmit = cc.canEmitFor( this.what ); + if( this.canEmit ) { return; // if you can emit for something, you can't make it with patterns. @@ -87,6 +90,7 @@ public class CraftingTreeNode boolean notRecursive( final ICraftingPatternDetails details ) { IAEItemStack[] o = details.getCondensedOutputs(); + for( final IAEItemStack i : o ) { if( i.equals( this.what ) ) @@ -96,6 +100,7 @@ public class CraftingTreeNode } o = details.getCondensedInputs(); + for( final IAEItemStack i : o ) { if( i.equals( this.what ) ) @@ -121,12 +126,32 @@ public class CraftingTreeNode this.what.setStackSize( l ); if( this.slot >= 0 && this.parent != null && this.parent.details.isCraftable() ) { - for( IAEItemStack fuzz : inv.getItemList().findFuzzy( this.what, FuzzyMode.IGNORE_ALL ) ) + final Collection itemList; + final IItemList inventoryList = inv.getItemList(); + + if( this.parent.details.canSubstitute() ) + { + itemList = inventoryList.findFuzzy( this.what, FuzzyMode.IGNORE_ALL ); + } + else + { + itemList = Lists.newArrayList(); + + final IAEItemStack item = inventoryList.findPrecise( this.what ); + + if( item != null ) + { + itemList.add( item ); + } + } + + for( IAEItemStack fuzz : itemList ) { if( this.parent.details.isValidItemForSlot( this.slot, fuzz.getItemStack(), this.world ) ) { fuzz = fuzz.copy(); fuzz.setStackSize( l ); + final IAEItemStack available = inv.extractItems( fuzz, Actionable.MODULATE, src ); if( available != null ) @@ -134,6 +159,7 @@ public class CraftingTreeNode if( !this.exhausted ) { final IAEItemStack is = this.job.checkUse( available ); + if( is != null ) { thingsUsed.add( is.copy() ); @@ -161,6 +187,7 @@ public class CraftingTreeNode if( !this.exhausted ) { final IAEItemStack is = this.job.checkUse( available ); + if( is != null ) { thingsUsed.add( is.copy() ); @@ -202,6 +229,7 @@ public class CraftingTreeNode pro.request( inv, pro.getTimes( l, madeWhat.getStackSize() ), src ); madeWhat.setStackSize( l ); + final IAEItemStack available = inv.extractItems( madeWhat, Actionable.MODULATE, src ); if( available != null ) diff --git a/src/main/java/appeng/helpers/PatternHelper.java b/src/main/java/appeng/helpers/PatternHelper.java index ba70508f..a08e603e 100644 --- a/src/main/java/appeng/helpers/PatternHelper.java +++ b/src/main/java/appeng/helpers/PatternHelper.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import net.minecraft.inventory.InventoryCrafting; import net.minecraft.item.Item; @@ -45,20 +47,21 @@ import appeng.util.item.AEItemStack; public class PatternHelper implements ICraftingPatternDetails, Comparable { - final ItemStack patternItem; - final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 ); - final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 ); - final ItemStack correctOutput; - final IRecipe standardRecipe; - final IAEItemStack[] condensedInputs; - final IAEItemStack[] condensedOutputs; - final IAEItemStack[] inputs; - final IAEItemStack[] outputs; - final boolean isCrafting; - final HashSet failCache = new HashSet(); - final HashSet passCache = new HashSet(); + private final ItemStack patternItem; + private final InventoryCrafting crafting = new InventoryCrafting( new ContainerNull(), 3, 3 ); + private final InventoryCrafting testFrame = new InventoryCrafting( new ContainerNull(), 3, 3 ); + private final ItemStack correctOutput; + private final IRecipe standardRecipe; + private final IAEItemStack[] condensedInputs; + private final IAEItemStack[] condensedOutputs; + private final IAEItemStack[] inputs; + private final IAEItemStack[] outputs; + private final boolean isCrafting; + private final boolean canSubstitute; + private final Set failCache = new HashSet(); + private final Set passCache = new HashSet(); private final IAEItemStack pattern; - public int priority = 0; + private int priority = 0; public PatternHelper( final ItemStack is, final World w ) { @@ -72,6 +75,8 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable tmpOutputs = new HashMap(); + final Map tmpOutputs = new HashMap(); + for( final IAEItemStack io : this.outputs ) { if( io == null ) @@ -132,6 +141,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable tmpInputs = new HashMap(); + final Map tmpInputs = new HashMap(); + for( final IAEItemStack io : this.inputs ) { if( io == null ) @@ -151,6 +162,7 @@ public class PatternHelper implements ICraftingPatternDetails, ComparableRoTW$6Bm}!<_HTnfc1z`N@n{*bnA(zfRnh zm~hl~Tjyy45v}`-D4UVs8FzrFTlh&MM^@&mg}Zxg(BN^`QLn)it2Y+jMT1)v|fP`sr1&mzgJn>#7uKt#1xTeajV5S672RZFeHzZ()+hVLu^0E2`DvCZ$tRICl60z7jk&m0qW2%x7=m zTw5OxbxuxoZkZu^rr~JC6r{K4fD_*fyEpoets3{GZB3sI<|E3Ty|LxZPB6Vud8kd$ z+?wx!I==ohlfAYThl77m{;UHZf6)EocSaZsLi`=2RPp1g^_xhOG0cnJb#nYw=B{ah zb3T68w-@|}0X%n7<}xQ_+zB#{aGz|>TLr|G#U=)@+%s2H-q$6MS>NxqOPO`-R&IZ^ zbc1HbD@p}9c>3we`?1BmNt8Fdu_@&2R%1Om@k-r+;~Ip?6$1s7Rjv@B8>d8ww4hRm0o2B14 z#j?4&IyEB7$~=cZQi3PlD2>{arzepY6s)LhL<2taa*s%-{!i7ODNojIn1RGp4$DE? z#G5^nXi;E%j6KTgC?Ji2=BtHA*!n3_*qN^#*n=ZmrdGWU1UA^r3|C{H)C4Q4HobCt z=6*&rEYq=Z<`7N^qkhg2|3YZ;na9_@K@Q;0r?7iW9Mf;i!46u#AbS2B9Rlo#`a)h+7o2|ZMh(|ebNRi=ShCmmU&&}Wmt<@$Waansw< z+8?;|rg_mx^2N?g5r-9mblMTPh$FKJ7YFJQV9?tSj^$Sy2&epfSLdv;VaCE*){qY- z2SDE_3TvFU|MV2Llo_?ZE+#$H&0n;6251lw=$WTvUk8=^8B_H-u>Qvl` z5WW;v9kqNU$(;c!!H}z-lkVWWnXwTqU+2D1UGKVNJG*#VU4$X3qj`OSB0NenvJjI( zTo;R^>fr=z4R|r!l^%XT;w&H#8+HMqUaEW~`-tZFLZSy#T}#MiudIB z4czA_b^tt<+dsn!&0yfVkRVVpDU)wsIl+AEFPYjm`^cSlkfbF>@O-k&5u4cfkteL< z%_E(&8DjCW0GrawXVoJgb?J`HKY1toc@;jwV&M4or&(4kyCbY!3Ot%ml{UI7g`}9D zGLWzVI4PP<+9gDfJU@b%s(a0pZ*|niVqiALOZ;q#+03B%2a*+aS=RA-4xBJ)Ny&)T z27Ofd_T?DzxReO68pm&Zt0~YPU}q;3%@5A2`@6>1mWMRWOxyIGvMVeS-~+j*P5CU0 z214Z9OS>8$XT}{E37D_B+E^0v;*P_{T|c7eEY}PEJs>)8BCK+CmSPuJXCIZF>ibd? zxG`rgm$9o}J}Yg-%hjgBC^P8%4qr%n)?!6|yd?maHxPK1_11N@+E+4bdygT4ie5Mv zt-2>Fe(}QL?lZkBi_NhISv}s)gfS5UQ5yckD221RTeEY1T)<+ZM_UAJPhl~X`>o{8k$(zYCW`$1d5^Ik1MctnLG^;D!(kTl(&G#`y!r))eHX$hHY_0m6h!e2 zXRxqgyeCB#Y?IT+ood&=YdCGMxNb(}{4ya3a$eO5=rIxG)5IQ$rfcJ#(-MfttXqDT zU(EJKcf;3I&$idcz+zNVIS4)iwb$Lig49Gw>Q?S=6TILEMX$J#4M-@tU|VYMH2Vj& zvA|}Fx|{fTlvkxxPqj`+FHd=Ld4ew;;gcN_>;TI|Iv6}J!bx!11>OAAkm-awl5jFR zl9?=}H9*;2Wmbcq>$$^;4fi`!ip~~mdzV>!T^NLQgbxA^7C=JaHnfohOqE!)I0EoE zofx1LosdQ)RTbAqUtJG;rmUdn!?A~%AVc|B#>P$`9uV68WSFrT8$)dYAdGnBdPGW@ zXJVuXIodLp2BYo9O$9OoM-DigkjVP{-^C>ok3_P+;{sGAo!&Pv?eiX7jZ;nPE5;ED z8o~(N-?Xe#E{N#<-d5wQI&yMDQ%63_Iq)_8^Yo`L=1NEy$r&};(WBy|-D}A+^zCZx zJCx}lVER}5kte3%@kbONltz5wSvvXTgv*vJ+=A(X2Un)Lgs4-%6K(Um1I8TJG)!C* z+~sszo0;00GV>2$S5K5+jCbC*Y}^t$Ju|#S@Jr~s#E@4|L%3G3e&)U7GhUip0P308 z+b8RV&n0vyat?=CpNIP;JoCqBc)Yp;6p)%TPSUu+7qxrJO)v){js_R&$%r$23C!^~ zIYo)d8qACnJtyAY+Sczxk*hFb*1t2%`kwkv!R@^G$mXy| zoru@h$5BIA*M!HFvHr8c`7sAtjvFf+iOUVW^x)@LEu#R~D|70j!v5mjHlX>SQA#!x z(?#~vuU|iy*x4g#yDfmwM#;IR3i;6bIE2es2}hP$^<%9C%b(V+z`bi`j#<9=>cqR6zs*ZkwmLW{x4!V)jb>Z!v4*kAqSN zn^)4{rBtIe068EnPBg8A?a7M@Z`erIp1sb(tedwE=?+*PMVNM(#8?Zef?bvD%Yl+! zz^zVwkSYG52;@jr46QBcXrI?X)Jz+=nxqAO6mB`L{}-6B zRl|S#^@=^Rt`S85$k?{O-KtWTsOGT-=dSE-oU!y5^Ewp5eGwk#_5Sbme|K{K;FA`y zZy9}Wh%Z=Jr5SmMiJ|9A>qgK2yH6%rBlItIdeRb%pBZR6r&GdMZx@DLF6bigGJPkd|$=RdbP zh#~zmD`|8?%z<}kVw`K*lR0g)_z0q*aB-(~eoTuVV(jKJO?r}4GV)_|?s=aiU9Cu+yZU2Gj4HcWcQWb9RAb4Dyl=u6Vg zcWwIl4`2lK7xD4ks?E+G0zB~CRQR)3v2#u3`Un!bXER7dnBBQZ6i76}g{hm89e1!c zh}X|K z`TO$QisN1#0`ql&csyodxNe6vDFKFa)YKkd-8?j3HJh(&9z^Z$XD^)b$6QaH)^spC z#^B45(&QL=LA&+vu6@h<51~(VCLUhAHJrh+D@TB-D;Z5}mW`C(^g+G434y9EzRM+t zf$VZnrv;yoLYxpd;Up2hcWUURQgQd8XIE|NFtT^44G%xtx60(C+w5c9<$r$<&r>^t zhrWp6jC<)YP*Qj=)1h>_-tPNLQM5Q%#?;D#^&jR^T6Ro|kf58d^&^8n=5SJSv_7Vq zEQVN+X_PHC^V!FugM{e>$zg6wi8eDs9O2Sn$xWjjR%zYVH*v)r zvn(f)HoVj%GY+5YGTjGr%0_GOS20)eVRrNDB!mQz#cr$l8JSINY>cwk$FP0xq{}q*4IeN|a-(S7+^Fq1!m|MRMyH2(qi_>|f zD?f`2nj0E|O|#Ypro+Gt!?Lg(VoA0*Kn?I`n#Dam_U$PI-BQ zu!mi;Au?n$`|a}=+~`?_I=pjVvT34*I0J5Gk1@AkP zt*Nj)zWceY{avz8gnBl$wI(RR!)&`?4)|@}Vrd2?Fl?)|BJvkNZ{$^s4V(E-KeJRP zr)!5Nu2xT~vAPC+W1OPrY?kF}A<>~Xf$E|Rx%m5~Y}t2g@M4c7u!(!W+0~f}f#J=| z9}1mbi%uiKxbk$V%HY=ih3F9DMmv)o9cKNO4|p!JG&|^XY@nzXbM{eY1hL~X z`@x`@hd~xS$P;y6K z-jt^ru#)j?6O*k>lThJ$newFu2Aa$N0;}V}!DvOPJ>KxgX70LOI7PzBsLy!2>q{i) zr6%tl`m!|Qn5_l2lppe$gw4h@#<*ZpO>vZ2E&|O%i_l^jvls4bj>gPnw&Y<3n+Ijz zJ|?&ZeE9Hs6h&6|UBFfBB@NUGa=6HDkMLUrz^b6q>jqaFfb*A#0&CQR$-A*mnPKrC zkK@>MXF6mxw8ODcG=*F)+yz~vs-lY<#?LY03z zV`bUI(06FO=%Yy}m#%dc*b}EvQx|pdtE7D@Ah2T+kWLfIUu-B$sh(?1k2*%KQ0$)5yJikCB?LyW6S3~IEJSLjEg&a42uvi zr?Zl7b$?BIaZg3#?!TKGj!_;KPP$w!c_#8?ek`;T{Gml;B<}qaX*jPegEbJaA9(6P z>cW1Qi;{s~1{3T9!3dJ=WVx#NRh66~w7YUW+!MksP+~Oa)OYd5lnLBFKhPNE&jDFN z-iB}(qEV7Y!EwMK@GFVLO67tHMP3x5LuFnyqVs&BMeSl4ciQYF3l{ONR)u=&gP#w7 zxSS_C*x0N9<$X6=tP`GTMj5P^qCJo39_RZtR!{CsF)iV8WY)kNC}FZyh%3>iJdbos z9+*6HA+dG;}YpP`+Uq|xJ;_>U{Fq|0&88jV)eZG9t& zc#zhlznQb@-@(3&8CXGwS99e;B^}=iRqY?6LB#qpWv77lU~5oP?@dczjiaaMNL}Y`%Q{rk?uz z2Nnhj%HHpT2_<*24AJNMmiR#?}77Q*El;}?3KJk;f+UDEPwC{Nwin8YSA14%WT(*$c9OI0?E><7z3S9N+laZ#A0QjkN|LY!&Gy?IG8!X)7jIr zW$BL(fHjTr{t>fDo*HrOj|p5!(%704kGydQsEeiTSLhlr z$I{`o8N3Fwd!e8(8xZ(asK$<9Nsp=5~4({g-43W!C2XSm^X52U@)_;cYNFo6BO z5z0*Eo^6qRa_7XgK^=1;t!@dm^OzTa_4i+tJ{4hy?525ss4I)3D2wF~5eD2gfo>_pQFmcLrul+1b1v105}MOuyhxSmGF=T+l)QS9I_I{=?-qE zBBwi|HTFMUf>KvAJ$31&4TgoaB;=@zNj7|A;f24XWJFq}#>(U)(#{@)Wl((JmK)>c z)Z|nMS^wJlH2LbxOM0zt8}P>d%yiLnO|Y03vCI~12bfKkxbgdcO>#`ui-jJo6C2Di zhWBGBVm|jt(*jrrvPh=Q6wj{Nr%K65C+TF;W{&4?H<8?LS2<`}CRWOxTkn3xXOY!m zM`=Lc-5ZD+o0&a5vfgYbzcEhGJ;w!_d3o*D;6rL@1SL4s?hm^5=hrp_iMnFUA>O4Y z7m8L2_G@<;6`ytB?PPNsyyoNe=B&k)!1=$U*1{EtJ%BB*DYWQn*h~Tsf5v3+VTJ;S zyXGCRGeN(e_}G?7vbWWPlK}Hq4o4EwW?#%cOVH#oOG<6ADo%+nLSoNIPc8s1&mgZF zdAaB9(dvFFY=k|3&gVC&jQewHvcNjn6)1&4>BWtnUNH3eW_W|Xx#8louV)5>1_C1l z)Iv9mC@>i{?GCvU(jrbyzm`T`jyZIeD~5cQiICYZ&U*r$li0`8@Q3t!FJ}espSL=E%STb>Bd*j z5A^O1?|-{?ulrF0v|tg^3zqWmt`ZY#bX7Wx`9 zt^>jKe4ikj8XHHh#^|6$aa~Me6CFPpXMQwjXjdE`LFYKZ%A^VOr1e8C;0xPX2-g^4 z1j9vK!u;*R?fI-`|A{1`*?so4pbgD?6h zkq1pH*mmq)EU13vkYBy1A+NYuqTzJIA@L5^^B@>K=}xV8`>!0bAEi+%Ibg-z$1{f% zWKP-C#C+7eRzs*9U$pO4U3id1duHL7*gBxzyITZ|WoxCaFw(au9ZDTTNjWNY>W@XR z7!xECplnnI+nxuI6YLVXEdq;Z^_=*aywIZHKEBNYJb97q@ojhGc!jr>a5za@2+Y#G z{G%REl{`?QPddi7>3q3IL6ue{=bd^F);G~1-5$MDe=0S8etWI0(+4jA z^NYIK=LbrEJ{D6Zuaw#fVqit-FoKIl5=zr;d8#`Xkdg&`d@-uuH|;5gKm{?!6^O+C zyn`3~NQPMcHgS>ms0`=T1Y*eXTFN9b6=w8Vu6BfRAsIE!GVu!Lw~BPM_z|>K_|g=$ zqXyFKowkEkxd-|4v=fu>TcaLP;brg<~NQZK574u#3Ls z?C+IjU7V+Cmg+4nSb+GGT zhO4H=PGoy9IwT|x+2LcHOREaUE@peY=#o|N@B}~GL7t`us$&OMj)n({&;i95^&mAq zN0SGYx@DBQqgh<9`U^CSMF=Z-&lx|^i)*X@=YFiH5Xi4+a)-)&YoD_(2N=rM#SlN* z<)LuPS?28~oA%*o^WNO8RlWV>5E;oBOKtupr-GV+Kn}C)oQ-F- zD~xn>mOjhPCON-3(lmLQIfmVqnXJ*ZRE~SdC|}X0MKEk#Y-mj?L!qAR)=VS8x-cs6 z<2>tdEPV1v&^J~(Q_&jiOc<)7%z6mItr4;sKkNQ;wQ`?8zC`W!ENnC-;r8fqn9Id5 zc}!F-LbwY5mFoPZFWDls6$;E!7~y9#Ci*s($H{40o|Bi1q;sUxAgupHO&HrQrVgX^ zVeTI=IiFK3EL{&0t%QlfBU_J#0 z_jwAxJzfAm=hMzsT%QNJ$jBBZ3Za{(5>mM3`k`B;j!B(^C-}<)1W_*hVl8+vaNrTL zua@vL@NcDSVrtkx>!$D!=@j!Vv(K*Q|NUQ$gJVp4XQ?B$xPIp8D`vyV{h2n7wy8A8 zD+lgSvy_rwXhAhslwVSMY-f8_Jk{FwVD7i`9JENNw=v~EcxAveOG;$O-sRhLcIu5Y zI5^;8_;Kk;^^mm7&?3xWw7wBjfiboVVSo{wILnLu|(U)zAc zgn(ujH3JH(dIL_-S{m^rnSc-Mn-wHb-~Ueht_gf$O|Cm}^eSPn7p#BpY#w4Xj^<4aL*{0NJkIzC*dy|8kT6$Hlf<3xG9gq`drIHA`l4lhPe! zEu8VJQ9rBM`6$%br9)t8(K;v>g*LeM`rW^PvqHbU@o_MMixqCtI6J{8#a(5-EMx3d zCG8{Cc#*11d6VLF#tG73AN|W=3fS8lPbVR;Od*gKsoKDW&@uKZQudI!6x5+wG@00w zm?dTT^*5bxdcch&WPRtnv)kCqq*pQge@2f*wV{P^f7+F9Z}SP}n(W!s7lfBa*y->J zdoGjyx!;~}Uxr%b&GtMt^Lyq1U8wp+FcPma5kwnb*4V()mWz0c)d!+92N(SQJ6i}t z&2V*DEeT})p6kZB_4jOf#}ZBtez7+&dR(~lFNZ8k&$|ZJZwmYc;w-xem$Elr)^R?g z?lCc1BKEOOP#%u`=kfe}x4Uh)7Ahg^{a$7tq?j4|{R_(Da}wx{8(x*LAJW>tGyaLd z|34S~b}J<#>=UYPmqrMd;jUfGmU|4DI<_H5;?J*gZmlkK6UqB_jl)mGm=4S12Tik> zo-G=QU|Zc*G`>oRwCGO-bK}@<)NQRiRmN>Q;kS&9_~2`mUtU;jIqpBNSIjXGuMImb}hROu0wttJ{@pnGno|Gsb8Pr%`?20zi2g z2v^lsLHjv(pX!km|FIN?6A@>~!f1eopYl{m!@gkVeE~abH6>#ezvyN(Z&GKTx}RZd zVK6MT=;V|87nz-J(_lok$@`=Y6KTx2g_C=<=qzECbKc-@dZPO`Z9p*ZS-lq>=9RKh z_M>&ahQdNk#m1Q_a=7hU4Ni5##tyYOXZc^`lMePWet^9m*^%w353oM1Uz!8t#Y3C2 z3=%!Eo_$&s%uhOCrTXo2avD0VUFTT`PI?{paG-|-TLriJayqBW3~R%xc%`Ur`2Q6Q zP!eq@E0YfV$ZEi%Yx}7liE<|PDe$DOy%GPLOrU8j#YW3N6LI_W<{sH2b;FDv5r8Kt zSn~+&Y)HtjSF6yM99mTak_}fu;L?LsHdXxQOI@Mhsr2xtrHq*!1){8Z%=k}Ys+V7vhC{w$RVXtizII}UdsTQsoNs90+Wbq;afJQj{_ zkP_|2-Sk;?eJbNBbo}6gTxn|HQVZ@f1jLafL7$P`YqhI2^boNC3zs#*|I|3-AGCK) z7I87N^6>D3z{v_vZErX;AgV(;`kAqnQ1nh0z?Gm>yd_FCOB0??vw|CwfdYT%TDFi^ zygUL+o8NAec}0lh!gdwX>f@qe$HA9mi(;q&wLnB-_2}L&7aC8ie+s5P+s*+(I0~;c zGNkuIFXo3_?q#bUg`ylar5#Bp3Q+T`O@5rZ4}f>wk=_2i)`SXU1OYLsE5tj8l=pb!$m zjgn9V%c0G_zt*1*S6_3| z6UDQtizglghz`M_CM{FZp8HdmL8LpU8Cl~tW$ z#xH>kB!P?HVH5rV65)B56H{}v!DL)9q+_m}9_PRvZH`9BTyVht3Kl&%y+*bIU3zGY z9&kI3?E0bV+_+}!`gd>T(I3#F`}i2G!v_fxw$l`$c+H;_9tH`LbF4dc>oBkg%! zk1&pyHi~x8>@fO`QPDE|Dayyeur@kTy^&2KR#vXjep@+HsQ380$@6~>OGQ2o6toy;v&Q(C#Uq?bhL z(5Uk}Nsa=IO&XuQdfOGnwbNGke^TBngRNk~8`Tb!zCJX1?Y+YdrB||oq;&P#C-Mja znRvy*U6=BX(!oj|e>I;=erV)_kq)M{J`e#7slMqB>a^+LF0+vikKTaqcf+vX6o1m& zg8ad(a{T&(hh@S;ZZ6+SdkvioH9kj>OGjTN1#PS-Om1&7w!e^inN~Ts)S84qnh)Uu zq0<5FDM5A^6~ocp><|QL*nGLsu*n>Htf0DwEo9jBNBab7Xm*~0PO_m_9kRdOSee&& zHRQ9hZQGfm*4~k<5;|=$_MOAKqTUTso-i97$6qKzS*;!5DB*cKF7vx!3;6-#+*&{- zq%)9`0BK);tml_*7$F+G^8V)7p*%T4zEn_!CT>M|pC;6fy6}*e?GNtr{ytI$r4x+n zhGihncE$G{EX9{%#tfSSH+)xJ!|=TDvhkmky|yYPQuR3So*&|`MUawFK3k&!cI5EI z-5gUNUirB4vuz~yp4AwIS_G&pPSc(E(@_E}eWW+lfT`}?qEaTA$=x* zP`RaOH?|o5^v~PFrAyE{4AH1YOuC6VmlPf`727Yr27@(}?zq!9!7~D@ym)7nKT{0_9D)~)@ZGe5KoR^ZD z%3px=8poKz+<<+kVAlG>Pg_>wFypX6s~{N8vP~(P@pUyzvq|F<5+dyxB>uPt zA!DrYZWlozjL|pug-lnZ7n5NpqPf1@(|g$A*e~5uoq8zExz$5GY7EBw*}YCoyIh4? zP1sA7OJx-Rs0gh;i3X4sOS086I%j1W!JbPkMulJXsEK4Ec`*nj%{q&0sA%yU|6T-U z;Ibw_3H5*pqwVBFVb0k80k0)9cSGp7f$K9!6BLK~9wSWt9Kd0T$Lri1I3UU;;gFa# z=ibWPuimHgjxcogPCNaY-`F}c>7nf)8JQOiV9JdT`EKaBYjBj1KM~&wc`_zvE&bA{ zJ?ao$lWEjLxII0Y#e$*F9XPFxdzx3cJSmrcsmMVRz%%tN7f6m}%fj`WM%4dPM$~%# lQL%g4OtUyPe9?`v16#|?ck_Nf*9o8>-IInV^0jcc{twPkUo`*# literal 12259 zcmajF2{_c|?)E<7N^)p9#Rx|HDFEc{4324^^|hG{2+FrV_n_}#;ghfF zX-VnZEKw_i)A*ePR5Cq}%D&qUmtIRgxb!Zt}wP|=MDUloV`tt?25$68e<@pTEr#H)uigcvq z2wACdHjPl(zQ&zY)nE82!)u#Ok0t@D?&Au-xvfe$+V%3d74HEc5IODgCFJZ-a6!5* zqvo(O`%uuB8HLmM7T|eqMVcX$gq*u0feH$`fxl~fd;K^P78n*o(Zy#6%A^Estgt?* zu^FD1Hv-db?x(q{EJX!YS5Y47uA(w#coCH#TlQvjQi#Nk6v|?gx3GHO)J2YgV%$7q z^#0itAMN~-FAWovkvjUi6{2-e1g#Rto2{SSPsmQ$rf7Xv(2TU0fmtWu-XAGl|ELVy zD;7G?*OsN)EJnw7m%Ecxlxm~XJ85N5&v6J)`G@?g_i5I(QcS-HBaWd^q9+JAOPp>_<0 z;t4}^`I<-eJkBScI<#kBM%6WdMi=a^KgR`}iU(JcvuCs@kL_HCjmLJbLg7~gNVb>} zS*$PJv|$71#R*%V3-@-D-*atwtzWIZd}d&!WhVG6-9i)L5E~ZHEUhgjUa?X?d2;hG z5=hTK;@IbqcqI)}6Af@VN=IH~0&oK%?)W+#eU_dDGUE>+BB$p)B2B_!hmp_PC6dju zNb>&6wTv(qxx1CD(PM&H@ub17Wo+h3PM}Eq-3M*9N5LrV*=^5L!z_y79XgC~n;qnFy_#b@9^9eKIi zBOu?odPHEbrdj3986s<=bfnA@UhjUQ){|P8=iLL$g!YbV1X#M}2geF)n%7+M0K>*z zJ71jf$bnn*-=ez7ZUbXq`NUT!NmpO<|fWgDB;b~%9^G;E5E*hJLMmUYxhjq zgZG&gYWZvGn{Kp+-)_t{5qHHg1W6*E0 zQD<4eGg>hbD^xp(3VZ+Nfj&mhM8+PFG}5o$HK;k#u`4dq{Pw&{dng;0b9wB}wLM0E z<0M`D9_p$*x+)jW)!deMdWVr9Kp6$1oEAt*jSRqWJVSVTWo>yTyI*%vbE((cX#G{E z%Cv>%x{z|gSr~OFf93QLKe&qFdG4z}=Mm3OD)6XUU+jZg^YD-gI>)bzm8u%qex%|T zpy%p2<`;+vfoxi(Qf2xCfJHPGlTy{O=HZ}`e$hEnXUwx) zMj{#?h+T~20hM>91`i+xJVe(j7+F&r&lw(@wNvEP9#+w;3|qWg8bW+wK7J$yCeHKB zK-OTCALSeK@jc?+sD*?JRUC{hZTpT!E=Pl;ZFgLBL?SV@> z7~(??Be4OZPwYOE(wwgI*N)OE7cC-`G2#f^wjo)epG|cV6YBL$1u5UF;OB?04=XF$ z`%Ci-S)BKgwmRLqwPD8AIzqJt|K=MHTJ5n+?=@^y`UhXfc4d3zc9p1D5%k^2RfoNtDu0I;3lC+G8%JxXvs~j*GIw z+w>mTc0VQWfP0mn#h5(4px@?l#%TL!EW@5LR=kq%@c>fbR?m*Eg@4Uon>XlPt}*l; z!{;ur0E%OPp>CTKVm3(6u3#$4HMOL%q1U)#0drpe-sL^nDLV~1s>cj|yiCi~47Sd5 zmU1n2Jthde8t&6F!N3(6%QEzg<2e5Ar|ER!ndKgG1nDt>*rd$?O*|;0*)FzS|FjBgiK!OzuV)@M6c-6l+x|RqkRH z1;U}}i+}d~*2d~ksCC>(Ogbf$7i`G4NM?Qri>0*WPJ5A6r6DvCJ=0-P19SqrIE`I7bOGViDYMFNr+*r4w22+e+@ zJ;17y)_S+3xdGfN1+B-rnJHz5QnnHQc{wkf?X}-0?|{3F5g!c3H*7r4ODEhAqzd#5R}4 z6#aZ>5&N!G{nxwD+m~hKz3X*D8_vtp7P9%}`V=oj1?5Hy@U)onZ)M{G|NcsV)`$a(0S_~7 z+oULlRI*AAvDpNzFU-^``9`#$P{-a1kyBO{@`5z|`!|NBG(Rcqg1_vF9kJyOnn&bF zI>&mfT{#TGMt|mgj=iCDlIU>wm3NKC-(q2;#1BSoP6C%-2=a2nI^^L`v+hlFzA)w+ z*!(Kr)V~|vN)<4IQy;OBKC3jl=oSuk7YSTBIZiG-!3Lf&2|{kbWU_Xc#E+ZY%U}D5 zlE=4JR#Aao-(9tQyl`zNTFXpmGigfQF>J|N>!_Bn@9fm(YX=8Fwrob=;yz;OdJ~G8 ze?_|70#VgN7R=Q4W~G1NJQXG!+%3YYwaD>)D>LF_noo2%K~gqsJD zAL2J21|{fc?xUJ__f%sr&Nx5B)IxE+4F*q#w%~aZ(|ox2az#Y zhmyW_wkCTHA zQ6;D_&nD$g|=wrd&rFN z_4JMZs{g4VEisUtAf#r#>u10J@*IDz#YAVsu=RV^w=BL9&aKRbef2zGXTmwM+Wh^~ zK?ZCypMBB+zb*YODoS(F0@v@mW@jL`z;*@CFMYFEqfx?C5)x3>w$>gAF>3R3r0qN= zHBG^58E>DpbCDN%Y%wZh^|DQr9dPtjj%*OUdttafR*^YNHaN^jQtll0s}8;WrITbH zb-d$?vy+gVXzQA;&cIwy4>u=_5V#>!D33e>dOqb(>K+8R#m6V2RN`%j1XPsY^guO3 zbIOn2dn->9wguu=q?C~m$s}@Acqr*yiGG`BL4G6sNt~L#_odB*sW>*0N>#B(WafF` zb|AW%SzZhWwN;xN%%nLw21DMgmO5Sf2Pk*m8N7fM$m6S$1^Ju3)7XD#UDQn#CJVAbkQf zALsEv@WY?sl}W;>I(t(Wkv`Dr=?NpMJXLz8!CFAS>eo1ukbURgjVEF0gRGZe;({lo z^V#PVac5O9i`wH;NY88@_sKbhdbmIVoXYg)1?4PGMxRPxjt{SzAJO9%M-BgxLy^y# zn!<{md)^p#@A&8}Yf|$Tnxy(UB>6#;>C;n>KM6WL_QusGKDBOBdG$YPw-^@9Oe4HhL%9Tku%;F9XbD}2S_V68--8Ha?fK*` zybs3$E{e52EAC|A0>=RqK;f2|RUK zeli7_t|Q*7@8U<+O=0gS6)6k+vhbtz4WJh=wzAo|RzJ6?I*q|>4lzomHebDE)!Ss- zn6|wNBdy0M+?-i5O=Q&F?>Z5Ak`8UU*Vd+U%*SQsEUl+Pr=ln4Mss#lyB1qk=idKt zQIVwGJwMRD>|s)3yB$6nTN|(4tXfOA#MF#7wH%=M&(>4r*cV^;cf0bpr(nM)c(6^P zn*CyzT4I@LzQY)D>rgT`AaC}szqNI^1!|Gq0}#zym!y=hPkK-) zM?4UzilywqrNHS%TJVcs%h=QG>P5JgRm;7D9Bfd*4I^RJi^-4}Poi}1hNE`W>X``b zftHWtJz8D4ruMq6N?Ao~lA=&%$uS^8e6425^2eZv2jJAh@-GvJ$ssF2Op3-wjnxyI z%7X9$5Y0M*7i2#|qs@*C09?rP!K>_^SYNrad;+ zZj}P6mavWR!*O%I`i%aSw$8xTQFHbIH#o5c;r45Ni_<#Q0hqUtpfXC}fU1ymQ7EM; zmwqoBkq5`kjv5ZUh+_xDRYdXr=q&&@O6?4@(FeGjG%_A%MC&!yL^dA{goMz|c z@NexC!b?pFU0@nGf&b`uIk^*}I`>E|D~iGSYaUAru@vYKFNG-lOC-_F>6DO7>)2Dm z%K+Grb8Dt#GYuApEi!Unom3f>4mKQ$Nzlk2VVAR#n(WnlAw)B#*{Mx ztYg=eA~RTDj_1Bo|D2U~sPg*p6Kgd>#sm=7G4!@eMt8wDS@`it&|k=^HvS3`#QoKt z9n>vka!ZYOV3loa!1Iw{M71zBQtEit_*Ph}Buf3rWsC{*kNY-v2Vvr)t7Alh!>J@O zWxr%@()O6_kPoqY>(wnZ5B&ME5kXy8EESQ%$~SSp1JMh8z>`~dl4D@2a#fm*6hj`H zgQAa<4T+)WI+a~C^zNoqFSPq&jp@-t+$~0ReSZ$i&T|jEb*&ym7dgjhOGb|wJj7dQ z8jt()bBxXj*xT}R)K!Ya{Q1Dbm8cd#@HG%0Ku z+iL~w>3!YG=&e2NTX+C%sx}I*wdW`MZM)<=uWvgnS5<6IR&5 zx*V#cf!Za5La*d)IJeE@mA@k7mVL!2sct;SxVXC|mhwLfKx~zf&$^Q)b9+(B+Nwo3 z=ypQ1P9z>V;Z_knsQuK2+B@a@gz#J2`|0&EQ(Be9 zi(O+BmapBJS0P#%nr4I`>5^QFV1#R~UjpymYeCE*AO-G}a^qX6XK%)>%*`uV)rAzw z20Oy_x(V<5P_TLg>D>Q)Zy@aAvn^aHFcB1E7VhrBX>oiHLb(l_AE=jairTE!qr_1* zeCc%4Kv$Sw#N6l{aQeDh+*uRv>P+y|ii3$GE}02kP$ay8t8YKbkV_>Z`F* zKtBY_=FZod-UV6~T=K%@?E%C#K8*#dkWF9x?E4e2eKMRE-icQqM8Q! zOOxoV!);=JEboo8i8kL6vEc6aNxH`)ZyjS1U=Nt#LOswNqdsMgBl1?XG&{Auqw3cSh9?g@^&cHO!zQEmAQz|*BOX6*q zscA^6kIGBluANGSHGjK?^g++FkdSxHes?E#Z{_eF_+`XlOv+l$if!4mPcKaU)s;i? zx1(mSVH3retVO2YwQz-mu8WS=MW;`fc~8G8*>n2 zY0G3SgP?tM6?aJmlcet8pQTEsastTI?}nYi1!8l7?;(z1B%og8Xx9Kp>#A8I!MT)9 z6BmR0d=5aWT6|o?tB#yjvHKToSp0=3RsrbmkD1@V}mnciPCCEE%jt=^k(pzRtjYqQ|kQg_Y>%P4*2Kw-OJEDL>;TyK$O1@dy%PssSvv@ zUu&#bkj$|!e%uy|M!sNYD^ys}iPAk_4xHvfE{9y8j;xVNlQk)I-5AQ(B#u|oz^{Tawl9-|2(ARfZ`LF)Xj6PNfoMF=q5T!`g=(+0_P4D-n zYo69EB-r{6-m;l993=(w;z8GEGX0+9A2kb|1BBJj;O{hf@Pr`fYU6xcr&4Qmo9K2C z>D6MFU+CtMAk;ex@{JqnE^v%?o~W{cS>#zWS+|b=(bX1WLpxfdk{KUy3&L&%SSn>B zBKaI?VYS)Qx7Tm(L(_TDm-Ptj)*_b}YpR3Qm%9!DRv)S`UrPTiU;zIOqR^ZT0YGQj zuncRg2Pb!y=={%6Pq0z>f|hk-{j~%D$V1}%EBrGAc9g=N=>AW$-J$^P?+(S$+(9e& z^6Ho^sPC-x756Fj_)cJQ#d1oFtu=wn{4MOn0@LQzZv>0Wg!&pckfii)Vc&C7iIcw% zwu|YaA^>e6mKlH^p0(aPvXFU|_0NDjucu?SHrvwr&%L?IQLmSE=i6TOhc5aJ?NXA$ zYGIEE9yNansebs{`1Jc>eU1ATVQl+nJ>t{&{sgkD?ZgH#i76LT&4-M_4q?c`sF{ z;p;kM*9+8fiDjV=esbRuyr@ zMk01FFBI5^?SQ9e8d>=LX{#1g-@pmAt8IdKg;viQ$Pg}%eqa+{1 zTDG-IWo!JT+e**5fkE=n`U4J9Yo|lqMpqzrS$LG$|EH1SGhHktmL_g8bRZ0ceLZ$3 zvO64V?qpqmq-_5Qmp|8{Gwg*q>>2*(K_FRUfH0@zUa8=Fy1w1gY&Nk-m`XcP0d0@@ zFKH+&6xw3XKV1N+O^6f!&r}-P8}H8~C_&8F?$7xDuf3Eog=ct!Eigzgcr1{eH0HyA zPCRcn48phOLwru7yny?Y;_?OwQ{+IWou|Ur1Zgw&A1!0PDfv8Yl$&2 z^Kf*I$W?TASNSy2Z2!Dm-c=Pr3OP#sDqVzPc*5^g}Q4HEV zufb{jNpHBx0i#ts&#o*_4^FFZ-7=c9Q^`fbiO<^njg?Ft1Q!U zn7IG-ivncCAW4C%inZBrL!IyJ$zoOo%SQ5_H6j9bsGUusx&yI7K8hgp{^WpGEgX06 z5CEH@76f**8n+kZ#{yF#AyA943r1Xpiy!9$+7RhA!Z*lHjpIK-mYF{Q9S3ovZDI^s z)xN)j^o+x>jcY>Y?C4B;)(%e6ZK2MVw%wp0=wox)wco;$(ZMv&Q3cr?+_lmL$St4> zoLyRP8xU$;JIm?8hE;EbH@=f-UV4Ge16|8U;<9eG0&20L^{bxWrQSiy^j6|&gEgz( zR>l#f@0x8M%n!5QP$1cLuXVBIRP7i5b!l5X?E}Q+?PbkJ0usaS@Bl6~iF~Iy1X?DE zVwk4)YLCE7IJRJ%*7?57{nz-S1e2n25;f8ZU6|nNF3I=D4$DO97 z{U+byF7NSN_jEh+q(ktxs!tTW&)Nw~ZQ^THYD}Vv7xS@lyC?W7HquEe%nglYq~Ou( zMujbZC}X8My?7WdK@5_#>n$blXVB%`FDzs2UOSAGX;t!R*HPt2eh(`$ZkkZU=(jbW z=ISuHs_sqrE?G-09Zcl8Q4_1fP=eL7v+E zS~IsFL75!oKfKR`z@Dt(SGdwUq7{F9K1K%AGCWQhZkXZzED0&57F#Oe2oK3La5gp= zBL3+55i$Si>Sv|6Rr#QmhNjNS#p3)ukY$arxvtMXP;8_FYW0G6TZ{^UAP~?1dm#-2 zaYa{{)T1lUUCf8M0sx<=~Fs0fDm@%OnoLkidA$L6?$eYLkPU zKz?`Bo}&Vb+7pUfDOpaLyY_o}t&PTRfu2TiEM`3cZw`}^Af?*Pg-CfId_dj)s>=qz zV!&Gz$U-s(62O)Wwmb0DsEY+~AW9rfo4zd10h12bc4zkl0|(@r=(Mg!VWNEC(Ray> zXFz6#&wm4>TC#8ltk$fFF}rAqe1X#;iW2;aRbji}#?A@B#cGW(gbMe!`vpa714~0GrmVbtDOMOoHw|#goVgLt)&%M?YfV| z{_|s?bUjuzaAs|ph7qlk;Fm^6a{`o>Dgfk^+jx|kDpF=H3dY^QplSUrUL9u%KLWhS z!k}RD(f0W*<<+v93~+5m?#{rXjwASZlGs*Ro#j;SnM5!01>>C10^rC9EOm?9>;ZAz zvH~o?``LMOh#4iqCOJu z=Y6A}1KsHS=TyZz#6<|&#HOb`7AP|q@ZtTT@~wWUd^rh7GEe!B98JlhP;? z4?Jre>X9iSJ4YnrH!njgBqczS@6z9b7H~~p*d2v{F=g4hE5C^&-;U>l36Bw}pOBBg zx;0X_A5a_;iNu7oyI5Xa@%~N7AOWGM2;GAU$ruj3jXtdSFi95*^p5iQ&qoQTY(0uv zO1>=^Ky*&hHpFXhK#s>x?ihZ%yRoqa*6e<>WnRSrcUxlher?aY{~1e7VhSQ`#snVAn?*~WU_`sxEgc(MEsF_)L? zxG#zqkeNko*HoEHlur{!Zv;Jeq^CHHynk3dFYj@l?bS!zk-0|2qyWc)(>R7olZ}rD;QzA9g!L$IbGuOIFZ6x_)`PjMLtj{Sex$LJt zehPybM+Jnwe*f?l1G<)E*kdC2YBoCp#GFK3Qg|dtyQq;<8%?L;B~CHnKeYN7QDt@% zbX7QdEOSHlvBtvnsfUSTwI`0GzPLWsr-E8k&Y%RA2?8|6SS)TsmQPGeq%r7i^`Q`G zx>d7DsziXco?5;4Jqq zbDHj82*!U0cs%7yS>ou(-ogpL^j%EV>( z{#UGI6CE*Oa+{05CB5cIvz1?(`w;XkgaV8t=qfkHrK{QDGVyS`Dn)lIG2IM4HjR^C zewl4ofz$JGbo9t27=J`Md)+!Yxb(!1(YxK{38OwYML{a$#n55V#MY1wwL_q&<+AR1 zBb0@6SwM@JvmjCHK$O%gh2KViJOV46oLLjRWCjC`4_zhbOWKPCC(U#_u2OoJ0I;rF zTC#*p_Ij?OCs72O z;(9S7{Nan)UuI$^AM8t|24iw`7YQxbsVwMK71E42L)(9e_G8GDIRUJ<9OyFc+SN`z zN@MLHUZ6RYy();>Lt?V~yQg>QbR5+Yw)nkXNRo>G-IeMDz)x04tOhEnJ)Hrw7G8Q3 zSdPb2QINae@;ji4fYxD!vDCj=02;4S&FhLSHKi5CFCBF@k?>7E3Hf3_J&$o&V3uf| zBv#Z1M-HRRoPBL$#=DHKkI*knXm>Uf4*v2^C`>_;7HbY4EH+yD0aM}clxw>Z=QNR(OTW6O}4WL@tfZc%j^Qs OkHPVi$8vRWH~$ZZeMp}G