mirror of
https://github.com/TeamMidnightDust/MidnightLib.git
synced 2025-12-15 17:05:09 +01:00
MidnightLib 0.4.0 - Color support, Client and Server-only config options, cleanup
This commit is contained in:
@@ -8,7 +8,7 @@ org.gradle.jvmargs=-Xmx1G
|
|||||||
loader_version=0.11.7
|
loader_version=0.11.7
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 0.3.1
|
mod_version = 0.4.0
|
||||||
maven_group = eu.midnightdust
|
maven_group = eu.midnightdust
|
||||||
archives_base_name = midnightlib
|
archives_base_name = midnightlib
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class MidnightLibServer implements DedicatedServerModInitializer {
|
|||||||
public void onInitializeServer() {
|
public void onInitializeServer() {
|
||||||
MidnightConfig.configClass.forEach((modid, config) -> {
|
MidnightConfig.configClass.forEach((modid, config) -> {
|
||||||
for (Field field : config.getFields()) {
|
for (Field field : config.getFields()) {
|
||||||
if (field.isAnnotationPresent(MidnightConfig.Entry.class))
|
if (field.isAnnotationPresent(MidnightConfig.Entry.class) && !field.isAnnotationPresent(MidnightConfig.Client.class))
|
||||||
new AutoCommand(field, modid).register();
|
new AutoCommand(field, modid).register();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.midnightdust.hats.witch;
|
package eu.midnightdust.hats.witch;
|
||||||
|
|
||||||
import eu.midnightdust.hats.web.HatLoader;
|
import eu.midnightdust.hats.web.HatLoader;
|
||||||
|
import eu.midnightdust.lib.config.MidnightConfig;
|
||||||
import eu.midnightdust.lib.util.MidnightColorUtil;
|
import eu.midnightdust.lib.util.MidnightColorUtil;
|
||||||
import net.fabricmc.api.EnvType;
|
import net.fabricmc.api.EnvType;
|
||||||
import net.fabricmc.api.Environment;
|
import net.fabricmc.api.Environment;
|
||||||
@@ -68,15 +69,14 @@ public class WitchHatFeatureRenderer<T extends LivingEntity, M extends EntityMod
|
|||||||
if (uuid.equals(MOTSCHEN)) {
|
if (uuid.equals(MOTSCHEN)) {
|
||||||
return MOTSCHEN_COLOR;
|
return MOTSCHEN_COLOR;
|
||||||
} else if (HatLoader.PLAYER_HATS != null && HatLoader.PLAYER_HATS.containsKey(uuid)) {
|
} else if (HatLoader.PLAYER_HATS != null && HatLoader.PLAYER_HATS.containsKey(uuid)) {
|
||||||
switch (HatLoader.PLAYER_HATS.get(uuid).getHatType()) {
|
return switch (HatLoader.PLAYER_HATS.get(uuid).getHatType()) {
|
||||||
case "adopter": return ADOPTER_COLOR;
|
case "adopter" -> ADOPTER_COLOR;
|
||||||
case "contributer": // old name
|
case "contributer", "modder" -> MODDER_COLOR;
|
||||||
case "modder": return MODDER_COLOR;
|
case "friend" -> FRIEND_COLOR;
|
||||||
case "friend": return FRIEND_COLOR;
|
case "donator", "donor" -> DONOR_COLOR;
|
||||||
case "donator": // old name
|
case "social" -> SOCIAL_COLOR;
|
||||||
case "donor": return DONOR_COLOR;
|
default -> MidnightColorUtil.hex2Rgb(HatLoader.PLAYER_HATS.get(uuid).getHatType());
|
||||||
case "social": return SOCIAL_COLOR;
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ import net.minecraft.client.gui.widget.TextFieldWidget;
|
|||||||
import net.minecraft.client.resource.language.I18n;
|
import net.minecraft.client.resource.language.I18n;
|
||||||
import net.minecraft.client.util.math.MatrixStack;
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
|
import net.minecraft.text.Style;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.text.TranslatableText;
|
import net.minecraft.text.TranslatableText;
|
||||||
import net.minecraft.util.Formatting;
|
import net.minecraft.util.Formatting;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
@@ -34,12 +36,13 @@ import java.lang.reflect.Modifier;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.List;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/** MidnightConfig v2.0.0 by TeamMidnightDust & Motschen
|
/** MidnightConfig v2.1.0 by TeamMidnightDust & Motschen
|
||||||
* Single class config library - feel free to copy!
|
* Single class config library - feel free to copy!
|
||||||
*
|
*
|
||||||
* Based on https://github.com/Minenash/TinyConfig
|
* Based on https://github.com/Minenash/TinyConfig
|
||||||
@@ -49,6 +52,7 @@ import java.util.regex.Pattern;
|
|||||||
public abstract class MidnightConfig {
|
public abstract class MidnightConfig {
|
||||||
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
|
private static final Pattern INTEGER_ONLY = Pattern.compile("(-?[0-9]*)");
|
||||||
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
private static final Pattern DECIMAL_ONLY = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
||||||
|
private static final Pattern HEXADECIMAL_ONLY = Pattern.compile("(-?[#0-9a-fA-F]*)");
|
||||||
|
|
||||||
private static final List<EntryInfo> entries = new ArrayList<>();
|
private static final List<EntryInfo> entries = new ArrayList<>();
|
||||||
|
|
||||||
@@ -65,6 +69,7 @@ public abstract class MidnightConfig {
|
|||||||
String id;
|
String id;
|
||||||
TranslatableText name;
|
TranslatableText name;
|
||||||
int index;
|
int index;
|
||||||
|
ClickableWidget colorButton;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final Map<String,Class<?>> configClass = new HashMap<>();
|
public static final Map<String,Class<?>> configClass = new HashMap<>();
|
||||||
@@ -78,7 +83,7 @@ public abstract class MidnightConfig {
|
|||||||
|
|
||||||
for (Field field : config.getFields()) {
|
for (Field field : config.getFields()) {
|
||||||
EntryInfo info = new EntryInfo();
|
EntryInfo info = new EntryInfo();
|
||||||
if (field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class))
|
if ((field.isAnnotationPresent(Entry.class) || field.isAnnotationPresent(Comment.class)) && !field.isAnnotationPresent(Server.class))
|
||||||
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) initClient(modid, field, info);
|
if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) initClient(modid, field, info);
|
||||||
if (field.isAnnotationPresent(Entry.class))
|
if (field.isAnnotationPresent(Entry.class))
|
||||||
try {
|
try {
|
||||||
@@ -107,7 +112,8 @@ public abstract class MidnightConfig {
|
|||||||
|
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
if (!e.name().equals("")) info.name = new TranslatableText(e.name());
|
if (!e.name().equals("")) info.name = new TranslatableText(e.name());
|
||||||
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, e.min(), e.max(), true);
|
if (type == int.class) textField(info, Integer::parseInt, INTEGER_ONLY, (int) e.min(), (int) e.max(), true);
|
||||||
|
else if (type == float.class) textField(info, Float::parseFloat, DECIMAL_ONLY, (float) e.min(), (float) e.max(), false);
|
||||||
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
|
else if (type == double.class) textField(info, Double::parseDouble, DECIMAL_ONLY, e.min(), e.max(), false);
|
||||||
else if (type == String.class || type == List.class) {
|
else if (type == String.class || type == List.class) {
|
||||||
info.max = e.max() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) e.max();
|
info.max = e.max() == Double.MAX_VALUE ? Integer.MAX_VALUE : (int) e.max();
|
||||||
@@ -160,6 +166,13 @@ public abstract class MidnightConfig {
|
|||||||
((List<String>) info.value).set(info.index, Arrays.stream(info.tempValue.replace("[", "").replace("]", "").split(", ")).toList().get(0));
|
((List<String>) info.value).set(info.index, Arrays.stream(info.tempValue.replace("[", "").replace("]", "").split(", ")).toList().get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info.field.getAnnotation(Entry.class).isColor()) {
|
||||||
|
if (!s.contains("#")) s = '#' + s;
|
||||||
|
if (!HEXADECIMAL_ONLY.matcher(s).matches()) return false;
|
||||||
|
try {
|
||||||
|
info.colorButton.setMessage(new LiteralText("⬛").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -251,7 +264,7 @@ public abstract class MidnightConfig {
|
|||||||
if (info.widget instanceof Map.Entry) {
|
if (info.widget instanceof Map.Entry) {
|
||||||
Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
|
Map.Entry<ButtonWidget.PressAction, Function<Object, Text>> widget = (Map.Entry<ButtonWidget.PressAction, Function<Object, Text>>) info.widget;
|
||||||
if (info.field.getType().isEnum()) widget.setValue(value -> new TranslatableText(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
if (info.field.getType().isEnum()) widget.setValue(value -> new TranslatableText(translationPrefix + "enum." + info.field.getType().getSimpleName() + "." + info.value.toString()));
|
||||||
this.list.addButton(new ButtonWidget(width - 160, 0,150, 20, widget.getValue().apply(info.value), widget.getKey()),resetButton, null,name);
|
this.list.addButton(List.of(new ButtonWidget(width - 160, 0,150, 20, widget.getValue().apply(info.value), widget.getKey()),resetButton), name);
|
||||||
} else if (info.field.getType() == List.class) {
|
} else if (info.field.getType() == List.class) {
|
||||||
if (!reload) info.index = 0;
|
if (!reload) info.index = 0;
|
||||||
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null);
|
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null);
|
||||||
@@ -271,16 +284,24 @@ public abstract class MidnightConfig {
|
|||||||
Objects.requireNonNull(client).setScreen(this);
|
Objects.requireNonNull(client).setScreen(this);
|
||||||
list.setScrollAmount(scrollAmount);
|
list.setScrollAmount(scrollAmount);
|
||||||
}));
|
}));
|
||||||
this.list.addButton(widget, resetButton, cycleButton, name);
|
this.list.addButton(List.of(widget, resetButton, cycleButton), name);
|
||||||
} else if (info.widget != null) {
|
} else if (info.widget != null) {
|
||||||
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null);
|
TextFieldWidget widget = new TextFieldWidget(textRenderer, width - 160, 0, 150, 20, null);
|
||||||
widget.setMaxLength(info.width);
|
widget.setMaxLength(info.width);
|
||||||
widget.setText(info.tempValue);
|
widget.setText(info.tempValue);
|
||||||
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done);
|
Predicate<String> processor = ((BiFunction<TextFieldWidget, ButtonWidget, Predicate<String>>) info.widget).apply(widget, done);
|
||||||
widget.setTextPredicate(processor);
|
widget.setTextPredicate(processor);
|
||||||
this.list.addButton(widget, resetButton, null, name);
|
if (info.field.getAnnotation(Entry.class).isColor()) {
|
||||||
|
resetButton.setWidth(20);
|
||||||
|
resetButton.setMessage(new LiteralText("R").formatted(Formatting.RED));
|
||||||
|
ButtonWidget colorButton = new ButtonWidget(width - 185, 0, 20, 20, new LiteralText("⬛"), (button -> {}));
|
||||||
|
try {colorButton.setMessage(new LiteralText("⬛").setStyle(Style.EMPTY.withColor(Color.decode(info.tempValue).getRGB())));} catch (Exception ignored) {}
|
||||||
|
info.colorButton = colorButton;
|
||||||
|
this.list.addButton(List.of(widget, colorButton, resetButton), name);
|
||||||
|
}
|
||||||
|
else this.list.addButton(List.of(widget, resetButton), name);
|
||||||
} else {
|
} else {
|
||||||
this.list.addButton(null,null,null,name);
|
this.list.addButton(List.of(),name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -325,15 +346,15 @@ public abstract class MidnightConfig {
|
|||||||
@Override
|
@Override
|
||||||
public int getScrollbarPositionX() { return this.width -7; }
|
public int getScrollbarPositionX() { return this.width -7; }
|
||||||
|
|
||||||
public void addButton(ClickableWidget button, ClickableWidget resetButton, ClickableWidget indexButton, Text text) {
|
public void addButton(List<ClickableWidget> buttons, Text text) {
|
||||||
this.addEntry(ButtonEntry.create(button, text, resetButton, indexButton));
|
this.addEntry(ButtonEntry.create(buttons, text));
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public int getRowWidth() { return 10000; }
|
public int getRowWidth() { return 10000; }
|
||||||
public Optional<ClickableWidget> getHoveredButton(double mouseX, double mouseY) {
|
public Optional<ClickableWidget> getHoveredButton(double mouseX, double mouseY) {
|
||||||
for (ButtonEntry buttonEntry : this.children()) {
|
for (ButtonEntry buttonEntry : this.children()) {
|
||||||
if (buttonEntry.button != null && buttonEntry.button.isMouseOver(mouseX, mouseY)) {
|
if (!buttonEntry.buttons.isEmpty() && buttonEntry.buttons.get(0).isMouseOver(mouseX, mouseY)) {
|
||||||
return Optional.of(buttonEntry.button);
|
return Optional.of(buttonEntry.buttons.get(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
@@ -341,53 +362,37 @@ public abstract class MidnightConfig {
|
|||||||
}
|
}
|
||||||
public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
|
public static class ButtonEntry extends ElementListWidget.Entry<ButtonEntry> {
|
||||||
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
private static final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
|
||||||
public final ClickableWidget button;
|
public final List<ClickableWidget> buttons;
|
||||||
private final ClickableWidget resetButton;
|
|
||||||
private final ClickableWidget indexButton;
|
|
||||||
private final Text text;
|
private final Text text;
|
||||||
private final List<ClickableWidget> children = new ArrayList<>();
|
private final List<ClickableWidget> children = new ArrayList<>();
|
||||||
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
|
public static final Map<ClickableWidget, Text> buttonsWithText = new HashMap<>();
|
||||||
|
|
||||||
private ButtonEntry(ClickableWidget button, Text text, ClickableWidget resetButton, ClickableWidget indexButton) {
|
private ButtonEntry(List<ClickableWidget> buttons, Text text) {
|
||||||
buttonsWithText.put(button,text);
|
if (!buttons.isEmpty()) buttonsWithText.put(buttons.get(0),text);
|
||||||
this.button = button;
|
this.buttons = buttons;
|
||||||
this.resetButton = resetButton;
|
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.indexButton = indexButton;
|
children.addAll(buttons);
|
||||||
if (button != null) children.add(button);
|
|
||||||
if (resetButton != null) children.add(resetButton);
|
|
||||||
if (indexButton != null) children.add(indexButton);
|
|
||||||
}
|
}
|
||||||
public static ButtonEntry create(ClickableWidget button, Text text, ClickableWidget resetButton, ClickableWidget indexButton) {
|
public static ButtonEntry create(List<ClickableWidget> buttons, Text text) {
|
||||||
return new ButtonEntry(button, text, resetButton, indexButton);
|
return new ButtonEntry(buttons, text);
|
||||||
}
|
}
|
||||||
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||||
if (button != null) {
|
buttons.forEach(b -> { b.y = y; b.render(matrices, mouseX, mouseY, tickDelta); });
|
||||||
button.y = y;
|
if (text != null && (!text.getString().contains("spacer") || !buttons.isEmpty()))
|
||||||
button.render(matrices, mouseX, mouseY, tickDelta);
|
|
||||||
}
|
|
||||||
if (resetButton != null) {
|
|
||||||
resetButton.y = y;
|
|
||||||
resetButton.render(matrices, mouseX, mouseY, tickDelta);
|
|
||||||
}
|
|
||||||
if (indexButton != null) {
|
|
||||||
indexButton.y = y;
|
|
||||||
indexButton.render(matrices, mouseX, mouseY, tickDelta);
|
|
||||||
}
|
|
||||||
if (text != null && (!text.getString().contains("spacer") || button != null))
|
|
||||||
DrawableHelper.drawTextWithShadow(matrices,textRenderer, text,12,y+5,0xFFFFFF);
|
DrawableHelper.drawTextWithShadow(matrices,textRenderer, text,12,y+5,0xFFFFFF);
|
||||||
}
|
}
|
||||||
public List<? extends Element> children() {return children;}
|
public List<? extends Element> children() {return children;}
|
||||||
public List<? extends Selectable> selectableChildren() {return children;}
|
public List<? extends Selectable> selectableChildren() {return children;}
|
||||||
}
|
}
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Entry {
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
public @interface Entry {
|
|
||||||
int width() default 100;
|
int width() default 100;
|
||||||
double min() default Double.MIN_NORMAL;
|
double min() default Double.MIN_NORMAL;
|
||||||
double max() default Double.MAX_VALUE;
|
double max() default Double.MAX_VALUE;
|
||||||
String name() default "";
|
String name() default "";
|
||||||
|
boolean isColor() default false;
|
||||||
}
|
}
|
||||||
|
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Client {}
|
||||||
|
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Server {}
|
||||||
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment {}
|
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Comment {}
|
||||||
|
|
||||||
public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
|
public static class HiddenAnnotationExclusionStrategy implements ExclusionStrategy {
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ public class MidnightColorUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @credit https://stackoverflow.com/questions/4129666/how-to-convert-hex-to-rgb-using-java
|
* @param colorStr e.g. "FFFFFF" or "#FFFFFF"
|
||||||
* @param colorStr e.g. "FFFFFF"
|
|
||||||
* @return Color as RGB
|
* @return Color as RGB
|
||||||
*/
|
*/
|
||||||
public static Color hex2Rgb(String colorStr) {
|
public static Color hex2Rgb(String colorStr) {
|
||||||
return new Color(
|
try {
|
||||||
Integer.valueOf( colorStr.substring( 0, 2 ), 16 ),
|
return Color.decode("#" + colorStr.replace("#", ""));
|
||||||
Integer.valueOf( colorStr.substring( 2, 4 ), 16 ),
|
} catch (Exception ignored) {}
|
||||||
Integer.valueOf( colorStr.substring( 4, 6 ), 16 ));
|
return Color.BLACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Color radialRainbow(float saturation, float brightness) {
|
public static Color radialRainbow(float saturation, float brightness) {
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
package eu.midnightdust.lib.util.render.entity;
|
|
||||||
|
|
||||||
import net.minecraft.client.render.RenderLayer;
|
|
||||||
import net.minecraft.client.render.entity.feature.EyesFeatureRenderer;
|
|
||||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
|
||||||
import net.minecraft.client.render.entity.model.EntityModel;
|
|
||||||
import net.minecraft.entity.LivingEntity;
|
|
||||||
import net.minecraft.util.Identifier;
|
|
||||||
|
|
||||||
public class EmissiveOverlayRenderer<T extends LivingEntity> extends EyesFeatureRenderer<T, EntityModel<T>> {
|
|
||||||
private final RenderLayer SKIN;
|
|
||||||
|
|
||||||
public EmissiveOverlayRenderer(FeatureRendererContext<T, EntityModel<T>> featureRendererContext, Identifier texture) {
|
|
||||||
super(featureRendererContext);
|
|
||||||
SKIN = RenderLayer.getEyes(texture);
|
|
||||||
}
|
|
||||||
public RenderLayer getEyesTexture() {
|
|
||||||
return SKIN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 672 B After Width: | Height: | Size: 293 B |
Reference in New Issue
Block a user