From 1e7126f98e4cb4d4c93a7d4ede41203c86236582 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 | 67 ++++++++---- .../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 | 98 ++++++++++-------- .../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, 249 insertions(+), 86 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 000000000..330dba7da --- /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 71f63b98f..7e6609248 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java +++ b/src/main/java/appeng/client/gui/implementations/GuiPatternTerm.java @@ -26,6 +26,7 @@ import net.minecraft.entity.player.InventoryPlayer; 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; @@ -40,13 +41,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 ) { @@ -65,7 +73,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 ) @@ -77,34 +85,44 @@ 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(), this.itemRender ) ); - this.buttonList.add( this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.furnace ), GuiText.ProcessingPattern.getLocal(), this.itemRender ) ); - // buttonList.add( substitutionsBtn = new GuiImgButton( this.guiLeft + 84, this.guiTop + this.ySize - 163, - // Settings.ACTIONS, ActionItems.SUBSTITUTION ) ); - // substitutionsBtn.halfSize = true; + this.tabCraftButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.crafting_table ), GuiText.CraftingPattern.getLocal(), this.itemRender ); + this.buttonList.add( this.tabCraftButton ); - this.buttonList.add( this.clearBtn = new GuiImgButton( this.guiLeft + 74, this.guiTop + this.ySize - 163, Settings.ACTIONS, ActionItems.CLOSE ) ); + this.tabProcessButton = new GuiTabButton( this.guiLeft + 173, this.guiTop + this.ySize - 177, new ItemStack( Blocks.furnace ), GuiText.ProcessingPattern.getLocal(), this.itemRender ); + this.buttonList.add( this.tabProcessButton ); + + 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 @@ -121,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 442e37959..ef6f9c0d3 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 b6c26afa4..04bd69f08 100644 --- a/src/main/java/appeng/container/implementations/ContainerPatternTerm.java +++ b/src/main/java/appeng/container/implementations/ContainerPatternTerm.java @@ -70,15 +70,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 ) { @@ -87,6 +89,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++ ) @@ -155,6 +158,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 ) ); @@ -237,6 +241,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 ); } @@ -268,6 +273,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 }; @@ -281,6 +287,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 ); @@ -346,9 +353,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, EnumFacing.UP ); + if( packetPatternSlot.shift ) { inv = playerInv; @@ -375,6 +382,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() ); @@ -411,6 +419,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 ); @@ -449,6 +458,8 @@ public class ContainerPatternTerm extends ContainerMEMonitorable implements IAEA this.craftingMode = this.ct.isCraftingRecipe(); this.updateOrderOfOutputSlots(); } + + this.substitute = this.ct.isSubstitution(); } } @@ -518,4 +529,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 b740b9693..9384ee8bc 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 4d251ed7d..fd7d0ce58 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 23ffab1dc..ed0ff5dd2 100644 --- a/src/main/java/appeng/core/sync/packets/PacketValueConfig.java +++ b/src/main/java/appeng/core/sync/packets/PacketValueConfig.java @@ -58,8 +58,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 @@ -157,6 +157,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 10db819e8..4d0b77c29 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; import appeng.api.config.Actionable; @@ -40,8 +43,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; @@ -49,14 +52,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 ) { @@ -68,6 +70,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. @@ -86,6 +89,7 @@ public class CraftingTreeNode boolean notRecursive( final ICraftingPatternDetails details ) { IAEItemStack[] o = details.getCondensedOutputs(); + for( final IAEItemStack i : o ) { if( i.equals( this.what ) ) @@ -95,6 +99,7 @@ public class CraftingTreeNode } o = details.getCondensedInputs(); + for( final IAEItemStack i : o ) { if( i.equals( this.what ) ) @@ -120,12 +125,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 ) @@ -133,6 +158,7 @@ public class CraftingTreeNode if( !this.exhausted ) { final IAEItemStack is = this.job.checkUse( available ); + if( is != null ) { thingsUsed.add( is.copy() ); @@ -160,6 +186,7 @@ public class CraftingTreeNode if( !this.exhausted ) { final IAEItemStack is = this.job.checkUse( available ); + if( is != null ) { thingsUsed.add( is.copy() ); @@ -201,6 +228,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 1dd642a0c..a2bf7ee88 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; @@ -44,20 +46,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 ) { @@ -71,6 +74,8 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable tmpOutputs = new HashMap(); + final Map tmpOutputs = new HashMap(); + for( final IAEItemStack io : this.outputs ) { if( io == null ) @@ -131,6 +140,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable tmpInputs = new HashMap(); + final Map tmpInputs = new HashMap(); + for( final IAEItemStack io : this.inputs ) { if( io == null ) @@ -150,6 +161,7 @@ public class PatternHelper implements ICraftingPatternDetails, Comparable!lvNA9* za29w(7BevLEdyc3_B$){85kHON?apKg7ec#$`gxH8440J^GfvcQcDy}^bGV&Q(KKv z85s1Bc)B=-RK&flt>2IuI`!V{O-o)bTR3}}V3fqqhaZwfb|=ato$yGRA(pFce6(Rk z7>|(|S7VT-kyez(rBF}iMV^^g5_pwYUOY65Yt~Gyw0|CpX3jA1Tsp&O@ywD*N;5n+ zJhESDWcW0`sAym9b*uclrPuGJzb`&l{d-^e_3*D(Z>GQh`u6wZH}9=~-}}Abx=f#8 z##6hQnw38#`Rezl-d^@jY0sAG zwTv&XY-Hqc`*Y1<)5NtKWr7%ddOvLXJzVwpGzr5%>+HR}XJFM#)tFrWL>h9Yd{KFn~&usPOU(cpRa$I;R6Hs26 z^zTE}Ee57F&ke))kN8Z_J|?n&x#;A8UlLxeVOU$Pd%fqM)mA~$IAT>Y%)@apL~2jx3|qmwUZ zHt;aMdL?k|irxcm`F#s_{(IHExSw%J*0EQr2^MB{0a%2vUbD;_f6F4x>Lp9@RXC`^qZ9%?=hT+-C&rrY+n7h#g`dglyW>sZu%&`Eqa_>;32!edpT(-Y+E$W}9rvIo_jTTI+F^IiW}M z^~{iK2bmeJmsK)3NZVd({|xbK&a!*ASU2qBZoD0(#Bk-VyhFqSG4~e^TfSDl`Pp-o z*Ud46oQ7;yEIc*DTJ=xl?&L^z7E~e}5jBS8o3L zqm$qM>&2II>}LFL$gN{wYqc!)m}J>=mHAT5rJRj*oa-2O=($aDX_T7B?P0r){Xh|m zgAU6YyOj$wbN(#;-EXqL=)<0a`Jd8We{{D~Wa&G1;@5}I3U_}7$E)cvC#m&*^-hpU z^OZCc-&tJApySWbFyk;6gWTn>CcV6O9PfXaRm`^kac)m5uVb-yS5^d*> zO!e?ztTxSv!C~HIspLy0eW9(XtJbwdr8yWaU4FK@%f_t)RsRpn3Hx2^H`tCy))+|oB} zl#yas;~p&)AAGIR%amJ~Q+&1!f(=TzN>pG!|BKb!tnhRMWNX6dq{ z`QP_c=q~#wSozX~E7Dwzp@ic?fxZQU!;61Mb^mLwTA%x1V^x);Hn%oI(G6*aJs(su zH8|t8Sg|D3*#%{a1hs!o{f8X-|^sR&& zADaXbA$|I3RK zff9x%=h~m2)8S=sU^}2(|6Y;5A(u;%L35EGn@bUUgX{8Mj%RvK*FFpGirHKD=29!a zLwlvy7K7z#XHG5Il%&AWcCP(810N^D0p^6?&g>0lyVUyCnHeOqU9NrJ=%Oz_d)KCe z{gJN(DF9oHiGV(p{yXBHWI zo<6~L=J=9zN)F#$Hk(EKzj5++lbrjjTb~*#XI=?qS-XC3L+turUN^FqO8zvimS3uN zbk460D|9?Q8)s^8uV}BFxwOj6zIb;lgDJb?t8D#*>#O$(ZHqEf>d~s-E zRg~N33Cpf8nWPe+e)ja4tJ$B8w+D0hwBF*r@paYumbKG*Pqa;acIEk<>*5SH=YCCT zn|9Ia$^V{1N%!S%I^@rszH?&L>-u#QlulYjm}*X1(;PY(!gLC*X51b3b?Szzn*>uC zPACV@Th7$*d}GGTLx(0m_%EcJ_D_b{S>8B*zFhgwD|`xDxf?XUaQjS5k=?dv-#4bR zy|1(rS3k{`zni$RMs*)uv=$Y_ou?*l-;r`?XBvH%ni;Cv-Y1qAj6>0 z&R}xq`ts?=wjVmcoG|yomAC`z!fRD?w$|wWW@>o7rE%sO|BIK}Th$jbH~jZD@zgR^ zWM*iIo0q@j9`k|;!aC5v+&9gNVM}J}ZheLwddE^27*;YYn542`GtZpW+shd5EE5vW zQQ-d5r0RJsQHweHLezv5SsMnfoxERabW0fu_S;=&n>I!9fXn`z?A(Y7u{8_}7U~pm z6fjJAb@Rt359dG+=Dja{^P?8jJXAPoNjjPiRnGB6mXojv+@mz~ZY zi4=x_aKU4*606ioRU5@am?o9p==ueVNwMp5PO80KeC5cD)tub=tP(S3H3vlRzZ(dP zr>JFjd@dOk<%GgR0+LQ;qDAj2mE?KC- za4fjHNt5~ThL8VGzrQCtgNt#`!sC6i-k)w|ub&&TKOw`>%=X9E_4T#|iY!{v30J>f z>e2l6ch2(8s5s;1IyRNZ>~ZCHOFtemspz{XA>ndVDp%^k@%z=wlC@Yqq^-C8pY&s~ zyqSz}ZT9^ik5d?UE|$BgMV*)bpIxN(%b@Mnfm3V|rF&Do)Mm>)nO%75jL*8sj16|H zr%k(Pb0Vi$MuKV0e5R$lC%!qp&4>Ab!KFX7iVD0r8&w!|jxi~G{iA!X)ghI6&8|4< zNxbKmZS62zn|w-2mSMrV<*8fvM7FX|W_D`W8mw@}_56DNKRfnrH8>=`|Hsh;i8hmN zlYi#-OV7!?-(OQ#XZGRN{{P&wXEG*aIXd6}{zvuwuGi}<<7&TNy~?}cRh3!N{FjcI zG1@E@eDjWHH3vDL*5DHPBBpBKa(BYgF#1w^K3+=Bbdnr{OSVqC@Qa%}EH+(KT^gCX-^{4v>)|PnGfo?>T$n1t%2m}Z zB(W&ncS;5Gt;L-S85uTj=vkTjcRN%J)ET~*?K5Hc1vYNp$^TIs*%>ZMoqott zWu`HEZoiM&o@Ykv4B289k50QNRP%{4c^+^u;O#hnjNk6ZgE^5~UaA%|GyI<_-*H?@ zh{4{Xw!XM1*Zs44_VO8w6RQ6CnC)GHFi%?g`K1?zQH%|CYS&+wX_#*5S>)iDKaufT zsZ3_wf($-Ekl{b>s~_c2;XOb9_e>Ml_FgWA8TO(K75^4|{j>DpM&*W=Gj(r?C+eJu z@k?k3y}r3H_&>M4=jkJpHu1gYbea9T)K+(~M!Gv_Fo2}mzH|3%0koo{6gW7t|(E&c@MzABoMcUQhoSyU`|EP9%#EI9 zug;S2N+^O+;r$acl~t}r|{|djBBO3*POn3!Dx=$r9aM24?fr5 z;^AVS&V-Lr+x?X$k`d2Y*{U-Opr1*pvC z{IW+*<>rwZI~A5Sb=_Ndmba$XsZG^!m?iu+eSfqZ!>vDIw`T>vXSlV_fo=QG3|5Ao z{|A`)O`gxMuQT{xegF5pcfQA1ZK}RxY%YF&PJr)I@A|zApxV)*ao%+f;b*<94(m3$ zvoqYce7VK?`d_gR{f!aF(xd)+aQK|OT_^BNpO@iE*5S`KoA|GMekJR0-%yOC6&uV>+AxI0=wIiQj+dIJ`FrWHBtPEC(;nIcxxMFRP!MBUS+B^k?8vtH zzTD61cpf}I&Gx)ZhhfLOCwmzgPHYop_-oRW>sElcPOp)h>1oMV(cgyde&ELV! zaQW+8!JAJ$-N{<+#PHX0id0nF>j}pu@WmaaY{esRc~7*O;U?t1zU< zPk!DpF?&hdw1-v+Jf5%48QD9xJM{fDT_cbXP~C>4p`*2n_1pcm>srF z*Q?ic-9)LVHtFV#&)5@g%+Y6(G-63%kjc2VsQADIhud%Z44J|h9`IhPXFibje4CAW zr1i>;21S+!nM(G)(tgNN702(BTV}RZraSQ3vA!z4s5WW#76wyx=3}})KPT`pN-}8b zvODOlVR&FJDbIY)`n^rh`M_E6`#x?JU+_9Ko>Tq8Y14x#%8xZ}hpkn)e(Z#4kn`z+ zpA)m|*j`yO{MuqrqUmWR1y}2B?6v9V%&^{N*N$kIZsFOkZt?R)iRMLJrRQEjvo^A2 zN?Pe8JP+9Qc|yhM=zEtMO0o_`iTI`K=>|`qFzw+t#@S($+PWC-Zr}g+?E%H&13&cN z#&P?!I_#Km?VCaS9)UF*Wp>q_ehpR4(DUod=l|<}PJaGB|3Q7-zvE}~?LU-v^Y;AW z|MPJFD<+1wlPsG)eqV2T_M+rPH+kOk3%@ZHfx<-Sg>G>4{NIkNr%ijv^Ji(KJhWtt zZwSqvc#LvP?-5+ z>-%l*3%%{$-{xfbET2(%JL>b?_chBaKb=%(zQ{H^I!)2xDdSf037~MF?x25GN0WEG zufFH$0yZ;+xq1xU_QwyD>}rVlYrXI444;>V%gP!4|G8hMKV$w(F2*n3i@hH&zPnxc z#k)Uif5z|1C_A41Sea#mFo$Bp+=d?(0o9Bpa{bXc3=B8_oY^OEV2**=uO$}~Yb04DoOy43s%+U^ zpPf^4+djQytMCDdtV0rSnX>d1K>0G`;`Moxwyr@(9vA0r+mrOk5V zPZ$G(MS8LK;mtR{N}RO%pvR!r|BfXuyOUwTZhPc_o6N!>R?%b0wyoq$?-k-@U^_2>TjGB7dJZe(D%AkW<}qQoGXS;$rlc{ecx(XE6yp81h=@gZ0S@QQ3B!6y9 z*2vOl0L5+|^WM}~LYIuncwFDIJ^-bh+y&R$w(a|SeahD@J)i5F(~-Js$jmd$2flub z;8VZgZQN{NQD1pB_pbWuOv&>+1=nNCOON=+hu6IC>if}dI^z-p&)Vb78zb9Z&6JQ{ z{JdU+WqoEx+&M3+tLl<2Oe<$y zkvP06G3v3S%7Wv%r*=q(lEh(z&rM=7(;{J)LmhBU`6^U3qQl-qb9CWBs)s)jiE-9S60aB9=V#J$%;u z{vCsr*^FED8$g8?c(_2S?f-{%`#Y=*w>AnWNS{?WyN>&*#MFF=8(+lN-IcAl7r)<5 ziUpxzeXZ8}KL-1Fn6z0=xV?VBm|0<=6^QZXXji$#|e|mDV;NJ4qmH!J@AKW(o{XY(7new%=v$z?r6mneI#{epSO8#cp z)|`BH+%UCfORDacgEc~z-dLO}o8QTJ<-s}qv;F@My3L>V{@;%?=gaG47%TeH19N4|E6i-({mJ<3$6(F;Mxch>0ir{a z0bCe5NS{$xJlnT8=ljeVjaK_UKc6w5G5E3ZzB{ZR=E~pae6X9b@;iH0JUG+ts@pQp zR?AnP_k7y*AX!!J=Y01yVTjJm}yH0-X^fb1_ z4-pI*pPN$_S9%=wzVxAuS&jXpc*CFT4R_pCWf6{vla@-ke41gy8U9JV(}Z)XPXFjZ z7_;4n7u4$D^)S1&>%~2n<;AR-GiTjQubYswW!Hv#A`BB()e@2m3HX)7HiK#weC6+@`@XS)T4xJii}UEd|8wW~^DvGHylEWI>@R%UmN13Y zWcwMX2EWrE51*dBRbGCMpyPrAj2FzTnXDv!F*z_j*Q|ZZ4eF^lT|Ynb=C04Li)EQo zn2qcq_5KRmZRIsmvz%{m^8B<=INQICF*l^m#H?>0v%;>rr(biPT$vj`|FnRD^cKbj z$Ye}^i-SaV_Dd6f$!F}KK9V~_+f|pnZ9H6T=YoIT5(hVv*YT^hE%at?a8{V1aOdyT zo7K(=<>C`E>l&C9STo~#Z}2$;z0QsYH-2~7&6sia{IWjD`>S}>HZU=Cv^tbAh|G|m zV9j9X#bn9I@F9??R*s=*-ThBhnOQfV6;C*y>TrgY;eh?`i<#`QOh0C9_#nt||Hc0o zre|C2e{KEx&*?MsK4y(2ufyZ?eb=8od(8jp1l~ux85TgMLcZLUzyD&p+x_2@&CSIB z%-?QS{qMW!(P!*6>;WFv*YA;2OKaY|^XDAq15$?tRiw`}%>VHrSbpv~#Tow{l3t%L z|1&?vGI`-o#`}ySmq004dGp4bPjYHj`)8eCGk(xtTpG5tW$;>m1+e7v-tiGl+ zmHo=T21v$lTIguDmxtl>ABCF-+&G$I9_I(bFeqClUceT^$E2=8ey88G2|NE{!Kczx>&D%h}pS@d-6}_ms9)2x)nV#a! zjNG>`m(S1h@-PxM(4D-Cjqz9g&$aog&sQQ!&eK;G{P{EgmxP1aEY<`1_rF&>xRw0& z4qN4)dDZVar6&3QKE$p6WmdQoJ5R|B<^zJyZQLd`pyW5N%i`<~JhhApzNZsD2YHHo z`WV>%VZsB0i~X^`nRdi|oqFNx;;++I9`xmBIK8E3&fJE&nk%nm8@}E^6#V%!rP_|? z|DOb^C47Y$e!V+?;wEcEKR<8#@ww))S8JXgl(uD1iQWIH>hzVx%nSNwZ)8qzVBhoc z!p~Ta2`WfMxo&VcCj&#;)!hwqcH2+*{38shklma5>LTNZ!}9+wsPrFaVt6o@p=bT} z_aRA2<_#sN%1$yfw4LW=U|5#^$YxvZ^cUO;KX1(7Z&`<^GIWE(`5Cxt6$PsQ>^r^= zIWQ-)Gh8-G;0#inu$g&-+-_to{Co@&Yx+a%B#M6PP5k^L#Ht-791ne%6b3H0kg7Fs z6z9g4fEmm56!n&D-FsS5p9NG& z-vXOtq5?q(BsIJ)q>zhDZY3PDy_Qf+eL>>FQ;&)5p|JnwREcvZ63&foF; z)aHoXb26Vkrqr&HH}H);bPCqs-0pMs*z|g40dA(KW3L~u>WS})`(hYTx=X)Y?^wuJ z%g;yVWqW1M+SM`@)`wZod-j<7Y-R_x#&ye6Z4L`Cdqk9Ov@A9ZtvzS6@%gMvvzF;4 zK1FmVvL}nPH!OR{-zpeU8g<#c9crj{-x&ji1Y~pd&z>o-7kGZ@kB=pbz>RNiiu0!Ex867sDgJeW<|0!s2tm|HRSD? zJg)>UB!7}wf^h5afL}Lw)@sjmzy2h{H+cGnPq04Z)`e?h8GaSYh%!t{ywDK3{P&Li z{7b(IMFoGFafRo>=PCD4te2K*xtJ>OVP~lK=^KV3%T{_vRKogW(^k#|P25OYw}FS& zU@nHV!0`xH3R=u%&X~EYWlN9j)`ZxQ<;K&et(>X-TlRqTx?MS^_iQLoT>CbbuTn7r z)GVKNJ$f12(vQK44yOyg*+11$Jn8eIUOa&(Z~xzKi!2lVW!L?U2$o{{vGd95_`g|V zf!>?=u2qXDdm{R1_l<{)phXU^M6d{i5}@*UsfmIG+5!J&s}7_5Vf!yrRs{_J6-u zJzG)n!%zF%E+>X#Znb&Mswm17#UgzTW`r2AXR{x0k^jDUnLb0(|7{Du-n)wEkZ#Y5uHDO+pqpT@ ztwXg!o#FB4x%=PGXS+V(+46NC3K^DM);X|7hN)Jb`wL$~Z-4PlZ4F+AJ>e_AuR|Kx zc>Vc`gzn)IhA+BFyffx?e!jAwYfa+JdY*&`Gy7W$zLqn|Fj#(JP}sF^*FB@HZ@Rx0 z&z|;h3uA(!I?FOMdxpc1;i=7sMd~?3s{jAkyZPRBcz3g3a`ySPc9njoH`FsWZ*-m0 z9m0{*@{@6f?ep#fzoYcc?#E{r^{c#Y_|E^{w+mFz!HSLPX>3ammV%mjTX;T;8F)Nx zW^9gDyU+32IN{$udwx5=W9Muq<(R-bpPAevt8Wo%R>I#SKNoctM63tY{$q9 zdWyP-w{F$1dC2X{>6!NEAiI3dj4P%R^M4#s?|Rno)Be-Mev_q&1&@w&J}aL8I|h^^ z7$j!bJ8J&)Z)}8z$#x&zo8N62bPq=|)O?yepU0-|&kj$y`WFk^7d>lwx&O~oee?L= zx2_*5^x-)0r{a#HV#9GgPDTmoua+*lCz(xBGDzcEY0J#)cW5#$c>nK=;qHb>0uC28{5&|RpV5lp$=vu&DhxUw zX0SVWgHpe7^R%A_7csneoc4yHp;|Gz?^-67(DgBC-=k2?$u2~}$65}(`=*l@<4 z%|K_ie6E0Flk!xS0){6B<_t;yT~%K&Ubysi@mEX61Iwo0xxlbtf-qC?Z25-7n}4o| z{#tP}@r^vw!3zmG3WZ;46tDOxxl-T;$7g1P>YUs9h2QU%oBP{* zbeUYOa+Ar1feWNol3}OffoJT87qJR37?jJetT9L^IQ>LAv5xIbe(rD81P=-8?;e|2 zpVY7%kO_Im_@Js0lFx3Tvzp7oxf ztZ`SVz>56>cvL4ZHX^_4@=h&q)8eAly`SgG&1#oiI+4Gi9HCMrya@X3V(rE1F>$A7e!Z zpFuc}C1b-ZyP!<=FH;%5$}#AIT5_3b7q}SY9v4e89c&OvxsYH|JLOn+Vu#(*jeSM) z5DlaB%h_3)6hws*0~zLb21E$s;=wLMT(CWBBOxwnFB&A4l+mdybSKobUYV~Xrme!O3$;jVz}jOFw5>3kIqCR<6{~BESJb# zwmS7Z5LwymnU+=z0SSRp`fXEYX67)iJibL^zWZBl(1@1P_5N#zkK|N5d%@7bm~1F) z{Oe1IS^Jb@O*L|e_AbBh=9x1WGcT}ZS^P5j%mE?iFPgojQ$8aN2>9?AXCHbJ#!+CO zRp4h9#ePN<>~7DAr=B(Z6FO0e+#QaYHUDIC&ADgnC*58v6tjYjOrBWf^ZEs&1E|-3 z^MsE!gUZsMj+-u8C9D%!nG+Pzf7yLf6~m5ua;G1H$EXY{x^~UW*;0COZ>QgLt{~}M zQ&JXJZHSw4`Q@3#sjq}4@#em<{r%?IoA5nJ&cRB11hT6qJJ%^g`pnTW`7?L5q#Uk{ zskrFM`{UO2z3X;9dT_A7Cj0-tM+y~(L#LZ6%$>F3FB@nA=)%{lUvpAkf3E9FV|bJA z`|sE4^?7`IK21H#Djs)Z&oA-#+k4(!Solm_Z||0!KR$WS{(R1Uf2HfQK89n*?H`w3 zK5MS-yx^Pki>j;PPS?Y)pJsSaCV!T};^~y&LuLQP+Ouzo;>B))=hv!!;%(VOYvi?HMopZ&PtKW6BIlMK8bZ^(M zyS{8&-LJ`0wkq5#$bGxzvR}5J{o|fzTkh_jUHki+>GOYoSkJE3+p%Ehn@^`_GqcCt zOsF~DCwq2YZMvDY-(5johJBw8|Jm{T@E?w5?e%*u@igAb2Tz~G#>bv_lapmI_@24^ zZQi%{_PcMEfBTnqexB{wb91emU&h~i$5*!fV8OGQ>1MyrS*^DGdL{TQL&E3wwf}S9 zb1{BcSAAdHiNU(@e9h;Xtpdp5`Q##FLqEgrvbS01ET7+b7P@|y!HmB>W$q38?&eAy z_>!S4Qugl7RsjYBv;5zQH4^`}zx(g-x#DvS2jd%tyo&GnZFQ1NTkku7Mre2K+cmG( z#)_fr{Y~k8%m?Pmm;b$6o&K!-qafdl+q=v2rFnkOy6kU%mxp17{4)ON|I^(2WH_Jg ze{|tsLS4(j^?#o6$}#v{-(9x^Y|4k5^2gj59#}UNpR+Z;^D?pSL(jH)e`%o~dJOXH z9@iL`{X1Y^qcOv#<-q-4YXumt@Bevy)@S}$DJO=xx5YZ#`1QW&r$4_n^Q5zl&J4%q&#X_Ym~nqUv%!n1>-|@} zgQpiLGNi>boqP8#eQv8hV|sb@oxkPVt(j-k9q$W1Y?0-;jX^@D6z8w0a-lX?2RkL`<) zwYN{oiQvCG`$36SH>eSla@gj<{}W3inY`_19h?2AWF1$0&Bvn$-*7in>&Gv=Jj{7M_$RyvZ^f|XW~s!9jS&nii#3@x$r>A6&tST1Ion)# zuHOY_22ep`$q-atbwO$~lY_LcSV=7>v$yYcv9AmDozFLairF-KGomw`%8=1)TxwBZ zEy{4}BkaN1&uJ0Zr$K#^? zYR=oNIcyb5Z3L{pGcd&N|MY84Kf^3;#sg_i!2!vMJ-lnaZjx`0EZ*D8cA%6+ZuaXO z#oyLW(h-P2;9$u8A@jMpm{GwX-K3c@$KmR=(oZo(e)AdE<}a0FSf?J9Y!lvNA9* za29w(7BevLEdyc3_B$){85kHON?apKg7ec#$`gxH8440J^GfvcQcDy}^bGWjd!9`X zU|`Ts^mK6ysfc@9TfZSSbn3mio0hy>ws7_`!6=EJ4?iS}WJAa^axkw?ND19*lgOf#Em;!D0NpqT{G{bYl zBm0#`hEL;*iuToBx5~d;di`Gd`{H-izweb_5C3}AGJWpXx4-XM{{DS#-*>wgorewC z&OZ4*dlrxVp+}KS-u6?D{`j)o{_c?@XX$Sf79LNMS^j+ zY%?9KN^+Q*1oxXx$Vqt}!>7q0*83s*X>-Wq#*NFIpB*+b<#=5GDtJDZPb&lO=9q?$ zncJH~yA>ts>#LLdd^-QSvM|=QO`7kVyrxcPUj4tHY)cNuJ^7;V&G6xJULeo@C^@lT zza;Xla^!S^lV!~6<2f!E%x+c`o;Uy7*C^U-ep;>4UMKCeW6sqJC? zDb^5g|6JFh;=KRqe+flgjDJ737w78Bmi_p1-}1_yj}Lxc{MZD*tU{^p_*AC{m?Rlkn^h&fe$ zUwf{4A1E-8Q$D^W=c4ByKtnH;2T!wwhbGd%IRA+jwfe=SqQ{ni7yx`GU^Uh*sGT&yw3ObTL5VZK=z64L))>^ppReN5%O2i<$FR{fdi&(WwHyveS{*2DkbmG;il z4KqBGOF8GXM+Uc@b$u5h$8cJhLE+d2riSw`>!gmc&0COPan`a~zev}%=iGeGmZ$Z* z<*PsCn{OyQ&c@JS`0Ln5hKO|x42FGt3^{A#q|&ODSPssTh))uHcD|MUz$aFQ700($ zIY=FQDA9KA$W#w|H(#Aph6bBurG1`@l*_Csh z%@&pFwR2y%ygpFaTarP-yG|nGYlF#|XAIBMgEE&E{`v87&3)%@w%_j*d;i^i-Rwhz z?O!R=jUkK&9&h*=_*j6U)Sh>9g~#Xo=>iQK^Y{P#cJIFPH(uU`jn`k7%kMPzj=y~% z`RkYLD{koH|z^`<%)yjSYjxXk%m^I3ggIph6n zia9PA6i%5XcK`0@CtGLy^0wgpa`*th{hxvxQOCR&x@h~}K7P2J|9r3LYiTKlPgZqb zw%BLM&HwZIO`!lo{O?Q6iVXiAEUuq-1?s=kOn+>;lf=B39E`LXDwvu=PC4nYc%9`x zOp~mRBESWN`YfpZC{4ur`;u|LW!S8@Fv>QfS}H zctF^HlAr3q$zkmbXU<1w^*X&O*rTI3A-T@sTQ4uezCP85n#>RK<^Jq_w)*|Q&Cl}x zAA3LJ*DW@=)yw0Pa~CozeEl;0`6NaK-W8s@o-YI>vg*{1HLgsEld!ygBzX(Nz4Mpf zC7fV5A?we6z?v`C(1M{t^ux{bb=P1X$>x@1(ERMZ=@<`#k43J-$$gzCs`j4cWPH6f zFqyY!&TkR9#i<|It4b_5tQd-pA3lFhhnK;D?ZDys_m2Dxxm=PAnv49|T#8s5JeT)! zJo9t9_E~IK%-*`Umpb_!+6%q57%W#ib85-9Bn5`HzV`c!GC~Xu><7NJ^D*R>_}b0q zVMtgb7iD&0n5ReRf4B*3v_P;aE@m{nQKw204b?(mBtrXgRPoz42#b zFgUVDDEZ5prH6BP4C{H4&+?zx&ft99nc>1a1qFtTa=xv+HevqzkKJNYOY=%@Hezw8 zm0Obds9|A7xxld($M=1U=rOfdU``NxtSbdm>NIQSNjHDV`QTgt6Fg*OYMff5#``!T zyhJS~@DeD(d}5uXj%{4E!RKL&Y}B$lUYAU|l25P~3T^#*nxjU-V|TN{*F>er(~o67 zxokQ2^upK0U#DqqpJdXTbD+jYOO$cf@!2O6{w_W*%U_kVa?7WN%9$ZrP1ml^JFqT% ztI)QnOt-r8_uN-{8ZNi@(c-@J$H!_a>zBiO&IH-cp1L5`-&{IFn5k$_h`sOPNRP|eLEb_yCO=Dk_G;_TnYT4r#9D6&-}t&J>`>Tgx0J(P z#jldrePv~spI+3$~v*eaC0-SNm{}i7B#c=81S-JNU{I!d$r0 zwlQ{nmTJz{92ZH3qSI53uVi>os1voz;G@cq{Vv@z?T;V0aQw{e<;R2VwlaCFWlG@s z%e~BF6W{6;>tQ-;^phDCw(pVWX2`6Q`Ml5O+AV{RDmM;TvE0~W$;hzzl|Vz^_A6OU zXV*JBTw7VnC&$nlbAY96@2aUAu72A4hMU1tn_TXnxV9MO@VPqCIE1^@X~=<$O~Ws-3uctIy7#UNd?cHfh;J-hX@(`Pvz7P4%7W z+|I{(x%vOo^7ni`tqgiEHYOjRwCCNf*J7*S3E)zX=C|6p%RA%d88`1^Q+doDSO53x z$73cHJr^Y;T#ic3nD_JR`g+@%`~M!lx4mm9%CzIg!v><26n+x|7X9qN^kofYiDgIUGeGt|3hhM3^SrGFegmA?Qq`hjj^pp zZ+0s~|G~!*zZYD&VA93JyVsYK=i+8HuRl(2ud%d-@G%Q8FgQ6#&DZ4pf7d;KR$@NG zmbR-pTn#+6uqaA>oOIf4`joV(rMW2rpW8LhC&$m5EH%q5aKXaunvIH8*IYWeFXZ|1 z@G{Jp>-=Ed?su8%i)2Y6JTbYKQpJ|Y$_kawKIiB+B+S- zNocW5a$xvyS?>LR`HBaP0xUkcRVVK-9H@WF{%C6(%K?7B`}b|kZ(jU!@`(sP!^zwQ z>CKxq7V7lMEf!^1VYt)%eRGiWWeqNqFJ_VnvBxJqWA8d9pg4iWr}KYpkPgF=hd*oW zC%3)W5Xs2!xtc-Z4qKI3-mChDs+lt*g1#l%HQso>>)rB95mu?H*-8m-mCl@R({oza z=G?&i;K#?uvOhiLjrY136l6zvN=Q65u4X=P;qVV1eujg&3)(p?860FbN6yTt3YcZ? zcI^ejhN?^{*T%Mc%OnyGxX!58KA?DjvEZ!fb(U{47k!Bzw5Q9Ss7A#a+m%%J3aVZe~X8U zF|+QU)Fyov3x->FH@tP$Vo3P5*uCFudR$eeM1SRn2M3?ozOOugr**w8Bd8FMX_)uC zS!MQ&{`QuJ(Cr?V3pQ>zbAHJ*OON8D|1;lDV{b6qzcs&iWjI5w=7fX4_iSZiIJW=) zzu&VzpSQQ4@qh38+Whi~h0OgjmY3e#*=gL;yywGK^#!0}f&0Q|nZ!eTHZq(r{q}<4 zfx5bE+3{U@jQ=G%Qfrod?Qc0SWzQS-#DA9<9M+rJ^ebmCkPBbW@N3&fh8^E-Wix+u zeYTyEgSCa>o98pe4bQ49{crrZ^uZ@`x>UENtVCI4C#W(b|GGt-^% z+pM8J&dlQdai)gfp7*2~8t!aoda&>JJML%4d=Gg&nB=X;DYb@eL;d%=<)2xz^IEKCb~(XX`oi?>ul!hm#>P`ICfU zQU8?-CU+Qm6g{8nd^RrOcrqjYFc+iR){+C~m+_uc^Pj7{b0<@W;07iJ`A>>0H=aZY zCdm8OtzjzI_)903kS-1%(NIXGGL%l1`o^9Kjb?b=FP2t;Fy1s{x9_C`S3T2rw^{oHW zfW>zuGZq&ooSd~Z_6XO5XS4J9+@_0%3;Wjz{8stQ5K+8$j{L1BH`s4(DZ0PtO2iYn zl?yX>SW0BqF|?iisW3s&*@5jqW15gGa~s>OyLr;e39Jly8~#Z%m|4F+ojhr4vy`y% zbnY3@us{E~apl=_%cea~nzDD}TDj(B51%nAI_z#{d_3(>r9pcGPs5aH%nIUR3?E#N z-ER1N&YJ&uy2e?3{hGI&FRDVdA2NL@@-w)3;>M}k)!~z>lOc}zbHdb~`L7H^ZIr~W zDJrtPw}dZ%noz7SmP)GL{NuCQJvcjQiqx#O+ro2dN_I?np*FEtSMzK{vk9-P*oGpF z*h-H*Pj&M%9jr_eeYut!PoK8Z+v9SX>u4Ztnef9JI^*<*+|2O|&Z~y=Cv+eKy?>@@r_MiRVhxk&) zhQE^xn?8Q`pY`m-lpF57e&-i_V<`efI_H;ZE7yMiyWpz#KdFM^vC}=y++_bW#*5Q<+ro%OzQs~ z#&qxxd(=I%%zdBdzBlo=`RJnX?clR(nH&Mt4sSW1fWlqq#nPFoOCN51shTO}caUw# zVatS1&n0H?J)f|;{`hvO$(pw3UWy*D|G)h{_p|h6P7I})C7CsEzOQB3rCy)?Z@S(r zyN@@2a4@c6apFi&Rk+88aI3UcYT0WU-@}?>sR>qdoY&nmvY&D3@f;q88UOG9JsO|Z z%5aS3=7U;SfBwGb`OFK9cXBlDWXPyq*tiWIjJGc26lIpJKE@+FqtSCO z4`YM<->ox*85CyEzbVcnA$-iuS4#HSbjOC`7YFzKu{?Bnzp0ts+xdpOqBtMOR2{O6 zVnuRPl_t{xBmEsStL8NStp7dV=C;i*_y4AnOdA;{usu(f!OnO;TQM+viBLT7Y&#Rf0mIqRQuEHPJ3ny^^LnO)PcOV4Y@5cx zQ1y#>tNH{`0q(uvdRv?aLqgN>8OaIW$M5*qGS?cheCTDE{a^e4$NHI!3=58_9T!{A zdTQ3vOisxz2cD`NW2cKaCqV{K^0Rb@KecYNnlWSG{(yROMy_NX1=x zwKQ`_E#u>?ODk0_9A})cdLoBBj}k}JC-yqAEPn-1&uO|t{>)u1pxpYQlEtI_=!u;t z?y3}6u?Nhm{=FP~24Z(yvlY-4X&@Ot%Ykg+kd=bwC@V(**G z-!LVv?;)eYi(jv*GSdQP%bQlt;b{<>w5Iv$WTlf<5w@Dh%rndfzJA*&qvxQ1mgf}1 zgs=A)3V58~ay|g%T(b+_#?6bv7`EJgdwNz&=ylU<8@IlB2ftpaaPT=l;W5ue?-Tcs zot0Q1%XI0_NrnkqvL-pIOnBuvH#x%A=XH$$=Znu`sqq4wC-%uqLbhOfGGk_v-dt=-z$(Dn^HGYF4Y0)>90#M;6{bK3N_6f^2CTr}P z{h}mnLFy}^OD1u#5#mQ*#)wBPON;WZ^WAjul~N2xcI6c3eG@=&dhhGhuhUjKO4xrp zIA7&vhM0T5T&~Wgm%4{_x8J#Bu+pUcmN_Vtoxr`KwuknA9`ctnHvEm?n9#dyLfZA- zPcmEcrEYu?_j|`@^M3t(0p2ErhV1#L)a`rpn-6d?Zo0_!qs7EVLR3e>;OF{(S(iVq z-?KY&-L9ARCg%S(+h^zH&e|!kqLvwyjY|Gz*!~vUGVjl?h<1jX8O)d7%(8IL-8%5h~MBdEOIRkvl{-kDXOUMEX3r7Y$x zVE7RB?)faqT7Ub$C7&O4>zmpCILN=L)ZklxRP+C<=WVXlth;;Y$8R-r)*=p@7mOPm zudm-Lx36WPH*R(_pi%gtnB&x;xj|W%U@fsAD*6*m04gnjZuL)DVUkzbe)-f(}NQel_MD&)UD@z z$f>aTx$(R<;~Jg~P9H=WE`H5k->#p^kg>S+RU{B^vGR=C;S~WA|6>Cqg|IdwF4+Ih( zz3k6t|DfB*4z?=2zbU8c=alVPLC$8k8cg)ePfBggl}gB~x!?c(uOQQcKf4(+>lS?D z1tmn#xX-0C3OsV$47qg^a!j~0D?F|CzHB(@_=i>Dzp29Y6-%ApN`o@g!q@Jvw=Q%v z+sngn`j5iR49kPdw)dPzICO7n)`YX?w^TW7y7+3*?he1_QkRTOH=hS7txb##Sza8P zF>{us6$50(=FT(@@k>#0PbcKJl$k<0F-&_?v&?MR8`fk_;$8M5@-@4}UP~+0sp_!; zZ*qTbn&|k!UN2kCzRK75=lkhrdYO}>6b`r5=B(fS&gyge13TZ?>A!B7gIY^Y*Uw8v z+5Oyk?06W*1m0yF&+IRJ+LkcI(qy}za|7S$kB3jsKH0y1j*#Pm1B@5mm9dl1 z=?g|^pK%kEhGm&jn2qe`{aO1ne%Fe-+x%;+Oq(|dNqj1Em?i(4ZA+l!r5iVXaW%a7 zwe|YuiNXGLwK~oXITzR%?tQ+z$$o~75Yxk$+urS!Ck*T%_9R63e#t(uAmM?<()G2> zpgvJat$`s=tQ3O`(?OPpFV~;BC(X2Tb%W1mW*G)ekIz|0!Wbq+#s6m86?fI^#jk`U zGyB%U}6e|7rIypKs^$?NNJ`o8PWo;~LObpr3B z)eH-`8*fJ`F?_i!KmWycxBI^*o12OMnZMnv`rr4hN1w6Rum*U5a;aKc^X8pDXD}bI zYS;BJo52+S@!@Jat2vGa{~M27nm_-C{m!gY2pi73r6q4ZdGkk@Z`KL6;0OIRP8?hO zYj#R;#PeU8EMKqV^0bmC;+uB`gUF??+3TmLvE6(S#*p#3Ii)%Bz>7aK9U}g1|9w$? zKifS%iTWp#nP(WcLtB>YSN1hRN}h8U6lTYMtlbjfvW!(zb;mtzG7gr@AvecR)(7yhKvj5|Ld6(+VJ()g@TGZm7lMk4VT+-lGy)#|Kkt4kgC`TB5Y3;t%Zq`*V09ep6Pv${bFOc9LUF1)`vLy? zAI_6&?8F!t*0Utk?5$ZYCcKkzi8G2aaXAKqnmh&u16$$a8=vlWiDx)@{aA%U$<};u z17@B4+U-8EwhTI7S{>ee{T;U(QG!idDK5w0bGkv*qt)RY*MX|Hh>9(GnVbxRL4^Fu zT7xH_VwIkMU0KS8Y#{HU50gNV9TkflH>I2>-Bx$MQ?i@G2|aR)I=x%wlgkFs5W4pI?LM(ivySyGH1Lf*bV~RHsLi8#A$pmf zqHpr?fEmm55}(4l6}rL3zxOdRWJ;ZX^y~Hd`Ie2zo?7P*zPkMPmj$bB7+=y}%j6T+ zC;#1Ol`v~p%T!p~ce~HoW7F%I1-O}J9g}{*si(ec-WS7&+FjGE#gYU6T0TBfcWufw zlTuD?SOaoB@7ZI=?bsW5nC|*tuIN%^o3Pp_u+9fBYyy4fDW%)e4 zu3w+`2>*`UnA#@Hv}~n!L?x^Zo0(SktJz}Ov-DR23o>n7PcbaKz`R=DEKTp&m*d}( z9r{(KPL8^KMRko0thsHnnTNr1&f~vRIU6orPdoANMjg+t_WocrMaCS3+U%uA#J4%f(cI4;!y~U%p`|g5s6aSI$iNIMbw8);ST`d_r-l=+Csg zm;qE6EZewPY|ZRfCC@GynHJ~TGglnGI(_XKeX+bHTlbt+^k;b;!v`v9PhVMJQm4g| zA?5df`5aZ1nVf&$GxZ#NyZwHg3EP?ax9jDzy_^~1r`LR49e-A-%JbU6U2cYxRFJ#N zx`&TDH7tAh=Kr+nPZ`$R9PQ+P+kas)*!ypKH0dP-r}#5>-#I`dtNRmV>&J{`v}jB+86tIR}}vE@bH5bXqGXIc6V7NgU7CYyX?~5OnLd#(D(3BmWH}t#>dt$ zc{zbwPZ6KY9M~IbK6zI$aO~Q*D{humTGd|t{!FQJeh=)9F(pjYW?=Z=5|PPaV98VD z+`!D>UzJ&B_e_+r>KBuOD?fwd_5N$#$)|PSzfQjE3~~~~HLZjfm*t-w->=+J@8;9y zaORIx7>B{iRJLne4V_ZgFJ2aB*jRu2!mctz$MV^=-(hRb8P;&}98=rK0xGELK7Idt z`GM4>KOtQC><(6En9iJ1yzqUS!+M4rKP;xLZo0&9V5?W`?puhge(m_mViVrWj2Fy1 zO%tlr`hx#!ZD>pVXV{Q<^Un?Twflu1Fq~KjYNuWOI&EdDZrJnMS#90C4BVEA8!|pK z8|ciQ@3qivx2)L5c886xk6%BxD-Z6ze#zPWYiHRk%e-OVc<_eGIae(fv%`NF&dmGl z_~7HU?z7+3ecw$>kuCUJkQ=n*nk1rEKTC27+jYhTXZbIgoSA(^n zj9YxpzA?7x7g?)qht4#Tl$`2k-4f)kLl zgz9fQ_63<1ybblH^>Sz8Q8~_dvHA1 z>g~jE%&ng9qW2~SNd_?+2Bng}8GBQ+)O`B)MvtSA_kZ6r-`<}a&+sA0zWu^AM4>b5OMv9Qq*Q-VekQspsVWtcAQb4!LZ?GzpS;`H^(=|pd`6x{^v4;_b#3B z$*n8!W^%CqJ2N?qQB|>FLE`6T)qLg>h7;=hQ#=_W9u&(l=*HSd>7V6^ddA+(w4gtF zBNKyM)r*B6QuH|))!H5NI0_gZXzHImfBeRxHaUKVMc^)X@-uczh7zd54n(o?)c!jB zNB;MXaO-*wCmv*I?HGt8^`P_E!?ELH#|?~le0BFuc(y#K!kXbyqF6#0U*o>*tW~TBjve0^BRYk}p$p>B^KNXG z3_*W>9JiM{p(vncFoBCf!p@w5VaB}9WC=@i7M;)ij6A2G9k=UHI5;he$%3J1hBU** z|BHmafO=jRf6ZY?xa^&m#Sn3Vv(a_7JSba*aGBnEYw(S~F(Jc1jKShL_7h zOuMNo#>!B<;-}*v%4<+n%<6Fopeke-r=>+{H;9gN}>Rz)gF~6d({5{wpl(ObScy?8H@p-%7Z}w!U z1g+1^eR@6+(U{B4m~rP8#)f%zLD}qAyc+8G8>X#`uik57oWaU4 z|8cS;6Ue*^2_}1|9_vo*uv@xuThSaun`!e))2%;eTCqG>D0v{p@Cc8Nq09VB5fhMF zuX1YB+R}@YwR`n%N;AAwlkm+?W}7Cl$Uk$4u#UcWVaS<_XYmME2LM2bcc%*d0Hf zQ#T=J3!_oE!K{17cx=R0Uf;4!j=|;n`n~gd&un3G2%06YBAv_d%xmH;F|OC8zdVBY z8Lr=cUbKVv3#iXMZ_zt->9u;hx?hy6Q{1}H+tX|n`|IgNR&y)2_{2JGTG+cceg54! zf4jnSvb&5b{Y zmQFVlkFU!tzW4LF`T7$vf(L&5NZ*sU@9DG@4unZ@Yz*(eU*u^B_On#g`Ck8V>-yZd z%byN)>*t-bEm%}QX@ zwJ_iRye|XU)Y-Rwz48zG)|7JiaVKIKD}VLu{S;c2M>dPoz2(s_j6~-A9J@@u&w<4Ju``KrpxEo?UH0Lu=kOl_D`2z z-cIIB{n3Nk%|8X%_J5jfUd3P#`~KHNuqg+s>m{Ta8_qMFv;2PN!;HK7SkQe2vu#CM^tS-fJ^BUf*4}WL~e1?_Kw5 z)(f+wp4r!)pZRw3zcU;9Z>?PZj%RhlhA;P7KhKv7V^f*U*v`;nZ~Fhr2ZR0fYzY^> zu9IImeVN|F7zQ7EmN|BJ&s%ZJGx^Q`R`Kh7UO1b<-#*#pZJ%GL-jqow5O`MqRsa9i zXQkn>cWu9J{n>a+95NIWe*HAV1J%0w*LWBnTv+J*u-U#wm|^kztoh%T&)KBB$J9X} zLABt;+5Em)@lCw)#&(Opv4Z9gFMPfFHRnky3&Z1M+xMx?kd^=ScENh4{2dS5bRJJ% zgrp{A#;%r=3<(LYAD*32{}+Hr)$@97rlcIMdZE{J`K8XX)K@~2ct1D%SDv26sq;5O z3Op#g@5iI==9}US$#JYFx=SVld#M(F=1sgQ{sN(ycl`s<^1e6eox_pZKVtun_nAD zc%H;4(6fx=#NQc>JKcp}^xfPu^F>LM9K(Xw*W=DJPN=%ne9cmuVavr7=WuU{h^$?; z7v-}gtL!xURd*XA1_Jb%9i->1Jlyy_n33Vk+#JR8-yOeg^b2;rRyzOAcLs*o{oj7w zNN1S#@axWf3>yrd+05r|sT7{Dw@0#(-NF0%`n~sl@hBYs^I!!-0yEc#o$HP}l&>=` zsFHD*mlM6beeSkT@WI5D{EScc**tsuLbSm^@4BgE(f;NO%t6Q1la522JpZ$pL$Myi z4WApLS7ulrXS-Gvc|2{`?v4Gj4Zk^R@|N9jx@PSp9f1fhmIkw$zMltYG6>8toOO`F zY{9MTwVxu2+~zZ`&0i|VuueS+T%gJ@TzX>oYC#7pgF&*{LB1S^o&Lu+P5*A4<*QgR z$1fgHO}^G;2%Z%?TYk$uCYC1>!C4jYlV0EODSv)G@{Qy53z=H?VI#xye@iylv90B2 zoIF8o>Tko2d1cORs=asQoAUOYf)BJGXL7i%)5h?kC&hqu_5CECu=PhpocQBimKXD$ gbdx*geD*(k2(v=dJ0l%Y1_lNOPgg&ebxsLQ0Ec}@p8x;=