From e9eb4c202fb5ec651db80cebd1a8c48769e51d27 Mon Sep 17 00:00:00 2001 From: Alexander Date: Sat, 26 Apr 2025 18:35:30 +0300 Subject: [PATCH] Final --- .idea/encodings.xml | 7 + pom.xml | 101 ++++++++++-- src/main/java/quiz/command/Command.java | 5 + src/main/java/quiz/command/RedoCommand.java | 25 +++ src/main/java/quiz/command/UndoCommand.java | 25 +++ .../java/quiz/deserializer/Deserializer.java | 5 + .../quiz/deserializer/DeserializerBase.java | 80 +++++++++ .../DeserializerObjectFactory.java | 34 ++++ .../json/DeserializerJSONObjectMapper.java | 45 +++++ src/main/java/quiz/editor/Editor.java | 65 ++++++++ src/main/java/quiz/history/History.java | 33 ++++ src/main/java/quiz/history/Memento.java | 31 ++++ .../quiz/history/QuestionsHistoryManager.java | 51 ++++++ src/main/java/quiz/scenarios/Check.java | 87 ++++++++++ src/main/java/quiz/scenarios/Question.java | 105 ++++++++++++ .../quiz/scenarios/QuestionsTemplate.java | 78 +++++++++ .../java/quiz/servlet/flags/LogicServlet.java | 123 ++++++++++++++ .../quiz/servlet/flags/RestartServlet.java | 17 ++ .../quiz/servlet/flags/ResultServlet.java | 17 ++ .../java/quiz/servlet/flags/StartServlet.java | 62 +++++++ src/main/resources/scenarios/flags.json | 104 ++++++++++++ src/main/webapp/WEB-INF/web.xml | 4 + src/main/webapp/images/australia_flag.webp | Bin 0 -> 15113 bytes src/main/webapp/images/brazil_flag.webp | Bin 0 -> 45128 bytes src/main/webapp/images/canada_flag.webp | Bin 0 -> 10250 bytes src/main/webapp/images/france_flag.webp | Bin 0 -> 2047 bytes src/main/webapp/images/india_flag.webp | Bin 0 -> 25745 bytes src/main/webapp/images/japan_flag.webp | Bin 0 -> 6618 bytes src/main/webapp/images/south_africa_flag.webp | Bin 0 -> 2988 bytes src/main/webapp/images/ukraine_flag.webp | Bin 0 -> 1433 bytes .../webapp/images/united_kingdom_flag.webp | Bin 0 -> 4635 bytes src/main/webapp/images/usa_flag.webp | Bin 0 -> 38711 bytes src/main/webapp/index.jsp | 5 - src/main/webapp/logic.jsp | 88 ++++++++++ src/main/webapp/result.jsp | 87 ++++++++++ src/main/webapp/start.jsp | 29 ++++ src/main/webapp/static/styles_logic.css | 33 ++++ src/main/webapp/static/styles_result.css | 23 +++ src/main/webapp/static/styles_start.css | 24 +++ .../java/quiz/command/RedoCommandTest.java | 40 +++++ .../java/quiz/command/UndoCommandTest.java | 40 +++++ .../deserializer/DeserializerBaseTest.java | 155 ++++++++++++++++++ .../DeserializerObjectFactoryTest.java | 67 ++++++++ .../DeserializerJSONObjectMapperTest.java | 82 +++++++++ src/test/java/quiz/editor/EditorTest.java | 100 +++++++++++ src/test/java/quiz/history/HistoryTest.java | 66 ++++++++ src/test/java/quiz/history/MementoTest.java | 65 ++++++++ .../history/QuestionsHistoryManagerTest.java | 104 ++++++++++++ src/test/java/quiz/scenarios/CheckTest.java | 99 +++++++++++ .../java/quiz/scenarios/QuestionTest.java | 99 +++++++++++ .../quiz/scenarios/QuestionsTemplateTest.java | 100 +++++++++++ 51 files changed, 2395 insertions(+), 15 deletions(-) create mode 100644 .idea/encodings.xml create mode 100644 src/main/java/quiz/command/Command.java create mode 100644 src/main/java/quiz/command/RedoCommand.java create mode 100644 src/main/java/quiz/command/UndoCommand.java create mode 100644 src/main/java/quiz/deserializer/Deserializer.java create mode 100644 src/main/java/quiz/deserializer/DeserializerBase.java create mode 100644 src/main/java/quiz/deserializer/DeserializerObjectFactory.java create mode 100644 src/main/java/quiz/deserializer/json/DeserializerJSONObjectMapper.java create mode 100644 src/main/java/quiz/editor/Editor.java create mode 100644 src/main/java/quiz/history/History.java create mode 100644 src/main/java/quiz/history/Memento.java create mode 100644 src/main/java/quiz/history/QuestionsHistoryManager.java create mode 100644 src/main/java/quiz/scenarios/Check.java create mode 100644 src/main/java/quiz/scenarios/Question.java create mode 100644 src/main/java/quiz/scenarios/QuestionsTemplate.java create mode 100644 src/main/java/quiz/servlet/flags/LogicServlet.java create mode 100644 src/main/java/quiz/servlet/flags/RestartServlet.java create mode 100644 src/main/java/quiz/servlet/flags/ResultServlet.java create mode 100644 src/main/java/quiz/servlet/flags/StartServlet.java create mode 100644 src/main/resources/scenarios/flags.json create mode 100644 src/main/webapp/images/australia_flag.webp create mode 100644 src/main/webapp/images/brazil_flag.webp create mode 100644 src/main/webapp/images/canada_flag.webp create mode 100644 src/main/webapp/images/france_flag.webp create mode 100644 src/main/webapp/images/india_flag.webp create mode 100644 src/main/webapp/images/japan_flag.webp create mode 100644 src/main/webapp/images/south_africa_flag.webp create mode 100644 src/main/webapp/images/ukraine_flag.webp create mode 100644 src/main/webapp/images/united_kingdom_flag.webp create mode 100644 src/main/webapp/images/usa_flag.webp delete mode 100644 src/main/webapp/index.jsp create mode 100644 src/main/webapp/logic.jsp create mode 100644 src/main/webapp/result.jsp create mode 100644 src/main/webapp/start.jsp create mode 100644 src/main/webapp/static/styles_logic.css create mode 100644 src/main/webapp/static/styles_result.css create mode 100644 src/main/webapp/static/styles_start.css create mode 100644 src/test/java/quiz/command/RedoCommandTest.java create mode 100644 src/test/java/quiz/command/UndoCommandTest.java create mode 100644 src/test/java/quiz/deserializer/DeserializerBaseTest.java create mode 100644 src/test/java/quiz/deserializer/DeserializerObjectFactoryTest.java create mode 100644 src/test/java/quiz/deserializer/json/DeserializerJSONObjectMapperTest.java create mode 100644 src/test/java/quiz/editor/EditorTest.java create mode 100644 src/test/java/quiz/history/HistoryTest.java create mode 100644 src/test/java/quiz/history/MementoTest.java create mode 100644 src/test/java/quiz/history/QuestionsHistoryManagerTest.java create mode 100644 src/test/java/quiz/scenarios/CheckTest.java create mode 100644 src/test/java/quiz/scenarios/QuestionTest.java create mode 100644 src/test/java/quiz/scenarios/QuestionsTemplateTest.java diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 84c1d81..bd64a78 100644 --- a/pom.xml +++ b/pom.xml @@ -15,28 +15,97 @@ UTF-8 - 8 - 8 + 23 + 23 - - junit - junit - 4.13.1 + org.junit.jupiter + junit-jupiter-engine + 5.12.1 test - + + org.junit.jupiter + junit-jupiter-params + 5.11.4 + test + + + + org.mockito + mockito-junit-jupiter + 5.15.2 + test + + + + org.mockito + mockito-core + 5.15.2 + test + + + + org.mockito + mockito-inline + 5.2.0 + test + + + jakarta.servlet + jakarta.servlet-api + 6.1.0 + provided + + + jakarta.servlet.jsp.jstl + jakarta.servlet.jsp.jstl-api + 3.0.2 + + + org.glassfish.web + jakarta.servlet.jsp.jstl + 3.0.1 + + + com.fasterxml.jackson.core + jackson-databind + 2.18.3 + + + com.fasterxml.jackson.core + jackson-core + 2.18.3 + + + com.fasterxml.jackson.core + jackson-annotations + 2.18.3 + + + org.slf4j + slf4j-api + 2.0.17 + + + ch.qos.logback + logback-classic + 1.5.18 + compile + + - final-project-module-3 - + quest_training + + maven-clean-plugin 3.4.0 - + maven-resources-plugin 3.3.1 @@ -44,6 +113,9 @@ maven-compiler-plugin 3.13.0 + + 23 + maven-surefire-plugin @@ -63,5 +135,14 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + + 23 + + + diff --git a/src/main/java/quiz/command/Command.java b/src/main/java/quiz/command/Command.java new file mode 100644 index 0000000..02a8956 --- /dev/null +++ b/src/main/java/quiz/command/Command.java @@ -0,0 +1,5 @@ +package quiz.command; + +public interface Command { + void execute(); +} diff --git a/src/main/java/quiz/command/RedoCommand.java b/src/main/java/quiz/command/RedoCommand.java new file mode 100644 index 0000000..b751613 --- /dev/null +++ b/src/main/java/quiz/command/RedoCommand.java @@ -0,0 +1,25 @@ +package quiz.command; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.history.QuestionsHistoryManager; + +public class RedoCommand implements Command { + private static final Logger logger = LoggerFactory.getLogger(RedoCommand.class); + + private final QuestionsHistoryManager memento; + + public RedoCommand(QuestionsHistoryManager memento) { + if (memento == null) { + logger.error("Memento cannot be null"); + throw new IllegalArgumentException("Memento cannot be null"); + } + + this.memento = memento; + } + + @Override + public void execute() { + memento.backup(); + } +} diff --git a/src/main/java/quiz/command/UndoCommand.java b/src/main/java/quiz/command/UndoCommand.java new file mode 100644 index 0000000..6ff8eae --- /dev/null +++ b/src/main/java/quiz/command/UndoCommand.java @@ -0,0 +1,25 @@ +package quiz.command; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.history.QuestionsHistoryManager; + +public class UndoCommand implements Command { + private static final Logger logger = LoggerFactory.getLogger(UndoCommand.class); + + private final QuestionsHistoryManager memento; + + public UndoCommand(QuestionsHistoryManager memento) { + if (memento == null) { + logger.error("Memento cannot be null"); + throw new IllegalArgumentException("Memento cannot be null"); + } + + this.memento = memento; + } + + @Override + public void execute() { + memento.restore(); + } +} diff --git a/src/main/java/quiz/deserializer/Deserializer.java b/src/main/java/quiz/deserializer/Deserializer.java new file mode 100644 index 0000000..7da2297 --- /dev/null +++ b/src/main/java/quiz/deserializer/Deserializer.java @@ -0,0 +1,5 @@ +package quiz.deserializer; + +public interface Deserializer { + T deserializeFromFile(String filePath, Class clazz); +} diff --git a/src/main/java/quiz/deserializer/DeserializerBase.java b/src/main/java/quiz/deserializer/DeserializerBase.java new file mode 100644 index 0000000..4206bd7 --- /dev/null +++ b/src/main/java/quiz/deserializer/DeserializerBase.java @@ -0,0 +1,80 @@ +package quiz.deserializer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Modifier; +import java.nio.file.Files; +import java.nio.file.Path; + +public abstract class DeserializerBase implements Deserializer { + private static final Logger logger = LoggerFactory.getLogger(DeserializerBase.class); + + protected void validateFilePath(String filePath) { + if (filePath == null || filePath.isBlank()) { + logger.error("File path cannot be null or empty"); + throw new IllegalArgumentException("File path cannot be null or empty"); + } + } + + protected void validateClass(Class clazz) { + if (clazz == null) { + logger.error("Target class cannot be null"); + throw new IllegalArgumentException("Target class cannot be null"); + } + + if (clazz.isInterface()) { + throw new IllegalArgumentException("Target class cannot be an interface"); + } + + if (Modifier.isAbstract(clazz.getModifiers())) { + throw new IllegalArgumentException("Target class cannot be abstract"); + } + } + + protected InputStream loadResourceAsStream(String filePath) throws IOException { + InputStream fileStream = loadFromFileSystem(filePath); + if (fileStream != null) { + return fileStream; + } + + return loadFromClasspath(filePath); + } + + protected InputStream loadFromFileSystem(String filePath) throws IOException { + validateFilePath(filePath); + + Path path = Path.of(filePath).normalize(); + + if (!Files.exists(path)) { + logger.debug("File not found in filesystem: {}", path); + return null; + } + + if (!Files.isReadable(path)) { + logger.error("File exists but is not readable: {}", path); + throw new IOException("File exists but is not readable: " + path); + } + + logger.debug("Loading file from filesystem: {}", path); + return Files.newInputStream(path); + } + + protected InputStream loadFromClasspath(String resourcePath) { + validateFilePath(resourcePath); + + InputStream inputStream = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream(resourcePath); + + if (inputStream == null) { + logger.error("Resource not found in classpath: {}", resourcePath); + throw new IllegalStateException("Resource not found in classpath: " + resourcePath); + } + + logger.debug("Loading resource from classpath: {}", resourcePath); + return inputStream; + } +} diff --git a/src/main/java/quiz/deserializer/DeserializerObjectFactory.java b/src/main/java/quiz/deserializer/DeserializerObjectFactory.java new file mode 100644 index 0000000..e04dc6b --- /dev/null +++ b/src/main/java/quiz/deserializer/DeserializerObjectFactory.java @@ -0,0 +1,34 @@ +package quiz.deserializer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.deserializer.json.DeserializerJSONObjectMapper; + +public class DeserializerObjectFactory { + private static final Logger logger = LoggerFactory.getLogger(DeserializerObjectFactory.class); + + public T deserializerAndCreateObject(String filePath, Class clazz) { + Deserializer deserializer = getDeserializer(filePath); + return deserializer.deserializeFromFile(filePath, clazz); + } + + private Deserializer getDeserializer(String filePath) { + // Поки що тільки JSON + String extension = getFileExtension(filePath); + return switch (extension) { + case "json" -> new DeserializerJSONObjectMapper<>(); + default -> { + logger.error("Unsupported file format: {}", filePath); + throw new IllegalArgumentException("Only JSON format is supported"); + } + }; + } + + private String getFileExtension(String filePath) { + if (filePath == null || filePath.isBlank()) { + return ""; + } + int lastDotIndex = filePath.lastIndexOf('.'); + return (lastDotIndex > 0) ? filePath.substring(lastDotIndex + 1) : ""; + } +} diff --git a/src/main/java/quiz/deserializer/json/DeserializerJSONObjectMapper.java b/src/main/java/quiz/deserializer/json/DeserializerJSONObjectMapper.java new file mode 100644 index 0000000..63e36fd --- /dev/null +++ b/src/main/java/quiz/deserializer/json/DeserializerJSONObjectMapper.java @@ -0,0 +1,45 @@ +package quiz.deserializer.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.deserializer.DeserializerBase; + +import java.io.IOException; +import java.io.InputStream; + +public class DeserializerJSONObjectMapper extends DeserializerBase { + private static final Logger logger = LoggerFactory.getLogger(DeserializerJSONObjectMapper.class); + + private final ObjectMapper mapper; + + public DeserializerJSONObjectMapper() { + this.mapper = new ObjectMapper(); + } + + DeserializerJSONObjectMapper(ObjectMapper mapper) { + this.mapper = mapper; + } + + @Override + public T deserializeFromFile(String filePath, Class clazz) { + logger.debug("Attempting to deserialize JSON file {} to {}", filePath, clazz.getName()); + + validateFilePath(filePath); + validateClass(clazz); + + try (InputStream inputStream = loadResourceAsStream(filePath)) + { + T object = mapper.readValue(inputStream, clazz); + if (object == null) { + logger.error("Deserialization failed: got null from file '{}'", filePath); + throw new IllegalStateException("Deserialization returned null from: " + filePath); + } + logger.debug("Successfully deserialized from JSON file '{}' into {}", filePath, object.getClass()); + return object; + } catch (IOException e) { + logger.error("Error reading JSON file: {}", filePath); + throw new IllegalStateException("Error reading JSON file: " + filePath, e); + } + } +} diff --git a/src/main/java/quiz/editor/Editor.java b/src/main/java/quiz/editor/Editor.java new file mode 100644 index 0000000..cc54e70 --- /dev/null +++ b/src/main/java/quiz/editor/Editor.java @@ -0,0 +1,65 @@ +package quiz.editor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.command.Command; +import quiz.command.RedoCommand; +import quiz.command.UndoCommand; +import quiz.history.QuestionsHistoryManager; +import quiz.scenarios.Question; + +import java.util.List; +import java.util.Optional; + +public class Editor { + private static final Logger logger = LoggerFactory.getLogger(Editor.class); + + private final Command undo; + private final Command redo; + + private int currentIndex = -1; + + private final QuestionsHistoryManager memento; + + public Editor(QuestionsHistoryManager memento) { + if (memento == null) { + logger.error("Memento cannot be null"); + throw new IllegalArgumentException("Memento cannot be null"); + } + + this.memento = memento; + + this.undo = new UndoCommand(memento); + this.redo = new RedoCommand(memento); + } + + public Optional getNextObject() { + redo.execute(); + return getQuestion(++currentIndex); + } + + public Optional getPreviousObject() { + undo.execute(); + return getQuestion(--currentIndex); + } + + public Optional getCurrentObject() { + return getQuestion(currentIndex); + } + + public List getAllObjects() { + return memento.getAllQuestions(); + } + + private Optional getQuestion(int index) { + List questions = memento.getAllQuestions(); + if (index < 0 || index >= questions.size()) { + return Optional.empty(); + } + + Question question = questions.get(index); + return question == null ? + Optional.empty() : + Optional.of(question); + } +} diff --git a/src/main/java/quiz/history/History.java b/src/main/java/quiz/history/History.java new file mode 100644 index 0000000..81467ca --- /dev/null +++ b/src/main/java/quiz/history/History.java @@ -0,0 +1,33 @@ +package quiz.history; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Optional; + +public class History { + private static final Logger logger = LoggerFactory.getLogger(History.class); + + private final Deque mementos = new ArrayDeque<>(); + + public void save(Memento memento) { + if (memento == null) { + logger.error("Memento cannot be null"); + throw new IllegalArgumentException("Memento cannot be null"); + } + mementos.push(memento); + } + + public Optional restore() { + return mementos.isEmpty() ? + Optional.empty() : + Optional.of(mementos.pop()); + } + + public void clear() { + mementos.clear(); + } + +} diff --git a/src/main/java/quiz/history/Memento.java b/src/main/java/quiz/history/Memento.java new file mode 100644 index 0000000..596ee79 --- /dev/null +++ b/src/main/java/quiz/history/Memento.java @@ -0,0 +1,31 @@ +package quiz.history; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.scenarios.Question; + +import java.util.ArrayList; +import java.util.List; + +public final class Memento { + private static final Logger logger = LoggerFactory.getLogger(Memento.class); + + private final List questionsClone; + + Memento(List questionsClone) { + if (questionsClone == null) { + logger.error("Questions cannot be null"); + throw new IllegalArgumentException("Questions cannot be null"); + } + + this.questionsClone = new ArrayList<>(); + + for (Question question : questionsClone) { + this.questionsClone.add(question.copy()); + } + } + + List getQuestions() { + return new ArrayList<>(questionsClone); + } +} diff --git a/src/main/java/quiz/history/QuestionsHistoryManager.java b/src/main/java/quiz/history/QuestionsHistoryManager.java new file mode 100644 index 0000000..b3955b7 --- /dev/null +++ b/src/main/java/quiz/history/QuestionsHistoryManager.java @@ -0,0 +1,51 @@ +package quiz.history; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.scenarios.Question; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +public class QuestionsHistoryManager { + private static final Logger logger = LoggerFactory.getLogger(QuestionsHistoryManager.class); + + private List questions; + private final History history = new History(); + + public QuestionsHistoryManager() {} + + public QuestionsHistoryManager(List questions) { + replaceObjects(questions); + } + + public void replaceObjects(List questionsNew) { + if (questionsNew == null || questionsNew.isEmpty()) { + logger.error("List Questions cannot be null or empty"); + throw new IllegalArgumentException("List Questions cannot be null or empty"); + } + this.questions = new ArrayList<>(questionsNew); + } + + public List getAllQuestions() { + return List.copyOf(questions); + } + + public void backup() { + history.save(createMemento()); + } + + public void restore() { + Optional optional = history.restore(); + optional.ifPresent(this::restoreFromMemento); + } + + private Memento createMemento() { + return new Memento(questions); + } + + private void restoreFromMemento(Memento memento) { + this.questions = memento.getQuestions(); + } +} diff --git a/src/main/java/quiz/scenarios/Check.java b/src/main/java/quiz/scenarios/Check.java new file mode 100644 index 0000000..8747988 --- /dev/null +++ b/src/main/java/quiz/scenarios/Check.java @@ -0,0 +1,87 @@ +package quiz.scenarios; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.Optional; + +public class Check { + private static final Logger logger = LoggerFactory.getLogger(Check.class); + + private final String choice; + private final Boolean isValidChoice; + + private boolean isSelected = false; + + @JsonCreator + public Check( + @JsonProperty("choice") String choice, + @JsonProperty("isValidChoice") Boolean isValidChoice + ) { + if (choice == null || choice.isBlank()) { + logger.error("Choice text cannot be null or empty"); + throw new IllegalArgumentException("Choice text cannot be null or empty"); + } + + this.choice = choice; + this.isValidChoice = Optional.ofNullable(isValidChoice).orElse(false); + } + + private Check (Check origin) { + if (origin == null) { + logger.error("Check origin cannot be null"); + throw new IllegalArgumentException("Check origin cannot be null"); + } + + this.choice = origin.choice; + this.isValidChoice = origin.isValidChoice; + this.isSelected = origin.isSelected; + } + + public Check copy() { + return new Check(this); + } + + public String getChoice() { + return choice; + } + + @JsonProperty("isValidChoice") + public boolean isValidChoice() { + return isValidChoice; + } + + public boolean getSelected() { + return isSelected; + } + + public void setSelected(boolean selected) { + isSelected = selected; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Check check)) return false; + return Objects.equals(choice, check.choice) && + Objects.equals(isValidChoice, check.isValidChoice) && + Objects.equals(isSelected, check.isSelected); + } + + @Override + public int hashCode() { + return Objects.hash(choice, isValidChoice, isSelected); + } + + @Override + public String toString() { + return "Check{" + + "choice='" + choice + '\'' + + ", isValidChoice=" + isValidChoice + + ", isSelected=" + isSelected + + '}'; + } +} diff --git a/src/main/java/quiz/scenarios/Question.java b/src/main/java/quiz/scenarios/Question.java new file mode 100644 index 0000000..79179ea --- /dev/null +++ b/src/main/java/quiz/scenarios/Question.java @@ -0,0 +1,105 @@ +package quiz.scenarios; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class Question { + private static final Logger logger = LoggerFactory.getLogger(Question.class); + + private final String questionID; + private final String description; + + private final Set checks; + + @JsonCreator + public Question( + @JsonProperty("questionID") String questionID, + @JsonProperty("description") String description, + @JsonProperty("checks") Set checks + ) { + this.questionID = questionID; + this.description = description; + this.checks = validateAndInitializeCheckSet(checks); + } + + private Set validateAndInitializeCheckSet(Set checks) { + if (checks == null) { + logger.warn("Options set is null for step {}", questionID); + return Collections.emptySet(); + } + + checks.forEach((check) -> { + if (check == null) { + logger.error("Check value cannot be null"); + throw new IllegalArgumentException("Check value cannot be null"); + } + }); + + return checks; + } + + private Question(Question origin) { + if (origin == null) { + logger.error("Step origin cannot be null"); + throw new IllegalArgumentException("Step origin cannot be null"); + } + + this.questionID = origin.questionID; + this.description = origin.description; + + Set copySet = new HashSet<>(); + for (Check check : origin.checks) { + copySet.add(check.copy()); + } + this.checks = copySet; + } + + public Question copy() { + return new Question(this); + } + + public String getQuestionID() { + return questionID; + } + + public String getDescription() { + return description; + } + + public List getChecks() { + return new ArrayList<>(checks); + } + + public List getShuffleChecks() { + List list = getChecks(); + Collections.shuffle(list); + return list; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Question question)) return false; + return Objects.equals(questionID, question.questionID) && + Objects.equals(description, question.description) && + Objects.equals(checks, question.checks); + } + + @Override + public int hashCode() { + return Objects.hash(questionID, description, checks); + } + + @Override + public String toString() { + return "Question{" + + "questionID='" + questionID + '\'' + + ", description='" + description + '\'' + + ", checks=" + checks + + '}'; + } +} diff --git a/src/main/java/quiz/scenarios/QuestionsTemplate.java b/src/main/java/quiz/scenarios/QuestionsTemplate.java new file mode 100644 index 0000000..6952e42 --- /dev/null +++ b/src/main/java/quiz/scenarios/QuestionsTemplate.java @@ -0,0 +1,78 @@ +package quiz.scenarios; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +public class QuestionsTemplate { + private static final Logger logger = LoggerFactory.getLogger(QuestionsTemplate.class); + + protected Set questions; + + @JsonCreator + public QuestionsTemplate(@JsonProperty("questions") Set questions) { + this.questions = validateAndInitializeQuestionsMap(questions); + } + + private Set validateAndInitializeQuestionsMap(Set questions) { + if (questions == null) { + logger.warn("Questions set is null. Return Questions set empty"); + return Collections.emptySet(); + } + + questions.forEach((question) -> { + if (question == null) { + logger.error("Question value cannot be null"); + throw new IllegalArgumentException("Question value cannot be null"); + } + }); + + return questions; + } + + private QuestionsTemplate(QuestionsTemplate origin) { + Set copySet = new HashSet<>(); + for (Question question : origin.questions) { + copySet.add(question.copy()); + } + this.questions = copySet; + } + + public QuestionsTemplate copy() { + return new QuestionsTemplate(this); + } + + public int size() { + return questions.size(); + } + + public List getQuestions() { + return new ArrayList<>(questions); + } + + public List getShuffleQuestions() { + List list = getQuestions(); + Collections.shuffle(list); + return list; + } + + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof QuestionsTemplate that)) return false; + return Objects.equals(questions, that.questions); + } + + public int hashCode() { + return Objects.hashCode(questions); + } + + @Override + public String toString() { + return "QuestionsTemplate{" + + "questions=" + questions + + '}'; + } +} diff --git a/src/main/java/quiz/servlet/flags/LogicServlet.java b/src/main/java/quiz/servlet/flags/LogicServlet.java new file mode 100644 index 0000000..f3e5e66 --- /dev/null +++ b/src/main/java/quiz/servlet/flags/LogicServlet.java @@ -0,0 +1,123 @@ +package quiz.servlet.flags; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.editor.Editor; +import quiz.scenarios.Check; +import quiz.scenarios.Question; + +import java.io.IOException; +import java.util.Optional; + +@WebServlet(name = "LogicServlet", value = "/logic") +public class LogicServlet extends HttpServlet { + private static final Logger logger = LoggerFactory.getLogger(LogicServlet.class); + + private static final String BUTTON_BACK = "back"; + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) { + HttpSession session = req.getSession(false); + + try { + if (isSessionInvalid(session, resp, req)) { + return; + } + + getAttributeFromSession(session, "question", Question.class) + .ifPresent(question -> applyUserChoice(question, req)); + + Editor editor = getAttributeFromSession(session, "editor", Editor.class) + .orElseThrow(() -> new IllegalStateException("Editor is missing in session")); + + int questionIndex = getAttributeFromSession(session, "questionIndex", Integer.class) + .orElseThrow(() -> new IllegalStateException("QuestionIndex is missing in session")); + + String action = req.getParameter("action"); + Optional nextQuestion = BUTTON_BACK.equals(action) + ? editor.getPreviousObject() + : editor.getNextObject(); + + if (nextQuestion.isEmpty()) { + logger.info("No more questions, redirect to result page"); + session.setAttribute("questions", editor.getAllObjects()); + resp.sendRedirect(req.getContextPath() + "/result.jsp"); + return; + } + + int updatedIndex = BUTTON_BACK.equals(action) ? questionIndex - 1 : questionIndex + 1; + + updateSession(session, editor, nextQuestion.get(), updatedIndex); + + resp.sendRedirect(req.getContextPath() + "/logic"); + } catch (IOException | IllegalStateException e) { + logger.error("Error processing request: ", e); + } + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + HttpSession session = req.getSession(false); + try { + if (isSessionInvalid(session, resp, req)) { + return; + } + + getAttributeFromSession(session, "question", Question.class) + .orElseThrow(() -> new IllegalStateException("Current question is missing")); + + req.getRequestDispatcher("/logic.jsp").forward(req, resp); + } catch (IOException | IllegalStateException e) { + logger.error("Error processing request: ", e); + } + } + + private boolean isSessionInvalid(HttpSession session, HttpServletResponse resp, HttpServletRequest req) throws IOException { + if (session == null) { + logger.warn("HttpSession does not exist"); + resp.sendRedirect(req.getContextPath() + "/restart"); + return true; + } + return false; + } + + private void applyUserChoice(Question question, HttpServletRequest req) { + String selectedChoice = req.getParameter("user-choice"); + if (selectedChoice != null) { + logger.debug("String selectedChoice not null"); + for (Check check : question.getChecks()) { + logger.debug("{} set selected {}", check.getChoice(), selectedChoice.equals(check.getChoice())); + check.setSelected(selectedChoice.equals(check.getChoice())); + } + } + } + + private Optional getAttributeFromSession(HttpSession session, String attributeName, Class expectedType) { + Object attribute = session.getAttribute(attributeName); + if (attribute == null) { + logger.warn("Session attribute '{}' is null", attributeName); + return Optional.empty(); + } + + if (!expectedType.isInstance(attribute)) { + logger.error("Attribute '{}' is not a {} (actual type: {})", + attributeName, expectedType.getSimpleName(), attribute.getClass().getName()); + throw new IllegalStateException("Attribute '" + attributeName + "' is not a " + + expectedType.getSimpleName() + " (actual type: " + attribute.getClass().getName() + ")"); + } + + return Optional.of(expectedType.cast(attribute)); + } + + private void updateSession(HttpSession session, Editor editor, Question question, int questionIndex) { + session.setAttribute("editor", editor); + session.setAttribute("question", question); + session.setAttribute("questionIndex", questionIndex); + } +} \ No newline at end of file diff --git a/src/main/java/quiz/servlet/flags/RestartServlet.java b/src/main/java/quiz/servlet/flags/RestartServlet.java new file mode 100644 index 0000000..b5d457b --- /dev/null +++ b/src/main/java/quiz/servlet/flags/RestartServlet.java @@ -0,0 +1,17 @@ +package quiz.servlet.flags; + +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +@WebServlet(name = "RestartServlet", value = "/restart") +public class RestartServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { + req.getSession(false).invalidate(); + resp.sendRedirect(req.getContextPath() + "/start"); + } +} diff --git a/src/main/java/quiz/servlet/flags/ResultServlet.java b/src/main/java/quiz/servlet/flags/ResultServlet.java new file mode 100644 index 0000000..fc2c8d5 --- /dev/null +++ b/src/main/java/quiz/servlet/flags/ResultServlet.java @@ -0,0 +1,17 @@ +package quiz.servlet.flags; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; + +@WebServlet(name = "ResultServlet", value = "/result") +public class ResultServlet extends HttpServlet { + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + req.getRequestDispatcher("/result.jsp").forward(req, resp); + } +} diff --git a/src/main/java/quiz/servlet/flags/StartServlet.java b/src/main/java/quiz/servlet/flags/StartServlet.java new file mode 100644 index 0000000..fe08bf1 --- /dev/null +++ b/src/main/java/quiz/servlet/flags/StartServlet.java @@ -0,0 +1,62 @@ +package quiz.servlet.flags; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import quiz.deserializer.DeserializerObjectFactory; +import quiz.editor.Editor; +import quiz.history.QuestionsHistoryManager; +import quiz.scenarios.Question; +import quiz.scenarios.QuestionsTemplate; + +import java.io.IOException; +import java.util.List; + +@WebServlet(name = "StartServlet", value = "/start") +public class StartServlet extends HttpServlet { + private static final Logger logger = LoggerFactory.getLogger(StartServlet.class); + + private static final String FLAGS_SCENARIO_PATH = "scenarios/flags.json"; + + private static final int FIRST_QUESTION_INDEX = 0; + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException { + logger.debug("Initializing StartServlet.doGet()"); + HttpSession session = createOrGetSession(req); + + try { + initializeQuizSession(session); + req.getRequestDispatcher("/start.jsp").forward(req, resp); + } catch (IOException | IllegalStateException e) { + logger.error("Initialization failed: {}", e.getMessage()); + session.invalidate(); + } + } + + private HttpSession createOrGetSession(HttpServletRequest req) { + HttpSession session = req.getSession(true); + logger.debug("Session created/retrieved: {}", session.getId()); + return session; + } + + private void initializeQuizSession(HttpSession session) { + DeserializerObjectFactory deserializer = new DeserializerObjectFactory(); + QuestionsTemplate questionsTemplate = deserializer.deserializerAndCreateObject(FLAGS_SCENARIO_PATH, QuestionsTemplate.class); + + List questions = questionsTemplate.getShuffleQuestions(); + + QuestionsHistoryManager memento = new QuestionsHistoryManager(questions); + Editor editor = new Editor(memento); + + session.setAttribute("editor", editor); + session.setAttribute("totalQuestionsCount", questionsTemplate.size()); + session.setAttribute("questionIndex", FIRST_QUESTION_INDEX); + logger.debug("Session initialized with {} Questions", questionsTemplate.size()); + } +} diff --git a/src/main/resources/scenarios/flags.json b/src/main/resources/scenarios/flags.json new file mode 100644 index 0000000..d0aeca7 --- /dev/null +++ b/src/main/resources/scenarios/flags.json @@ -0,0 +1,104 @@ +{ + "questions": [ + { + "questionID": "Україна", + "description": "ukraine_flag.webp", + "checks": [ + { "choice": "Польща", "isValidChoice": false }, + { "choice": "Україна", "isValidChoice": true }, + { "choice": "Швеція", "isValidChoice": false }, + { "choice": "Фінляндія", "isValidChoice": false } + ] + }, + { + "questionID": "США", + "description": "usa_flag.webp", + "checks": [ + { "choice": "Велика Британія", "isValidChoice": false }, + { "choice": "Австралія", "isValidChoice": false }, + { "choice": "США", "isValidChoice": true }, + { "choice": "Канада", "isValidChoice": false } + ] + }, + { + "questionID": "Японія", + "description": "japan_flag.webp", + "checks": [ + { "choice": "Китай", "isValidChoice": false }, + { "choice": "Південна Корея", "isValidChoice": false }, + { "choice": "Вʼєтнам", "isValidChoice": false }, + { "choice": "Японія", "isValidChoice": true } + ] + }, + { + "questionID": "Канада", + "description": "canada_flag.webp", + "checks": [ + { "choice": "Швейцарія", "isValidChoice": false }, + { "choice": "Канада", "isValidChoice": true }, + { "choice": "Норвегія", "isValidChoice": false }, + { "choice": "Данія", "isValidChoice": false } + ] + }, + { + "questionID": "Франція", + "description": "france_flag.webp", + "checks": [ + { "choice": "Бельгія", "isValidChoice": false }, + { "choice": "Франція", "isValidChoice": true }, + { "choice": "Нідерланди", "isValidChoice": false }, + { "choice": "Люксембург", "isValidChoice": false } + ] + }, + { + "questionID": "Велика Британія", + "description": "united_kingdom_flag.webp", + "checks": [ + { "choice": "Ірландія", "isValidChoice": false }, + { "choice": "Шотландія", "isValidChoice": false }, + { "choice": "Велика Британія", "isValidChoice": true }, + { "choice": "Уельс", "isValidChoice": false } + ] + }, + { + "questionID": "Австралія", + "description": "australia_flag.webp", + "checks": [ + { "choice": "Фіджі", "isValidChoice": false }, + { "choice": "Австралія", "isValidChoice": true }, + { "choice": "Нова Зеландія", "isValidChoice": false }, + { "choice": "Самоа", "isValidChoice": false } + ] + }, + { + "questionID": "Бразилія", + "description": "brazil_flag.webp", + "checks": [ + { "choice": "Перу", "isValidChoice": false }, + { "choice": "Бразилія", "isValidChoice": true }, + { "choice": "Аргентина", "isValidChoice": false }, + { "choice": "Чилі", "isValidChoice": false } + ] + }, + { + "questionID": "ПАР", + "description": "south_africa_flag.webp", + "checks": [ + { "choice": "Кенія", "isValidChoice": false }, + { "choice": "Нігерія", "isValidChoice": false }, + { "choice": "ПАР", "isValidChoice": true }, + { "choice": "Єгипет", "isValidChoice": false } + ] + }, + { + "questionID": "Індія", + "description": "india_flag.webp", + "checks": [ + { "choice": "Бангладеш", "isValidChoice": false }, + { "choice": "Індія", "isValidChoice": true }, + { "choice": "Пакистан", "isValidChoice": false }, + { "choice": "Шрі-Ланка", "isValidChoice": false } + ] + } + ] +} diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index b9c921f..daf1c08 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -7,4 +7,8 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"> Archetype Created Web Application + + + start + diff --git a/src/main/webapp/images/australia_flag.webp b/src/main/webapp/images/australia_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..47d113bf8f1966695e9805ceacebd8a5201ba390 GIT binary patch literal 15113 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 z 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 Ct$-u| literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/brazil_flag.webp b/src/main/webapp/images/brazil_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..bf5b0f37e1dc33734c98623a998d8b0a4baecf83 GIT binary patch literal 45128 zcmeEt1y>#2vhBuQL-0Uwg1Zykg9mqacX#*TZXvi^a1FsdcyMqPX#f}cgQP@-KD#d+|8{X#HhY9S-|H_*;E?^T z^8qWet<84Sz^I#Jx3j~`Z+W$)rek>(k12>*=;vgQeVB0m>FE~^8|{g+xEe^CfTqvW zyN@ldCx{7&*B_~dd~#MMo)xx7E}((OfjWe{LyI$@~k^*7q^sKp^r-5XioK z!X#4nKs5m~HH|3sPn{Y<;$%1i$X_RaFm($9FdtqF+Q|x}QKH@1S?@8E%9+c+^C*0b zKq!ztRhqFWr~m|-JaSLES^M}y0M6vzsk(gST%RCys9alP_l;#l#K1%-2n1F`|9Ixj z0sf6rx9_tor5uPHxLA0*v(Bk9Hle!e`s-xcAW#QV5FYSfYM90EG}n!7Qwdtn>&grE z${CLI3n#SMusUTw3Mdc905E{O`OyTL+u&lk1U7}wZKv`Wm{gN=$!hay3qzVz(CDB% zHGS}}aNO%+v_xjyLW>{lk>B}L@GgJ<$Ytf`UPg@La|(C_2ytLwo>*do(#?_C8x}#q zhs%p{xbn?Px)vm}8p&ytSdd764K9xuap#~Z_?y6i;<$;rou3sUEWgGylSUa|G4^~0 zH#{Q<1Q??KOOWgoqi3=$>Ja?KL96RXCt)9AvouMcr!al(ByJ=uXx~*`5(bpF9OG=M zO_20vY~J~(e*5q~4l9({;tT0I2=p6~3=qn1$-##96Xga5uAkX9$ESN=YDZfddr_OsuYZjT}G6o_7=}QorlB~0wn0xjSd46oOd!K z02c37wU}Egu3g6<`yc_3d~+}cFx)CpjJp0tOEdQ+`{Hk_J`@Jtzx!-ecxcHK$%J!x zLH-QSB|pi9fg|SVj1NIPtH!jxTJ_;q>AC_YJ{hWRR7lW1CN5w|`;c^zzSD)?GLquZ zdRBJTV{umMr>aBW_Gc`aA66hhD<7kQ@vc+}3E#AKANL3+XLpT%uCy03_`}_Z+lCBU zch$!v0SWFQ;HIE?BVigbEcxAjf{%D>E+;`zi7<-6Ot;_$0%eC{qJsS8G8jtN2-119 z%JxM>FtEg6kyK<>%8-z~KZ`+uoKe97;03xx+&+9olwTzL z!eEy9@Kev2Kw1FPg*&?V#|sR|oa*namXaA<@(&aPebdZg?QceY(<~xCBuN|o_(BUT zb0CK+@SjOAPZuYRwV_!J`xs(Kv-mB{Mnnk!B;P;$y#so#!E>|QMQ9$KK-DV7i!NHz z1&K#8?TEJ$J@a(Q1=L^9KZ#)^Hq4Jv8l`QSj&;K2#~wu5mz8mv^2_uv7zXwuDip|{ z<0B0QB*-88E8SH_cUGZdYTr8-OC5AIxA&wTz~pI1g0~<*c`)E-YMaG=uH__k2~>|5 za-M=b3A#MQf5WSB6buCg%EJRMV%7O3Zc|v%39|f+DFHeP0cVqgkNsTE`DeeMC6I6+ zb2RX6&?DoMZQt_t&1^#BixxI2n@gmLz!RAQt(PzX zu!m}yRN|nc?@CTAqwXf2lk+O6xUeB^77Pg@M5n}n^zTbx8q0m$dl%OpeB3f4?A{uL zF+>o^sx!HV3L-?4<^pxs0{+5P;;URTn*z1qcYZ7q2gorc4;OksJ^h1vzym=B9ftcTh<>tgbG9?t9pQRFj3cK}#j9t0xeDXLU}xrTC;qQ{(~56sg$l}~HnMc`wA zZvy3A30C53D-yon8U9%jUtog^;IfpYRIx)%_JiSJK-WfqsrdVj%oW)>nTu1)hnZg^ z3se~Z3l?v{pP!;`jtnR;*okzK>6R?vrQG^ku}2kP#1K8}<`0@HZh5D+%HS)eCq(&! z1Yd)sfN{6^RyxA#x0$z>TV60H=OFdHbZ8Z6Fh8zJrA0pZ(Y zBnMUM%1fP68oTTP+!BQhVOKSQJiyoBHRy~Ko09iTvO^gQUne6uVts0P2>WX`4Vuv( z-9VEP1|)Am`-z*-hi8FxVR;kcxyc1Cnu@rty7c1Ipu7no1US$&vv=qX)LLLvElvXe zodp#1A*&*I>RD;v;rbv0GS6egqf$DJkj&oG4y%9l^)DFI&p#y6kWJBzuihhj51Le4 z=Y>aOLpukbcy1uYSD}DX}pcPJd zs-jRlk$rhoGWe7-$$PV#nyhdT5a3@;=GK0A5UZXZBf%r#dshI_+?Q&kzM=ZTSY5t^ z0vjLj7L!gj@ra=7tOU6jt02dMdvy);R;4PyT^RgHp!^^V0pf=OTg02-Pb148#f}1< zRu;uYp;}X-O>{}CFE?@H%E@8rS|GvkN*-|j??QsrU_;JxS=6$@Ts_?en$+sAwRvhqrwG@Ks94eQ9`L2{AO!?V6u|})Am2TkL?4%b>9+L_htz0L<$smnCpT>nxV+vbGmF$J^;@l00!+# z{};AKnG2p>ZsDi2snmUV_?NYWfYndOG+v>Dfyt{zAwhmPPK{z%6%hEY`yEO#1J-&u0 z2!B+t4{`4P2T>uvzMI^G`M)4_(iRLUC+z7@W3^~At}w@`KL-|~n&Q7K z1ei~D#*hdFw=YIBnVAmQf1Fd(PCH?$?-%asvdrI!nXQKS{bFjMWaHp{+mjE z!tX2fv3(({Fa$V#B}@pm@Es}MN4R5wg`I5;SE8VPOg<)Cr8g_6CXHN;tgs+;AP(=Cu;21BeZW2pY_}o{q6zG<3Tn41fTV39Y~VRbJ^h}!xu?wf^DT|13PT24%L1r z>|JgoGQ1@$Lkd}@{t3y|LE^+VzLEx!mfaDsJg~>oTRY!|m@j*M*lW{IZgid5Z?W)L zO|5%o-1|eZ_i%{ve5K|^G>^5Rhllr>nYzN*+?nK%f2n$^*Rzmr-S5|`Dt@EFUvK1x zuyHU4z5OYP?LAiWSI!znW7sTdRM}B@I_lIJ)D&E1T<1KslgYF|MX1YAQSAKbLVmeY za$2N57H44~OajP)YdGsj-|_lu*<4a06EQa1f{KBAZO!wRhCJn=d`*5h2$Ep?gu&VFha~c$s%G3I+QKK=b*A6rOU7eB5kTRD5?hD}t4y()`!;+uS_`FFj zogF1T=sgpEN5^UPm3&`85Mg;!5Q&SN72QZLOQo%d?yCyMZou#a*U0qMb?+E_d&-lf z%tZ@f%9EwXZ=N5$uLD?_BgLtpzlx9x|K1nkRt_zSBT5?)rTmR3JJ^a}jT0H9qDuLX zv>&3=m43`av;eUR-Gb}t)7|1e4@HVe=gFrfDPB+g(y*T;H6r+?w7gx?f zB6?(6&isjY;HlTBxeZ%(p$U!JD@*_pcqmwK_!ou z61)0tEXj0kq)6z1Ji| zQheuUukt(pP;5tT(Hsm1)>wA{C;(=CI^x8p;@VQXj+CkUr5%ISD`z7{3<&OG+vD;4 z&95(Ukj2m<=vw^-4yK@-@Q{(aFtd{{6pPlp-uj9INb~m&)N*+*4Afrmt+N=0Y_+Ia zG4~Gh`+<(1mg^WhiEiBF`J3&Z#E5WQ-jRzP0Rj3kAK-BSy2wB0r5iF+R_S-o-V@S^XOh#*Pm4W@~`=9fbH!KlL30voC zg(F5V24dnws0iR^+PC3ib!h9hED7lK+pjRVctUygtttXHm_Fp@B7dMDnK)n1N<;F|QnL9)4C+`=beu{R{yXQ1;t@u`Jt@E(Jfo^a^MS)ECG_Zso5zxmkD`UgT>O zCVm)p@EXyc^IUr3l9$J?k^-Kcr|D_ZsY~m~5Io|UIo_*Ij1W>@PIp%fCy#1|J6E`_* zP!2Q8&Y~9@m!pAmXU?m+;zEzO86g^Ynbu8#4AZYYD#xDDh|3b?>#yNIJJlOjO)>NP zEnGx|S@Cx2E_)ko#aU)thi6P|Bm_q*x%8-tY0M7TV6|v4iT!-xq92R)bG-&*klw}5 z>UVpCw;dt!Bpqqq<;{+tIIJpBX{wNlYj}i5GgpFw^n;sX^C=8gv>5 zs1r~>nv1>2&wIrSFtByrRuq4sNS|6$#&<`u5 zKNU{A6J+#rGlIs?y9>T_wt}pu3QtBQfQZR?T&z}Zen<3aMiPE~4j0*Tsvl`$#YwQ6 zmB$)guAG7vsdw5%7+AFq7yz3){+k^lO7vE#}wV0JM^t>vT*24u%=;8Iu+Oj!7)#lI>?J2cGTgg6josyG_v?E@gJ_~F)EcY zMZ&)OHht-ui)&tlcY#3>+p>+ANLnZs<2GbD?JOr&5(x_^+GH0(dP=iTsmwHY3CvX&2Sq`N2%2CWY+I33dwm zsisnIz50~RxM>ORqfXD9rsOL-t4pTe{)AfT%<#Mz-wGm^Yc1(U{22`r11DWV9x4d| zsS#!7V2yo_;9dR$BwS&>FqkP@92?VkTy_=NuVZr&uy0a={TYl{>SOf~8Ot5;xZlV9 zaGbnR75y|~sBwaxe;6#iWNffe0#=8~X2t&ruZI%06f}1(7vN;Zi(t0m{ZHeyHXW#$ zE!{r_eE#aP@ILs$1+7ixpdwl{1|Hxg02I1b0iy12@zHzyBhay}=(S@JG6wSA-hL+8 zSYgo4#6{9IkK5g#>Q=#Oo-h>1ID>44%3N~Q97UPKng>om5dNJZ|KzX;L*eUI@3>Lf zWS<+nuC><2W(Y2HP=Ajbn?Cz6Ea@9liM~}r<%2x>$xi21ZmfK5(TMx65ugBUW43|C z$hHb0?8%_R1DW3@45;T_B} zQ-)|exCe}6mB{|_?KL7Z6gQ8ggdH;3WB1qHD#Q$>%8~Y;1??=R&+oE{&pMbms4i>D3UK^uelJ-vTm9G@at<KUl^ z?O~=aOE|QUaElf#ReSAsJDgZ z`ZyJ;0|`+WY_ce^bl(U&u>>^pbQr3wYiho*{c(W@CN9W`uzl!4UfvJ^x1VOgmk_tgeiUHYxi2ms`||W@y`Ze zLKV3Dcj!dT%W|8$h(ZdnTAcX;HGVdc$63#)Fe7leUbd3+rqZ8&l62utjH&m*?lm!J ze~I)&ON4)9w(t30EFf%7b%~OsYUh=LPzzzce`kRZ1)swQ>!)>VssIS!awck)(b5B3 z4V!OrV21rYc;>C4NhU8V0%v{@Emd?+mtHEsO6_=|rKpYog40T}?AhoatPOG`m*Wxb z8%Q_t?QZ1BsOFyDt`PfY{LL2sAr2!r=4s08bzW{ol3kR7AsuozM{2eEAtXt}x8PpQxh_ z*oCR%D#G7P0%U$GQ2qMQ_;som;28juZNT|AP4561E!X&2^`vg|cNms5vVxG`V1Ar- zcp4MA3|)W2`VruwX@Aqu2lJF;&H!u>5PYqt0Nj{B-!zd^^}1o5KJBlY&E&I>>P7MI zu_gt~uUE)$$fzicBcTWLtNXs~4}A$;9KXR~E0F#NDD4v&qj5T<{g8%`*Eh-=P;O#+ zC06}vz9QDc=Ia64L&Xpx`!0uJJ-=B;CWml~#UmMD^h&>^F=L?s&&~@`EEwq6_;5F9 zsgCPz8ztT6bsSXWQFIEV`vNieJ?TmDrF}CVgw9JA$R@gO5STUj zrz;6xm^J9_@3j}d7dc{LANL<+YBdqBjc#P+%w__MQRKHAN5jRf80fAr=MVLBPSd2z zL~?lrA!DHN30DY94c$Z!KTAP{5L4N8TN`}rcvv0bRxc%ZXyGZMW}k2y82n5LB_Prm zKuRu`r$JL)1xWgzYg6Es|A;8e@pgt_I+wOFXMB69w_Qy@N`Qyq3XJ5jkPUKwTBi%% z6wgXafnjhF2`)>dv3LXMDc~P|3jMpXfKK(cz`@C?N&e4G^+q@pSM0H&JY^6Op+>aA ziYTsL^Jt~CnF+b2C?F_cwhvwCIkqyA15P<6-l1=&zPCJ^844^h1+6b*5RQh7f{2?# z0iP1QN$HM!Q}lT)*3&T_34oqiGjY}y|N%LNT940_J-H@NR^Uibc_ z)Qg)cjj26UF#5d%5}CW;;#hl2 zVQQXjb)`RW0%PBp-@vcqOKCt%3GMh2-N1`IhFrJ+=!Al;`b9k09N?UD8}qvmHV;un z$?Z_3+)NB~PGdimraZ4TBUP#zPk`oYHB09^bpgW+RB#SY0+(Q%*bW`J(B3fTcL5ap zHSs@8mX*0UG%@kqyKk)aL|%3l$-;pOpaxT>S|Ftz$8$>mA^iF$_G0gl*tOi4^1js#sUmd0)Lf(KkW%WH&K#jVJ{OA~nNqVYMGT+ts-zG!nkL z&`5w48ATuM5AqT3$B-kDI&Usm(LyI6Li&CicM%TNJ!XRA1?x^D>}`b}DQ9m+K%AoH z=@c!YqC^&hs00o&yapnYyhxSyxaT+ezRwI>W#`^+>n7qQ?m*a{XnRgZCs>dM5asVf zN0J7GlzADmYj_HE5@qk^qlwHx_$0HAv{N$eNzU#teUfiMQKh{Z$hgOU=ldDP9H%km zZfQQMLe<;LRrkHxtD5^TKqzq&D0k#n_W~;=1(r`par9eGL*Zc?&3d2Ssy9#=aQ?UD zN|IdGGTx%h!VbIzFiSg^!>~w4qz@}X#KBJH`$p}Hp#s7)OwLmj(@5=IuTIFDph?9w z>+JZ9y&$d?%4M{OM^Yt7F6xMYj{sRT={9~#?HQuAGalZ+6#zT+-A9w(?AN0V{%3Vt zoV-5s4CztiEY4GwFcTp*TV;6p=IM@U;gWh9X4&(4Qg9r|QwuqkYhV%As%HPex%3F1 z*e1<`k{#Lsw4X(ZqF1;TOOzI+u=0^ZOg@Ee)J0KyGMq*>?F)ntNSdpA^@92+^P?C} z0V8T(>xvH5hY`Q!jUGTKCku|$8%j;Yo0BTAh_hyei68GK-moxNp#ko}whz}~t7rkq z&K<`ASN*ws1Xs4g%{NWNNQ%jS*{D&;t}@e%Eg!}>)j;uDnaE^_8HZ8^A04H}jCupa zO98Om*YtmQ-oqurw5@P1QxeKW3loBDbCu}zS@ua3#o)zo91YTm?JH4t4`R!|^3cA4 zfZzoRr8N>xUn6H1`iuF7adF8{EL$i}fxHg5v~?Jb_vdzM3kj-D6e+;-99~02$Y__N zqX4>NkCbD*H8**ky-}*3+Qtjy?7RY_%vwwZP?IK~On3d}#`>mde)nYCXcK2O^78$P zi~8uMucy!paT`c#T%`45{JcR(n7v?1mgAJ5Wy_ookYuCf;g4}rn@^J5!c*`5O`kso zvYOT)0bF7J;0Qp^_J3jpuEC0tvucWy07lrCno0EmKN~&Fmeg4D<2gMSkq>u9oC~O% zK_4356ECws@0#W};TMcvz-RtG47#bGzN~e{7i?xq*RZ6w)Ar^Np7QzcJVc0?WM2h0 zAas>&y7WTnI0UHIe&1J`A7eq{zsrgi0iHM!Yjlwwq8l#KY^Z!aqDxU)8}X)JS`;c? zFsQHR%z;1RTj?(XGxbW`8i;*yz$m6d@%C$0p%iWa|KEc#_JxMU@QvOrjR9uG$nQ6| zxe-#sm*9yk?+|v0L?ncZpw*1=PDJu{4HjWf0TI>Y1W;@MYJF3QB~*CP$BZ1Z;)Ed2 z0V;yxBNXfYe6t0f+*3r6J>`81fCuO2)U5e;!JAUFkm|X{={Nxi7ZYlq#PVI-1p5yO zEHW&9%IIpZh5vyiaLr)yO`u0B6vhxx)i9<523D9v(-Zoe3^2(YeyevgljNd=o?n73 zUPcAZ)VFuwJF%zyi2%BLU-#eSJ?zI>&mVx!X%8Zc0^|EKG-}LJ*=LA|9!a$OzjA{- zEr3vNoqC@S@R-wPFCN0*V5asxBE^fx;KE2zLHuXU&wVvj($(vVbDZr_45E63p^id; zzWK!dMWFZ0yPNv?h*SIYYtP)+iRmEEknwJfE-$RjNi9Q|jG4bhGErpYH6S3{Co`2i zVuj6<(P1pNL4S52Cju;&KJ$f0bLPD`p(lM;e${nL=9yBMIq>5etMR{OWgwDy0R+B0 z_rkoY-+#_3Sj`ON;-`c$T-OYYu^Vxd4FI)oYfV-F0f>_bs0WM@*#lK!7~!cSnxn6N zL(RA11~BSh!4MLqj&0Nh3!_Gjp+~sWVJpAiwr`LYg9F6z??1Z1~yU7 zYSuEECRz8Fu>$*n3XRXzs{^wC^SXoVW5 z0}DTU1nCr7pc0?GczrjCYBKSOvTspr{g^aqBsAO57`sUW;L)fAv`SSd z!w3?1={idu*60Ra{b&vs7f!b~P8TE@}oZC5*tflD!c*L-_q>_#aGcmstbf;EpUx0S*vr!DOuyX$i$mzcGOwyYLXSTQLs zValKnrbr9ODR06i3~GX{Kc)_0*L?TJcB@cZ>CI!VY|djou)DnEku7IW!Jbb|W=l$% zO$AP{=J$4H*=St24)gdS`Hq@=t|@{7dP#U2#Yps2uvE>&kL1no5O9S-Cu|aBe<-Pc zX4(i+AFFyk7cwI>XYzC6ey+}atnJAw<19J6k!^YfK2Uuab`!|#$slHXm{BbE&f2ad zuByjPv~*ftsS{pHT2yG~@R^^1I{jn5O-3h9Adq=DD!y!0^ZS*udPaJt@{M`oFFH-$ z#GjkrFN%mDQ#hwh!{b70U7Ql+_ROe=W zMrG?qhQ0J)a!AbC5;SDF`o-;9RBU)CI=LfSE0-9yd>2!Z+Ok%46`xuTugJ6bT`ddYxW$*xzD6)X1>4>Stq6>x2;VEQ zjSQLX^xMz6-Pd-ll2DeOR+gUHmnx!%E27KVv+xrUP%Qn?g#qY|fL_XJsRdWFPrv-C zqCuqRI7deZ+-pP&(&Em>J>jiB1f->fmH~6S{jimDtWM1-uVgMR&epY03*ISeAGiMfX*^FX8Xv?U!V6%Lo;eJ&cy2pFz zM6!Qo|2^-pE=Jt$Y7Tm7&8PHVS*AiuHP0*jxMhECuiJy2)rmKAA#`(7-w|6vODUCBusqjGukk z3f;Qf3ek1OdZ+y;?yQAX#i#LdHRZ6f4-)h4#MS+rE-LZ>AaW1_3g&y z)(bDsRsJBM`}?*}x$mwvt!6l^HC-Pr%a?EYZqJ%cCvpVdbA6UGXejSmcA#4|@BOZ_ zhR*moJ4WuIyV+kNznY=};>_6G;@|yKI)@KmkaxBm#^;lDtr@v4l;`xCMn*`@+7r(6 zatA9_i=Xs{iO;B>4VyF>W{ta?J;&y^ax6O75#~$9iz_%wmb@7%hw`3_Cj;lp(9_4h zUzQp+HSsqM8#(U6#6Hltz>$!5)%J?4JNiKSn2fBM9CIuAN)7H_r4fFNBGbS4{;4T` zY>R1ujKAQgJBqo}R^w~5pcjJ4TYND^Wt9$H69V(Kw5z*Dm^tJ~OJ>1Ul2_SPQbQ!z z!9X&dCsAvmJ&tLm5+<_v5uk1DHwKrMxEC^R@K7$br;opnE^OD6mAqH2gzA zmxxl|#q`h0q8O8_@WKLuK`?s9cv7;4%Yorg%S=dWqBOE+MbDJHwEzn)g7X??@65Ys z$yN2emro9o{C{Z~a|59AqM{$m2nVP^j-{;kpYFYR+$5p&r`w{32CljW}*sj&dwCgeYlZN@`L3cLKDq8vJ&Dv(dfKHAf zTc6xr{Qb=JH7@?j`{H1u&^0El0qbAsNRbE*`=0UVW4{V*=vv4qd+6Z6c8w zWmU4zw2hI{m7DqpKX$tqL^plZ27@`nJ}w*-uU{-Sy%3>Q;+n8&PAiWv<}k{&DmdO7 zM#!1fg%!%ZUpH?QZ-3-DwAQp2%bp!kiBPyE!6HHXt}36v)(-TM0gOF4vk_x<&+*AqPE9yj?}G`eB`ticoTjc;H=Q^=r_+7= zKH}D1QV!J~3?Mi=WsI0K5sq6_1-uvyEGPQFWmfD`7S0K45ujMo<`Z1g(B}Ir9}4*F zXm93X><@JYwR~#oF>F=Ol!d?l=v003K(R41S9C@a?Ck8h**JX^WsMWsCV{Zn{#mT2 zF%f4>RYp}rs-)Br+6O6lnsk&e&=VyFO#!d=Je=6 z^9kS;rW$Se`EWd!p3kdn{kSwR($Peo$OQ=-O&S;5AG+1aH5>QOLID|8hzi2vS0JEc z-t6ZbhI~;wu_;nK3kS$fd4Qv!d~a3&jZ}PN(=sf!ahc+RHRkkaJ8Kry_x;Ob6Sv%o zcJIYf{G-_en%gc62<>aj~OVZ~4OA_&uA*b&PCs ziUFbtX)i_iC%70D)h|BXP8SKbqB&<^GYzv1hW4>N`EBosex z%;eu@ab;w>SJl8Fe)}m4e|4S074hBjZDc1;MVZ`}FMDrrG$R$R6#+-a`q~bb^*_C( zU|D1Rr@6yi6(KwsMyw6G|2wpJ>z}JMHCuq!jE2U4 zXmiiE)X|q~2fE;{p;R;8;j&iU+=%=pgQlyRv*uFE_QZfc{i}X!h|C_x&GQ!ICjYUvrXn5x!NMQdNwAGQhNQ3244kQ@3!%9<&@l-Y z{bMq3Tiu$1`&2ir+pM*i+FO*eq?iLKbcy4wBD$#wv@jNf7zhzUYl3nZI@Zn4} zM0P;R-4L)Ao3&=luNeF3=uu%n78DwT?0L~>0mRxrW4E)ozGQlr&RU*$_jKox_-^%_H`2j`6YA>9wb(LZAl8z%PM|^CF?_7-u5cM#3!LoIY`Rbng&u@@k z+)fID_R8z6ZPE}(?m}cOp3edAAKIiT#7aE?A6Ie$Lsiy@QgoQHo8zqZQ5pABqyk%h zC7aIV=f&NT92_pot)%&-W77GR{X%VJwVi0ZlgTtZ1p4zBxe$;X} z>hvo;S9_`5Vc4qq(~OPmH)2iZvMN=dC&}@AD2)g+B;F}qo*T!-_7JE&x^N@ywG9@I z@yEi6v-d!6jkATrb6FVYCjFwEi}chE;o6^Y!{7qq@C_?DF{;Y)3(tHmbrTa(@LK7m ze^Bv$7k@PIiwx^ILiM~m#@5qnzs~0VXELmdxX(pAeOx>5(?-PVg?PDz*2~5G#B)hA zE&_?NcUZJddA_3)%5}_~62e2Vi*rkBl^CSWNd9sKD8(^b+-smJJi{k(RNl;H!GV)OV#1g&T;PK8NpUhmTGf<&5UsKC7?yJ zoPgEYkwe1y$*4_OZ8@FGuVW8hvgh;@yD&2jt+l85ai6xCk56Z$5e+8FIOWMN24h2Z zom`&0K`W^H-HW*7lh3e!t8|M>KN7`AmI=1OK(vpxvN#a;duS~9y?#=4GEm;>fLpb2fV0a#ic8eBy{g^JOtD879&kr3`Sn5PyWxlCn2R$f zH*fm;J>StEf`+Pj6#Tqg#{H%SN}Hs$}*H+R%^{lshMk^7-jr0(qT{&AGQ z4RK$^!@3$hJSR8{j%gKZt)cvcw_bHVXnH~<6SysVJIb=n5Jt% zBYmTKMOl+9f6_%i>vPxy0xt86pZigzgGU8IA{phU*h$M62~^Xw&pk17W(h5b zTd?=&!pNTW;zsrf2rYcK;fg{(QTNuL7Z4;E#NP*;rv9@}=TX~A6+77E2nJrVOEiJ; zCmG`NNkw=8u^Xe`e6hk{!+ZQ^^<=f|uvBD+{i#Iks40svWF(u87o#LZbT0s8Ihq>? z*70X~s%@y&ZlXqJ)ly(~z-dV#r6*d(_8Wmw{>VP#^vaYUkFQq}JqW^*!S#B(9YJaH?QF-I*tG$XK!b8awJ&({ShyLmNet z@?ZF4yXD-}Q9sb(t1>aDoi|z1k%hw(!$*u+vPAhfGKco+J-j)>`mlH$H0Zubj=qU- zH$;#p-;C(zTNV&AB#QbKqxV?_pq0V|hD#V}RDatmL8K0;RFIZ~H}l(_VV}0?+f!-!!M4lj%olHR#^T*EzY}ZQ9cC}zl^MoQ8QdFJa%^`X;lV0- zfjft43BreFtjZaHX}H>V3WLT!ev@n9)7J*Cb4b|#<6#0;-lw&^$+U421tsIbv$8<7 zQo$Vmklm&65HKIzd_{ooeT%P>*!e6=;CUa@Z5Gwfhm$_3!r*)H8ncbDHQ3s3J){)tqk`^G#{LSxnT!5XM{~g(s0} z(H-3k6H|4Z}3hmn9?#6t@q>Ah*q5Dldi%=y3C4(+!}Q!QlZP~ z|C#m>SAwIB0gO-& zqgS^sw-+ucZ4uhPv#PY?c|AO2v>JG9yEL;|R20*6^{9=nGWY0QXGecmAJcx6fL~-k z>R5yzOM<JUMAil5xgd-g0la7Rqbf>@vJ8I|x0ztn#0TTGJEthE znM0&A-t$=c7@`wAFGGW$k#N!CBei{tUN4`x9q8sQdo(=fae1ltu5f&X2nj{=1Mbun z7krD5gad%WS}yCzQ-EC$VlyIQtvxPmeK7v#pBt<8m^F*mm2_$;DYL05Y)Js=3;YMp zQ$NJOvKF|#A!Ha?mN?uy+dSIa+}b-n0#1&O59m+k>f+1Wei=I6+s4jW>occChPiQY zzG*0(`oKyMX^|1@gwm;)`bD16&f{fvJ~%#g^X$dGpRDrCzTxRI_}#=(o&6ZuBTw_H zyNTG=_(`hUbAq<+w|-`)%s<*&Q|!c!3+_fd@$`uITR#jMDS?V#aXym78W?P7UkSMh z0F9K%adfz5Uv%maPRv!)O4Cct)iN3Zb|}8H5^X8RMcM6rYVCbG!WJ@S!OL026cE7C z^GjV<@DPl*k}S!rmzkfa5YR}s)Cy2@H7){}A{ zPzY6RCrYiabI@y0mjNWjdzj|(j6-Dd(OUO^zV|zYEcd$RqMV~h?XmzLv%#A&)PWYt<1~<&EIPB7#NGcDVB6OUc?D%qSmQFRgRjP4plud;$v2Oo%O#-L^sFG8apPTWWj7J=iWOh z6)ar3Z|@`KKfM~J^er;HGla3L4hS)x>>s$xsgE<(7CpMjH@X8o#u%ca$?L&Z3L z0egp|wjEAYKJPz;MsJ7ctI)8#Y|~$M^*t71n(P{MG|GWlM$<@FFz4@n4*5?F6JpbG%lj$$Au3m?*FIekvW_fYpMQeLZ#(s?sf!c$Zf zczKA5dcnetEH6HgmFJTy951$Z4A93c-S!`pISUV-DeH00q`ZTnx=YTQNxQB*;~rx) zxU0C+;#`tZ#QJo9b&sE2H+F)gzLJRa>Na9RNjsdp%t7(oa`L4>E~qb0$A}d9VIc!8 z3)(Zd*FfiA9nu&iSU`+^1oRouu2NKcrr6`+{&q0`nb@22vi-3?KW=A6SnhMQ+Oc5n z0@v9BSMGB4oq4{t@?NuVZSpsO6&b60*W`%Q@#Bx%L5KjNob~9-vT-B2u(rn+Dp)#q z_LolV8{A;@A|ZbB8APoa^N&%F0Fj6kI1s)NNVb!@+HziR!~O?7!fl{Kpt0C-$+(Vi zA@$?d01nK^Qj_K zNyjSUz{x#xwt;>pv537$>(}eclmXQ1*qEz`ckA!o9=SZ~d~DhwZk}c%F;?w9-`!68 zxjl-2Yw>8e(K(MmVuz-6Yd*Td(R`lUf75gfaGWpvZZ26?H75@M(Fyp)P+N}%@#0Y{ zx>t(5b-*9m-Fq%r?^d+b*6$AJwyIwqJzRyMnHF6Amen4=5P>||U&Iv?*iqz=DRXb2 zKGrW}g$#tow@n4w3gg_S-kh2sKN+IEde6IV%w_fSxxDe^J+%PPG1778h5sNJohbJm z-VQg@s@uX~cff_OwyxR76u?w!b<}a$nr*auce)C zt+yB*{fzd5;)owdQ%aku0&F?{A<6(mw8><6Y1;5MBBN|?a#76+syBQe91rxt0o$|& zc<#)iM6gV+Tk5UUvwl~NCD14ty~({4yhT<^qaTg#tvdE@I4r$*31ES4!Z~pHCW9m6 ztL=6;6~+-8`MSOua@48rv;QZ7P^C@Y8bFYpRz6|)xS{mj)X4|bv7K?A`us6^LK>Mm z6&Wc>6bOE$wMrqgZFlbZNPb%B(4;w^GZ2>Xl%w9PfNz-k&VXf&m zHQ@EdC3wiVANicBjRq490<(I1Jz;J2LRd_&|jz;kNlJEU=DOO@gHi*;X zu4T5bi{dYURAfX|`~G)BC-w-KUQ7Y+Aw^(oI6HO<(faYz7sils?pt6=Ym=|YF3t6Y zOF9!bBtnA^<;+m3bRuJN)%_)I?gSCjAXwxZWI?2b{90=ogS)>m_)f($rJtw-P*We8 zJi>Mx7UoM&Ha3?0G@T?{FeQ?*<<#y2j^?KcHCR8; z_WqPd?8^H5Fw?3GP)3s_v6S16vBa3><_0OB6EMoX+aSSdQ(xtOTK3^#8a{O7(H?OE z0ec?xCNcHZ^%woO$X?%O(#NwIxZGOTksJqSWLUgEPnIx~^hv-Wg=F3GJqZpaQ)mtV z<%%m*!|~**_cxv@nQmM_KIBR=Kml~4U~#B0tiI;%CRi_j11xbZ#m`$~JDPnf*X}nv zxX5U>wvwHx^E}f!^LY1-*ZpoEyxU=Ka-fBI<`M`Jw9S41n|++K(IIMyKe4ca6l=gc zwWi9Qog~HK(GsoKLpxV_6iW}E%=QC$w|+(=As{9%&pm#3JFs8=GVAD;Ale%jc|piD zX!g`^U%#js;=QC>suBuRGNB$>d>>9{Ta-g?ZtzP#+g}y^01DO}!BvphcL(3aY*zC> z>9p0KC!JhAZzyZ7Sk`3_^IZ!yRt2D6Zu^Jy@fT>Wkf>>JI4-|wiP;&O4_|;RycsT_ zPd&UGW^Wu*nWZ1p&Zd-&$>R3|W+%RJa2Lt^@3x_QW-J@3GmYzj zCaC{I)mH~a`L%zmD4l|Ih#=iv3%Ur1lyrl1cee^imw+?~NJ)2tbhC7abT8fY9==cf zo_EG^#u@)umis>E`s78GLOhAM_U^b8{%9_AxShCmw{kYYa&`CB#o~-dhJHgHiRY71 zuEx{z5Q>IMn0W_m+e`9O$qvvv47vh3JFXXgX>JlgrLaAMQcBeJI?^=?TUlO)!|mb2FVj>>;YBJmfp*nYDK z`;+_>*|ZF}%y)s6FG?mVyXvbRae zN_7q%N7-RPZv5PS84V3tdp4}h`e+}g?NOlcjj{oeDn@;|1saQvXDEm2vdCwVcJ z)Qm2i2C+08%BWvXkQSF!iS048ONP839gEQ;;s_!};+*sQ-_$d4il#fR_)m{fro82y z&sriZbqCOTAdPN@aUa(kDt>7x60z}C+ibULq7f`NU;BJp>G~mj3u5Thgn8ZoEmfKvWuIyqh#VC z32lb-ar;$k6MMtCW4BF*H>^9bJks@ePm}R8^~~>fn@|s>L_Rruf9re+#cmzn(YS@B ze*)KYWU0ZsL^G_#V}e{@B*hKSc}c5>WdG&$)7HxqCPl~? zX8hPXJW2=sQKJItGf3cLz&#sKu*g~0kZtk9HAM(wza44{eea}9MTr;Cc61VBdAA21 z9BA@2QAme|RxTenh9^%q0HQKWytoi3pYESHkFoW`k{Cq)?z-LoO+52k-|9QQ>v;;{ zwXPsm7zU|i<+#|+`^zlAJfct@`--!olFzQA)rffZvYmGec&(@v^RcE|>^95cw8wC3YYbENYpJcwyZ=2mj9`QvRE#kDl&6ja#X`UsEVl+1wA%dCu4Z`jl z#WKx5vEJNwEtQFfq9$_N{JD@^vN9gotETaq%#;v$?I*;0FeoQpXx=2;T&fR<(ig+! z$+a0tHtFw_anJg05&L2}d3l>oYQKb}5to!Wl}cnPRNvK)Hs5&;{@hRF+*=*|ji6i9 zd5Dr?tMFP~o-j2F_az<#SX?1~{}a=}!PtD7_2FQz3Prn&o;>Y#N^wQkXAOoSl3c20 zS~+vDQPszUZ*X+dy_Xb?z3mO-p}9TRC2F>jX6i0BDkW_4X2HwkY*Td$TdTq`6^Xj8 zWUOsSxEQS`;C+D5P#K<%8ohHFnMnB3WDWs{SIIg5K@fn{qyv>wt!%+FYQg9Du z6}Pj)4NrZZ=g=iy;>t95uTX^x?d5ig=o;MMC@$di`E_%&R;Sh25nsqOpXhSa7}9*8 z-Vl|_EajGmuskDU$OPG3SAH*NOtijmY3wxE_Cg+g(+7%-nulC`oMlq zx!t{r7`uXM5*PApITNJNPmT>>kWMduQ7~zVA(D^I7Gv0{eCBpb8%ECllC`@Y6N%a} zQE;|GT4!s3o!sI(F>uYJI8tznYBaM7IsGVq62Lasv=Y|}!e&&MLxtPs<6!)_san#q zlW$b(KR@}dP<_QcCAE2_38#d<56<}eX-f>>SG~|`O5N3c{17&R=Re?fmThKJ;rhwl zYj~wgBohUk=go3nzOZEudhrG!N9EmyN2Ml-89!To()dx2uZ!0{eOF&`sJ!+HS2h8M z+cnomM^;AL%7?Hf422;Ajj_WHx!U*tYi)SGDGc&E4^bb*dm(zXamyj@vsB_p`OPrC zH&|>*h5YK{g7@zi$~na{d9E(&k^OmZ#Q3DQ^Le%gm9lW5AI2*MQRS@rFR$O2={Me) zXQnfcE}}AS2*r@P4k`b~V*gLYP2`)|Vo+Xj9vQ0I_`y$_G2^lJPCeO5 zjQI^AQsd`rNjI}L-TG0$0gms;e0f_WBwXL&1ukvCrsL3^#T-(QmA7WmWU--smJ5A{=M~<1 z?jcbfH3Ai#`kY7@XPPy93x*Yjzm(59c*rb&7#-qOeD^DAH&NT*W9*cQ$x+t#PYC<$ z_~PUXoEX@U=NfOw(x9}!PW;)r`%^AXpAIMC;WScXM4MiC5@FM3(FG6}t?jFMVfQBh zD(Z*-blk!RLzF`^_!ya0khjPwO8N2#TI9gIdf<*X`?bI@D;l^c|4Lj9|E3 zU_J-=dTrG|$c_YrFF)=hOZiL{KG)vJ zCRp{y7_-Ntdad9sQaWgy4!Ir-A^FQF`$ZBUGB0rLoxVL9vNXzL2K6J-v77pRK!DG zAATFoVq(1|{ZmA@Jtl!=WV4t&HuVz?+1|;%4$e3&x9Tmo`HS9LRHNXrcg^mI&+|!K z=sU|6a3~8Dhr13D8W>xp zQ!sGJV!%pC-NL*)lYx2vXgcK_-Od?bOO|1avF|gCJcTLR)YkDW@8KsBitqmv1&u#H zsTF-PFW4FU5N#o-9pgB3AaN|e;i#UcMS6w#DZo)+bnVxOOf&Vm@uaJ3@I0h_a$)9` z2aVs{{ds-Xwg$N1eDPtIIhTlHxwa;Yz(EtLGTPIt6#Ow2I_=n;zC+VsYtnr&Ay>y@ zaE_JWfkLTJ6uqEN?FY_pUn2s5_74f%`~HH>w-~ zdbp2eqvMii)KCx!_U4Dm@siB<%BOlGHX7wR?f5ssdrpr-CST1uuL$}?S4CqV0peaa z+-qjCr|?u>l(O4v5j~KLoC|SK zYjJblp_6Z?#pLK$mb70>E7x`Y zqV)rKw6Jd~Wl@d2m1-u)%jxq#pJv@bkt?r@UGEx4V{(Z!;Cb56VZ81V1QY1L8Z-+~nbiVwv zUN^Y8egKI^#blc0X-MNtgD8-6H+p6*9jWr+YEYudb9XYh16{kre1 zLyWy@ZZmAHlu7f#y+u0jmBE{35NVPAYNoyS^?A5v$dbh!NDcNkehumQIwbXQ!K!YD z^Syzgh1mN1O~;X@S^0a{KWNorSoVu1&gSlQY29ynwr=HDje1{QOL;aHH=1bu(0>Fp zj!pE^(=saR3N(JZ;pB~?p%#m31{M%X!$3{Gq?T8H?`vA0y)~e@K>whOH%B3CB!4hP z0!fLhc5ET@MHT}{p-{!+()Ii}H!VIg2m#BTJShY8XRY%wKIeW&vDUv}`eh&DyTuP1 zxd+iHBG8NFKKdIgE?E*qob+dxbPCb!Zb-DYArvuMzcijpCRDt9+K}Il>%7ose`HHQ z{Z0R;kI~uUMefGXH$Mwb3q68i!hkh4w`!A%)=>wrsiTl9J-|vmRxMf#SzY8(xlr={ z>XO33>BDT{-K%pf@qz|MN2tRh7NZrnI&)QUcoHLhk5hFC$l;nGo&Z{UI9E#7qz??5RiH7#i0dOrD zzaDXe+Jw?=X8>xmru-MN&=tA#gSk%V!e(p_p@-V%ucz+ZF5avYq>*laXV#U>^lAR6 zm5Yq}L$F>;CUY8H<*Vkqon3Vc9wu3XSz7}s>9|p{Bq_4g+S!=$6_LW9>3u%iVzjF zMjO=`vhrrP_0q+1&U|a{jqy01*gOjqN-!KC=Pg$9J_~|WOZyyOe1!$n_;b>C0JVS(>{1*j)FK%CgV^2gFPY{e3(UkTwpuc-}jXIvM@UD*A^N(UvkEtI8*tZA=A z9X5SII`-zi&DZLtRpeZjNMOqMHf0iWEv+8Lx%>#STP>pEeLfH*io}ufZVuMmxUoSo zND7IWCzCVG5A!~%4Qje$DYQ{esAv*lw&v1Nf7Ibm>rS=Q(xtyXV~n9Q&~3JJxm~bC z&Z}v^3EoAY{Z`f!5idkF^!3K{=mnxX+mIKUN-|e4Rf@T)Jc1AOo{()9?<4+jNC|H} ziD7xZy-E!Srs_==JZnEzGw)-LI9`k8E|#3V*MAcA>Qo{49rJ!)=jl>-_$Y&u}k}C2JR%F1Lt3wjKi5PyJVHJ z(H${royXxxHT(N6iS^DxgzUG6Q%H^08D@7LwZ&6AId zm7g}y+bA25GEV7SLUIo5Dv^zwki%z${qCqVmbm|5zxg!r-(|W3$ZJ~%osT@u=EFHPb z#^p>{1N=d4k9L3jZ(zJ)1yfAW`U%5=op?*D3@w&0ev_?WHu)V$m!RuCQot0Qgv9Ncb2o4uX){k5}4qtinsD6-) z{@T4>d2|=!0kLgaN-NEX+z{U1jTE z^)cbqtEe+mkKf$ClUMz5|GB9s_a{6nr&{>vFN|M(65~<8`-WrQ`0F|bGDKwYH= z(R|_NhiZvKuYVKIu9fN_kVmB0)Hf7g%#ryt>g8{~^dn>vpY^wwnU~S&`DGTR=_0~o ztxxET`q|f^9mf=RfNyHGL6cqz`!|GNob>6Zd+#}J#Mh)`-0oVr5yetwk`U;yNK71k zwT&zTqZJ|Bki^RdfiFE>l1)tZ;-9+>{7g#A#`szy`OT91Z zgQ@&@4z-UlirYDYBa?R-vi;J^!Hvz65#M`2Bu^w3R*jIKCU2D+c-|(%QW@A1n6&Rq z?D>sjY~Q3sX5+GS2i<0O_Wg}y^cJ+naLfw2HYm*L>?LKken-SLReS0ouJ>F|0&;fZ zSAu*F4mg}(Z{KW5S(VeOMOF@jL1mT!Qc!&Y(AAh6y)OCHNcs3adR|1N5tC{4NUw2$i^<_7>^> z60rwi?Z!Iwko4WQ21iQiv-U~}Gcr^HgM^&TQwe){ z=-#xlvsgr=?$i1t(z(gpl@vTpxn<`h%o9HjyVbz{F8=ULX_2yO#|H+v0npM98%OhC zZ7K&CiT6B-yzf{IYwRm4HD?c?6lGlbarO zJE>!;?E%Yo2)npRLHlFjC=n;NKTuLqo`D}DP`p`5dH7;kQBzf@gp##-oyLV^A9B!p zTX~A{jZw-7Sf2Md7s#2K6?$*pjuaD}cBHssfB|iow(Is}M|44WgvFzL#gb@OIn)1C z+OB)5{|k`-WyY7RhT>L*g-_KbF)kkMv=_~HgO<7?1c;eyfj`GT#KrM69CxN3o1o(4 zdVlLNoO9A`HINH)d0sgz8$xq(P?$fcYJvj=*_auQ+ky2g1@KRd#k$_Af^%?M0ehZL zW{z51smE!S3@~1Uj2*DHrIMDEbiAq5Fml~Eod=51;$50=Rzr)h9{v80G$FO1gKgTM zv9(zX%#u{Z%+@iV{$TC)Otgu{FeD!?LV?30+$!$&Mhn_Hr!jYOuA30SdY@JE@eAFl z2$xI_P2B!mDwE@~_&c|cljl0=$lQY#e~W98oQw^s%1%thj`;S!3~J#}z8j45cHL4% zvwH1^JlzoR%A}(97Pwb0fDh`$6;0w0L-d)w_Cnps{4<#sAe=R04q7QmSuBoD=yXLk zfZcCkeO6;kg+-Y;^?Tqv>RD!QyITX@N$kj98no=?mtUGnNgMwLXvjToOMGbw#bPSK zoyEdZ;S!+4tTyD)#Dc>tmA1tr(9D{SnkjB?d#;hJISU^P=8O^p7J=WTj*VkxRM~qz zNvsoB?u4kKezRca7o)tgPxP5dRau3S_BFgCY#Kw=T}1AX46sy6I|DQmhRpmIca>W; zd(g61J_cutz#wX@c~XfE4WZ%+?kfY+;1Ix>VTm3Te8&n7<_+ zaAN*|JNJrZp|Vp23m^-h9{!8|9@g_0Y31__pX}1Y>dOZ(;EcjH`G+t4gmCKL+;4ta zt#7X8?qi%BlbOB*?{WF$f(X~#ZS@`_T$`g{)aOZ(Kd<1_vsv`g*OyW8l;57#8Gw>U zyF8S56V$Ue)I(Ird)0pj-}*%Y@DAo8l*H_fMRsI%J5v0R(@BgCc>L`EP(~(o_UR)Z zgb)$q2C|jsu6w7?!w=5QiY4lwR@8C}@0ho30fWO|HgyEUw;smL_wKFFp@D;zH6Hhx zRpG7!KrId_mhrfc_J8s?hcm|q3V>Q%x`evNPrnu80zZMQ@4Ke9VFbBeHEQQ1?gLw^ zLvsp_(WV5=kKzR3#78Fv%~p47(BqorT@B48N7=+R7kF6|%~J~8)f5b$IbBP!6qiGs9;bO{v49H_&F zV%{pELBr-Mnh-pH?H&@-&|!gyC~Wx4iVLIcTrE z>IAciU!;_i8~n+})9OIR^U_2Yyku%WJZ|M?fs3XI&>)Mp&P=MNn%~=7V192wPOQym z|AzdG>_iBdZhVZsV690g#SfVypg0m3vk?zp2}Hb175*M!$Fym-^-P$6;|Wf{86Bh5 z(3bS1PUdJrBt(#@eA*rExYT3dR%*AvG3h+e4yIwdW|7^_xX$h;D3k_`%V&6Lg%dp3 zP>|N7ph63FJfroq91wACc;%0+pFMC->`4)Ao;d|PQ=w^i@K?C0B8s0%D=cn|`hO+^ zYy2+Xrk+P^S;BOwM+^rs0&LHBdjT_-&7NSry?-E_xvPihgeea>$Ldi^T$GC4eybBe z=!RSibz)n(9UI_o+UGww18_WFT7xpF+F)G}LG|;oC1FI_mZkkv<}iC z18Ug|*=IG(;Q0r>2DoMo3#4)x|I$y^tp30Qt`{=?0T~6`Z8zySJ)Y|213x8pt;4E3 z*?l>ZQoe9&KF4{_yZS{_*u$`5gLPIVl-y;uHuDzxCTue*<9B2A-$t zakH__7%438H^}M8l?=uUUw^Xi31Iv=C(RO3|@i-xt^hm7WOe)OZN$ro6%!C{Ai zSQ(qG?e-l^oK-ubS;7M4!z#`4zkU;MlM^xQO^xY*0vp6@F>#Mnp&uTZ`rna^Q==rg zreub^`ngVxDq$&Z!|H0gPf#3L$^9jgehJ2wwLmL*k-XqP>p$X6mzdyzb`s@8VyAkS zY}2vM7L+^b2`7Uw0U2#0zi&lEqovE5Mn_tT8 za9d%?45sE|l})F^{t_2LxX##)(T0ViH_21`7LYJ5b8PS}SDE8(NN`1$uSH& zERb0Pfe0s}`r_4=R}mhqH1h`@Z)Zyy|F(A~H{a9oMQO!>&^|y~1J!liehvifYa8P) z2pEcda!4q2J>#JSPd5<-7*`rm?~#tEq{2-7hMv(Kt+~ES&j-EnprcDVdV&gXXbr#N z!cg9y5qv9a@zR~a$_6SzJU?0*Se$MJ_Fy^TK6>eee%Od&&w?RRnx47Hm&5ynd+xJVa98T zb-MPL;pgO=4Ko*j26O&?h$SEq3U#2j>Uhm6W+&;XyL9H7XrE%Er{OU#v`f zW~Fs|fy@&Hty^vOVAT)QX#F_?VYii4pV_*Z%J)%ScZZHab)9E05VTAqEcpu`3i_fC zJGpw5Ic``Ij~Sz*Mh*$-Ye?*U8qg~dfd;YTQqANEC5+^C|HN|k%rO=iUHg+CcPT6Q zW%Q-{Ws(d;PWa$Pt~`WzY_CC`=GF0H_Djt0m4Wm15w6>`NoPtth-Lr95br_?qr;1; z8l7~T-;=yy z@vzoDe``xeC5{wENEXU>(ts=Bu%CFow-tTKToiZMp01EaVg&1ARIr@pOlq0o-0`(2 zH-Ww{Y2N{wtz}&GDw)Ntt!nM)IZ50%u{z2-+oS?6bp{=rOUi)Nd6&4ywDTR<_s|+DUZ;Xq20eX4(T(nuQ2vq&~F$P*Se$+6mkqt zH3pF7T*p6cIJk5;^)uZ$Ht<>Mtl`G-tOC(rP`N^z!x*NKl3c^Wp(h!ozc!KvmP|B+Rs?(C7t9}T6dun!h|aD0Y?)d&vkjuP z*|HYk0yPvu8CTKP)t1S`ttMs!W4)yO`&F5a& zosG#rrc{}knWL-o*LA?0VL^9@usp^bUlR-Daa8&jbgAk80*HGQM-d6!vh+bJf!9kL z0xn>y0`*w+Z=1%y{KqRaG9m5ZJ5v%*Wh#iumMh}+7NYF;zdF@U^9luF zxSUb>shM4UR9D#1>>I1x*S#5czWj2KXJ!4ixL-Uu-5|iomx<=}(lG-CW0=mf_dm%* zD}&0ZMeLoOErY%Un7*mU-ArscQlRiLZe65J^H{D80$`7prQu`%>%6wY92Jqb%+^kb za`jJBDDZGThvF~1h=`x^U4GSZ>*C$)<)DyMJ%~nXRDS?q2Qm62^OH!RX*g|!R52PD zy+!*fUS0bv`;g-+`ks>6@>~=NgqF4neaHU%In%F^B>U5^PL-+BQ1QS-TLy&ccerJz zAE9Zkc|j&2zZqgijXSZSWgPkBUZ$DiR_)}LSXgq0BWsz$t`__E!Vu4!_tui7`rDzK zULGT33Z4ypLpj4-Gqkjkefo%jPC&+aKLiU%zV#<{Hr1$&LkfMs1=^e`^Z zr+}|+Mul>~#LlJPGso?9D}HFl{(Dz3WRAI`kWboSlMTu7eHxDE+cIkJJ6J;hy$VVq zjOrgh-04Ac|Bt5OAhG@1sYf=e7q$>;G}}6vJ18MGUb(fDpF7$o7t1aiEiN}~3PC7_OOOb^RI!2@v&28UDEhCV zkFDHK^9An&$YwQR=vx$a3<9lCPv~Q>7 zoKKYBH(V~Mrp~J9e8Uy`yd%pba&;p+y(bebBXA(u(1(UhQ}MHuZL#P;S9{5V5>!m- zvN;XFhgN$T&StmQ0ud|N*a{{QKRxu5Uz zdnlSmOj+)j9~R?HB!ueAx3e;*+=QesOm5p0+j|D`$uUMbh%uBdx+k88lh~u>Za|X{ z`|YOWxUvk^{PifDEJZ6&Gl%<1GW=Dj?P(x~-H&yNpOegBLj0xuLEX~4l|WfoP3*Cy znzWSkN4H|3(^a!5zsMn5-dYlOS|`E?SaA3$JYnN`kXwWhe|T%4GK_<`|Ni_a+(l>6 zs#HzzYAT~ai^g9#0=Sd8C`Be~|2^Vz?OyE=QkFP;;CukTg&0SbkEd}wnV&pCXp>?w zM07kaXG<6ZkdQ)BtG_QGXzi)26M!}2< zkZ@-sRQ<*U5qh1z1owW-@*(SNTDh6Z!#ZNCJOh}qwi7lI`DuUj7)qxGi;a17fvfd= z@lYE`M%NUtDoEeXktQc(H{~7$Ns)Zrtu1~-5H3uk^7CPtRev5zx~&=mhRsc8v05SI z1kLMX;LQqbzou%MnX=tHYtqZhb5FIaFqfr{ofqqH{`@tlb`nTA?C_B>DJ5F;v{TAt zuc;Ftn~IA{(3w`2Yu_l>^)VR)8E)g~4%4!yPkZTtITDzRUSnvngy?^ixEs7WX+ywA zb5?=jpz`l~mDvLKmFB{zdFeLH4VkYJIkBw{>_O4N_LleEu4#ITmUqI=O*4q)ME*h? z?i%zx?__8a>f_(_Hok>6ofl#*}cV>nHio{nC-K z8RFvZK2evk`d7r^^ptfav}r8fffPv&^H)p5>^f6udxw+o3Q)%KaqM?e^zV9tg4^|w zOzr#9Pw67JfA_OoZhuZ{TaAq5j?I^U+JlLtc7$)Hz|7HZhwFXj?KRRfc7^oUex_lC zu?+WYDuAS&yGm_P{YzeBI~~WupfFRu#9_Ny$faZXItGA%r|aYUd(EDuG1%YPgi1sm zevztYD$v?4KZlwomP|{>epvK^#YSrn)T{?QX2^L*Y94#*FIb+FJr5N*8Vu>F7aB%l7WMBwW!wgo2a>ziRG^ zY8UUy?&jLCZcc8iY0VN-*=g|wGa#L^$gllwb}siGp2|!Gmvb+ac~@g@mY4x!^RaKb z-U1dJ8gme8%5>|gXN~awo|^#pWod@i^c79YAR+a1I5z(}0q;M7wEK6?(9S=kjgN+H zv9-d@Y~R_zgeKeRadPBV=h=6XzAw8&1IM8c>S=^}Fy9Tlt)Y?3?x{tRs7iA53?`+_gp&ZD0Gj zFcp0-_yVB_HtuJSZXD-CK0VhHk+)p+(%tFF*u=@8Nq)iqRXpskqrEAXki3ixIN|7- z>#USw7-6aXyu{2?IMt4q`eurwv1J(1!}fQUF5|`JQ|PQVTYWHV#e57uY$IRi<6?qW z8A9Os)MK4ONSUZGF)@Ghlj$NcmB%QL1aj#^#dn(;OS5C%h`-utxb6245G!FdP8670 zy)p6K!KRHRKnl?~b6>OA zul^-l2gzAZGEN=(nVZz4UuA^{}`t{`OxKqv}Na$``EkfpqMj%3gv` z=%E5lQ4H}>tr0t{Y!QMy8PSbZs>>#Dbvco@uZ>m-p`d%@u4r!W=BDl&=Mcr~0y;l+ z$y6mxOuDS|<1|e{K0M&S0@|$n>95>Cux2uWwn?X<|D9QDWPi9YHPeXK8tw|VK>c&x zZlt%iZvdag#;7AsdiDDMc#QbD2vDby3!Yl(53MjKII`G%G`2Ezbgtk@f0t;0)Kk~Na6XPkP=cj*4pu7IwuI6JeLnI~Nc&LMt&JE=xKB*%r z6QeHtOvL=OMh~KiAQUnZKXPzqjB0K#(N`UdSdDYydU~c@pTkKA_dU)LMB`W}h)5Z9 zFE6I*;ZlUc9LN$*a_(mx^p-s3)u~?Ffn11f!Hq*{N`$o`_8A+i?fTl*5}%1pC8F{P z3JMPm<)3=NuW*H7H9HqSljbPt+MQ%h=F&ugH@I&@rRBFplgT z2nY!1cef+H*P^C*>nSus9k%o(MHXCw1qSBNu^R7N^w4Rjgj*uoj0*4Jj@8aV-|!di zOud~|l+El!i-oR_&-czFx%F93u(&9})|YkTE}ETWYz(9pC^BilM6YKSm#IUe=fB!X zKA#{QE_K+OC|mh%io4MD7i)Ujv>q2@8kZKO@(yTn*)C*!QDIC;QLi+gW<5KTkclUK zD?c`-KD=1WKOJ$N(qnizc|0o-fq@g`W*lua-bPZ0f3rI40BxJo((-dy??@3&T|9=t z;Uioxf8lwg`@A1TQN{O5lLs5Yz;7cBEV%?=EbW-dYcwZNLa!#@#(-^85`~D@3|VG$ z)wlX=Z!Yy_OEqL3Qsmu~B=Z9Z;4>Ga>VlV|Dn-PCRw@-ehQnLZAQa#iSz>#Bn)IVI z9=++aw#LW-fXm~ISF>NOKotq9|N5|zNb}ix!LWfSVD4Ke=M4bxp!N$Tr|320VEQrW z^IQQ>uZ+-Gv8#&BNKF92O8mOTj7`Q%W9wSn?Q=`8t}_|t2R_oM*pE3%-(^s%37dGZ z!7r7Ma`9lJ^df07r%K%EOzCdf12?hw@@_WTnY+n@y)?c}Zy+9bXN`I7u;?Vr?i{;s zUhLA%iB+V&P(E+R=USF&srdTpolNX@1hXU)erCE($VzQeiCUiF70aB~;>}nBio9qm#7f(@YnG^UyYNMqH+iS{x`?eAp4J?*x-qf* z2`+40u3X5`aKH7c)K5ZwGD{HF$kE~4V#=1ruYAxNO=i(AWb!r{*tB7TF=ry}qsm0M zTHz@pF5DVwHZjj`if3kn$ELq5NgxG?{~IOhg+RkiPsY#Ld{ZIoN6h=qUGt(R0;8M} zR*Af)eGPMoxrA~-?Qj)#CWc(bI&blnyT+}lj-l6s$qez3%aF`~nWAVjrR`L;!yV3u z+l67byHg5O z0{bVDXf)LG4XGoeni=E78#32NQ%k!bJ2-zl0l(yQ8rD8MI}1SePX-jDUu1OGQDUN_ z-^b`23H^Jhs(d~=4AQi9ud|?6sdMfvDMhc#wX*|KlY4WrZ+`A{7WToYo85WVbU}~k zn{IxGt?_dD`AFEV<&f}^6E zIyDy}v7O3a5HT6=K+q;9lyuD+!Nu^EA3{p`G6bY+FS4z9zLmS<)t&~)C903Pgh`{J0l_B92Zw8s<;*8#izzmr6q z-&v;SFi)k@ItrXcE)MZR z4b*7Ho?gH!OZiSdr}lnue=vnU=KbYV^N>G{TnIHDr5_kZxnyvmAoG_caADCfZ0dGD z(0F>PI$~Yec`>(=$S}rn^Y^7a9Y3J*;oOC8e{t0JFOl=|{a zUCr(NTUSDS`U|Teny4aUnEv%7LHeT_6fD-mkpPJ%pu~bU8gm}az7HgKbKY*i8U}*s zZAfJT6?t80DQfcBo+s&PAamWlRQ3%MtTtl1UdO8S*uKO;I4U8y@}mwj)sgLoIguNG z1$I8fU{8K>`OhR26c3=${ND3nS>jYJs5A9v6@F`=&-W(`7;ZGQlytRRwaW<*ed|`> zElEC&L+LV?NZrB3X2he*X;z-e3MUl#_Z$1^e{@P5G#HNy?eE85G~xdmv;_-czi9#! zabfW>^70ndrP^9ck)+s6NW$Y6l^1z9f4>EXY-J0kEIKHbY|XDFpB&YlF$Bt7yEm| z9~w*_3d*&O|ErW(!FMO7-txa)P#ePhd8}4oeW`(d@S7xP+eENRj8Y;_0Q~oPF*9R` z0wIsE!KW&6FZeEw*f60VoEKc!UY_!iqob*=&iXEv&Re^RYFZ)nk+_ORb=fkSV>kc0@kGU{lmQx=(WVC;Lq`!-jVrY2c)(yv2Dz=4~EiI&@p1H{s!uP<5o#HTvCkw*-A&~bt$ZI zH$Wx)6k)5(qGJssHEjb|&CLQ5Z$M?=k z?-en4)7_PVC(M*Of0`UTHZ*}Jx`)HK&(aBYK^Mc?o{*I>*O@kFUinKlHF8o07w5ON zO0a}%&y|!%k67PGzI&@A#QZ%Y7g#;&Y?FkFw!$R|ur;sK%Q@~8$s;3q_`o)8E>Ka8 z{CE!Y9}2R(yyZ0MbF$fp`_p#v_kMNL2H&emrAv+{Yi;drZUhmDFpLQjA~U*08O2|t zqhSZv@F$E@G~LDxZw^s8%B&b1$qX|gWm!fEit08Mn$C=~$Gs_TrI28}F6 z&9cbDJJMYd>kW5DX^5g55uKMS(bTe=kIh;CBN&7sS>J<(*St5XwTdd&u|DC+R!};3 zZRHfh1+Wua=FIzB!$lJ%YlA@8K+_dk=TdX|-D#_{@4`~qh8brjg@?INKp)@_5Phfn zB(_)EU;E{be+%Y#9oM&Pua4+@nRHJ!+f0ig;W~*LadL5!R6hqPX7p0Y$6ysH-#ZDK zHBV{LOS->VMZ;33`Z~7*02AXV9N(mZ&mjW}5h} z%U$q@MM{o2jd!mP1jsZN9c_KqZ_ISFXyR7>z-eeQI|f#^V@#uPVfwZ6xcn?#Cx3Sp z1FiOdgO_%-lW8!dh~4g=7t`4)ZR9n>>!mhS5wsuBJxGzlI2rEspRue22ZL%W*+gM@ zGw^hDfVyz_(vX)n7xBvMeRX|D*$A-fu?km$L$*tPK8)5L&*ZAfy!)t}Y;j~d`8(fE*M!Q>tq3PVI02YW%~hle#mhkALMmw0~lq8-7% zlBC0;(^Woo9)VsrS}duo_N$FF*tX%R9#I3e8U)rn>YZ5EYMJcIk#ONOF9+VZKKHwz z0gb|_9>a!%VlxE9tGQ}Z?TvFPFpiJHw5W;Ot5koP`!k}p!P18r97(`e%=??e&O7(C zfVUhFk^JcWbDM`JF%}9IZgCDbyJs&F2PQJ0V#gxf=AuTmBQ57M?Rhw(#^R$~(-CixaqjEvQ8aMcKCh_3UjjvlYH58 zb5A_9_PB3VR{&*X>zzdV-pk4FwnjpzJn*+wck zQ%OlGJtk2cKlU`|33})o(Fl7J5|Oh$AF!+@eUn`r*P;bYPGw9Il%02Nl%Kle&i|eZ z%0Q0jn%EjLY(#7CbaSx~!3CRhtSG#KD(gK);E2;;)uNI3%@`sC3G6n=1grLdp`^Ur zKt5%{fY0(6SjlXYo6lR;GOyqvlUp<0pvjm^CKBR;!s{|z&MLPxk>d()YL0}Q$A7@x z2%p>J=P&I}1$%T(d>$B1rIXs7hxMIU;Y{{{a$Gb{i=u6y$9-yRC>xxSi0zjLm-EV4 zoLqIbt&vRawMav&AL8n)PVN8M5s^8h7GE5L7$!pzUxfRL81lCR>5QH5*2lk@QWODz z8*u&^M2IFC_Xh*uK-J~v*hj$7cGY@&jlD`9nZF^|OM3BMPc7Qt-}FuKpD3iptqP3? zp3osR>;8~snWF&t{W;2caiZYaQF!Lz?KLbJoZT%yjr+r=udc;*9f4D$+Yi>jm5`C! ziO3w?5g2$x?N{LL?s@Wvl@>>p;e}QcsKoeotbL>vLZgFz+V(U8ZuEakQrVv%H=;x% zx3K(Q=YZIGo(nF1*}CW zg5dX{RtHDiqP9y@3(T)g-nNM>uw~wpa^kryjhlf&zhi5y5p%Zq=;tB2p62=D27ew8 zsh04emzOg7d|$Rzhc$Ao6eXy|e0`lKiB3)oe54v3-e}w}ZmD0y5Zl9G9aIj`7&L=UF zP9*O6^br(&>tq9znS$ME%vo>PXZd4o;DsO|IYp6N)&GMwqlaO${PFQeS+Wli6vdLX7JV;|ByZX@U1bT;a4~=?YV!8=64}j z)L@XtS~y-w?$Px;JA8}iOUzzpk*a@rv+{PKlFzRWU#1(dC&Tn8|Eaql()kySeyHwS z!eSApDO^n9y(pJTZdN}eL}@t_YP!2~mc+$u57^xWcW0Vt_se@@Qo;L?=~W-d;oQ66 z4B@-waDZC`9Iq||RH`hDl0D!Qy-N!v#W8CA`30sAHDiEB=aQN5ak&awYYr!#eTL%r zS#{pGTyFVdOXJf0!Ak<(c2rK45+uP6YEA^~XC<1i5f{$6Q}Ll;j^_FbgyHbth8@H& zJ|1oyx+cO!p84;4H+*LOODdRr-0dr($vjcxDng;V5hjw#o-|B;*x94|bLWJgT}ODN z1UaI9pJJQA<@ayXBP?4Y4yHebWpvwIkh2e_iOB+~anZ^UJM*V;eXso32xERr-p}DC z-OZ#dq%t=g!jpmE3!0>OY%0|X!DFv8Yn7Ry<#y)y<@C&ZRiABBF70-Hw(xP6f-3vy zSlqa<%et6}!RAx2&}wdCgFZc+NAg~&t`lusm{j`N4l%rpMl4fN{EN%|g+qqE(0+}_ zf$BZvsAcvV7@$F?GJRYh=&mRzQZX`8(sNmSZ;#W0)iY0Ds_PrTbmkOHD{#jECI*6{6WWQp+(bdb! z0|a(dTmU@R1uT%JNVD+V4=Q9b_TeL$z8IaxpXQ|eRab^G?cjk&zz|=+xcH2ThKjb{ zVq#>)HXfx7p)(xI>RxniPD~|HhifNkQs=^;M|;u3Ln@&^$xD(DKz!>4CH<>p2k znGzlG1<{JS;{3^eoU^0LS-+v$qL(E}*#^s@YNnJU2e?@&e4k@(8YrnuWV=_RH`+G5 zr#H-KIIZeVQO2VTBKm^tPnE>QZ9g&=$f`ndWw4V~irZ#xp2#uEAlO*Bsm99d5|uw^ zc2tqez9MR5pOai*UYkV6rdE`ztjWad0TU2J^U?B9nEv_NZ%ifsY)^LWc*?zTiv}yN zz;v#WYV9uIn<7v@BxM=2@BSc0m(I$er8VsQt-vwkbG23ki-m!O*r9{+1IPh=Zh98L zbRr2xN+4fRT;Lbj=KqQ8*mHGVI6U5ZOTc0GYOe;d^I8}T5=3UPev!au&~Z*PH#mWg zcjB>dCf4zNmSe4Bd@1_wYL_$iCGUzTTr6fdBQu2e1bazX) zw4`(hNaqHmd(%iaNJ}@|*`9O0<9W_K_s_fkcsI|(UhmABSv9{|GmCOLf;eF8^Pn-x z1uY1*=DFWwX_3V|=okSN&Q-G`XO1@wvXHO@BK3??ix$i7a1yanK{9VTxls8<& zj7poAM_=^m{83pKkIwBX9B$9h`w;D}^4i%>F3I_#%3F{W)5d zp-6eN>dNK&>?Vkc>i(^iUcyw17-xD(E2zfyV2pksqB8Z^=;WaSO@KEjifX2; zHJ2YV$WQm?<$?p-!_gT(>t4zqk#UNRTM@nF%rcCN#4E?=?JTWV1**cZp!SxTRh&OS zey{-lN%MQQB!W(e5~QTgPQK4ELP z5nTU{Ar6*vUOa@kPWg)xYrmfO`@BI&8PROAwgp z$yE)Stv+ciZ<#lr_KMNI~`g~4w0uLKG9UR0%Ium(>tb3QgTZJ_=X zU||^vj$AkC;XmdL{`Upo6_N^mTfUaemTjBQ2YbL)1-Qk`euvxlrPjQYV{t%k8^|%5 zly#J6dn`7YZvJ7|ww4iKU+qrC$wVm*-Luylw?J&8@Rt=h=7lAIsHt(sYTj6qiXYvoDu@k;yUrmzoz>HqN8V zmjE_2nhBpRk|m3}_?eLzh{Bn~&h$zD?J~We{m2PfY@O+?dZcFIM54)C_)n>7cXE>%RCgCS!Sasp6G&^o`UkLlRrHR%x4I`gB6sECE(ir3W&`TT)~@y8Y< z6V48$&O?9*g^;am?OJEI#KMh1F{`YBE6VZYtMkrs?PD!7?!)Yf9LpP~eQ+S@kx*o8 z+B*)D4=aAQ?I8U^(5Ye_cH5?kK4meZ78`Wvr0|m=`@0+wQ3evuT~OFttc9~_Rq5!X zD+vmn8&6M$-HhbC&gZzj>)V}KXSdN~*xvs9wk!Q5mf>SsZ^KV`>M`OX49~ykseG$m z&!~DAJo{!RUoab1by78!Ix;oqTBuEn<&*q8`$SE=F!qD?TRhS6$VA3yzmJASWqpnC zWZ|XK;5_wiLywa6R^d@$|2|`nS94A9y~}I2XMWJ4rY{$g!m#%T^E#gzZHomgJsZjm zbn$Nk{X*8Vaz4DDyp6c_vBer8Vq&@(p$vbYda+FI12#HCl>QrMtBlVB+(I_aRL&=GciO#9X-}Bz#fEEi6mHR&Op1=b4c(PVQWj*b~Wmjt?bnS(S+Y2Xa zB$*EJ&CQD*CoQXb-x8SFeN?^4o?245gNn!NEBCG(wwQ+x(ZXc&Ia1VQUC`$`Nudjr z5^FPpf-&m3$9;q~2S?`JpumvaO7amStsOkc00I~(@w;P&jh3TV8anbiF$M?xP4)3utO7!aP zUQuj!R=;tMVVk70p3d^E2P4PWs}xDGB~VYv*c@79c4C^3&MMtkkJiyl8GZB1Y-nl3 z-qKYuuOrYd^EArUK^eZ4Ly$m#AN1|lC%%cVC7*+db>7Zg{yKHY$#%*=3|tnvE*r6* z|H*hPX7U2X;5;e#8F@2r7u|lz+R>F^oC8y_CpVIeg%;Q6JSWhx#|47JIA@c!e5c0* z{>x^&kd9C~@@A(t)b7XfJ<%w9gdcSBKacdHW>dTD97OvvYe!dleb6PpxYYU(wiKeN z+E>!|09EvPY{CaD_VRnew;Lf8z*U6$NsQpe&Z#`2-Mx@nj3EWP}!7CPVaFk+@5#`xyK-cOMp^Q9&HS3gLe zy?k=f|4C{|r*3~tz|zI<0LzD!Aj)!w*`#8%JPaiPb6f=FL8T*A;Z@tPd6k>=W6YNI z5}`9oo#{g5!Sz9n1Tnve#`G)=vqe(%e?%v(`^<%L;f)4aqi05?JG` zAkn&p1G9j0Xs&`A^A?%Jnz=pWMYS9fhK92f4opLH}* zq{8Xg=t;wt{FAndYYJZCEwMBidR#H>wg=fIy z-3`3TYCd8D(-~e4Iq{A!Q=vMc1} z#@q<`A!q7tY3d-)#X1z>nq~Nh*gRq-w58!om%BWb@I9=8+UF2tPF9Z4zS?Py1enM& zgF;9(HhmQ4-QIfHY(b3hShQ9w=1_&;&ZT(9XBE>gJf|*q7a+MFp>Ya(m+d^KGj6K_ z_}23!uto0iq{3U?1j5x0!i0=@3&urA&Y1wcSrTL<1!8K8D_dwSNCHlBxLq$7zVAka{E+?HV<2=7B4mNbrXa9t}T=QVuUJr zkpM+4U+~*7)rKN57`Ix}(ns?y-QB+BPiM*=^RBt8=WgUlJkNQ)3SIPC3MCr-3aZ7t z^k?7fA7kMgStgG_2KIw?A*}nx_URTyiJss0zX-OH1!@_qj1+7)%%-Pv*UFMnq8%-X z&KB2%=dD{!+0|t$#CeHTJ-)z}E{#L975L&&MZC~INy~^#L*dbPGE!~dDe5*EO?Iz^ zH`s$gz$5-Bp?Py0S70E7GJ%4iRN`fx-IJc)ldT_J7$Dl( zn0GP%RTtZ-bad02E2Gag@T$GW!}YZRLZ4iDgbfCR9iuH|M9RNpZ+^e=(M{gFk9di; zqtq<4_q4;10sBp@Sg7qTE&g|97YAqa-l!b?T*+QKZ?E6RaIRGxyC#C0L1$aGB_--;278s#Qg$ z>7cmDR~8iUs6yY9lfBdCD~*?paTrz9(-%CRCvaEe^?Sipm~d?4ujL7;lmoib z6s$YEQfN|C6WKUdIX~ECNC?c)>Ml4uW`6t{AhFoq$K^V#^Za%Wr$ciXQcV~BdNon} zNjqGN8J$XW&>I~;kS=|8v1>%yAjF>8I#t|k^m3wvH`VADg=HcI7RQk4_Px61>YMeD zd6>ISokCUsUOSpzHBIh!eg27!lh!05^i{ecoe-;qvIT0ACc?8tWOF=ddv_31i#bmLSU*l!ii5E4@~z%mV8d<6^qGA|3Z0kyWE^i-+4b$%hw@&gX*WQH z&9F8#iyv3sjg91FNb80cA!2;nv8acCz|bfh*ByHSh%d9apP%Lob679$HGlO?>){=S z*`KpktBbeR$B#4LZ}WJR*8B<-yw%jU6_m|K!5oAzHWb3(?jJIxz42C-> zU2OGMyL9#WGG6w>p|Q06BL;hTgQ~#7s8U!6W9v_K*U5Z%F`puTuLPGw!`ho`Mb|{W z^lSpqzKH&0q~5Ju6rIw5@4;!C{&1_DxIC=kr)9u;C-hQ|EuXW|$@@5mVNSg~PkrDp z@|K%C$}_h4@P6vAQmL!ALDx2$OwZ z?d1%ID@*2Kb>N&rYQ=e!#C?-fri|~j^Ryc1aX7mC|37^qV!6J&Z#7lpn*|seH--(-g!1l2hXvY)Tx8wvKAqd zX{1hz`L`YK_phdn6-vrA&?;VQ2hA;_f% z$CV#Cm%-XTlyO-n`XPg5b~hNFAM+ycVN>I`0|9Nidh*&BWFTF5_cIv}GSw+`difYu zyANrtow)?7M&G+?ln7RKrjBn(?UZI8^DCl=wu@hqj22jlj=vQhxAGW&>#=6#ae{b? zp0F0O)5~b#ISAP7ZZcAYKFvc1tWrtzVh;d&>J}EED4T+m>oJ&5b^;BU-Md~sg8B<; zFLhe*>}`*J_U^pPe}eNJto-j{bu zcHF28gXf**lDe5Zn~U=7mfFuEgAurGR{V1%oAZ0RL`K2t^E%B3hpBw_wrOezrqHZ;h0Qz4i$5-3ja zXH6CW;3hI9S;s}$J8U-uHZ(4|KwxvV%Mr2%qWXnb;ZE2fcB0#a6lQp@2XKrh$^l2( z2G%ZT5dJ~Pzyz71`?%tmF8A@rM2ovoWqz^Ml`5l2aw(!*V-TxH;3v#|_=6VJ>)E|D z_WV5kJb^uP-d|m8k2N3BWJ9b(?b4ClzAgs3g;bi^D-{8ILW<{ml5S*f+ut!Rjlq$M zN-!5g<2|ZLz^8~FREwa|6Y>W)?+Rxv0{)mLsh_0-S#*-7vgM@Pkg&0 zmKH3+eaYC6%vXqi9tXrm@Y!I{1QVj?DoQhuc7qk%+`MK@zPX2EAX7O6NL`MIY$W+X z)(gH!r7tJ31=j?q98-n6qab?8|NiwMP})$mBuu2xM6SHX4lP(|e>EM!db#3)!6 zdvqs0T6ZFVD1lJN>)9x!>f98!Cv36}OIZtby`?8f^La^m!hj7kk5|4Jn3@>VJ5aJ6 zXLfJU#&c^?XvM0IWj_BJ$6IVf9MDZg9>43Dz2lgp{lUtZp@jf7+9e=oa!~PD*He^r z0GkwHN>_#{6nUl&U~H4pzDmq`0~GWg2K3GgGs$5^u|-JOV-SRCO8%`BHO8#<(pyZb zZ0k77r#YQ9b7n63Q~}TIAEhFh1$QPC zupz{hV01^;0w=zWq-thiF%F*Pp-XJkE{56@jU2X;07uTM{S$;eZ)j{gN&EUJT64E> z87xf;b)QpvnMeX=kIGRi1jwB=Ow39L=)M#NMg-n%v5FJKkhb@TnZ$Nij0Hdb#i+39E7R=B zl5A24J_h(vP*>J5H&IgjrgqHBitzIz$BKB$eVZ~WuaB+tFCjrcv*fG4nk*8TCJNAJ zlIkyqbXPgVGx9s%*&q?o*S~||g-S?FE7{<$eKLcu;-xaQwC}^=u5Ej43wVrd20ThZ z1@*?lm{iC#8O-(Q#-uD>-9INXoviF1qj(HVkrWgtcOL{Cn$0|E;B?MJewl@3_>deblb>3>SX0}j)shv_r2Hcq{=!5#dAM2OmG?U(7i~!f&3(9ab$Un zrap;pW8tWQLi+4}t3p$0_GYM#Bp0NQDzp@Zm1Ybo7!i{|yfG7_@6W$DVp$aj+d*i9 z5jmobtebB(0fLsS8EPh0&$G#E*`q=HbLo25(!As+R+%~;2qYlP83|N;E3chxs9e1} zc-~Q@Q*pGI?v5TCjVSr55AjZmBK0YMeT>RlUWvhFnq&%=MEuldqB79d-&}9zXmCu6 zAoW=RrfGfYn=ImKcqH!^47ub>AcKgdbU^Fc(UCM85{Zf!Is9wA)gtr5t^S-hs^j#Z z<{~%gWmfHpl;qXKxgfL{pv#D*Vts$ylX%R&+9ZeHO2LyL*Lm$yfJBwZ+JPft^LOZx zM4x+A*T1uhk*J74MKa_K1bx6yMPS=`F2PJZ7@-Zb?GM6b9`W+5ADZ7)lR=>ZCIdZk zMSAQeAcXPV!+@vl;#SS(SDz}s21TPG(Q?IMB1_p6A@v)7HnlJs&D~gU>7s}avUTpSNVfXNJneHj(ZVH>BCi0Ocp;77Yz$2Q z@|_%|&`+H*1UE-j1#dAb6M6*#6G+7z=jBi@D9;eaG+s+*MKvsMEbZDWWH|&i|S5_+WXvhk@46NEz~P{%$DWU zF^#i3%1Uqvg|pC4PidE}D9fw=%tm{ptUkBu%S1q?O9YXvy2@mG$dR5HX; z5`qaPe8C;|c+8kd1=~nTJ|W0#uk>GTFu4~SvX_a14WVRbUuV{Sls{4{K4&p25UB!; zWC*Z1zw{8~Zhy;Axf+IC#ozM9drJ-x@&TM`sr~5yhx%$m+URhP;ZuVeliR>tL$n@Z zqBYmK|tXO8$s9r;5=wlNJg*;WNQ?0MdDlMK; z&+9X3jwqWhYFR)Ya)A+J(ND$x`LLs8#i94o0+I+sP#l?AfVoDjxo zQDR=ai`n0`Ebh`$K&Dv$RBEb4T1XD^kOA?IH$|dynN0G`_nA3rjHG#}iHJ#e&L@)O zp18RPi9#MycKkqU7GoN9CJpHiYRXs!=4?{Kqbs^a5*_kD6oV8(U+}jNq~A=g7twOj zv0ThKIoB5DN+U)%LEVe6e`8k|_?yPA|KS87vdBO{nzKyqLdUr$X2w<7@LmVZ?$P$o&5ag3CrG0fQwusfdC!CA^#@;r1~+J zx5SjYLK%T`g&x}7M?^2I(e?qOVO4IHvQ@(iF*5X?1KPaIfA~Oj;3y%qzQD>YaPN}z z6%V_Fs6_Lv@5)7311z^q1P25-3rh=Zln|{Ke>lPOHl2R5So0m`+AF&qlcw+~@?&BPjcyizKaL1FAx-~C{=iVWpI&rXi~iW@G68pIxP&U>LUKa>;RL-lD%sm>i@LP-gBbY#211?^ zLu6SH0&-pFvngrrtRPw@yZ6c6a6p@u**VX1+<#oUTt}t|qC17?1FHV83)nr9IW9iE zg|nsIgr6MHynjQ4>LrGd5&S@=uQR({JJ|WEWC5Ah8>euh`8n002dWAr5GisnEmZdj zpP~3r*?mj^igZWv%^e68()|=9Dm^wp4M8Xkc!DSe0zu3Y1R+-72?qLKPY`&3Kf&~X z5AZVoLGnKc|0Map6aLxOA1(e#_(xm+uTK7h2R{ zAKm-^KOnjvu88BW$2{o$0{Ot?(AkNr*%|8D{l#x!^B4Gnu(PsrGO_Y9vGOUia`UtD s^0RX?u(I;AvU)dZ?EVLVxuv0rk@Np1__eg82nZmr#ove(ztr{lKZI+IV*mgE literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/canada_flag.webp b/src/main/webapp/images/canada_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..3c1796a4d5549003e1bf527af864ea7e329c19bf GIT binary patch literal 10250 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 V9VVB17J&oenx_7h!pqhV{~ruGy!ZeB literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/france_flag.webp b/src/main/webapp/images/france_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..a1ab4fa2f8fe69ac2580c36d6c200982b3d12d0d GIT binary patch literal 2047 zcmeAS@N?(olHy`uVBq!ia0y~yU;#3jR0mS)j1~o>CE*|{2_Hx+xaS)F>iEd; zHr-b#>e=UFU|pwL;u=wsl30>zm0Xkxq!^40j7)S54Rwu-Lkx|qj7+VJ4YUmmtPBh; hUG;84(U6;;l9^VCTf^dx&vrl!44$rjF6*2UngCHa;9>v( literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/india_flag.webp b/src/main/webapp/images/india_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..1d6491268dfef5188c9d18419c8de16c7c75b722 GIT binary patch literal 25745 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 Na?tER;jbqz{~a%TX%+wg literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/japan_flag.webp b/src/main/webapp/images/japan_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..aa696ff6b0a5be85944cb6acc83cfa49a9394e3e GIT binary patch literal 6618 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 literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/south_africa_flag.webp b/src/main/webapp/images/south_africa_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..5bfb9f5e6505dfd5afb800c0748ab788373bc2f6 GIT binary patch literal 2988 zcmb_eX;4#F6n-Wz5cb5KMf1$KjR*t^Sc8Owh9ZMOKvYnwge8n4w16O}5sX?0r3xrw zD5%v!XIfbVX`t3x6|A(SL)DHTK?{gf1q4BmEzoyIEr3_%DB$wYuiM$LDD4;sngaS)_D(`cMe0yY-5(VvGP2UjA< zk>dz53ZNs;5hQ_uATL7@gegIgMKJ}}{5F7t2H#Bq9^29r{Z3{koxPfO>95^UKOhUf zKoY%}xp7S|pH5Crjy{%khV5wGU~eGYEWY{uxLiItKK{D!LL0}KB}r)M?#wQ*Gd$oq zS#9;CY#B%FI#Fenciz_cpy$NcSnoMW8{28L(sHD^sWW7|4MwUzy%3~DiAdr$laWeG zSsC3m&CO8gyXBkXTMJX=)l0Gp7$kH~QR3X#9H&zSc18z1}JGToBXBLf)%2U#7N#+?why707DZl@8rxVDb7w_-0rMmLm$=I!L zTAD)vGAGpAlWXw$QBgNA^y9sF9{SIX4be3pcyDm2LlA>HFD@q_skuk?B6q$ACAG~x zrU~W5G@IlU#nM`CnQ(rd+}mzQPv$0Ui->Uj$0p#$zb`(F6fpN*zuZ{b(0n4lH?Ktc zT>=(a_31Bem$O_F-TLyPTG&`9K_oUn=_@H>i4Bd+-Gou>MeJIXK)w2mICTQug2M2V zc}lmgH6TWdU~qvZ0dT8l8Y!u@+@e?O27+VhMYT`X$3G>~6eY2Pl^?1@% zdGPXZq}&-w#F4<$ug#b7Tii8Ra9`9t~ zXKbv(f^N3-N#(PuV2qNNAuhQ>B8uvQxlw(ZDHUafk4%H$8@Pd2i7QcPgTpeVbSiO| zwK}m{5PDyxArEhXqA4;k&Kfl5=>3E1WVRi$-Wyd;jfXHw`PRn6nC-M7s&}3br#G7V zV^Z>~3|TdtuJ*aAWuTt8s2ug2YEGQs7$`#RrfHybY1+&|VC%4JhbTH*L%oB<6!k?3sfgowL7ACOoExq$6D77Jlqv(in!piOWU(K3I*n5ov;TLkt`z>?niMYz_J_}hlI|!Z!S;ebgF0ZvA@C;pm#;Mj?Y_dG zG^Tacw8P?zVA*R;m8h_F8n`@bAo^`=FN;+i0Y=Eu5k$@~m=Yd1Tdgy#syTi%q?*gD z+Y@6nMkc;umm(fYrE7x1RAyWiNG4X2=x+z zZ{PV_#h4p2S*!w z2OE1v0K<{#=)iPhSTh(*24mE<)>|te`m^vof&=dk$OsX>1p$bchYz>ZJ>=+r@3R0y literal 0 HcmV?d00001 diff --git a/src/main/webapp/images/ukraine_flag.webp b/src/main/webapp/images/ukraine_flag.webp new file mode 100644 index 0000000000000000000000000000000000000000..0c62225c122d9a30283d6b1d0cee8a4230b15bfe GIT binary patch literal 1433 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
OL#gyHT-dV)fyQSycR`&ZVzcK1dk-K$*u5v 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 - -

<%= "Hello World!" %>

- - diff --git a/src/main/webapp/logic.jsp b/src/main/webapp/logic.jsp new file mode 100644 index 0000000..8ac6275 --- /dev/null +++ b/src/main/webapp/logic.jsp @@ -0,0 +1,88 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + + + + + + + Впізнай країну за прапором + + + + + + + + + + +
+
+

Впізнай країну за прапором

+ +

Питання: ${questionIndex} / ${totalQuestionsCount}

+
+
+ + + +
+ + + + Flag of ${question.description} + +
+ +
+ +
+
+
+
+
+ + + + + + +
+
+
+ +
+ +

Немає даних для відображення

+
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/result.jsp b/src/main/webapp/result.jsp new file mode 100644 index 0000000..22a7e6e --- /dev/null +++ b/src/main/webapp/result.jsp @@ -0,0 +1,87 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> + + + + + + + Впізнай країну за прапором + + + + + + + +
+

Результат

+ + + + + + + Flag of ${question.description} + +
+ + + + + + + + + + + + + + + + +
+
+ ${fn:escapeXml(check.choice)} +
+ + Ваш вибір + + + + Правильний + + + + Неправильний + +
+
+
+
+
+
+
+
+
+ +

Немає даних для відображення

+
+
+
+
+ +
+
+
+ + \ No newline at end of file diff --git a/src/main/webapp/start.jsp b/src/main/webapp/start.jsp new file mode 100644 index 0000000..112beee --- /dev/null +++ b/src/main/webapp/start.jsp @@ -0,0 +1,29 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + Впізнай країну за прапором + + + + + +
+

Впізнай країну за прапором

+
+

Перевір свої знання географії!

+

Цей тест покаже, наскільки добре ти розпізнаєш прапори країн світу. + У кожному запитанні буде зображення прапора — обери правильну назву країни з кількох варіантів.

+

Результати з’являться наприкінці тесту.

+
+
+<%-- Який метод викликати під час переходу на інший сервлет get чи post--%> +
+ +
+
+
+ + diff --git a/src/main/webapp/static/styles_logic.css b/src/main/webapp/static/styles_logic.css new file mode 100644 index 0000000..d3cd550 --- /dev/null +++ b/src/main/webapp/static/styles_logic.css @@ -0,0 +1,33 @@ +body, html { + height: 100%; + margin: 0; +} +.full-screen-color { + min-height: 100vh; + background-color: #81674d; + color: white; + display: flex; + flex-direction: column; + justify-content: center; + padding: 2rem; + font-size: 1.25rem; +} +img.object-fit-fill.border.rounded { + object-fit: cover; + border: 2px solid #dee2e6; + border-radius: 12px; + width: auto; + max-width: 300px; + height: auto; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} +h1 { + font-size: 2.5rem; +} +.form-check-label { + font-size: 1.2rem; +} +.btn { + font-size: 1.2rem; + padding: 0.6rem 2rem; +} \ No newline at end of file diff --git a/src/main/webapp/static/styles_result.css b/src/main/webapp/static/styles_result.css new file mode 100644 index 0000000..d2527ff --- /dev/null +++ b/src/main/webapp/static/styles_result.css @@ -0,0 +1,23 @@ +.full-screen-color { + min-height: 100vh; + background-color: #81674d; + color: white; + display: flex; + flex-direction: column; + justify-content: center; + padding: 2rem; + font-size: 1.25rem; +} +img.object-fit-fill.border.rounded { + object-fit: cover; + border: 2px solid #dee2e6; + border-radius: 12px; + width: auto; + max-width: 300px; + height: auto; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); +} +.btn { + font-size: 1.2rem; + padding: 0.6rem 2rem; +} \ No newline at end of file diff --git a/src/main/webapp/static/styles_start.css b/src/main/webapp/static/styles_start.css new file mode 100644 index 0000000..69a357c --- /dev/null +++ b/src/main/webapp/static/styles_start.css @@ -0,0 +1,24 @@ +body, html { + height: 100%; + margin: 0; +} +.full-screen-color { + min-height: 100vh; + background-color: #81674d; + color: white; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + padding: 2rem; +} +h1 { + font-size: 3rem; +} +p { + font-size: 1.5rem; +} +.btn { + font-size: 1.2rem; + padding: 0.6rem 2rem; +} \ No newline at end of file diff --git a/src/test/java/quiz/command/RedoCommandTest.java b/src/test/java/quiz/command/RedoCommandTest.java new file mode 100644 index 0000000..0abd95a --- /dev/null +++ b/src/test/java/quiz/command/RedoCommandTest.java @@ -0,0 +1,40 @@ +package quiz.command; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import quiz.history.QuestionsHistoryManager; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class RedoCommandTest { + + private QuestionsHistoryManager mockHistoryManager; + private RedoCommand redoCommand; + + @BeforeEach + void setUp() { + mockHistoryManager = mock(QuestionsHistoryManager.class); + redoCommand = new RedoCommand(mockHistoryManager); + } + + @Test + void testConstructor_shouldInitializeWithValidManager() { + assertNotNull(redoCommand, "RedoCommand should be properly initialized"); + } + + @Test + void testConstructor_withNullManager_shouldThrowException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new RedoCommand(null); + }); + assertEquals("Memento cannot be null", exception.getMessage(), "Should throw exception for null memento"); + } + + @Test + void testExecute_shouldCallRestore() { + redoCommand.execute(); + + verify(mockHistoryManager, times(1)).backup(); + } +} diff --git a/src/test/java/quiz/command/UndoCommandTest.java b/src/test/java/quiz/command/UndoCommandTest.java new file mode 100644 index 0000000..72422df --- /dev/null +++ b/src/test/java/quiz/command/UndoCommandTest.java @@ -0,0 +1,40 @@ +package quiz.command; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import quiz.history.QuestionsHistoryManager; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class UndoCommandTest { + + private QuestionsHistoryManager mockHistoryManager; + private UndoCommand undoCommand; + + @BeforeEach + void setUp() { + mockHistoryManager = mock(QuestionsHistoryManager.class); + undoCommand = new UndoCommand(mockHistoryManager); + } + + @Test + void testConstructor_shouldInitializeWithValidManager() { + assertNotNull(undoCommand, "UndoCommand should be properly initialized"); + } + + @Test + void testConstructor_withNullManager_shouldThrowException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new UndoCommand(null); + }); + assertEquals("Memento cannot be null", exception.getMessage(), "Should throw exception for null memento"); + } + + @Test + void testExecute_shouldCallBackup() { + undoCommand.execute(); + + verify(mockHistoryManager, times(1)).restore(); + } +} diff --git a/src/test/java/quiz/deserializer/DeserializerBaseTest.java b/src/test/java/quiz/deserializer/DeserializerBaseTest.java new file mode 100644 index 0000000..f06e8ef --- /dev/null +++ b/src/test/java/quiz/deserializer/DeserializerBaseTest.java @@ -0,0 +1,155 @@ +package quiz.deserializer; + +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class DeserializerBaseTest { + + private DeserializerBase createStubDeserializer(T returnValue) { + return new DeserializerBase<>() { + @Override + public T deserializeFromFile(String filePath, Class clazz) { + return returnValue; + } + }; + } + + @Test + void givenNullFilePath_whenValidate_thenThrowException() { + DeserializerBase deserializer = createStubDeserializer(null); + + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath(null)); + assertDoesNotThrow(() -> deserializer.validateFilePath("valid/path.json")); + } + + @Test + void givenEmptyOrBlankFilePath_whenValidate_thenThrowException() { + DeserializerBase deserializer = createStubDeserializer(null); + + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath("")); + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath(" ")); + assertDoesNotThrow(() -> deserializer.validateFilePath("valid/path.json")); + } + + @Test + void givenBlankFilePath_whenValidate_thenThrowException() { + DeserializerBase deserializer = createStubDeserializer(null); + + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath(" ")); + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath("")); + assertThrows(IllegalArgumentException.class, () -> deserializer.validateFilePath(" \t ")); + } + + @Test + void givenNullClass_whenValidate_thenThrowException() { + DeserializerBase deserializer = createStubDeserializer(null); + + assertThrows(IllegalArgumentException.class, () -> deserializer.validateClass(null)); + assertDoesNotThrow(() -> deserializer.validateClass(String.class)); + } + + @Test + void givenInterfaceClass_whenValidate_thenThrowException() { + interface TestInterface {} + + DeserializerBase deserializer = createStubDeserializer(null); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> deserializer.validateClass(TestInterface.class)); + assertEquals("Target class cannot be an interface", exception.getMessage()); + } + + @Test + void givenAbstractClass_whenValidate_thenThrowException() { + abstract class TestAbstract {} + + DeserializerBase deserializer = createStubDeserializer(null); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, + () -> deserializer.validateClass(TestAbstract.class)); + assertEquals("Target class cannot be abstract", exception.getMessage()); + } + + @Test + void givenValidResource_whenLoadFromClasspath_thenReturnInputStream() { + // Arrange + ClassLoader mockClassLoader = mock(ClassLoader.class); + InputStream mockInputStream = mock(InputStream.class); + + try (MockedStatic threadMock = mockStatic(Thread.class)) { + threadMock.when(Thread::currentThread).thenReturn(Thread.currentThread()); + when(Thread.currentThread().getContextClassLoader()).thenReturn(mockClassLoader); + when(mockClassLoader.getResourceAsStream("valid/resource.txt")).thenReturn(mockInputStream); + + DeserializerBase deserializer = createStubDeserializer(null); + + // Act + InputStream result = deserializer.loadFromClasspath("valid/resource.txt"); + + // Assert + assertNotNull(result); + assertSame(mockInputStream, result); + verify(mockClassLoader).getResourceAsStream("valid/resource.txt"); + } + } + + @Test + void givenInvalidResource_whenLoadFromClasspath_thenThrowException() { + try (MockedStatic threadMock = mockStatic(Thread.class)) { + Thread mockThread = mock(Thread.class); + ClassLoader mockClassLoader = mock(ClassLoader.class); + + threadMock.when(Thread::currentThread).thenReturn(mockThread); + when(mockThread.getContextClassLoader()).thenReturn(mockClassLoader); + when(mockClassLoader.getResourceAsStream("invalid/resource.txt")).thenReturn(null); + + DeserializerBase deserializer = createStubDeserializer(null); + + IllegalStateException exception = assertThrows(IllegalStateException.class, + () -> deserializer.loadFromClasspath("invalid/resource.txt")); + + assertEquals("Resource not found in classpath: invalid/resource.txt", exception.getMessage()); + verify(mockClassLoader).getResourceAsStream("invalid/resource.txt"); + } + } + + @Test + void givenValidResource_whenLoadFromFileSystem_thenReturnInputStream() { + try (MockedStatic filesMock = mockStatic(Files.class); + MockedStatic pathMock = mockStatic(Path.class)) { + + // Arrange + Path mockPath = mock(Path.class); + Path normalizedPath = mock(Path.class); + InputStream mockInputStream = mock(InputStream.class); + + pathMock.when(() -> Path.of("valid/resource.txt")).thenReturn(mockPath); + when(mockPath.normalize()).thenReturn(normalizedPath); + + filesMock.when(() -> Files.exists(normalizedPath)).thenReturn(true); + filesMock.when(() -> Files.isReadable(normalizedPath)).thenReturn(true); + filesMock.when(() -> Files.newInputStream(normalizedPath)).thenReturn(mockInputStream); + + DeserializerBase deserializer = createStubDeserializer(null); + + assertDoesNotThrow(() -> { + try (InputStream result = deserializer.loadFromFileSystem("valid/resource.txt")) { + assertNotNull(result); + assertSame(mockInputStream, result); + } + }); + + // Verify + filesMock.verify(() -> Files.exists(normalizedPath)); + filesMock.verify(() -> Files.isReadable(normalizedPath)); + filesMock.verify(() -> Files.newInputStream(normalizedPath)); + } + } +} diff --git a/src/test/java/quiz/deserializer/DeserializerObjectFactoryTest.java b/src/test/java/quiz/deserializer/DeserializerObjectFactoryTest.java new file mode 100644 index 0000000..6e60c12 --- /dev/null +++ b/src/test/java/quiz/deserializer/DeserializerObjectFactoryTest.java @@ -0,0 +1,67 @@ +package quiz.deserializer; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; +import org.junit.jupiter.params.provider.NullSource; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.junit.jupiter.api.Assertions.*; + +class DeserializerObjectFactoryTest { + + private DeserializerObjectFactory factory; + + @BeforeEach + void setUp() { + factory = new DeserializerObjectFactory(); + } + + @ParameterizedTest + @NullAndEmptySource + void shouldThrowWhenFilePathIsNullOrEmpty(String filePath) { + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> factory.deserializerAndCreateObject(filePath, Object.class) + ); + assertEquals("File path cannot be null or blank.", exception.getMessage()); + } + + @ParameterizedTest + @NullSource + void shouldThrowWhenClassIsNull(Class clazz) { + String filePath = "test.json"; + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> factory.deserializerAndCreateObject(filePath, clazz) + ); + assertEquals("Target class cannot be null", exception.getMessage()); + } + + @ParameterizedTest + @ValueSource(strings = { + "test.xml", + "test.doc", + "test.txt", + "test.yaml", + "test.yml", + "test.csv", + "test.ini", + "test.exe", + "test.bin", + "test", + "test.", + "test.json.backup", + "testjson", + "test.jsonn", + "TEST.JSON", + "тест.json" + }) + void shouldThrowWhenFilePathHasUnsupportedExtension(String filePath) { + IllegalArgumentException exception = assertThrows( + IllegalArgumentException.class, + () -> factory.deserializerAndCreateObject(filePath, Object.class) + ); + assertEquals("Only JSON format is supported.", exception.getMessage()); + } +} diff --git a/src/test/java/quiz/deserializer/json/DeserializerJSONObjectMapperTest.java b/src/test/java/quiz/deserializer/json/DeserializerJSONObjectMapperTest.java new file mode 100644 index 0000000..1bf62d1 --- /dev/null +++ b/src/test/java/quiz/deserializer/json/DeserializerJSONObjectMapperTest.java @@ -0,0 +1,82 @@ +package quiz.deserializer.json; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Objects; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +class DeserializerJSONObjectMapperTest { + + @Test + void testDeserializeFromFile_withMockedMapperAndRealInputStream() throws IOException { + String json = "{\"name\":\"Charlie\",\"age\":40}"; + + try (InputStream realStream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8))) { + ObjectMapper mockMapper = mock(ObjectMapper.class); + Person expected = new Person("Charlie", 40); + + when(mockMapper.readValue(any(InputStream.class), eq(Person.class))).thenReturn(expected); + + DeserializerJSONObjectMapper deserializer = new DeserializerJSONObjectMapper<>(mockMapper) { + @Override + protected InputStream loadResourceAsStream(String path) { + return realStream; + } + }; + + Person actual = deserializer.deserializeFromFile("dummy.json", Person.class); + + assertEquals(expected, actual); + verify(mockMapper).readValue(any(InputStream.class), eq(Person.class)); + } + } + + private static class Person { + private String name; + private int age; + + public Person() {} + + public Person(String name, int age) { + this.name = name; + this.age = age; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Person person)) return false; + return age == person.age && Objects.equals(name, person.name); + } + + @Override + public int hashCode() { + return Objects.hash(name, age); + } + } +} \ No newline at end of file diff --git a/src/test/java/quiz/editor/EditorTest.java b/src/test/java/quiz/editor/EditorTest.java new file mode 100644 index 0000000..478dd45 --- /dev/null +++ b/src/test/java/quiz/editor/EditorTest.java @@ -0,0 +1,100 @@ +package quiz.editor; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import quiz.history.QuestionsHistoryManager; +import quiz.scenarios.Question; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class EditorTest { + + private QuestionsHistoryManager mockHistoryManager; + private Editor editor; + + @BeforeEach + void setUp() { + mockHistoryManager = mock(QuestionsHistoryManager.class); + editor = new Editor(mockHistoryManager); + } + + @Test + void testConstructor_shouldInitializeWithValidHistoryManager() { + assertNotNull(editor, "Editor should be properly initialized"); + } + + @Test + void testConstructor_withNullHistoryManager_shouldThrowException() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Editor(null); + }); + assertEquals("Memento cannot be null", exception.getMessage(), "Should throw exception for null memento"); + } + + @Test + void testGetNextObject_shouldReturnNextQuestion() { + Question mockQuestion = mock(Question.class); + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of(mockQuestion)); + + Optional result = editor.getNextObject(); + + assertTrue(result.isPresent(), "Next question should be present"); + assertEquals(mockQuestion, result.get(), "Returned question should match the mock"); + } + + @Test + void testGetNextObject_shouldReturnEmptyIfOutOfBounds() { + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of()); + + Optional result = editor.getNextObject(); + + assertFalse(result.isPresent(), "Next question should be empty if out of bounds"); + } + + @Test + void testGetPreviousObject_shouldReturnPreviousQuestion() { + Question mockQuestion = mock(Question.class); + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of(mockQuestion)); + + Optional result = editor.getPreviousObject(); + + assertTrue(result.isPresent(), "Previous question should be present"); + assertEquals(mockQuestion, result.get(), "Returned question should match the mock"); + } + + @Test + void testGetPreviousObject_shouldReturnEmptyIfOutOfBounds() { + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of()); + + Optional result = editor.getPreviousObject(); + + assertFalse(result.isPresent(), "Previous question should be empty if out of bounds"); + } + + @Test + void testGetCurrentObject_shouldReturnCurrentQuestion() { + Question mockQuestion = mock(Question.class); + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of(mockQuestion)); + + Optional result = editor.getCurrentObject(); + + assertTrue(result.isPresent(), "Current question should be present"); + assertEquals(mockQuestion, result.get(), "Returned question should match the mock"); + } + + @Test + void testGetAllObjects_shouldReturnAllQuestions() { + Question mockQuestion = mock(Question.class); + when(mockHistoryManager.getAllQuestions()).thenReturn(List.of(mockQuestion)); + + List result = editor.getAllObjects(); + + assertNotNull(result, "List of questions should not be null"); + assertEquals(1, result.size(), "The list should contain one question"); + assertEquals(mockQuestion, result.get(0), "The question in the list should match the mock"); + } +} diff --git a/src/test/java/quiz/history/HistoryTest.java b/src/test/java/quiz/history/HistoryTest.java new file mode 100644 index 0000000..2101bf9 --- /dev/null +++ b/src/test/java/quiz/history/HistoryTest.java @@ -0,0 +1,66 @@ +package quiz.history; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class HistoryTest { + + private History history; + private Memento mockMemento; + + @BeforeEach + void setUp() { + history = new History(); + mockMemento = mock(Memento.class); + } + + @Test + void save_shouldStoreMemento() { + history.save(mockMemento); + Optional restored = history.restore(); + + assertTrue(restored.isPresent(), "Memento should be present after save"); + assertEquals(mockMemento, restored.get(), "Restored memento should match the one saved"); + } + + @Test + void save_shouldThrowExceptionWhenNull() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + history.save(null); + }); + + assertEquals("Memento cannot be null", exception.getMessage()); + } + + @Test + void restore_shouldReturnEmptyOptionalWhenNoMemento() { + Optional restored = history.restore(); + assertTrue(restored.isEmpty(), "Should return empty if no memento is saved"); + } + + @Test + void restore_shouldReturnInLIFOOrder() { + Memento m1 = mock(Memento.class); + Memento m2 = mock(Memento.class); + + history.save(m1); + history.save(m2); + + assertEquals(m2, history.restore().orElse(null), "Should return last pushed memento first"); + assertEquals(m1, history.restore().orElse(null), "Should return first pushed memento last"); + assertTrue(history.restore().isEmpty(), "Should be empty after all mementos restored"); + } + + @Test + void clear_shouldRemoveAllMementos() { + history.save(mockMemento); + history.clear(); + + assertTrue(history.restore().isEmpty(), "All mementos should be cleared"); + } +} diff --git a/src/test/java/quiz/history/MementoTest.java b/src/test/java/quiz/history/MementoTest.java new file mode 100644 index 0000000..723fbed --- /dev/null +++ b/src/test/java/quiz/history/MementoTest.java @@ -0,0 +1,65 @@ +package quiz.history; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import quiz.scenarios.Question; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class MementoTest { + + private Question mockQuestion1; + private Question mockQuestion2; + + private List originalList; + + @BeforeEach + void setUp() { + mockQuestion1 = mock(Question.class); + mockQuestion2 = mock(Question.class); + + when(mockQuestion1.copy()).thenReturn(mockQuestion1); + when(mockQuestion2.copy()).thenReturn(mockQuestion2); + + originalList = new ArrayList<>(); + originalList.add(mockQuestion1); + originalList.add(mockQuestion2); + } + + @Test + void constructor_shouldCopyQuestions() { + Memento memento = new Memento(originalList); + + List questions = memento.getQuestions(); + + assertNotNull(questions, "List should not be null"); + assertEquals(2, questions.size(), "List should contain 2 elements"); + + verify(mockQuestion1, times(1)).copy(); + verify(mockQuestion2, times(1)).copy(); + } + + @Test + void getQuestions_shouldReturnNewList() { + Memento memento = new Memento(originalList); + + List firstCall = memento.getQuestions(); + List secondCall = memento.getQuestions(); + + assertNotSame(firstCall, secondCall, "Each call should return a new list"); + assertEquals(firstCall, secondCall, "But contents should be equal"); + } + + @Test + void constructor_shouldThrowExceptionWhenNullPassed() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Memento(null); + }); + + assertEquals("Questions cannot be null", exception.getMessage()); + } +} diff --git a/src/test/java/quiz/history/QuestionsHistoryManagerTest.java b/src/test/java/quiz/history/QuestionsHistoryManagerTest.java new file mode 100644 index 0000000..235eb93 --- /dev/null +++ b/src/test/java/quiz/history/QuestionsHistoryManagerTest.java @@ -0,0 +1,104 @@ +package quiz.history; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import quiz.scenarios.Question; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class QuestionsHistoryManagerTest { + + private Question mockQuestion1; + private Question mockQuestion2; + + private List questionsList; + private QuestionsHistoryManager manager; + + @BeforeEach + void setUp() { + mockQuestion1 = mock(Question.class); + mockQuestion2 = mock(Question.class); + + when(mockQuestion1.copy()).thenReturn(mockQuestion1); + when(mockQuestion2.copy()).thenReturn(mockQuestion2); + + questionsList = new ArrayList<>(); + questionsList.add(mockQuestion1); + questionsList.add(mockQuestion2); + + manager = new QuestionsHistoryManager(questionsList); + } + + @Test + void testConstructorWithQuestions_shouldInitializeCorrectly() { + List result = manager.getAllQuestions(); + assertEquals(2, result.size()); + assertTrue(result.contains(mockQuestion1)); + assertTrue(result.contains(mockQuestion2)); + } + + @Test + void testReplaceObjects_shouldReplaceQuestions() { + Question mockNew = mock(Question.class); + when(mockNew.copy()).thenReturn(mockNew); + List newList = List.of(mockNew); + + manager.replaceObjects(newList); + + List result = manager.getAllQuestions(); + assertEquals(1, result.size()); + assertTrue(result.contains(mockNew)); + } + + @Test + void testReplaceObjects_withNull_shouldThrowException() { + Exception ex = assertThrows(IllegalArgumentException.class, () -> { + manager.replaceObjects(null); + }); + + assertEquals("List Questions cannot be null or empty", ex.getMessage()); + } + + @Test + void testReplaceObjects_withEmptyList_shouldThrowException() { + Exception ex = assertThrows(IllegalArgumentException.class, () -> { + manager.replaceObjects(new ArrayList<>()); + }); + + assertEquals("List Questions cannot be null or empty", ex.getMessage()); + } + + @Test + void testBackupAndRestore_shouldRestorePreviousState() { + manager.backup(); + + Question mockNew = mock(Question.class); + when(mockNew.copy()).thenReturn(mockNew); + manager.replaceObjects(List.of(mockNew)); + + assertEquals(1, manager.getAllQuestions().size()); + assertTrue(manager.getAllQuestions().contains(mockNew)); + + manager.restore(); + + List restored = manager.getAllQuestions(); + assertEquals(2, restored.size()); + assertTrue(restored.contains(mockQuestion1)); + assertTrue(restored.contains(mockQuestion2)); + } + + @Test + void testRestore_withoutBackup_shouldDoNothing() { + QuestionsHistoryManager freshManager = new QuestionsHistoryManager(questionsList); + freshManager.restore(); + + List current = freshManager.getAllQuestions(); + assertEquals(2, current.size()); + assertTrue(current.contains(mockQuestion1)); + assertTrue(current.contains(mockQuestion2)); + } +} diff --git a/src/test/java/quiz/scenarios/CheckTest.java b/src/test/java/quiz/scenarios/CheckTest.java new file mode 100644 index 0000000..01c06c8 --- /dev/null +++ b/src/test/java/quiz/scenarios/CheckTest.java @@ -0,0 +1,99 @@ +package quiz.scenarios; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class CheckTest { + + private Check validCheck; + private Check anotherValidCheck; + + @BeforeEach + void setUp() { + validCheck = new Check("Yes", true); + anotherValidCheck = new Check("No", false); + } + + @Test + void testConstructor_shouldThrowExceptionForNullChoice() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Check(null, true); + }); + + assertEquals("Choice text cannot be null or empty", exception.getMessage(), "Should throw exception when choice is null"); + } + + @Test + void testConstructor_shouldThrowExceptionForEmptyChoice() { + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new Check("", true); + }); + + assertEquals("Choice text cannot be null or empty", exception.getMessage(), "Should throw exception when choice is empty"); + } + + @Test + void testConstructor_shouldNotThrowExceptionForValidChoice() { + assertDoesNotThrow(() -> new Check("Yes", true), "Constructor should not throw exception for valid choice"); + } + + @Test + void testCopy_shouldReturnDifferentInstanceWithSameValues() { + Check copiedCheck = validCheck.copy(); + + assertNotSame(validCheck, copiedCheck, "The copied check should be a different instance"); + assertEquals(validCheck, copiedCheck, "The copied check should have the same values"); + } + + @Test + void testGetChoice_shouldReturnCorrectChoice() { + assertEquals("Yes", validCheck.getChoice(), "getChoice should return the correct choice"); + } + + @Test + void testIsValidChoice_shouldReturnCorrectValue() { + assertTrue(validCheck.isValidChoice(), "isValidChoice should return true for valid choice"); + assertFalse(anotherValidCheck.isValidChoice(), "isValidChoice should return false for invalid choice"); + } + + @Test + void testGetSelected_shouldReturnDefaultFalse() { + assertFalse(validCheck.getSelected(), "getSelected should return false by default"); + } + + @Test + void testSetSelected_shouldUpdateSelectedStatus() { + validCheck.setSelected(true); + assertTrue(validCheck.getSelected(), "setSelected should correctly update the selected status"); + } + + @Test + void testEquals_shouldReturnTrueForEqualObjects() { + Check anotherCheck = new Check("Yes", true); + assertEquals(validCheck, anotherCheck, "Two Check objects with the same choice and validity should be equal"); + } + + @Test + void testEquals_shouldReturnFalseForDifferentObjects() { + assertNotEquals(validCheck, anotherValidCheck, "Two Check objects with different choices should not be equal"); + } + + @Test + void testHashCode_shouldReturnSameHashCodeForEqualObjects() { + Check anotherCheck = new Check("Yes", true); + assertEquals(validCheck.hashCode(), anotherCheck.hashCode(), "Hash codes should be the same for equal Check objects"); + } + + @Test + void testHashCode_shouldReturnDifferentHashCodeForDifferentObjects() { + assertNotEquals(validCheck.hashCode(), anotherValidCheck.hashCode(), "Hash codes should be different for Check objects with different values"); + } + + @Test + void testToString_shouldReturnCorrectString() { + String expectedString = "Check{choice='Yes', isValidChoice=true, isSelected=false}"; + assertEquals(expectedString, validCheck.toString(), "toString should return the correct string representation"); + } +} diff --git a/src/test/java/quiz/scenarios/QuestionTest.java b/src/test/java/quiz/scenarios/QuestionTest.java new file mode 100644 index 0000000..55cc449 --- /dev/null +++ b/src/test/java/quiz/scenarios/QuestionTest.java @@ -0,0 +1,99 @@ +package quiz.scenarios; + +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +class QuestionTest { + + private Check createCheck(String text, boolean isValid) { + return new Check(text, isValid); + } + + @Test + void testConstructorWithValidData() { + Set checks = Set.of( + createCheck("A", true), + createCheck("B", false) + ); + + Question q = new Question("Q1", "What is the capital?", checks); + + assertEquals("Q1", q.getQuestionID()); + assertEquals("What is the capital?", q.getDescription()); + assertEquals(2, q.getChecks().size()); + } + + @Test + void testConstructorWithNullCheckSetReturnsEmptySet() { + Question q = new Question("Q2", "Some question", null); + assertTrue(q.getChecks().isEmpty()); + } + + @Test + void testConstructorThrowsExceptionOnNullElementInCheckSet() { + Set checks = new HashSet<>(); + checks.add(null); + + assertThrows(IllegalArgumentException.class, () -> + new Question("Q3", "Bad question", checks) + ); + } + + @Test + void testCopyCreatesDeepCopy() { + Check originalCheck = createCheck("A", true); + originalCheck.setSelected(true); + + Set originalChecks = Set.of(originalCheck); + Question original = new Question("Q4", "Copy me", originalChecks); + + Question copy = original.copy(); + + assertEquals(original, copy); + assertNotSame(original, copy); + + Check copiedCheck = copy.getChecks().get(0); + assertNotSame(originalCheck, copiedCheck); + assertEquals(originalCheck, copiedCheck); + } + + @Test + void testGetShuffleChecksReturnsShuffledList() { + Set checks = new LinkedHashSet<>(); + checks.add(createCheck("A", true)); + checks.add(createCheck("B", false)); + checks.add(createCheck("C", false)); + + Question q = new Question("Q5", "Shuffled?", checks); + List original = q.getChecks(); + List shuffled = q.getShuffleChecks(); + + assertEquals(new HashSet<>(original), new HashSet<>(shuffled)); + } + + @Test + void testEqualsAndHashCode() { + Set checks1 = Set.of(createCheck("A", true)); + Set checks2 = Set.of(createCheck("A", true)); + + Question q1 = new Question("Q6", "Same?", checks1); + Question q2 = new Question("Q6", "Same?", checks2); + + assertEquals(q1, q2); + assertEquals(q1.hashCode(), q2.hashCode()); + } + + @Test + void testToStringContainsKeyParts() { + Set checks = Set.of(createCheck("Yes", true)); + Question question = new Question("Q7", "Yes?", checks); + + String result = question.toString(); + assertTrue(result.contains("Q7")); + assertTrue(result.contains("Yes?")); + assertTrue(result.contains("Yes")); + } +} \ No newline at end of file diff --git a/src/test/java/quiz/scenarios/QuestionsTemplateTest.java b/src/test/java/quiz/scenarios/QuestionsTemplateTest.java new file mode 100644 index 0000000..9b2d9f8 --- /dev/null +++ b/src/test/java/quiz/scenarios/QuestionsTemplateTest.java @@ -0,0 +1,100 @@ +package quiz.scenarios; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class QuestionsTemplateTest { + + private Set mockQuestions; + private QuestionsTemplate questionsTemplate; + + @BeforeEach + void setUp() { + mockQuestions = new HashSet<>(); + Question mockQuestion = mock(Question.class); + when(mockQuestion.copy()).thenReturn(mockQuestion); + mockQuestions.add(mockQuestion); + + questionsTemplate = new QuestionsTemplate(mockQuestions); + } + + @Test + void testConstructor_shouldInitializeQuestions() { + assertNotNull(questionsTemplate); + assertEquals(1, questionsTemplate.size(), "Questions set should contain one question"); + } + + @Test + void testSize_shouldReturnCorrectSize() { + assertEquals(1, questionsTemplate.size(), "The size of the questions should be 1"); + } + + @Test + void testGetQuestions_shouldReturnListOfQuestions() { + List questions = questionsTemplate.getQuestions(); + assertNotNull(questions, "Questions list should not be null"); + assertEquals(1, questions.size(), "The list should contain exactly one question"); + } + + @Test + void testGetShuffleQuestions_shouldShuffleQuestions() { + List originalList = questionsTemplate.getQuestions(); + List shuffledList = questionsTemplate.getShuffleQuestions(); + + assertEquals(new HashSet<>(originalList), new HashSet<>(shuffledList), "Shuffled should contain same questions"); + } + + @Test + void testEquals_shouldReturnTrueForEqualObjects() { + QuestionsTemplate copyTemplate = new QuestionsTemplate(mockQuestions); + assertEquals(questionsTemplate, copyTemplate, "The templates should be equal"); + } + + @Test + void testEquals_shouldReturnFalseForDifferentObjects() { + Set differentQuestions = new HashSet<>(); + Question anotherMock = mock(Question.class); + when(anotherMock.copy()).thenReturn(anotherMock); + differentQuestions.add(anotherMock); + + QuestionsTemplate differentTemplate = new QuestionsTemplate(differentQuestions); + assertNotEquals(questionsTemplate, differentTemplate, "The templates should not be equal"); + } + + @Test + void testHashCode_shouldReturnSameHashCodeForEqualObjects() { + QuestionsTemplate copyTemplate = new QuestionsTemplate(mockQuestions); + assertEquals(questionsTemplate.hashCode(), copyTemplate.hashCode(), "Hash codes should match for equal objects"); + } + + @Test + void testCopy_shouldReturnNewInstanceWithSameQuestions() { + QuestionsTemplate copiedTemplate = questionsTemplate.copy(); + assertNotSame(questionsTemplate, copiedTemplate, "Copy should be a different instance"); + assertEquals(questionsTemplate, copiedTemplate, "Copy should be equal in content"); + } + + @Test + void testConstructor_shouldHandleNullQuestions() { + QuestionsTemplate nullQuestionsTemplate = new QuestionsTemplate(null); + assertNotNull(nullQuestionsTemplate, "Template should not be null"); + assertEquals(0, nullQuestionsTemplate.size(), "Size should be 0 for null input"); + } + + @Test + void testConstructor_shouldHandleNullQuestionInSet() { + Set invalidQuestions = new HashSet<>(); + invalidQuestions.add(null); + + IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> { + new QuestionsTemplate(invalidQuestions); + }); + + assertEquals("Question value cannot be null", exception.getMessage(), "Should throw exception for null question"); + } +} \ No newline at end of file