From 4ca46e8266ce5e8cebad37b129ddcc37eb196645 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 4 Jan 2016 13:11:46 -0500 Subject: [PATCH] Essentia Terminal QoL Essentia terminal player different sounds depending on item. Added debug level to logger. Updated essentia terminal lore. Updated essentia terminal gui. --- ChangeLog.txt | 10 ++- .../ContainerEssentiaCellTerminalBase.java | 52 +++++++-------- .../features/FeatureEssentiaMonitoring.java | 7 +- .../client/Packet_C_EssentiaCellTerminal.java | 22 +------ .../network/packet/client/Packet_C_Sync.java | 62 +++++++++++++----- .../common/utils/ThELog.java | 11 ++++ .../common/utils/ThEUtils.java | 51 +++++++++++++- .../integration/tc/PseudoResearchItem.java | 8 +-- .../assets/thaumicenergistics/lang/en_US.lang | 6 +- .../textures/gui/essentia.terminal.png | Bin 4072 -> 4163 bytes 10 files changed, 153 insertions(+), 76 deletions(-) diff --git a/ChangeLog.txt b/ChangeLog.txt index a2386d6c..940999c5 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,4 +1,11 @@ -01/03/2016 0.10.0.0 - Beta +01/04/2016 0.10.0.0 - Beta + Essentia terminal player different sounds depending on item. + Added debug level to logger. + Updated essentia terminal lore. + Updated essentia terminal gui. + Todo: Lore, recipe, texture for Distilation Encoder. + +01/03/2016 0.10.0.0 - Beta Essentia terminal can fill/drain containers when they are dragged and clicked over an aspect. 01/02/2016 0.10.0.0 - Beta @@ -13,7 +20,6 @@ Fixed sort-by-name in the Essentia Terminal. Fixed a bug where some parts would not be aware of neighboring blocks when placed. Fixes #53: :D - Todo: Lore, recipe, texture. 12/30/2015 0.10.0.0 - Beta Added Distillation Encoder diff --git a/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminalBase.java b/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminalBase.java index 773699ce..5266444c 100644 --- a/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminalBase.java +++ b/src/main/java/thaumicenergistics/common/container/ContainerEssentiaCellTerminalBase.java @@ -4,14 +4,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Nullable; -import net.minecraft.client.Minecraft; -import net.minecraft.client.audio.PositionedSoundRecord; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.Slot; import net.minecraft.inventory.SlotFurnace; import net.minecraft.item.ItemStack; -import net.minecraft.util.ResourceLocation; import org.apache.commons.lang3.tuple.ImmutablePair; import thaumcraft.api.aspects.Aspect; import thaumicenergistics.api.grid.ICraftingIssuerHost; @@ -30,6 +27,7 @@ import thaumicenergistics.common.network.packet.server.Packet_S_EssentiaCellTerm import thaumicenergistics.common.storage.AspectStack; import thaumicenergistics.common.storage.EssentiaRepo; import thaumicenergistics.common.utils.EffectiveSide; +import thaumicenergistics.common.utils.ThEUtils; import thaumicenergistics.integration.tc.EssentiaItemContainerHelper; import thaumicenergistics.integration.tc.EssentiaItemContainerHelper.AspectItemType; import appeng.api.config.Actionable; @@ -39,8 +37,6 @@ import appeng.api.networking.security.BaseActionSource; import appeng.api.networking.security.ISecurityGrid; import appeng.api.networking.security.MachineSource; import appeng.api.networking.security.PlayerSource; -import cpw.mods.fml.relauncher.Side; -import cpw.mods.fml.relauncher.SideOnly; /** * Base class for cell and terminal inventory containers @@ -162,9 +158,14 @@ public abstract class ContainerEssentiaCellTerminalBase private Slot inputSlot, outputSlot; /** - * Location of the transfer audio + * Location of the splash sound */ - private ResourceLocation transferSound = null; + private final String soundLocation_Splash = "game.neutral.swim"; + + /** + * Location of the paper sound + */ + private final String soundLocation_Paper = "thaumcraft:page"; /** * Set to true once a full list request is sent to the server. @@ -182,8 +183,8 @@ public abstract class ContainerEssentiaCellTerminalBase if( EffectiveSide.isClientSide() ) { + // Set the sound time this.lastSoundPlaytime = System.currentTimeMillis(); - this.transferSound = new ResourceLocation( "game.neutral.swim" ); } else { @@ -396,16 +397,6 @@ public abstract class ContainerEssentiaCellTerminalBase new AspectStack( withAspect, proposedFillAmount ) ); } - /** - * Plays the transfer sound. - */ - @SideOnly(Side.CLIENT) - private void playTransferSound() - { - Minecraft.getMinecraft().getSoundHandler() - .playSound( PositionedSoundRecord.func_147674_a( this.transferSound, 1.0F ) ); - } - /** * Attach this container to the Essentia monitor */ @@ -844,7 +835,8 @@ public abstract class ContainerEssentiaCellTerminalBase // Update Packet_C_Sync.sendPlayerHeldItem( player, sourceStack ); this.detectAndSendChanges(); - this.playTransferSound( player, false ); + this.playTransferSound( player, false, + ( EssentiaItemContainerHelper.INSTANCE.getItemType( sourceStack ) == AspectItemType.JarLabel ? 1 : 0 ) ); } @@ -857,7 +849,7 @@ public abstract class ContainerEssentiaCellTerminalBase // Is this client side? if( EffectiveSide.isClientSide() ) { - this.playTransferSound( null, true ); + this.playTransferSound( null, true, 0 ); } } @@ -946,12 +938,15 @@ public abstract class ContainerEssentiaCellTerminalBase /** * Checks if the transfer sound should play. + * if checkWorkSlots is true the type will be automatically determined. * * @param player * @param checkWorkSlots + * @param type + * 0 = splash, 1 = paper */ - public void playTransferSound( final EntityPlayer player, final boolean checkWorkSlots ) + public void playTransferSound( final EntityPlayer player, final boolean checkWorkSlots, int type ) { if( checkWorkSlots ) { @@ -965,8 +960,11 @@ public abstract class ContainerEssentiaCellTerminalBase // Is the item a label? if( EssentiaItemContainerHelper.INSTANCE.getItemType( itemStack ) == AspectItemType.JarLabel ) { - // TODO: Special sound for labels? - return; + type = 1; + } + else + { + type = 0; } // Has the count changed? @@ -992,13 +990,13 @@ public abstract class ContainerEssentiaCellTerminalBase // Has enough time passed to play the sound again? if( ( System.currentTimeMillis() - this.lastSoundPlaytime ) > MINIMUM_SOUND_WAIT ) { - if( EffectiveSide.isClientSide() ) + if( type == 0 ) { - this.playTransferSound(); + ThEUtils.playClientSound( this.player, this.soundLocation_Splash ); } - else + else if( type == 1 ) { - Packet_C_EssentiaCellTerminal.sendPlayTransferAudio( player ); + ThEUtils.playClientSound( this.player, this.soundLocation_Paper ); } // Set the playtime diff --git a/src/main/java/thaumicenergistics/common/features/FeatureEssentiaMonitoring.java b/src/main/java/thaumicenergistics/common/features/FeatureEssentiaMonitoring.java index 20cfe46e..97a057c4 100644 --- a/src/main/java/thaumicenergistics/common/features/FeatureEssentiaMonitoring.java +++ b/src/main/java/thaumicenergistics/common/features/FeatureEssentiaMonitoring.java @@ -10,10 +10,7 @@ import thaumcraft.api.research.ResearchPage; import thaumicenergistics.api.IThEItems; import thaumicenergistics.api.IThEParts; import thaumicenergistics.api.ThEApi; -import thaumicenergistics.common.registries.AEPartsEnum; -import thaumicenergistics.common.registries.FeatureRegistry; -import thaumicenergistics.common.registries.RecipeRegistry; -import thaumicenergistics.common.registries.ResearchRegistry; +import thaumicenergistics.common.registries.*; import thaumicenergistics.common.registries.ResearchRegistry.ResearchTypes; import appeng.core.AEConfig; import appeng.core.features.AEFeature; @@ -126,7 +123,9 @@ public class FeatureEssentiaMonitoring { pageList.add( new ResearchPage( RecipeRegistry.ITEM_WIRELESS_ESSENTIA_TERMINAL ) ); } + pageList.add( new ResearchPage( ResearchTypes.ESSENTIATERMINAL.getPageName( 3 ) ) ); pageList.add( new ResearchPage( RecipeRegistry.PART_ESSENTIA_LEVEL_EMITTER ) ); + pageList.add( new ResearchPage( ResearchTypes.ESSENTIATERMINAL.getPageName( 4 ) ) ); pageList.add( new ResearchPage( RecipeRegistry.PART_ESSENTIA_STORAGE_MONITOR ) ); if( this.isConversionEnabled ) { diff --git a/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_EssentiaCellTerminal.java b/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_EssentiaCellTerminal.java index 8178c822..2072ee50 100644 --- a/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_EssentiaCellTerminal.java +++ b/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_EssentiaCellTerminal.java @@ -9,7 +9,6 @@ import net.minecraft.entity.player.EntityPlayer; import thaumcraft.api.aspects.Aspect; import thaumicenergistics.api.storage.IAspectStack; import thaumicenergistics.client.gui.GuiEssentiaCellTerminal; -import thaumicenergistics.common.container.ContainerEssentiaCellTerminalBase; import thaumicenergistics.common.network.NetworkHandler; import thaumicenergistics.common.network.ThEBasePacket; import thaumicenergistics.common.registries.EnumCache; @@ -28,8 +27,7 @@ public class Packet_C_EssentiaCellTerminal private static final byte MODE_FULL_LIST = 0, MODE_SELECTED_ASPECT = 1, MODE_VIEWING_CHANGED = 2, - MODE_LIST_CHANGED = 3, - MODE_PLAY_SOUND = 4; + MODE_LIST_CHANGED = 3; private Collection aspectStackList; private Aspect selectedAspect; @@ -76,19 +74,6 @@ public class Packet_C_EssentiaCellTerminal NetworkHandler.sendPacketToClient( packet ); } - /** - * Asks the client to play the transfer audio. - * - * @param player - */ - public static void sendPlayTransferAudio( final EntityPlayer player ) - { - Packet_C_EssentiaCellTerminal packet = newPacket( player, MODE_PLAY_SOUND ); - - // Send it - NetworkHandler.sendPacketToClient( packet ); - } - /** * Sends the viewing modes. * @@ -170,11 +155,6 @@ public class Packet_C_EssentiaCellTerminal // Update the list ( (GuiEssentiaCellTerminal)gui ).onReceiveAspectListChange( this.change ); break; - - case MODE_PLAY_SOUND: - // Play the sound! - ( (ContainerEssentiaCellTerminalBase)this.player.openContainer ).playTransferSound( this.player, false ); - break; } } } diff --git a/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_Sync.java b/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_Sync.java index 9653a18b..1180a106 100644 --- a/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_Sync.java +++ b/src/main/java/thaumicenergistics/common/network/packet/client/Packet_C_Sync.java @@ -5,9 +5,10 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import thaumicenergistics.common.network.NetworkHandler; import thaumicenergistics.common.network.ThEBasePacket; +import thaumicenergistics.common.utils.ThEUtils; /** - * Packed used to send misc. sync events to the client. + * Packed used to send miscellaneous events to the client. * * @author Nividica * @@ -18,11 +19,14 @@ public class Packet_C_Sync /** * Packet modes. */ - private static final byte MODE_PLAYER_HELD = 1; + private static final byte MODE_PLAYER_HELD = 1, + MODE_SOUND = 2; - private ItemStack itemStack; + private ItemStack syncStack; - private boolean flag; + private boolean syncFlag; + + private String syncString; /** * Creates the packet @@ -56,10 +60,28 @@ public class Packet_C_Sync Packet_C_Sync packet = newPacket( player, MODE_PLAYER_HELD ); // Set the held item - packet.itemStack = heldItem; + packet.syncStack = heldItem; // Is the player holding anything? - packet.flag = ( heldItem != null ); + packet.syncFlag = ( heldItem != null ); + + // Send it + NetworkHandler.sendPacketToClient( packet ); + } + + /** + * Sends a sound to the player to play. + * + * @param player + * @param soundLocation + */ + public static void sendPlaySound( final EntityPlayer player, final String soundLocation ) + { + // Create the packet + Packet_C_Sync packet = newPacket( player, MODE_SOUND ); + + // Set the sound location + packet.syncString = soundLocation; // Send it NetworkHandler.sendPacketToClient( packet ); @@ -72,17 +94,21 @@ public class Packet_C_Sync { case MODE_PLAYER_HELD: // Read if the item is null - this.flag = stream.readBoolean(); - if( this.flag ) + this.syncFlag = stream.readBoolean(); + if( this.syncFlag ) { // Read stack - this.itemStack = ThEBasePacket.readItemstack( stream ); + this.syncStack = ThEBasePacket.readItemstack( stream ); } else { - this.itemStack = null; + this.syncStack = null; } + break; + case MODE_SOUND: + // Read the sound location + this.syncString = ThEBasePacket.readString( stream ); break; } } @@ -94,8 +120,11 @@ public class Packet_C_Sync { case MODE_PLAYER_HELD: // Set what the player is holding. - this.player.inventory.setItemStack( this.itemStack ); + this.player.inventory.setItemStack( this.syncStack ); break; + case MODE_SOUND: + // Play the sound + ThEUtils.playClientSound( null, this.syncString ); } } @@ -106,13 +135,16 @@ public class Packet_C_Sync { case MODE_PLAYER_HELD: // Write if the held item is null - stream.writeBoolean( this.flag ); - if( this.flag ) + stream.writeBoolean( this.syncFlag ); + if( this.syncFlag ) { // Write the stack - ThEBasePacket.writeItemstack( this.itemStack, stream ); + ThEBasePacket.writeItemstack( this.syncStack, stream ); } - + break; + case MODE_SOUND: + // Write the sound location + ThEBasePacket.writeString( this.syncString, stream ); break; } } diff --git a/src/main/java/thaumicenergistics/common/utils/ThELog.java b/src/main/java/thaumicenergistics/common/utils/ThELog.java index 29ad7533..9664bcbc 100644 --- a/src/main/java/thaumicenergistics/common/utils/ThELog.java +++ b/src/main/java/thaumicenergistics/common/utils/ThELog.java @@ -16,6 +16,17 @@ public class ThELog return System.currentTimeMillis(); } + /** + * Logs a debug statement. + * + * @param format + * @param data + */ + public static void debug( final String format, final Object ... data ) + { + log.debug( String.format( format, data ) ); + } + /** * Displays the section footer. */ diff --git a/src/main/java/thaumicenergistics/common/utils/ThEUtils.java b/src/main/java/thaumicenergistics/common/utils/ThEUtils.java index 74c76487..e25eb653 100644 --- a/src/main/java/thaumicenergistics/common/utils/ThEUtils.java +++ b/src/main/java/thaumicenergistics/common/utils/ThEUtils.java @@ -1,8 +1,16 @@ package thaumicenergistics.common.utils; +import javax.annotation.Nullable; +import net.minecraft.client.Minecraft; +import net.minecraft.client.audio.PositionedSoundRecord; +import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; import thaumcraft.common.items.wands.ItemWandCasting; +import thaumicenergistics.common.network.packet.client.Packet_C_Sync; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; /** * Houses commonly used methods. @@ -12,6 +20,15 @@ import thaumcraft.common.items.wands.ItemWandCasting; */ public final class ThEUtils { + /** + * Plays a sound for this player. + */ + @SideOnly(Side.CLIENT) + private static final void playLocalSound( final ResourceLocation sound ) + { + Minecraft.getMinecraft().getSoundHandler() + .playSound( PositionedSoundRecord.func_147674_a( sound, 1.0F ) ); + } /** * Returns true if the item stack is a wand, scepter, or staff if they are @@ -21,7 +38,7 @@ public final class ThEUtils * @param allowStaves * @return */ - public static boolean isItemValidWand( final ItemStack stack, final boolean allowStaves ) + public static final boolean isItemValidWand( final ItemStack stack, final boolean allowStaves ) { Item potentialWand; @@ -104,4 +121,36 @@ public final class ThEUtils return minValue + rangePercentage; } + /** + * Plays a sound only the specified player can hear. + * + * @param player + * Can be null on client side. + * @param soundLocation + */ + public static final void playClientSound( @Nullable final EntityPlayer player, final String soundLocation ) + { + // Ensure there is a sound + if( ( soundLocation == null ) || ( soundLocation == "" ) ) + { + return; + } + + if( EffectiveSide.isClientSide() ) + { + // Create the resource + ResourceLocation sound = new ResourceLocation( soundLocation ); + + // Play the sound + playLocalSound( sound ); + } + else + { + // Send to the player + if( player != null ) + { + Packet_C_Sync.sendPlaySound( player, soundLocation ); + } + } + } } diff --git a/src/main/java/thaumicenergistics/integration/tc/PseudoResearchItem.java b/src/main/java/thaumicenergistics/integration/tc/PseudoResearchItem.java index eff1f3b9..827f840e 100644 --- a/src/main/java/thaumicenergistics/integration/tc/PseudoResearchItem.java +++ b/src/main/java/thaumicenergistics/integration/tc/PseudoResearchItem.java @@ -28,8 +28,8 @@ public class PseudoResearchItem // Call super and create the research item super( key, category, new AspectList(), column, row, 1, icon ); - // Set as a hidden stub - this.setHidden().setStub(); + // Set as a stub + this.setStub().setHidden(); } /** @@ -46,8 +46,8 @@ public class PseudoResearchItem // Call super and create the research item super( key, category, new AspectList(), column, row, 1, icon ); - // Set as a hidden stub - this.setHidden().setStub(); + // Set as a stub + this.setStub().setHidden(); } /** diff --git a/src/main/resources/assets/thaumicenergistics/lang/en_US.lang b/src/main/resources/assets/thaumicenergistics/lang/en_US.lang index e819fecb..001600af 100644 --- a/src/main/resources/assets/thaumicenergistics/lang/en_US.lang +++ b/src/main/resources/assets/thaumicenergistics/lang/en_US.lang @@ -109,8 +109,10 @@ thaumicenergistics.research_page.TEARCANETERM.1=You have discovered that using p # Research Essentia terminal tc.research_name.thaumicenergistics.TEESSTERM=Essentia Monitoring tc.research_text.thaumicenergistics.TEESSTERM=Knowing how much you have. -thaumicenergistics.research_page.TEESSTERM.1=The §lEssentia Terminal§r and §lWireless Essentia Terminal§r allows you to view how much essentia is stored within the network, and provides a way to fill and drain essentia containers within the terminal.
The §lEssentia Level Emitter§r provides a redstone signal when the level of essentia in the network falls below or rises above a set amount. -thaumicenergistics.research_page.TEESSTERM.2=The §lEssentia Storage Monitor§r & §lEssentia Conversion Monitor§r allow you to see how much of an aspect is in the network at a glance. The conversion monitor also allows you to insert and extract essentia from the network.
Right-clicking with a wrench will lock/unlock the monitor.
Right-clicking an unlocked monitor with a label or filled jar or phial will set the displayed aspect, and right-clicking with an empty hand will clear aspect.
Right-clicking a locked conversion monitor will fill jar or phial and Shift-Right-Clicking will empty them.
Shift-Double-Right-Click will empty all essentia from your inventory. +thaumicenergistics.research_page.TEESSTERM.1=The §lEssentia Terminal§r provides a convenient way to insert or extract essentia stored within the network.
When placing a jar or phial it will be emptied if it contains any essentia, or filled with the selected aspect. Labels can also be set or cleared depending on the selected aspect. +thaumicenergistics.research_page.TEESSTERM.2=For the Thaumaturge with little time on their hands and many aspects to work with, the displayed aspects can be clicked with an item to fill, drain, or set the item in question.
When holding multiple of an item, items will be returned to your inventory. +thaumicenergistics.research_page.TEESSTERM.3=The §lEssentia Level Emitter§r provides a redstone signal when the level of essentia in the network falls below or rises above a set amount. +thaumicenergistics.research_page.TEESSTERM.4=The §lEssentia Storage Monitor§r & §lEssentia Conversion Monitor§r allow you to see how much of an aspect is in the network at a glance. The conversion monitor also allows you to insert and extract essentia from the network.
Right-clicking with a wrench will lock/unlock the monitor.
Right-clicking an unlocked monitor with a label or filled jar or phial will set the displayed aspect, and right-clicking with an empty hand will clear aspect.
Right-clicking a locked conversion monitor will fill jar or phial and Shift-Right-Clicking will empty them.
Shift-Double-Right-Click will empty all essentia from your inventory. # Research Essentia Provider tc.research_name.thaumicenergistics.TEESSPROV=Essentia Provider diff --git a/src/main/resources/assets/thaumicenergistics/textures/gui/essentia.terminal.png b/src/main/resources/assets/thaumicenergistics/textures/gui/essentia.terminal.png index b2dff2d526a3cf0251d9a0280d69632e7ab959b9..edcfdee7f28aef0c573a043df9e0454f6c73694f 100644 GIT binary patch delta 1140 zcmaDMe^_C|0j~NyPZ!6Kid%2)-p#!gAkpyfe4v?Ux`UEjleC!QCy||r0-N0uI?I~h z6jTLT_O4)NyM5zb<-FPdG=43TI@kU7kf&h%(uO}G^SKqCZfBYI|KIJk^+qv&T_^5y zQ!w`zv$wRC>yMoOSL`{X#azF6qAAJy@4LIW#9p5mbn2bYgP*VE>vjIUoY$}=dTm(X zw57}+I~WY^PM%X18d{ks^;3>PfuVtcfr)_w!Pro6kJDn~)hyA_P)h+0hrUyrzJ!H8 zlWf?&eS1aKtMaKE;?}cQHqD;=e$F<2=C@_LXQ$_GkCxZj^_3@KZ`}7^Y_rd*`7NJp z`RtDE^T&@L-)7~g<(Aj^HGOu&v=kShk@@75KZlESVDI z;`07(bVBC0-?c6-S4w3ymmX4Ocp#*pl(hXeZ_%nU3mLYV$@vx)2@JDZue*na7J>vG z3$+^h{bzm9C9kjl@$>cd=i}f1y#-{?-~Zld`RnURAB`T_Hl#V0m+FedifwVNKfhS4 zKK8m`eO`w(^Nw#>cfNhk?f$x(W6NCGEoXmLsWFO+y%Xq)=}%nFP_zBOZL#X<;s3TB z{eM>`ohf3Ea6D5?)CFgq3k#nyD9>R$5M!F3^tdsd;raCs-{V&Eo3hV%AoSpmR2^S& z13T-2)4!SIEZKpsZHw9>X0P)_h#_L#?5O)3SN=@D`_r`gvsT?p-969qh4+~)e|@{Z zQINSHbK$+JsQYEl_rLzmqPBx&$Jfvww;sLSv_ZFS#zjeo>EVB~8aSB^uI$VH zmfy_Ewm|2!quE1=EIxySwv!j~2~XzdW0iZB7HBVfV~)-9A1f~ivo5G)_$BdaIrHqv z&t>FQia9~C;0TR{s4M>LX6olHdzN=}ObP1h_>umY6%yOet(o3_|J~8C;u27t2-~KV?jv&Xg6MYVPj6hKqh8?Gm&Tc4UHB09!K3C5A z%n_1EtFnQKG|z80%Vb8N2RHDs0L|j|=D8_)W6sUakIrSk$jCAs=ogvE m4g9)5%sx4hUrECFYc)f^uz`_>(AjtfAn5c71DYS2qiYZ zDfoS1m#1bg%k_la-+wRhdV6|h)`$MLYU-giUW`vy*3D;FxhMF+$ItiQ{aJos^Zr$r zu5(OzcJQSC$#1`FFNW{Gn#sV|-dxUl^u;bcC8b~c`lkdHhBNiY|F3`WWd1we6P2s4 zYRy_!sPImZVOjO$;<($}>}KTs;b9P9aA06yWMDxsA}r!LEjC`w63xABCBWg(IcwR+ zrR&ZZGpt{~{^N%U<z`aak2TGOa^-xEOYi4s+XVJZ^raca`FLwQ9}iW1_lNu1`Y-Vh6D9y z+!Tt_?Atq;5|k%c7SBjlzTm*H<;=YhVO?87gq>A)bvB*3u1!Hj99 z@o!5X5eDhTGcym%NH?l+9r(cXWW&c}bM9E0F;%in4&+m+XWb-tV$RL;mg$>sy4>D& z?txFJ%aSQUE-v4`iABs>_gYD5(fi*XnxT1&4BHt51#iDCo8rCoZl3umncWW`^f5~K z?UBj7eJpRgbZTF;NM7MjeTD~5bSI@Vh}3`jUMv6cbK?%}25%dCTUVDOzduS8&v1^c zo4X@#|^ObnAZ@rlW9STmn5 z$8TowpO6=jh&cA=<$-5YERUN{+Q|wGQza`V-B-(*X9qu%$y?slF(s(0<45+#re23< zXA;l7bOWXWSTOlLmX2lQ(RbjJ&OdWn%TkTrFD+dsc`Q<$MF z-3W9vC`lAd&6j7o#g%hT=GmM))@Od;w6N{oEMQtVoVgulYY@!V=*F{PTf-8>j)x^| z2PZ6t!s-8e9vdpHTD9s@-Tv}|g%`9NUOjz!^kRY`FgyMDDKML7IlF