From f3cc4b7c6da312c7e30a9a65e15dea6fce026ccd Mon Sep 17 00:00:00 2001 From: Leo dev Date: Thu, 20 Mar 2025 00:28:52 +0100 Subject: [PATCH] config (not interactable) --- .../saturnclient/SaturnClient.java | 5 + .../saturnclient/config/ConfigManager.java | 152 ++++++++++++++++++ .../saturnclient/config/Property.java | 80 +++++++++ .../saturnclient/menus/HudEditor.java | 44 ++--- .../saturnclient/menus/ModMenu.java | 112 +++++++++++++ .../saturnmods/ModDimensions.java | 54 ++++--- .../saturnclient/saturnmods/ModManager.java | 4 +- .../saturnmods/mods/ArmorDisplay.java | 11 +- .../saturnmods/mods/Coordinates.java | 11 +- .../assets/saturnclient/font/fonts.json | 8 + .../textures/gui/components/settings.png | Bin 0 -> 2121 bytes 11 files changed, 435 insertions(+), 46 deletions(-) create mode 100644 src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java create mode 100644 src/main/java/org/saturnclient/saturnclient/config/Property.java create mode 100644 src/main/java/org/saturnclient/saturnclient/menus/ModMenu.java create mode 100644 src/main/resources/assets/saturnclient/font/fonts.json create mode 100644 src/main/resources/assets/saturnclient/textures/gui/components/settings.png diff --git a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java index 6029235..4c02940 100644 --- a/src/main/java/org/saturnclient/saturnclient/SaturnClient.java +++ b/src/main/java/org/saturnclient/saturnclient/SaturnClient.java @@ -1,10 +1,12 @@ package org.saturnclient.saturnclient; import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents; import net.minecraft.client.font.TextRenderer; import net.minecraft.util.math.ColorHelper; import org.saturnclient.saturnclient.cloaks.Cloaks; +import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnclient.event.KeyInputHandler; import org.saturnclient.saturnmods.ModManager; import org.saturnclient.saturnclient.auth.SaturnSocket; @@ -26,6 +28,9 @@ public class SaturnClient implements ModInitializer { public void onInitialize() { LOGGER.info("Initializing " + MOD_ID); ModManager.init(); + ConfigManager.load(); + + ClientLifecycleEvents.CLIENT_STOPPING.register(c -> ConfigManager.save()); KeyInputHandler.register(); if (SaturnSocket.authenticate()) { diff --git a/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java new file mode 100644 index 0000000..e74eaf9 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/config/ConfigManager.java @@ -0,0 +1,152 @@ +package org.saturnclient.saturnclient.config; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; + +import org.saturnclient.saturnclient.SaturnClient; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonElement; + +import net.minecraft.client.MinecraftClient; + +public class ConfigManager { + private static File configFile = new File(MinecraftClient.getInstance().runDirectory, "saturn.json"); + private static Map>> properties = new HashMap<>(); + + private String namespace; + + public ConfigManager(String namespace) { + this.namespace = namespace; + properties.put(namespace, new HashMap<>()); + } + + // Generic method to store any type of property + public Property property(String name, Property value) { + properties.get(namespace).put(name, value); + return value; + } + + @SuppressWarnings("unchecked") + public static void load() { + try { + SaturnClient.LOGGER.info("Starting to load config..."); + if (!configFile.exists()) { + configFile.createNewFile(); + } + + JsonObject jsonObject = JsonParser.parseString(new String(Files.readAllBytes(configFile.toPath()))) + .getAsJsonObject(); + + for (String namespace : properties.keySet()) { + JsonElement configElement = jsonObject.get(namespace); + + if (configElement == null) + continue; + + JsonObject config = jsonObject.get(namespace).getAsJsonObject(); + + if (config == null) { + SaturnClient.LOGGER.warn("No config found for namespace: " + namespace); + continue; + } + + Map> propertyMap = properties.get(namespace); + + for (String propertyName : propertyMap.keySet()) { + JsonElement c = config.get(propertyName); + + if (c == null) { + SaturnClient.LOGGER.warn("No property found in config for " + propertyName); + continue; + } + + SaturnClient.LOGGER.info("got prop " + c); + Property p = propertyMap.get(propertyName); + SaturnClient.LOGGER.info("setting prop " + propertyName + " to " + p.value); + + SaturnClient.LOGGER.info("Property type: " + p.getType()); + if (p.matchesJson(c)) { + switch (p.getType()) { + case BOOLEAN: + ((Property) p).value = c.getAsBoolean(); + break; + case INTEGER: + ((Property) p).value = c.getAsInt(); + break; + case FLOAT: + ((Property) p).value = c.getAsFloat(); + break; + case STRING: + ((Property) p).value = c.getAsString(); + break; + default: + break; + } + } else { + SaturnClient.LOGGER.warn("Property does not match JSON: " + propertyName); + } + } + } + } catch (IOException e) { + SaturnClient.LOGGER.error("Error reading the config file", e); + } + } + + public static void save() { + try { + SaturnClient.LOGGER.info("Starting to save config..."); + + JsonObject jsonObject = new JsonObject(); + + // Iterate through all namespaces and their properties + for (String namespace : properties.keySet()) { + JsonObject namespaceConfig = new JsonObject(); + Map> propertyMap = properties.get(namespace); + + // Iterate through each property in the namespace + for (String propertyName : propertyMap.keySet()) { + Property property = propertyMap.get(propertyName); + JsonElement propertyValue = null; + + // Convert the property value based on its type + switch (property.getType()) { + case BOOLEAN: + propertyValue = new JsonPrimitive((Boolean) property.value); + break; + case INTEGER: + propertyValue = new JsonPrimitive((Integer) property.value); + break; + case FLOAT: + propertyValue = new JsonPrimitive((Float) property.value); + break; + case STRING: + propertyValue = new JsonPrimitive((String) property.value); + break; + default: + SaturnClient.LOGGER.warn("Unknown property type for: " + propertyName); + break; + } + + if (propertyValue != null) { + namespaceConfig.add(propertyName, propertyValue); + } + } + + // Add the namespace config to the main JSON object + jsonObject.add(namespace, namespaceConfig); + } + + // Write the JSON object to the config file + Files.write(configFile.toPath(), jsonObject.toString().getBytes()); + SaturnClient.LOGGER.info("Config saved successfully."); + } catch (IOException e) { + SaturnClient.LOGGER.error("Error saving the config file", e); + } + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/config/Property.java b/src/main/java/org/saturnclient/saturnclient/config/Property.java new file mode 100644 index 0000000..6c563c3 --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/config/Property.java @@ -0,0 +1,80 @@ +package org.saturnclient.saturnclient.config; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; + +public class Property { + public enum PropertyType { + BOOLEAN, INTEGER, FLOAT, STRING, UNKNOWN + } + + public T value; + + public Property(T value) { + this.value = value; + } + + public boolean getBool() { + if (value instanceof Boolean) { + return (boolean) value; + } + throw new IllegalStateException("Property does not contain a boolean"); + } + + public int getInt() { + if (value instanceof Integer) { + return (int) value; + } + throw new IllegalStateException("Property does not contain an int"); + } + + public float getFloat() { + if (value instanceof Float) { + return (float) value; + } + throw new IllegalStateException("Property does not contain a float"); + } + + public String getString() { + if (value instanceof String) { + return (String) value; + } + throw new IllegalStateException("Property does not contain a string"); + } + + public PropertyType getType() { + if (value instanceof Boolean) { + return PropertyType.BOOLEAN; + } + if (value instanceof Integer) { + return PropertyType.INTEGER; + } + if (value instanceof Float) { + return PropertyType.FLOAT; + } + if (value instanceof String) { + return PropertyType.STRING; + } + return PropertyType.UNKNOWN; + } + + public boolean matchesJson(JsonElement element) { + if (element.isJsonPrimitive()) { + JsonPrimitive primitive = element.getAsJsonPrimitive(); + if (value instanceof Boolean && primitive.isBoolean()) + return true; + if (value instanceof Integer && primitive.isNumber()) + return true; + if (value instanceof Float && primitive.isNumber()) + return true; + if (value instanceof String && primitive.isString()) + return true; + } + return false; + } + + @Override + public String toString() { + return String.valueOf(value); + } +} diff --git a/src/main/java/org/saturnclient/saturnclient/menus/HudEditor.java b/src/main/java/org/saturnclient/saturnclient/menus/HudEditor.java index c1a20fa..9c29b2b 100644 --- a/src/main/java/org/saturnclient/saturnclient/menus/HudEditor.java +++ b/src/main/java/org/saturnclient/saturnclient/menus/HudEditor.java @@ -4,6 +4,8 @@ import net.minecraft.client.gui.DrawContext; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; + +import org.saturnclient.saturnclient.config.ConfigManager; import org.saturnclient.saturnmods.HudMod; import org.saturnclient.saturnmods.ModDimensions; import org.saturnclient.saturnmods.ModManager; @@ -38,8 +40,8 @@ public class HudEditor extends Screen { if (isCorner(mouseX, mouseY, dim)) { draggingMod = mod; resizing = true; - offsetX = (int) (mouseX - (dim.x + dim.width * dim.scale)); - offsetY = (int) (mouseY - (dim.y + dim.height * dim.scale)); + offsetX = (int) (mouseX - (dim.x.value + dim.width * dim.scale.value)); + offsetY = (int) (mouseY - (dim.y.value + dim.height * dim.scale.value)); return true; } @@ -47,8 +49,8 @@ public class HudEditor extends Screen { if (isInside(mouseX, mouseY, dim)) { draggingMod = mod; resizing = false; - offsetX = (int) (mouseX - dim.x); - offsetY = (int) (mouseY - dim.y); + offsetX = (int) (mouseX - dim.x.value); + offsetY = (int) (mouseY - dim.y.value); return true; } } @@ -72,12 +74,12 @@ public class HudEditor extends Screen { if (resizing) { // Scale based on cursor movement - float newScale = Math.max(0.5f, ((float) (mouseX - dim.x) / dim.width)); - dim.scale = newScale; + float newScale = Math.max(0.5f, ((float) (mouseX - dim.x.value) / dim.width)); + dim.scale.value = newScale; } else { // Move the mod - dim.x = (int) mouseX - offsetX; - dim.y = (int) mouseY - offsetY; + dim.x.value = (int) mouseX - offsetX; + dim.y.value = (int) mouseY - offsetY; } } return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); @@ -90,8 +92,8 @@ public class HudEditor extends Screen { MatrixStack matrices = context.getMatrices(); matrices.push(); - matrices.translate(dim.x, dim.y, 0); - matrices.scale(dim.scale, dim.scale, 1.0f); + matrices.translate(dim.x.value, dim.y.value, 0); + matrices.scale(dim.scale.value, dim.scale.value, 1.0f); // Render the mod mod.renderDummy(context); @@ -99,24 +101,30 @@ public class HudEditor extends Screen { matrices.pop(); // Draw border around mod - int borderX = dim.x; - int borderY = dim.y; - int borderW = (int) (dim.width * dim.scale); - int borderH = (int) (dim.height * dim.scale); + int borderX = dim.x.value; + int borderY = dim.y.value; + int borderW = (int) (dim.width * dim.scale.value); + int borderH = (int) (dim.height * dim.scale.value); context.drawBorder(borderX, borderY, borderW, borderH, 0xFFFFFFFF); // White border } } private boolean isInside(double mouseX, double mouseY, ModDimensions dim) { - return mouseX >= dim.x && mouseX <= dim.x + (dim.width * dim.scale) && - mouseY >= dim.y && mouseY <= dim.y + (dim.height * dim.scale); + return mouseX >= dim.x.value && mouseX <= dim.x.value + (dim.width * dim.scale.value) && + mouseY >= dim.y.value && mouseY <= dim.y.value + (dim.height * dim.scale.value); } private boolean isCorner(double mouseX, double mouseY, ModDimensions dim) { - float rightX = dim.x + dim.width * dim.scale; - float bottomY = dim.y + dim.height * dim.scale; + float rightX = dim.x.value + dim.width * dim.scale.value; + float bottomY = dim.y.value + dim.height * dim.scale.value; return Math.abs(mouseX - rightX) < RESIZE_MARGIN && Math.abs(mouseY - bottomY) < RESIZE_MARGIN; } + + @Override + public void close() { + ConfigManager.save(); + super.close(); + } } diff --git a/src/main/java/org/saturnclient/saturnclient/menus/ModMenu.java b/src/main/java/org/saturnclient/saturnclient/menus/ModMenu.java new file mode 100644 index 0000000..b42e49f --- /dev/null +++ b/src/main/java/org/saturnclient/saturnclient/menus/ModMenu.java @@ -0,0 +1,112 @@ +package org.saturnclient.saturnclient.menus; + +import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnmods.ModManager; +import org.saturnclient.saturnmods.SaturnMod; +import org.saturnclient.ui.SaturnUi; +import org.saturnclient.ui.Textures; +import org.saturnclient.ui.animations.FadeIn; +import org.saturnclient.ui.animations.Slide; +import org.saturnclient.ui.components.SaturnModComp; +import org.saturnclient.ui.widgets.SaturnClickableImage; +import org.saturnclient.ui.widgets.SaturnScroll; +import org.saturnclient.ui.widgets.SaturnSprite; +import net.minecraft.text.Text; + +public class ModMenu extends SaturnUi { + public ModMenu() { + super(Text.literal("Mods")); + } + + @Override + protected void init() { + int rectWidth = 330; + int rectHeight = 228; + int modsX = (width - rectWidth) / 2; + int modsY = (height - rectHeight + 15) / 2; + + draw(new SaturnSprite(Textures.SETTINGS_BG) + .setX(modsX) + .setY(modsY) + .setWidth(rectWidth) + .setHeight(rectHeight) + .setAnimations(new Slide(1, 10))); + + int tabsX = (width - 43) / 2; + int tabsY = modsY - 17; + + draw(new SaturnSprite(Textures.TABS) + .setX(tabsX) + .setY(tabsY) + .setWidth(43) + .setHeight(15) + .setAnimations(new Slide(1, 10))); + + int tabSize = 9; + tabsX = (width - tabSize) / 2; + draw(new SaturnClickableImage(Textures.SETTINGS, () -> { + System.out.println("Pressed"); + }) + .setX(tabsX) + .setY(tabsY + 3) + .setWidth(tabSize) + .setHeight(tabSize) + .setAnimations(new FadeIn(2)) + .setAnimations(new Slide(1, 10))); + + draw(new SaturnClickableImage(Textures.MODS_TAB, () -> { + System.out.println("Pressed"); + }) + .setX(tabsX - 12) + .setY(tabsY + 3) + .setWidth(tabSize) + .setHeight(tabSize) + .setAnimations(new FadeIn(2)) + .setAnimations(new Slide(1, 10))); + + draw(new SaturnClickableImage(Textures.SEARCH, () -> { + System.out.println("Pressed"); + }) + .setX(tabsX + 12) + .setY(tabsY + 3) + .setWidth(tabSize) + .setHeight(tabSize) + .setAnimations(new FadeIn(2)) + .setAnimations(new Slide(1, 10))); + + int modX = 0; + int modY = 0; + int col = 0; + + SaturnScroll modsScroll = new SaturnScroll(); + + for (SaturnMod mod : ModManager.MODS) { + modsScroll.draw(new SaturnModComp(mod) + .setX(modX) + .setY(modY) + .setWidth(86) + .setHeight(20)); + + col++; + + if (col < 3) { + modX += 86 + 18; + } else { + modX = 0; + modY += 20 + 20; + col = 0; + } + } + + draw(modsScroll.setX(modsX + 17).setY(modsY + 10).setWidth(rectWidth - 17).setHeight(rectHeight - 10) + .setAnimations(new Slide(1, 10))); + + super.init(); + } + + @Override + public void close() { + ConfigManager.save(); + super.close(); + } +} \ No newline at end of file diff --git a/src/main/java/org/saturnclient/saturnmods/ModDimensions.java b/src/main/java/org/saturnclient/saturnmods/ModDimensions.java index 4d28070..412eb55 100644 --- a/src/main/java/org/saturnclient/saturnmods/ModDimensions.java +++ b/src/main/java/org/saturnclient/saturnmods/ModDimensions.java @@ -1,39 +1,57 @@ package org.saturnclient.saturnmods; +import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.Property; + public class ModDimensions { - public int x = 0; - public int y = 0; - public float scale = 1.0f; + public Property x = new Property<>(0); + public Property y = new Property<>(0); + public Property scale = new Property<>(1.0f); public int width = 0; public int height = 0; - public ModDimensions() { + public ModDimensions(ConfigManager configManager) { + configManager.property("x", this.x); + configManager.property("y", this.y); + configManager.property("scale", this.scale); } - public ModDimensions(int x, int y) { - this.x = x; - this.y = y; + public ModDimensions(ConfigManager configManager, int x, int y) { + this.x.value = x; + this.y.value = y; + configManager.property("x", this.x); + configManager.property("y", this.y); + configManager.property("scale", this.scale); } - public ModDimensions(int x, int y, int width, int height) { - this.x = x; - this.y = y; + public ModDimensions(ConfigManager configManager, int x, int y, int width, int height) { + this.x.value = x; + this.y.value = y; this.width = width; this.height = height; + configManager.property("x", this.x); + configManager.property("y", this.y); + configManager.property("scale", this.scale); } - public ModDimensions(int x, int y, float scale) { - this.x = x; - this.y = y; - this.scale = scale; + public ModDimensions(ConfigManager configManager, int x, int y, float scale) { + this.x.value = x; + this.y.value = y; + this.scale.value = scale; + configManager.property("x", this.x); + configManager.property("y", this.y); + configManager.property("scale", this.scale); } - public ModDimensions(int x, int y, int width, int height, float scale) { - this.x = x; - this.y = y; + public ModDimensions(ConfigManager configManager, int x, int y, int width, int height, float scale) { + this.x.value = x; + this.y.value = y; + this.scale.value = scale; this.width = width; this.height = height; - this.scale = scale; + configManager.property("x", this.x); + configManager.property("y", this.y); + configManager.property("scale", this.scale); } } diff --git a/src/main/java/org/saturnclient/saturnmods/ModManager.java b/src/main/java/org/saturnclient/saturnmods/ModManager.java index c31b383..56b1798 100644 --- a/src/main/java/org/saturnclient/saturnmods/ModManager.java +++ b/src/main/java/org/saturnclient/saturnmods/ModManager.java @@ -30,9 +30,9 @@ public class ModManager { MatrixStack matrices = context.getMatrices(); matrices.push(); - matrices.translate(dim.x, dim.y, 0); + matrices.translate(dim.x.value, (float) dim.y.value, 0); - matrices.scale(dim.scale, dim.scale, 1.0f); + matrices.scale(dim.scale.value, dim.scale.value, 1.0f); ((HudMod) m).render(context); diff --git a/src/main/java/org/saturnclient/saturnmods/mods/ArmorDisplay.java b/src/main/java/org/saturnclient/saturnmods/mods/ArmorDisplay.java index 88c8698..80c4df6 100644 --- a/src/main/java/org/saturnclient/saturnmods/mods/ArmorDisplay.java +++ b/src/main/java/org/saturnclient/saturnmods/mods/ArmorDisplay.java @@ -1,6 +1,8 @@ package org.saturnclient.saturnmods.mods; import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnmods.HudMod; import org.saturnclient.saturnmods.ModDimensions; import org.saturnclient.saturnmods.SaturnMod; @@ -16,8 +18,9 @@ import net.minecraft.item.Items; import net.minecraft.util.Identifier; public class ArmorDisplay implements SaturnMod, HudMod { - private static ModDimensions dimensions = new ModDimensions(0, 0, 34, 75); - public static boolean enabled = false; + private static ConfigManager config = new ConfigManager("armor"); + private static ModDimensions dimensions = new ModDimensions(config, 0, 0, 34, 75); + public static Property enabled = config.property("enabled", new Property<>(false)); private boolean renderItem(DrawContext context, ItemStack item, int y) { if (item.isEmpty()) { @@ -101,10 +104,10 @@ public class ArmorDisplay implements SaturnMod, HudMod { } public boolean isEnabled() { - return enabled; + return enabled.value; } public void setEnabled(boolean e) { - enabled = e; + enabled.value = e; } } diff --git a/src/main/java/org/saturnclient/saturnmods/mods/Coordinates.java b/src/main/java/org/saturnclient/saturnmods/mods/Coordinates.java index cd5ea1e..dde209e 100644 --- a/src/main/java/org/saturnclient/saturnmods/mods/Coordinates.java +++ b/src/main/java/org/saturnclient/saturnmods/mods/Coordinates.java @@ -1,6 +1,8 @@ package org.saturnclient.saturnmods.mods; import org.saturnclient.saturnclient.SaturnClient; +import org.saturnclient.saturnclient.config.ConfigManager; +import org.saturnclient.saturnclient.config.Property; import org.saturnclient.saturnmods.HudMod; import org.saturnclient.saturnmods.ModDimensions; import org.saturnclient.saturnmods.SaturnMod; @@ -12,8 +14,9 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.Identifier; public class Coordinates implements SaturnMod, HudMod { - private static ModDimensions dimensions = new ModDimensions(); - public static boolean enabled = false; + private static ConfigManager config = new ConfigManager("coords"); + private static ModDimensions dimensions = new ModDimensions(config); + public static Property enabled = config.property("enabled", new Property<>(false)); public Coordinates() { } @@ -58,10 +61,10 @@ public class Coordinates implements SaturnMod, HudMod { } public boolean isEnabled() { - return enabled; + return enabled.value; } public void setEnabled(boolean e) { - enabled = e; + enabled.value = e; } } diff --git a/src/main/resources/assets/saturnclient/font/fonts.json b/src/main/resources/assets/saturnclient/font/fonts.json new file mode 100644 index 0000000..3f2448f --- /dev/null +++ b/src/main/resources/assets/saturnclient/font/fonts.json @@ -0,0 +1,8 @@ +{ + "providers": [ + { + "type": "reference", + "id": "saturnclient:panton" + } + ] +} diff --git a/src/main/resources/assets/saturnclient/textures/gui/components/settings.png b/src/main/resources/assets/saturnclient/textures/gui/components/settings.png new file mode 100644 index 0000000000000000000000000000000000000000..93074e02b0a391ecb6df8694cbcf85f646ad40df GIT binary patch literal 2121 zcmV-P2)6f$P)V!8n2^?|f_n?_Rlw zH$Yc)_spna!97O@F+KfJO?_@v_lVr!1~-@^7UT-?@#Dv$-|xRTIXQWbe+zsDwdTWx zg@yg&vJr? zAFb1eNhV|y(C5#et4MVT5ZpE*+3?Y$M+^M$J1)Obh8q0%@uRU8rlK#IK=Z)U_ca|p ze*E~HX1TCFf=T|(eiu7n91441G9a4<;YWGR0s?qrbn~{s(chO$$R5QmEuh!S&TUeV zQ$SCB7r~TEtpl`cs$9RmK8O+I=g*(Zaz0!i!m%D|DZ$sTU)RxIC_|RYb>W!MFkjOm z$9(YM!G5>M`V%Z>7aFlq3CgkN zO?-W>3|k^<4aEQ)^?{}_zWHw5y0znT>{_1?q6CCRE@D!$*dpeBCYiXOLNrYQ!hVT` z?ppVN9*ps4T{@Vrh7x^NA3l6|7`ibiAg2WfqG(ME1huDvr9~|;g^*T4LNc8+%?iSK zCvy-Ev}YyuW|+jP7{00@2DFM0D>ns1pCgfGm4KOWQffTB*9kPbPb3Ni95ekYd?cYTqiJA`Q$)9+wkB0T$eOn> z_?oW`6Te1!uvPu}-=UCz5)nlc~meWy@>LkMWe*GCl)!t1H;Iy3F7tP!_?qbmo#HdYaQ*OQra zm%^#YC!Z==ul#Q=48dgQd$>O7YEFi9JouzO$r=QQ_E+1wa17(EBbEJH^J;-d(;zF% zm%fY0aW-nd+A^g+Ll{g+T(*t7JJ5`_LS=*Xx9;+h9rUsCZm}&Bc20j z(k91{M9}xpL5q?T(ww!vmVmZI$4pfrs2KiJEs}}uSXzQ(q-YZ7rDL`7a37<=5Y8y@pl9`P%eR@S#@)Mj$Cmmz?1b_eIAofIb`Oc& z22+WuXb+H+Sf$tjoxIUrJ(Q3+UaE&*L@=9o1u`zi(iD}622vI?FLQnAI|^UB6;Yu* zjFKZ!z!C|zvsXhAIaqS#0Qm8%tli*WZLl@b7orL_l(g28RPVf2q6y(>^D^~$4NkNY zLsz0}(kyJTexfuF7%99H^m@;H*U4>Sc#XSfTN%S!=SHMk7R96?@TGbl8A4Lgo=lXg zsWf{9WE8qW0pJYyQTxi+MdJ0nRI-`8tARzwgCvA<-HDdUzT{RDPwD9>b*`j zZ3x?oXaQA8rqVps`~(*DUg@(I!-gH<8~NH;4)I-g{!QDJeM^Qdkq8QiMA22^)Fcy6 za-#JInbSh*Y{$eBQjI8j!CH~%(4r&-zQf-X^MHZ^0vUT3C{2`BvPUvzP=guEChM)M zK6wnYcBiq0uVaWuxd)^ADE=lM2Mnc2W~zZjZ-!2V#q5sGVe^ss+fshDSx5PeS*^STabvhAa89MY*NX2z`(_2>$CMS;!0g5P<@aNfd9nU8@7_xPIBKB|D+ zw$GyH`Z9MjAn`Y~MV=kc1F<~Eb#QO#UTbQ-@mIlZJaV^U6g!{W-54oD?rC$WCgy6< zR7WknAjkOT4oQwAf&}tJM!(;B@=QAXrf%_Ue!*WI5Gis^>A-ZDyNBMbJC&QE&>=fBFsDkl2Kn&DZ2IhtAQH;mlq*($?Hoq#FkzGJEHB$W)Q{lbnv(i<;Ed|+4 ztPWSS=lfqzFGQ@VE84Ttw|f(1N5DV>00000NkvXXu0mjfte@(% literal 0 HcmV?d00001