diff --git a/charsets/35f770a6-5d94-4ddf-a132-dc3788a3adaf.png b/charsets/35f770a6-5d94-4ddf-a132-dc3788a3adaf.png new file mode 100644 index 0000000..65963d7 Binary files /dev/null and b/charsets/35f770a6-5d94-4ddf-a132-dc3788a3adaf.png differ diff --git a/charsets/4a636044-2dbd-4ef3-8bdf-b63501c85ae3.png b/charsets/4a636044-2dbd-4ef3-8bdf-b63501c85ae3.png new file mode 100644 index 0000000..3cea4cb Binary files /dev/null and b/charsets/4a636044-2dbd-4ef3-8bdf-b63501c85ae3.png differ diff --git a/data.sql b/data.sql index d0e65dc..4361f7a 100644 --- a/data.sql +++ b/data.sql @@ -163,5 +163,19 @@ INSERT INTO "PUBLIC"."ENEMY" VALUES ('eagle', 'Eagle', 'Eagle', 'Corpse', '2d4+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'), ('skeleton', 'Skeleton', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_sword', NULL, NULL, 'Poof', 'Deku death'), ('skeleton_archer', 'Skeleton Archer', 'Skeleton', 'Corpse', '2d6+2', '10d2', TRUE, 'wooden_dagger', 'wooden_bow,wooden_arrow,2d4+3', NULL, 'Poof', 'Deku death'); +CREATE MEMORY TABLE "PUBLIC"."FRIEND"( + "ID" VARCHAR NOT NULL, + "NAME" VARCHAR NOT NULL, + "CHARSET" VARCHAR NOT NULL, + "SPEED" VARCHAR NOT NULL, + "BLOCKING" BOOLEAN DEFAULT FALSE NOT NULL, + "DIALOG_COLOR" VARCHAR DEFAULT '0xFFFFFF' NOT NULL +); +ALTER TABLE "PUBLIC"."FRIEND" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_7C" PRIMARY KEY("ID"); +-- 3 +/- SELECT COUNT(*) FROM PUBLIC.FRIEND; +INSERT INTO "PUBLIC"."FRIEND" VALUES +('turtle', 'Turtle', 'Turtle', '10d2', TRUE, 'AA00DD'), +('neko', 'Neko', 'Neko', '14', TRUE, 'AA00DD'), +('grandma', 'Grandma', 'Grandma', '7', TRUE, 'DD00AA'); ALTER TABLE "PUBLIC"."ENEMY_DROP" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_8A" FOREIGN KEY("ENEMY") REFERENCES "PUBLIC"."ENEMY"("ID") NOCHECK; ALTER TABLE "PUBLIC"."ENEMY" ADD CONSTRAINT "PUBLIC"."CONSTRAINT_3F" FOREIGN KEY("MELEE_WEAPON") REFERENCES "PUBLIC"."MELEE_WEAPON"("ID") NOCHECK; diff --git a/maps/1825b6a1-842d-4565-97e0-2005118b2b2b.dat b/maps/1825b6a1-842d-4565-97e0-2005118b2b2b.dat deleted file mode 100644 index 6ec77ab..0000000 --- a/maps/1825b6a1-842d-4565-97e0-2005118b2b2b.dat +++ /dev/null @@ -1,2 +0,0 @@ - -$1825b6a1-842d-4565-97e0-2005118b2b2b2 ( :+com.bartlomiejpluta.demo.map.ForrestHandler \ No newline at end of file diff --git a/maps/8fbb151f-682a-4357-ba92-157e4097898f.dat b/maps/8fbb151f-682a-4357-ba92-157e4097898f.dat index 759d592..0b52c00 100644 --- a/maps/8fbb151f-682a-4357-ba92-157e4097898f.dat +++ b/maps/8fbb151f-682a-4357-ba92-157e4097898f.dat @@ -7,8 +7,8 @@ $04ac5ad8-4100-4016-97b3-a51a728ca49d Water> $fc294b9e-105a-4120-8caa-393d78fdf414!?(2G Objects belowF -$413e09cf-ba41-4fe8-ac47-9697b5ad0245<=<=PPPPKSTST[PPPPPP9lm;|}IstSTQRjkstz{QR9STIZWXYiPPPPyst]I]YPPNN``I``<=`WXQRYIJQRjk`]z{ST`STEFQRSTQRQRUVopIWXlmGH|}KUVQRABWXY[STQRIWXQRST^NNNQRABGHSTSTQRstWXJiWXWXy:WXEFQRQRUVABstQRGHY9STQRWXPPNNNNNNAB:WXQRlmQR|}2B -Main"B /* +$413e09cf-ba41-4fe8-ac47-9697b5ad0245<=<=PPPPKSTST[PPPPPP9lm;|}IstSTQRjkstz{QR9STIZWXYiPPPPyst]I]YPPNN``I``<=`WXQRYIJQRjk`]z{ST`STEFQRSTQRQRUVopIWXlmGH|}KUVQRABWXY[STQRIWXQRST^NNNQRABGHSTSTQRstWXJiWXWXy:WXEFQRQRUVABstQRGHY9STQRWXPPNNNNNNAB:WXQRlmQR|}2B +Main"B /* * Following final parameters are available to use: * x: int - the x coordinate of tile the object has been created on * y: int - the y coordinate of tile the object has been created on @@ -18,11 +18,11 @@ $413e09cf-ba41-4fe8-ac47-9697b5ad0245 * runner: DemoRunner - the game runner of the project * context: Context - the game context */ -handler.warp(here, A.maps.hero_house.main.forrest);" +warp(here, A.maps.hero_house.main.forrest); house 2D Objects aboveD $413e09cf-ba41-4fe8-ac47-9697b5ad02453434CDCD3434CDCD34cd34CD34stcdCDCD12cdAB3434cdcdCDCD78ststGH12abABqrcdcdstcdst78abGHcdqrabcdstqrstcd34st34CD56cd34CD12abcd56EF78stCDABqrstEFGHcd56cdstcdabcd34EFstqr12stcdCDcd78ab34ABststGHcdcdqrCDababqrabqr34qr341278cd78cdCDCDABcdGHstGHst78cdst56cdGHstab56EFstqrEF12cdcdcdAB34st12st56cdst78CDABcdEFstGH78abstUV12cd12GHqrcdABstABst2@ Border forrest@ $413e09cf-ba41-4fe8-ac47-9697b5ad0245cdstcdstcdstcdst2 Layer 8* - :+com.bartlomiejpluta.demo.map.ForrestHandler \ No newline at end of file + :+com.bartlomiejpluta.demo.map.ForrestHandlerB \ No newline at end of file diff --git a/maps/b602601a-e9b0-44bf-bc0d-5f31c9964ba1.dat b/maps/b602601a-e9b0-44bf-bc0d-5f31c9964ba1.dat index b452410..a974922 100644 Binary files a/maps/b602601a-e9b0-44bf-bc0d-5f31c9964ba1.dat and b/maps/b602601a-e9b0-44bf-bc0d-5f31c9964ba1.dat differ diff --git a/maps/d1b85d85-c52a-46f5-b81e-444847f8ddae.dat b/maps/d1b85d85-c52a-46f5-b81e-444847f8ddae.dat index ef3ecfc..3f823c2 100644 Binary files a/maps/d1b85d85-c52a-46f5-b81e-444847f8ddae.dat and b/maps/d1b85d85-c52a-46f5-b81e-444847f8ddae.dat differ diff --git a/project.bep b/project.bep index 7398f42..ed9054d 100644 Binary files a/project.bep and b/project.bep differ diff --git a/src/main/java/com/bartlomiejpluta/demo/entity/Friend.java b/src/main/java/com/bartlomiejpluta/demo/entity/Friend.java new file mode 100644 index 0000000..efad180 --- /dev/null +++ b/src/main/java/com/bartlomiejpluta/demo/entity/Friend.java @@ -0,0 +1,74 @@ +package com.bartlomiejpluta.demo.entity; + +import DB.model.FriendModel; +import com.bartlomiejpluta.base.api.ai.AI; +import com.bartlomiejpluta.base.api.ai.NPC; +import com.bartlomiejpluta.base.api.character.Character; +import com.bartlomiejpluta.base.api.context.ContextHolder; +import com.bartlomiejpluta.base.lib.ai.NoopAI; +import com.bartlomiejpluta.base.lib.ai.RandomMovementAI; +import com.bartlomiejpluta.base.util.random.DiceRoller; +import com.bartlomiejpluta.demo.world.item.Item; +import lombok.Getter; +import lombok.NonNull; + +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; + +public class Friend extends Creature implements NPC { + @Getter + private AI strategy = NoopAI.INSTANCE; + private AI priorStrategy; + private boolean interacting; + + @Getter + private final String name; + + @Getter + private final int dialogNameColor; + private Function> interaction; + + public Friend(@NonNull String id) { + this(DB.dao.friend.find(id)); + } + + public Friend(@NonNull FriendModel template) { + super(ContextHolder.INSTANCE.getContext().createCharacter(A.charsets.byName(template.getCharset()).$)); + name = template.getName(); + setSpeed(DiceRoller.roll(template.getSpeed()) / 10f); + setBlocking(template.isBlocking()); + dialogNameColor = Integer.parseInt(template.getDialogColor(), 16); + } + + @Override + public void removeItemFromEquipment(Item item) { + + } + + public CompletableFuture interact(Character trigger) { + if(interaction != null && !interacting) { + setFaceDirection(getDirectionTowards(trigger)); + priorStrategy = strategy; + strategy = NoopAI.INSTANCE; + interacting = true; + + return interaction.apply(this).thenApply(o -> { + strategy = priorStrategy; + interacting = false; + return o; + }); + } + + return CompletableFuture.completedFuture(null); + } + + public Friend interaction(Function> interaction) { + this.interaction = interaction; + return this; + } + + public Friend asAnimal() { + this.strategy = new RandomMovementAI<>(this, 4f); + return this; + } +} diff --git a/src/main/java/com/bartlomiejpluta/demo/entity/NamedCharacter.java b/src/main/java/com/bartlomiejpluta/demo/entity/NamedCharacter.java index f91a2bd..163bbaf 100644 --- a/src/main/java/com/bartlomiejpluta/demo/entity/NamedCharacter.java +++ b/src/main/java/com/bartlomiejpluta/demo/entity/NamedCharacter.java @@ -17,4 +17,8 @@ public abstract class NamedCharacter extends CharacterDelegate { } public abstract String getName(); + + public int getDialogNameColor() { + return 0xFFFFFF; + } } \ No newline at end of file diff --git a/src/main/java/com/bartlomiejpluta/demo/entity/Player.java b/src/main/java/com/bartlomiejpluta/demo/entity/Player.java index a3381fb..961c26b 100644 --- a/src/main/java/com/bartlomiejpluta/demo/entity/Player.java +++ b/src/main/java/com/bartlomiejpluta/demo/entity/Player.java @@ -47,12 +47,22 @@ public class Player extends Creature { for (var i = 0; i < entities.size(); ++i) { var entity = entities.get(i); - // Use some map object which player is looking at - if (entity.getCoordinates().equals(coords) && entity instanceof MapObject object) { - object.triggerInteraction(); - return; + if (entity.getCoordinates().equals(coords)) { + + // Use some map object which player is looking at + if(entity instanceof MapObject object) { + object.triggerInteraction(); + return; + } + + // Interact with friend creature which player is looking at + if(entity instanceof Friend friend) { + friend.interact(this).thenApply(o -> interactionCooldown = INTERACTION_COOLDOWN); + return; + } } + if (entity.getCoordinates().equals(getCoordinates())) { // Pick some item from the ground @@ -223,7 +233,12 @@ public class Player extends Creature { @Override public String getName() { - return "Player"; + return "Luna"; + } + + @Override + public int getDialogNameColor() { + return 0x00AA00; } @Override diff --git a/src/main/java/com/bartlomiejpluta/demo/gui/DialogChoiceWindow.java b/src/main/java/com/bartlomiejpluta/demo/gui/DialogChoiceWindow.java new file mode 100644 index 0000000..fa65b69 --- /dev/null +++ b/src/main/java/com/bartlomiejpluta/demo/gui/DialogChoiceWindow.java @@ -0,0 +1,54 @@ +package com.bartlomiejpluta.demo.gui; + +import A.fonts; +import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.gui.*; +import com.bartlomiejpluta.base.lib.gui.TextView; +import com.bartlomiejpluta.base.lib.gui.VOptionChoice; + +import java.util.Collections; +import java.util.Map; + +public class DialogChoiceWindow extends DecoratedWindow { + + @Ref("speaker") + private TextView speaker; + + @Ref("choice") + private VOptionChoice choice; + + @SuppressWarnings("unchecked") + @Override + public void onOpen(WindowManager manager, Object[] args) { + super.onOpen(manager, args); + + speaker.setText((String) args[0]); + speaker.setColor((int) args[1]); + + var index = 0; + choice.removeAllChildren(); + var options = (String[]) args[2]; + for(var option : options) { + var button = new Button(context, gui, Collections.emptyMap()); + choice.add(button); + button.setText(option); + button.setColor(0xFFFFFF); + button.setWidthMode(SizeMode.RELATIVE); + button.setWidth(1f); + button.setFont(fonts.roboto_regular.$); + button.setFontSize(20f); + button.setAction(onChoose(index)); + ++index; + } + + choice.focus(); + } + + private Runnable onChoose(int index) { + return () -> resolve(index); + } + + public DialogChoiceWindow(Context context, GUI gui, Map refs) { + super(context, gui, refs); + } +} diff --git a/src/main/java/com/bartlomiejpluta/demo/gui/DialogWindow.java b/src/main/java/com/bartlomiejpluta/demo/gui/DialogWindow.java index 426db28..46c8b74 100644 --- a/src/main/java/com/bartlomiejpluta/demo/gui/DialogWindow.java +++ b/src/main/java/com/bartlomiejpluta/demo/gui/DialogWindow.java @@ -5,14 +5,18 @@ import com.bartlomiejpluta.base.api.gui.*; import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.input.KeyAction; import com.bartlomiejpluta.base.api.input.KeyEvent; +import com.bartlomiejpluta.base.lib.gui.PrintedTextView; import com.bartlomiejpluta.base.lib.gui.TextView; import java.util.Map; public class DialogWindow extends DecoratedWindow { + @Ref("speaker") + private TextView speaker; + @Ref("message") - private TextView text; + private PrintedTextView text; public DialogWindow(Context context, GUI gui, Map refs) { super(context, gui, refs); @@ -26,6 +30,12 @@ public class DialogWindow extends DecoratedWindow { } if (event.getKey() == Key.KEY_ENTER && event.getAction() == KeyAction.PRESS) { + if (text.isPrinting()) { + text.printAll(); + event.consume(); + return; + } + manager.close(); event.consume(); } @@ -35,11 +45,16 @@ public class DialogWindow extends DecoratedWindow { public void onOpen(WindowManager manager, Object[] args) { super.onOpen(manager, args); - text.setText((String) args[0]); + speaker.setText((String) args[0]); + speaker.setColor((int) args[1]); - if (args.length > 1) { - setWindowPosition((WindowPosition) args[1]); + text.setText((String) args[2]); + + if (args.length > 3) { + setWindowPosition((WindowPosition) args[3]); } + + text.start(); } @Override diff --git a/src/main/java/com/bartlomiejpluta/demo/gui/PrintTextView.java b/src/main/java/com/bartlomiejpluta/demo/gui/PrintTextView.java new file mode 100644 index 0000000..b8ff1d5 --- /dev/null +++ b/src/main/java/com/bartlomiejpluta/demo/gui/PrintTextView.java @@ -0,0 +1,49 @@ +package com.bartlomiejpluta.demo.gui; + +import com.bartlomiejpluta.base.api.context.Context; +import com.bartlomiejpluta.base.api.gui.Component; +import com.bartlomiejpluta.base.api.gui.GUI; +import com.bartlomiejpluta.base.lib.gui.TextView; +import lombok.Setter; + +import java.util.Map; + +public class PrintTextView extends TextView { + + @Setter + private Float duration; + + private float acc; + + private String originalText; + + public void start() { + acc = 0f; + } + + public boolean isPrinting() { + return originalText.length() != super.getText().length(); + } + + public void printAll() { + acc = originalText.length() * duration; + } + + @Override + public void setText(String text) { + super.setText(""); + this.originalText = text; + } + + @Override + public void update(float dt) { + super.update(dt); + + acc += dt; + super.setText(originalText.substring(0, Math.min(originalText.length(), (int) (acc / duration)))); + } + + public PrintTextView(Context context, GUI gui, Map refs) { + super(context, gui, refs); + } +} diff --git a/src/main/java/com/bartlomiejpluta/demo/map/BaseMapHandler.java b/src/main/java/com/bartlomiejpluta/demo/map/BaseMapHandler.java index 793d8f1..42b49a2 100644 --- a/src/main/java/com/bartlomiejpluta/demo/map/BaseMapHandler.java +++ b/src/main/java/com/bartlomiejpluta/demo/map/BaseMapHandler.java @@ -1,29 +1,22 @@ package com.bartlomiejpluta.demo.map; -import A.maps; import com.bartlomiejpluta.base.api.camera.Camera; import com.bartlomiejpluta.base.api.context.Context; import com.bartlomiejpluta.base.api.entity.Entity; -import com.bartlomiejpluta.base.api.gui.Window; import com.bartlomiejpluta.base.api.gui.WindowPosition; import com.bartlomiejpluta.base.api.icon.Icon; import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.input.Key; import com.bartlomiejpluta.base.api.map.handler.MapHandler; import com.bartlomiejpluta.base.api.map.layer.object.MapPin; -import com.bartlomiejpluta.base.api.map.layer.object.ObjectLayer; import com.bartlomiejpluta.base.api.map.model.GameMap; -import com.bartlomiejpluta.base.api.move.Direction; import com.bartlomiejpluta.base.api.screen.Screen; import com.bartlomiejpluta.base.lib.camera.CameraController; import com.bartlomiejpluta.base.lib.camera.FollowingCameraController; import com.bartlomiejpluta.base.util.input.InputUtil; import com.bartlomiejpluta.base.util.world.CharacterSpawner; import com.bartlomiejpluta.base.util.world.Warp; -import com.bartlomiejpluta.demo.entity.Chest; -import com.bartlomiejpluta.demo.entity.Door; -import com.bartlomiejpluta.demo.entity.Enemy; -import com.bartlomiejpluta.demo.entity.Player; +import com.bartlomiejpluta.demo.entity.*; import com.bartlomiejpluta.demo.event.EnemyDiedEvent; import com.bartlomiejpluta.demo.menu.GuiManager; import com.bartlomiejpluta.demo.runner.DemoRunner; @@ -82,12 +75,16 @@ public abstract class BaseMapHandler implements MapHandler { cameraController.update(); } - public CompletableFuture dialog(String message, WindowPosition position) { - return guiManager.showDialog(message, position); + public CompletableFuture dialog(NamedCharacter speaker, String message, WindowPosition position) { + return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, position); } - public CompletableFuture dialog(String message) { - return guiManager.showDialog(message, WindowPosition.BOTTOM); + public CompletableFuture dialog(NamedCharacter speaker, String message) { + return guiManager.showDialog(speaker.getName(), speaker.getDialogNameColor(), message, WindowPosition.BOTTOM); + } + + public CompletableFuture dialogChoice(NamedCharacter speaker, String... choices) { + return guiManager.showDialogChoice(speaker.getName(), speaker.getDialogNameColor(), choices); } protected T addEntity(T entity, MapPin tile) { @@ -100,6 +97,10 @@ public abstract class BaseMapHandler implements MapHandler { return addEntity(new Enemy(id), tile); } + public Friend friend(@NonNull MapPin tile, @NonNull String id) { + return addEntity(new Friend(id), tile); + } + public Chest chest(@NonNull MapPin tile, @NonNull String id) { return addEntity(new Chest(id), tile); } diff --git a/src/main/java/com/bartlomiejpluta/demo/map/HeroHomeHandler.java b/src/main/java/com/bartlomiejpluta/demo/map/HeroHomeHandler.java index 8fa78ad..bf6a077 100644 --- a/src/main/java/com/bartlomiejpluta/demo/map/HeroHomeHandler.java +++ b/src/main/java/com/bartlomiejpluta/demo/map/HeroHomeHandler.java @@ -1,11 +1,11 @@ package com.bartlomiejpluta.demo.map; import com.bartlomiejpluta.base.api.context.Context; -import com.bartlomiejpluta.base.api.input.Input; import com.bartlomiejpluta.base.api.map.model.GameMap; -import com.bartlomiejpluta.base.api.map.handler.MapHandler; -import com.bartlomiejpluta.base.api.screen.Screen; public class HeroHomeHandler extends BaseMapHandler { - + @Override + public void onOpen(Context context, GameMap map) { + dialog(player, "Ahhh, another beautiful day for an adventure... Let's go!"); + } } \ No newline at end of file diff --git a/src/main/java/com/bartlomiejpluta/demo/menu/GuiManager.java b/src/main/java/com/bartlomiejpluta/demo/menu/GuiManager.java index b398fdb..403ac61 100644 --- a/src/main/java/com/bartlomiejpluta/demo/menu/GuiManager.java +++ b/src/main/java/com/bartlomiejpluta/demo/menu/GuiManager.java @@ -26,6 +26,7 @@ public class GuiManager { private final EquipmentWindow equipment; private final LootWindow loot; private final DialogWindow dialog; + private final DialogChoiceWindow dialogChoice; private final Consumer gameMenuHandler = this::handleGameMenuKeyEvent; public GuiManager(@NonNull DemoRunner runner, @NonNull Context context) { @@ -49,6 +50,7 @@ public class GuiManager { this.gameMenu.reference("exit", Button.class).setAction(runner::exit); this.dialog = gui.inflateWindow(A.widgets.dialog.$, DialogWindow.class); + this.dialogChoice = gui.inflateWindow(A.widgets.dialog_choice.$, DialogChoiceWindow.class); this.loot = gui.inflateWindow(widgets.loot_menu.$, LootWindow.class); } @@ -83,7 +85,7 @@ public class GuiManager { return manager.size(); } - public CompletableFuture showStartMenu() { + public CompletableFuture showStartMenu() { manager.closeAll(); return manager.open(startMenu); } @@ -100,19 +102,23 @@ public class GuiManager { manager.setDisplayMode(DisplayMode.DISPLAY_TOP); } - public CompletableFuture showDialog(@NonNull String message, @NonNull WindowPosition position) { - return manager.open(dialog, message, position); + public CompletableFuture showDialog(@NonNull String speaker, int color, @NonNull String message, @NonNull WindowPosition position) { + return manager.open(dialog, speaker, color, message, position); } - public CompletableFuture openLootWindow(@NonNull Enemy enemy) { + public CompletableFuture showDialogChoice(@NonNull String speaker, int color, @NonNull String... choices) { + return manager.openForResult(Integer.class, dialogChoice, speaker, color, choices); + } + + public CompletableFuture openLootWindow(@NonNull Enemy enemy) { return manager.open(loot, enemy.getLoot(), "Loot"); } - public CompletableFuture openChestWindow(@NonNull Chest chest) { + public CompletableFuture openChestWindow(@NonNull Chest chest) { return manager.open(loot, chest.getContent(), chest.getName()); } - public CompletableFuture openGameMenu() { + public CompletableFuture openGameMenu() { return manager.open(gameMenu); } diff --git a/widgets/1c2b2ba2-66bf-40ee-97bf-6e5065b7b420.xml b/widgets/1c2b2ba2-66bf-40ee-97bf-6e5065b7b420.xml index 39e8ae4..dc07f33 100644 --- a/widgets/1c2b2ba2-66bf-40ee-97bf-6e5065b7b420.xml +++ b/widgets/1c2b2ba2-66bf-40ee-97bf-6e5065b7b420.xml @@ -7,7 +7,10 @@ margin="20f" width="900f" height="auto"> - + + + + + \ No newline at end of file diff --git a/widgets/5a5aea0a-8c8b-4730-8e45-9ec6ccc5c4f6.xml b/widgets/5a5aea0a-8c8b-4730-8e45-9ec6ccc5c4f6.xml new file mode 100644 index 0000000..3d0f935 --- /dev/null +++ b/widgets/5a5aea0a-8c8b-4730-8e45-9ec6ccc5c4f6.xml @@ -0,0 +1,16 @@ + + + + + + + + + \ No newline at end of file