From fa5119ab040c45ffd01b78d7aef7cfcf5f382b3c Mon Sep 17 00:00:00 2001 From: Martin Prokoph Date: Thu, 6 Nov 2025 22:40:21 +0100 Subject: [PATCH] stonecutter: support MC 1.20.1 (Fabric) --- .../core/mixin/MixinOptionsScreen.java | 37 ++++++++--- .../screen/MidnightConfigOverviewScreen.java | 8 ++- .../midnightdust/lib/config/ButtonEntry.java | 34 +++++++--- .../eu/midnightdust/lib/config/EntryInfo.java | 6 +- .../lib/config/MidnightConfig.java | 22 +++++-- .../lib/config/MidnightConfigListWidget.java | 12 +++- .../lib/config/MidnightConfigScreen.java | 59 +++++++++++++----- src/main/resources/fabric.mod.json | 2 +- .../midnightdust/test/MidnightLibExtras.java | 2 + .../test/config/MidnightConfigExample.java | 5 +- .../assets/midnightlib/icon/explorer.png | Bin 0 -> 136 bytes .../assets/midnightlib/icon/midnightlib.png | Bin 0 -> 136 bytes .../assets/midnightlib/icon/reset.png | Bin 0 -> 114 bytes 13 files changed, 139 insertions(+), 48 deletions(-) create mode 100644 versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/explorer.png create mode 100644 versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/midnightlib.png create mode 100644 versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/reset.png diff --git a/src/main/java/eu/midnightdust/core/mixin/MixinOptionsScreen.java b/src/main/java/eu/midnightdust/core/mixin/MixinOptionsScreen.java index bfac090..6693fa2 100644 --- a/src/main/java/eu/midnightdust/core/mixin/MixinOptionsScreen.java +++ b/src/main/java/eu/midnightdust/core/mixin/MixinOptionsScreen.java @@ -1,34 +1,42 @@ package eu.midnightdust.core.mixin; import eu.midnightdust.core.screen.MidnightConfigOverviewScreen; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.util.Objects; -import net.minecraft.client.gui.components.SpriteIconButton; -import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; + import net.minecraft.client.gui.screens.Screen; -import net.minecraft.client.gui.screens.options.OptionsScreen; + import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; -import static eu.midnightdust.core.MidnightLib.MOD_ID; +//? if >= 1.21 { + import org.spongepowered.asm.mixin.Final; + import org.spongepowered.asm.mixin.Shadow; + import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; + import net.minecraft.client.gui.components.SpriteIconButton; + import net.minecraft.client.gui.screens.options.OptionsScreen; + import static eu.midnightdust.core.MidnightLib.MOD_ID; +//?} else { +/*import net.minecraft.client.gui.components.TextAndImageButton; +import net.minecraft.client.gui.screens.OptionsScreen; +*///?} + import static eu.midnightdust.core.config.MidnightLibConfig.shouldShowButton; @Mixin(OptionsScreen.class) public abstract class MixinOptionsScreen extends Screen { + private MixinOptionsScreen(Component title) {super(title);} + //? if >= 1.20.4 { @Shadow @Final private HeaderAndFooterLayout layout; @Unique SpriteIconButton midnightlib$button = SpriteIconButton.builder(Component.translatable("midnightlib.overview.title"), ( buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this)), true) .sprite(ResourceLocation.fromNamespaceAndPath(MOD_ID,"icon/"+MOD_ID), 16, 16).size(20, 20).build(); - private MixinOptionsScreen(Component title) {super(title);} - @Inject(at = @At("HEAD"), method = "init") public void midnightlib$onInit(CallbackInfo ci) { if (shouldShowButton()) { @@ -46,4 +54,17 @@ public abstract class MixinOptionsScreen extends Screen { public void midnightlib$setButtonPos() { midnightlib$button.setPosition(layout.getWidth() / 2 + 158, layout.getY() + layout.getFooterHeight() - 4); } + //?} else { + /*@Unique TextAndImageButton midnightlib$button = TextAndImageButton.builder(Component.translatable("midnightlib.overview.title"), new ResourceLocation("midnightlib", "icon/midnightlib.png"), + button -> Objects.requireNonNull(minecraft).setScreen(new MidnightConfigOverviewScreen(this))).textureSize(16, 16).usedTextureSize(16, 16).offset(0, 2).build(); + + @Inject(at = @At("HEAD"), method = "init") + private void midnightlib$init(CallbackInfo ci) { + if (shouldShowButton()){ + midnightlib$button.setWidth(20); + midnightlib$button.setPosition(this.width / 2 + 158, this.height / 6 - 12); + this.addRenderableWidget(midnightlib$button); + } + } + *///?} } \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/core/screen/MidnightConfigOverviewScreen.java b/src/main/java/eu/midnightdust/core/screen/MidnightConfigOverviewScreen.java index 9cacb79..1fb5f2f 100644 --- a/src/main/java/eu/midnightdust/core/screen/MidnightConfigOverviewScreen.java +++ b/src/main/java/eu/midnightdust/core/screen/MidnightConfigOverviewScreen.java @@ -38,8 +38,14 @@ public class MidnightConfigOverviewScreen extends Screen { } @Override public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); + //? if >= 1.21 { + super.render(context, mouseX, mouseY, delta); + //?} else { + /*super.renderBackground(context); + *///?} this.list.render(context, mouseX, mouseY, delta); context.drawCenteredString(font, title, width / 2, 10, 0xFFFFFFFF); + //? if < 1.21 + /*super.render(context, mouseX, mouseY, delta);*/ } } \ No newline at end of file diff --git a/src/main/java/eu/midnightdust/lib/config/ButtonEntry.java b/src/main/java/eu/midnightdust/lib/config/ButtonEntry.java index 166e1f6..4c13191 100644 --- a/src/main/java/eu/midnightdust/lib/config/ButtonEntry.java +++ b/src/main/java/eu/midnightdust/lib/config/ButtonEntry.java @@ -2,6 +2,8 @@ package eu.midnightdust.lib.config; import com.google.common.collect.Lists; import java.util.List; +import java.util.Optional; + import net.minecraft.client.Minecraft; import net.minecraft.client.gui.Font; import net.minecraft.client.gui.GuiGraphics; @@ -35,7 +37,13 @@ public class ButtonEntry extends ContainerObjectSelectionList.Entry int scaledWidth = Minecraft.getInstance().getWindow().getGuiScaledWidth(); if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty())) { - title = new MultiLineTextWidget(12, 0, Component.translationArg(text), textRenderer).setCentered(centered); + title = new MultiLineTextWidget(12, 0, + //? if >= 1.21 { + Component.translationArg(text) + //?} else { + /*text.copy() + *///?} + , textRenderer).setCentered(centered); if (info != null) title.setTooltip(info.getTooltip(false)); title.setMaxWidth(!buttons.isEmpty() ? buttons.get(buttons.size() > 2 ? buttons.size() - 1 : 0).getX() - 16 : scaledWidth - 24); @@ -58,17 +66,19 @@ public class ButtonEntry extends ContainerObjectSelectionList.Entry title.setY(y + 5); title.render(context, mouseX, mouseY, tickDelta); - if (info.entry != null && !this.buttons.isEmpty() && this.buttons.getFirst() instanceof AbstractWidget widget) { - int idMode = this.info.entry.idMode(); - if (idMode != -1) context.renderItem(idMode == 0 ? - //? if >= 1.21.4 { + if (info.entry != null && !this.buttons.isEmpty()) { + Optional.ofNullable(this.buttons.get(0)).ifPresent(widget -> { + int idMode = this.info.entry.idMode(); + if (idMode != -1) context.renderItem(idMode == 0 ? + //? if >= 1.21.4 { BuiltInRegistries.ITEM.getValue(ResourceLocation.tryParse(this.info.tempValue)).getDefaultInstance() : BuiltInRegistries.BLOCK.getValue(ResourceLocation.tryParse(this.info.tempValue)).asItem().getDefaultInstance(), //?} else { - /*BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(this.info.tempValue)).getDefaultInstance() - : BuiltInRegistries.BLOCK.get(ResourceLocation.tryParse(this.info.tempValue)).asItem().getDefaultInstance(), - *///?} - widget.getX() + widget.getWidth() - 18, y + 2); + /*BuiltInRegistries.ITEM.get(ResourceLocation.tryParse(this.info.tempValue)).getDefaultInstance() + : BuiltInRegistries.BLOCK.get(ResourceLocation.tryParse(this.info.tempValue)).asItem().getDefaultInstance(), + *///?} + widget.getX() + widget.getWidth() - 18, y + 2); + }); } } } @@ -80,7 +90,11 @@ public class ButtonEntry extends ContainerObjectSelectionList.Entry /*public boolean mouseClicked(double d, double e, int i) { *///?} if (this.info != null && this.info.comment != null && !this.info.comment.url().isBlank()) - ConfirmLinkScreen.confirmLinkNow(Minecraft.getInstance().screen, this.info.comment.url(), true); + //? if >= 1.21 { + ConfirmLinkScreen.confirmLinkNow(Minecraft.getInstance().screen, this.info.comment.url(), true); + //?} else { + /*ConfirmLinkScreen.confirmLinkNow(this.info.comment.url(), Minecraft.getInstance().screen, true); + *///?} //? if >= 1.21.9 { return super.mouseClicked(click, doubled); //?} else { diff --git a/src/main/java/eu/midnightdust/lib/config/EntryInfo.java b/src/main/java/eu/midnightdust/lib/config/EntryInfo.java index fc05bad..fdd4a9d 100644 --- a/src/main/java/eu/midnightdust/lib/config/EntryInfo.java +++ b/src/main/java/eu/midnightdust/lib/config/EntryInfo.java @@ -3,6 +3,8 @@ package eu.midnightdust.lib.config; import eu.midnightdust.lib.util.PlatformFunctions; import java.lang.reflect.Field; import java.util.List; +import java.util.Optional; + import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.tabs.Tab; @@ -81,8 +83,8 @@ public class EntryInfo { if (!condition.requiredModId().isEmpty() && !PlatformFunctions.isModLoaded(condition.requiredModId())) this.conditionsMet = false; String requiredOption = condition.requiredOption().contains(":") ? condition.requiredOption() : (this.modid + ":" + condition.requiredOption()); - if (MidnightConfig.entries.get(requiredOption) instanceof EntryInfo info) - this.conditionsMet &= List.of(condition.requiredValue()).contains(info.tempValue); + Optional.ofNullable(MidnightConfig.entries.get(requiredOption)).ifPresent(info -> this.conditionsMet &= List.of(condition.requiredValue()).contains(info.tempValue)); + if (!this.conditionsMet) break; } if (prevConditionState != this.conditionsMet) MidnightConfig.configInstances.get(modid).reloadScreen = true; diff --git a/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java b/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java index 0903c5a..fbd4421 100644 --- a/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java +++ b/src/main/java/eu/midnightdust/lib/config/MidnightConfig.java @@ -45,10 +45,16 @@ public abstract class MidnightConfig { public boolean shouldSkipClass(Class clazz) { return false; } public boolean shouldSkipField(FieldAttributes fieldAttributes) { return fieldAttributes.getAnnotation(Entry.class) == null; } }) - .registerTypeAdapter(ResourceLocation.class, new TypeAdapter() { - public void write(JsonWriter out, ResourceLocation id) throws IOException { out.value(id.toString()); } - public ResourceLocation read(JsonReader in) throws IOException { return ResourceLocation.parse(in.nextString()); } - }).setPrettyPrinting().create(); + .registerTypeAdapter(ResourceLocation.class, + //? if >= 1.21.6 { + new TypeAdapter() { + public void write(JsonWriter out, ResourceLocation id) throws IOException { out.value(id.toString()); } + public ResourceLocation read(JsonReader in) throws IOException { return ResourceLocation.parse(in.nextString()); } + } + //?} else { + /*new ResourceLocation.Serializer() + *///?} + ).setPrettyPrinting().create(); protected static final LinkedHashMap entries = new LinkedHashMap<>(); // modid:fieldName -> EntryInfo @@ -124,7 +130,13 @@ public abstract class MidnightConfig { info.function = (BiFunction>) (t, b) -> s -> { s = s.trim(); if (!(s.isEmpty() || !isNumber || pattern.matcher(s).matches()) || - (info.dataType == ResourceLocation.class && ResourceLocation.read(s).isError())) return false; + (info.dataType == ResourceLocation.class && ResourceLocation.read(s) + //? if >= 1.21 { + .isError() + //?} else { + /*.error().isPresent() + *///?} + )) return false; Number value = 0; boolean inLimits = false; info.error = null; if (!(isNumber && s.isEmpty()) && !s.equals("-") && !s.equals(".")) { diff --git a/src/main/java/eu/midnightdust/lib/config/MidnightConfigListWidget.java b/src/main/java/eu/midnightdust/lib/config/MidnightConfigListWidget.java index 2f09ece..f87427c 100644 --- a/src/main/java/eu/midnightdust/lib/config/MidnightConfigListWidget.java +++ b/src/main/java/eu/midnightdust/lib/config/MidnightConfigListWidget.java @@ -18,7 +18,11 @@ public class MidnightConfigListWidget extends ContainerObjectSelectionList= 1.21 { + super(client, width, height, y, itemHeight); + //?} else { + /*super(client, width, height, y, height + y, itemHeight); + *///?} } @Override @@ -30,6 +34,7 @@ public class MidnightConfigListWidget extends ContainerObjectSelectionList= 1.21 { @Override public void renderListSeparators(GuiGraphics context) { if (renderHeaderSeparator) @@ -39,10 +44,11 @@ public class MidnightConfigListWidget extends ContainerObjectSelectionList= 1.21.6 { RenderPipelines.GUI_TEXTURED, //?} else if >= 1.21.4 { - //RenderType::guiTextured, - //?} + /*RenderType::guiTextured, + *///?} this.minecraft.level == null ? Screen.FOOTER_SEPARATOR : Screen.INWORLD_FOOTER_SEPARATOR, this.getX(), this.getBottom(), 0, 0, this.getWidth(), 2, 32, 2); } + //?} public void addButton(List buttons, Component text, EntryInfo info) { this.addEntry(new ButtonEntry(buttons, text, info)); diff --git a/src/main/java/eu/midnightdust/lib/config/MidnightConfigScreen.java b/src/main/java/eu/midnightdust/lib/config/MidnightConfigScreen.java index b7c49ba..3e67220 100644 --- a/src/main/java/eu/midnightdust/lib/config/MidnightConfigScreen.java +++ b/src/main/java/eu/midnightdust/lib/config/MidnightConfigScreen.java @@ -4,11 +4,8 @@ import com.google.common.collect.Lists; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.AbstractWidget; +import net.minecraft.client.gui.components.*; import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.components.SpriteIconButton; -import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.gui.components.tabs.GridLayoutTab; import net.minecraft.client.gui.components.tabs.Tab; import net.minecraft.client.gui.components.tabs.TabManager; @@ -32,6 +29,10 @@ import java.util.function.Predicate; import net.minecraft.client.input.KeyEvent; //?} +//? if >=1.21 { + import net.minecraft.client.gui.components.SpriteIconButton; +//?} + public class MidnightConfigScreen extends Screen { public MidnightConfig instance; public final String translationPrefix, modid; @@ -78,11 +79,7 @@ public class MidnightConfigScreen extends Screen { updateList(); list.setScrollAmount(0); } - //? >= 1.21.4 { - scrollProgress = list.scrollAmount(); - //?} else { - /*scrollProgress = list.getScrollAmount(); - *///?} + scrollProgress = /*? < 1.21.4 {*/ /*list.getScrollAmount() *//*?} else {*/ list.scrollAmount() /*?}*/; for (EntryInfo info : MidnightConfig.entries.values()) if (Objects.equals(modid, info.modid)) info.updateFieldValue(); updateButtons(); @@ -97,9 +94,10 @@ public class MidnightConfigScreen extends Screen { for (ButtonEntry entry : this.list.children()) { if (entry.buttons != null && entry.buttons.size() > 1 && entry.info.field != null) { - if (entry.buttons.get(0) instanceof AbstractWidget widget) + Optional.ofNullable(entry.buttons.get(0)).ifPresent(widget -> { if (widget.isFocused() || widget.isHovered()) widget.setTooltip(entry.info.getTooltip(true)); + }); if (entry.buttons.get(1) instanceof Button button) button.active = !Objects.equals(String.valueOf(entry.info.value), String.valueOf(entry.info.defaultValue)) && entry.info.conditionsMet; } @@ -169,12 +167,24 @@ public class MidnightConfigScreen extends Screen { if (!visibleButLocked) continue; } if (info.modid.equals(modid) && (info.tab == null || info.tab == tabManager.getCurrentTab())) { - SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"), (button -> { + //? if >= 1.21 { + SpriteIconButton resetButton = SpriteIconButton.builder(Component.translatable("controls.reset"), + //?} else { + /*TextAndImageButton resetButton = TextAndImageButton.builder(Component.translatable("controls.reset"), new ResourceLocation("midnightlib", "icon/reset.png"), + *///?} + (button -> { info.value = info.defaultValue; info.listIndex = 0; info.tempValue = info.toTemporaryValue(); updateList(); - }), true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/reset"), 12, 12).size(20, 20).build(); + }) + //? if >= 1.21 { + , true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/reset"), 12, 12).size(20, 20).build(); + //?} else { + /*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4).build(); + resetButton.setWidth(20); + *///?} + resetButton.setPosition(width - 205 + 150 + 25, 0); if (info.function != null) { @@ -225,7 +235,13 @@ public class MidnightConfigScreen extends Screen { } info.actionButton = colorButton; } else if (e.selectionMode() > -1) { - Button explorerButton = SpriteIconButton.builder(Component.empty(), + + Button explorerButton = + //? if >= 1.21 { + SpriteIconButton.builder(Component.empty(), + //?} else { + /*TextAndImageButton.builder(Component.empty(), new ResourceLocation("midnightlib", "icon/explorer.png"), + *///?} button -> new Thread(() -> { JFileChooser fileChooser = new JFileChooser(info.tempValue); fileChooser.setFileSelectionMode(e.selectionMode()); @@ -238,8 +254,13 @@ public class MidnightConfigScreen extends Screen { info.setValue(fileChooser.getSelectedFile().getAbsolutePath()); updateList(); } - }).start(), true - ).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/explorer"), 12, 12).size(20, 20).build(); + }).start() + //? if >= 1.21 { + , true).sprite(ResourceLocation.fromNamespaceAndPath("midnightlib", "icon/explorer"), 12, 12).size(20, 20) + //?} else { + /*).textureSize(12, 12).usedTextureSize(12, 12).offset(0, 4) + *///?} + .build(); explorerButton.setTooltip(Tooltip.create(Component.translatable("midnightconfig.action.file_chooser"))); explorerButton.setPosition(width - 185, 0); info.actionButton = explorerButton; @@ -269,8 +290,14 @@ public class MidnightConfigScreen extends Screen { @Override public void render(GuiGraphics context, int mouseX, int mouseY, float delta) { - super.render(context, mouseX, mouseY, delta); + //? if >= 1.21 { + super.render(context, mouseX, mouseY, delta); + //?} else { + /*super.renderBackground(context); + *///?} this.list.render(context, mouseX, mouseY, delta); if (tabs.size() < 2) context.drawCenteredString(font, title, width / 2, 10, 0xFFFFFFFF); + //? if < 1.21 + /*super.render(context, mouseX, mouseY, delta);*/ } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1778c72..c2c855e 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -34,7 +34,7 @@ }, "depends": { "fabric-resource-loader-v0": "*", - "minecraft": ">=1.21" + "minecraft": "*" }, "mixins": [ diff --git a/src/test/java/eu/midnightdust/test/MidnightLibExtras.java b/src/test/java/eu/midnightdust/test/MidnightLibExtras.java index 206307c..fcae6c9 100644 --- a/src/test/java/eu/midnightdust/test/MidnightLibExtras.java +++ b/src/test/java/eu/midnightdust/test/MidnightLibExtras.java @@ -1,5 +1,6 @@ package eu.midnightdust.test; +//? if >= 1.21.10 { import com.google.common.collect.Lists; import com.mojang.blaze3d.platform.InputConstants; import eu.midnightdust.lib.config.EntryInfo; @@ -97,3 +98,4 @@ public class MidnightLibExtras { } } } +//?} \ No newline at end of file diff --git a/src/test/java/eu/midnightdust/test/config/MidnightConfigExample.java b/src/test/java/eu/midnightdust/test/config/MidnightConfigExample.java index 5d8ed09..10f94b5 100644 --- a/src/test/java/eu/midnightdust/test/config/MidnightConfigExample.java +++ b/src/test/java/eu/midnightdust/test/config/MidnightConfigExample.java @@ -1,5 +1,6 @@ package eu.midnightdust.test.config; +//? if >= 1.21.10 { import com.google.common.collect.Lists; import eu.midnightdust.lib.config.MidnightConfigListWidget; import eu.midnightdust.lib.config.MidnightConfigScreen; @@ -169,5 +170,5 @@ public class MidnightConfigExample extends MidnightConfig { MidnightLibExtras.KeybindButton.add(Minecraft.getInstance().options.keyDrop, list, screen); } } - -} \ No newline at end of file +} +//?} \ No newline at end of file diff --git a/versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/explorer.png b/versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/explorer.png new file mode 100644 index 0000000000000000000000000000000000000000..d7f43110bfbd13d174f33377da698b9f2835d879 GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^JRr=$0wn*`OvwRKjKx9jP7LeL$-D$|I14-?iy0Wi zR6&^0Gf3qFP*B&?#WAGfRmdKI;Vst0N;WkumAu6 literal 0 HcmV?d00001 diff --git a/versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/midnightlib.png b/versions/1.20.1-fabric/src/main/resources/assets/midnightlib/icon/midnightlib.png new file mode 100644 index 0000000000000000000000000000000000000000..f76adb6b0fa44613c26f5f52246e26b89cc9cfc6 GIT binary patch literal 136 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6I14-?iy0WWg+Z8+Vb&Z8prDnf zi(^Q|tz-qMKkm#tDvkdw7=Hc|Z17T>^P^u{$f$8blemHVqe0S#gB MboFyt=akR{065nm8~^|S literal 0 HcmV?d00001