From b3e689d220bf7cde61a7ea4f488270daf7e37fd3 Mon Sep 17 00:00:00 2001 From: Sollace Date: Thu, 10 Jan 2019 11:35:15 +0200 Subject: [PATCH] Re-implemented spellbooks --- .../minelittlepony/unicopia/UEntities.java | 4 + .../com/minelittlepony/unicopia/UItems.java | 8 +- .../unicopia/entity/EntitySpellbook.java | 166 ++++++++++++++++++ .../unicopia/item/ItemSpellbook.java | 104 +++++++++++ .../unicopia/model/ModelSpellbook.java | 13 ++ .../unicopia/render/RenderSpellbook.java | 73 ++++++++ .../resources/assets/unicopia/lang/en_US.lang | 2 +- .../unicopia/models/item/spellbook.json | 18 ++ .../assets/unicopia/recipes/spellbook.json | 18 ++ .../unicopia/textures/items/spellbook.png | Bin 0 -> 3278 bytes 10 files changed, 404 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/entity/EntitySpellbook.java create mode 100644 src/main/java/com/minelittlepony/unicopia/item/ItemSpellbook.java create mode 100644 src/main/java/com/minelittlepony/unicopia/model/ModelSpellbook.java create mode 100644 src/main/java/com/minelittlepony/unicopia/render/RenderSpellbook.java create mode 100644 src/main/resources/assets/unicopia/models/item/spellbook.json create mode 100644 src/main/resources/assets/unicopia/recipes/spellbook.json create mode 100644 src/main/resources/assets/unicopia/textures/items/spellbook.png diff --git a/src/main/java/com/minelittlepony/unicopia/UEntities.java b/src/main/java/com/minelittlepony/unicopia/UEntities.java index b58fd7a7..599c2354 100644 --- a/src/main/java/com/minelittlepony/unicopia/UEntities.java +++ b/src/main/java/com/minelittlepony/unicopia/UEntities.java @@ -4,11 +4,13 @@ import com.minelittlepony.unicopia.entity.EntityCloud; import com.minelittlepony.unicopia.entity.EntityConstructionCloud; import com.minelittlepony.unicopia.entity.EntityRacingCloud; import com.minelittlepony.unicopia.entity.EntitySpell; +import com.minelittlepony.unicopia.entity.EntitySpellbook; import com.minelittlepony.unicopia.entity.EntityProjectile; import com.minelittlepony.unicopia.entity.EntityWildCloud; import com.minelittlepony.unicopia.render.RenderCloud; import com.minelittlepony.unicopia.render.RenderGem; import com.minelittlepony.unicopia.render.RenderProjectile; +import com.minelittlepony.unicopia.render.RenderSpellbook; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityList.EntityEggInfo; @@ -29,6 +31,7 @@ public class UEntities { new Entry(EntityRacingCloud.class, "racing_cloud"), new Entry(EntityConstructionCloud.class, "construction_cloud"), new Entry(EntitySpell.class, "magic_spell"), + new Entry(EntitySpellbook.class, "spellbook"), EntityEntryBuilder.create().entity(EntityProjectile.class).name("thrown_item").id(new ResourceLocation(Unicopia.MODID, "thrown_item"), 0).tracker(10, 5, true).build() ); } @@ -37,6 +40,7 @@ public class UEntities { RenderingRegistry.registerEntityRenderingHandler(EntityCloud.class, RenderCloud::new); RenderingRegistry.registerEntityRenderingHandler(EntitySpell.class, RenderGem::new); RenderingRegistry.registerEntityRenderingHandler(EntityProjectile.class, RenderProjectile::new); + RenderingRegistry.registerEntityRenderingHandler(EntitySpellbook.class, RenderSpellbook::new); } static class Entry extends EntityEntry { diff --git a/src/main/java/com/minelittlepony/unicopia/UItems.java b/src/main/java/com/minelittlepony/unicopia/UItems.java index e52babff..9d301ab7 100644 --- a/src/main/java/com/minelittlepony/unicopia/UItems.java +++ b/src/main/java/com/minelittlepony/unicopia/UItems.java @@ -6,6 +6,7 @@ import com.minelittlepony.unicopia.item.ItemCloud; import com.minelittlepony.unicopia.item.ItemCurse; import com.minelittlepony.unicopia.item.ItemOfHolding; import com.minelittlepony.unicopia.item.ItemSpell; +import com.minelittlepony.unicopia.item.ItemSpellbook; import com.minelittlepony.unicopia.item.ItemStick; import com.minelittlepony.unicopia.item.ItemTomato; import com.minelittlepony.unicopia.item.ItemTomatoSeeds; @@ -90,6 +91,8 @@ public class UItems { public static final ItemOfHolding bag_of_holding = new ItemOfHolding(Unicopia.MODID, "bag_of_holding"); + public static final ItemSpellbook spellbook = new ItemSpellbook(Unicopia.MODID, "spellbook"); + public static final Item alfalfa_seeds = new ItemSeedFood(1, 4, UBlocks.alfalfa, Blocks.FARMLAND) .setTranslationKey("alfalfa_seeds") .setRegistryName(Unicopia.MODID, "alfalfa_seeds") @@ -119,7 +122,9 @@ public class UItems { registry.registerAll(cloud_spawner, dew_drop, cloud_matter, cloud_block, cloud_stairs, cloud_slab, cloud_farmland, mist_door, anvil, - bag_of_holding, spell, curse, + + bag_of_holding, spell, curse, spellbook, + alfalfa_seeds, alfalfa_leaves, cereal, sugar_cereal, sugar_block, @@ -139,6 +144,7 @@ public class UItems { registerAllVariants(bag_of_holding, "bag_of_holding"); registerAllVariants(spell, "gem"); registerAllVariants(curse, "corrupted_gem"); + registerAllVariants(spellbook, "spellbook"); registerAllVariants(alfalfa_seeds, "alfalfa_seeds"); registerAllVariants(alfalfa_leaves, "alfalfa_leaves"); registerAllVariants(cereal, "cereal"); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/EntitySpellbook.java b/src/main/java/com/minelittlepony/unicopia/entity/EntitySpellbook.java new file mode 100644 index 00000000..0caf39f7 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/entity/EntitySpellbook.java @@ -0,0 +1,166 @@ +package com.minelittlepony.unicopia.entity; + +import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.UItems; + +import net.minecraft.block.SoundType; +import net.minecraft.entity.EntityLiving; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.util.DamageSource; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumHand; +import net.minecraft.util.EnumParticleTypes; +import net.minecraft.util.SoundCategory; +import net.minecraft.util.math.RayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EntitySpellbook extends EntityLiving implements IMagicals { + + private static final DataParameter OPENED = EntityDataManager.createKey(EntitySpellbook.class, DataSerializers.BOOLEAN); + private static final DataParameter OPENED_USER = EntityDataManager.createKey(EntitySpellbook.class, DataSerializers.BYTE); + + public EntitySpellbook(World worldIn) { + super(worldIn); + setSize(0.6f, 0.6f); + } + + @Override + protected void entityInit() { + super.entityInit(); + dataManager.register(OPENED, true); + dataManager.register(OPENED_USER, (byte)1); + } + + @Override + protected boolean canTriggerWalking() { + return false; + } + + @Override + public boolean isPushedByWater() { + return false; + } + + @Override + public boolean canRenderOnFire() { + return false; + } + + public boolean getIsOpen() { + return dataManager.get(OPENED); + } + + public Boolean getUserSetState() { + byte state = dataManager.get(OPENED_USER); + return state == 1 ? null : state == 2; + } + + public void setIsOpen(boolean val) { + dataManager.set(OPENED, val); + } + + public void setUserSetState(Boolean val) { + dataManager.set(OPENED_USER, val == null ? (byte)1 : val == true ? (byte)2 : (byte)0); + } + + @Override + public void onUpdate() { + boolean open = getIsOpen(); + this.isJumping = open && isInWater(); + super.onUpdate(); + if (open && world.isRemote) { + for (int offX = -2; offX <= 1; ++offX) { + for (int offZ = -2; offZ <= 1; ++offZ) { + if (offX > -1 && offX < 1 && offZ == -1) offZ = 1; + if (rand.nextInt(320) == 0) { + for (int offY = 0; offY <= 1; ++offY) { + float vX = (float)offX/2 + rand.nextFloat(); + float vY = (float)offY/2 - rand.nextFloat() + 0.5f; + float vZ = (float)offZ/2 + rand.nextFloat(); + world.spawnParticle(EnumParticleTypes.ENCHANTMENT_TABLE, posX, posY, posZ, vX, vY, vZ, new int[0]); + } + } + } + } + } + + if (world.rand.nextInt(30) == 0) { + float celest = world.getCelestialAngle(1) * 4; + boolean isDay = celest > 3 || celest < 1; + Boolean userState = getUserSetState(); + boolean canToggle = (isDay != open) && (userState == null || userState == isDay); + if (canToggle) { + setUserSetState(null); + setIsOpen(isDay); + } + if (userState != null && (isDay == open) && (userState == open)) { + setUserSetState(null); + } + } + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount) { + if (!world.isRemote) { + setDead(); + SoundType sound = SoundType.WOOD; + world.playSound(posX, posY, posZ, sound.getBreakSound(), SoundCategory.BLOCKS, sound.getVolume(), sound.getPitch(), true); + if (world.getGameRules().getBoolean("doTileDrops")) { + entityDropItem(new ItemStack(UItems.spellbook, 1), 0); + } + } + return false; + } + + @Override + public EnumActionResult applyPlayerInteraction(EntityPlayer player, Vec3d vec, EnumHand hand) { + if (player.isSneaking()) { + boolean open = !getIsOpen(); + + setIsOpen(open); + setUserSetState(open); + + return EnumActionResult.SUCCESS; + } + + if (Predicates.MAGI.test(player)) { + //ApiGui.openContainer((EntityPlayerMP)player, new InterfaceBook()); + + return EnumActionResult.SUCCESS; + } + + return EnumActionResult.PASS; + } + + @Override + public void readEntityFromNBT(NBTTagCompound compound) { + super.readEntityFromNBT(compound); + setIsOpen(compound.getBoolean("open")); + if (compound.hasKey("force_open")) { + setUserSetState(compound.getBoolean("force_open")); + } else { + setUserSetState(null); + } + } + + @Override + public void writeEntityToNBT(NBTTagCompound compound) { + super.writeEntityToNBT(compound); + compound.setBoolean("open", getIsOpen()); + Boolean state = getUserSetState(); + if (state != null) { + compound.setBoolean("force_open", state); + } + } + + @Override + public ItemStack getPickedResult(RayTraceResult target) { + return new ItemStack(UItems.spellbook); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/item/ItemSpellbook.java b/src/main/java/com/minelittlepony/unicopia/item/ItemSpellbook.java new file mode 100644 index 00000000..f1737de0 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/item/ItemSpellbook.java @@ -0,0 +1,104 @@ +package com.minelittlepony.unicopia.item; + +import com.minelittlepony.unicopia.Predicates; +import com.minelittlepony.unicopia.entity.EntitySpellbook; + +import net.minecraft.block.BlockDispenser; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.dispenser.BehaviorDefaultDispenseItem; +import net.minecraft.dispenser.IBehaviorDispenseItem; +import net.minecraft.dispenser.IBlockSource; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.ItemBook; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.EnumActionResult; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.EnumHand; +import net.minecraft.world.World; + +public class ItemSpellbook extends ItemBook { + private static final IBehaviorDispenseItem dispenserBehavior = new BehaviorDefaultDispenseItem() { + @Override + protected ItemStack dispenseStack(IBlockSource source, ItemStack stack) { + EnumFacing facing = source.getBlockState().getValue(BlockDispenser.FACING); + BlockPos pos = source.getBlockPos().offset(facing); + int yaw = 0; + + + //0deg == SOUTH + //90deg == WEST + //180deg == NORTH + //270deg == EAST + + /*switch (facing) { + case NORTH: yaw -= 90; break; + case SOUTH: yaw += 90; break; + case EAST: yaw += 180; break; + default: + }*/ + + yaw = facing.getOpposite().getHorizontalIndex() * 90; + placeBook(source.getWorld(), pos.getX(), pos.getY(), pos.getZ(), yaw); + stack.shrink(1); + return stack; + } + }; + + public ItemSpellbook(String domain, String name) { + super(); + setTranslationKey(name); + setRegistryName(domain, name); + + setMaxDamage(0); + maxStackSize = 1; + setCreativeTab(CreativeTabs.BREWING); + BlockDispenser.DISPENSE_BEHAVIOR_REGISTRY.putObject(this, dispenserBehavior); + } + + + public EnumActionResult onItemUse(EntityPlayer player, World world, BlockPos pos, EnumHand hand, EnumFacing side, float hitX, float hitY, float hitZ) { + + if (!world.isRemote && Predicates.MAGI.test(player)) { + pos = pos.offset(side); + + double diffX = player.posX - (pos.getX() + 0.5); + double diffZ = player.posZ - (pos.getZ() + 0.5); + float yaw = (float)Math.toDegrees(Math.atan2(diffZ, diffX) + Math.PI); + + placeBook(world, pos.getX(), pos.getY(), pos.getZ(), yaw); + + if (!player.capabilities.isCreativeMode) { + player.getHeldItem(hand).shrink(1); + } + + return EnumActionResult.SUCCESS; + } + return EnumActionResult.PASS; + } + + private static void placeBook(World world, int x, int y, int z, float yaw) { + EntitySpellbook book = new EntitySpellbook(world); + + book.setPositionAndRotation(x + 0.5, y, z + 0.5, yaw, 0); + book.renderYawOffset = 0; + book.prevRotationYaw = yaw; + + world.spawnEntity(book); + } +} + + + + + + + + + + + + + + + diff --git a/src/main/java/com/minelittlepony/unicopia/model/ModelSpellbook.java b/src/main/java/com/minelittlepony/unicopia/model/ModelSpellbook.java new file mode 100644 index 00000000..b6e0a442 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/model/ModelSpellbook.java @@ -0,0 +1,13 @@ +package com.minelittlepony.unicopia.model; + +import net.minecraft.client.model.ModelBook; +import net.minecraft.client.model.ModelRenderer; + +public class ModelSpellbook extends ModelBook { + public ModelSpellbook() { + super(); + bookSpine = (new ModelRenderer(this)).setTextureOffset(12, 0); + bookSpine.addBox(-1, -5, 0, 2, 10, 0, 0.1f); + bookSpine.rotateAngleY = ((float)Math.PI / 2F); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/render/RenderSpellbook.java b/src/main/java/com/minelittlepony/unicopia/render/RenderSpellbook.java new file mode 100644 index 00000000..eb8eed36 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/render/RenderSpellbook.java @@ -0,0 +1,73 @@ +package com.minelittlepony.unicopia.render; + +import com.minelittlepony.unicopia.entity.EntitySpellbook; +import com.minelittlepony.unicopia.model.ModelSpellbook; + +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.entity.RenderLiving; +import net.minecraft.client.renderer.entity.RenderManager; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.ResourceLocation; + +public class RenderSpellbook extends RenderLiving { + + private static final ResourceLocation texture = new ResourceLocation("textures/entity/enchanting_table_book.png"); + + public RenderSpellbook(RenderManager rendermanagerIn) { + super(rendermanagerIn, new ModelSpellbook(), 0); + } + + @Override + protected ResourceLocation getEntityTexture(EntitySpellbook entity) { + return texture; + } + + @Override + protected float getDeathMaxRotation(EntitySpellbook entity) { + return 0; + } + + @Override + protected void renderModel(EntitySpellbook entity, float time, float walkSpeed, float stutter, float yaw, float pitch, float increment) { + + float breath = MathHelper.sin(((float)entity.ticksExisted + stutter) / 20) * 0.01F + 0.1F; + + float first_page_rot = walkSpeed + (breath * 10); + float second_page_rot = 1 - first_page_rot; + float open_angle = 0.9f - walkSpeed; + + if (first_page_rot > 1) first_page_rot = 1; + if (second_page_rot > 1) second_page_rot = 1; + + if (!((EntitySpellbook)entity).getIsOpen()) { + GlStateManager.translate(0, 1.44f, 0); + } else { + GlStateManager.translate(0, 1.2f + breath, 0); + } + GlStateManager.pushMatrix(); + + if (!((EntitySpellbook)entity).getIsOpen()) { + first_page_rot = second_page_rot = open_angle = 0; + GlStateManager.rotate(90.0F, 1.0F, 0.0F, 0.0F); + GlStateManager.rotate(90.0F, 0.0F, 0.0F, 1.0F); + GlStateManager.translate(-0.25f, 0, 0); + } else { + GlStateManager.rotate(-60.0F, 0.0F, 0.0F, 1.0F); + } + + GlStateManager.enableCull(); + super.renderModel(entity, 0, first_page_rot, second_page_rot, open_angle, 0.0F, 0.0625F); + + GlStateManager.popMatrix(); + } + + @Override + protected void applyRotations(EntitySpellbook entity, float p_77043_2_, float p_77043_3_, float partialTicks) { + GlStateManager.rotate(-interpolateRotation(entity.prevRotationYaw, entity.rotationYaw, partialTicks), 0, 1, 0); + } + + @Override + protected boolean canRenderName(EntitySpellbook targetEntity) { + return super.canRenderName(targetEntity) && (targetEntity.getAlwaysRenderNameTagForRender() || targetEntity.hasCustomName() && targetEntity == renderManager.pointedEntity); + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/lang/en_US.lang b/src/main/resources/assets/unicopia/lang/en_US.lang index ac6986ee..c303410c 100644 --- a/src/main/resources/assets/unicopia/lang/en_US.lang +++ b/src/main/resources/assets/unicopia/lang/en_US.lang @@ -64,7 +64,7 @@ entity.racing_cloud.name=Bucking Bronco entity.construction_cloud.name=Construction Cloud entity.cloud.name=Cloud entity.spell.name=Magic - +entity.spellbook.name=Spellbook commands.race.success.self=Your race has been updated commands.race.success.otherself=%s changed race to %s diff --git a/src/main/resources/assets/unicopia/models/item/spellbook.json b/src/main/resources/assets/unicopia/models/item/spellbook.json new file mode 100644 index 00000000..82e46601 --- /dev/null +++ b/src/main/resources/assets/unicopia/models/item/spellbook.json @@ -0,0 +1,18 @@ +{ + "parent": "builtin/generated", + "textures": { + "layer0": "unicopia:items/spellbook" + }, + "display": { + "thirdperson": { + "rotation": [ -90, 0, 0 ], + "translation": [ 0, 1, -3 ], + "scale": [ 0.55, 0.55, 0.55 ] + }, + "firstperson": { + "rotation": [ 0, -135, 25 ], + "translation": [ 0, 4, 2 ], + "scale": [ 1.7, 1.7, 1.7 ] + } + } +} diff --git a/src/main/resources/assets/unicopia/recipes/spellbook.json b/src/main/resources/assets/unicopia/recipes/spellbook.json new file mode 100644 index 00000000..19fab215 --- /dev/null +++ b/src/main/resources/assets/unicopia/recipes/spellbook.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { + "item": "minecraft:book", + "data": 0 + }, + { + "item": "unicopia:gem", + "data": 0 + } + ], + "result": { + "item": "unicopia:spellbook", + "count": 1, + "data": 0 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/unicopia/textures/items/spellbook.png b/src/main/resources/assets/unicopia/textures/items/spellbook.png new file mode 100644 index 0000000000000000000000000000000000000000..992380b03c06199709d67253420c13009536ca16 GIT binary patch literal 3278 zcmV;<3^DVGP)pPPiaF#P*7-ZbZ>KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z0005`Nklkv6j8&kpW_&(3)d7qz> z5Q6`aYa@rTSiksOZJ{bMFLDiOtzG(C1|wmg7*u3-YXi<(CjX5$rSDSD0K2yN1i+!V zLMReMRXn^~tg}+71MoaoCBLvNtt(+H-Y>pbtq!o84#pH>5ueEY3L@=|`oz{Pn~3fl za(;0K{0wV;tg6jY#b%{a#~tuHc7VB3jhFd`e2vuN6)C%EA;{i}Ws0HcTM)zsj5