From d153a4ca34f43b01d8586fb7ffe6806bbc986b1d Mon Sep 17 00:00:00 2001 From: CosmoOrSth <79050675+CosmoOrSth@users.noreply.github.com> Date: Thu, 23 Jan 2025 23:23:41 +0530 Subject: [PATCH] partial implementation of ghostly armour --- CHANGELOG | 4 +- .../smithy/terraoriginum/TerraOriginum.java | 2 +- .../client/TerraOriginumClient.java | 13 ++ .../client/armour/ghostlyArmourModel.java | 23 +++ .../client/armour/ghostlyArmourRenderer.java | 16 +++ .../terraoriginum/items/ghostlyArmour.java | 108 ++++++++++++++ ...obesItems.java => ghostlyArmourItems.java} | 31 ++-- .../item/armor/ghost_armour.animation.json | 127 ++++++++++++++++ .../geo/item/armor/ghost_armour.geo.json | 135 ++++++++++++++++++ .../textures/item/armor/ghost_armour.png | Bin 0 -> 3805 bytes .../powers/spirit-powers/ectodiff.json | 69 ++++++++- 11 files changed, 508 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/smithy/terraoriginum/client/TerraOriginumClient.java create mode 100644 src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourModel.java create mode 100644 src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourRenderer.java create mode 100644 src/main/java/com/smithy/terraoriginum/items/ghostlyArmour.java rename src/main/java/com/smithy/terraoriginum/items/{robesItems.java => ghostlyArmourItems.java} (50%) create mode 100644 src/main/resources/assets/terraoriginum/animations/item/armor/ghost_armour.animation.json create mode 100644 src/main/resources/assets/terraoriginum/geo/item/armor/ghost_armour.geo.json create mode 100644 src/main/resources/assets/terraoriginum/textures/item/armor/ghost_armour.png diff --git a/CHANGELOG b/CHANGELOG index 20df753..305bd6e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -7,4 +7,6 @@ - Renamed java class "sun_totem" to "sunTotem" to fit convention. - added robes - added the munch -- mobs are now passive to florian \ No newline at end of file +- mobs are now passive to florian +- registered items related to ghostly armour +- added a model for ghostly armour \ No newline at end of file diff --git a/src/main/java/com/smithy/terraoriginum/TerraOriginum.java b/src/main/java/com/smithy/terraoriginum/TerraOriginum.java index 05f213b..359a6e1 100644 --- a/src/main/java/com/smithy/terraoriginum/TerraOriginum.java +++ b/src/main/java/com/smithy/terraoriginum/TerraOriginum.java @@ -28,7 +28,7 @@ public class TerraOriginum implements ModInitializer { cottonItems.register(); sunTotem.register(); ghostlyItems.register(); - robesItems.register(); + ghostlyArmourItems.register(); modPowers.register(); ItemGroupEvents.modifyEntriesEvent(ItemGroups.TOOLS).register((content) -> content.add(umbrella.UMBRELLA)); diff --git a/src/main/java/com/smithy/terraoriginum/client/TerraOriginumClient.java b/src/main/java/com/smithy/terraoriginum/client/TerraOriginumClient.java new file mode 100644 index 0000000..58764a9 --- /dev/null +++ b/src/main/java/com/smithy/terraoriginum/client/TerraOriginumClient.java @@ -0,0 +1,13 @@ +package com.smithy.terraoriginum.client; + +import net.fabricmc.api.ClientModInitializer; + +public class TerraOriginumClient implements ClientModInitializer { + + + @Override + public void onInitializeClient() { + + + } +} diff --git a/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourModel.java b/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourModel.java new file mode 100644 index 0000000..4953e2a --- /dev/null +++ b/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourModel.java @@ -0,0 +1,23 @@ +package com.smithy.terraoriginum.client.armour; + +import com.smithy.terraoriginum.items.ghostlyArmour; +import net.minecraft.util.Identifier; +import software.bernie.geckolib.model.GeoModel; + +public class ghostlyArmourModel extends GeoModel { + + @Override + public Identifier getModelResource(ghostlyArmour animatable) { + return new Identifier("terraoriginum", "geo/ghostly_armour.geo.json"); + } + + @Override + public Identifier getTextureResource(ghostlyArmour animatable) { + return new Identifier("terraoriginum", "textures/models/armor/ghost_armour_model_texture"); + } + + @Override + public Identifier getAnimationResource(ghostlyArmour animatable) { + return null; + } +} diff --git a/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourRenderer.java b/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourRenderer.java new file mode 100644 index 0000000..3c0d0cb --- /dev/null +++ b/src/main/java/com/smithy/terraoriginum/client/armour/ghostlyArmourRenderer.java @@ -0,0 +1,16 @@ +package com.smithy.terraoriginum.client.armour; + +import com.smithy.terraoriginum.TerraOriginum; +import com.smithy.terraoriginum.items.ghostlyArmour; +import net.minecraft.util.Identifier; +import software.bernie.geckolib.GeckoLib; +import software.bernie.geckolib.model.DefaultedItemGeoModel; +import software.bernie.geckolib.renderer.GeoArmorRenderer; + +public class ghostlyArmourRenderer extends GeoArmorRenderer { + + public ghostlyArmourRenderer() { + super(new DefaultedItemGeoModel<>(new Identifier(TerraOriginum.MOD_ID, "armor/ghost_armour"))); + } + +} diff --git a/src/main/java/com/smithy/terraoriginum/items/ghostlyArmour.java b/src/main/java/com/smithy/terraoriginum/items/ghostlyArmour.java new file mode 100644 index 0000000..2253206 --- /dev/null +++ b/src/main/java/com/smithy/terraoriginum/items/ghostlyArmour.java @@ -0,0 +1,108 @@ +package com.smithy.terraoriginum.items; + +import com.smithy.terraoriginum.client.armour.ghostlyArmourRenderer; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.item.ArmorItem; +import net.minecraft.item.ArmorMaterial; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import software.bernie.example.client.renderer.armor.GeckoArmorRenderer; +import software.bernie.geckolib.animatable.GeoItem; +import software.bernie.geckolib.animatable.client.RenderProvider; +import software.bernie.geckolib.constant.DataTickets; +import software.bernie.geckolib.constant.DefaultAnimations; +import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache; +import software.bernie.geckolib.core.animation.AnimatableManager; +import software.bernie.geckolib.core.animation.AnimationController; +import software.bernie.geckolib.core.object.PlayState; +import software.bernie.geckolib.renderer.GeoArmorRenderer; +import software.bernie.geckolib.util.GeckoLibUtil; + +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class ghostlyArmour extends ArmorItem implements GeoItem { + + private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this); + private final Supplier renderProvider = GeoItem.makeRenderer(this); + + public ghostlyArmour(ArmorMaterial armorMaterial, ArmorItem.Type type, Settings properties) { + super(armorMaterial, type, properties); + } + + // Create our armor model/renderer for Fabric and return it + @Override + public void createRenderer(Consumer consumer) { + consumer.accept(new RenderProvider() { + private GeoArmorRenderer renderer; + + @Override + public BipedEntityModel getHumanoidArmorModel(LivingEntity livingEntity, ItemStack itemStack, EquipmentSlot equipmentSlot, BipedEntityModel original) { + if (this.renderer == null) + this.renderer = new ghostlyArmourRenderer(); + + // This prepares our GeoArmorRenderer for the current render frame. + // These parameters may be null however, so we don't do anything further with them + this.renderer.prepForRender(livingEntity, itemStack, equipmentSlot, original); + + return this.renderer; + } + }); + } + + @Override + public Supplier getRenderProvider() { + return this.renderProvider; + } + + // Let's add our animation controller + @Override + public void registerControllers(AnimatableManager.ControllerRegistrar controllers) { + controllers.add(new AnimationController<>(this, 20, state -> { + // Apply our generic idle animation. + // Whether it plays or not is decided down below + + // Let's gather some data from the state to use below + // This is the entity that is currently wearing/holding the item + Entity entity = state.getData(DataTickets.ENTITY); + + // We'll just have ArmorStands always animate, so we can return here + if (entity instanceof ArmorStandEntity) + return PlayState.CONTINUE; + + // For this example, we only want the animation to play if the entity is wearing all pieces of the armor + // Let's collect the armor pieces the entity is currently wearing + Set wornArmor = new ObjectOpenHashSet<>(); + + for (ItemStack stack : entity.getArmorItems()) { + // We can stop immediately if any of the slots are empty + if (stack.isEmpty()) + return PlayState.STOP; + + wornArmor.add(stack.getItem()); + } + + // Check each of the pieces match our set + boolean isFullSet = wornArmor.containsAll(ObjectArrayList.of( + ghostlyArmourItems.GHOSTLY_BOOTS, + ghostlyArmourItems.GHOSTLY_LEGGING, + ghostlyArmourItems.GHOSTLY_CHESTPLATE, + ghostlyArmourItems.GHOSTLY_HELMET)); + + // Play the animation if the full set is being worn, otherwise stop + return isFullSet ? PlayState.CONTINUE : PlayState.STOP; + })); + } + + @Override + public AnimatableInstanceCache getAnimatableInstanceCache() { + return this.cache; + } +} diff --git a/src/main/java/com/smithy/terraoriginum/items/robesItems.java b/src/main/java/com/smithy/terraoriginum/items/ghostlyArmourItems.java similarity index 50% rename from src/main/java/com/smithy/terraoriginum/items/robesItems.java rename to src/main/java/com/smithy/terraoriginum/items/ghostlyArmourItems.java index abf778b..957ecee 100644 --- a/src/main/java/com/smithy/terraoriginum/items/robesItems.java +++ b/src/main/java/com/smithy/terraoriginum/items/ghostlyArmourItems.java @@ -13,22 +13,25 @@ import net.minecraft.registry.Registry; import net.minecraft.util.Identifier; import net.minecraft.util.Rarity; -public class robesItems { - - public static final Item ROBES_HELMET = new ArmorItem(robesMaterial.ROBES, ArmorItem.Type.HELMET, new FabricItemSettings().rarity(Rarity.EPIC)); - public static final Item ROBES_CHESTPLATE = new ArmorItem(robesMaterial.ROBES, ArmorItem.Type.CHESTPLATE, new FabricItemSettings().rarity(Rarity.EPIC)); - public static final Item ROBES_LEGGING = new ArmorItem(robesMaterial.ROBES, ArmorItem.Type.LEGGINGS, new FabricItemSettings().rarity(Rarity.EPIC)); - public static final Item ROBES_BOOTS = new ArmorItem(robesMaterial.ROBES, ArmorItem.Type.BOOTS, new FabricItemSettings().rarity(Rarity.EPIC)); +public class ghostlyArmourItems { + + public static final Item GHOSTLY_HELMET = new ghostlyArmour(robesMaterial.ROBES, ArmorItem.Type.HELMET, new FabricItemSettings().rarity(Rarity.EPIC)); + public static final Item GHOSTLY_CHESTPLATE = new ghostlyArmour(robesMaterial.ROBES, ArmorItem.Type.CHESTPLATE, new FabricItemSettings().rarity(Rarity.EPIC)); + public static final Item GHOSTLY_LEGGING = new ghostlyArmour(robesMaterial.ROBES, ArmorItem.Type.LEGGINGS, new FabricItemSettings().rarity(Rarity.EPIC)); + public static final Item GHOSTLY_BOOTS = new ghostlyArmour(robesMaterial.ROBES, ArmorItem.Type.BOOTS, new FabricItemSettings().rarity(Rarity.EPIC)); public static void register() { - Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "robes_helmet"), ROBES_HELMET); - Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "robes_chestplate"), ROBES_CHESTPLATE); - Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "robes_leggings"), ROBES_LEGGING); - Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "robes_boots"), ROBES_BOOTS); + Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "ghostly_helmet"), GHOSTLY_HELMET); + Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "ghostly_chestplate"), GHOSTLY_CHESTPLATE); + Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "ghostly_leggings"), GHOSTLY_LEGGING); + Registry.register(Registries.ITEM, new Identifier(TerraOriginum.MOD_ID, "ghostly_boots"), GHOSTLY_BOOTS); - ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(ROBES_HELMET)); - ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(ROBES_CHESTPLATE)); - ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(ROBES_LEGGING)); - ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(ROBES_BOOTS)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(GHOSTLY_HELMET)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(GHOSTLY_CHESTPLATE)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(GHOSTLY_LEGGING)); + ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register((content) -> content.add(GHOSTLY_BOOTS)); } + + + } diff --git a/src/main/resources/assets/terraoriginum/animations/item/armor/ghost_armour.animation.json b/src/main/resources/assets/terraoriginum/animations/item/armor/ghost_armour.animation.json new file mode 100644 index 0000000..1ec2009 --- /dev/null +++ b/src/main/resources/assets/terraoriginum/animations/item/armor/ghost_armour.animation.json @@ -0,0 +1,127 @@ +{ + "format_version": "1.8.0", + "animations": { + "walk": { + "loop": "hold_on_last_frame", + "animation_length": 0.25, + "bones": { + "torsoEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [20, 0, 0], + "easing": "linear" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [0, -2, -3], + "easing": "linear" + } + } + }, + "bandanaEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [20, 0, 0], + "easing": "linear" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [0, -2, 1], + "easing": "linear" + } + } + } + } + }, + "sprint": { + "loop": "hold_on_last_frame", + "animation_length": 0.25, + "bones": { + "bandanaEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [55, 0, 0], + "easing": "linear" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [0, -4, 4], + "easing": "linear" + } + } + }, + "torsoEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [50, 0, 0], + "easing": "linear" + } + }, + "position": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "0.25": { + "vector": [0, -6, -5], + "easing": "linear" + } + } + } + } + }, + "idle": { + "animation_length": 3, + "bones": { + "bandanaEnd": { + "rotation": { + "0.0": { + "vector": [0, 0, 0], + "easing": "linear" + }, + "1.5": { + "vector": [2.5, 0, 0], + "easing": "linear" + }, + "3.0": { + "vector": [0, 0, 0], + "easing": "linear" + } + } + } + } + } + }, + "geckolib_format_version": 2 +} \ No newline at end of file diff --git a/src/main/resources/assets/terraoriginum/geo/item/armor/ghost_armour.geo.json b/src/main/resources/assets/terraoriginum/geo/item/armor/ghost_armour.geo.json new file mode 100644 index 0000000..6577653 --- /dev/null +++ b/src/main/resources/assets/terraoriginum/geo/item/armor/ghost_armour.geo.json @@ -0,0 +1,135 @@ +{ + "format_version": "1.12.0", + "minecraft:geometry": [ + { + "description": { + "identifier": "geometry.ghost_armour", + "texture_width": 128, + "texture_height": 128, + "visible_bounds_width": 3, + "visible_bounds_height": 3.5, + "visible_bounds_offset": [0, 1.25, 0] + }, + "bones": [ + { + "name": "bipedHead", + "pivot": [0, 24, 0] + }, + { + "name": "armorHead", + "parent": "bipedHead", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-5, 24, -5], "size": [10, 9, 10], "uv": [0, 16]}, + {"origin": [-4, 24, -4], "size": [8, 8, 8], "uv": [32, 35]} + ] + }, + { + "name": "bandana", + "parent": "armorHead", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-6, 23, -6], "size": [12, 4, 12], "uv": [0, 0]} + ] + }, + { + "name": "bandanaEnd", + "parent": "armorHead", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 15, 6], "size": [3, 11, 0], "pivot": [-3, 24, 7], "rotation": [7.5, 0, 0], "uv": [72, 0]} + ] + }, + { + "name": "bipedBody", + "pivot": [0, 24, 0] + }, + { + "name": "armorBody", + "parent": "bipedBody", + "pivot": [0, 24, 0] + }, + { + "name": "torso", + "parent": "armorBody", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [-4, 12, -3], "size": [8, 12, 6], "uv": [40, 16]} + ] + }, + { + "name": "torsoEnd", + "parent": "armorBody", + "pivot": [0, 24, 0], + "cubes": [ + {"origin": [1, 7, 3], "size": [2, 10, 0], "pivot": [2, 15, 2], "rotation": [5, 0, 0], "uv": [76, 65]} + ] + }, + { + "name": "bipedRightArm", + "pivot": [-4, 22, 0] + }, + { + "name": "armorRightArm", + "parent": "bipedRightArm", + "pivot": [-4, 22, 0], + "cubes": [ + {"origin": [-9, 12, -3], "size": [5, 13, 6], "uv": [0, 51]} + ] + }, + { + "name": "bipedLeftArm", + "pivot": [4, 22, 0] + }, + { + "name": "armorLeftArm", + "parent": "bipedLeftArm", + "pivot": [4, 22, 0], + "cubes": [ + {"origin": [4, 12, -3], "size": [5, 13, 6], "uv": [22, 51]} + ] + }, + { + "name": "bipedLeftLeg", + "pivot": [2, 12, 0] + }, + { + "name": "armorLeftLeg", + "parent": "bipedLeftLeg", + "pivot": [2, 12, 0], + "cubes": [ + {"origin": [0, 4, -3], "size": [5, 9, 6], "uv": [44, 51]} + ] + }, + { + "name": "armorLeftBoot", + "parent": "bipedLeftLeg", + "pivot": [2, 12, 0], + "cubes": [ + {"origin": [0, 0, -3], "size": [5, 4, 6], "uv": [0, 70]} + ] + }, + { + "name": "bipedRightLeg", + "pivot": [-2, 12, 0] + }, + { + "name": "armorRightLeg", + "parent": "bipedRightLeg", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-5, 4, -3], "size": [5, 9, 6], "uv": [64, 34]} + ] + }, + { + "name": "armorRightBoot", + "parent": "bipedRightLeg", + "pivot": [-2, 12, 0], + "cubes": [ + {"origin": [-5, 0, -3], "size": [5, 4, 6], "uv": [22, 70]} + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/terraoriginum/textures/item/armor/ghost_armour.png b/src/main/resources/assets/terraoriginum/textures/item/armor/ghost_armour.png new file mode 100644 index 0000000000000000000000000000000000000000..b6670a58c33c69df98209bfb0ae9e292667b8b1f GIT binary patch literal 3805 zcmb`K=Reht`^VqMv8t0*ak6I$iR^uha41`Hj6>pNWSm1b=a7+bj*)ppBB5huRXEur z)GjUjD>*?P%+562mmZ`a6N6SAmVD?q&JV!rPyhqri7My z7Zc)+;TkG*8Gdg1jEKpH#T4cm!{%#b9u&2!SR6Gd+M^S#=NIrWm9~-Q{s&YN>E5X zQ5^Y-Xc-s}{at&EiHZk2acrz zSH~AVm{Lppc1RJAi;)X8NxFMymw4mUE@IB;AWx0yRGjo(`l78;NVDlwH<(*42)-+Z-pv5hjA+07GAo5}#kx`%5B4q+GL?;yu+9RV#fMEgOYOxEF*3i6%@M%1m774BM<<8#p8tpcLivq9{?r`q2^BmJ1P$!?ajOJ5<1jJ(2ydxG<+ zM$U{!^?K(-@ZO^7{sl9Z-K)HvQwRUz1R}22Mp~#ZxBBM?F$Y ze2m^ftodptSVTfYL1Ty?fyRRLSx`W5t~)!0<1G-a9o#{Uohlt}{dxb};nTbc_u4=v z!9vlTq?q6asX`G(*5o%88GqkJ!+yfluhfZB^2?F)j{aL2E0dr^S((8vY+tZxae@zD zK~n%SITTru65B9{t9`L&L0K?E{6dW@`H3SN*M6$J2SdR%oDl3odQ^K#dP^n?AyEVT z;DxeOsz*?W`grCo*=PrqXPI76Dh7O~o-8#WWIvXo{l?|0!z(J#Dj57F-qsIrN zgl!*&^M_3zX$!30!em_pfUdVG0=npa-T6s1rZ${o2)FuB=C_a!ofy$I zhN+6!daxPyg2Dp(&x)J!SRt|sL7eUAPjCRiBNf$H&^P7c>-u&`1`F-Yw3)4yCx$J) zOHkDTI4^XR7-R(+cMJ>{;q)$3&D#Vbk5XJC{kTXsK_dC>!-a3`^abQZVxK&{bFWWa ze(?KBnc2tt`sZfC$0ix&Au8^djNl(e+U;DNAvhwKmM;1;gq54IW5ANzHr+pRi~H?! z(cktQ%R*!bxCaWoEz{!~I8I2TY~Fv|RH2ft&X@?AM`H?BZ;bfSg-Lew2S z#ES*qS+_Lq_^XO9LV{SK7iQx-AL7{P=td0jpf1Elm0<{i(o!Z%3}PfK(_hQj!eEi1#e*7HTRvmnv-!%6oXS8IeILX|8 zcg{)xo2_6FLG;dz=w#c6cKZa5cWfXSxv?33-OT#b}c3|fBkQU}EUu+_7TK&qg z5BjH#zN08OnO}%rD$`h9Q`3asqscys6g|K=U%_5JT{~^E9chWMFU^X4UOl14#KQkM zn9fH@P$}_>wjl>hDPjPbulXI8J`#_v6TR9_ER2<<*DEf;jm#Y2Yw7(4HOlW?XLU3+ zBMpulR5r}gQDZ@9XX`&!6PY~U=~)Rktks_4XD_I9(<343PF_;2lcHdmw=8TrS@d3% zUd|2vh)FQZ7Y>m>Vmxq^#Rd_G}*Owws_Xu%vc?u5}5@uulUU zlY!H?_>KAeNX6D-WCSh7)yh;$Xmp=8!07xheFV(Bl6LA%>Xd<$eyLq9vF^ycg`6s~ zM(mtsW{GDVYl*(<^86mVBxG1)h=I#RJ+m2rd}OTXZPR?NQCQgn31TYb@wZ;(2^BZ&hnQt^t>&DxRop%+noZSzP z;J77~COeGlywbaWzi!i+vQMS^dXP}2en?Upu3u_KSwT$WdAA~6+wnkbviGF|W1j*g_>sdjZ(!z548i7_xSSg$Rl$dR z*)o?WZHzNv6)6DHXN9@(mGq%n z&8_v-C7IZbq&`ZP>3Nd_#(qd`e31LqT{SSVv>@8GEhy2Q;kJofTE9HHsZxkdYwzy1 zWT}+ncz!+}=a(V@5V_uD#e{_F5)(NT>Dy@yexvf$R)T@Jb>E?dOIpP`mn$v@IxV|1&9D44Yq z*ECPzaUfmarq>JZXs^$U$rn<}HtSKapZ~Jpl$Xu<&V67h5S=P! zrgI(eO@FESX!BZvGg?CyC8X19_O%+c2nbrbNk;2&JMoS}Gm~=lt`}4F>SV0fQa?;y z=80B0=7t|oD;qXJ&%uBCxHQVLR7`pBz1N3NKJ_9$RE(y%G;RLTgi_ir6|LVYp_`d` zF^F3KGKHr_2v+J0y57T~rx{5wv#({SX2)TVx>>Y6Ny~pAPcU+LaW8ObM6$0ZZ>-tU z`&%JC;HE?U?28zFm+H2?kby-0} zU7gS})ZX5%O=?Aul#eI3#EzcvPEJkLKurP?TdXCl@mUVImk#r$nx9#|W*JfBgO;%a z9(50|zj+$2KdN;zaUsm@Rk{KE_d@u=&dJFu4?oG^@T-ewE-tZ`;;HkP#JQa3m(BJ< zJoTckE>E=(m*~?C3pmq4rUwQtdiqILqP>j;8rEzC&WyjMYJ2jBd$P$tX;R%|l{p@i zGU0hSkMGm=521s5gCwNg{Af4g(D9J>lp!!sV86W^9~QcY^TFFUKVsqa0!9x_Y_C0C zI*hn*zx+z3Swr=M$P>?up{83*Trq360sQNhd0zix=~SC^k=Jq&gW)O%^S@2C9rm

_jJ#%&Mk*NHIgbuTpRR@r!b8ZWUwy%MSU-YtMHo;JN5^ zJ_IggIJj@#`)mHZkT8LV{QhOMArL}HoE?rJ?AooF3i k^jFO@DfxfIAj3waKY7PH%=)